IDEA-69328 Code completion in switch...case: complete other possible values from already ref'd class

This commit is contained in:
peter
2011-12-27 18:17:43 +01:00
parent 8f8976dbba
commit 784c2f101a
7 changed files with 70 additions and 16 deletions
@@ -526,8 +526,7 @@ public class JavaCompletionData extends JavaAwareCompletionData{
if (JavaSmartCompletionContributor.INSIDE_EXPRESSION.accepts(position) &&
!BasicExpressionCompletionContributor.AFTER_DOT.accepts(position) &&
!(position.getParent() instanceof PsiLiteralExpression) &&
!(position.getParent().getParent() instanceof PsiSwitchLabelStatement)) {
!(position.getParent() instanceof PsiLiteralExpression)) {
for (final ExpectedTypeInfo info : JavaSmartCompletionContributor.getExpectedTypes(parameters)) {
new JavaMembersGetter(info.getDefaultType(), position).addMembers(position, parameters.getInvocationCount() > 1, new Consumer<LookupElement>() {
@Override
@@ -354,10 +354,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
boolean quick,
Consumer<LookupElement> consumer) {
PsiElement position = params.getPosition();
final PsiElement parent = position.getParent();
if (!BasicExpressionCompletionContributor.AFTER_DOT.accepts(position) &&
parent != null &&
!(parent.getParent() instanceof PsiSwitchLabelStatement)) {
if (!BasicExpressionCompletionContributor.AFTER_DOT.accepts(position)) {
for (ExpectedTypeInfo info : mergedInfos) {
new JavaMembersGetter(info.getType(), position).addMembers(position, !quick, consumer);
if (!info.getDefaultType().equals(info.getType())) {
@@ -46,6 +46,7 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@@ -149,7 +150,7 @@ public class ReferenceExpressionCompletionContributor {
private static Set<LookupElement> completeFinalReference(final PsiElement element, PsiReference reference, ElementFilter filter,
final JavaSmartCompletionParameters parameters) {
final Set<PsiEnumConstant> used = findConstantsToSkip(element, parameters);
final Set<PsiField> used = parameters.getParameters().getInvocationCount() < 2 ? findConstantsUsedInSwitch(element) : Collections.<PsiField>emptySet();
final Set<LookupElement> elements =
JavaSmartCompletionContributor.completeReference(element, reference, new AndFilter(filter, new ElementFilter() {
@@ -164,7 +165,7 @@ public class ReferenceExpressionCompletionContributor {
}
//noinspection SuspiciousMethodCalls
if (member instanceof PsiEnumConstant && used.contains(member)) {
if (member instanceof PsiEnumConstant && used.contains(CompletionUtil.getOriginalOrSelf(member))) {
return false;
}
@@ -192,11 +193,9 @@ public class ReferenceExpressionCompletionContributor {
return elements;
}
private static Set<PsiEnumConstant> findConstantsToSkip(PsiElement element, JavaSmartCompletionParameters parameters) {
final Set<PsiEnumConstant> used = new HashSet<PsiEnumConstant>();
if (parameters.getParameters().getInvocationCount() < 2 &&
psiElement().withSuperParent(2, psiElement(PsiSwitchLabelStatement.class).withSuperParent(2, PsiSwitchStatement.class))
.accepts(element)) {
public static Set<PsiField> findConstantsUsedInSwitch(PsiElement element) {
final Set<PsiField> used = new HashSet<PsiField>();
if (psiElement().withSuperParent(2, psiElement(PsiSwitchLabelStatement.class).withSuperParent(2, PsiSwitchStatement.class)).accepts(element)) {
PsiSwitchStatement sw = PsiTreeUtil.getParentOfType(element, PsiSwitchStatement.class);
assert sw != null;
final PsiCodeBlock body = sw.getBody();
@@ -206,8 +205,8 @@ public class ReferenceExpressionCompletionContributor {
final PsiExpression value = ((PsiSwitchLabelStatement)statement).getCaseValue();
if (value instanceof PsiReferenceExpression) {
final PsiElement target = ((PsiReferenceExpression)value).resolve();
if (target instanceof PsiEnumConstant) {
used.add((PsiEnumConstant)target);
if (target instanceof PsiField) {
used.add(CompletionUtil.getOriginalOrSelf((PsiField)target));
}
}
}
@@ -15,19 +15,26 @@
*/
package com.intellij.psi.filters.getters;
import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.completion.JavaCompletionUtil;
import com.intellij.codeInsight.completion.JavaMethodCallElement;
import com.intellij.codeInsight.completion.ReferenceExpressionCompletionContributor;
import com.intellij.codeInsight.completion.SmartCompletionDecorator;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.TailTypeDecorator;
import com.intellij.codeInsight.lookup.VariableLookupItem;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.Consumer;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Set;
/**
* @author peter
*/
@@ -40,15 +47,39 @@ public class JavaMembersGetter extends MembersGetter {
myExpectedType = JavaCompletionUtil.originalize(expectedType);
}
public void addMembers(PsiElement position, boolean searchInheritors, Consumer<LookupElement> results) {
public void addMembers(PsiElement position, boolean searchInheritors, final Consumer<LookupElement> results) {
if (myExpectedType instanceof PsiPrimitiveType && PsiType.DOUBLE.isAssignableFrom(myExpectedType)) {
addConstantsFromTargetClass(position, results, searchInheritors);
addConstantsFromReferencedClassesInSwitch(position, results);
}
if (position.getParent().getParent() instanceof PsiSwitchLabelStatement) {
return; //non-enum values are processed above, enum values will be suggested by reference completion
}
final PsiClass psiClass = PsiUtil.resolveClassInType(myExpectedType);
processMembers(position, results, psiClass, PsiTreeUtil.getParentOfType(position, PsiAnnotation.class) != null, searchInheritors);
}
private void addConstantsFromReferencedClassesInSwitch(PsiElement position, final Consumer<LookupElement> results) {
final Set<PsiField> fields = ReferenceExpressionCompletionContributor.findConstantsUsedInSwitch(position);
final Set<PsiClass> classes = new HashSet<PsiClass>();
for (PsiField field : fields) {
ContainerUtil.addIfNotNull(classes, field.getContainingClass());
}
for (PsiClass aClass : classes) {
processMembers(position, new Consumer<LookupElement>() {
@Override
public void consume(LookupElement element) {
//noinspection SuspiciousMethodCalls
if (!fields.contains(element.getObject())) {
results.consume(TailTypeDecorator.withTail(element, TailType.CASE_COLON));
}
}
}, aClass, false, false);
}
}
private void addConstantsFromTargetClass(PsiElement position, Consumer<LookupElement> results, boolean searchInheritors) {
PsiElement parent = position.getParent();
if (!(parent instanceof PsiReferenceExpression)) {
@@ -0,0 +1,13 @@
class Foo {
void foo(int i) {
switch (i) {
case Constants.BAR0: return;
case B<caret>:
}
}
}
interface Constants {
int BAR0 = 0;
int BAR1 = 1;
}
@@ -0,0 +1,13 @@
class Foo {
void foo(int i) {
switch (i) {
case Constants.BAR0: return;
case Constants.BAR1:<caret>
}
}
}
interface Constants {
int BAR0 = 0;
int BAR1 = 1;
}
@@ -985,6 +985,8 @@ public class ListUtils {
public void testNewGenericInterface() throws Throwable { doTest() }
public void testEnumPrivateFinal() throws Throwable { doTest() }
public void testSwitchConstantsFromReferencedClass() throws Throwable { doTest('\n') }
public void testUnfinishedMethodTypeParameter() throws Throwable {
configure()
assertStringItems("MyParameter", "MySecondParameter")