From af9704ef04e5ff7de3502727cbb6c828226c2ff0 Mon Sep 17 00:00:00 2001 From: anna Date: Fri, 26 Oct 2012 18:56:44 +0200 Subject: [PATCH] method refs: fix qualifier when static method is moved; show conflict if instance method is moved --- .../MethodCallUsageInfo.java | 9 ++--- .../MoveInstanceMethodProcessor.java | 34 ++++++++++++------- .../PsiMethodReferenceExpressionImpl.java | 17 ++++++++++ .../moveInstanceMethod/MethodReference.java | 16 +++++++++ .../moveMethod/MoveInstanceMethodTest.java | 11 ++++++ 5 files changed, 71 insertions(+), 16 deletions(-) create mode 100644 java/java-tests/testData/refactoring/moveInstanceMethod/MethodReference.java diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MethodCallUsageInfo.java b/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MethodCallUsageInfo.java index 66e1d5ed5b57..d0c1e69a1c92 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MethodCallUsageInfo.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MethodCallUsageInfo.java @@ -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; } diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java index 531b12d7522c..068fe4f15583 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveInstanceMethod/MoveInstanceMethodProcessor.java @@ -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()); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java index 45e036d7b2a6..f09ccf4f0edf 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java @@ -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(); diff --git a/java/java-tests/testData/refactoring/moveInstanceMethod/MethodReference.java b/java/java-tests/testData/refactoring/moveInstanceMethod/MethodReference.java new file mode 100644 index 000000000000..b2123810ca9e --- /dev/null +++ b/java/java-tests/testData/refactoring/moveInstanceMethod/MethodReference.java @@ -0,0 +1,16 @@ +interface SAM { + String m(MethodReference f, F f1); +} + + +class F {} + +class MethodReference { + String getX(F f1) { + return null; + } + + static void test() { + SAM s = MethodReference::getX; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/moveMethod/MoveInstanceMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/moveMethod/MoveInstanceMethodTest.java index 3d3e3912dbcc..da41d701a2f2 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/moveMethod/MoveInstanceMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/moveMethod/MoveInstanceMethodTest.java @@ -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); }