fa201a4713e74bcf4fc302d01cc4de354c3972ef
[idea/community.git] / plugins / groovy / groovy-psi / src / org / jetbrains / plugins / groovy / lang / psi / impl / statements / expressions / GrReferenceResolveRunner.java
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions;
17
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;
36
37 import java.util.List;
38 import java.util.ListIterator;
39
40 /**
41  * @author Medvedev Max
42  */
43 public class GrReferenceResolveRunner {
44
45   private final GrReferenceExpression place;
46   private ResolverProcessor processor;
47
48   public GrReferenceResolveRunner(@NotNull GrReferenceExpression _place) {
49     place = _place;
50   }
51
52   public boolean resolveImpl(@NotNull ResolverProcessor _processor) {
53     processor = _processor;
54     try {
55       boolean result = doResolve();
56       ProgressManager.checkCanceled();
57       return result;
58     }
59     finally {
60       processor = null;
61     }
62   }
63
64   private boolean doResolve() {
65     GrExpression qualifier = place.getQualifier();
66     if (qualifier == null) {
67       if (!ResolveUtil.treeWalkUp(place, processor, true)) return false;
68       if (!processor.hasCandidates()) {
69         GrExpression runtimeQualifier = PsiImplUtil.getRuntimeQualifier(place);
70         if (runtimeQualifier != null) {
71           if (!processQualifier(runtimeQualifier)) return false;
72         }
73       }
74     }
75     else {
76       if (place.getDotTokenType() == GroovyTokenTypes.mSPREAD_DOT) {
77         final PsiType qtype = qualifier.getType();
78         final PsiType componentType = ClosureParameterEnhancer.findTypeForIteration(qtype, place);
79         if (componentType != null) {
80           final ResolveState state = ResolveState.initial()
81             .put(ClassHint.RESOLVE_CONTEXT, qualifier)
82             .put(SpreadState.SPREAD_STATE, SpreadState.create(qtype, null));
83           if (!processQualifierType(componentType, state)) return false;
84         }
85       }
86       else {
87         if (ResolveUtil.isClassReference(place)) return true;
88         if (!processQualifier(qualifier)) return false;
89         if (!processJavaLangClass(qualifier)) return false;
90       }
91     }
92     return true;
93   }
94
95   private boolean processJavaLangClass(@NotNull GrExpression qualifier) {
96     if (!(qualifier instanceof GrReferenceExpression)) return true;
97
98     //optimization: only 'class' or 'this' in static context can be an alias of java.lang.Class
99     if (!("class".equals(((GrReferenceExpression)qualifier).getReferenceName()) ||
100           PsiUtil.isThisReference(qualifier))) {
101       return true;
102     }
103
104     PsiType type = qualifier.getType();
105     if (!(type instanceof PsiClassType)) return true;
106
107     final PsiClass psiClass = ((PsiClassType)type).resolve();
108     if (psiClass == null || !CommonClassNames.JAVA_LANG_CLASS.equals(psiClass.getQualifiedName())) return true;
109
110     final PsiType[] params = ((PsiClassType)type).getParameters();
111     if (params.length != 1) return true;
112
113     if (!processQualifierType(params[0], ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, qualifier))) {
114       return false;
115     }
116     return true;
117   }
118
119   private boolean processQualifier(@NotNull GrExpression qualifier) {
120     PsiType qualifierType = qualifier.getType();
121     ResolveState state = ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, qualifier);
122     if (qualifierType == null || PsiType.VOID.equals(qualifierType)) {
123       if (qualifier instanceof GrReferenceExpression) {
124         PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
125         if (resolved != null && !resolved.processDeclarations(processor, state, null, place)) return false;
126         if (!(resolved instanceof PsiPackage)) {
127           PsiType objectQualifier = TypesUtil.getJavaLangObject(place);
128           if (!processQualifierType(objectQualifier, state)) return false;
129         }
130       }
131     }
132     else if (qualifierType instanceof PsiIntersectionType) {
133       for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) {
134         if (!processQualifierType(conjunct, state)) return false;
135       }
136     }
137     else {
138       if (!processQualifierType(qualifierType, state)) return false;
139       if (qualifier instanceof GrReferenceExpression && !PsiUtil.isSuperReference(qualifier) && !PsiUtil.isInstanceThisRef(qualifier)) {
140         PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
141         if (resolved instanceof PsiClass) {
142           if (!processJavaLangClass(qualifierType, state)) return false;
143         }
144       }
145     }
146     return true;
147   }
148
149   private boolean processJavaLangClass(@NotNull PsiType qualifierType,
150                                        @NotNull ResolveState state) {
151     //omitted .class
152     PsiClass javaLangClass = PsiUtil.getJavaLangClass(place, place.getResolveScope());
153     if (javaLangClass == null) return true;
154
155     PsiTypeParameter[] typeParameters = javaLangClass.getTypeParameters();
156     PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY);
157     if (substitutor == null) substitutor = PsiSubstitutor.EMPTY;
158     if (typeParameters.length == 1) {
159       substitutor = substitutor.put(typeParameters[0], qualifierType);
160       state = state.put(PsiSubstitutor.KEY, substitutor);
161     }
162     if (!javaLangClass.processDeclarations(processor, state, null, place)) return false;
163
164     PsiType javaLangClassType = JavaPsiFacade.getElementFactory(place.getProject()).createType(javaLangClass, substitutor);
165
166     if (!ResolveUtil.processNonCodeMembers(javaLangClassType, processor, place, state)) return false;
167
168     return true;
169   }
170
171   private boolean processQualifierType(@NotNull PsiType originalQualifierType,
172                                        @NotNull ResolveState state) {
173     PsiType qualifierType = originalQualifierType instanceof PsiDisjunctionType
174                             ? ((PsiDisjunctionType)originalQualifierType).getLeastUpperBound()
175                             : originalQualifierType;
176
177     if (qualifierType instanceof PsiIntersectionType) {
178       for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) {
179         if (!processQualifierType(conjunct, state)) return false;
180       }
181       return true;
182     }
183
184     if (qualifierType instanceof GrTraitType) {
185       if (!processTraitType((GrTraitType)qualifierType, state)) {
186         return false;
187       }
188       return true;
189     }
190
191     if (qualifierType instanceof PsiClassType) {
192       PsiClassType.ClassResolveResult qualifierResult = ((PsiClassType)qualifierType).resolveGenerics();
193       PsiClass qualifierClass = qualifierResult.getElement();
194       if (qualifierClass != null) {
195         if (!qualifierClass.processDeclarations(processor, state.put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor()), null, place)) {
196           return false;
197         }
198       }
199     }
200     else if (qualifierType instanceof PsiArrayType) {
201       final GroovyPsiManager gmanager = GroovyPsiManager.getInstance(place.getProject());
202       final GrTypeDefinition arrayClass = gmanager.getArrayClass(((PsiArrayType)qualifierType).getComponentType());
203       if (arrayClass != null && !arrayClass.processDeclarations(processor, state, null, place)) return false;
204     }
205
206     if (!(place.getParent() instanceof GrMethodCall) && InheritanceUtil.isInheritor(qualifierType, CommonClassNames.JAVA_UTIL_COLLECTION)) {
207       final PsiType componentType = ClosureParameterEnhancer.findTypeForIteration(qualifierType, place);
208       if (componentType != null) {
209         final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE);
210         processQualifierType(componentType, state.put(SpreadState.SPREAD_STATE, SpreadState.create(qualifierType, spreadState)));
211       }
212     }
213
214     if (!ResolveUtil.processCategoryMembers(place, processor, state)) return false;
215     if (!ResolveUtil.processNonCodeMembers(qualifierType, processor, place, state)) return false;
216     return true;
217   }
218
219   private boolean processTraitType(@NotNull GrTraitType traitType, @NotNull ResolveState state) {
220     GrTypeDefinition mockDefinition = traitType.getMockTypeDefinition();
221     if (mockDefinition != null) {
222       if (!mockDefinition.processDeclarations(processor, state, null, place)) {
223         return false;
224       }
225     }
226     else {
227       PsiClassType exprType = traitType.getExprType();
228
229       if (!processQualifierType(exprType, state)) return false;
230
231       List<PsiClassType> traitTypes = traitType.getTraitTypes();
232       for (ListIterator<PsiClassType> iterator = traitTypes.listIterator(); iterator.hasPrevious(); ) {
233         PsiClassType type = iterator.previous();
234         if (!processQualifierType(type, state)) return false;
235       }
236     }
237
238     return true;
239   }
240 }