20f4c6918d9d4371e04bedabc20f2a401eb3c8cb
[fedora-idea.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / lang / psi / impl / statements / expressions / GrReferenceExpressionImpl.java
blob20f4c6918d9d4371e04bedabc20f2a401eb3c8cb
1 /*
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;
71 /**
72 * @author ilyas
74 public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements GrReferenceExpression {
75 public GrReferenceExpressionImpl(@NotNull ASTNode node) {
76 super(node);
79 public void accept(GroovyElementVisitor visitor) {
80 visitor.visitReferenceExpression(this);
83 @Nullable
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();
91 return null;
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);
100 @Nullable
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();
115 return null;
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);
128 } else {
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);
148 @Override
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());
155 return qualifiedRef;
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);
162 return this;
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";
182 @Nullable
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();
200 @Nullable
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);
222 } else {
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();
237 } else
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();
245 } else {
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);
250 } else {
251 if (method instanceof GrAccessorMethod) {
252 result = ((GrAccessorMethod) method).getReturnTypeGroovy();
253 } else {
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",
274 getResolveScope());
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();
283 if (clazz != null) {
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) {
301 return result;
302 } else {
303 return ResolveUtil.getListTypeForSpreadOperator(this, result);
307 @Nullable
308 private PsiType getTypeForObjectGetClass(JavaPsiFacade facade, PsiMethod method) {
309 PsiType type = method.getReturnType();
310 if (type instanceof PsiClassType) {
311 PsiClass clazz = ((PsiClassType) type).resolve();
312 if (clazz != null &&
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();
323 } else {
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);
338 return type;
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();
353 return nominal;
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
363 return inferred;
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);
386 return this;
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);
421 } else {
422 if (refExpr.getDotTokenType() != GroovyTokenTypes.mSPREAD_DOT) {
423 processQualifier(refExpr, processor, qualifier);
424 } else {
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();
435 if (clazz != null) {
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
459 return;
461 else {
462 qualifierType = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory()
463 .createTypeByFQClassName(CommonClassNames.JAVA_LANG_OBJECT, refExpr.getResolveScope());
464 processClassQualifierType(refExpr, processor, qualifierType);
467 } else {
468 if (qualifierType instanceof PsiIntersectionType) {
469 for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) {
470 processClassQualifierType(refExpr, processor, conjunct);
472 } else {
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))
505 return;
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);
515 return;
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());
531 } else {
532 processor = new PropertyResolverProcessor(name, refExpr);
535 return processor;
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);
549 enum Kind {
550 TYPE_OR_PROPERTY,
551 METHOD_OR_PROPERTY
554 Kind getKind() {
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;
565 @Nullable
566 public String getCanonicalText() {
567 return null;
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)) {
574 return true;
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)) {
583 return true;
586 for (final GrAccessorMethod getter : ((GrField)element).getGetters()) {
587 if (getManager().areElementsEquivalent(getter, target)) {
588 return true;
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());
597 return false;
600 @NotNull
601 public Object[] getVariants() {
602 return CompleteReferenceExpression.getVariants(this);
606 public boolean isSoft() {
607 return false;
610 public GrExpression getQualifierExpression() {
611 return findChildByClass(GrExpression.class);
614 public boolean isQualified() {
615 return getQualifierExpression() != null;
618 @Nullable
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());
632 @Nullable
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;
643 @NotNull
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);
648 @NotNull
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());
663 } else {
664 if (oldQualifier != null) {
665 node.replaceChild(oldQualifier.getNode(), newQualifier.getNode());
666 } else {
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);
690 return this;