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.Consumer;
35 import com.intellij.util.Function;
36 import com.intellij.util.IncorrectOperationException;
37 import org.jetbrains.annotations.NonNls;
38 import org.jetbrains.annotations.NotNull;
39 import org.jetbrains.annotations.Nullable;
40 import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
41 import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
42 import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
43 import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
44 import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
45 import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
46 import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
47 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
48 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
49 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableBase;
50 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
51 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplicationStatement;
52 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression;
53 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
54 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
55 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
56 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
57 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
58 import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
59 import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList;
60 import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
61 import org.jetbrains.plugins.groovy.lang.psi.impl.GrReferenceElementImpl;
62 import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
63 import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
64 import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
65 import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
66 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
67 import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
68 import org.jetbrains.plugins.groovy.lang.resolve.processors.*;
70 import java.util.ArrayList;
71 import java.util.Arrays;
72 import java.util.EnumSet;
73 import java.util.List;
78 public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements GrReferenceExpression {
79 public GrReferenceExpressionImpl(@NotNull ASTNode node) {
83 public void accept(GroovyElementVisitor visitor) {
84 visitor.visitReferenceExpression(this);
88 public PsiElement getReferenceNameElement() {
89 final ASTNode lastChild = getNode().getLastChildNode();
90 if (lastChild == null) return null;
91 for (IElementType elementType : TokenSets.REFERENCE_NAMES.getTypes()) {
92 if (lastChild.getElementType() == elementType) return lastChild.getPsi();
98 public PsiReference getReference() {
99 PsiReference[] otherReferences = ReferenceProvidersRegistry.getReferencesFromProviders(this, GrReferenceExpression.class);
100 PsiReference[] thisReference = {this};
101 return new PsiMultiReference(otherReferences.length == 0 ? thisReference : ArrayUtil.mergeArrays(thisReference, otherReferences, PsiReference.class), this);
105 public PsiElement getQualifier() {
106 return getQualifierExpression();
109 public String getReferenceName() {
110 PsiElement nameElement = getReferenceNameElement();
111 if (nameElement != null) {
112 if (nameElement.getNode().getElementType() == GroovyElementTypes.mSTRING_LITERAL ||
113 nameElement.getNode().getElementType() == GroovyElementTypes.mGSTRING_LITERAL) {
114 return GrStringUtil.removeQuotes(nameElement.getText());
117 return nameElement.getText();
122 public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
123 final PsiElement resolved = resolve();
124 if (resolved instanceof PsiMethod) {
125 final PsiMethod method = (PsiMethod) resolved;
126 final String oldName = getReferenceName();
127 if (!method.getName().equals(oldName)) { //was property reference to accessor
128 if (GroovyPropertyUtils.isSimplePropertyAccessor(method)) {
129 final String newPropertyName = PropertyUtil.getPropertyName(newElementName);
130 if (newPropertyName != null) {
131 return doHandleElementRename(newPropertyName);
133 //todo encapsulate fields:)
137 } else if (resolved instanceof GrField && ((GrField) resolved).isProperty()) {
138 final GrField field = (GrField) resolved;
139 final String oldName = getReferenceName();
140 if (oldName != null && !oldName.equals(field.getName())) { //was accessor reference to property
141 if (oldName.startsWith("get")) {
142 return doHandleElementRename("get" + StringUtil.capitalize(newElementName));
143 } else if (oldName.startsWith("set")) {
144 return doHandleElementRename("set" + StringUtil.capitalize(newElementName));
149 return doHandleElementRename(newElementName);
153 protected PsiElement bindWithQualifiedRef(String qName) {
154 final GrTypeArgumentList list = getTypeArgumentList();
155 final String typeArgs = (list != null) ? list.getText() : "";
156 final String text = qName + typeArgs;
157 GrReferenceExpression qualifiedRef = GroovyPsiElementFactory.getInstance(getProject()).createReferenceExpressionFromText(text);
158 getNode().getTreeParent().replaceChild(getNode(), qualifiedRef.getNode());
162 private PsiElement doHandleElementRename(String newElementName) throws IncorrectOperationException {
163 if (!PsiUtil.isValidReferenceName(newElementName)) {
164 PsiElement element = GroovyPsiElementFactory.getInstance(getProject()).createStringLiteral(newElementName);
165 getReferenceNameElement().replace(element);
169 return super.handleElementRename(newElementName);
172 public int getTextOffset() {
173 PsiElement parent = getParent();
174 TextRange range = getTextRange();
175 if (!(parent instanceof GrAssignmentExpression) || !this.equals(((GrAssignmentExpression) parent).getLValue())) {
176 return range.getEndOffset(); //need this as a hack against TargetElementUtil
179 return range.getStartOffset();
182 public String toString() {
183 return "Reference expression";
187 public PsiElement resolve() {
188 ResolveResult[] results = getManager().getResolveCache().resolveWithCaching(this, RESOLVER, true, false);
189 return results.length == 1 ? results[0].getElement() : null;
192 private static final OurResolver RESOLVER = new OurResolver();
194 private static final OurTypesCalculator TYPES_CALCULATOR = new OurTypesCalculator();
196 public PsiType getNominalType() {
197 return GroovyPsiManager.getInstance(getProject()).getTypeInferenceHelper().doWithInferenceDisabled(new Computable<PsiType>() {
198 public PsiType compute() {
199 return getNominalTypeImpl();
205 private PsiType getNominalTypeImpl() {
206 IElementType dotType = getDotTokenType();
208 final GroovyResolveResult resolveResult = advancedResolve();
209 PsiElement resolved = resolveResult.getElement();
210 if (dotType == GroovyTokenTypes.mMEMBER_POINTER) {
211 if (resolved instanceof PsiMethod) {
212 return GrClosureType.create((PsiMethod) resolved, resolveResult.getSubstitutor());
214 return JavaPsiFacade.getInstance(getProject()).getElementFactory().createTypeByFQClassName(GrClosableBlock.GROOVY_LANG_CLOSURE, getResolveScope());
216 PsiType result = null;
217 JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject());
218 if (resolved == null && !"class".equals(getReferenceName())) {
219 resolved = getReference().resolve();
221 if (resolved instanceof PsiClass) {
222 if (getParent() instanceof GrReferenceExpression) {
223 result = facade.getElementFactory().createType((PsiClass) resolved);
225 PsiClass javaLangClass = facade.findClass("java.lang.Class", getResolveScope());
226 if (javaLangClass != null) {
227 PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
228 final PsiTypeParameter[] typeParameters = javaLangClass.getTypeParameters();
229 if (typeParameters.length == 1) {
230 substitutor = substitutor.put(typeParameters[0], facade.getElementFactory().createType((PsiClass) resolved));
232 result = facade.getElementFactory().createType(javaLangClass, substitutor);
235 } else if (resolved instanceof GrVariableBase) {
236 result = ((GrVariableBase) resolved).getDeclaredType();
237 } else if (resolved instanceof PsiVariable) {
238 result = ((PsiVariable) resolved).getType();
240 if (resolved instanceof PsiMethod && !GroovyPsiManager.isTypeBeingInferred(resolved)) {
241 if (dotType == GroovyTokenTypes.mMEMBER_POINTER) {
242 return facade.getElementFactory().createTypeByFQClassName("groovy.lang.Closure", getResolveScope());
244 PsiMethod method = (PsiMethod) resolved;
245 if (PropertyUtil.isSimplePropertySetter(method) && !method.getName().equals(getReferenceName())) {
246 result = method.getParameterList().getParameters()[0].getType();
248 PsiClass containingClass = method.getContainingClass();
249 if (containingClass != null && "java.lang.Object".equals(containingClass.getQualifiedName()) &&
250 "getClass".equals(method.getName())) {
251 result = getTypeForObjectGetClass(facade, method);
253 if (method instanceof GrAccessorMethod) {
254 result = ((GrAccessorMethod) method).getReturnTypeGroovy();
256 result = method.getReturnType();
261 } else if (resolved instanceof GrReferenceExpression) {
262 PsiElement parent = resolved.getParent();
263 if (parent instanceof GrAssignmentExpression) {
264 GrAssignmentExpression assignment = (GrAssignmentExpression) parent;
265 if (resolved.equals(assignment.getLValue())) {
266 GrExpression rValue = assignment.getRValue();
267 if (rValue != null) {
268 PsiType rType = rValue.getType();
269 if (rType != null) result = rType;
273 } else if (resolved == null) {
274 if ("class".equals(getReferenceName())) {
275 return JavaPsiFacade.getInstance(getProject()).getElementFactory().createTypeByFQClassName("java.lang.Class",
279 GrExpression qualifier = getQualifierExpression();
280 if (qualifier != null) {
281 PsiType qType = qualifier.getType();
282 if (qType instanceof PsiClassType) {
283 PsiClassType.ClassResolveResult qResult = ((PsiClassType) qType).resolveGenerics();
284 PsiClass clazz = qResult.getElement();
286 PsiClass mapClass = facade.findClass("java.util.Map", getResolveScope());
287 if (mapClass != null && mapClass.getTypeParameters().length == 2) {
288 PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(mapClass, clazz, qResult.getSubstitutor());
289 if (substitutor != null) {
290 return substitutor.substitute(mapClass.getTypeParameters()[1]);
298 if (result != null) {
299 result = resolveResult.getSubstitutor().substitute(result);
300 result = TypesUtil.boxPrimitiveType(result, getManager(), getResolveScope());
302 if (dotType != GroovyTokenTypes.mSPREAD_DOT) {
305 return ResolveUtil.getListTypeForSpreadOperator(this, result);
310 private PsiType getTypeForObjectGetClass(JavaPsiFacade facade, PsiMethod method) {
311 PsiType type = method.getReturnType();
312 if (type instanceof PsiClassType) {
313 PsiClass clazz = ((PsiClassType) type).resolve();
315 "java.lang.Class".equals(clazz.getQualifiedName())) {
316 PsiTypeParameter[] typeParameters = clazz.getTypeParameters();
317 if (typeParameters.length == 1) {
318 PsiClass qualifierClass = null;
319 GrExpression qualifier = getQualifierExpression();
320 if (qualifier != null) {
321 PsiType qualifierType = qualifier.getType();
322 if (qualifierType instanceof PsiClassType) {
323 qualifierClass = ((PsiClassType) qualifierType).resolve();
326 PsiNamedElement context = PsiTreeUtil.getParentOfType(this, PsiClass.class, GroovyFile.class);
327 if (context instanceof PsiClass) qualifierClass = (PsiClass) context;
328 else if (context instanceof GroovyFile) qualifierClass = ((GroovyFile) context).getScriptClass();
331 PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
332 if (qualifierClass != null) {
333 PsiType t = facade.getElementFactory().createType(qualifierClass);
334 substitutor = substitutor.put(typeParameters[0], t);
336 return facade.getElementFactory().createType(clazz, substitutor);
343 private static final class OurTypesCalculator implements Function<GrReferenceExpressionImpl, PsiType> {
344 public PsiType fun(GrReferenceExpressionImpl refExpr) {
345 final PsiType inferred = GroovyPsiManager.getInstance(refExpr.getProject()).getTypeInferenceHelper().getInferredType(refExpr);
346 final PsiType nominal = refExpr.getNominalTypeImpl();
347 if (inferred == null || PsiType.NULL.equals(inferred)) {
348 if (nominal == null) {
349 /*inside nested closure we could still try to infer from variable initializer.
350 * Not sound, but makes sense*/
351 final PsiElement resolved = refExpr.resolve();
352 if (resolved instanceof GrVariableBase) return ((GrVariableBase) resolved).getTypeGroovy();
358 if (nominal == null) return inferred;
359 if (!TypeConversionUtil.isAssignable(nominal, inferred, false)) {
360 final PsiElement resolved = refExpr.resolve();
361 if (resolved instanceof GrVariable && ((GrVariable) resolved).getTypeElementGroovy() != null) {
362 return nominal; //see GRVY-487
369 public PsiType getType() {
370 return GroovyPsiManager.getInstance(getProject()).getType(this, TYPES_CALCULATOR);
373 public GrExpression replaceWithExpression(@NotNull GrExpression newExpr, boolean removeUnnecessaryParentheses) {
374 return PsiImplUtil.replaceExpression(this, newExpr, removeUnnecessaryParentheses);
377 public String getName() {
378 return getReferenceName();
381 public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
382 PsiElement nameElement = getReferenceNameElement();
383 ASTNode node = nameElement.getNode();
384 ASTNode newNameNode = GroovyPsiElementFactory.getInstance(getProject()).createReferenceNameFromText(name).getNode();
385 assert newNameNode != null && node != null;
386 node.getTreeParent().replaceChild(node, newNameNode);
391 private static class OurResolver implements ResolveCache.PolyVariantResolver<GrReferenceExpressionImpl> {
392 public GroovyResolveResult[] resolve(GrReferenceExpressionImpl refExpr, boolean incompleteCode) {
393 String name = refExpr.getReferenceName();
394 if (name == null) return GroovyResolveResult.EMPTY_ARRAY;
396 Kind kind = refExpr.getKind();
397 if (incompleteCode) {
398 ResolverProcessor processor = CompletionProcessor.createRefSameNameProcessor(refExpr, name);
399 resolveImpl(refExpr, processor);
400 GroovyResolveResult[] propertyCandidates = processor.getCandidates();
401 if (propertyCandidates.length > 0) return propertyCandidates;
404 if (kind == Kind.METHOD_OR_PROPERTY) {
405 final PsiType[] argTypes = PsiUtil.getArgumentTypes(refExpr, false);
406 PsiType thisType = getThisType(refExpr);
408 MethodResolverProcessor methodResolver =
409 new MethodResolverProcessor(name, refExpr, false, thisType, argTypes, refExpr.getTypeArguments());
410 resolveImpl(refExpr, methodResolver);
411 if (methodResolver.hasApplicableCandidates()) return methodResolver.getCandidates();
413 PropertyResolverProcessor propertyResolver = new PropertyResolverProcessor(name, refExpr);
414 resolveImpl(refExpr, propertyResolver);
415 if (propertyResolver.hasCandidates()) return propertyResolver.getCandidates();
417 final String[] names = GroovyPropertyUtils.suggestGettersName(name);
418 List<GroovyResolveResult> list = new ArrayList<GroovyResolveResult>();
419 for (String getterName : names) {
420 AccessorResolverProcessor getterResolver = new AccessorResolverProcessor(getterName, refExpr, true);
421 resolveImpl(refExpr, getterResolver);
422 list.addAll(Arrays.asList(getterResolver.getCandidates()));
424 if (list.size() > 0) return list.toArray(new GroovyResolveResult[list.size()]);
425 return methodResolver.getCandidates();
427 else if (kind == Kind.TYPE_OR_PROPERTY) {
428 ResolverProcessor processor = new PropertyResolverProcessor(name, refExpr);
429 resolveImpl(refExpr, processor);
430 final GroovyResolveResult[] fieldCandidates = processor.getCandidates();
432 //if reference expression is in class we need to return field instead of accessor method
433 for (GroovyResolveResult candidate : fieldCandidates) {
434 final PsiElement element = candidate.getElement();
435 if (element instanceof PsiField) {
436 final PsiClass containingClass = ((PsiField)element).getContainingClass();
437 if (containingClass != null && PsiTreeUtil.isAncestor(containingClass, refExpr, true)) return fieldCandidates;
439 return fieldCandidates;
443 final boolean isLValue = PsiUtil.isLValue(refExpr);
445 names = isLValue ? GroovyPropertyUtils.suggestSettersName(name) : GroovyPropertyUtils.suggestGettersName(name);
446 for (String getterName : names) {
447 AccessorResolverProcessor accessorResolver = new AccessorResolverProcessor(getterName, refExpr, !isLValue);
448 resolveImpl(refExpr, accessorResolver);
449 final GroovyResolveResult[] candidates = accessorResolver.getCandidates();
450 if (candidates.length > 0) return candidates;
452 if (fieldCandidates.length > 0) return fieldCandidates;
454 EnumSet<ClassHint.ResolveKind> kinds = refExpr.getParent() instanceof GrReferenceExpression
455 ? EnumSet.of(ClassHint.ResolveKind.CLASS, ClassHint.ResolveKind.PACKAGE)
456 : EnumSet.of(ClassHint.ResolveKind.CLASS);
457 ResolverProcessor classProcessor = new ClassResolverProcessor(refExpr.getReferenceName(), refExpr, kinds);
458 resolveImpl(refExpr, classProcessor);
459 return classProcessor.getCandidates();
462 return GroovyResolveResult.EMPTY_ARRAY;
465 private static void resolveImpl(GrReferenceExpressionImpl refExpr, ResolverProcessor processor) {
466 GrExpression qualifier = refExpr.getQualifierExpression();
467 if (qualifier == null) {
468 ResolveUtil.treeWalkUp(refExpr, processor, true);
469 if (!processor.hasCandidates()) {
470 qualifier = PsiImplUtil.getRuntimeQualifier(refExpr);
471 if (qualifier != null) {
472 processQualifier(refExpr, processor, qualifier);
476 if (refExpr.getDotTokenType() != GroovyTokenTypes.mSPREAD_DOT) {
477 processQualifier(refExpr, processor, qualifier);
479 processQualifierForSpreadDot(refExpr, processor, qualifier);
484 private static void processQualifierForSpreadDot(GrReferenceExpressionImpl refExpr, ResolverProcessor processor, GrExpression qualifier) {
485 PsiType qualifierType = qualifier.getType();
486 if (qualifierType instanceof PsiClassType) {
487 PsiClassType.ClassResolveResult result = ((PsiClassType) qualifierType).resolveGenerics();
488 PsiClass clazz = result.getElement();
490 PsiClass listClass = ResolveUtil.findListClass(refExpr.getManager(), refExpr.getResolveScope());
491 if (listClass != null && listClass.getTypeParameters().length == 1) {
492 PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(listClass, clazz, result.getSubstitutor());
493 if (substitutor != null) {
494 PsiType componentType = substitutor.substitute(listClass.getTypeParameters()[0]);
495 if (componentType != null) {
496 processClassQualifierType(refExpr, processor, componentType);
501 } else if (qualifierType instanceof PsiArrayType) {
502 processClassQualifierType(refExpr, processor, ((PsiArrayType) qualifierType).getComponentType());
506 private static void processQualifier(GrReferenceExpressionImpl refExpr, ResolverProcessor processor, GrExpression qualifier) {
507 PsiType qualifierType = qualifier.getType();
508 if (qualifierType == null) {
509 if (qualifier instanceof GrReferenceExpression) {
510 PsiElement resolved = ((GrReferenceExpression) qualifier).resolve();
511 if (resolved instanceof PsiPackage) {
512 if (!resolved.processDeclarations(processor, ResolveState.initial(), null, refExpr)) //noinspection UnnecessaryReturnStatement
516 qualifierType = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory()
517 .createTypeByFQClassName(CommonClassNames.JAVA_LANG_OBJECT, refExpr.getResolveScope());
518 processClassQualifierType(refExpr, processor, qualifierType);
522 if (qualifierType instanceof PsiIntersectionType) {
523 for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) {
524 processClassQualifierType(refExpr, processor, conjunct);
527 processClassQualifierType(refExpr, processor, qualifierType);
528 if (qualifier instanceof GrReferenceExpression) {
529 PsiElement resolved = ((GrReferenceExpression) qualifier).resolve();
530 if (resolved instanceof PsiClass) { //omitted .class
531 PsiClass javaLangClass = PsiUtil.getJavaLangClass(resolved, refExpr.getResolveScope());
532 if (javaLangClass != null) {
533 ResolveState state = ResolveState.initial();
534 PsiTypeParameter[] typeParameters = javaLangClass.getTypeParameters();
535 PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY);
536 if (substitutor == null) substitutor = PsiSubstitutor.EMPTY;
537 if (typeParameters.length == 1) {
538 substitutor = substitutor.put(typeParameters[0], qualifierType);
539 state = state.put(PsiSubstitutor.KEY, substitutor);
541 if (!javaLangClass.processDeclarations(processor, state, null, refExpr)) return;
542 PsiType javaLangClassType = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory().createType(javaLangClass, substitutor);
543 ResolveUtil.processNonCodeMethods(javaLangClassType, processor, refExpr.getProject(), refExpr, false);
551 private static void processClassQualifierType(GrReferenceExpressionImpl refExpr, ResolverProcessor processor, PsiType qualifierType) {
552 Project project = refExpr.getProject();
553 if (qualifierType instanceof PsiClassType) {
554 PsiClassType.ClassResolveResult qualifierResult = ((PsiClassType) qualifierType).resolveGenerics();
555 PsiClass qualifierClass = qualifierResult.getElement();
556 if (qualifierClass != null) {
557 if (!qualifierClass.processDeclarations(processor,
558 ResolveState.initial().put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor()), null, refExpr))
561 if (!ResolveUtil.processCategoryMembers(refExpr, processor)) return;
562 } else if (qualifierType instanceof PsiArrayType) {
563 final GrTypeDefinition arrayClass = GroovyPsiManager.getInstance(project).getArrayClass();
564 if (!arrayClass.processDeclarations(processor, ResolveState.initial(), null, refExpr)) return;
565 } else if (qualifierType instanceof PsiIntersectionType) {
566 for (PsiType conjunct : ((PsiIntersectionType) qualifierType).getConjuncts()) {
567 processClassQualifierType(refExpr, processor, conjunct);
572 ResolveUtil.processNonCodeMethods(qualifierType, processor, project, refExpr, false);
576 private static PsiType getThisType(GrReferenceExpression refExpr) {
577 GrExpression qualifier = refExpr.getQualifierExpression();
578 if (qualifier != null) {
579 PsiType qType = qualifier.getType();
580 if (qType != null) return qType;
583 return TypesUtil.getJavaLangObject(refExpr);
593 if (getDotTokenType() == GroovyTokenTypes.mMEMBER_POINTER) return Kind.METHOD_OR_PROPERTY;
595 PsiElement parent = getParent();
596 if (parent instanceof GrMethodCallExpression || parent instanceof GrApplicationStatement) {
597 return Kind.METHOD_OR_PROPERTY;
600 return Kind.TYPE_OR_PROPERTY;
604 public String getCanonicalText() {
608 public boolean isReferenceTo(PsiElement element) {
609 if (element instanceof PsiMethod && GroovyPropertyUtils.isSimplePropertyAccessor((PsiMethod) element)) {
610 final PsiElement target = resolve();
611 if (element instanceof GrAccessorMethod && getManager().areElementsEquivalent(((GrAccessorMethod)element).getProperty(), target)) {
615 return getManager().areElementsEquivalent(element, target);
618 if (element instanceof GrField && ((GrField) element).isProperty()) {
619 final PsiElement target = resolve();
620 if (getManager().areElementsEquivalent(element, target)) {
624 for (final GrAccessorMethod getter : ((GrField)element).getGetters()) {
625 if (getManager().areElementsEquivalent(getter, target)) {
629 return getManager().areElementsEquivalent(((GrField)element).getSetter(), target);
632 if (element instanceof PsiNamedElement && Comparing.equal(((PsiNamedElement) element).getName(), getReferenceName())) {
633 return getManager().areElementsEquivalent(element, resolve());
639 public Object[] getVariants() {
640 return ArrayUtil.EMPTY_OBJECT_ARRAY;
644 public boolean isSoft() {
648 public GrExpression getQualifierExpression() {
649 return findChildByClass(GrExpression.class);
652 public boolean isQualified() {
653 return getQualifierExpression() != null;
657 public PsiElement getDotToken() {
658 return findChildByType(GroovyTokenTypes.DOTS);
661 public void replaceDotToken(PsiElement newDot) {
662 if (newDot == null) return;
663 if (!GroovyTokenTypes.DOTS.contains(newDot.getNode().getElementType())) return;
664 final PsiElement oldDot = getDotToken();
665 if (oldDot == null) return;
667 getNode().replaceChild(oldDot.getNode(), newDot.getNode());
671 public IElementType getDotTokenType() {
672 PsiElement dot = getDotToken();
673 return dot == null ? null : dot.getNode().getElementType();
676 public GroovyResolveResult advancedResolve() {
677 ResolveResult[] results = getManager().getResolveCache().resolveWithCaching(this, RESOLVER, false, false);
678 return results.length == 1 ? (GroovyResolveResult) results[0] : GroovyResolveResult.EMPTY_RESULT;
682 public GroovyResolveResult[] multiResolve(boolean incomplete) { //incomplete means we do not take arguments into consideration
683 return (GroovyResolveResult[]) getManager().getResolveCache().resolveWithCaching(this, RESOLVER, false, incomplete);
686 public void processVariants(Consumer<Object> consumer) {
687 CompleteReferenceExpression.processVariants(consumer, this);
691 public GroovyResolveResult[] getSameNameVariants() {
692 return RESOLVER.resolve(this, true);
695 public void setQualifierExpression(GrReferenceExpression newQualifier) {
696 final GrExpression oldQualifier = getQualifierExpression();
697 final ASTNode node = getNode();
698 final PsiElement refNameElement = getReferenceNameElement();
699 if (newQualifier == null) {
700 if (oldQualifier != null) {
701 if (refNameElement != null) {
702 node.removeRange(node.getFirstChildNode(), refNameElement.getNode());
706 if (oldQualifier != null) {
707 node.replaceChild(oldQualifier.getNode(), newQualifier.getNode());
709 if (refNameElement != null) {
710 node.addChild(newQualifier.getNode(), refNameElement.getNode());
711 node.addLeaf(GroovyTokenTypes.mDOT, ".", refNameElement.getNode());
718 public GrReferenceExpression bindToElementViaStaticImport(@NotNull PsiClass qualifierClass) {
719 if (getQualifier() != null) {
720 throw new IncorrectOperationException("Reference has qualifier");
723 if (StringUtil.isEmpty(getReferenceName())) {
724 throw new IncorrectOperationException("Reference has empty name");
726 final PsiFile file = getContainingFile();
727 if (file instanceof GroovyFile) {
728 final GrImportStatement statement = GroovyPsiElementFactory.getInstance(getProject())
729 .createImportStatementFromText("import static " + qualifierClass.getQualifiedName() + "." + getReferenceName());
730 ((GroovyFile)file).addImport(statement);