From 0fff99976a624e62f68bd1ff441ecb6d00c131dd Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Fri, 25 Apr 2014 23:58:09 +0400 Subject: [PATCH] Groovy PSI doesn't depends on LookupElements anymore --- .../GroovyCompletionContributor.java | 8 +- .../lang/completion/GroovyCompletionUtil.java | 27 +- .../GroovySmartCompletionContributor.java | 53 ++-- .../groovy/lang/psi/GrReferenceElement.java | 6 - .../CompleteReferenceExpression.java | 261 ++++++++---------- .../CompleteReferencesWithSameQualifier.java | 94 +++++++ .../GrReferenceExpressionImpl.java | 9 - .../GrLightClassReferenceElement.java | 8 - .../types/CompleteCodeReferenceElement.java | 223 +++++++++++++++ .../types/GrCodeReferenceElementImpl.java | 175 +----------- 10 files changed, 483 insertions(+), 381 deletions(-) create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferencesWithSameQualifier.java create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/CompleteCodeReferenceElement.java diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java index 3aec0b1036ff..38a6423d0a20 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java @@ -65,7 +65,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatem import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameter; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameterList; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.CompleteReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.CompleteReferencesWithSameQualifier; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.refactoring.DefaultGroovyVariableNameValidator; @@ -432,8 +432,7 @@ public class GroovyCompletionContributor extends CompletionContributor { final PsiType qualifierType = qualifier instanceof GrExpression ? ((GrExpression)qualifier).getType() : null; if (reference instanceof GrReferenceExpression && (qualifier instanceof GrExpression || qualifier == null)) { - for (String string : CompleteReferenceExpression.getVariantsWithSameQualifier(matcher, (GrExpression)qualifier, - (GrReferenceExpression)reference)) { + for (String string : CompleteReferencesWithSameQualifier.getVariantsWithSameQualifier((GrReferenceExpression)reference, matcher, (GrExpression)qualifier)) { consumer.consume(LookupElementBuilder.create(string).withItemTextUnderlined(true)); } if (parameters.getInvocationCount() < 2 && qualifier != null && qualifierType == null && @@ -446,7 +445,8 @@ public class GroovyCompletionContributor extends CompletionContributor { } final List zeroPriority = newArrayList(); - reference.processVariants(matcher, parameters, new Consumer() { + + GroovyCompletionUtil.processVariants(reference, matcher, parameters, new Consumer() { @Override public void consume(LookupElement lookupElement) { Object object = lookupElement.getObject(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java index e3b6fc6e6ecb..14106fa9dc57 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java @@ -18,10 +18,7 @@ package org.jetbrains.plugins.groovy.lang.completion; import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.codeInsight.TailType; -import com.intellij.codeInsight.completion.AllClassesGetter; -import com.intellij.codeInsight.completion.JavaClassNameCompletionContributor; -import com.intellij.codeInsight.completion.JavaCompletionUtil; -import com.intellij.codeInsight.completion.PrefixMatcher; +import com.intellij.codeInsight.completion.*; import com.intellij.codeInsight.completion.originInfo.OriginInfoProvider; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; @@ -42,6 +39,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.*; +import com.intellij.util.Consumer; import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; @@ -77,6 +75,10 @@ import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.modifiers.GrAnnotationCollector; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.CompleteReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrReferenceExpressionImpl; +import org.jetbrains.plugins.groovy.lang.psi.impl.types.CompleteCodeReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrCodeReferenceElementImpl; import org.jetbrains.plugins.groovy.lang.psi.util.GdkMethodUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil; @@ -289,11 +291,11 @@ public class GroovyCompletionUtil { for (GroovyResolveResult r : importReference.multiResolve(false)) { final PsiElement resolved = r.getElement(); if (context.getManager().areElementsEquivalent(resolved, element) && (alias || !(element instanceof PsiClass))) { - return generateLookupForImportedElement(candidate, importedName, alias); + return generateLookupForImportedElement(candidate, importedName); } else { if (resolved instanceof PsiField && element instanceof PsiMethod && isAccessorFor((PsiMethod)element, (PsiField)resolved)) { - return generateLookupForImportedElement(candidate, getAccessorPrefix((PsiMethod)element) + capitalize(importedName), alias); + return generateLookupForImportedElement(candidate, getAccessorPrefix((PsiMethod)element) + capitalize(importedName)); } } } @@ -330,9 +332,7 @@ public class GroovyCompletionUtil { return AllClassesGetter.createLookupItem(psiClass, new GroovyClassNameInsertHandler()); } - private static List generateLookupForImportedElement(GroovyResolveResult resolveResult, - String importedName, - boolean alias) { + private static List generateLookupForImportedElement(GroovyResolveResult resolveResult, String importedName) { final PsiElement element = resolveResult.getElement(); assert element != null; final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); @@ -672,4 +672,13 @@ public class GroovyCompletionUtil { pparent instanceof GrVariableDeclaration && ((GrVariableDeclaration)pparent).isTuple(); } + + public static void processVariants(GrReferenceElement referenceElement, PrefixMatcher matcher, CompletionParameters parameters, Consumer consumer) { + if (referenceElement instanceof GrCodeReferenceElementImpl) { + CompleteCodeReferenceElement.processVariants((GrCodeReferenceElementImpl)referenceElement, consumer, matcher); + } + else if (referenceElement instanceof GrReferenceExpressionImpl) { + CompleteReferenceExpression.processVariants(matcher, consumer, (GrReferenceExpressionImpl)referenceElement, parameters); + } + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java index c9f6f98c3132..674fad7e55e5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovySmartCompletionContributor.java @@ -107,33 +107,34 @@ public class GroovySmartCompletionContributor extends CompletionContributor { final PsiElement reference = position.getParent(); if (reference == null) return; if (reference instanceof GrReferenceElement) { - ((GrReferenceElement)reference).processVariants(result.getPrefixMatcher(), params, new Consumer() { - public void consume(LookupElement variant) { - PsiType type = null; + GroovyCompletionUtil.processVariants((GrReferenceElement)reference, result.getPrefixMatcher(), params, + new Consumer() { + public void consume(LookupElement variant) { + PsiType type = null; - Object o = variant.getObject(); - if (o instanceof GroovyResolveResult) { - if (!((GroovyResolveResult)o).isAccessible()) return; - o = ((GroovyResolveResult)o).getElement(); - } + Object o = variant.getObject(); + if (o instanceof GroovyResolveResult) { + if (!((GroovyResolveResult)o).isAccessible()) return; + o = ((GroovyResolveResult)o).getElement(); + } - if (o instanceof PsiElement) { - type = getTypeByElement((PsiElement)o, position); - } - else if (o instanceof String) { - if ("true".equals(o) || "false".equals(o)) { - type = PsiType.BOOLEAN; - } - } - if (type == null) return; - for (TypeConstraint info : infos) { - if (info.satisfied(type, position)) { - result.addElement(variant); - break; - } - } - } - }); + if (o instanceof PsiElement) { + type = getTypeByElement((PsiElement)o, position); + } + else if (o instanceof String) { + if ("true".equals(o) || "false".equals(o)) { + type = PsiType.BOOLEAN; + } + } + if (type == null) return; + for (TypeConstraint info : infos) { + if (info.satisfied(type, position)) { + result.addElement(variant); + break; + } + } + } + }); } addExpectedClassMembers(params, result); @@ -225,7 +226,7 @@ public class GroovySmartCompletionContributor extends CompletionContributor { result.addElement(element); } } - }); + }, params); } }); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrReferenceElement.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrReferenceElement.java index d4a076087611..161971d44ed2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrReferenceElement.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/GrReferenceElement.java @@ -15,13 +15,9 @@ */ package org.jetbrains.plugins.groovy.lang.psi; -import com.intellij.codeInsight.completion.CompletionParameters; -import com.intellij.codeInsight.completion.PrefixMatcher; -import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.PsiType; -import com.intellij.util.Consumer; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -48,8 +44,6 @@ public interface GrReferenceElement extends GroovyPsiEleme @Nullable GrTypeArgumentList getTypeArgumentList(); - void processVariants(PrefixMatcher matcher, CompletionParameters parameters, Consumer consumer); - @Nullable String getClassNameText(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java index 5362eb79deb5..85322e0962fe 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java @@ -15,7 +15,6 @@ */ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions; -import com.intellij.codeInsight.PsiEquivalenceUtil; import com.intellij.codeInsight.completion.CompletionParameters; import com.intellij.codeInsight.completion.JavaClassNameCompletionContributor; import com.intellij.codeInsight.completion.PrefixMatcher; @@ -38,7 +37,6 @@ import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionUtil; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; @@ -51,7 +49,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssign import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrReflectedMethod; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; @@ -73,59 +70,76 @@ import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils.*; * @author ven */ public class CompleteReferenceExpression { - private CompleteReferenceExpression() { + private static final Logger LOG = Logger.getInstance(CompleteReferenceExpression.class); + + private final PrefixMatcher myMatcher; + private final Consumer myConsumer; + private final GrReferenceExpressionImpl myRefExpr; + private final CompletionParameters myParameters; + private final CompleteReferenceProcessor myProcessor; + + private CompleteReferenceExpression(@NotNull PrefixMatcher matcher, + @NotNull Consumer consumer, + @NotNull GrReferenceExpressionImpl refExpr, + @NotNull CompletionParameters parameters) { + myMatcher = matcher; + myConsumer = consumer; + myParameters = parameters; + myRefExpr = refExpr; + + myProcessor = new CompleteReferenceProcessor(); + } public static void processVariants(@NotNull PrefixMatcher matcher, - @NotNull final Consumer consumer, + @NotNull Consumer consumer, @NotNull GrReferenceExpressionImpl refExpr, @NotNull CompletionParameters parameters) { - processRefInAnnotation(refExpr, matcher, consumer); + new CompleteReferenceExpression(matcher, consumer, refExpr, parameters).processVariantsImpl(); + } - final int[] count = new int[]{0}; - final CompleteReferenceProcessor processor = new CompleteReferenceProcessor(refExpr, new Consumer() { - @Override - public void consume(LookupElement element) { - count[0]++; - consumer.consume(element); - } - }, matcher, parameters); + private void processVariantsImpl() { + processRefInAnnotationImpl(); - getVariantsImpl(refExpr, processor); - final GroovyResolveResult[] candidates = processor.getCandidates(); + getVariantsImpl(); + final GroovyResolveResult[] candidates = myProcessor.getCandidates(); List results = GroovyCompletionUtil.getCompletionVariants(candidates, - JavaClassNameCompletionContributor.AFTER_NEW.accepts(refExpr), matcher, refExpr); + JavaClassNameCompletionContributor.AFTER_NEW.accepts(myRefExpr), myMatcher, myRefExpr); - if (count[0] == 0 && results.size() == 0) { - results = GroovyCompletionUtil.getCompletionVariants(processor.getInapplicableResults(), - JavaClassNameCompletionContributor.AFTER_NEW.accepts(refExpr), matcher, refExpr); + if (myProcessor.isEmpty() && results.size() == 0) { + results = GroovyCompletionUtil.getCompletionVariants(myProcessor.getInapplicableResults(), + JavaClassNameCompletionContributor.AFTER_NEW.accepts(myRefExpr), myMatcher, + myRefExpr); } for (LookupElement o : results) { - consumer.consume(o); + myConsumer.consume(o); } } public static void processRefInAnnotation(@NotNull GrReferenceExpression refExpr, @NotNull PrefixMatcher matcher, - @NotNull Consumer consumer) { - if (refExpr.getParent() instanceof GrAnnotationNameValuePair && - ((GrAnnotationNameValuePair)refExpr.getParent()).getNameIdentifierGroovy() == null) { - PsiElement parent = refExpr.getParent().getParent(); + @NotNull Consumer consumer, + @NotNull CompletionParameters parameters) { + new CompleteReferenceExpression(matcher, consumer, (GrReferenceExpressionImpl)refExpr, parameters).processRefInAnnotationImpl(); + } + + private void processRefInAnnotationImpl() { + if (myRefExpr.getParent() instanceof GrAnnotationNameValuePair && + ((GrAnnotationNameValuePair)myRefExpr.getParent()).getNameIdentifierGroovy() == null) { + PsiElement parent = myRefExpr.getParent().getParent(); if (!(parent instanceof GrAnnotation)) { parent = parent.getParent(); } if (parent instanceof GrAnnotation) { - for (LookupElement result : GroovyCompletionUtil.getAnnotationCompletionResults((GrAnnotation)parent, matcher)) { - consumer.consume(result); + for (LookupElement result : GroovyCompletionUtil.getAnnotationCompletionResults((GrAnnotation)parent, myMatcher)) { + myConsumer.consume(result); } } } } - private static void processIfJavaLangClass(@NotNull GrReferenceExpression refExpr, - @NotNull ResolverProcessor consumer, - @Nullable PsiType type) { + private void processIfJavaLangClass(@Nullable PsiType type) { if (!(type instanceof PsiClassType)) return; final PsiClass psiClass = ((PsiClassType)type).resolve(); @@ -134,53 +148,51 @@ public class CompleteReferenceExpression { final PsiType[] params = ((PsiClassType)type).getParameters(); if (params.length != 1) return; - getVariantsFromQualifierType(refExpr, consumer, params[0], refExpr.getProject()); + getVariantsFromQualifierType(params[0], myRefExpr.getProject()); } - private static void getVariantsImpl(@NotNull GrReferenceExpression refExpr, - @NotNull CompleteReferenceProcessor processor) { - GrExpression qualifier = refExpr.getQualifierExpression(); + private void getVariantsImpl() { + GrExpression qualifier = myRefExpr.getQualifierExpression(); if (qualifier == null) { - ResolveUtil.treeWalkUp(refExpr, processor, true); + ResolveUtil.treeWalkUp(myRefExpr, myProcessor, true); - for (PsiElement e = refExpr.getParent(); e != null; e = e.getParent()) { + for (PsiElement e = myRefExpr.getParent(); e != null; e = e.getParent()) { if (e instanceof GrClosableBlock) { ResolveState state = ResolveState.initial().put(ResolverProcessor.RESOLVE_CONTEXT, e); for (ClosureMissingMethodContributor contributor : ClosureMissingMethodContributor.EP_NAME.getExtensions()) { - contributor.processMembers((GrClosableBlock)e, processor, refExpr, state); + contributor.processMembers((GrClosableBlock)e, myProcessor, myRefExpr, state); } } } - GrExpression runtimeQualifier = PsiImplUtil.getRuntimeQualifier(refExpr); + GrExpression runtimeQualifier = PsiImplUtil.getRuntimeQualifier(myRefExpr); if (runtimeQualifier != null) { - getVariantsFromQualifier(refExpr, processor, runtimeQualifier); + getVariantsFromQualifier(runtimeQualifier); } - getBindings(refExpr, processor); + getBindings(); } else { - if (refExpr.getDotTokenType() != GroovyTokenTypes.mSPREAD_DOT) { - getVariantsFromQualifier(refExpr, processor, qualifier); + if (myRefExpr.getDotTokenType() != GroovyTokenTypes.mSPREAD_DOT) { + getVariantsFromQualifier(qualifier); if (qualifier instanceof GrReferenceExpression && ("class".equals(((GrReferenceExpression)qualifier).getReferenceName()) || PsiUtil.isThisReference(qualifier) && !PsiUtil.isInstanceThisRef(qualifier))) { - processIfJavaLangClass(refExpr, processor, qualifier.getType()); + processIfJavaLangClass(qualifier.getType()); } } else { - getVariantsFromQualifierForSpreadOperator(refExpr, processor, qualifier); + getVariantsFromQualifierForSpreadOperator(qualifier); } } - ResolveUtil.processCategoryMembers(refExpr, processor, ResolveState.initial()); + ResolveUtil.processCategoryMembers(myRefExpr, myProcessor, ResolveState.initial()); } - private static void getBindings(@NotNull final GrReferenceExpression refExpr, - @NotNull final CompleteReferenceProcessor processor) { - final PsiClass containingClass = PsiTreeUtil.getParentOfType(refExpr, PsiClass.class); + private void getBindings() { + final PsiClass containingClass = PsiTreeUtil.getParentOfType(myRefExpr, PsiClass.class); if (containingClass != null) return; - final PsiFile file = FileContextUtil.getContextFile(refExpr); + final PsiFile file = FileContextUtil.getContextFile(myRefExpr); if (file instanceof GroovyFile) { ((GroovyFile)file).accept(new GroovyRecursiveElementVisitor() { @Override @@ -191,10 +203,10 @@ public class CompleteReferenceExpression { if (value instanceof GrReferenceExpression && !((GrReferenceExpression)value).isQualified()) { final PsiElement resolved = ((GrReferenceExpression)value).resolve(); if (resolved instanceof GrBindingVariable) { - processor.execute(resolved, ResolveState.initial()); + myProcessor.execute(resolved, ResolveState.initial()); } else if (resolved == null) { - processor.execute(new GrBindingVariable((GroovyFile)file, ((GrReferenceExpression)value).getReferenceName(), true), + myProcessor.execute(new GrBindingVariable((GroovyFile)file, ((GrReferenceExpression)value).getReferenceName(), true), ResolveState.initial()); } } @@ -208,12 +220,10 @@ public class CompleteReferenceExpression { } } - private static void getVariantsFromQualifierForSpreadOperator(@NotNull GrReferenceExpression refExpr, - @NotNull ResolverProcessor processor, - @NotNull GrExpression qualifier) { - final PsiType spreadType = ClosureParameterEnhancer.findTypeForIteration(qualifier, refExpr); + private void getVariantsFromQualifierForSpreadOperator(@NotNull GrExpression qualifier) { + final PsiType spreadType = ClosureParameterEnhancer.findTypeForIteration(qualifier, myRefExpr); if (spreadType != null) { - getVariantsFromQualifierType(refExpr, processor, spreadType, refExpr.getProject()); + getVariantsFromQualifierType(spreadType, myRefExpr.getProject()); } } @@ -285,9 +295,7 @@ public class CompleteReferenceExpression { } } - private static void getVariantsFromQualifier(@NotNull GrReferenceExpression refExpr, - @NotNull ResolverProcessor processor, - @NotNull GrExpression qualifier) { + private void getVariantsFromQualifier(@NotNull GrExpression qualifier) { Project project = qualifier.getProject(); PsiType qualifierType = qualifier.getType(); final ResolveState state = ResolveState.initial(); @@ -295,24 +303,23 @@ public class CompleteReferenceExpression { if (qualifier instanceof GrReferenceExpression) { PsiElement resolved = ((GrReferenceExpression)qualifier).resolve(); if (resolved instanceof PsiPackage || resolved instanceof PsiVariable) { - resolved.processDeclarations(processor, state, null, refExpr); + resolved.processDeclarations(myProcessor, state, null, myRefExpr); return; } } - getVariantsFromQualifierType(refExpr, processor, - PsiType.getJavaLangObject(refExpr.getManager(), qualifier.getResolveScope()), project); + getVariantsFromQualifierType(PsiType.getJavaLangObject(myRefExpr.getManager(), qualifier.getResolveScope()), project); } else if (qualifierType instanceof PsiIntersectionType) { for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) { - getVariantsFromQualifierType(refExpr, processor, conjunct, project); + getVariantsFromQualifierType(conjunct, project); } } else { - getVariantsFromQualifierType(refExpr, processor, qualifierType, project); + getVariantsFromQualifierType(qualifierType, project); if (qualifier instanceof GrReferenceExpression && !PsiUtil.isSuperReference(qualifier) && !PsiUtil.isInstanceThisRef(qualifier)) { PsiElement resolved = ((GrReferenceExpression)qualifier).resolve(); if (resolved instanceof PsiClass) { ////omitted .class - GlobalSearchScope scope = refExpr.getResolveScope(); + GlobalSearchScope scope = myRefExpr.getResolveScope(); PsiClass javaLangClass = PsiUtil.getJavaLangClass(resolved, scope); if (javaLangClass != null) { PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; @@ -320,93 +327,49 @@ public class CompleteReferenceExpression { if (typeParameters.length == 1) { substitutor = substitutor.put(typeParameters[0], qualifierType); } - PsiType javaLangClassType = JavaPsiFacade.getElementFactory(refExpr.getProject()).createType(javaLangClass, substitutor); - ResolveUtil.processAllDeclarations(javaLangClassType, processor, state, refExpr); + PsiType javaLangClassType = JavaPsiFacade.getElementFactory(myRefExpr.getProject()).createType(javaLangClass, substitutor); + ResolveUtil.processAllDeclarations(javaLangClassType, myProcessor, state, myRefExpr); } } } } } - @NotNull - public static Set getVariantsWithSameQualifier(@NotNull PrefixMatcher matcher, - @Nullable GrExpression qualifier, - @NotNull GrReferenceExpression refExpr) { - if (qualifier != null && qualifier.getType() != null) return Collections.emptySet(); - final PsiElement scope = PsiTreeUtil.getParentOfType(refExpr, GrMember.class, PsiFile.class); - Set result = new LinkedHashSet(); - if (scope != null) { - addVariantsWithSameQualifier(matcher, scope, refExpr, qualifier, result); - } - return result; - } - - private static void addVariantsWithSameQualifier(@NotNull PrefixMatcher matcher, - @NotNull PsiElement element, - @NotNull GrReferenceExpression patternExpression, - @Nullable GrExpression patternQualifier, - @NotNull Set result) { - if (element instanceof GrReferenceExpression && element != patternExpression && !PsiUtil.isLValue((GroovyPsiElement)element)) { - final GrReferenceExpression refExpr = (GrReferenceExpression)element; - final String refName = refExpr.getReferenceName(); - if (refName != null && !result.contains(refName) && matcher.prefixMatches(refName)) { - final GrExpression hisQualifier = refExpr.getQualifierExpression(); - if (hisQualifier != null && patternQualifier != null) { - if (PsiEquivalenceUtil.areElementsEquivalent(hisQualifier, patternQualifier)) { - if (refExpr.resolve() == null) { - result.add(refName); - } - } - } - else if (hisQualifier == null && patternQualifier == null) { - if (refExpr.resolve() == null) { - result.add(refName); - } - } - } - } - - for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) { - addVariantsWithSameQualifier(matcher, child, patternExpression, patternQualifier, result); - } - } - - private static void getVariantsFromQualifierType(@NotNull GrReferenceExpression refExpr, - @NotNull ResolverProcessor processor, - @NotNull PsiType qualifierType, - @NotNull Project project) { + private void getVariantsFromQualifierType(@NotNull PsiType qualifierType, + @NotNull Project project) { final ResolveState state = ResolveState.initial(); if (qualifierType instanceof PsiClassType) { PsiClassType.ClassResolveResult result = ((PsiClassType)qualifierType).resolveGenerics(); PsiClass qualifierClass = result.getElement(); if (qualifierClass != null) { - qualifierClass.processDeclarations(processor, state.put(PsiSubstitutor.KEY, result.getSubstitutor()), null, refExpr); + qualifierClass.processDeclarations(myProcessor, state.put(PsiSubstitutor.KEY, result.getSubstitutor()), null, myRefExpr); } } else if (qualifierType instanceof PsiArrayType) { - final GrTypeDefinition arrayClass = GroovyPsiManager.getInstance(project).getArrayClass(((PsiArrayType)qualifierType).getComponentType()); + final GrTypeDefinition arrayClass = + GroovyPsiManager.getInstance(project).getArrayClass(((PsiArrayType)qualifierType).getComponentType()); if (arrayClass != null) { - if (!arrayClass.processDeclarations(processor, state, null, refExpr)) return; + if (!arrayClass.processDeclarations(myProcessor, state, null, myRefExpr)) return; } } else if (qualifierType instanceof PsiIntersectionType) { for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) { - getVariantsFromQualifierType(refExpr, processor, conjunct, project); + getVariantsFromQualifierType(conjunct, project); } return; } - ResolveUtil.processNonCodeMembers(qualifierType, processor, refExpr, state); + ResolveUtil.processNonCodeMembers(qualifierType, myProcessor, myRefExpr, state); } @NotNull - private static Set addAllRestrictedProperties(@NotNull GrReferenceExpression place) { - if (place.getQualifier() != null) { + private Set addAllRestrictedProperties() { + if (myRefExpr.getQualifier() != null) { return Collections.emptySet(); } Set propertyNames = new HashSet(); - for (GrTypeDefinition containingClass = PsiTreeUtil.getParentOfType(place, GrTypeDefinition.class); + for (GrTypeDefinition containingClass = PsiTreeUtil.getParentOfType(myRefExpr, GrTypeDefinition.class); containingClass != null; containingClass = PsiTreeUtil.getParentOfType(containingClass, GrTypeDefinition.class)) { for (PsiField field : containingClass.getFields()) { @@ -416,17 +379,14 @@ public class CompleteReferenceExpression { return propertyNames; } - private static boolean isMap(@NotNull GrReferenceExpression place) { - final PsiType qType = GrReferenceResolveUtil.getQualifierType(place); + private boolean isMap() { + final PsiType qType = GrReferenceResolveUtil.getQualifierType(myRefExpr); return InheritanceUtil.isInheritor(qType, CommonClassNames.JAVA_UTIL_MAP); } - private static class CompleteReferenceProcessor extends ResolverProcessor implements Consumer { - private static final Logger LOG = Logger.getInstance(CompleteReferenceProcessor.class); + private class CompleteReferenceProcessor extends ResolverProcessor implements Consumer { private final Consumer myConsumer; - private final PrefixMatcher myMatcher; - private final CompletionParameters myParameters; private final boolean mySkipPackages; private final PsiClass myEventListener; @@ -443,32 +403,39 @@ public class CompleteReferenceExpression { private List myInapplicable; - protected CompleteReferenceProcessor(@NotNull GrReferenceExpression place, - @NotNull Consumer consumer, - @NotNull PrefixMatcher matcher, - @NotNull CompletionParameters parameters) { - super(null, EnumSet.allOf(ResolveKind.class), place, PsiType.EMPTY_ARRAY); - myConsumer = consumer; - myMatcher = matcher; - myParameters = parameters; - myPreferredFieldNames = addAllRestrictedProperties(place); - mySkipPackages = shouldSkipPackages(place); - myEventListener = JavaPsiFacade.getInstance(place.getProject()).findClass("java.util.EventListener", place.getResolveScope()); + private boolean myIsEmpty = true; + + protected CompleteReferenceProcessor() { + super(null, EnumSet.allOf(ResolveKind.class), myRefExpr, PsiType.EMPTY_ARRAY); + myConsumer = new Consumer() { + @Override + public void consume(LookupElement element) { + myIsEmpty = false; + CompleteReferenceExpression.this.myConsumer.consume(element); + } + }; + myPreferredFieldNames = addAllRestrictedProperties(); + mySkipPackages = shouldSkipPackages(); + myEventListener = JavaPsiFacade.getInstance(myRefExpr.getProject()).findClass("java.util.EventListener", myRefExpr.getResolveScope()); myPropertyNames.addAll(myPreferredFieldNames); - myFieldPointerOperator = place.hasAt(); - myMethodPointerOperator = place.getDotTokenType() == GroovyTokenTypes.mMEMBER_POINTER; - myIsMap = isMap(place); - final PsiType thisType = GrReferenceResolveUtil.getQualifierType(place); - mySubstitutorComputer = new SubstitutorComputer(thisType, PsiType.EMPTY_ARRAY, PsiType.EMPTY_ARRAY, place, place.getParent()); + myFieldPointerOperator = myRefExpr.hasAt(); + myMethodPointerOperator = myRefExpr.getDotTokenType() == GroovyTokenTypes.mMEMBER_POINTER; + myIsMap = isMap(); + final PsiType thisType = GrReferenceResolveUtil.getQualifierType(myRefExpr); + mySubstitutorComputer = new SubstitutorComputer(thisType, PsiType.EMPTY_ARRAY, PsiType.EMPTY_ARRAY, myRefExpr, myRefExpr.getParent()); } - private static boolean shouldSkipPackages(@NotNull GrReferenceExpression place) { - if (PsiImplUtil.getRuntimeQualifier(place) != null) { + public boolean isEmpty() { + return myIsEmpty; + } + + private boolean shouldSkipPackages() { + if (PsiImplUtil.getRuntimeQualifier(myRefExpr) != null) { return false; } - PsiElement parent = place.getParent(); + PsiElement parent = myRefExpr.getParent(); return parent == null || parent.getLanguage().isKindOf(GroovyFileType.GROOVY_LANGUAGE); //don't skip in Play! } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferencesWithSameQualifier.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferencesWithSameQualifier.java new file mode 100644 index 000000000000..f49267408842 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferencesWithSameQualifier.java @@ -0,0 +1,94 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions; + +import com.intellij.codeInsight.PsiEquivalenceUtil; +import com.intellij.codeInsight.completion.PrefixMatcher; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; + +import java.util.Collections; +import java.util.Set; + +/** + * Created by Max Medvedev on 25/04/14 + */ +public class CompleteReferencesWithSameQualifier { + private final GrReferenceExpression myRefExpr; + private final PrefixMatcher myMatcher; + private final GrExpression myQualifier; + + private CompleteReferencesWithSameQualifier(@NotNull GrReferenceExpression refExpr, + @NotNull PrefixMatcher matcher, + @Nullable GrExpression qualifier) { + myRefExpr = refExpr; + myMatcher = matcher; + myQualifier = qualifier; + } + + @NotNull + public static Set getVariantsWithSameQualifier(@NotNull GrReferenceExpression refExpr, + @NotNull PrefixMatcher matcher, + @Nullable GrExpression qualifier) { + return new CompleteReferencesWithSameQualifier(refExpr, matcher, qualifier).getVariantsWithSameQualifierImpl(); + } + + private Set getVariantsWithSameQualifierImpl() { + if (myQualifier != null && myQualifier.getType() != null) return Collections.emptySet(); + + final PsiElement scope = PsiTreeUtil.getParentOfType(myRefExpr, GrMember.class, PsiFile.class); + Set result = ContainerUtil.newLinkedHashSet(); + if (scope != null) { + addVariantsWithSameQualifier(scope, result); + } + return result; + } + + private void addVariantsWithSameQualifier(@NotNull PsiElement element, @NotNull Set result) { + if (element instanceof GrReferenceExpression && element != myRefExpr && !PsiUtil.isLValue((GroovyPsiElement)element)) { + final GrReferenceExpression refExpr = (GrReferenceExpression)element; + final String refName = refExpr.getReferenceName(); + if (refName != null && !result.contains(refName) && myMatcher.prefixMatches(refName)) { + final GrExpression hisQualifier = refExpr.getQualifierExpression(); + if (hisQualifier != null && myQualifier != null) { + if (PsiEquivalenceUtil.areElementsEquivalent(hisQualifier, myQualifier)) { + if (refExpr.resolve() == null) { + result.add(refName); + } + } + } + else if (hisQualifier == null && myQualifier == null) { + if (refExpr.resolve() == null) { + result.add(refName); + } + } + } + } + + for (PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()) { + addVariantsWithSameQualifier(child, result); + } + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index b8d735e8aa5a..c052c8b86d25 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -16,9 +16,6 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions; -import com.intellij.codeInsight.completion.CompletionParameters; -import com.intellij.codeInsight.completion.PrefixMatcher; -import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Computable; @@ -34,7 +31,6 @@ import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.ArrayUtil; -import com.intellij.util.Consumer; import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; @@ -903,11 +899,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl consumer) { - CompleteReferenceExpression.processVariants(matcher, consumer, this, parameters); - } - @NotNull public GroovyResolveResult[] getSameNameVariants() { return doPolyResolve(true, true); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightClassReferenceElement.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightClassReferenceElement.java index 993974268013..dc42cf8fe5d6 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightClassReferenceElement.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightClassReferenceElement.java @@ -15,16 +15,12 @@ */ package org.jetbrains.plugins.groovy.lang.psi.impl.synthetic; -import com.intellij.codeInsight.completion.CompletionParameters; -import com.intellij.codeInsight.completion.PrefixMatcher; -import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiType; import com.intellij.psi.impl.light.LightElement; import com.intellij.util.ArrayUtil; -import com.intellij.util.Consumer; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -95,10 +91,6 @@ public class GrLightClassReferenceElement extends LightElement implements GrCode return null; } - @Override - public void processVariants(PrefixMatcher matcher, CompletionParameters parameters, Consumer consumer) { - } - @Override public String getClassNameText() { return myClassName; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/CompleteCodeReferenceElement.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/CompleteCodeReferenceElement.java new file mode 100644 index 000000000000..18679f3a2e4e --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/CompleteCodeReferenceElement.java @@ -0,0 +1,223 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.impl.types; + +import com.intellij.codeInsight.completion.JavaClassNameCompletionContributor; +import com.intellij.codeInsight.completion.PrefixMatcher; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionUtil; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody; +import org.jetbrains.plugins.groovy.lang.psi.api.types.*; +import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; +import org.jetbrains.plugins.groovy.lang.resolve.processors.CompletionProcessor; +import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor; + +import java.util.List; + +import static org.jetbrains.plugins.groovy.lang.psi.impl.types.GrCodeReferenceElementImpl.ReferenceKind.*; + +/** + * Created by Max Medvedev on 25/04/14 + */ +public class CompleteCodeReferenceElement { + private static final Logger LOG = Logger.getInstance(CompleteCodeReferenceElement.class); + + private final GrCodeReferenceElementImpl myRef; + private final Consumer myConsumer; + private final PrefixMatcher myMatcher; + + private CompleteCodeReferenceElement(@NotNull GrCodeReferenceElementImpl ref, + @NotNull Consumer consumer, + @NotNull PrefixMatcher matcher) { + myRef = ref; + myConsumer = consumer; + myMatcher = matcher; + } + + public static void processVariants(@NotNull GrCodeReferenceElementImpl ref, + @NotNull Consumer consumer, + @NotNull PrefixMatcher matcher) { + new CompleteCodeReferenceElement(ref, consumer, matcher).processVariantsImpl(); + } + + private void feedLookupElements(@NotNull PsiNamedElement psi, boolean afterNew) { + GroovyResolveResultImpl candidate = new GroovyResolveResultImpl(psi, true); + List elements = GroovyCompletionUtil.createLookupElements(candidate, afterNew, myMatcher, null); + for (LookupElement element : elements) { + myConsumer.consume(element); + } + } + + public void processVariantsImpl() { + boolean afterNew = JavaClassNameCompletionContributor.AFTER_NEW.accepts(myRef); + + switch (myRef.getKind(true)) { + case STATIC_MEMBER_FQ: { + final GrCodeReferenceElement qualifier = myRef.getQualifier(); + if (qualifier != null) { + final PsiElement resolve = qualifier.resolve(); + if (resolve instanceof PsiClass) { + final PsiClass clazz = (PsiClass)resolve; + + for (PsiField field : clazz.getFields()) { + if (field.hasModifierProperty(PsiModifier.STATIC)) { + feedLookupElements(field, afterNew); + } + } + + for (PsiMethod method : clazz.getMethods()) { + if (method.hasModifierProperty(PsiModifier.STATIC)) { + feedLookupElements(method, afterNew); + } + } + + for (PsiClass inner : clazz.getInnerClasses()) { + if (inner.hasModifierProperty(PsiModifier.STATIC)) { + feedLookupElements(inner, afterNew); + } + } + return; + } + } + } + // fall through + + case PACKAGE_FQ: + case CLASS_FQ: + case CLASS_OR_PACKAGE_FQ: { + final String refText = PsiUtil.getQualifiedReferenceText(myRef); + LOG.assertTrue(refText != null, myRef.getText()); + + String parentPackageFQName = StringUtil.getPackageName(refText); + final PsiPackage parentPackage = JavaPsiFacade.getInstance(myRef.getProject()).findPackage(parentPackageFQName); + if (parentPackage != null) { + final GlobalSearchScope scope = myRef.getResolveScope(); + if (myRef.getKind(true) == PACKAGE_FQ) { + for (PsiPackage aPackage : parentPackage.getSubPackages(scope)) { + feedLookupElements(aPackage, afterNew); + } + return; + } + + if (myRef.getKind(true) == CLASS_FQ) { + for (PsiClass aClass : parentPackage.getClasses(scope)) { + feedLookupElements(aClass, afterNew); + } + return; + } + + for (PsiPackage aPackage : parentPackage.getSubPackages(scope)) { + feedLookupElements(aPackage, afterNew); + } + for (PsiClass aClass : parentPackage.getClasses(scope)) { + feedLookupElements(aClass, afterNew); + } + return; + } + } + + case CLASS_OR_PACKAGE: + case CLASS_IN_QUALIFIED_NEW: + case CLASS: { + GrCodeReferenceElement qualifier = myRef.getQualifier(); + if (qualifier != null) { + PsiElement qualifierResolved = qualifier.resolve(); + if (qualifierResolved instanceof PsiPackage) { + PsiPackage aPackage = (PsiPackage)qualifierResolved; + for (PsiClass aClass : aPackage.getClasses(myRef.getResolveScope())) { + feedLookupElements(aClass, afterNew); + } + if (myRef.getKind(true) == CLASS) return; + + for (PsiPackage subpackage : aPackage.getSubPackages(myRef.getResolveScope())) { + feedLookupElements(subpackage, afterNew); + } + } + else if (qualifierResolved instanceof PsiClass) { + for (PsiClass aClass : ((PsiClass)qualifierResolved).getInnerClasses()) { + feedLookupElements(aClass, afterNew); + } + } + } + else { + ResolverProcessor classProcessor = CompletionProcessor.createClassCompletionProcessor(myRef); + processTypeParametersFromUnfinishedMethodOrField(classProcessor); + + ResolveUtil.treeWalkUp(myRef, classProcessor, false); + + for (LookupElement o : GroovyCompletionUtil.getCompletionVariants(classProcessor.getCandidates(), afterNew, myMatcher, myRef)) { + myConsumer.consume(o); + } + } + } + } + } + + private void processTypeParametersFromUnfinishedMethodOrField(@NotNull ResolverProcessor processor) { + + final PsiElement candidate = findTypeParameterListCandidate(); + + if (candidate instanceof GrTypeParameterList) { + for (GrTypeParameter p : ((GrTypeParameterList)candidate).getTypeParameters()) { + ResolveUtil.processElement(processor, p, ResolveState.initial()); + } + } + } + + @Nullable + private PsiElement findTypeParameterListCandidate() { + final GrTypeElement typeElement = getRootTypeElement(); + if (typeElement == null) return null; + + if (typeElement.getParent() instanceof GrTypeDefinitionBody) { + return PsiUtil.skipWhitespacesAndComments(typeElement.getPrevSibling(), false); + } + + if (typeElement.getParent() instanceof GrVariableDeclaration) { + final PsiElement errorElement = PsiUtil.skipWhitespacesAndComments(typeElement.getPrevSibling(), false); + if (errorElement instanceof PsiErrorElement) { + return errorElement.getFirstChild(); + } + } + + return null; + } + + @Nullable + private GrTypeElement getRootTypeElement() { + PsiElement parent = myRef.getParent(); + while (isTypeElementChild(parent)) { + if (parent instanceof GrTypeElement && !isTypeElementChild(parent.getParent())) return (GrTypeElement)parent; + parent = parent.getParent(); + } + + return null; + } + + private static boolean isTypeElementChild(@Nullable PsiElement element) { + return element instanceof GrCodeReferenceElement || element instanceof GrTypeArgumentList || element instanceof GrTypeElement; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java index 80a41de9d3e4..587bdfeff5f5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java @@ -16,23 +16,16 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.types; -import com.intellij.codeInsight.completion.CompletionParameters; -import com.intellij.codeInsight.completion.JavaClassNameCompletionContributor; -import com.intellij.codeInsight.completion.PrefixMatcher; -import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.ResolveCache; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; -import com.intellij.util.Consumer; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionUtil; import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocReferenceElement; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; @@ -41,14 +34,13 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.types.*; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; import org.jetbrains.plugins.groovy.lang.psi.impl.GrReferenceElementImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; @@ -58,7 +50,6 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint; import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassResolverProcessor; -import org.jetbrains.plugins.groovy.lang.resolve.processors.CompletionProcessor; import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor; import java.util.ArrayList; @@ -132,7 +123,7 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl consumer, PrefixMatcher matcher) { - for (LookupElement element : GroovyCompletionUtil - .createLookupElements(new GroovyResolveResultImpl(psi, true), afterNew, matcher, null)) { - consumer.consume(element); - } - } - - private void processVariantsImpl(ReferenceKind kind, Consumer consumer, PrefixMatcher matcher) { - boolean afterNew = JavaClassNameCompletionContributor.AFTER_NEW.accepts(this); - switch (kind) { - case STATIC_MEMBER_FQ: { - final GrCodeReferenceElement qualifier = getQualifier(); - if (qualifier != null) { - final PsiElement resolve = qualifier.resolve(); - if (resolve instanceof PsiClass) { - final PsiClass clazz = (PsiClass)resolve; - - for (PsiField field : clazz.getFields()) { - if (field.hasModifierProperty(PsiModifier.STATIC)) { - feedLookupElements(field, afterNew, consumer, matcher); - } - } - - for (PsiMethod method : clazz.getMethods()) { - if (method.hasModifierProperty(PsiModifier.STATIC)) { - feedLookupElements(method, afterNew, consumer, matcher); - } - } - - for (PsiClass inner : clazz.getInnerClasses()) { - if (inner.hasModifierProperty(PsiModifier.STATIC)) { - feedLookupElements(inner, afterNew, consumer, matcher); - } - } - return; - } - } - } - // fall through - - case PACKAGE_FQ: - case CLASS_FQ: - case CLASS_OR_PACKAGE_FQ: { - final String refText = PsiUtil.getQualifiedReferenceText(this); - LOG.assertTrue(refText != null, this.getText()); - - String parentPackageFQName = StringUtil.getPackageName(refText); - final PsiPackage parentPackage = JavaPsiFacade.getInstance(getProject()).findPackage(parentPackageFQName); - if (parentPackage != null) { - final GlobalSearchScope scope = getResolveScope(); - if (kind == PACKAGE_FQ) { - for (PsiPackage aPackage : parentPackage.getSubPackages(scope)) { - feedLookupElements(aPackage, afterNew, consumer, matcher); - } - return; - } - - if (kind == CLASS_FQ) { - for (PsiClass aClass : parentPackage.getClasses(scope)) { - feedLookupElements(aClass, afterNew, consumer, matcher); - } - return; - } - - for (PsiPackage aPackage : parentPackage.getSubPackages(scope)) { - feedLookupElements(aPackage, afterNew, consumer, matcher); - } - for (PsiClass aClass : parentPackage.getClasses(scope)) { - feedLookupElements(aClass, afterNew, consumer, matcher); - } - return; - } - } - - case CLASS_OR_PACKAGE: - case CLASS_IN_QUALIFIED_NEW: - case CLASS: { - GrCodeReferenceElement qualifier = getQualifier(); - if (qualifier != null) { - PsiElement qualifierResolved = qualifier.resolve(); - if (qualifierResolved instanceof PsiPackage) { - PsiPackage aPackage = (PsiPackage)qualifierResolved; - for (PsiClass aClass : aPackage.getClasses(getResolveScope())) { - feedLookupElements(aClass, afterNew, consumer, matcher); - } - if (kind == CLASS) return; - - for (PsiPackage subpackage : aPackage.getSubPackages(getResolveScope())) { - feedLookupElements(subpackage, afterNew, consumer, matcher); - } - } - else if (qualifierResolved instanceof PsiClass) { - for (PsiClass aClass : ((PsiClass)qualifierResolved).getInnerClasses()) { - feedLookupElements(aClass, afterNew, consumer, matcher); - } - } - } - else { - ResolverProcessor classProcessor = CompletionProcessor.createClassCompletionProcessor(this); - processTypeParametersFromUnfinishedMethodOrField(classProcessor); - - ResolveUtil.treeWalkUp(this, classProcessor, false); - - for (LookupElement o : GroovyCompletionUtil.getCompletionVariants(classProcessor.getCandidates(), afterNew, matcher, this)) { - consumer.consume(o); - } - } - } - } - } - - private void processTypeParametersFromUnfinishedMethodOrField(@NotNull ResolverProcessor processor) { - final PsiElement candidate = findTypeParameterListCandidate(); - - if (candidate instanceof GrTypeParameterList) { - for (GrTypeParameter p : ((GrTypeParameterList)candidate).getTypeParameters()) { - ResolveUtil.processElement(processor, p, ResolveState.initial()); - } - } - } - - @Nullable - private PsiElement findTypeParameterListCandidate() { - final GrTypeElement typeElement = getRootTypeElement(); - if (typeElement == null) return null; - - if (typeElement.getParent() instanceof GrTypeDefinitionBody) { - return PsiUtil.skipWhitespacesAndComments(typeElement.getPrevSibling(), false); - } - - if (typeElement.getParent() instanceof GrVariableDeclaration) { - final PsiElement errorElement = PsiUtil.skipWhitespacesAndComments(typeElement.getPrevSibling(), false); - if (errorElement instanceof PsiErrorElement) { - return errorElement.getFirstChild(); - } - } - - return null; - } - - @Nullable - private GrTypeElement getRootTypeElement() { - PsiElement parent = getParent(); - while (isTypeElementChild(parent)) { - if (parent instanceof GrTypeElement && !isTypeElementChild(parent.getParent())) return (GrTypeElement)parent; - parent = parent.getParent(); - } - - return null; - } - - private static boolean isTypeElementChild(PsiElement element) { - return element instanceof GrCodeReferenceElement || element instanceof GrTypeArgumentList || element instanceof GrTypeElement; - } - public boolean isSoft() { return false; } @@ -681,11 +517,6 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl consumer) { - processVariantsImpl(getKind(true), consumer, matcher); - } - @NotNull @Override public PsiType[] getTypeArguments() {