Name validator for introduce variable action.

This commit is contained in:
Alefas
2012-02-15 15:51:11 +04:00
parent 2ec05429b8
commit 94402c5f3f
3 changed files with 132 additions and 47 deletions
@@ -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<DeclarationDescriptor> descriptorsSet = Sets.newHashSet();
ArrayList<ReceiverDescriptor> result = new ArrayList<ReceiverDescriptor>();
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<DeclarationDescriptor> 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<DeclarationDescriptor> descriptorsSet = Sets.newHashSet();
ArrayList<ReceiverDescriptor> result = new ArrayList<ReceiverDescriptor>();
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<DeclarationDescriptor> excludePrivateDescriptors(
@NotNull Collection<DeclarationDescriptor> descriptors) {
@@ -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<Boolean> result = new Ref<Boolean>(true);
JetVisitorVoid visitor = new JetVisitorVoid() {
@Override
public void visitElement(PsiElement element) {
if (result.get()) {
element.acceptChildren(this);
}
}
@Override
public void visitExpression(JetExpression expression) {
Collection<DeclarationDescriptor> 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();
}
}
@@ -128,11 +128,15 @@ public class JetIntroduceVariableHandler extends JetIntroduceHandlerBase {
allReplaces = Collections.singletonList(expression);
}
String[] suggestedNames = JetNameSuggester.suggestNames(expression, new JetNameValidatorImpl(expression));
final LinkedHashSet<String> suggestedNamesSet = new LinkedHashSet<String>();
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<String> suggestedNamesSet = new LinkedHashSet<String>();
Collections.addAll(suggestedNamesSet, suggestedNames);
final Ref<JetProperty> propertyRef = new Ref<JetProperty>();
final ArrayList<JetExpression> references = new ArrayList<JetExpression>();
final Ref<JetExpression> reference = new Ref<JetExpression>();
@@ -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<JetExpression> 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<JetExpression> findOccurrences(PsiElement occurrenceContainer, @NotNull JetExpression expression) {
if (expression instanceof JetParenthesizedExpression) {
JetParenthesizedExpression parenthesizedExpression = (JetParenthesizedExpression) expression;