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.psi.PsiElement;
|
||||
import kotlin.Function1;
|
||||
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.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetVisitorVoid;
|
||||
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 java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class JetNameValidatorImpl extends JetNameValidator {
|
||||
public static enum Target {
|
||||
FUNCTIONS_AND_CLASSES,
|
||||
PROPERTIES
|
||||
}
|
||||
|
||||
private final PsiElement myContainer;
|
||||
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());
|
||||
myContainer = container;
|
||||
myAnchor = anchor;
|
||||
myFilter = filter;
|
||||
myTarget = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateInner(String name) {
|
||||
Set<JetScope> visitedScopes = new HashSet<JetScope>();
|
||||
|
||||
PsiElement sibling;
|
||||
if (myAnchor != null) {
|
||||
sibling = myAnchor;
|
||||
}
|
||||
else {
|
||||
if (myContainer instanceof JetExpression) {
|
||||
return checkElement(name, myContainer);
|
||||
return checkElement(name, myContainer, visitedScopes);
|
||||
}
|
||||
sibling = myContainer.getFirstChild();
|
||||
}
|
||||
|
||||
while (sibling != null) {
|
||||
if (!checkElement(name, sibling)) return false;
|
||||
if (!checkElement(name, sibling, visitedScopes)) return false;
|
||||
sibling = sibling.getNextSibling();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
JetVisitorVoid visitor = new JetVisitorVoid() {
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
public void visitElement(@NotNull PsiElement element) {
|
||||
if (result.get()) {
|
||||
element.acceptChildren(this);
|
||||
}
|
||||
@@ -79,13 +87,26 @@ public class JetNameValidatorImpl extends JetNameValidator {
|
||||
|
||||
@Override
|
||||
public void visitExpression(@NotNull JetExpression expression) {
|
||||
Collection<DeclarationDescriptor> variants = TipsManager.getVariantsNoReceiver(expression, bindingContext);
|
||||
for (DeclarationDescriptor variant : variants) {
|
||||
if (variant.getName().asString().equals(name) && myFilter.invoke(variant)) {
|
||||
JetScope resolutionScope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, expression);
|
||||
if (!visitedScopes.add(resolutionScope)) return;
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.visitExpression(expression);
|
||||
}
|
||||
};
|
||||
|
||||
+8
-8
@@ -168,8 +168,8 @@ private fun List<Instruction>.analyzeControlFlow(
|
||||
is AbstractJumpInstruction -> {
|
||||
val element = it.getElement()
|
||||
if (element is JetReturnExpression
|
||||
|| element is JetBreakExpression
|
||||
|| element is JetContinueExpression) {
|
||||
|| element is JetBreakExpression
|
||||
|| element is JetContinueExpression) {
|
||||
jumpExits.add(it)
|
||||
}
|
||||
else if (element !is JetThrowExpression) {
|
||||
@@ -312,7 +312,7 @@ private fun ExtractionData.inferParametersInfo(
|
||||
val varNameValidator = JetNameValidatorImpl(
|
||||
commonParent.getParentByType(javaClass<JetExpression>()),
|
||||
originalElements.first,
|
||||
{ it is VariableDescriptor }
|
||||
JetNameValidatorImpl.Target.PROPERTIES
|
||||
)
|
||||
val modifiedVarDescriptors = localInstructions.getModifiedVarDescriptors(bindingContext)
|
||||
|
||||
@@ -536,7 +536,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
||||
val functionNameValidator = JetNameValidatorImpl(
|
||||
nextSibling.getParent(),
|
||||
nextSibling,
|
||||
{it is FunctionDescriptor || it is ClassDescriptor}
|
||||
JetNameValidatorImpl.Target.FUNCTIONS_AND_CLASSES
|
||||
)
|
||||
val functionName = JetNameSuggester.suggestNames(controlFlow.returnType, functionNameValidator, DEFAULT_FUNCTION_NAME).first()
|
||||
|
||||
@@ -584,12 +584,12 @@ fun ExtractionDescriptor.validate(): ExtractionDescriptorWithConflicts {
|
||||
} as? PsiNamedElement
|
||||
if (currentTarget is JetParameter && currentTarget.getParent() == function.getValueParameterList()) continue
|
||||
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 }
|
||||
|| (currentDescriptor != null
|
||||
&& !ErrorUtils.isError(currentDescriptor)
|
||||
&& !compareDescriptors(currentDescriptor, resolveResult.descriptor))) {
|
||||
|| (currentDescriptor != null
|
||||
&& !ErrorUtils.isError(currentDescriptor)
|
||||
&& !compareDescriptors(currentDescriptor, resolveResult.descriptor))) {
|
||||
conflicts.putValue(
|
||||
currentRefExpr,
|
||||
JetRefactoringBundle.message(
|
||||
|
||||
+1
-7
@@ -195,13 +195,7 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase {
|
||||
JetNameValidatorImpl validator = new JetNameValidatorImpl(
|
||||
commonContainer,
|
||||
calculateAnchor(commonParent, commonContainer, allReplaces),
|
||||
new Function1<DeclarationDescriptor, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(DeclarationDescriptor descriptor) {
|
||||
return descriptor instanceof VariableDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
JetNameValidatorImpl.Target.PROPERTIES
|
||||
);
|
||||
String[] suggestedNames = JetNameSuggester.suggestNames(expression, validator, "value");
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("noConflictWithInnerVariable.kt")
|
||||
public void testNoConflictWithInnerVariable() throws Exception {
|
||||
doIntroduceVariableTest("idea/testData/refactoring/introduceVariable/noConflictWithInnerVariable.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonEquivalentReceivers.kt")
|
||||
public void testNonEquivalentReceivers() throws Exception {
|
||||
doIntroduceVariableTest("idea/testData/refactoring/introduceVariable/nonEquivalentReceivers.kt");
|
||||
@@ -238,6 +243,11 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
||||
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")
|
||||
public void testPrivateMemberRef() throws Exception {
|
||||
doExtractFunctionTest("idea/testData/refactoring/extractFunction/basic/privateMemberRef.kt");
|
||||
|
||||
Reference in New Issue
Block a user