From 855ed81c116a06f091a893d58c2b19daa8d9e70e Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 31 Jul 2014 18:37:02 +0400 Subject: [PATCH] Introduce Variable: Use expression unifier to find duplicates --- .../KotlinIntroduceVariableHandler.java | 99 ++++--------------- .../OccurrencesInStringTemplate.kt | 4 + .../OccurrencesInStringTemplate.kt.after | 5 + .../UnresolvedOccurrences.kt | 7 ++ .../UnresolvedOccurrences.kt.after | 8 ++ .../JetExtractionTestGenerated.java | 10 ++ 6 files changed, 54 insertions(+), 79 deletions(-) create mode 100644 idea/testData/refactoring/introduceVariable/OccurrencesInStringTemplate.kt create mode 100644 idea/testData/refactoring/introduceVariable/OccurrencesInStringTemplate.kt.after create mode 100644 idea/testData/refactoring/introduceVariable/UnresolvedOccurrences.kt create mode 100644 idea/testData/refactoring/introduceVariable/UnresolvedOccurrences.kt.after diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java b/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java index f856b055e49..e4c58a2f338 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java @@ -16,7 +16,6 @@ package org.jetbrains.jet.plugin.refactoring.introduce.introduceVariable; -import com.intellij.codeInsight.PsiEquivalenceUtil; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; @@ -31,6 +30,7 @@ import com.intellij.psi.PsiWhiteSpace; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.HelpID; import com.intellij.refactoring.introduce.inplace.OccurrencesChooser; +import kotlin.Function1; import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -42,7 +42,6 @@ import org.jetbrains.jet.lang.resolve.BindingTraceContext; import org.jetbrains.jet.lang.resolve.ObservableBindingTrace; import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; -import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeUtils; @@ -52,20 +51,25 @@ import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage; import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils; import org.jetbrains.jet.plugin.codeInsight.ShortenReferences; -import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; import org.jetbrains.jet.plugin.project.ResolveSessionForBodies; import org.jetbrains.jet.plugin.refactoring.JetNameSuggester; import org.jetbrains.jet.plugin.refactoring.JetNameValidatorImpl; import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle; import org.jetbrains.jet.plugin.refactoring.JetRefactoringUtil; import org.jetbrains.jet.plugin.refactoring.introduce.KotlinIntroduceHandlerBase; +import org.jetbrains.jet.plugin.util.psi.patternMatching.JetPsiRange; +import org.jetbrains.jet.plugin.util.psi.patternMatching.JetPsiUnifier; +import org.jetbrains.jet.plugin.util.psi.patternMatching.PatternMatchingPackage; +import org.jetbrains.jet.plugin.util.psi.patternMatching.UnifierParameter; import org.jetbrains.jet.plugin.util.psiModificationUtil.PsiModificationUtilPackage; import org.jetbrains.jet.renderer.DescriptorRenderer; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory; -import static org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage.getResolvedCall; public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase { @@ -431,84 +435,21 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase { return anchor; } - private static ArrayList findOccurrences(PsiElement occurrenceContainer, @NotNull JetExpression expression) { - if (expression instanceof JetParenthesizedExpression) { - JetParenthesizedExpression parenthesizedExpression = (JetParenthesizedExpression)expression; - JetExpression innerExpression = parenthesizedExpression.getExpression(); - if (innerExpression != null) { - expression = innerExpression; - } - } - final JetExpression actualExpression = expression; - - final ArrayList result = new ArrayList(); - - final BindingContext bindingContext = AnalyzerFacadeWithCache.getContextForElement(expression); - - JetVisitorVoid visitor = new JetVisitorVoid() { - @Override - public void visitJetElement(@NotNull JetElement element) { - element.acceptChildren(this); - super.visitJetElement(element); - } - - @Override - public void visitExpression(@NotNull JetExpression expression) { - if (PsiEquivalenceUtil.areElementsEquivalent(expression, actualExpression, null, new Comparator() { - private boolean compareCalleesAndReceivers(@NotNull ResolvedCall rc1, @NotNull ResolvedCall rc2) { - if (rc1.getResultingDescriptor() != rc2.getResultingDescriptor() || - rc1.getExplicitReceiverKind() != rc2.getExplicitReceiverKind()) return false; - - switch (rc1.getExplicitReceiverKind()) { - case NO_EXPLICIT_RECEIVER: - return rc1.getReceiverArgument() == rc2.getReceiverArgument() - && rc1.getThisObject() == rc2.getThisObject(); - case RECEIVER_ARGUMENT: - return rc1.getThisObject() == rc2.getThisObject(); - case THIS_OBJECT: - return rc1.getReceiverArgument() == rc2.getReceiverArgument(); - default: - return true; - } - } - + private static List findOccurrences(PsiElement occurrenceContainer, @NotNull JetExpression originalExpression) { + return KotlinPackage.map( + PatternMatchingPackage.toRange(originalExpression).match(occurrenceContainer, JetPsiUnifier.DEFAULT), + new Function1() { @Override - public int compare(@NotNull PsiElement element1, @NotNull PsiElement element2) { - if (element1.getNode().getElementType() == JetTokens.IDENTIFIER && - element2.getNode().getElementType() == JetTokens.IDENTIFIER) { - if (element1.getParent() instanceof JetSimpleNameExpression && - element2.getParent() instanceof JetSimpleNameExpression) { - JetSimpleNameExpression expr1 = (JetSimpleNameExpression)element1.getParent(); - JetSimpleNameExpression expr2 = (JetSimpleNameExpression)element2.getParent(); + public JetExpression invoke(JetPsiRange.Match match) { + PsiElement candidate = ((JetPsiRange.ListRange) match.getRange()).getStartElement(); + if (candidate instanceof JetExpression) return (JetExpression) candidate; + if (candidate instanceof JetStringTemplateEntryWithExpression) + return ((JetStringTemplateEntryWithExpression) candidate).getExpression(); - ResolvedCall rc1 = getResolvedCall(expr1, bindingContext); - ResolvedCall rc2 = getResolvedCall(expr2, bindingContext); - return (rc1 != null && rc2 != null) && compareCalleesAndReceivers(rc1, rc2) ? 0 : 1; - } - } - if (!element1.textMatches(element2)) { - return 1; - } - else { - return 0; - } - } - }, null, false)) { - PsiElement parent = expression.getParent(); - if (parent instanceof JetParenthesizedExpression) { - result.add((JetParenthesizedExpression)parent); - } - else { - result.add(expression); + throw new AssertionError("Unexpected candidate element: " + candidate.getText()); } } - else { - super.visitExpression(expression); - } - } - }; - occurrenceContainer.accept(visitor); - return result; + ); } @Nullable diff --git a/idea/testData/refactoring/introduceVariable/OccurrencesInStringTemplate.kt b/idea/testData/refactoring/introduceVariable/OccurrencesInStringTemplate.kt new file mode 100644 index 00000000000..084f4521aec --- /dev/null +++ b/idea/testData/refactoring/introduceVariable/OccurrencesInStringTemplate.kt @@ -0,0 +1,4 @@ +fun a(x: Int) { + val a = x + 1 + "it's a number ${x + 1}" +} \ No newline at end of file diff --git a/idea/testData/refactoring/introduceVariable/OccurrencesInStringTemplate.kt.after b/idea/testData/refactoring/introduceVariable/OccurrencesInStringTemplate.kt.after new file mode 100644 index 00000000000..6690add000b --- /dev/null +++ b/idea/testData/refactoring/introduceVariable/OccurrencesInStringTemplate.kt.after @@ -0,0 +1,5 @@ +fun a(x: Int) { + val i = x + 1 + val a = i + "it's a number ${i}" +} \ No newline at end of file diff --git a/idea/testData/refactoring/introduceVariable/UnresolvedOccurrences.kt b/idea/testData/refactoring/introduceVariable/UnresolvedOccurrences.kt new file mode 100644 index 00000000000..ad3b5a78131 --- /dev/null +++ b/idea/testData/refactoring/introduceVariable/UnresolvedOccurrences.kt @@ -0,0 +1,7 @@ +fun a() { + val x = Foo() + println(Foo()) + println(Foo) + println(Foo(1)) + println(1.Foo()) +} \ No newline at end of file diff --git a/idea/testData/refactoring/introduceVariable/UnresolvedOccurrences.kt.after b/idea/testData/refactoring/introduceVariable/UnresolvedOccurrences.kt.after new file mode 100644 index 00000000000..98f1e7e3892 --- /dev/null +++ b/idea/testData/refactoring/introduceVariable/UnresolvedOccurrences.kt.after @@ -0,0 +1,8 @@ +fun a() { + val foo = Foo() + val x = foo + println(foo) + println(Foo) + println(Foo(1)) + println(1.Foo()) +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java index b13b463ed6b..fb0e14e6237 100644 --- a/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/JetExtractionTestGenerated.java @@ -173,6 +173,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { doIntroduceVariableTest(fileName); } + @TestMetadata("OccurrencesInStringTemplate.kt") + public void testOccurrencesInStringTemplate() throws Exception { + doIntroduceVariableTest("idea/testData/refactoring/introduceVariable/OccurrencesInStringTemplate.kt"); + } + @TestMetadata("OneExplicitReceiver.kt") public void testOneExplicitReceiver() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/OneExplicitReceiver.kt"); @@ -209,6 +214,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { doIntroduceVariableTest(fileName); } + @TestMetadata("UnresolvedOccurrences.kt") + public void testUnresolvedOccurrences() throws Exception { + doIntroduceVariableTest("idea/testData/refactoring/introduceVariable/UnresolvedOccurrences.kt"); + } + @TestMetadata("WhenAddBlock.kt") public void testWhenAddBlock() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/WhenAddBlock.kt");