Introduce Variable: Use expression unifier to find duplicates
This commit is contained in:
+20
-79
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.plugin.refactoring.introduce.introduceVariable;
|
package org.jetbrains.jet.plugin.refactoring.introduce.introduceVariable;
|
||||||
|
|
||||||
import com.intellij.codeInsight.PsiEquivalenceUtil;
|
|
||||||
import com.intellij.openapi.actionSystem.DataContext;
|
import com.intellij.openapi.actionSystem.DataContext;
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
import com.intellij.openapi.command.CommandProcessor;
|
import com.intellij.openapi.command.CommandProcessor;
|
||||||
@@ -31,6 +30,7 @@ import com.intellij.psi.PsiWhiteSpace;
|
|||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import com.intellij.refactoring.HelpID;
|
import com.intellij.refactoring.HelpID;
|
||||||
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
|
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
|
||||||
|
import kotlin.Function1;
|
||||||
import kotlin.KotlinPackage;
|
import kotlin.KotlinPackage;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
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.ObservableBindingTrace;
|
||||||
import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage;
|
import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
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.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
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.caches.resolve.ResolvePackage;
|
||||||
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils;
|
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils;
|
||||||
import org.jetbrains.jet.plugin.codeInsight.ShortenReferences;
|
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.project.ResolveSessionForBodies;
|
||||||
import org.jetbrains.jet.plugin.refactoring.JetNameSuggester;
|
import org.jetbrains.jet.plugin.refactoring.JetNameSuggester;
|
||||||
import org.jetbrains.jet.plugin.refactoring.JetNameValidatorImpl;
|
import org.jetbrains.jet.plugin.refactoring.JetNameValidatorImpl;
|
||||||
import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle;
|
import org.jetbrains.jet.plugin.refactoring.JetRefactoringBundle;
|
||||||
import org.jetbrains.jet.plugin.refactoring.JetRefactoringUtil;
|
import org.jetbrains.jet.plugin.refactoring.JetRefactoringUtil;
|
||||||
import org.jetbrains.jet.plugin.refactoring.introduce.KotlinIntroduceHandlerBase;
|
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.plugin.util.psiModificationUtil.PsiModificationUtilPackage;
|
||||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
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.psi.PsiPackage.JetPsiFactory;
|
||||||
import static org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage.getResolvedCall;
|
|
||||||
|
|
||||||
public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
|
public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
|
||||||
|
|
||||||
@@ -431,84 +435,21 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
|
|||||||
return anchor;
|
return anchor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArrayList<JetExpression> findOccurrences(PsiElement occurrenceContainer, @NotNull JetExpression expression) {
|
private static List<JetExpression> findOccurrences(PsiElement occurrenceContainer, @NotNull JetExpression originalExpression) {
|
||||||
if (expression instanceof JetParenthesizedExpression) {
|
return KotlinPackage.map(
|
||||||
JetParenthesizedExpression parenthesizedExpression = (JetParenthesizedExpression)expression;
|
PatternMatchingPackage.toRange(originalExpression).match(occurrenceContainer, JetPsiUnifier.DEFAULT),
|
||||||
JetExpression innerExpression = parenthesizedExpression.getExpression();
|
new Function1<JetPsiRange.Match, JetExpression>() {
|
||||||
if (innerExpression != null) {
|
|
||||||
expression = innerExpression;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final JetExpression actualExpression = expression;
|
|
||||||
|
|
||||||
final ArrayList<JetExpression> result = new ArrayList<JetExpression>();
|
|
||||||
|
|
||||||
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<PsiElement>() {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(@NotNull PsiElement element1, @NotNull PsiElement element2) {
|
public JetExpression invoke(JetPsiRange.Match match) {
|
||||||
if (element1.getNode().getElementType() == JetTokens.IDENTIFIER &&
|
PsiElement candidate = ((JetPsiRange.ListRange) match.getRange()).getStartElement();
|
||||||
element2.getNode().getElementType() == JetTokens.IDENTIFIER) {
|
if (candidate instanceof JetExpression) return (JetExpression) candidate;
|
||||||
if (element1.getParent() instanceof JetSimpleNameExpression &&
|
if (candidate instanceof JetStringTemplateEntryWithExpression)
|
||||||
element2.getParent() instanceof JetSimpleNameExpression) {
|
return ((JetStringTemplateEntryWithExpression) candidate).getExpression();
|
||||||
JetSimpleNameExpression expr1 = (JetSimpleNameExpression)element1.getParent();
|
|
||||||
JetSimpleNameExpression expr2 = (JetSimpleNameExpression)element2.getParent();
|
|
||||||
|
|
||||||
ResolvedCall<?> rc1 = getResolvedCall(expr1, bindingContext);
|
throw new AssertionError("Unexpected candidate element: " + candidate.getText());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
);
|
||||||
super.visitExpression(expression);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
occurrenceContainer.accept(visitor);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
fun a(x: Int) {
|
||||||
|
val a = <selection>x + 1</selection>
|
||||||
|
"it's a number ${x + 1}"
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun a(x: Int) {
|
||||||
|
val i = x + 1
|
||||||
|
val a = i
|
||||||
|
"it's a number ${i}"
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun a() {
|
||||||
|
val x = <selection>Foo()</selection>
|
||||||
|
println(Foo())
|
||||||
|
println(Foo)
|
||||||
|
println(Foo(1))
|
||||||
|
println(1.Foo())
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun a() {
|
||||||
|
val foo = Foo()
|
||||||
|
val x = foo
|
||||||
|
println(foo)
|
||||||
|
println(Foo)
|
||||||
|
println(Foo(1))
|
||||||
|
println(1.Foo())
|
||||||
|
}
|
||||||
+10
@@ -173,6 +173,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doIntroduceVariableTest(fileName);
|
doIntroduceVariableTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("OccurrencesInStringTemplate.kt")
|
||||||
|
public void testOccurrencesInStringTemplate() throws Exception {
|
||||||
|
doIntroduceVariableTest("idea/testData/refactoring/introduceVariable/OccurrencesInStringTemplate.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("OneExplicitReceiver.kt")
|
@TestMetadata("OneExplicitReceiver.kt")
|
||||||
public void testOneExplicitReceiver() throws Exception {
|
public void testOneExplicitReceiver() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/OneExplicitReceiver.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/OneExplicitReceiver.kt");
|
||||||
@@ -209,6 +214,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doIntroduceVariableTest(fileName);
|
doIntroduceVariableTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("UnresolvedOccurrences.kt")
|
||||||
|
public void testUnresolvedOccurrences() throws Exception {
|
||||||
|
doIntroduceVariableTest("idea/testData/refactoring/introduceVariable/UnresolvedOccurrences.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("WhenAddBlock.kt")
|
@TestMetadata("WhenAddBlock.kt")
|
||||||
public void testWhenAddBlock() throws Exception {
|
public void testWhenAddBlock() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/WhenAddBlock.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/WhenAddBlock.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user