From 94402c5f3f429e89f2a61fbe2a3745c0a5dd7291 Mon Sep 17 00:00:00 2001 From: Alefas Date: Wed, 15 Feb 2012 15:51:11 +0400 Subject: [PATCH] Name validator for introduce variable action. --- .../jetbrains/jet/compiler/TipsManager.java | 44 +++++----- .../refactoring/JetNameValidatorImpl.java | 82 +++++++++++++++++-- .../JetIntroduceVariableHandler.java | 53 +++++++----- 3 files changed, 132 insertions(+), 47 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/TipsManager.java b/compiler/backend/src/org/jetbrains/jet/compiler/TipsManager.java index 8fb0c59e9d8..5b1281de6cb 100644 --- a/compiler/backend/src/org/jetbrains/jet/compiler/TipsManager.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/TipsManager.java @@ -68,32 +68,34 @@ public final class TipsManager { excludePrivateDescriptors(expressionType.getMemberScope().getAllDescriptors()), resolutionScope, new ExpressionReceiver(receiverExpression, expressionType)); } + return Collections.emptyList(); } else { - JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression); - if (resolutionScope != null) { - if (expression.getParent() instanceof JetImportDirective || expression.getParent() instanceof JetNamespaceHeader) { - return excludeNonPackageDescriptors(resolutionScope.getAllDescriptors()); - } else { - HashSet descriptorsSet = Sets.newHashSet(); - - ArrayList result = new ArrayList(); - resolutionScope.getImplicitReceiversHierarchy(result); - - for (ReceiverDescriptor receiverDescriptor : result) { - JetType receiverType = receiverDescriptor.getType(); - descriptorsSet.addAll(receiverType.getMemberScope().getAllDescriptors()); - } - - descriptorsSet.addAll(resolutionScope.getAllDescriptors()); - return excludeNotCallableExtensions(excludePrivateDescriptors(descriptorsSet), resolutionScope); - } - } + return getVariantsNoReceiver(expression, context); } - - return Collections.emptyList(); } + public static Collection getVariantsNoReceiver(JetExpression expression, BindingContext context) { + JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression); + if (resolutionScope != null) { + if (expression.getParent() instanceof JetImportDirective || expression.getParent() instanceof JetNamespaceHeader) { + return excludeNonPackageDescriptors(resolutionScope.getAllDescriptors()); + } else { + HashSet descriptorsSet = Sets.newHashSet(); + ArrayList result = new ArrayList(); + resolutionScope.getImplicitReceiversHierarchy(result); + + for (ReceiverDescriptor receiverDescriptor : result) { + JetType receiverType = receiverDescriptor.getType(); + descriptorsSet.addAll(receiverType.getMemberScope().getAllDescriptors()); + } + + descriptorsSet.addAll(resolutionScope.getAllDescriptors()); + return excludeNotCallableExtensions(excludePrivateDescriptors(descriptorsSet), resolutionScope); + } + } + return Collections.emptyList(); + } public static Collection excludePrivateDescriptors( @NotNull Collection descriptors) { diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameValidatorImpl.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameValidatorImpl.java index b9c8126df81..f6884d5b77c 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameValidatorImpl.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetNameValidatorImpl.java @@ -17,8 +17,22 @@ package org.jetbrains.jet.plugin.refactoring; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.compiler.TipsManager; +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.JetFile; +import org.jetbrains.jet.lang.psi.JetVisitorVoid; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; /** * User: Alefas @@ -39,18 +53,76 @@ public class JetNameValidatorImpl implements JetNameValidator { }; } - private final PsiElement myPlace; + private final PsiElement myContainer; + private PsiElement myAnchor; + BindingContext myBindingContext; - public JetNameValidatorImpl(PsiElement place) { - myPlace = place; + public JetNameValidatorImpl(PsiElement container, PsiElement anchor) { + myContainer = container; + myAnchor = anchor; } @Nullable public String validateName(String name) { - return name; + if (validateInner(name)) return name; + int i = 1; + while (true) { + if (validateInner(name + i)) return name + i; + ++i; + } + } + + private boolean validateInner(String name) { + PsiElement sibling; + if (myAnchor != null) { + sibling = myAnchor; + } else { + if (myContainer instanceof JetExpression) { + return checkElement(name, myContainer); + } + sibling = myContainer.getFirstChild(); + } + + while (sibling != null) { + if (!checkElement(name, sibling)) return false; + sibling = sibling.getNextSibling(); + } + + return true; + } + + private boolean checkElement(final String name, PsiElement sibling) { + if (myBindingContext == null) { + myBindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile( + (JetFile) myContainer.getContainingFile()); + } + final Ref result = new Ref(true); + JetVisitorVoid visitor = new JetVisitorVoid() { + @Override + public void visitElement(PsiElement element) { + if (result.get()) { + element.acceptChildren(this); + } + } + + @Override + public void visitExpression(JetExpression expression) { + Collection variants = + TipsManager.getVariantsNoReceiver(expression, myBindingContext); + for (DeclarationDescriptor variant : variants) { + if (variant.getName().equals(name)) { + result.set(false); + return; + } + } + super.visitExpression(expression); + } + }; + sibling.accept(visitor); + return result.get(); } public Project getProject() { - return myPlace.getProject(); + return myContainer.getProject(); } } diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/introduceVariable/JetIntroduceVariableHandler.java b/idea/src/org/jetbrains/jet/plugin/refactoring/introduceVariable/JetIntroduceVariableHandler.java index 6e5382b8612..3208e0be9c9 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/introduceVariable/JetIntroduceVariableHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/introduceVariable/JetIntroduceVariableHandler.java @@ -128,11 +128,15 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase { allReplaces = Collections.singletonList(expression); } - String[] suggestedNames = JetNameSuggester.suggestNames(expression, new JetNameValidatorImpl(expression)); - final LinkedHashSet suggestedNamesSet = new LinkedHashSet(); - Collections.addAll(suggestedNamesSet, suggestedNames); PsiElement commonParent = PsiTreeUtil.findCommonParent(allReplaces); PsiElement commonContainer = getContainer(commonParent); + JetNameValidatorImpl validator = new JetNameValidatorImpl(commonContainer, + calculateAnchor(commonParent, + commonContainer, + allReplaces)); + String[] suggestedNames = JetNameSuggester.suggestNames(expression, validator); + final LinkedHashSet suggestedNamesSet = new LinkedHashSet(); + Collections.addAll(suggestedNamesSet, suggestedNames); final Ref propertyRef = new Ref(); final ArrayList references = new ArrayList(); final Ref reference = new Ref(); @@ -192,23 +196,8 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase { } else variableText += expression.getText(); JetProperty property = JetPsiFactory.createProperty(project, variableText); if (property == null) return; - PsiElement anchor = commonParent; - if (anchor != commonContainer) { - while (anchor.getParent() != commonContainer) { - anchor = anchor.getParent(); - } - } else { - anchor = commonContainer.getFirstChild(); - int startOffset = commonContainer.getTextRange().getEndOffset(); - for (JetExpression expr : allReplaces) { - int offset = expr.getTextRange().getStartOffset(); - if (offset < startOffset) startOffset = offset; - } - while (anchor != null && !anchor.getTextRange().contains(startOffset)) { - anchor = anchor.getNextSibling(); - } - if (anchor == null) return; - } + PsiElement anchor = calculateAnchor(commonParent, commonContainer, allReplaces); + if (anchor == null) return; boolean needBraces = !(commonContainer instanceof JetBlockExpression || commonContainer instanceof JetClassBody || commonContainer instanceof JetClassInitializer); @@ -263,7 +252,29 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase { } }; } - + + private static PsiElement calculateAnchor(PsiElement commonParent, PsiElement commonContainer, + List allReplaces) { + PsiElement anchor = commonParent; + if (anchor != commonContainer) { + while (anchor.getParent() != commonContainer) { + anchor = anchor.getParent(); + } + } else { + anchor = commonContainer.getFirstChild(); + int startOffset = commonContainer.getTextRange().getEndOffset(); + for (JetExpression expr : allReplaces) { + int offset = expr.getTextRange().getStartOffset(); + if (offset < startOffset) startOffset = offset; + } + while (anchor != null && !anchor.getTextRange().contains(startOffset)) { + anchor = anchor.getNextSibling(); + } + if (anchor == null) return null; + } + return anchor; + } + private static ArrayList findOccurrences(PsiElement occurrenceContainer, @NotNull JetExpression expression) { if (expression instanceof JetParenthesizedExpression) { JetParenthesizedExpression parenthesizedExpression = (JetParenthesizedExpression) expression;