2 * Copyright 2000-2015 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions;
18 import com.intellij.openapi.progress.ProgressManager;
19 import com.intellij.psi.*;
20 import com.intellij.psi.util.InheritanceUtil;
21 import org.jetbrains.annotations.NotNull;
22 import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
23 import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState;
24 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
25 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
26 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
27 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
28 import org.jetbrains.plugins.groovy.lang.psi.impl.GrTraitType;
29 import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
30 import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
31 import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParameterEnhancer;
32 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
33 import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
34 import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint;
35 import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor;
38 * @author Medvedev Max
40 public class GrReferenceResolveRunner {
42 private final GrReferenceExpression place;
43 private ResolverProcessor processor;
45 public GrReferenceResolveRunner(@NotNull GrReferenceExpression _place) {
49 public boolean resolveImpl(@NotNull ResolverProcessor _processor) {
50 processor = _processor;
52 boolean result = doResolve();
53 ProgressManager.checkCanceled();
61 private boolean doResolve() {
62 GrExpression qualifier = place.getQualifier();
63 if (qualifier == null) {
64 if (!ResolveUtil.treeWalkUp(place, processor, true)) return false;
65 if (!processor.hasCandidates()) {
66 GrExpression runtimeQualifier = PsiImplUtil.getRuntimeQualifier(place);
67 if (runtimeQualifier != null) {
68 if (!processQualifier(runtimeQualifier)) return false;
73 if (place.getDotTokenType() == GroovyTokenTypes.mSPREAD_DOT) {
74 final PsiType qtype = qualifier.getType();
75 final PsiType componentType = ClosureParameterEnhancer.findTypeForIteration(qtype, place);
76 if (componentType != null) {
77 final ResolveState state = ResolveState.initial()
78 .put(ClassHint.RESOLVE_CONTEXT, qualifier)
79 .put(SpreadState.SPREAD_STATE, SpreadState.create(qtype, null));
80 if (!processQualifierType(componentType, state)) return false;
84 if (ResolveUtil.isClassReference(place)) return true;
85 if (!processQualifier(qualifier)) return false;
86 if (!processJavaLangClass(qualifier)) return false;
92 private boolean processJavaLangClass(@NotNull GrExpression qualifier) {
93 if (!(qualifier instanceof GrReferenceExpression)) return true;
95 //optimization: only 'class' or 'this' in static context can be an alias of java.lang.Class
96 if (!("class".equals(((GrReferenceExpression)qualifier).getReferenceName()) ||
97 PsiUtil.isThisReference(qualifier))) {
101 PsiType type = qualifier.getType();
102 if (!(type instanceof PsiClassType)) return true;
104 final PsiClass psiClass = ((PsiClassType)type).resolve();
105 if (psiClass == null || !CommonClassNames.JAVA_LANG_CLASS.equals(psiClass.getQualifiedName())) return true;
107 final PsiType[] params = ((PsiClassType)type).getParameters();
108 if (params.length != 1) return true;
110 if (!processQualifierType(params[0], ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, qualifier))) {
116 private boolean processQualifier(@NotNull GrExpression qualifier) {
117 PsiType qualifierType = qualifier.getType();
118 ResolveState state = ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, qualifier);
119 if (qualifierType == null || PsiType.VOID.equals(qualifierType)) {
120 if (qualifier instanceof GrReferenceExpression) {
121 PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
122 if (resolved != null && !resolved.processDeclarations(processor, state, null, place)) return false;
123 if (!(resolved instanceof PsiPackage)) {
124 PsiType objectQualifier = TypesUtil.getJavaLangObject(place);
125 if (!processQualifierType(objectQualifier, state)) return false;
130 if (!processQualifierType(qualifierType, state)) return false;
131 if (qualifier instanceof GrReferenceExpression && !PsiUtil.isSuperReference(qualifier) && !PsiUtil.isInstanceThisRef(qualifier)) {
132 PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
133 if (resolved instanceof PsiClass) {
134 if (!processJavaLangClass(qualifierType, state)) return false;
141 private boolean processJavaLangClass(@NotNull PsiType qualifierType,
142 @NotNull ResolveState state) {
144 PsiClass javaLangClass = PsiUtil.getJavaLangClass(place, place.getResolveScope());
145 if (javaLangClass == null) return true;
147 PsiTypeParameter[] typeParameters = javaLangClass.getTypeParameters();
148 PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY);
149 if (substitutor == null) substitutor = PsiSubstitutor.EMPTY;
150 if (typeParameters.length == 1) {
151 substitutor = substitutor.put(typeParameters[0], qualifierType);
152 state = state.put(PsiSubstitutor.KEY, substitutor);
154 if (!javaLangClass.processDeclarations(processor, state, null, place)) return false;
156 PsiType javaLangClassType = JavaPsiFacade.getElementFactory(place.getProject()).createType(javaLangClass, substitutor);
158 if (!ResolveUtil.processNonCodeMembers(javaLangClassType, processor, place, state)) return false;
163 private boolean processQualifierType(@NotNull PsiType originalQualifierType,
164 @NotNull ResolveState state) {
165 PsiType qualifierType = originalQualifierType instanceof PsiDisjunctionType
166 ? ((PsiDisjunctionType)originalQualifierType).getLeastUpperBound()
167 : originalQualifierType;
169 if (qualifierType instanceof GrTraitType) {
170 return processTraitType((GrTraitType)qualifierType, state);
172 else if (qualifierType instanceof PsiIntersectionType) {
173 for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) {
174 if (!processQualifierType(conjunct, state)) return false;
179 if (qualifierType instanceof PsiClassType) {
180 PsiClassType.ClassResolveResult qualifierResult = ((PsiClassType)qualifierType).resolveGenerics();
181 PsiClass qualifierClass = qualifierResult.getElement();
182 if (qualifierClass != null) {
183 if (!qualifierClass.processDeclarations(processor, state.put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor()), null, place)) {
188 else if (qualifierType instanceof PsiArrayType) {
189 final GroovyPsiManager gmanager = GroovyPsiManager.getInstance(place.getProject());
190 final GrTypeDefinition arrayClass = gmanager.getArrayClass(((PsiArrayType)qualifierType).getComponentType());
191 if (arrayClass != null && !arrayClass.processDeclarations(processor, state, null, place)) return false;
194 if (!(place.getParent() instanceof GrMethodCall) && InheritanceUtil.isInheritor(qualifierType, CommonClassNames.JAVA_UTIL_COLLECTION)) {
195 final PsiType componentType = ClosureParameterEnhancer.findTypeForIteration(qualifierType, place);
196 if (componentType != null) {
197 final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE);
198 processQualifierType(componentType, state.put(SpreadState.SPREAD_STATE, SpreadState.create(qualifierType, spreadState)));
202 if (!ResolveUtil.processCategoryMembers(place, processor, state)) return false;
203 if (!ResolveUtil.processNonCodeMembers(qualifierType, processor, place, state)) return false;
207 private boolean processTraitType(@NotNull GrTraitType traitType, @NotNull ResolveState state) {
208 final PsiType[] conjuncts = traitType.getConjuncts();
209 for (int i = conjuncts.length - 1; i >= 0; i--) {
210 if (!processQualifierType(conjuncts[i], state)) return false;