2 * Copyright 2000-2014 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;
37 import java.util.List;
38 import java.util.ListIterator;
41 * @author Medvedev Max
43 public class GrReferenceResolveRunner {
45 private final GrReferenceExpression place;
46 private ResolverProcessor processor;
48 public GrReferenceResolveRunner(@NotNull GrReferenceExpression _place) {
52 public boolean resolveImpl(@NotNull ResolverProcessor _processor) {
53 processor = _processor;
55 boolean result = doResolve();
56 ProgressManager.checkCanceled();
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;
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;
87 if (ResolveUtil.isClassReference(place)) return true;
88 if (!processQualifier(qualifier)) return false;
89 if (!processJavaLangClass(qualifier)) return false;
95 private boolean processJavaLangClass(@NotNull GrExpression qualifier) {
96 if (!(qualifier instanceof GrReferenceExpression)) return true;
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))) {
104 PsiType type = qualifier.getType();
105 if (!(type instanceof PsiClassType)) return true;
107 final PsiClass psiClass = ((PsiClassType)type).resolve();
108 if (psiClass == null || !CommonClassNames.JAVA_LANG_CLASS.equals(psiClass.getQualifiedName())) return true;
110 final PsiType[] params = ((PsiClassType)type).getParameters();
111 if (params.length != 1) return true;
113 if (!processQualifierType(params[0], ResolveState.initial().put(ClassHint.RESOLVE_CONTEXT, qualifier))) {
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;
132 else if (qualifierType instanceof PsiIntersectionType) {
133 for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) {
134 if (!processQualifierType(conjunct, state)) return false;
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;
149 private boolean processJavaLangClass(@NotNull PsiType qualifierType,
150 @NotNull ResolveState state) {
152 PsiClass javaLangClass = PsiUtil.getJavaLangClass(place, place.getResolveScope());
153 if (javaLangClass == null) return true;
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);
162 if (!javaLangClass.processDeclarations(processor, state, null, place)) return false;
164 PsiType javaLangClassType = JavaPsiFacade.getElementFactory(place.getProject()).createType(javaLangClass, substitutor);
166 if (!ResolveUtil.processNonCodeMembers(javaLangClassType, processor, place, state)) return false;
171 private boolean processQualifierType(@NotNull PsiType originalQualifierType,
172 @NotNull ResolveState state) {
173 PsiType qualifierType = originalQualifierType instanceof PsiDisjunctionType
174 ? ((PsiDisjunctionType)originalQualifierType).getLeastUpperBound()
175 : originalQualifierType;
177 if (qualifierType instanceof PsiIntersectionType) {
178 for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) {
179 if (!processQualifierType(conjunct, state)) return false;
184 if (qualifierType instanceof GrTraitType) {
185 if (!processTraitType((GrTraitType)qualifierType, state)) {
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)) {
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;
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)));
214 if (!ResolveUtil.processCategoryMembers(place, processor, state)) return false;
215 if (!ResolveUtil.processNonCodeMembers(qualifierType, processor, place, state)) return false;
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)) {
227 PsiClassType exprType = traitType.getExprType();
229 if (!processQualifierType(exprType, state)) return false;
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;