IDEA-91838 Complete instance members from static inner class

This commit is contained in:
peter
2012-10-13 17:33:08 +02:00
parent af9432cc45
commit af44ecd7cf
8 changed files with 105 additions and 28 deletions
@@ -17,6 +17,7 @@ package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor;
import com.intellij.codeInsight.daemon.impl.quickfix.ImportClassFix;
import com.intellij.codeInsight.hint.ShowParameterInfoHandler;
import com.intellij.codeInsight.lookup.*;
@@ -276,7 +277,7 @@ public class JavaCompletionContributor extends CompletionContributor {
private static Set<String> addReferenceVariants(final CompletionParameters parameters, CompletionResultSet result, final InheritorsHolder inheritors) {
final Set<String> usedWords = new HashSet<String>();
final PsiElement position = parameters.getPosition();
final boolean checkAccess = parameters.getInvocationCount() <= 1;
final boolean first = parameters.getInvocationCount() <= 1;
final boolean isSwitchLabel = SWITCH_LABEL.accepts(position);
final boolean isAfterNew = JavaClassNameCompletionContributor.AFTER_NEW.accepts(position);
final boolean pkgContext = JavaCompletionUtil.inSomePackage(position);
@@ -286,10 +287,15 @@ public class JavaCompletionContributor extends CompletionContributor {
final ElementFilter filter = getReferenceFilter(position);
if (filter != null) {
final PsiFile originalFile = parameters.getOriginalFile();
JavaCompletionProcessor.Options options =
JavaCompletionProcessor.Options.DEFAULT_OPTIONS
.withCheckAccess(first)
.withFilterStaticAfterInstance(first)
.withShowInstanceInStaticContext(!first);
for (LookupElement element : JavaCompletionUtil.processJavaReference(position,
(PsiJavaReference)reference,
new ElementExtractorFilter(filter),
checkAccess, checkAccess,
options,
result.getPrefixMatcher(), parameters)) {
if (inheritors.alreadyProcessed(element)) {
continue;
@@ -429,7 +435,7 @@ public class JavaCompletionContributor extends CompletionContributor {
if (showClasses && insertedElement.getParent() instanceof PsiReferenceExpression) {
final Set<LookupElement> set = JavaCompletionUtil.processJavaReference(
insertedElement, (PsiJavaReference)insertedElement.getParent(), TrueFilter.INSTANCE, true, false, result.getPrefixMatcher(), parameters);
insertedElement, (PsiJavaReference)insertedElement.getParent(), TrueFilter.INSTANCE, JavaCompletionProcessor.Options.DEFAULT_OPTIONS, result.getPrefixMatcher(), parameters);
for (final LookupElement element : set) {
result.addElement(element);
}
@@ -324,7 +324,8 @@ public class JavaCompletionUtil {
}
public static Set<LookupElement> processJavaReference(PsiElement element, PsiJavaReference javaReference, ElementFilter elementFilter,
final boolean checkAccess, boolean filterStaticAfterInstance, final PrefixMatcher matcher, CompletionParameters parameters) {
JavaCompletionProcessor.Options options,
final PrefixMatcher matcher, CompletionParameters parameters) {
final Set<LookupElement> set = new LinkedHashSet<LookupElement>();
final Condition<String> nameCondition = new Condition<String>() {
public boolean value(String s) {
@@ -335,7 +336,7 @@ public class JavaCompletionUtil {
PsiMethodCallExpression call = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class);
boolean checkInitialized = parameters.getInvocationCount() <= 1 && call != null && PsiKeyword.SUPER.equals(call.getMethodExpression().getText());
final JavaCompletionProcessor processor = new JavaCompletionProcessor(element, elementFilter, checkAccess, checkInitialized, filterStaticAfterInstance, nameCondition);
final JavaCompletionProcessor processor = new JavaCompletionProcessor(element, elementFilter, options.withInitialized(checkInitialized), nameCondition);
final PsiType plainQualifier = processor.getQualifierType();
PsiType qualifierType = plainQualifier;
@@ -28,6 +28,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorModificationUtil;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.patterns.PsiJavaPatterns;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.*;
@@ -75,7 +76,7 @@ public class JavaDocCompletionContributor extends CompletionContributor {
if (ref instanceof PsiJavaReference) {
result.stopHere();
final JavaCompletionProcessor processor = new JavaCompletionProcessor(position, TrueFilter.INSTANCE, false, false, false, null);
final JavaCompletionProcessor processor = new JavaCompletionProcessor(position, TrueFilter.INSTANCE, JavaCompletionProcessor.Options.CHECK_NOTHING, Condition.TRUE);
((PsiJavaReference) ref).processVariants(processor);
for (final CompletionElement _item : processor.getResults()) {
@@ -16,6 +16,7 @@
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.*;
import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor;
import com.intellij.codeInsight.lookup.*;
import com.intellij.openapi.util.Key;
import com.intellij.patterns.ElementPattern;
@@ -396,7 +397,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
if (reference instanceof PsiJavaReference) {
final PsiJavaReference javaReference = (PsiJavaReference)reference;
return JavaCompletionUtil.processJavaReference(element, javaReference, new ElementFilter() {
ElementFilter checkClass = new ElementFilter() {
public boolean isAcceptable(Object element, PsiElement context) {
return filter.isAcceptable(element, context);
}
@@ -413,7 +414,10 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
}
return false;
}
}, true, parameters.getInvocationCount() <= 1, matcher, parameters);
};
JavaCompletionProcessor.Options options =
JavaCompletionProcessor.Options.DEFAULT_OPTIONS.withFilterStaticAfterInstance(parameters.getInvocationCount() <= 1);
return JavaCompletionUtil.processJavaReference(element, javaReference, checkClass, options, matcher, parameters);
}
return Collections.emptySet();
@@ -51,7 +51,7 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
private boolean myStatic = false;
private PsiElement myDeclarationHolder = null;
private final Set<Object> myResultNames = new THashSet<Object>();
private final List<CompletionElement> myResults;
private final List<CompletionElement> myResults = new ArrayList<CompletionElement>();
private final PsiElement myElement;
private final PsiElement myScope;
private final ElementFilter myFilter;
@@ -59,13 +59,12 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
private PsiType myQualifierType = null;
private PsiClass myQualifierClass = null;
private final Condition<String> myMatcher;
private final boolean myCheckAccess;
private final Options myOptions;
private final Set<PsiField> myNonInitializedFields = new HashSet<PsiField>();
private boolean myAllowStaticWithInstanceQualifier;
public JavaCompletionProcessor(PsiElement element, ElementFilter filter, final boolean checkAccess, boolean checkInitialized, boolean filterStaticAfterInstance, @Nullable Condition<String> nameCondition) {
myCheckAccess = checkAccess;
myResults = new ArrayList<CompletionElement>();
public JavaCompletionProcessor(@NotNull PsiElement element, ElementFilter filter, Options options, @NotNull Condition<String> nameCondition) {
myOptions = options;
myElement = element;
myMatcher = nameCondition;
myFilter = filter;
@@ -106,11 +105,11 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
}
}
if (checkInitialized) {
if (myOptions.checkInitialized) {
myNonInitializedFields.addAll(getNonInitializedFields(element));
}
myAllowStaticWithInstanceQualifier = !filterStaticAfterInstance || CodeInsightSettings.getInstance().SHOW_STATIC_AFTER_INSTANCE ||
myAllowStaticWithInstanceQualifier = !options.filterStaticAfterInstance || CodeInsightSettings.getInstance().SHOW_STATIC_AFTER_INSTANCE ||
SuppressManager.getInstance()
.isSuppressedFor(element, AccessStaticViaInstance.ACCESS_STATIC_VIA_INSTANCE);
@@ -199,17 +198,16 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
return true;
}
final PsiElement elementParent = myElement.getParent();
if (!(elementParent instanceof PsiMethodReferenceExpression) && checkStaticFlag(element)) return true;
if (!(myElement.getParent() instanceof PsiMethodReferenceExpression) && !isStaticsOk(element)) {
return true;
}
if (element instanceof PsiPackage && myScope instanceof PsiClass) {
if (!(elementParent instanceof PsiQualifiedReference && ((PsiQualifiedReference)elementParent).getQualifier() != null)) {
return true;
}
if (element instanceof PsiPackage && myScope instanceof PsiClass && !isQualifiedContext()) {
return true;
}
if (satisfies(element, state) && isAccessible(element)) {
CompletionElement element1 = new CompletionElement((PsiNamedElement)element, state.get(PsiSubstitutor.KEY));
CompletionElement element1 = new CompletionElement(element, state.get(PsiSubstitutor.KEY));
if (myResultNames.add(element1.getUniqueId())) {
myResults.add(element1);
}
@@ -217,13 +215,21 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
return true;
}
private boolean checkStaticFlag(PsiElement element) {
private boolean isQualifiedContext() {
final PsiElement elementParent = myElement.getParent();
return elementParent instanceof PsiQualifiedReference && ((PsiQualifiedReference)elementParent).getQualifier() != null;
}
private boolean isStaticsOk(PsiElement element) {
if (myOptions.showInstanceInStaticContext && !isQualifiedContext()) {
return true;
}
if (!(element instanceof PsiClass) && element instanceof PsiModifierListOwner) {
PsiModifierListOwner modifierListOwner = (PsiModifierListOwner)element;
if (myStatic) {
if (!modifierListOwner.hasModifierProperty(PsiModifier.STATIC)) {
// we don't need non static method in static context.
return true;
return false;
}
}
else {
@@ -231,16 +237,16 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
&& modifierListOwner.hasModifierProperty(PsiModifier.STATIC)
&& !myMembersFlag) {
// according settings we don't need to process such fields/methods
return true;
return false;
}
}
}
return false;
return true;
}
public boolean satisfies(@NotNull PsiElement element, @NotNull ResolveState state) {
final String name = PsiUtilCore.getName(element);
if (StringUtil.isNotEmpty(name) && (myMatcher == null || myMatcher.value(name))) {
if (name != null && StringUtil.isNotEmpty(name) && myMatcher.value(name)) {
if (myFilter.isClassAcceptable(element.getClass()) && myFilter.isAcceptable(new CandidateInfo(element, state.get(PsiSubstitutor.KEY)), myElement)) {
return true;
}
@@ -254,7 +260,7 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
}
private boolean isAccessible(final PsiElement element) {
if (!myCheckAccess) return true;
if (!myOptions.checkAccess) return true;
if (!(element instanceof PsiMember)) return true;
PsiMember member = (PsiMember)element;
@@ -302,12 +308,43 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
@Override
public <T> T getHint(@NotNull Key<T> hintKey) {
if (hintKey == ElementClassHint.KEY) {
//noinspection unchecked
return (T)this;
}
if (hintKey == JavaCompletionHints.NAME_FILTER) {
//noinspection unchecked
return (T)myMatcher;
}
return super.getHint(hintKey);
}
public static class Options {
public static final Options DEFAULT_OPTIONS = new Options(true, false, true, false);
public static final Options CHECK_NOTHING = new Options(false, false, false, false);
final boolean checkAccess;
final boolean checkInitialized;
final boolean filterStaticAfterInstance;
final boolean showInstanceInStaticContext;
private Options(boolean checkAccess, boolean checkInitialized, boolean filterStaticAfterInstance, boolean showInstanceInStaticContext) {
this.checkAccess = checkAccess;
this.checkInitialized = checkInitialized;
this.filterStaticAfterInstance = filterStaticAfterInstance;
this.showInstanceInStaticContext = showInstanceInStaticContext;
}
public Options withInitialized(boolean checkInitialized) {
return new Options(checkAccess, checkInitialized, filterStaticAfterInstance, showInstanceInStaticContext);
}
public Options withCheckAccess(boolean checkAccess) {
return new Options(checkAccess, checkInitialized, filterStaticAfterInstance, showInstanceInStaticContext);
}
public Options withFilterStaticAfterInstance(boolean filterStaticAfterInstance) {
return new Options(checkAccess, checkInitialized, filterStaticAfterInstance, showInstanceInStaticContext);
}
public Options withShowInstanceInStaticContext(boolean showInstanceInStaticContext) {
return new Options(checkAccess, checkInitialized, filterStaticAfterInstance, showInstanceInStaticContext);
}
}
}
@@ -0,0 +1,11 @@
public class Inspection {
public boolean ignoreEnums = false;
private static class Visitor {
public void visitClass() {
if (ignoen<caret>) {
}
}
}
}
@@ -0,0 +1,11 @@
public class Inspection {
public boolean ignoreEnums = false;
private static class Visitor {
public void visitClass() {
if (ignoreEnums<caret>) {
}
}
}
}
@@ -497,6 +497,12 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase {
checkResult()
}
public void testAccessInstanceFromStaticSecond() throws Throwable {
configure()
myFixture.complete(CompletionType.BASIC, 2)
checkResult()
}
public void testContinueLabel() throws Throwable { doTest(); }
public void testAnonymousProcess() {