Merge branch 'alias'
[idea/community.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / lang / psi / util / PsiUtil.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.jetbrains.plugins.groovy.lang.psi.util;
18
19 import com.intellij.codeInsight.CodeInsightSettings;
20 import com.intellij.lang.ASTNode;
21 import com.intellij.openapi.application.ApplicationManager;
22 import com.intellij.openapi.diagnostic.Logger;
23 import com.intellij.openapi.util.Computable;
24 import com.intellij.openapi.util.Key;
25 import com.intellij.openapi.util.TextRange;
26 import com.intellij.psi.*;
27 import com.intellij.psi.codeStyle.CodeStyleManager;
28 import com.intellij.psi.search.GlobalSearchScope;
29 import com.intellij.psi.search.SearchScope;
30 import com.intellij.psi.tree.IElementType;
31 import com.intellij.psi.util.InheritanceUtil;
32 import com.intellij.psi.util.PsiTreeUtil;
33 import com.intellij.util.IncorrectOperationException;
34 import com.intellij.util.containers.HashSet;
35 import gnu.trove.TIntStack;
36 import org.jetbrains.annotations.NotNull;
37 import org.jetbrains.annotations.Nullable;
38 import org.jetbrains.plugins.groovy.GroovyFileTypeLoader;
39 import org.jetbrains.plugins.groovy.debugger.fragments.GroovyCodeFragment;
40 import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocComment;
41 import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocMemberReference;
42 import org.jetbrains.plugins.groovy.lang.lexer.GroovyLexer;
43 import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
44 import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
45 import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
46 import org.jetbrains.plugins.groovy.lang.psi.*;
47 import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
48 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
49 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation;
50 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
51 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrTopLevelDefintion;
52 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
53 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
54 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
55 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
56 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression;
57 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty;
58 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
59 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrPropertySelection;
60 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
61 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
62 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
63 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant;
64 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
65 import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
66 import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
67 import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
68 import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
69 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
70 import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
71 import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.JavaIdentifier;
72 import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
73 import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersProcessor;
74 import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
75 import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor;
76 import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor;
77
78 import java.util.*;
79
80 /**
81  * @author ven
82  */
83 public class PsiUtil {
84   public static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil");
85   public static final Key<JavaIdentifier> NAME_IDENTIFIER = new Key<JavaIdentifier>("Java Identifier");
86
87   private PsiUtil() {
88   }
89
90   @Nullable
91   public static String getQualifiedReferenceText(GrCodeReferenceElement referenceElement) {
92     StringBuilder builder = new StringBuilder();
93     if (!appendName(referenceElement, builder)) return null;
94
95     return builder.toString();
96   }
97
98   private static boolean appendName(GrCodeReferenceElement referenceElement, StringBuilder builder) {
99     String refName = referenceElement.getReferenceName();
100     if (refName == null) return false;
101     GrCodeReferenceElement qualifier = referenceElement.getQualifier();
102     if (qualifier != null) {
103       appendName(qualifier, builder);
104       builder.append(".");
105     }
106
107     builder.append(refName);
108     return true;
109   }
110
111   public static boolean isLValue(GroovyPsiElement element) {
112     if (element instanceof GrExpression) {
113       PsiElement parent = PsiTreeUtil.skipParentsOfType(element, GrParenthesizedExpression.class);
114       if (parent instanceof GrListOrMap && !((GrListOrMap)parent).isMap()) {
115         return isLValue((GroovyPsiElement)parent);
116       }
117       return parent instanceof GrAssignmentExpression && PsiTreeUtil.isAncestor(((GrAssignmentExpression)parent).getLValue(), element, false);
118     }
119     return false;
120   }
121
122   public static boolean isApplicable(@Nullable PsiType[] argumentTypes,
123                                      PsiMethod method,
124                                      PsiSubstitutor substitutor,
125                                      boolean isInUseCategory, GroovyPsiElement place) {
126     if (argumentTypes == null) return true;
127
128     GrClosureSignature signature = GrClosureSignatureUtil.createSignature(method, substitutor);
129     if (isInUseCategory && method.hasModifierProperty(PsiModifier.STATIC) && method.getParameterList().getParametersCount() > 0) {
130       signature = signature.curry(1);
131     }
132
133     //check for default constructor
134     if (method.isConstructor() && method.getParameterList().getParametersCount() == 0 && argumentTypes.length == 1) {
135       return InheritanceUtil.isInheritor(argumentTypes[0], CommonClassNames.JAVA_UTIL_MAP);
136     }
137     LOG.assertTrue(signature != null);
138     return GrClosureSignatureUtil.isSignatureApplicable(signature, argumentTypes, place);
139   }
140
141   public static boolean isApplicable(@Nullable PsiType[] argumentTypes, GrClosureType type, GroovyPsiElement context) {
142     if (argumentTypes == null) return true;
143
144     GrClosureSignature signature = type.getSignature();
145     return GrClosureSignatureUtil.isSignatureApplicable(signature, argumentTypes, context);
146   }
147
148   public static PsiClassType createMapType(PsiManager manager, GlobalSearchScope scope) {
149     return JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createTypeByFQClassName(CommonClassNames.JAVA_UTIL_MAP, scope);
150   }
151
152   @Nullable
153   public static GrArgumentList getArgumentsList(PsiElement methodRef) {
154     PsiElement parent = methodRef.getParent();
155     if (parent instanceof GrCall) {
156       return ((GrCall)parent).getArgumentList();
157     }
158     if (parent instanceof GrAnonymousClassDefinition) {
159       return ((GrAnonymousClassDefinition)parent).getArgumentListGroovy();
160     }
161     return null;
162   }
163
164   @Nullable
165   public static PsiType[] getArgumentTypes(PsiElement place, boolean nullAsBottom) {
166     PsiElement parent = place.getParent();
167     if (parent instanceof GrCallExpression) {
168       List<PsiType> result = new ArrayList<PsiType>();
169       GrCallExpression call = (GrCallExpression)parent;
170
171       GrNamedArgument[] namedArgs = call.getNamedArguments();
172       if (namedArgs.length > 0) {
173         result.add(createMapType(place.getManager(), place.getResolveScope()));
174       }
175
176       GrExpression[] expressions = call.getExpressionArguments();
177       for (GrExpression expression : expressions) {
178         PsiType type = expression.getType();
179         if (type == null) {
180           result.add(nullAsBottom ? PsiType.NULL : TypesUtil.getJavaLangObject(call));
181         } else {
182           result.add(type);
183         }
184       }
185
186       GrClosableBlock[] closures = call.getClosureArguments();
187       for (GrClosableBlock closure : closures) {
188         PsiType closureType = closure.getType();
189         if (closureType != null) {
190           result.add(closureType);
191         }
192       }
193
194       return result.toArray(new PsiType[result.size()]);
195
196     }
197     else if (parent instanceof GrAnonymousClassDefinition) {
198       final GrAnonymousClassDefinition anonymous = (GrAnonymousClassDefinition)parent;
199       final GrArgumentList argList = anonymous.getArgumentListGroovy();
200       List<PsiType> result = new ArrayList<PsiType>();
201
202       GrNamedArgument[] namedArgs = argList.getNamedArguments();
203       if (namedArgs.length > 0) {
204         result.add(createMapType(place.getManager(), place.getResolveScope()));
205       }
206
207       GrExpression[] expressions = argList.getExpressionArguments();
208       for (GrExpression expression : expressions) {
209         PsiType type = expression.getType();
210         if (type == null) {
211           result.add(nullAsBottom ? PsiType.NULL : TypesUtil.getJavaLangObject(argList));
212         } else {
213           result.add(type);
214         }
215       }
216
217       return result.toArray(new PsiType[result.size()]);
218     }
219     else if (parent instanceof GrApplicationStatement) {
220       final GrApplicationStatement call = (GrApplicationStatement)parent;
221       GrExpression[] args = call.getArguments();
222       final GrArgumentList argList = call.getArgumentList();
223       GrNamedArgument[] namedArgs = argList != null ? argList.getNamedArguments() : GrNamedArgument.EMPTY_ARRAY;
224       final ArrayList<PsiType> result = new ArrayList<PsiType>();
225       if (namedArgs.length > 0) {
226         result.add(createMapType(place.getManager(), place.getResolveScope()));
227       }
228       for (GrExpression arg : args) {
229         PsiType argType = arg.getType();
230         if (argType == null) {
231           result.add(nullAsBottom ? PsiType.NULL : TypesUtil.getJavaLangObject(parent));
232         }
233         else {
234           result.add(argType);
235         }
236       }
237       return result.toArray(new PsiType[result.size()]);
238     } else if (parent instanceof GrConstructorInvocation || parent instanceof GrEnumConstant) {
239       final GrArgumentList argList = ((GrCall)parent).getArgumentList();
240       if (argList == null) return PsiType.EMPTY_ARRAY;
241
242       List<PsiType> result = new ArrayList<PsiType>();
243       if (argList.getNamedArguments().length > 0) {
244         result.add(createMapType(place.getManager(), place.getResolveScope()));
245       }
246
247       GrExpression[] expressions = argList.getExpressionArguments();
248       for (GrExpression expression : expressions) {
249         PsiType type = expression.getType();
250         if (type == null) {
251           result.add(nullAsBottom ? PsiType.NULL : TypesUtil.getJavaLangObject(argList));
252         } else {
253           result.add(type);
254         }
255       }
256
257       return result.toArray(new PsiType[result.size()]);
258     }
259
260     return null;
261   }
262
263   public static SearchScope restrictScopeToGroovyFiles(final Computable<SearchScope> originalScopeComputation) { //important to compute originalSearchScope in read action!
264     return ApplicationManager.getApplication().runReadAction(new Computable<SearchScope>() {
265       public SearchScope compute() {
266         final SearchScope originalScope = originalScopeComputation.compute();
267         if (originalScope instanceof GlobalSearchScope) {
268           return GlobalSearchScope
269             .getScopeRestrictedByFileTypes((GlobalSearchScope)originalScope, GroovyFileTypeLoader.getGroovyEnabledFileTypes());
270         }
271         return originalScope;
272       }
273     });
274   }
275
276   @Nullable
277   public static PsiClass getJavaLangClass(PsiElement resolved, GlobalSearchScope scope) {
278     return JavaPsiFacade.getInstance(resolved.getProject()).findClass(CommonClassNames.JAVA_LANG_CLASS, scope);
279   }
280
281   public static boolean isValidReferenceName(String text) {
282     final GroovyLexer lexer = new GroovyLexer();
283     lexer.start(text);
284     return TokenSets.REFERENCE_NAMES.contains(lexer.getTokenType()) && lexer.getTokenEnd() == text.length();
285   }
286
287   public static void shortenReferences(GroovyPsiElement element) {
288     doShorten(element);
289   }
290
291   private static void doShorten(PsiElement element) {
292     PsiElement child = element.getFirstChild();
293     while (child != null) {
294       if (child instanceof GrCodeReferenceElement) {
295         shortenReference((GrCodeReferenceElement)child);
296       }
297
298       doShorten(child);
299       child = child.getNextSibling();
300     }
301   }
302
303
304   public static void shortenReference(GrReferenceElement ref) {
305     final PsiElement qualifier = ref.getQualifier();
306     if (qualifier != null &&
307         (PsiTreeUtil.getParentOfType(ref, GrDocMemberReference.class) != null ||
308          PsiTreeUtil.getParentOfType(ref, GrDocComment.class) == null) &&
309         PsiTreeUtil.getParentOfType(ref, GrImportStatement.class) == null &&
310         PsiTreeUtil.getParentOfType(ref, GroovyCodeFragment.class) == null) {
311       final PsiElement resolved = ref.resolve();
312       if (resolved instanceof PsiClass) {
313         setQualifier(ref, null);
314         if (ref.isReferenceTo(resolved)) return;
315
316         final GroovyFileBase file = (GroovyFileBase)ref.getContainingFile();
317         final PsiClass clazz = (PsiClass)resolved;
318         final String qName = clazz.getQualifiedName();
319         if (qName != null) {
320           if (mayInsertImport(ref)) {
321             final GrImportStatement added = file.addImportForClass(clazz);
322             if (!ref.isReferenceTo(resolved)) {
323               file.removeImport(added);
324               setQualifier(ref, qualifier);
325             }
326           }
327         }
328       }
329     }
330   }
331
332   private static void setQualifier(@NotNull GrReferenceElement ref, @Nullable PsiElement qualifier) {
333     if (ref instanceof GrReferenceExpression) {
334       ((GrReferenceExpression)ref).setQualifierExpression((GrReferenceExpression)qualifier);
335     }
336     else if (ref instanceof GrCodeReferenceElement) {
337       ((GrCodeReferenceElement)ref).setQualifier((GrCodeReferenceElement)qualifier);
338     }
339   }
340
341   private static boolean mayInsertImport(GrReferenceElement ref) {
342     return PsiTreeUtil.getParentOfType(ref, GrDocComment.class) == null && !(ref.getContainingFile() instanceof GroovyCodeFragment) && PsiTreeUtil.getParentOfType(ref, GrImportStatement.class) == null;
343   }
344
345   @Nullable
346   public static GrTopLevelDefintion findPreviousTopLevelElementByThisElement(PsiElement element) {
347     PsiElement parent = element.getParent();
348
349     while (parent != null && !(parent instanceof GrTopLevelDefintion)) {
350       parent = parent.getParent();
351     }
352
353     if (parent == null) return null;
354     return ((GrTopLevelDefintion)parent);
355   }
356
357   public static boolean isStaticsOK(PsiModifierListOwner owner, PsiElement place) {
358     if (owner instanceof PsiMember) {
359       if (place instanceof GrReferenceExpression) {
360         GrExpression qualifier = ((GrReferenceExpression)place).getQualifierExpression();
361         if (qualifier != null) {
362           if (qualifier instanceof GrReferenceExpression) {
363             PsiElement qualifierResolved = ((GrReferenceExpression)qualifier).resolve();
364             if (qualifierResolved instanceof PsiClass || qualifierResolved instanceof PsiPackage) { //static context
365               if (owner instanceof PsiClass) {
366                 return true;
367               }
368               //members from java.lang.Class can be invoked without ".class"
369               PsiClass javaLangClass = JavaPsiFacade.getInstance(place.getProject()).findClass("java.lang.Class", place.getResolveScope());
370               if (javaLangClass != null) {
371                 PsiClass containingClass = ((PsiMember)owner).getContainingClass();
372                 if ((containingClass == null) || //default groovy method
373                     InheritanceUtil.isInheritorOrSelf(javaLangClass, containingClass, true)) {
374                   return true;
375                 }
376               }
377               return owner.hasModifierProperty(PsiModifier.STATIC);
378             }
379           }
380
381           //instance context
382           if (owner instanceof PsiClass) {
383             return false;
384           }
385           return CodeInsightSettings.getInstance().SHOW_STATIC_AFTER_INSTANCE || !owner.hasModifierProperty(PsiModifier.STATIC);
386         }
387       }
388     }
389     return true;
390   }
391
392   public static boolean isAccessible(PsiElement place, PsiMember member) {
393
394     if (PsiTreeUtil.getParentOfType(place, GrDocComment.class) != null) return true;
395     if (!member.isPhysical()) {
396       return true;
397     }
398
399     if (place instanceof GrReferenceExpression && ((GrReferenceExpression)place).getQualifierExpression() == null) {
400       if (member.getContainingClass() instanceof GroovyScriptClass) { //calling toplevel script members from the same script file
401         return true;
402       }
403     }
404     return com.intellij.psi.util.PsiUtil.isAccessible(member, place, null);
405   }
406
407   public static void reformatCode(final PsiElement element) {
408     final TextRange textRange = element.getTextRange();
409     try {
410       CodeStyleManager.getInstance(element.getProject())
411         .reformatText(element.getContainingFile(), textRange.getStartOffset(), textRange.getEndOffset());
412     }
413     catch (IncorrectOperationException e) {
414       LOG.error(e);
415     }
416   }
417
418   public static boolean isInStaticContext(GrReferenceExpression refExpression, PsiClass targetClass) {
419     if (refExpression.isQualified()) {
420       GrExpression qualifer = refExpression.getQualifierExpression();
421       if (qualifer instanceof GrReferenceExpression) return ((GrReferenceExpression)qualifer).resolve() instanceof PsiClass;
422     } else {
423       PsiElement run = refExpression;
424       while (run != null && run != targetClass) {
425         if (run instanceof PsiModifierListOwner && ((PsiModifierListOwner)run).hasModifierProperty(PsiModifier.STATIC)) return true;
426         run = run.getParent();
427       }
428     }
429     return false;
430
431   }
432
433   public static Iterable<PsiClass> iterateSupers(final @NotNull PsiClass psiClass, final boolean includeSelf) {
434     return new Iterable<PsiClass>() {
435       public Iterator<PsiClass> iterator() {
436         return new Iterator<PsiClass>() {
437           TIntStack indices = new TIntStack();
438           Stack<PsiClassType[]> superTypesStack = new Stack<PsiClassType[]>();
439           PsiClass current;
440           boolean nextObtained;
441           Set<PsiClass> visited = new HashSet<PsiClass>();
442
443           {
444             if (includeSelf) {
445               current = psiClass;
446               nextObtained = true;
447             } else {
448               current = null;
449               nextObtained = false;
450             }
451
452             pushSuper(psiClass);
453           }
454
455           public boolean hasNext() {
456             nextElement();
457             return current != null;
458           }
459
460           private void nextElement() {
461             if (nextObtained) return;
462
463             nextObtained = true;
464             while (!superTypesStack.empty()) {
465               assert indices.size() > 0;
466
467               int i = indices.pop();
468               PsiClassType[] superTypes = superTypesStack.peek();
469               while (i < superTypes.length) {
470                 PsiClass clazz = superTypes[i].resolve();
471                 if (clazz != null && !visited.contains(clazz)) {
472                   current = clazz;
473                   visited.add(clazz);
474                   indices.push(i + 1);
475                   pushSuper(clazz);
476                   return;
477                 }
478                 i++;
479               }
480
481               superTypesStack.pop();
482             }
483
484             current = null;
485           }
486
487           private void pushSuper(PsiClass clazz) {
488             superTypesStack.push(clazz.getSuperTypes());
489             indices.push(0);
490           }
491
492           @NotNull
493           public PsiClass next() {
494             nextElement();
495             nextObtained = false;
496             if (current == null) throw new NoSuchElementException();
497             return current;
498           }
499
500           public void remove() {
501             throw new IllegalStateException("should not be called");
502           }
503         };
504       }
505     };
506   }
507
508   @Nullable
509   public static PsiClass getContextClass(PsiElement context) {
510     GroovyPsiElement parent = PsiTreeUtil.getParentOfType(context, GrTypeDefinition.class, GroovyFileBase.class);
511     if (parent instanceof GrTypeDefinition) {
512       return (PsiClass)parent;
513     } else if (parent instanceof GroovyFileBase) {
514       return ((GroovyFileBase)parent).getScriptClass();
515     }
516     return null;
517   }
518
519   public static boolean mightBeLVlaue(GrExpression expr) {
520     if (expr instanceof GrParenthesizedExpression) return mightBeLVlaue(((GrParenthesizedExpression)expr).getOperand());
521
522     if (expr instanceof GrListOrMap) {
523       GrListOrMap listOrMap = (GrListOrMap)expr;
524       if (listOrMap.isMap()) return false;
525       GrExpression[] initializers = listOrMap.getInitializers();
526       for (GrExpression initializer : initializers) {
527         if (!mightBeLVlaue(initializer)) return false;
528       }
529       return true;
530     }
531     if (expr instanceof GrTupleExpression) return true;
532     return expr instanceof GrReferenceExpression || expr instanceof GrIndexProperty || expr instanceof GrPropertySelection;
533   }
534
535   public static boolean isRawMethodCall(GrMethodCallExpression call) {
536     final GroovyResolveResult[] resolveResults = call.getMethodVariants();
537     if (resolveResults.length == 0) return false;
538     final PsiElement element = resolveResults[0].getElement();
539     if (element instanceof PsiMethod) {
540       PsiType returnType = getSmartReturnType((PsiMethod)element);
541       return isRawType(returnType, resolveResults[0].getSubstitutor());
542     }
543     return false;
544   }
545
546   public static boolean isRawFieldAccess(GrReferenceExpression ref) {
547     PsiElement element = null;
548     final GroovyResolveResult[] resolveResults = ref.multiResolve(false);
549     if (resolveResults.length == 0) return false;
550     final GroovyResolveResult resolveResult = resolveResults[0];
551     if (resolveResult != null) {
552       element = resolveResult.getElement();
553     }
554     if (element instanceof PsiField) {
555       return isRawType(((PsiField)element).getType(), resolveResult.getSubstitutor());
556     }
557     else if (element instanceof GrAccessorMethod) {
558       return isRawType(((GrAccessorMethod)element).getReturnType(), resolveResult.getSubstitutor());
559     }
560     return false;
561   }
562
563   private static boolean isRawIndexPropertyAccess(GrIndexProperty expr) {
564     final GrExpression qualifier = expr.getSelectedExpression();
565     final PsiType qualifierType = qualifier.getType();
566     if (qualifierType instanceof PsiClassType) {
567
568       if (InheritanceUtil.isInheritor(qualifierType, CommonClassNames.JAVA_UTIL_LIST)) {
569         return com.intellij.psi.util.PsiUtil.extractIterableTypeParameter(qualifierType, false) == null;
570       }
571
572       if (InheritanceUtil.isInheritor(qualifierType, CommonClassNames.JAVA_UTIL_MAP)) {
573         return com.intellij.psi.util.PsiUtil.substituteTypeParameter(qualifierType, CommonClassNames.JAVA_UTIL_MAP, 1, false) == null;
574       }
575       PsiClassType classType = (PsiClassType)qualifierType;
576       final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
577       GrExpression[] arguments = expr.getArgumentList().getExpressionArguments();
578       PsiType[] argTypes = new PsiType[arguments.length];
579       for (int i = 0; i < arguments.length; i++) {
580         PsiType argType = arguments[i].getType();
581         if (argType == null) argType = TypesUtil.getJavaLangObject(expr);
582         argTypes[i] = argType;
583       }
584
585       MethodResolverProcessor processor = new MethodResolverProcessor("getAt", expr, false, qualifierType, argTypes, PsiType.EMPTY_ARRAY);
586
587       final PsiClass qClass = resolveResult.getElement();
588       if (qClass != null) {
589         qClass.processDeclarations(processor, ResolveState.initial().put(PsiSubstitutor.KEY, PsiSubstitutor.EMPTY), null, expr);
590       }
591
592       ResolveUtil.processNonCodeMethods(qualifierType, processor, expr.getProject(), expr, false);
593       final GroovyResolveResult[] candidates = processor.getCandidates();
594       PsiType type = null;
595       if (candidates.length == 1) {
596         final PsiElement element = candidates[0].getElement();
597         if (element instanceof PsiMethod) {
598           type = getSmartReturnType((PsiMethod)element);
599         }
600       }
601       return isRawType(type, resolveResult.getSubstitutor());
602     }
603     return false;
604   }
605
606   public static boolean isRawClassMemberAccess(GrExpression expr) {
607     while (expr instanceof GrParenthesizedExpression) {
608       expr = ((GrParenthesizedExpression)expr).getOperand();
609     }
610
611     if (expr instanceof GrMethodCallExpression) {
612       return isRawMethodCall((GrMethodCallExpression)expr);
613     }
614     if (expr instanceof GrReferenceExpression) {
615       return isRawFieldAccess((GrReferenceExpression)expr);
616     }
617     if (expr instanceof GrIndexProperty) {
618       return isRawIndexPropertyAccess((GrIndexProperty)expr);
619     }
620     return false;
621   }
622
623   public static boolean isRawType(PsiType type, PsiSubstitutor substitutor) {
624     if (type instanceof PsiClassType) {
625       final PsiClass returnClass = ((PsiClassType)type).resolve();
626       if (returnClass instanceof PsiTypeParameter) {
627         final PsiTypeParameter typeParameter = (PsiTypeParameter)returnClass;
628         final PsiType substitutedType = substitutor.substitute(typeParameter);
629         if (substitutedType == null) {
630           return true;
631         }
632       }
633     }
634     return false;
635   }
636
637   public static boolean isNewLine(PsiElement element) {
638     if (element == null) return false;
639     ASTNode node = element.getNode();
640     if (node == null) return false;
641     return node.getElementType() == GroovyTokenTypes.mNLS;
642   }
643
644   @Nullable
645   public static PsiElement getPrevNonSpace(final PsiElement elem) {
646     PsiElement prevSibling = elem.getPrevSibling();
647     while (prevSibling instanceof PsiWhiteSpace) {
648       prevSibling = prevSibling.getPrevSibling();
649     }
650     return prevSibling;
651   }
652
653   @Nullable
654   public static PsiElement getNextNonSpace(final PsiElement elem) {
655     PsiElement nextSibling = elem.getNextSibling();
656     while (nextSibling instanceof PsiWhiteSpace) {
657       nextSibling = nextSibling.getNextSibling();
658     }
659     return nextSibling;
660   }
661
662   public static PsiIdentifier getJavaNameIdentifier(GrNamedElement namedElement) {
663     final PsiElement element = namedElement.getNameIdentifierGroovy();
664     JavaIdentifier identifier = element.getUserData(NAME_IDENTIFIER);
665     if (identifier == null) {
666       //noinspection SynchronizationOnLocalVariableOrMethodParameter
667       synchronized (element) {
668         identifier = element.getUserData(NAME_IDENTIFIER);
669         if (identifier != null) {
670           return identifier;
671         }
672
673         identifier = new JavaIdentifier(element.getManager(), element);
674         element.putUserData(NAME_IDENTIFIER, identifier);
675       }
676     }
677     return identifier;
678   }
679
680   @Nullable
681   public static PsiElement findEnclosingStatement(@Nullable PsiElement context) {
682     if (context == null) return null;
683     context = PsiTreeUtil.getParentOfType(context, GrStatement.class, false);
684     while (context != null) {
685       final PsiElement parent = context.getParent();
686       if (parent instanceof GrControlFlowOwner) return context;
687       context = parent;
688     }
689     return null;
690   }
691
692   public static boolean isMethodCall(GrMethodCallExpression call, String methodName) {
693     final GrExpression expression = call.getInvokedExpression();
694     return expression instanceof GrReferenceExpression && methodName.equals(expression.getText().trim());
695   }
696
697   public static boolean hasEnclosingInstanceInScope(PsiClass clazz, PsiElement scope, boolean isSuperClassAccepted) {
698     PsiElement place = scope;
699     while (place != null && place != clazz && !(place instanceof PsiFile)) {
700       if (place instanceof PsiClass) {
701         if (isSuperClassAccepted) {
702           if (InheritanceUtil.isInheritorOrSelf((PsiClass)place, clazz, true)) return true;
703         }
704         else {
705           if (clazz.getManager().areElementsEquivalent(place, clazz)) return true;
706         }
707       }
708       if (place instanceof PsiModifierListOwner && ((PsiModifierListOwner)place).hasModifierProperty(PsiModifier.STATIC)) return false;
709       place = place.getParent();
710     }
711     return place == clazz;
712   }
713
714   @Nullable
715   public static PsiElement skipWhitespaces(@Nullable PsiElement elem, boolean forward) {
716     //noinspection ConstantConditions
717     while (elem != null &&
718            elem.getNode() != null &&
719            GroovyElementTypes.WHITE_SPACES_OR_COMMENTS.contains(elem.getNode().getElementType())) {
720       if (forward) {
721         elem = elem.getNextSibling();
722       }
723       else {
724         elem = elem.getPrevSibling();
725       }
726     }
727     return elem;
728   }
729
730   @Nullable
731   public static PsiType getSmartReturnType(PsiMethod method) {
732     if (method instanceof GrMethod) {
733       return ((GrMethod)method).getInferredReturnType();
734     }
735     else if (method instanceof GrAccessorMethod) {
736       return ((GrAccessorMethod)method).getInferredReturnType();
737     }
738     else {
739       return method.getReturnType();
740     }
741   }
742
743   public static boolean isMethodUsage(PsiElement element) {
744     if (element instanceof GrEnumConstant) return true;
745     if (!(element instanceof GrReferenceElement)) return false;
746     PsiElement parent = element.getParent();
747     if (parent instanceof GrCall) {
748       return true;
749     }
750     else if (parent instanceof GrAnonymousClassDefinition) {
751       return element.equals(((GrAnonymousClassDefinition)parent).getBaseClassReferenceGroovy());
752     }
753     return false;
754   }
755
756   public static GroovyResolveResult[] getConstructorCandidates(GroovyPsiElement place, GroovyResolveResult[] classCandidates, PsiType[] argTypes) {
757     List<GroovyResolveResult> constructorResults = new ArrayList<GroovyResolveResult>();
758     for (GroovyResolveResult classResult : classCandidates) {
759       final PsiElement element = classResult.getElement();
760       if (element instanceof PsiClass) {
761         final GroovyPsiElement context = classResult.getCurrentFileResolveContext();
762         PsiClass clazz = (PsiClass)element;
763         String className = clazz.getName();
764         PsiType thisType = JavaPsiFacade.getInstance(place.getProject()).getElementFactory().createType(clazz, classResult.getSubstitutor());
765         final MethodResolverProcessor processor = new MethodResolverProcessor(className, place, true, thisType, argTypes, PsiType.EMPTY_ARRAY);
766         PsiSubstitutor substitutor = classResult.getSubstitutor();
767         final ResolveState state =
768           ResolveState.initial().put(PsiSubstitutor.KEY, substitutor).put(ResolverProcessor.RESOLVE_CONTEXT, context);
769         final boolean toBreak = element.processDeclarations(processor, state, null, place);
770
771         for (NonCodeMembersProcessor membersProcessor : NonCodeMembersProcessor.EP_NAME.getExtensions()) {
772           if (!membersProcessor.processNonCodeMembers(thisType, processor, place, true)) break;
773         }
774         constructorResults.addAll(Arrays.asList(processor.getCandidates()));
775         if (!toBreak) break;
776       }
777     }
778
779     return constructorResults.toArray(new GroovyResolveResult[constructorResults.size()]);
780   }
781
782   public static boolean isAccessedForReading(GrExpression expr) {
783     return !isLValue(expr);
784   }
785
786   public static boolean isAccessedForWriting(GrExpression expr) {
787     if (isLValue(expr)) return true;
788
789     PsiElement parent = PsiTreeUtil.skipParentsOfType(expr, GrParenthesizedExpression.class);
790
791     if (parent instanceof GrUnaryExpression) {
792       IElementType tokenType = ((GrUnaryExpression)parent).getOperationTokenType();
793       return tokenType == GroovyTokenTypes.mINC || tokenType == GroovyTokenTypes.mDEC;
794     }
795     return false;
796   }
797 }