2 * Copyright 2000-2009 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.
17 package org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.statements
.expressions
;
19 import com
.intellij
.lang
.ASTNode
;
20 import com
.intellij
.openapi
.project
.Project
;
21 import com
.intellij
.openapi
.util
.Comparing
;
22 import com
.intellij
.openapi
.util
.Computable
;
23 import com
.intellij
.openapi
.util
.TextRange
;
24 import com
.intellij
.openapi
.util
.text
.StringUtil
;
25 import com
.intellij
.psi
.*;
26 import com
.intellij
.psi
.impl
.source
.resolve
.ResolveCache
;
27 import com
.intellij
.psi
.impl
.source
.resolve
.reference
.ReferenceProvidersRegistry
;
28 import com
.intellij
.psi
.impl
.source
.resolve
.reference
.impl
.PsiMultiReference
;
29 import com
.intellij
.psi
.tree
.IElementType
;
30 import com
.intellij
.psi
.util
.PropertyUtil
;
31 import com
.intellij
.psi
.util
.PsiTreeUtil
;
32 import com
.intellij
.psi
.util
.TypeConversionUtil
;
33 import com
.intellij
.util
.ArrayUtil
;
34 import com
.intellij
.util
.Function
;
35 import com
.intellij
.util
.IncorrectOperationException
;
36 import org
.jetbrains
.annotations
.NonNls
;
37 import org
.jetbrains
.annotations
.NotNull
;
38 import org
.jetbrains
.annotations
.Nullable
;
39 import org
.jetbrains
.plugins
.groovy
.lang
.lexer
.GroovyTokenTypes
;
40 import org
.jetbrains
.plugins
.groovy
.lang
.lexer
.TokenSets
;
41 import org
.jetbrains
.plugins
.groovy
.lang
.parser
.GroovyElementTypes
;
42 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.GroovyElementVisitor
;
43 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.GroovyFile
;
44 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.GroovyPsiElementFactory
;
45 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.GroovyResolveResult
;
46 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.GrField
;
47 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.GrVariable
;
48 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.GrVariableBase
;
49 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.blocks
.GrClosableBlock
;
50 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.GrApplicationStatement
;
51 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.GrAssignmentExpression
;
52 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.GrExpression
;
53 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.GrReferenceExpression
;
54 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.path
.GrMethodCallExpression
;
55 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.typedef
.GrTypeDefinition
;
56 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.typedef
.members
.GrAccessorMethod
;
57 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.toplevel
.imports
.GrImportStatement
;
58 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.types
.GrTypeArgumentList
;
59 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.GrClosureType
;
60 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.GrReferenceElementImpl
;
61 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.GroovyPsiManager
;
62 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.PsiImplUtil
;
63 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.util
.GrStringUtil
;
64 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.util
.GroovyPropertyUtils
;
65 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.util
.PsiUtil
;
66 import org
.jetbrains
.plugins
.groovy
.lang
.resolve
.ResolveUtil
;
67 import org
.jetbrains
.plugins
.groovy
.lang
.resolve
.processors
.*;
69 import java
.util
.EnumSet
;
74 public class GrReferenceExpressionImpl
extends GrReferenceElementImpl
implements GrReferenceExpression
{
75 public GrReferenceExpressionImpl(@NotNull ASTNode node
) {
79 public void accept(GroovyElementVisitor visitor
) {
80 visitor
.visitReferenceExpression(this);
84 public PsiElement
getReferenceNameElement() {
85 final ASTNode lastChild
= getNode().getLastChildNode();
86 if (lastChild
== null) return null;
87 for (IElementType elementType
: TokenSets
.REFERENCE_NAMES
.getTypes()) {
88 if (lastChild
.getElementType() == elementType
) return lastChild
.getPsi();
94 public PsiReference
getReference() {
95 PsiReference
[] otherReferences
= ReferenceProvidersRegistry
.getReferencesFromProviders(this, GrReferenceExpression
.class);
96 PsiReference
[] thisReference
= {this};
97 return new PsiMultiReference(otherReferences
.length
== 0 ? thisReference
: ArrayUtil
.mergeArrays(thisReference
, otherReferences
, PsiReference
.class), this);
101 public PsiElement
getQualifier() {
102 return getQualifierExpression();
105 public String
getReferenceName() {
106 PsiElement nameElement
= getReferenceNameElement();
107 if (nameElement
!= null) {
108 if (nameElement
.getNode().getElementType() == GroovyElementTypes
.mSTRING_LITERAL
||
109 nameElement
.getNode().getElementType() == GroovyElementTypes
.mGSTRING_LITERAL
) {
110 return GrStringUtil
.removeQuotes(nameElement
.getText());
113 return nameElement
.getText();
118 public PsiElement
handleElementRename(String newElementName
) throws IncorrectOperationException
{
119 final PsiElement resolved
= resolve();
120 if (resolved
instanceof PsiMethod
) {
121 final PsiMethod method
= (PsiMethod
) resolved
;
122 final String oldName
= getReferenceName();
123 if (!method
.getName().equals(oldName
)) { //was property reference to accessor
124 if (GroovyPropertyUtils
.isSimplePropertyAccessor(method
)) {
125 final String newPropertyName
= PropertyUtil
.getPropertyName(newElementName
);
126 if (newPropertyName
!= null) {
127 return doHandleElementRename(newPropertyName
);
129 //todo encapsulate fields:)
133 } else if (resolved
instanceof GrField
&& ((GrField
) resolved
).isProperty()) {
134 final GrField field
= (GrField
) resolved
;
135 final String oldName
= getReferenceName();
136 if (oldName
!= null && !oldName
.equals(field
.getName())) { //was accessor reference to property
137 if (oldName
.startsWith("get")) {
138 return doHandleElementRename("get" + StringUtil
.capitalize(newElementName
));
139 } else if (oldName
.startsWith("set")) {
140 return doHandleElementRename("set" + StringUtil
.capitalize(newElementName
));
145 return doHandleElementRename(newElementName
);
149 protected PsiElement
bindWithQualifiedRef(String qName
) {
150 final GrTypeArgumentList list
= getTypeArgumentList();
151 final String typeArgs
= (list
!= null) ? list
.getText() : "";
152 final String text
= qName
+ typeArgs
;
153 GrReferenceExpression qualifiedRef
= GroovyPsiElementFactory
.getInstance(getProject()).createReferenceExpressionFromText(text
);
154 getNode().getTreeParent().replaceChild(getNode(), qualifiedRef
.getNode());
158 private PsiElement
doHandleElementRename(String newElementName
) throws IncorrectOperationException
{
159 if (!PsiUtil
.isValidReferenceName(newElementName
)) {
160 PsiElement element
= GroovyPsiElementFactory
.getInstance(getProject()).createStringLiteral(newElementName
);
161 getReferenceNameElement().replace(element
);
165 return super.handleElementRename(newElementName
);
168 public int getTextOffset() {
169 PsiElement parent
= getParent();
170 TextRange range
= getTextRange();
171 if (!(parent
instanceof GrAssignmentExpression
) || !this.equals(((GrAssignmentExpression
) parent
).getLValue())) {
172 return range
.getEndOffset(); //need this as a hack against TargetElementUtil
175 return range
.getStartOffset();
178 public String
toString() {
179 return "Reference expression";
183 public PsiElement
resolve() {
184 ResolveResult
[] results
= getManager().getResolveCache().resolveWithCaching(this, RESOLVER
, true, false);
185 return results
.length
== 1 ? results
[0].getElement() : null;
188 private static final OurResolver RESOLVER
= new OurResolver();
190 private static final OurTypesCalculator TYPES_CALCULATOR
= new OurTypesCalculator();
192 public PsiType
getNominalType() {
193 return GroovyPsiManager
.getInstance(getProject()).getTypeInferenceHelper().doWithInferenceDisabled(new Computable
<PsiType
>() {
194 public PsiType
compute() {
195 return getNominalTypeImpl();
201 private PsiType
getNominalTypeImpl() {
202 IElementType dotType
= getDotTokenType();
204 final GroovyResolveResult resolveResult
= advancedResolve();
205 PsiElement resolved
= resolveResult
.getElement();
206 if (dotType
== GroovyTokenTypes
.mMEMBER_POINTER
) {
207 if (resolved
instanceof PsiMethod
) {
208 PsiMethod method
= (PsiMethod
) resolved
;
209 PsiType returnType
= resolveResult
.getSubstitutor().substitute(method
.getReturnType());
210 return GrClosureType
.create(getResolveScope(), returnType
, method
.getParameterList().getParameters(), getManager());
212 return JavaPsiFacade
.getInstance(getProject()).getElementFactory().createTypeByFQClassName(GrClosableBlock
.GROOVY_LANG_CLOSURE
, getResolveScope());
214 PsiType result
= null;
215 JavaPsiFacade facade
= JavaPsiFacade
.getInstance(getProject());
216 if (resolved
== null && !"class".equals(getReferenceName())) {
217 resolved
= getReference().resolve();
219 if (resolved
instanceof PsiClass
) {
220 if (getParent() instanceof GrReferenceExpression
) {
221 result
= facade
.getElementFactory().createType((PsiClass
) resolved
);
223 PsiClass javaLangClass
= facade
.findClass("java.lang.Class", getResolveScope());
224 if (javaLangClass
!= null) {
225 PsiSubstitutor substitutor
= PsiSubstitutor
.EMPTY
;
226 final PsiTypeParameter
[] typeParameters
= javaLangClass
.getTypeParameters();
227 if (typeParameters
.length
== 1) {
228 substitutor
= substitutor
.put(typeParameters
[0], facade
.getElementFactory().createType((PsiClass
) resolved
));
230 result
= facade
.getElementFactory().createType(javaLangClass
, substitutor
);
233 } else if (resolved
instanceof GrVariableBase
) {
234 result
= ((GrVariableBase
) resolved
).getDeclaredType();
235 } else if (resolved
instanceof PsiVariable
) {
236 result
= ((PsiVariable
) resolved
).getType();
238 if (resolved
instanceof PsiMethod
&& !GroovyPsiManager
.isTypeBeingInferred(resolved
)) {
239 if (dotType
== GroovyTokenTypes
.mMEMBER_POINTER
) {
240 return facade
.getElementFactory().createTypeByFQClassName("groovy.lang.Closure", getResolveScope());
242 PsiMethod method
= (PsiMethod
) resolved
;
243 if (PropertyUtil
.isSimplePropertySetter(method
) && !method
.getName().equals(getReferenceName())) {
244 result
= method
.getParameterList().getParameters()[0].getType();
246 PsiClass containingClass
= method
.getContainingClass();
247 if (containingClass
!= null && "java.lang.Object".equals(containingClass
.getQualifiedName()) &&
248 "getClass".equals(method
.getName())) {
249 result
= getTypeForObjectGetClass(facade
, method
);
251 if (method
instanceof GrAccessorMethod
) {
252 result
= ((GrAccessorMethod
) method
).getReturnTypeGroovy();
254 result
= method
.getReturnType();
259 } else if (resolved
instanceof GrReferenceExpression
) {
260 PsiElement parent
= resolved
.getParent();
261 if (parent
instanceof GrAssignmentExpression
) {
262 GrAssignmentExpression assignment
= (GrAssignmentExpression
) parent
;
263 if (resolved
.equals(assignment
.getLValue())) {
264 GrExpression rValue
= assignment
.getRValue();
265 if (rValue
!= null) {
266 PsiType rType
= rValue
.getType();
267 if (rType
!= null) result
= rType
;
271 } else if (resolved
== null) {
272 if ("class".equals(getReferenceName())) {
273 return JavaPsiFacade
.getInstance(getProject()).getElementFactory().createTypeByFQClassName("java.lang.Class",
277 GrExpression qualifier
= getQualifierExpression();
278 if (qualifier
!= null) {
279 PsiType qType
= qualifier
.getType();
280 if (qType
instanceof PsiClassType
) {
281 PsiClassType
.ClassResolveResult qResult
= ((PsiClassType
) qType
).resolveGenerics();
282 PsiClass clazz
= qResult
.getElement();
284 PsiClass mapClass
= facade
.findClass("java.util.Map", getResolveScope());
285 if (mapClass
!= null && mapClass
.getTypeParameters().length
== 2) {
286 PsiSubstitutor substitutor
= TypeConversionUtil
.getClassSubstitutor(mapClass
, clazz
, qResult
.getSubstitutor());
287 if (substitutor
!= null) {
288 return substitutor
.substitute(mapClass
.getTypeParameters()[1]);
296 if (result
!= null) {
297 result
= resolveResult
.getSubstitutor().substitute(result
);
298 result
= TypesUtil
.boxPrimitiveType(result
, getManager(), getResolveScope());
300 if (dotType
!= GroovyTokenTypes
.mSPREAD_DOT
) {
303 return ResolveUtil
.getListTypeForSpreadOperator(this, result
);
308 private PsiType
getTypeForObjectGetClass(JavaPsiFacade facade
, PsiMethod method
) {
309 PsiType type
= method
.getReturnType();
310 if (type
instanceof PsiClassType
) {
311 PsiClass clazz
= ((PsiClassType
) type
).resolve();
313 "java.lang.Class".equals(clazz
.getQualifiedName())) {
314 PsiTypeParameter
[] typeParameters
= clazz
.getTypeParameters();
315 if (typeParameters
.length
== 1) {
316 PsiClass qualifierClass
= null;
317 GrExpression qualifier
= getQualifierExpression();
318 if (qualifier
!= null) {
319 PsiType qualifierType
= qualifier
.getType();
320 if (qualifierType
instanceof PsiClassType
) {
321 qualifierClass
= ((PsiClassType
) qualifierType
).resolve();
324 PsiNamedElement context
= PsiTreeUtil
.getParentOfType(this, PsiClass
.class, GroovyFile
.class);
325 if (context
instanceof PsiClass
) qualifierClass
= (PsiClass
) context
;
326 else if (context
instanceof GroovyFile
) qualifierClass
= ((GroovyFile
) context
).getScriptClass();
329 PsiSubstitutor substitutor
= PsiSubstitutor
.EMPTY
;
330 if (qualifierClass
!= null) {
331 PsiType t
= facade
.getElementFactory().createType(qualifierClass
);
332 substitutor
= substitutor
.put(typeParameters
[0], t
);
334 return facade
.getElementFactory().createType(clazz
, substitutor
);
341 private static final class OurTypesCalculator
implements Function
<GrReferenceExpressionImpl
, PsiType
> {
342 public PsiType
fun(GrReferenceExpressionImpl refExpr
) {
343 final PsiType inferred
= GroovyPsiManager
.getInstance(refExpr
.getProject()).getTypeInferenceHelper().getInferredType(refExpr
);
344 final PsiType nominal
= refExpr
.getNominalTypeImpl();
345 if (inferred
== null || PsiType
.NULL
.equals(inferred
)) {
346 if (nominal
== null) {
347 /*inside nested closure we could still try to infer from variable initializer.
348 * Not sound, but makes sense*/
349 final PsiElement resolved
= refExpr
.resolve();
350 if (resolved
instanceof GrVariableBase
) return ((GrVariableBase
) resolved
).getTypeGroovy();
356 if (nominal
== null) return inferred
;
357 if (!TypeConversionUtil
.isAssignable(nominal
, inferred
, false)) {
358 final PsiElement resolved
= refExpr
.resolve();
359 if (resolved
instanceof GrVariable
&& ((GrVariable
) resolved
).getTypeElementGroovy() != null) {
360 return nominal
; //see GRVY-487
367 public PsiType
getType() {
368 return GroovyPsiManager
.getInstance(getProject()).getType(this, TYPES_CALCULATOR
);
371 public GrExpression
replaceWithExpression(@NotNull GrExpression newExpr
, boolean removeUnnecessaryParentheses
) {
372 return PsiImplUtil
.replaceExpression(this, newExpr
, removeUnnecessaryParentheses
);
375 public String
getName() {
376 return getReferenceName();
379 public PsiElement
setName(@NonNls @NotNull String name
) throws IncorrectOperationException
{
380 PsiElement nameElement
= getReferenceNameElement();
381 ASTNode node
= nameElement
.getNode();
382 ASTNode newNameNode
= GroovyPsiElementFactory
.getInstance(getProject()).createReferenceNameFromText(name
).getNode();
383 assert newNameNode
!= null && node
!= null;
384 node
.getTreeParent().replaceChild(node
, newNameNode
);
389 private static class OurResolver
implements ResolveCache
.PolyVariantResolver
<GrReferenceExpressionImpl
> {
390 public GroovyResolveResult
[] resolve(GrReferenceExpressionImpl refExpr
, boolean incompleteCode
) {
391 String name
= refExpr
.getReferenceName();
392 if (name
== null) return null;
393 ResolverProcessor processor
= getMethodOrPropertyResolveProcessor(refExpr
, name
, incompleteCode
);
395 resolveImpl(refExpr
, processor
);
397 GroovyResolveResult
[] propertyCandidates
= processor
.getCandidates();
398 if (propertyCandidates
.length
> 0) return propertyCandidates
;
399 if (refExpr
.getKind() == Kind
.TYPE_OR_PROPERTY
) {
400 EnumSet
<ClassHint
.ResolveKind
> kinds
= refExpr
.getParent() instanceof GrReferenceExpression ?
401 EnumSet
.of(ClassHint
.ResolveKind
.CLASS
, ClassHint
.ResolveKind
.PACKAGE
) :
402 EnumSet
.of(ClassHint
.ResolveKind
.CLASS
);
403 ResolverProcessor classProcessor
= new ClassResolverProcessor(refExpr
.getReferenceName(), refExpr
, kinds
);
404 resolveImpl(refExpr
, classProcessor
);
405 return classProcessor
.getCandidates();
408 return GroovyResolveResult
.EMPTY_ARRAY
;
411 private void resolveImpl(GrReferenceExpressionImpl refExpr
, ResolverProcessor processor
) {
412 GrExpression qualifier
= refExpr
.getQualifierExpression();
413 if (qualifier
== null) {
414 ResolveUtil
.treeWalkUp(refExpr
, processor
, true);
415 if (!processor
.hasCandidates()) {
416 qualifier
= PsiImplUtil
.getRuntimeQualifier(refExpr
);
417 if (qualifier
!= null) {
418 processQualifier(refExpr
, processor
, qualifier
);
422 if (refExpr
.getDotTokenType() != GroovyTokenTypes
.mSPREAD_DOT
) {
423 processQualifier(refExpr
, processor
, qualifier
);
425 processQualifierForSpreadDot(refExpr
, processor
, qualifier
);
430 private static void processQualifierForSpreadDot(GrReferenceExpressionImpl refExpr
, ResolverProcessor processor
, GrExpression qualifier
) {
431 PsiType qualifierType
= qualifier
.getType();
432 if (qualifierType
instanceof PsiClassType
) {
433 PsiClassType
.ClassResolveResult result
= ((PsiClassType
) qualifierType
).resolveGenerics();
434 PsiClass clazz
= result
.getElement();
436 PsiClass listClass
= ResolveUtil
.findListClass(refExpr
.getManager(), refExpr
.getResolveScope());
437 if (listClass
!= null && listClass
.getTypeParameters().length
== 1) {
438 PsiSubstitutor substitutor
= TypeConversionUtil
.getClassSubstitutor(listClass
, clazz
, result
.getSubstitutor());
439 if (substitutor
!= null) {
440 PsiType componentType
= substitutor
.substitute(listClass
.getTypeParameters()[0]);
441 if (componentType
!= null) {
442 processClassQualifierType(refExpr
, processor
, componentType
);
447 } else if (qualifierType
instanceof PsiArrayType
) {
448 processClassQualifierType(refExpr
, processor
, ((PsiArrayType
) qualifierType
).getComponentType());
452 private static void processQualifier(GrReferenceExpressionImpl refExpr
, ResolverProcessor processor
, GrExpression qualifier
) {
453 PsiType qualifierType
= qualifier
.getType();
454 if (qualifierType
== null) {
455 if (qualifier
instanceof GrReferenceExpression
) {
456 PsiElement resolved
= ((GrReferenceExpression
) qualifier
).resolve();
457 if (resolved
instanceof PsiPackage
) {
458 if (!resolved
.processDeclarations(processor
, ResolveState
.initial(), null, refExpr
)) //noinspection UnnecessaryReturnStatement
462 qualifierType
= JavaPsiFacade
.getInstance(refExpr
.getProject()).getElementFactory()
463 .createTypeByFQClassName(CommonClassNames
.JAVA_LANG_OBJECT
, refExpr
.getResolveScope());
464 processClassQualifierType(refExpr
, processor
, qualifierType
);
468 if (qualifierType
instanceof PsiIntersectionType
) {
469 for (PsiType conjunct
: ((PsiIntersectionType
) qualifierType
).getConjuncts()) {
470 processClassQualifierType(refExpr
, processor
, conjunct
);
473 processClassQualifierType(refExpr
, processor
, qualifierType
);
474 if (qualifier
instanceof GrReferenceExpression
) {
475 PsiElement resolved
= ((GrReferenceExpression
) qualifier
).resolve();
476 if (resolved
instanceof PsiClass
) { //omitted .class
477 PsiClass javaLangClass
= PsiUtil
.getJavaLangClass(resolved
, refExpr
.getResolveScope());
478 if (javaLangClass
!= null) {
479 ResolveState state
= ResolveState
.initial();
480 PsiTypeParameter
[] typeParameters
= javaLangClass
.getTypeParameters();
481 PsiSubstitutor substitutor
= state
.get(PsiSubstitutor
.KEY
);
482 if (substitutor
== null) substitutor
= PsiSubstitutor
.EMPTY
;
483 if (typeParameters
.length
== 1) {
484 substitutor
= substitutor
.put(typeParameters
[0], qualifierType
);
485 state
= state
.put(PsiSubstitutor
.KEY
, substitutor
);
487 if (!javaLangClass
.processDeclarations(processor
, state
, null, refExpr
)) return;
488 PsiType javaLangClassType
= JavaPsiFacade
.getInstance(refExpr
.getProject()).getElementFactory().createType(javaLangClass
, substitutor
);
489 ResolveUtil
.processNonCodeMethods(javaLangClassType
, processor
, refExpr
.getProject(), refExpr
, false);
497 private static void processClassQualifierType(GrReferenceExpressionImpl refExpr
, ResolverProcessor processor
, PsiType qualifierType
) {
498 Project project
= refExpr
.getProject();
499 if (qualifierType
instanceof PsiClassType
) {
500 PsiClassType
.ClassResolveResult qualifierResult
= ((PsiClassType
) qualifierType
).resolveGenerics();
501 PsiClass qualifierClass
= qualifierResult
.getElement();
502 if (qualifierClass
!= null) {
503 if (!qualifierClass
.processDeclarations(processor
,
504 ResolveState
.initial().put(PsiSubstitutor
.KEY
, qualifierResult
.getSubstitutor()), null, refExpr
))
507 if (!ResolveUtil
.processCategoryMembers(refExpr
, processor
, (PsiClassType
) qualifierType
)) return;
508 } else if (qualifierType
instanceof PsiArrayType
) {
509 final GrTypeDefinition arrayClass
= GroovyPsiManager
.getInstance(project
).getArrayClass();
510 if (!arrayClass
.processDeclarations(processor
, ResolveState
.initial(), null, refExpr
)) return;
511 } else if (qualifierType
instanceof PsiIntersectionType
) {
512 for (PsiType conjunct
: ((PsiIntersectionType
) qualifierType
).getConjuncts()) {
513 processClassQualifierType(refExpr
, processor
, conjunct
);
518 ResolveUtil
.processNonCodeMethods(qualifierType
, processor
, project
, refExpr
, false);
522 private static ResolverProcessor
getMethodOrPropertyResolveProcessor(GrReferenceExpression refExpr
, String name
, boolean incomplete
) {
523 if (incomplete
) return CompletionProcessor
.createRefSameNameProcessor(refExpr
, name
);
525 Kind kind
= ((GrReferenceExpressionImpl
) refExpr
).getKind();
526 ResolverProcessor processor
;
527 if (kind
== Kind
.METHOD_OR_PROPERTY
) {
528 final PsiType
[] argTypes
= PsiUtil
.getArgumentTypes(refExpr
, false, false);
529 PsiType thisType
= getThisType(refExpr
);
530 processor
= new MethodResolverProcessor(name
, refExpr
, false, thisType
, argTypes
, refExpr
.getTypeArguments());
532 processor
= new PropertyResolverProcessor(name
, refExpr
);
538 private static PsiType
getThisType(GrReferenceExpression refExpr
) {
539 GrExpression qualifier
= refExpr
.getQualifierExpression();
540 if (qualifier
!= null) {
541 PsiType qType
= qualifier
.getType();
542 if (qType
!= null) return qType
;
545 return TypesUtil
.getJavaLangObject(refExpr
);
555 if (getDotTokenType() == GroovyTokenTypes
.mMEMBER_POINTER
) return Kind
.METHOD_OR_PROPERTY
;
557 PsiElement parent
= getParent();
558 if (parent
instanceof GrMethodCallExpression
|| parent
instanceof GrApplicationStatement
) {
559 return Kind
.METHOD_OR_PROPERTY
;
562 return Kind
.TYPE_OR_PROPERTY
;
566 public String
getCanonicalText() {
570 public boolean isReferenceTo(PsiElement element
) {
571 if (element
instanceof PsiMethod
&& GroovyPropertyUtils
.isSimplePropertyAccessor((PsiMethod
) element
)) {
572 final PsiElement target
= resolve();
573 if (element
instanceof GrAccessorMethod
&& getManager().areElementsEquivalent(((GrAccessorMethod
)element
).getProperty(), target
)) {
577 return getManager().areElementsEquivalent(element
, target
);
580 if (element
instanceof GrField
&& ((GrField
) element
).isProperty()) {
581 final PsiElement target
= resolve();
582 if (getManager().areElementsEquivalent(element
, target
)) {
586 for (final GrAccessorMethod getter
: ((GrField
)element
).getGetters()) {
587 if (getManager().areElementsEquivalent(getter
, target
)) {
591 return getManager().areElementsEquivalent(((GrField
)element
).getSetter(), target
);
594 if (element
instanceof PsiNamedElement
&& Comparing
.equal(((PsiNamedElement
) element
).getName(), getReferenceName())) {
595 return getManager().areElementsEquivalent(element
, resolve());
601 public Object
[] getVariants() {
602 return CompleteReferenceExpression
.getVariants(this);
606 public boolean isSoft() {
610 public GrExpression
getQualifierExpression() {
611 return findChildByClass(GrExpression
.class);
614 public boolean isQualified() {
615 return getQualifierExpression() != null;
619 public PsiElement
getDotToken() {
620 return findChildByType(GroovyTokenTypes
.DOTS
);
623 public void replaceDotToken(PsiElement newDot
) {
624 if (newDot
== null) return;
625 if (!GroovyTokenTypes
.DOTS
.contains(newDot
.getNode().getElementType())) return;
626 final PsiElement oldDot
= getDotToken();
627 if (oldDot
== null) return;
629 getNode().replaceChild(oldDot
.getNode(), newDot
.getNode());
633 public IElementType
getDotTokenType() {
634 PsiElement dot
= getDotToken();
635 return dot
== null ?
null : dot
.getNode().getElementType();
638 public GroovyResolveResult
advancedResolve() {
639 ResolveResult
[] results
= getManager().getResolveCache().resolveWithCaching(this, RESOLVER
, false, false);
640 return results
.length
== 1 ?
(GroovyResolveResult
) results
[0] : GroovyResolveResult
.EMPTY_RESULT
;
644 public GroovyResolveResult
[] multiResolve(boolean incomplete
) { //incomplete means we do not take arguments into consideration
645 return (GroovyResolveResult
[]) getManager().getResolveCache().resolveWithCaching(this, RESOLVER
, false, incomplete
);
649 public GroovyResolveResult
[] getSameNameVariants() {
650 return RESOLVER
.resolve(this, true);
653 public void setQualifierExpression(GrReferenceExpression newQualifier
) {
654 final GrExpression oldQualifier
= getQualifierExpression();
655 final ASTNode node
= getNode();
656 final PsiElement refNameElement
= getReferenceNameElement();
657 if (newQualifier
== null) {
658 if (oldQualifier
!= null) {
659 if (refNameElement
!= null) {
660 node
.removeRange(node
.getFirstChildNode(), refNameElement
.getNode());
664 if (oldQualifier
!= null) {
665 node
.replaceChild(oldQualifier
.getNode(), newQualifier
.getNode());
667 if (refNameElement
!= null) {
668 node
.addChild(newQualifier
.getNode(), refNameElement
.getNode());
669 node
.addLeaf(GroovyTokenTypes
.mDOT
, ".", refNameElement
.getNode());
676 public GrReferenceExpression
bindToElementViaStaticImport(@NotNull PsiClass qualifierClass
) {
677 if (getQualifier() != null) {
678 throw new IncorrectOperationException("Reference has qualifier");
681 if (StringUtil
.isEmpty(getReferenceName())) {
682 throw new IncorrectOperationException("Reference has empty name");
684 final PsiFile file
= getContainingFile();
685 if (file
instanceof GroovyFile
) {
686 final GrImportStatement statement
= GroovyPsiElementFactory
.getInstance(getProject())
687 .createImportStatementFromText("import static " + qualifierClass
.getQualifiedName() + "." + getReferenceName());
688 ((GroovyFile
)file
).addImport(statement
);