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