diff options
Diffstat (limited to 'plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl')
6 files changed, 445 insertions, 421 deletions
diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java index 0cde75af230b..dce723b5f3bc 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java @@ -46,10 +46,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; -import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; -import org.jetbrains.plugins.groovy.lang.psi.GrNamedElement; -import org.jetbrains.plugins.groovy.lang.psi.GrQualifiedReference; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; +import org.jetbrains.plugins.groovy.lang.psi.*; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrCondition; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; @@ -76,6 +73,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrM import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrReferenceList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod; +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.api.types.GrTypeElement; @@ -988,4 +986,38 @@ public class PsiImplUtil { } return expr == null; } + + @Nullable + public static PsiType getQualifierType(@NotNull GrReferenceExpression ref) { + final GrExpression rtQualifier = getRuntimeQualifier(ref); + if (rtQualifier != null) { + return rtQualifier.getType(); + } + + PsiClass containingClass = null; + final GrMember member = PsiTreeUtil.getParentOfType(ref, GrMember.class); + if (member == null) { + final PsiFile file = ref.getContainingFile(); + if (file instanceof GroovyFileBase && ((GroovyFileBase)file).isScript()) { + containingClass = ((GroovyFileBase)file).getScriptClass(); + } + else { + return null; + } + } + else if (member instanceof GrMethod) { + if (!member.hasModifierProperty(PsiModifier.STATIC)) { + containingClass = member.getContainingClass(); + } + } + + if (containingClass != null) { + final PsiClassType categoryType = GdkMethodUtil.getCategoryType(containingClass); + if (categoryType != null) { + return categoryType; + } + return JavaPsiFacade.getElementFactory(ref.getProject()).createType(containingClass); + } + return null; + } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index 40589065654d..4b8a032a5602 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -46,7 +46,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplicationStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall; @@ -59,10 +58,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.*; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrBindingVariable; import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.GrReferenceTypeEnhancer; -import org.jetbrains.plugins.groovy.lang.psi.util.GdkMethodUtil; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; -import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import org.jetbrains.plugins.groovy.lang.psi.util.*; import org.jetbrains.plugins.groovy.lang.resolve.ClosureMissingMethodContributor; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.processors.*; @@ -159,15 +155,15 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi IElementType nameType = nameElement.getNode().getElementType(); if (nameType == GroovyTokenTypes.kTHIS) { - ArrayList<GroovyResolveResult> results = new ArrayList<GroovyResolveResult>(); - if (GrReferenceResolveUtil.resolveThisExpression(this, results)) { - return results.toArray(new GroovyResolveResult[results.size()]); + GroovyResolveResult[] results = GrThisReferenceResolver.resolveThisExpression(this); + if (results != null) { + return results; } } else if (nameType == GroovyTokenTypes.kSUPER) { - ArrayList<GroovyResolveResult> results = new ArrayList<GroovyResolveResult>(); - if (GrReferenceResolveUtil.resolveSuperExpression(this, results)) { - return results.toArray(new GroovyResolveResult[results.size()]); + GroovyResolveResult[] results = GrSuperReferenceResolver.resolveSuperExpression(this); + if (results != null) { + return results; } } @@ -178,8 +174,10 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi GroovyResolveResult[] classCandidates = null; + GrReferenceResolveRunner resolveRunner = new GrReferenceResolveRunner(this); + ResolverProcessor processor = new PropertyResolverProcessor(name, this); - GrReferenceResolveUtil.resolveImpl(processor, this); + resolveRunner.resolveImpl(processor); final GroovyResolveResult[] fieldCandidates = processor.getCandidates(); if (hasAt()) { @@ -191,7 +189,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi if (canBeClassOrPackage && findClassOrPackageAtFirst()) { ResolverProcessor classProcessor = new ClassResolverProcessor(name, this, kinds); - GrReferenceResolveUtil.resolveImpl(classProcessor, this); + resolveRunner.resolveImpl(classProcessor); classCandidates = classProcessor.getCandidates(); if (classCandidates.length > 0 && containsPackage(classCandidates)) return classCandidates; } @@ -215,9 +213,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi List<GroovyResolveResult> accessorResults = new ArrayList<GroovyResolveResult>(); for (String accessorName : accessorNames) { AccessorResolverProcessor accessorResolver = - new AccessorResolverProcessor(accessorName, name, this, !isLValue, false, GrReferenceResolveUtil.getQualifierType(this), - getTypeArguments()); - GrReferenceResolveUtil.resolveImpl(accessorResolver, this); + new AccessorResolverProcessor(accessorName, name, this, !isLValue, false, PsiImplUtil.getQualifierType(this), getTypeArguments()); + resolveRunner.resolveImpl(accessorResolver); final GroovyResolveResult[] candidates = accessorResolver.getCandidates(); //can be only one correct candidate or some incorrect @@ -237,9 +234,10 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi if (classCandidates == null && canBeClassOrPackage ) { ResolverProcessor classProcessor = new ClassResolverProcessor(name, this, kinds); - GrReferenceResolveUtil.resolveImpl(classProcessor, this); + resolveRunner.resolveImpl(classProcessor); classCandidates = classProcessor.getCandidates(); } + if (classCandidates != null && classCandidates.length > 0) return classCandidates; if (!accessorResults.isEmpty()) return new GroovyResolveResult[]{accessorResults.get(0)}; return GroovyResolveResult.EMPTY_ARRAY; @@ -258,23 +256,14 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi } private void processMethods(@NotNull MethodResolverProcessor methodResolver) { - GrReferenceResolveUtil.resolveImpl(methodResolver, this); + new GrReferenceResolveRunner(this).resolveImpl(methodResolver); if (methodResolver.hasApplicableCandidates()) { return; } // Search in ClosureMissingMethodContributor if (!isQualified() && getContext() instanceof GrMethodCall) { - for (PsiElement e = this.getContext(); e != null; e = e.getContext()) { - if (e instanceof GrClosableBlock) { - ResolveState state = ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, e); - for (ClosureMissingMethodContributor contributor : ClosureMissingMethodContributor.EP_NAME.getExtensions()) { - if (!contributor.processMembers((GrClosableBlock)e, methodResolver, this, state)) { - return; - } - } - } - } + ClosureMissingMethodContributor.processMethodsFromClosures(this, methodResolver); } } @@ -287,8 +276,10 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi final String name = getReferenceName(); if (name == null) return GroovyResolveResult.EMPTY_ARRAY; + GrReferenceResolveRunner resolveRunner = new GrReferenceResolveRunner(this); + PropertyResolverProcessor propertyResolver = new PropertyResolverProcessor(name, this); - GrReferenceResolveUtil.resolveImpl(propertyResolver, this); + resolveRunner.resolveImpl(propertyResolver); final GroovyResolveResult[] propertyCandidates = propertyResolver.getCandidates(); if (!allVariants) { //search for local variables @@ -345,8 +336,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi //search for getters for (String getterName : GroovyPropertyUtils.suggestGettersName(name)) { AccessorResolverProcessor getterResolver = - new AccessorResolverProcessor(getterName, name, this, true, genericsMatter, GrReferenceResolveUtil.getQualifierType(this), getTypeArguments()); - GrReferenceResolveUtil.resolveImpl(getterResolver, this); + new AccessorResolverProcessor(getterName, name, this, true, genericsMatter, PsiImplUtil.getQualifierType(this), getTypeArguments()); + resolveRunner.resolveImpl(getterResolver); final GroovyResolveResult[] candidates = getterResolver.getCandidates(); //can be only one candidate if (!allVariants && candidates.length == 1) { return candidates; @@ -424,7 +415,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi argTypes[i] = TypeConversionUtil.erasure(argTypes[i]); } } - PsiType qualifierType = GrReferenceResolveUtil.getQualifierType(this); + PsiType qualifierType = PsiImplUtil.getQualifierType(this); return new MethodResolverProcessor(name, this, false, qualifierType, argTypes, getTypeArguments(), allVariants, byShape); } @@ -610,7 +601,19 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi return factory.createType((PsiClass)resolved); } } - if (getParent() instanceof GrReferenceExpression || PsiUtil.isSuperReference(this)) { + else if (PsiUtil.isSuperReference(this)) { + PsiClass contextClass = PsiUtil.getContextClass(this); + if (GrTraitUtil.isTrait(contextClass)) { + PsiClassType[] extendsTypes = contextClass.getExtendsListTypes(); + PsiClassType[] implementsTypes = contextClass.getImplementsListTypes(); + + PsiClassType[] superTypes = ArrayUtil.mergeArrays(implementsTypes, extendsTypes, PsiClassType.ARRAY_FACTORY); + + return PsiIntersectionType.createIntersection(ArrayUtil.reverseArray(superTypes)); + } + return factory.createType((PsiClass)resolved); + } + if (getParent() instanceof GrReferenceExpression) { return factory.createType((PsiClass)resolved); } else { @@ -637,7 +640,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) && "getClass".equals(method.getName())) { - return TypesUtil.createJavaLangClassType(GrReferenceResolveUtil.getQualifierType(this), getProject(), getResolveScope()); + return TypesUtil.createJavaLangClassType(PsiImplUtil.getQualifierType(this), getProject(), getResolveScope()); } return PsiUtil.getSmartReturnType(method); @@ -701,7 +704,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi @Nullable private static PsiType getTypeFromClassRef(@NotNull GrReferenceExpressionImpl ref) { if ("class".equals(ref.getReferenceName())) { - return TypesUtil.createJavaLangClassType(GrReferenceResolveUtil.getQualifierType(ref), ref.getProject(), ref.getResolveScope()); + return TypesUtil.createJavaLangClassType(PsiImplUtil.getQualifierType(ref), ref.getProject(), ref.getResolveScope()); } return null; } @@ -710,7 +713,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi @Override @Nullable public PsiType fun(GrReferenceExpressionImpl refExpr) { - if (GrReferenceResolveUtil.isClassReference(refExpr)) { + if (ResolveUtil.isClassReference(refExpr)) { GrExpression qualifier = refExpr.getQualifier(); LOG.assertTrue(qualifier != null); return TypesUtil.createJavaLangClassType(qualifier.getType(), refExpr.getProject(), refExpr.getResolveScope()); @@ -783,7 +786,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi if (incompleteCode) { ResolverProcessor processor = CompletionProcessor.createRefSameNameProcessor(this, name); - GrReferenceResolveUtil.resolveImpl(processor, this); + new GrReferenceResolveRunner(this).resolveImpl(processor); GroovyResolveResult[] propertyCandidates = processor.getCandidates(); if (propertyCandidates.length > 0 && !PsiUtil.isSingleBindingVariant(propertyCandidates)) return propertyCandidates; } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveRunner.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveRunner.java new file mode 100644 index 000000000000..13159892a3ee --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveRunner.java @@ -0,0 +1,240 @@ +/* + * 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.openapi.progress.ProgressManager; +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; +import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall; +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.impl.GrTraitType; +import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; +import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; +import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParameterEnhancer; +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.ResolverProcessor; + +import java.util.List; +import java.util.ListIterator; + +/** + * @author Medvedev Max + */ +public class GrReferenceResolveRunner { + + private final GrReferenceExpression place; + private ResolverProcessor processor; + + public GrReferenceResolveRunner(@NotNull GrReferenceExpression _place) { + place = _place; + } + + public boolean resolveImpl(@NotNull ResolverProcessor _processor) { + processor = _processor; + try { + boolean result = doResolve(); + ProgressManager.checkCanceled(); + return result; + } + finally { + processor = null; + } + } + + private boolean doResolve() { + GrExpression qualifier = place.getQualifier(); + if (qualifier == null) { + if (!ResolveUtil.treeWalkUp(place, processor, true)) return false; + if (!processor.hasCandidates()) { + GrExpression runtimeQualifier = PsiImplUtil.getRuntimeQualifier(place); + if (runtimeQualifier != null) { + if (!processQualifier(runtimeQualifier)) return false; + } + } + } + else { + if (place.getDotTokenType() == GroovyTokenTypes.mSPREAD_DOT) { + final PsiType qtype = qualifier.getType(); + final PsiType componentType = ClosureParameterEnhancer.findTypeForIteration(qtype, place); + if (componentType != null) { + final ResolveState state = ResolveState.initial() + .put(ClassHint.RESOLVE_CONTEXT, qualifier) + .put(SpreadState.SPREAD_STATE, SpreadState.create(qtype, null)); + if (!processQualifierType(componentType, state)) return false; + } + } + else { + if (ResolveUtil.isClassReference(place)) return true; + if (!processQualifier(qualifier)) return false; + if (!processJavaLangClass(qualifier)) return false; + } + } + return true; + } + + private boolean processJavaLangClass(@NotNull GrExpression qualifier) { + if (!(qualifier instanceof GrReferenceExpression)) return true; + + //optimization: only 'class' or 'this' in static context can be an alias of java.lang.Class + if (!("class".equals(((GrReferenceExpression)qualifier).getReferenceName()) || + PsiUtil.isThisReference(qualifier))) { + return true; + } + + PsiType type = qualifier.getType(); + if (!(type instanceof PsiClassType)) return true; + + final PsiClass psiClass = ((PsiClassType)type).resolve(); + if (psiClass == null || !CommonClassNames.JAVA_LANG_CLASS.equals(psiClass.getQualifiedName())) return true; + + final PsiType[] params = ((PsiClassType)type).getParameters(); + if (params.length != 1) return true; + + if (!processQualifierType(params[0], ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, qualifier))) { + return false; + } + return true; + } + + private boolean processQualifier(@NotNull GrExpression qualifier) { + PsiType qualifierType = qualifier.getType(); + ResolveState state = ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, qualifier); + if (qualifierType == null || qualifierType == PsiType.VOID) { + if (qualifier instanceof GrReferenceExpression) { + PsiElement resolved = ((GrReferenceExpression)qualifier).resolve(); + if (resolved != null && !resolved.processDeclarations(processor, state, null, place)) return false; + if (!(resolved instanceof PsiPackage)) { + PsiType objectQualifier = TypesUtil.getJavaLangObject(place); + if (!processQualifierType(objectQualifier, state)) return false; + } + } + } + else if (qualifierType instanceof PsiIntersectionType) { + for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) { + if (!processQualifierType(conjunct, state)) return false; + } + } + else { + if (!processQualifierType(qualifierType, state)) return false; + if (qualifier instanceof GrReferenceExpression && !PsiUtil.isSuperReference(qualifier) && !PsiUtil.isInstanceThisRef(qualifier)) { + PsiElement resolved = ((GrReferenceExpression)qualifier).resolve(); + if (resolved instanceof PsiClass) { + if (!processJavaLangClass(qualifierType, state)) return false; + } + } + } + return true; + } + + private boolean processJavaLangClass(@NotNull PsiType qualifierType, + @NotNull ResolveState state) { + //omitted .class + PsiClass javaLangClass = PsiUtil.getJavaLangClass(place, place.getResolveScope()); + if (javaLangClass == null) return true; + + PsiTypeParameter[] typeParameters = javaLangClass.getTypeParameters(); + PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY); + if (substitutor == null) substitutor = PsiSubstitutor.EMPTY; + if (typeParameters.length == 1) { + substitutor = substitutor.put(typeParameters[0], qualifierType); + state = state.put(PsiSubstitutor.KEY, substitutor); + } + if (!javaLangClass.processDeclarations(processor, state, null, place)) return false; + + PsiType javaLangClassType = JavaPsiFacade.getElementFactory(place.getProject()).createType(javaLangClass, substitutor); + + if (!ResolveUtil.processNonCodeMembers(javaLangClassType, processor, place, state)) return false; + + return true; + } + + private boolean processQualifierType(@NotNull PsiType originalQualifierType, + @NotNull ResolveState state) { + PsiType qualifierType = originalQualifierType instanceof PsiDisjunctionType + ? ((PsiDisjunctionType)originalQualifierType).getLeastUpperBound() + : originalQualifierType; + + if (qualifierType instanceof PsiIntersectionType) { + for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) { + if (!processQualifierType(conjunct, state)) return false; + } + return true; + } + + if (qualifierType instanceof GrTraitType) { + if (!processTraitType((GrTraitType)qualifierType, state)) { + return false; + } + return true; + } + + if (qualifierType instanceof PsiClassType) { + PsiClassType.ClassResolveResult qualifierResult = ((PsiClassType)qualifierType).resolveGenerics(); + PsiClass qualifierClass = qualifierResult.getElement(); + if (qualifierClass != null) { + if (!qualifierClass.processDeclarations(processor, state.put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor()), null, place)) { + return false; + } + } + } + else if (qualifierType instanceof PsiArrayType) { + final GroovyPsiManager gmanager = GroovyPsiManager.getInstance(place.getProject()); + final GrTypeDefinition arrayClass = gmanager.getArrayClass(((PsiArrayType)qualifierType).getComponentType()); + if (arrayClass != null && !arrayClass.processDeclarations(processor, state, null, place)) return false; + } + + if (!(place.getParent() instanceof GrMethodCall) && InheritanceUtil.isInheritor(qualifierType, CommonClassNames.JAVA_UTIL_COLLECTION)) { + final PsiType componentType = ClosureParameterEnhancer.findTypeForIteration(qualifierType, place); + if (componentType != null) { + final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE); + processQualifierType(componentType, state.put(SpreadState.SPREAD_STATE, SpreadState.create(qualifierType, spreadState))); + } + } + + if (!ResolveUtil.processCategoryMembers(place, processor, state)) return false; + if (!ResolveUtil.processNonCodeMembers(qualifierType, processor, place, state)) return false; + return true; + } + + private boolean processTraitType(@NotNull GrTraitType traitType, @NotNull ResolveState state) { + GrTypeDefinition mockDefinition = traitType.getMockTypeDefinition(); + if (mockDefinition != null) { + if (!mockDefinition.processDeclarations(processor, state, null, place)) { + return false; + } + } + else { + PsiClassType exprType = traitType.getExprType(); + + if (!processQualifierType(exprType, state)) return false; + + List<PsiClassType> traitTypes = traitType.getTraitTypes(); + for (ListIterator<PsiClassType> iterator = traitTypes.listIterator(); iterator.hasPrevious(); ) { + PsiClassType type = iterator.previous(); + if (!processQualifierType(type, state)) return false; + } + } + + return true; + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveUtil.java deleted file mode 100644 index 4779fb12f25f..000000000000 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceResolveUtil.java +++ /dev/null @@ -1,380 +0,0 @@ -/* - * 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.openapi.progress.ProgressManager; -import com.intellij.psi.*; -import com.intellij.psi.scope.PsiScopeProcessor; -import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; -import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; -import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; -import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrClassInitializer; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall; -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.impl.GrTraitType; -import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; -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.typeEnhancers.ClosureParameterEnhancer; -import org.jetbrains.plugins.groovy.lang.psi.util.GdkMethodUtil; -import org.jetbrains.plugins.groovy.lang.psi.util.GrTraitUtil; -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.ResolverProcessor; - -import java.util.List; -import java.util.ListIterator; - -/** - * @author Medvedev Max - */ -public class GrReferenceResolveUtil { - - private GrReferenceResolveUtil() { - } - - static boolean resolveImpl(@NotNull ResolverProcessor processor, - @NotNull GrReferenceExpression place) { - boolean b = doResolve(processor, place); - ProgressManager.checkCanceled(); - return b; - } - - private static boolean doResolve(ResolverProcessor processor, GrReferenceExpression place) { - GrExpression qualifier = place.getQualifier(); - if (qualifier == null) { - if (!ResolveUtil.treeWalkUp(place, processor, true)) return false; - if (!processor.hasCandidates()) { - GrExpression runtimeQualifier = PsiImplUtil.getRuntimeQualifier(place); - if (runtimeQualifier != null) { - if (!processQualifier(processor, runtimeQualifier, place)) return false; - } - } - } - else { - if (place.getDotTokenType() == GroovyTokenTypes.mSPREAD_DOT) { - final PsiType qtype = qualifier.getType(); - final PsiType componentType = ClosureParameterEnhancer.findTypeForIteration(qtype, place); - if (componentType != null) { - final ResolveState state = ResolveState.initial() - .put(ClassHint.RESOLVE_CONTEXT, qualifier) - .put(SpreadState.SPREAD_STATE, SpreadState.create(qtype, null)); - if (!processQualifierType(processor, componentType, state, place)) return false; - } - } - else { - if (isClassReference(place)) return true; - if (!processQualifier(processor, qualifier, place)) return false; - } - - if (qualifier instanceof GrReferenceExpression && - ("class".equals(((GrReferenceExpression)qualifier).getReferenceName()) || PsiUtil.isThisReference(qualifier))) { - if (!processIfJavaLangClass(processor, qualifier.getType(), qualifier, place)) return false; - } - } - return true; - } - - private static boolean processIfJavaLangClass(@NotNull ResolverProcessor processor, - @Nullable PsiType type, - @NotNull GroovyPsiElement resolveContext, - @NotNull GrReferenceExpression place) { - if (!(type instanceof PsiClassType)) return true; - - final PsiClass psiClass = ((PsiClassType)type).resolve(); - if (psiClass == null || !CommonClassNames.JAVA_LANG_CLASS.equals(psiClass.getQualifiedName())) return true; - - final PsiType[] params = ((PsiClassType)type).getParameters(); - if (params.length != 1) return true; - - if (!processQualifierType(processor, params[0], ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, resolveContext), place)) { - return false; - } - return true; - } - - public static boolean processQualifier(@NotNull PsiScopeProcessor processor, - @NotNull GrExpression qualifier, - @NotNull GrReferenceExpression place) { - PsiType qualifierType = qualifier.getType(); - ResolveState state = ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, qualifier); - if (qualifierType == null || qualifierType == PsiType.VOID) { - if (qualifier instanceof GrReferenceExpression) { - PsiElement resolved = ((GrReferenceExpression)qualifier).resolve(); - if (resolved != null && !resolved.processDeclarations(processor, state, null, place)) return false; - if (!(resolved instanceof PsiPackage)) { - PsiType objectQualifier = TypesUtil.getJavaLangObject(place); - if (!processQualifierType(processor, objectQualifier, state, place)) return false; - } - } - } - else if (qualifierType instanceof PsiIntersectionType) { - for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) { - if (!processQualifierType(processor, conjunct, state, place)) return false; - } - } - else { - if (!processQualifierType(processor, qualifierType, state, place)) return false; - if (qualifier instanceof GrReferenceExpression && !PsiUtil.isSuperReference(qualifier) && !PsiUtil.isInstanceThisRef(qualifier)) { - PsiElement resolved = ((GrReferenceExpression)qualifier).resolve(); - if (resolved instanceof PsiClass) { - if (!processJavaLangClass(qualifierType, processor, state, place)) return false; - } - } - } - return true; - } - - private static boolean processJavaLangClass(@NotNull PsiType qualifierType, - @NotNull PsiScopeProcessor processor, - @NotNull ResolveState state, - @NotNull GrReferenceExpression place) { - //omitted .class - PsiClass javaLangClass = PsiUtil.getJavaLangClass(place, place.getResolveScope()); - if (javaLangClass == null) return true; - - PsiTypeParameter[] typeParameters = javaLangClass.getTypeParameters(); - PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY); - if (substitutor == null) substitutor = PsiSubstitutor.EMPTY; - if (typeParameters.length == 1) { - substitutor = substitutor.put(typeParameters[0], qualifierType); - state = state.put(PsiSubstitutor.KEY, substitutor); - } - if (!javaLangClass.processDeclarations(processor, state, null, place)) return false; - - PsiType javaLangClassType = JavaPsiFacade.getElementFactory(place.getProject()).createType(javaLangClass, substitutor); - - if (!ResolveUtil.processNonCodeMembers(javaLangClassType, processor, place, state)) return false; - - return true; - } - - private static boolean processQualifierType(@NotNull PsiScopeProcessor processor, - @NotNull PsiType originalQualifierType, - @NotNull ResolveState state, - @NotNull GrReferenceExpression place) { - PsiType qualifierType = originalQualifierType instanceof PsiDisjunctionType - ? ((PsiDisjunctionType)originalQualifierType).getLeastUpperBound() - : originalQualifierType; - - if (qualifierType instanceof PsiIntersectionType) { - for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) { - if (!processQualifierType(processor, conjunct, state, place)) return false; - } - return true; - } - - if (qualifierType instanceof GrTraitType) { - if (!processTraitType((GrTraitType)qualifierType, processor, state, place)) { - return false; - } - return true; - } - - if (qualifierType instanceof PsiClassType) { - PsiClassType.ClassResolveResult qualifierResult = ((PsiClassType)qualifierType).resolveGenerics(); - PsiClass qualifierClass = qualifierResult.getElement(); - if (qualifierClass != null) { - if (!qualifierClass.processDeclarations(processor, state.put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor()), null, place)) { - return false; - } - } - } - else if (qualifierType instanceof PsiArrayType) { - final GroovyPsiManager gmanager = GroovyPsiManager.getInstance(place.getProject()); - final GrTypeDefinition arrayClass = gmanager.getArrayClass(((PsiArrayType)qualifierType).getComponentType()); - if (arrayClass != null && !arrayClass.processDeclarations(processor, state, null, place)) return false; - } - - if (!(place.getParent() instanceof GrMethodCall) && InheritanceUtil.isInheritor(qualifierType, CommonClassNames.JAVA_UTIL_COLLECTION)) { - final PsiType componentType = ClosureParameterEnhancer.findTypeForIteration(qualifierType, place); - if (componentType != null) { - final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE); - processQualifierType(processor, componentType, state.put(SpreadState.SPREAD_STATE, SpreadState.create(qualifierType, spreadState)), place); - } - } - - if (!ResolveUtil.processCategoryMembers(place, processor, state)) return false; - if (!ResolveUtil.processNonCodeMembers(qualifierType, processor, place, state)) return false; - return true; - } - - private static boolean processTraitType(@NotNull GrTraitType traitType, - @NotNull PsiScopeProcessor processor, - @NotNull ResolveState state, - @NotNull GrReferenceExpression place) { - GrTypeDefinition mockDefinition = traitType.getMockTypeDefinition(); - if (mockDefinition != null) { - if (!mockDefinition.processDeclarations(processor, state, null, place)) { - return false; - } - } - else { - PsiClassType exprType = traitType.getExprType(); - - if (!processQualifierType(processor, exprType, state, place)) return false; - - List<PsiClassType> traitTypes = traitType.getTraitTypes(); - for (ListIterator<PsiClassType> iterator = traitTypes.listIterator(); iterator.hasPrevious(); ) { - PsiClassType type = iterator.previous(); - if (!processQualifierType(processor, type, state, place)) return false; - } - } - - return true; - } - - @Nullable - public static PsiType getQualifierType(@NotNull GrReferenceExpression ref) { - final GrExpression rtQualifier = PsiImplUtil.getRuntimeQualifier(ref); - if (rtQualifier != null) { - return rtQualifier.getType(); - } - - PsiClass containingClass = null; - final GrMember member = PsiTreeUtil.getParentOfType(ref, GrMember.class); - if (member == null) { - final PsiFile file = ref.getContainingFile(); - if (file instanceof GroovyFileBase && ((GroovyFileBase)file).isScript()) { - containingClass = ((GroovyFileBase)file).getScriptClass(); - } - else { - return null; - } - } - else if (member instanceof GrMethod) { - if (!member.hasModifierProperty(PsiModifier.STATIC)) { - containingClass = member.getContainingClass(); - } - } - - if (containingClass != null) { - final PsiClassType categoryType = GdkMethodUtil.getCategoryType(containingClass); - if (categoryType != null) { - return categoryType; - } - return JavaPsiFacade.getElementFactory(ref.getProject()).createType(containingClass); - } - return null; - } - - public static boolean resolveThisExpression(@NotNull GrReferenceExpression ref, - @NotNull List<GroovyResolveResult> results) { - GrExpression qualifier = ref.getQualifier(); - - if (qualifier == null) { - final PsiElement parent = ref.getParent(); - if (parent instanceof GrConstructorInvocation) { - GroovyResolveResult[] res = ((GrConstructorInvocation)parent).multiResolve(false); - ContainerUtil.addAll(results, res); - return true; - } - - PsiClass aClass = PsiUtil.getContextClass(ref); - if (aClass == null) return false; - - results.add(new GroovyResolveResultImpl(aClass, null, null, PsiSubstitutor.EMPTY, true, true)); - return true; - } - else { - if (!(qualifier instanceof GrReferenceExpression)) return false; - - GroovyResolveResult result = ((GrReferenceExpression)qualifier).advancedResolve(); - PsiElement resolved = result.getElement(); - if (!(resolved instanceof PsiClass)) return false; - if (!PsiUtil.hasEnclosingInstanceInScope((PsiClass)resolved, ref, false)) return false; - - results.add(result); - return true; - } - } - - public static boolean resolveSuperExpression(@NotNull GrReferenceExpression ref, - @NotNull List<GroovyResolveResult> results) { - GrExpression qualifier = ref.getQualifier(); - - PsiClass aClass; - if (qualifier == null) { - final PsiElement parent = ref.getParent(); - if (parent instanceof GrConstructorInvocation) { - GroovyResolveResult[] res = ((GrConstructorInvocation)parent).multiResolve(false); - ContainerUtil.addAll(results, res); - return true; - } - - aClass = PsiUtil.getContextClass(ref); - if (aClass == null) return false; - } - else { - if (!(qualifier instanceof GrReferenceExpression)) return false; - - GroovyResolveResult result = ((GrReferenceExpression)qualifier).advancedResolve(); - PsiElement resolved = result.getElement(); - if (!(resolved instanceof PsiClass)) return false; - aClass = (PsiClass)resolved; - - GrTypeDefinition scopeClass = PsiTreeUtil.getParentOfType(ref, GrTypeDefinition.class, true); - if (GrTraitUtil.isTrait(aClass) && scopeClass != null && PsiUtil.scopeClassImplementsTrait(aClass, ref)) { - PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(aClass, scopeClass, PsiSubstitutor.EMPTY); - results.add(new GroovyResolveResultImpl(aClass, null, null, superClassSubstitutor, true, true)); - return true; - } - - if (!PsiUtil.hasEnclosingInstanceInScope((PsiClass)resolved, ref, false)) return false; - - } - PsiClass superClass = aClass.getSuperClass(); - if (superClass == null) return true; //no super class, but the reference is definitely super-reference - - PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY); - results.add(new GroovyResolveResultImpl(superClass, null, null, superClassSubstitutor, true, true)); - return true; - } - - public static boolean isClassReference(@NotNull GrReferenceExpression ref) { - GrExpression qualifier = ref.getQualifier(); - return "class".equals(ref.getReferenceName()) && - qualifier instanceof GrReferenceExpression && - ((GrReferenceExpression)qualifier).resolve() instanceof PsiClass && - !PsiUtil.isThisReference(qualifier); - } - - public static boolean isPropertyAccessInStaticMethod(@NotNull GrReferenceExpression referenceExpression) { - return isInStaticContext(referenceExpression) && - !(referenceExpression.getParent() instanceof GrMethodCall) && - referenceExpression.getQualifier() == null; - } - - public static boolean isInStaticContext(@NotNull PsiElement place) { - GrMember context = PsiTreeUtil.getParentOfType(place, GrMember.class, true, GrClosableBlock.class); - return (context instanceof GrMethod || context instanceof GrClassInitializer) && context.hasModifierProperty(PsiModifier.STATIC); - } -} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrSuperReferenceResolver.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrSuperReferenceResolver.java new file mode 100644 index 000000000000..0b45314b34a0 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrSuperReferenceResolver.java @@ -0,0 +1,84 @@ +/* + * 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.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiSubstitutor; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.TypeConversionUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation; +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.impl.GroovyResolveResultImpl; +import org.jetbrains.plugins.groovy.lang.psi.util.GrTraitUtil; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; + +/** + * Created by Max Medvedev on 15/06/14 + */ +public class GrSuperReferenceResolver { + @Nullable("null if ref is not 'super' reference") + public static GroovyResolveResult[] resolveSuperExpression(@NotNull GrReferenceExpression ref) { + GrExpression qualifier = ref.getQualifier(); + + if (qualifier == null) { + final PsiElement parent = ref.getParent(); + if (parent instanceof GrConstructorInvocation) { + return ((GrConstructorInvocation)parent).multiResolve(false); + } + PsiClass aClass = PsiUtil.getContextClass(ref); + if (aClass != null) { + return getSuperClass(aClass); + } + } + else if (qualifier instanceof GrReferenceExpression) { + GroovyResolveResult result = ((GrReferenceExpression)qualifier).advancedResolve(); + PsiElement resolved = result.getElement(); + if (resolved instanceof PsiClass) { + PsiClass superClass = (PsiClass)resolved; + + GrTypeDefinition scopeClass = PsiTreeUtil.getParentOfType(ref, GrTypeDefinition.class, true); + if (scopeClass != null && GrTraitUtil.isTrait(superClass) && scopeClass.isInheritor(superClass, false)) { + PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, scopeClass, PsiSubstitutor.EMPTY); + return new GroovyResolveResultImpl[]{new GroovyResolveResultImpl(superClass, null, null, superClassSubstitutor, true, true)}; + } + + if (PsiUtil.hasEnclosingInstanceInScope(superClass, ref, false)) { + return getSuperClass(superClass); + } + } + } + + return null; + } + + @NotNull + private static GroovyResolveResult[] getSuperClass(@NotNull PsiClass aClass) { + PsiClass superClass = aClass.getSuperClass(); + if (superClass != null) { + PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY); + return new GroovyResolveResultImpl[]{new GroovyResolveResultImpl(superClass, null, null, superClassSubstitutor, true, true)}; + } + else { + return GroovyResolveResult.EMPTY_ARRAY; //no super class, but the reference is definitely super-reference + } + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrThisReferenceResolver.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrThisReferenceResolver.java new file mode 100644 index 000000000000..c891459ae7de --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrThisReferenceResolver.java @@ -0,0 +1,45 @@ +package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiSubstitutor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation; +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.impl.GroovyResolveResultImpl; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; + +/** + * Created by Max Medvedev on 15/06/14 + */ +public class GrThisReferenceResolver { + @Nullable("null if ref is not actually 'this' reference") + public static GroovyResolveResult[] resolveThisExpression(@NotNull GrReferenceExpression ref) { + GrExpression qualifier = ref.getQualifier(); + + if (qualifier == null) { + final PsiElement parent = ref.getParent(); + if (parent instanceof GrConstructorInvocation) { + return ((GrConstructorInvocation)parent).multiResolve(false); + } + else { + PsiClass aClass = PsiUtil.getContextClass(ref); + if (aClass != null) { + return new GroovyResolveResultImpl[]{new GroovyResolveResultImpl(aClass, null, null, PsiSubstitutor.EMPTY, true, true)}; + } + } + } + else if (qualifier instanceof GrReferenceExpression) { + GroovyResolveResult result = ((GrReferenceExpression)qualifier).advancedResolve(); + PsiElement resolved = result.getElement(); + if (resolved instanceof PsiClass && PsiUtil.hasEnclosingInstanceInScope((PsiClass)resolved, ref, false)) { + return new GroovyResolveResult[]{result}; + } + } + + return null; + } +} |