Improve JetNameValidatorImpl performance
This commit is contained in:
@@ -18,60 +18,68 @@ package org.jetbrains.jet.plugin.refactoring;
|
|||||||
|
|
||||||
import com.intellij.openapi.util.Ref;
|
import com.intellij.openapi.util.Ref;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import kotlin.Function1;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.psi.JetElement;
|
import org.jetbrains.jet.lang.psi.JetElement;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
import org.jetbrains.jet.lang.psi.JetVisitorVoid;
|
import org.jetbrains.jet.lang.psi.JetVisitorVoid;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
import org.jetbrains.jet.plugin.codeInsight.TipsManager;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class JetNameValidatorImpl extends JetNameValidator {
|
public class JetNameValidatorImpl extends JetNameValidator {
|
||||||
|
public static enum Target {
|
||||||
|
FUNCTIONS_AND_CLASSES,
|
||||||
|
PROPERTIES
|
||||||
|
}
|
||||||
|
|
||||||
private final PsiElement myContainer;
|
private final PsiElement myContainer;
|
||||||
private final PsiElement myAnchor;
|
private final PsiElement myAnchor;
|
||||||
private final Function1<DeclarationDescriptor, Boolean> myFilter;
|
private final Target myTarget;
|
||||||
|
|
||||||
public JetNameValidatorImpl(PsiElement container, PsiElement anchor, Function1<DeclarationDescriptor, Boolean> filter) {
|
public JetNameValidatorImpl(PsiElement container, PsiElement anchor, Target target) {
|
||||||
super(container.getProject());
|
super(container.getProject());
|
||||||
myContainer = container;
|
myContainer = container;
|
||||||
myAnchor = anchor;
|
myAnchor = anchor;
|
||||||
myFilter = filter;
|
myTarget = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean validateInner(String name) {
|
protected boolean validateInner(String name) {
|
||||||
|
Set<JetScope> visitedScopes = new HashSet<JetScope>();
|
||||||
|
|
||||||
PsiElement sibling;
|
PsiElement sibling;
|
||||||
if (myAnchor != null) {
|
if (myAnchor != null) {
|
||||||
sibling = myAnchor;
|
sibling = myAnchor;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (myContainer instanceof JetExpression) {
|
if (myContainer instanceof JetExpression) {
|
||||||
return checkElement(name, myContainer);
|
return checkElement(name, myContainer, visitedScopes);
|
||||||
}
|
}
|
||||||
sibling = myContainer.getFirstChild();
|
sibling = myContainer.getFirstChild();
|
||||||
}
|
}
|
||||||
|
|
||||||
while (sibling != null) {
|
while (sibling != null) {
|
||||||
if (!checkElement(name, sibling)) return false;
|
if (!checkElement(name, sibling, visitedScopes)) return false;
|
||||||
sibling = sibling.getNextSibling();
|
sibling = sibling.getNextSibling();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkElement(final String name, PsiElement sibling) {
|
private boolean checkElement(String name, PsiElement sibling, final Set<JetScope> visitedScopes) {
|
||||||
if (!(sibling instanceof JetElement)) return true;
|
if (!(sibling instanceof JetElement)) return true;
|
||||||
|
|
||||||
final BindingContext bindingContext = AnalyzerFacadeWithCache.getContextForElement((JetElement) sibling);
|
final BindingContext bindingContext = AnalyzerFacadeWithCache.getContextForElement((JetElement) sibling);
|
||||||
|
final Name identifier = Name.identifier(name);
|
||||||
|
|
||||||
final Ref<Boolean> result = new Ref<Boolean>(true);
|
final Ref<Boolean> result = new Ref<Boolean>(true);
|
||||||
JetVisitorVoid visitor = new JetVisitorVoid() {
|
JetVisitorVoid visitor = new JetVisitorVoid() {
|
||||||
@Override
|
@Override
|
||||||
public void visitElement(PsiElement element) {
|
public void visitElement(@NotNull PsiElement element) {
|
||||||
if (result.get()) {
|
if (result.get()) {
|
||||||
element.acceptChildren(this);
|
element.acceptChildren(this);
|
||||||
}
|
}
|
||||||
@@ -79,13 +87,26 @@ public class JetNameValidatorImpl extends JetNameValidator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitExpression(@NotNull JetExpression expression) {
|
public void visitExpression(@NotNull JetExpression expression) {
|
||||||
Collection<DeclarationDescriptor> variants = TipsManager.getVariantsNoReceiver(expression, bindingContext);
|
JetScope resolutionScope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, expression);
|
||||||
for (DeclarationDescriptor variant : variants) {
|
if (!visitedScopes.add(resolutionScope)) return;
|
||||||
if (variant.getName().asString().equals(name) && myFilter.invoke(variant)) {
|
|
||||||
|
if (resolutionScope != null) {
|
||||||
|
boolean noConflict;
|
||||||
|
if (myTarget == Target.PROPERTIES) {
|
||||||
|
noConflict = resolutionScope.getProperties(identifier).isEmpty()
|
||||||
|
&& resolutionScope.getLocalVariable(identifier) == null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
noConflict = resolutionScope.getFunctions(identifier).isEmpty()
|
||||||
|
&& resolutionScope.getClassifier(identifier) == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!noConflict) {
|
||||||
result.set(false);
|
result.set(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.visitExpression(expression);
|
super.visitExpression(expression);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+8
-8
@@ -168,8 +168,8 @@ private fun List<Instruction>.analyzeControlFlow(
|
|||||||
is AbstractJumpInstruction -> {
|
is AbstractJumpInstruction -> {
|
||||||
val element = it.getElement()
|
val element = it.getElement()
|
||||||
if (element is JetReturnExpression
|
if (element is JetReturnExpression
|
||||||
|| element is JetBreakExpression
|
|| element is JetBreakExpression
|
||||||
|| element is JetContinueExpression) {
|
|| element is JetContinueExpression) {
|
||||||
jumpExits.add(it)
|
jumpExits.add(it)
|
||||||
}
|
}
|
||||||
else if (element !is JetThrowExpression) {
|
else if (element !is JetThrowExpression) {
|
||||||
@@ -312,7 +312,7 @@ private fun ExtractionData.inferParametersInfo(
|
|||||||
val varNameValidator = JetNameValidatorImpl(
|
val varNameValidator = JetNameValidatorImpl(
|
||||||
commonParent.getParentByType(javaClass<JetExpression>()),
|
commonParent.getParentByType(javaClass<JetExpression>()),
|
||||||
originalElements.first,
|
originalElements.first,
|
||||||
{ it is VariableDescriptor }
|
JetNameValidatorImpl.Target.PROPERTIES
|
||||||
)
|
)
|
||||||
val modifiedVarDescriptors = localInstructions.getModifiedVarDescriptors(bindingContext)
|
val modifiedVarDescriptors = localInstructions.getModifiedVarDescriptors(bindingContext)
|
||||||
|
|
||||||
@@ -536,7 +536,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
|||||||
val functionNameValidator = JetNameValidatorImpl(
|
val functionNameValidator = JetNameValidatorImpl(
|
||||||
nextSibling.getParent(),
|
nextSibling.getParent(),
|
||||||
nextSibling,
|
nextSibling,
|
||||||
{it is FunctionDescriptor || it is ClassDescriptor}
|
JetNameValidatorImpl.Target.FUNCTIONS_AND_CLASSES
|
||||||
)
|
)
|
||||||
val functionName = JetNameSuggester.suggestNames(controlFlow.returnType, functionNameValidator, DEFAULT_FUNCTION_NAME).first()
|
val functionName = JetNameSuggester.suggestNames(controlFlow.returnType, functionNameValidator, DEFAULT_FUNCTION_NAME).first()
|
||||||
|
|
||||||
@@ -584,12 +584,12 @@ fun ExtractionDescriptor.validate(): ExtractionDescriptorWithConflicts {
|
|||||||
} as? PsiNamedElement
|
} as? PsiNamedElement
|
||||||
if (currentTarget is JetParameter && currentTarget.getParent() == function.getValueParameterList()) continue
|
if (currentTarget is JetParameter && currentTarget.getParent() == function.getValueParameterList()) continue
|
||||||
if (currentDescriptor is LocalVariableDescriptor
|
if (currentDescriptor is LocalVariableDescriptor
|
||||||
&& parameters.any { it.mirrorVarName == currentDescriptor.getName().asString() }) continue
|
&& parameters.any { it.mirrorVarName == currentDescriptor.getName().asString() }) continue
|
||||||
|
|
||||||
if (diagnostics.any { it.getFactory() == Errors.UNRESOLVED_REFERENCE }
|
if (diagnostics.any { it.getFactory() == Errors.UNRESOLVED_REFERENCE }
|
||||||
|| (currentDescriptor != null
|
|| (currentDescriptor != null
|
||||||
&& !ErrorUtils.isError(currentDescriptor)
|
&& !ErrorUtils.isError(currentDescriptor)
|
||||||
&& !compareDescriptors(currentDescriptor, resolveResult.descriptor))) {
|
&& !compareDescriptors(currentDescriptor, resolveResult.descriptor))) {
|
||||||
conflicts.putValue(
|
conflicts.putValue(
|
||||||
currentRefExpr,
|
currentRefExpr,
|
||||||
JetRefactoringBundle.message(
|
JetRefactoringBundle.message(
|
||||||
|
|||||||
+1
-7
@@ -195,13 +195,7 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
|
|||||||
JetNameValidatorImpl validator = new JetNameValidatorImpl(
|
JetNameValidatorImpl validator = new JetNameValidatorImpl(
|
||||||
commonContainer,
|
commonContainer,
|
||||||
calculateAnchor(commonParent, commonContainer, allReplaces),
|
calculateAnchor(commonParent, commonContainer, allReplaces),
|
||||||
new Function1<DeclarationDescriptor, Boolean>() {
|
JetNameValidatorImpl.Target.PROPERTIES
|
||||||
@Override
|
|
||||||
public Boolean invoke(DeclarationDescriptor descriptor) {
|
|
||||||
return descriptor instanceof VariableDescriptor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
);
|
);
|
||||||
String[] suggestedNames = JetNameSuggester.suggestNames(expression, validator, "value");
|
String[] suggestedNames = JetNameSuggester.suggestNames(expression, validator, "value");
|
||||||
final LinkedHashSet<String> suggestedNamesSet = new LinkedHashSet<String>();
|
final LinkedHashSet<String> suggestedNamesSet = new LinkedHashSet<String>();
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun foo() {
|
||||||
|
val a = 1
|
||||||
|
// NEXT_SIBLING
|
||||||
|
if (<selection>a > 0</selection>) {
|
||||||
|
fun b(): Int { return 0 }
|
||||||
|
println(b())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
fun foo() {
|
||||||
|
val a = 1
|
||||||
|
// NEXT_SIBLING
|
||||||
|
fun b1(): Boolean {
|
||||||
|
return a > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b1()) {
|
||||||
|
fun b(): Int { return 0 }
|
||||||
|
println(b())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo() {
|
||||||
|
val a = 1
|
||||||
|
if (<selection>a > 0</selection>) {
|
||||||
|
val b = 0
|
||||||
|
println(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun foo() {
|
||||||
|
val a = 1
|
||||||
|
val b1 = a > 0
|
||||||
|
if (b1) {
|
||||||
|
val b = 0
|
||||||
|
println(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -128,6 +128,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doIntroduceVariableTest("idea/testData/refactoring/introduceVariable/ManyOccurrences.kt");
|
doIntroduceVariableTest("idea/testData/refactoring/introduceVariable/ManyOccurrences.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("noConflictWithInnerVariable.kt")
|
||||||
|
public void testNoConflictWithInnerVariable() throws Exception {
|
||||||
|
doIntroduceVariableTest("idea/testData/refactoring/introduceVariable/noConflictWithInnerVariable.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nonEquivalentReceivers.kt")
|
@TestMetadata("nonEquivalentReceivers.kt")
|
||||||
public void testNonEquivalentReceivers() throws Exception {
|
public void testNonEquivalentReceivers() throws Exception {
|
||||||
doIntroduceVariableTest("idea/testData/refactoring/introduceVariable/nonEquivalentReceivers.kt");
|
doIntroduceVariableTest("idea/testData/refactoring/introduceVariable/nonEquivalentReceivers.kt");
|
||||||
@@ -238,6 +243,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/misdirectedRef.kt");
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/misdirectedRef.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("noConflictWithInnerFunction.kt")
|
||||||
|
public void testNoConflictWithInnerFunction() throws Exception {
|
||||||
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/noConflictWithInnerFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("privateMemberRef.kt")
|
@TestMetadata("privateMemberRef.kt")
|
||||||
public void testPrivateMemberRef() throws Exception {
|
public void testPrivateMemberRef() throws Exception {
|
||||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/privateMemberRef.kt");
|
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/privateMemberRef.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user