method refs: fix qualifier when static method is moved; show conflict if instance method is moved

This commit is contained in:
anna
2012-10-26 18:59:47 +02:00
parent 337235214d
commit af9704ef04
5 changed files with 71 additions and 16 deletions
@@ -15,7 +15,8 @@
*/
package com.intellij.refactoring.move.moveInstanceMethod;
import com.intellij.psi.PsiMethodCallExpression;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethodReferenceExpression;
import com.intellij.psi.PsiReferenceExpression;
import com.intellij.usageView.UsageInfo;
@@ -23,16 +24,16 @@ import com.intellij.usageView.UsageInfo;
* @author ven
*/
public class MethodCallUsageInfo extends UsageInfo {
private final PsiMethodCallExpression myMethodCallExpression;
private final PsiElement myMethodCallExpression;
private final boolean myIsInternal;
public MethodCallUsageInfo(final PsiReferenceExpression referenceExpression, final boolean internal) {
super(referenceExpression);
myIsInternal = internal;
myMethodCallExpression = (PsiMethodCallExpression)referenceExpression.getParent();
myMethodCallExpression = referenceExpression instanceof PsiMethodReferenceExpression ? referenceExpression : referenceExpression.getParent();
}
public PsiMethodCallExpression getMethodCallExpression() {
public PsiElement getMethodCallExpression() {
return myMethodCallExpression;
}
@@ -107,18 +107,22 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{
PsiParameter parameter = (PsiParameter)myTargetVariable;
for (final UsageInfo usageInfo : usages) {
if (usageInfo instanceof MethodCallUsageInfo) {
final PsiMethodCallExpression methodCall = ((MethodCallUsageInfo)usageInfo).getMethodCallExpression();
final PsiExpression[] expressions = methodCall.getArgumentList().getExpressions();
final int index = myMethod.getParameterList().getParameterIndex(parameter);
if (index < expressions.length) {
PsiExpression instanceValue = expressions[index];
instanceValue = RefactoringUtil.unparenthesizeExpression(instanceValue);
if (instanceValue instanceof PsiLiteralExpression && ((PsiLiteralExpression)instanceValue).getValue() == null) {
String message = RefactoringBundle.message("0.contains.call.with.null.argument.for.parameter.1",
RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(methodCall), true),
CommonRefactoringUtil.htmlEmphasize(parameter.getName()));
conflicts.putValue(instanceValue, message);
final PsiElement methodCall = ((MethodCallUsageInfo)usageInfo).getMethodCallExpression();
if (methodCall instanceof PsiMethodCallExpression) {
final PsiExpression[] expressions = ((PsiMethodCallExpression)methodCall).getArgumentList().getExpressions();
final int index = myMethod.getParameterList().getParameterIndex(parameter);
if (index < expressions.length) {
PsiExpression instanceValue = expressions[index];
instanceValue = RefactoringUtil.unparenthesizeExpression(instanceValue);
if (instanceValue instanceof PsiLiteralExpression && ((PsiLiteralExpression)instanceValue).getValue() == null) {
String message = RefactoringBundle.message("0.contains.call.with.null.argument.for.parameter.1",
RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(methodCall), true),
CommonRefactoringUtil.htmlEmphasize(parameter.getName()));
conflicts.putValue(instanceValue, message);
}
}
} else if (methodCall instanceof PsiMethodReferenceExpression) {
conflicts.putValue(methodCall, "Method reference would be broken after move");
}
}
}
@@ -220,7 +224,13 @@ public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{
addMethodToClass(inheritor, patternMethod, true);
}
else if (usage instanceof MethodCallUsageInfo && !((MethodCallUsageInfo)usage).isInternal()) {
correctMethodCall(((MethodCallUsageInfo)usage).getMethodCallExpression(), false);
final PsiElement expression = ((MethodCallUsageInfo)usage).getMethodCallExpression();
if (expression instanceof PsiMethodCallExpression) {
correctMethodCall((PsiMethodCallExpression)expression, false);
} else if (expression instanceof PsiMethodReferenceExpression) {
PsiExpression newQualifier = JavaPsiFacade.getInstance(myProject).getElementFactory().createExpressionFromText(myTargetVariable.getType().getCanonicalText(), null);
((PsiMethodReferenceExpression)expression).setQualifierExpression(newQualifier);
}
}
else if (usage instanceof JavadocUsageInfo) {
docRefs.add(usage.getElement().getReference());
@@ -94,6 +94,23 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
PsiScopesUtil.resolveAndWalk(proc, this, null, true);
}
@Override
public void setQualifierExpression(@Nullable PsiExpression newQualifier) throws IncorrectOperationException {
if (newQualifier == null) {
super.setQualifierExpression(newQualifier);
return;
}
final PsiExpression expression = getQualifierExpression();
if (expression != null) {
expression.replace(newQualifier);
} else {
final PsiElement qualifier = getQualifier();
if (qualifier != null) {
qualifier.replace(newQualifier);
}
}
}
@Override
public int getChildRole(ASTNode child) {
final IElementType elType = child.getElementType();
@@ -0,0 +1,16 @@
interface SAM {
String m(MethodReference<String> f, F f1);
}
class F {}
class MethodReference<X> {
String ge<caret>tX(F f1) {
return null;
}
static void test() {
SAM s = MethodReference<String>::getX;
}
}
@@ -5,6 +5,7 @@ import com.intellij.codeInsight.TargetElementUtilBase;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiVariable;
import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.LightRefactoringTestCase;
import com.intellij.refactoring.move.moveInstanceMethod.MoveInstanceMethodHandler;
import com.intellij.refactoring.move.moveInstanceMethod.MoveInstanceMethodProcessor;
@@ -81,6 +82,16 @@ public class MoveInstanceMethodTest extends LightRefactoringTestCase {
doTest(false, 0);
}
public void testMethodReference() throws Exception {
try {
doTest(true, 0);
fail("Conflict was not detected");
}
catch (BaseRefactoringProcessor.ConflictsInTestsException e) {
assertEquals("Method reference would be broken after move", e.getMessage());
}
}
private void doTest(boolean isTargetParameter, final int targetIndex) throws Exception {
doTest(isTargetParameter, targetIndex, null);
}