change signature: propagate parameters change to lambda expressions (IDEA-150138)

This commit is contained in:
Anna Kozlova
2016-01-13 11:15:47 +01:00
parent ef59b92a12
commit b56e7e0c20
10 changed files with 131 additions and 45 deletions

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.refactoring.changeSignature;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.usageView.UsageInfo;
class FunctionalInterfaceChangedUsageInfo extends UsageInfo {
private final PsiMethod myMethod;
public FunctionalInterfaceChangedUsageInfo(PsiElement element, PsiMethod method) {
super(element);
myMethod = method;
}
public String getDescription() {
return "Functional expression will be corrupted";
}
public PsiMethod getMethod() {
return myMethod;
}
}

View File

@@ -110,6 +110,15 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr
}
return true;
}
else if (usage instanceof FunctionalInterfaceChangedUsageInfo) {
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(usage.getProject());
final PsiElement element = usage.getElement();
if (element instanceof PsiLambdaExpression) {
processMethodParams((JavaChangeInfo)changeInfo, ((FunctionalInterfaceChangedUsageInfo)usage).getMethod(),
elementFactory, PsiSubstitutor.EMPTY, ((PsiLambdaExpression)element).getParameterList(), ((PsiLambdaExpression)element).getBody());
}
return true;
}
}
else {
@@ -728,10 +737,24 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr
}
PsiParameterList list = method.getParameterList();
int newParamsLength = processMethodParams(changeInfo, baseMethod, factory, substitutor, list, method.getBody());
fixJavadocsForChangedMethod(method, changeInfo, newParamsLength);
if (changeInfo.isExceptionSetOrOrderChanged()) {
final PsiClassType[] newExceptions = getPrimaryChangedExceptionInfo(changeInfo);
fixPrimaryThrowsLists(method, newExceptions);
}
}
private static int processMethodParams(JavaChangeInfo changeInfo,
PsiMethod baseMethod,
PsiElementFactory factory,
PsiSubstitutor substitutor,
PsiParameterList list,
PsiElement methodBody) {
PsiParameter[] parameters = list.getParameters();
final JavaParameterInfo[] parameterInfos = changeInfo.getNewParameters();
final int delta = baseMethod != null ? baseMethod.getParameterList().getParametersCount() - method.getParameterList().getParametersCount() : 0;
final int delta = baseMethod != null ? baseMethod.getParameterList().getParametersCount() - list.getParametersCount() : 0;
PsiParameter[] newParms = new PsiParameter[Math.max(parameterInfos.length - delta, 0)];
final String[] oldParameterNames = changeInfo.getOldParameterNames();
final String[] oldParameterTypes = changeInfo.getOldParameterTypes();
@@ -748,12 +771,15 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr
parameter.getNameIdentifier().replace(newIdentifier);
}
String oldType = oldParameterTypes[index];
if (!oldType.equals(info.getTypeText())) {
parameter.normalizeDeclaration();
PsiType newType = substitutor.substitute(info.createType(changeInfo.getMethod().getParameterList(), method.getManager()));
parameter.getTypeElement().replace(factory.createTypeElement(newType));
final PsiTypeElement typeElement = parameter.getTypeElement();
if (typeElement != null) {
String oldType = oldParameterTypes[index];
if (!oldType.equals(info.getTypeText())) {
parameter.normalizeDeclaration();
PsiType newType =
substitutor.substitute(info.createType(changeInfo.getMethod().getParameterList(), changeInfo.getMethod().getManager()));
typeElement.replace(factory.createTypeElement(newType));
}
}
}
else {
@@ -762,12 +788,8 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr
}
resolveParameterVsFieldsConflicts(newParms, method, list, changeInfo.toRemoveParm());
fixJavadocsForChangedMethod(method, changeInfo, newParms.length);
if (changeInfo.isExceptionSetOrOrderChanged()) {
final PsiClassType[] newExceptions = getPrimaryChangedExceptionInfo(changeInfo);
fixPrimaryThrowsLists(method, newExceptions);
}
resolveParameterVsFieldsConflicts(newParms, list, changeInfo.toRemoveParm(), methodBody);
return newParms.length;
}
private static PsiClassType[] getPrimaryChangedExceptionInfo(JavaChangeInfo changeInfo) throws IncorrectOperationException {
@@ -804,7 +826,7 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr
PsiParameter[] arrayed = newParameters.toArray(new PsiParameter[newParameters.size()]);
boolean[] toRemoveParm = new boolean[arrayed.length];
Arrays.fill(toRemoveParm, false);
resolveParameterVsFieldsConflicts(arrayed, caller, caller.getParameterList(), toRemoveParm);
resolveParameterVsFieldsConflicts(arrayed, caller.getParameterList(), toRemoveParm, caller.getBody());
}
if (toInsertThrows) {
@@ -883,12 +905,12 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr
}
private static void resolveParameterVsFieldsConflicts(final PsiParameter[] newParms,
final PsiMethod method,
final PsiParameterList list,
boolean[] toRemoveParm) throws IncorrectOperationException {
boolean[] toRemoveParm,
final PsiElement methodBody) throws IncorrectOperationException {
List<FieldConflictsResolver> conflictResolvers = new ArrayList<FieldConflictsResolver>();
for (PsiParameter parameter : newParms) {
conflictResolvers.add(new FieldConflictsResolver(parameter.getName(), method.getBody()));
conflictResolvers.add(new FieldConflictsResolver(parameter.getName(), methodBody));
}
ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newParms), ParameterList.INSTANCE, toRemoveParm);
JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list);
@@ -957,7 +979,8 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr
}
checkContract(conflictDescriptions, method);
} else if (element instanceof PsiMethodReferenceExpression) {
}
else if (element instanceof PsiMethodReferenceExpression) {
conflictDescriptions.putValue(element, "Changed method is used in method reference");
}
}

View File

@@ -329,16 +329,4 @@ class JavaChangeSignatureUsageSearcher {
RefactoringUIUtil.getDescription(myMethod, true));
}
}
private static class FunctionalInterfaceChangedUsageInfo extends UnresolvableCollisionUsageInfo {
public FunctionalInterfaceChangedUsageInfo(PsiElement element, PsiElement referencedElement) {
super(element, referencedElement);
}
@Override
public String getDescription() {
return "Functional expression will be corrupted";
}
}
}

View File

@@ -31,12 +31,16 @@ import java.util.List;
*/
public class FieldConflictsResolver {
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.util.FieldConflictsResolver");
private final PsiCodeBlock myScope;
private final PsiElement myScope;
private final PsiField myField;
private final List<PsiReferenceExpression> myReferenceExpressions;
private PsiClass myQualifyingClass;
public FieldConflictsResolver(String name, PsiCodeBlock scope) {
this(name, (PsiElement)scope);
}
public FieldConflictsResolver(String name, PsiElement scope) {
myScope = scope;
if (myScope == null) {
myField = null;

View File

@@ -0,0 +1,11 @@
interface SAM {
void foo(boolean b);
}
class Test {
{
bar((boolean b) -> {});
}
void bar(SAM sam){}
}

View File

@@ -0,0 +1,9 @@
interface SAM {
void foo(boolean b);
}
class Test {
{
SAM sam = (boolean b) -> {};
}
}

View File

@@ -0,0 +1,9 @@
interface I {
void m<caret>(int a, int b);
}
class Test {
{
I i = (a, b) -> {};
}
}

View File

@@ -0,0 +1,9 @@
interface I {
void m(int b, boolean a);
}
class Test {
{
I i = (b, a) -> {};
}
}

View File

@@ -15,23 +15,19 @@
*/
package com.intellij.codeInsight.daemon.lambda;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiType;
import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.ChangeSignatureBaseTest;
import com.intellij.refactoring.changeSignature.ParameterInfoImpl;
import com.intellij.refactoring.changeSignature.ThrownExceptionInfo;
import com.intellij.testFramework.IdeaTestUtil;
public class ChangeSignatureTouchLambdaTest extends ChangeSignatureBaseTest {
public void testVariableDeclaration() {
doTestConflict();
doTest(null, null, null, new ParameterInfoImpl[] {new ParameterInfoImpl(-1, "b", PsiType.BOOLEAN)}, new ThrownExceptionInfo[0], false);
}
public void testMethodArgument() throws Exception {
doTestConflict();
doTest(null, null, null, new ParameterInfoImpl[] {new ParameterInfoImpl(-1, "b", PsiType.BOOLEAN)}, new ThrownExceptionInfo[0], false);
}
public void testDefaultMethodTouched() throws Exception {
@@ -42,14 +38,6 @@ public class ChangeSignatureTouchLambdaTest extends ChangeSignatureBaseTest {
doTest(null, null, null, new ParameterInfoImpl[] {new ParameterInfoImpl(-1, "b", PsiType.BOOLEAN, "false")}, new ThrownExceptionInfo[0], true);
}
private void doTestConflict() {
try {
doTest(null, null, null, new ParameterInfoImpl[] {new ParameterInfoImpl(-1, "b", PsiType.BOOLEAN)}, new ThrownExceptionInfo[0], false);
fail("Conflict expected");
}
catch (BaseRefactoringProcessor.ConflictsInTestsException ignored) { }
}
@Override
protected String getRelativePath() {
return "/codeInsight/daemonCodeAnalyzer/lambda/changeSignature/";

View File

@@ -333,6 +333,13 @@ public class ChangeSignatureTest extends ChangeSignatureBaseTest {
}, false);
}
public void testReorderParamsOfFunctionalInterface() {
doTest(null, null, null, method -> new ParameterInfoImpl[]{
new ParameterInfoImpl(1, "b", PsiType.INT),
new ParameterInfoImpl(0, "a", PsiType.BOOLEAN)
}, false);
}
public void testMethodParametersAlignmentAfterMethodNameChange() {
getJavaSettings().ALIGN_MULTILINE_PARAMETERS = true;
getJavaSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;