15e7087baa5d35ae99bd66f08357e85004e55d95
[idea/community.git] / plugins / groovy / groovy-psi / src / org / jetbrains / plugins / groovy / lang / psi / util / PsiUtil.java
1 /*
2  * Copyright 2000-2016 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.lang.ASTNode;
20 import com.intellij.openapi.diagnostic.Logger;
21 import com.intellij.openapi.util.Condition;
22 import com.intellij.openapi.util.Key;
23 import com.intellij.openapi.util.TextRange;
24 import com.intellij.openapi.util.Trinity;
25 import com.intellij.psi.*;
26 import com.intellij.psi.codeStyle.CodeStyleManager;
27 import com.intellij.psi.impl.light.JavaIdentifier;
28 import com.intellij.psi.impl.light.LightElement;
29 import com.intellij.psi.search.GlobalSearchScope;
30 import com.intellij.psi.tree.IElementType;
31 import com.intellij.psi.tree.TokenSet;
32 import com.intellij.psi.util.*;
33 import com.intellij.util.ArrayUtil;
34 import com.intellij.util.IncorrectOperationException;
35 import com.intellij.util.VisibilityUtil;
36 import com.intellij.util.containers.ContainerUtil;
37 import com.intellij.util.containers.HashSet;
38 import gnu.trove.TIntStack;
39 import org.jetbrains.annotations.Contract;
40 import org.jetbrains.annotations.NotNull;
41 import org.jetbrains.annotations.Nullable;
42 import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
43 import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
44 import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocComment;
45 import org.jetbrains.plugins.groovy.lang.lexer.GroovyLexer;
46 import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
47 import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
48 import org.jetbrains.plugins.groovy.lang.psi.*;
49 import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
50 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
51 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier;
52 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
53 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation;
54 import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature;
55 import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignature;
56 import org.jetbrains.plugins.groovy.lang.psi.api.statements.*;
57 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
58 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
59 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
60 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrSpreadArgument;
61 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
62 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock;
63 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
64 import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrAssertStatement;
65 import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement;
66 import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement;
67 import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseSection;
68 import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrForInClause;
69 import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrTraditionalForClause;
70 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
71 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
72 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty;
73 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
74 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrPropertySelection;
75 import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
76 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
77 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
78 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.*;
79 import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
80 import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
81 import org.jetbrains.plugins.groovy.lang.psi.api.util.GrNamedArgumentsOwner;
82 import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
83 import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper;
84 import org.jetbrains.plugins.groovy.lang.psi.impl.*;
85 import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil;
86 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
87 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl;
88 import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrBindingVariable;
89 import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
90 import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParameterEnhancer;
91 import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
92 import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor;
93
94 import java.util.*;
95
96 /**
97  * @author ven
98  */
99 public class PsiUtil {
100   public static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil");
101   public static final Key<JavaIdentifier> NAME_IDENTIFIER = new Key<JavaIdentifier>("Java Identifier");
102   public static final Set<String> OPERATOR_METHOD_NAMES = ContainerUtil.newHashSet(
103     "plus", "minus", "multiply", "power", "div", "mod", "or", "and", "xor", "next", "previous", "getAt", "putAt", "leftShift", "rightShift",
104     "isCase", "bitwiseNegate", "negative", "positive", "call"
105   );
106
107   private PsiUtil() {
108   }
109
110   @Nullable
111   public static PsiElement findModifierInList(@NotNull GrModifierList list, @GrModifier.GrModifierConstant @NotNull String modifier) {
112     for (PsiElement element : list.getModifiers()) {
113       if (modifier.equals(element.getText())) return element;
114     }
115     return null;
116   }
117
118   @Nullable
119   public static String getMethodName(GrMethodCall methodCall) {
120     GrExpression invokedExpression = methodCall.getInvokedExpression();
121     if (!(invokedExpression instanceof GrReferenceExpression)) return null;
122
123     return ((GrReferenceExpression)invokedExpression).getReferenceName();
124   }
125
126   @Nullable
127   public static String getUnqualifiedMethodName(GrMethodCall methodCall) {
128     GrExpression invokedExpression = methodCall.getInvokedExpression();
129     if (!(invokedExpression instanceof GrReferenceExpression)) return null;
130
131     if (((GrReferenceExpression)invokedExpression).isQualified()) return null;
132
133     return ((GrReferenceExpression)invokedExpression).getReferenceName();
134   }
135
136   @Nullable
137   public static String getQualifiedReferenceText(GrCodeReferenceElement referenceElement) {
138     StringBuilder builder = new StringBuilder();
139     if (!appendName(referenceElement, builder)) return null;
140
141     return builder.toString();
142   }
143
144   private static boolean appendName(GrCodeReferenceElement referenceElement, StringBuilder builder) {
145     String refName = referenceElement.getReferenceName();
146     if (refName == null) return false;
147     GrCodeReferenceElement qualifier = referenceElement.getQualifier();
148     if (qualifier != null) {
149       appendName(qualifier, builder);
150       builder.append(".");
151     }
152
153     builder.append(refName);
154     return true;
155   }
156
157   public static boolean isLValue(GroovyPsiElement element) {
158     if (element instanceof GrExpression) {
159       PsiElement parent = PsiTreeUtil.skipParentsOfType(element, GrParenthesizedExpression.class);
160       if (parent instanceof GrTupleExpression) {
161         return isLValue((GroovyPsiElement)parent);
162       }
163       return parent instanceof GrAssignmentExpression &&
164              PsiTreeUtil.isAncestor(((GrAssignmentExpression)parent).getLValue(), element, false);
165     }
166     return false;
167   }
168
169   public static boolean isApplicable(@Nullable PsiType[] argumentTypes,
170                                      PsiMethod method,
171                                      PsiSubstitutor substitutor,
172                                      PsiElement place,
173                                      final boolean eraseParameterTypes) {
174     return isApplicableConcrete(argumentTypes, method, substitutor, place, eraseParameterTypes) !=
175            GrClosureSignatureUtil.ApplicabilityResult.inapplicable;
176   }
177
178   public static GrClosureSignatureUtil.ApplicabilityResult isApplicableConcrete(@Nullable PsiType[] argumentTypes,
179                                                                                 PsiMethod method,
180                                                                                 PsiSubstitutor substitutor,
181                                                                                 PsiElement place,
182                                                                                 final boolean eraseParameterTypes) {
183     if (argumentTypes == null) return GrClosureSignatureUtil.ApplicabilityResult.canBeApplicable;
184
185     GrClosureSignature signature = eraseParameterTypes
186                                    ? GrClosureSignatureUtil.createSignatureWithErasedParameterTypes(method)
187                                    : GrClosureSignatureUtil.createSignature(method, substitutor);
188
189     //check for default constructor
190     if (method.isConstructor()) {
191       final PsiParameter[] parameters = method.getParameterList().getParameters();
192       if (parameters.length == 0 && argumentTypes.length == 1) {
193         return InheritanceUtil.isInheritor(argumentTypes[0], CommonClassNames.JAVA_UTIL_MAP)
194                ? GrClosureSignatureUtil.ApplicabilityResult.applicable
195                : GrClosureSignatureUtil.ApplicabilityResult.inapplicable;
196       }
197       if (parameters.length == 1 &&
198           argumentTypes.length == 0 &&
199           InheritanceUtil.isInheritor(parameters[0].getType(), CommonClassNames.JAVA_UTIL_MAP)) {
200         return GrClosureSignatureUtil.ApplicabilityResult.inapplicable;
201       }
202     }
203     LOG.assertTrue(signature != null);
204     GrClosureSignatureUtil.ApplicabilityResult result =
205       GrClosureSignatureUtil.isSignatureApplicableConcrete(signature, argumentTypes, place);
206     if (result != GrClosureSignatureUtil.ApplicabilityResult.inapplicable) {
207       return result;
208     }
209
210     if (method instanceof GrBuilderMethod && !((GrBuilderMethod)method).hasObligatoryNamedArguments()) {
211       final PsiParameter[] parameters = method.getParameterList().getParameters();
212       if (parameters.length > 0 && parameters[0].getType() instanceof GrMapType &&
213           (argumentTypes.length == 0 || !(argumentTypes[0] instanceof GrMapType))) {
214         return GrClosureSignatureUtil.isSignatureApplicableConcrete(GrClosureSignatureUtil.removeParam(signature, 0), argumentTypes, place);
215       }
216     }
217     return GrClosureSignatureUtil.ApplicabilityResult.inapplicable;
218   }
219
220   public static boolean isApplicable(@Nullable PsiType[] argumentTypes,
221                                      GrClosureType type,
222                                      GroovyPsiElement context) {
223     return isApplicableConcrete(argumentTypes, type, context) != GrClosureSignatureUtil.ApplicabilityResult.inapplicable;
224   }
225
226   public static GrClosureSignatureUtil.ApplicabilityResult isApplicableConcrete(@Nullable PsiType[] argumentTypes,
227                                                                                 GrClosureType type,
228                                                                                 GroovyPsiElement context) {
229     if (argumentTypes == null) return GrClosureSignatureUtil.ApplicabilityResult.canBeApplicable;
230
231     GrSignature signature = type.getSignature();
232     return GrClosureSignatureUtil.isSignatureApplicableConcrete(signature, argumentTypes, context);
233   }
234
235   @Nullable
236   public static GrArgumentList getArgumentsList(@Nullable PsiElement methodRef) {
237     if (methodRef == null) return null;
238
239     if (methodRef instanceof GrEnumConstant) return ((GrEnumConstant)methodRef).getArgumentList();
240     PsiElement parent = methodRef.getParent();
241     if (parent instanceof GrCall) {
242       return ((GrCall)parent).getArgumentList();
243     }
244     if (parent instanceof GrAnonymousClassDefinition) {
245       return ((GrAnonymousClassDefinition)parent).getArgumentListGroovy();
246     }
247     return null;
248   }
249
250   @Nullable
251   public static PsiType[] getArgumentTypes(@Nullable PsiElement place, boolean nullAsBottom) {
252     return getArgumentTypes(place, nullAsBottom, null, false);
253   }
254
255   @Nullable
256   public static PsiType[] getArgumentTypes(@Nullable PsiElement place,
257                                            boolean nullAsBottom,
258                                            @Nullable GrExpression stopAt,
259                                            boolean byShape) {
260     PsiElement parent = place instanceof GrEnumConstant ? place : place != null ? place.getParent() : null;
261
262     if (parent instanceof GrIndexProperty) {
263       GrIndexProperty index = (GrIndexProperty)parent;
264       PsiType[] argTypes = getArgumentTypes(index.getNamedArguments(), index.getExpressionArguments(), index.getClosureArguments(), nullAsBottom, stopAt, byShape);
265       if (isLValue(index) && argTypes != null) {
266         PsiType rawInitializer = TypeInferenceHelper.getInitializerTypeFor(index);
267
268         PsiType initializer = notNullizeType(rawInitializer, nullAsBottom, index);
269         return ArrayUtil.append(argTypes, initializer);
270       }
271       else {
272         return argTypes;
273       }
274     }
275     if (parent instanceof GrCall) {
276       GrCall call = (GrCall)parent;
277       GrNamedArgument[] namedArgs = call.getNamedArguments();
278       GrExpression[] expressions = call.getExpressionArguments();
279       GrClosableBlock[] closures = call.getClosureArguments();
280
281       return getArgumentTypes(namedArgs, expressions, closures, nullAsBottom, stopAt, byShape);
282     }
283     else if (parent instanceof GrAnonymousClassDefinition) {
284       final GrArgumentList argList = ((GrAnonymousClassDefinition)parent).getArgumentListGroovy();
285       if (argList == null) {
286         return getArgumentTypes(GrNamedArgument.EMPTY_ARRAY, GrExpression.EMPTY_ARRAY, GrClosableBlock.EMPTY_ARRAY, nullAsBottom, stopAt, byShape);
287       }
288       else {
289         return getArgumentTypes(argList.getNamedArguments(), argList.getExpressionArguments(), GrClosableBlock.EMPTY_ARRAY, nullAsBottom, stopAt, byShape);
290       }
291     }
292     else if (parent instanceof GrBinaryExpression) {
293       GrExpression right = ((GrBinaryExpression)parent).getRightOperand();
294       PsiType type = right != null ? right.getType() : null;
295       return new PsiType[] {notNullizeType(type, nullAsBottom, parent)};
296     }
297
298     return null;
299   }
300
301   @Contract("_, false, _ -> !null; !null, _, _ -> !null; null, true, _ -> null")
302   private static PsiType notNullizeType(PsiType type, boolean acceptNull, PsiElement context) {
303     return type != null || acceptNull ? type : TypesUtil.getJavaLangObject(context);
304   }
305
306   @Nullable
307   public static PsiType[] getArgumentTypes(GrArgumentList argList) {
308     return getArgumentTypes(argList, false, null, false);
309   }
310
311   @Nullable
312   public static PsiType[] getArgumentTypes(@NotNull GrNamedArgument[] namedArgs,
313                                            @NotNull GrExpression[] expressions,
314                                            @NotNull GrClosableBlock[] closures,
315                                            boolean nullAsBottom,
316                                            @Nullable GrExpression stopAt,
317                                            boolean byShape) {
318     List<PsiType> result = new ArrayList<PsiType>();
319
320     if (namedArgs.length > 0) {
321       GrNamedArgument context = namedArgs[0];
322       result.add(GrMapType.createFromNamedArgs(context, byShape ? new GrNamedArgument[0] : namedArgs));
323     }
324
325     for (GrExpression expression : expressions) {
326       PsiType type = expression.getType();
327       if (expression instanceof GrSpreadArgument) {
328         if (type instanceof GrTupleType) {
329           result.addAll(Arrays.asList(((GrTupleType)type).getComponentTypes()));
330         }
331         else {
332           return null;
333         }
334       }
335       else {
336         if (type == null) {
337           result.add(nullAsBottom ? null : TypesUtil.getJavaLangObject(expression));
338         }
339         else {
340           if (stopAt == expression) {
341             type = TypeConversionUtil.erasure(type);
342           }
343           result.add(type);
344         }
345       }
346
347       if (stopAt == expression) {
348         return result.toArray(PsiType.createArray(result.size()));
349       }
350     }
351
352     for (GrClosableBlock closure : closures) {
353       PsiType closureType = closure.getType();
354       if (closureType != null) {
355         if (stopAt == closure) {
356           closureType = TypeConversionUtil.erasure(closureType);
357         }
358         result.add(notNullizeType(closureType, nullAsBottom, closure));
359       }
360       if (stopAt == closure) {
361         break;
362       }
363     }
364
365     return result.toArray(PsiType.createArray(result.size()));
366   }
367
368   @Nullable
369   public static PsiClass getJavaLangClass(PsiElement resolved, GlobalSearchScope scope) {
370     return JavaPsiFacade.getInstance(resolved.getProject()).findClass(CommonClassNames.JAVA_LANG_CLASS, scope);
371   }
372
373   public static boolean isValidReferenceName(@NotNull String text) {
374     final GroovyLexer lexer = new GroovyLexer();
375     lexer.start(text);
376     return TokenSets.REFERENCE_NAMES_WITHOUT_NUMBERS.contains(lexer.getTokenType()) && lexer.getTokenEnd() == text.length();
377   }
378
379   public static boolean isAccessible(@NotNull PsiElement place, @NotNull PsiMember member) {
380     if (member instanceof LightElement) {
381       return true;
382     }
383
384     if (place instanceof GrReferenceExpression && ((GrReferenceExpression)place).getQualifierExpression() == null) {
385       if (member.getContainingClass() instanceof GroovyScriptClass) { //calling top level script members from the same script file
386         return true;
387       }
388     }
389
390     if (PsiTreeUtil.getParentOfType(place, GrDocComment.class) != null) return true;
391
392     return com.intellij.psi.util.PsiUtil.isAccessible(member, place, null);
393   }
394
395   public static void reformatCode(final PsiElement element) {
396     final TextRange textRange = element.getTextRange();
397
398     PsiFile file = element.getContainingFile();
399     FileViewProvider viewProvider = file.getViewProvider();
400
401     if (viewProvider instanceof MultiplePsiFilesPerDocumentFileViewProvider) {
402       MultiplePsiFilesPerDocumentFileViewProvider multiProvider = (MultiplePsiFilesPerDocumentFileViewProvider)viewProvider;
403       file = multiProvider.getPsi(multiProvider.getBaseLanguage());
404       LOG.assertTrue(file != null, element + " " + multiProvider.getBaseLanguage());
405     }
406
407     try {
408       CodeStyleManager.getInstance(element.getProject())
409         .reformatText(file, textRange.getStartOffset(), textRange.getEndOffset());
410     }
411     catch (IncorrectOperationException e) {
412       LOG.error(e);
413     }
414   }
415
416   public static Iterable<PsiClass> iterateSupers(@NotNull final PsiClass psiClass, final boolean includeSelf) {
417     return new Iterable<PsiClass>() {
418       @Override
419       public Iterator<PsiClass> iterator() {
420         return new Iterator<PsiClass>() {
421           TIntStack indices = new TIntStack();
422           Stack<PsiClassType[]> superTypesStack = new Stack<PsiClassType[]>();
423           PsiClass current;
424           boolean nextObtained;
425           Set<PsiClass> visited = new HashSet<PsiClass>();
426
427           {
428             if (includeSelf) {
429               current = psiClass;
430               nextObtained = true;
431             }
432             else {
433               current = null;
434               nextObtained = false;
435             }
436
437             pushSuper(psiClass);
438           }
439
440           @Override
441           public boolean hasNext() {
442             nextElement();
443             return current != null;
444           }
445
446           private void nextElement() {
447             if (nextObtained) return;
448
449             nextObtained = true;
450             while (!superTypesStack.empty()) {
451               assert indices.size() > 0;
452
453               int i = indices.pop();
454               PsiClassType[] superTypes = superTypesStack.peek();
455               while (i < superTypes.length) {
456                 PsiClass clazz = superTypes[i].resolve();
457                 if (clazz != null && !visited.contains(clazz)) {
458                   current = clazz;
459                   visited.add(clazz);
460                   indices.push(i + 1);
461                   pushSuper(clazz);
462                   return;
463                 }
464                 i++;
465               }
466
467               superTypesStack.pop();
468             }
469
470             current = null;
471           }
472
473           private void pushSuper(PsiClass clazz) {
474             superTypesStack.push(clazz.getSuperTypes());
475             indices.push(0);
476           }
477
478           @Override
479           @NotNull
480           public PsiClass next() {
481             nextElement();
482             nextObtained = false;
483             if (current == null) throw new NoSuchElementException();
484             return current;
485           }
486
487           @Override
488           public void remove() {
489             throw new IllegalStateException("should not be called");
490           }
491         };
492       }
493     };
494   }
495
496   @Nullable
497   public static PsiClass getContextClass(@Nullable PsiElement context) {
498     while (context != null) {
499       if (context instanceof PsiClass && !isInDummyFile(context)) {
500         return (PsiClass)context;
501       }
502       else if (context instanceof GroovyFileBase && !isInDummyFile(context)) {
503         return ((GroovyFileBase)context).getScriptClass();
504       }
505
506       context = context.getContext();
507     }
508     return null;
509   }
510
511   public static boolean isInDummyFile(@NotNull PsiElement context) {
512     PsiFile file = context.getContainingFile();
513     if (file == null) return false;
514
515     String name = file.getName();
516     return name.startsWith(GroovyPsiElementFactory.DUMMY_FILE_NAME);
517   }
518
519   @Nullable
520   public static GroovyPsiElement getFileOrClassContext(PsiElement context) {
521     while (context != null) {
522       if (context instanceof GrTypeDefinition) {
523         return (GroovyPsiElement)context;
524       }
525       else if (context instanceof GroovyFileBase && context.isPhysical()) {
526         return (GroovyPsiElement)context;
527       }
528
529       context = context.getContext();
530     }
531
532     return null;
533   }
534
535   public static boolean mightBeLValue(@Nullable GrExpression expr) {
536     if (expr instanceof GrParenthesizedExpression) return mightBeLValue(((GrParenthesizedExpression)expr).getOperand());
537
538     if (expr instanceof GrTupleExpression ||
539         expr instanceof GrReferenceExpression ||
540         expr instanceof GrIndexProperty ||
541         expr instanceof GrPropertySelection) {
542       return true;
543     }
544
545     if ((isThisOrSuperRef(expr)) &&
546         GroovyConfigUtils.getInstance().isVersionAtLeast(expr, GroovyConfigUtils.GROOVY1_8)) {
547       return true;
548     }
549     return false;
550   }
551
552   public static boolean isRawMethodCall(GrMethodCallExpression call) {
553     final GroovyResolveResult result = call.advancedResolve();
554     final PsiElement element = result.getElement();
555     if (element == null) return false;
556     if (element instanceof PsiMethod) {
557       PsiType returnType = getSmartReturnType((PsiMethod)element);
558       final GrExpression expression = call.getInvokedExpression();
559       if (expression instanceof GrReferenceExpression && result.isInvokedOnProperty()) {
560         if (returnType instanceof GrClosureType) {
561           return isRawClosureCall(call, result, (GrClosureType)returnType);
562         }
563       }
564       else {
565         return isRawType(returnType, result.getSubstitutor());
566       }
567     }
568     if (element instanceof PsiVariable) {
569       GrExpression expression = call.getInvokedExpression();
570       final PsiType type = expression.getType();
571       if (type instanceof GrClosureType) {
572         return isRawClosureCall(call, result, (GrClosureType)type);
573       }
574     }
575
576     return false;
577   }
578
579   private static boolean isRawClosureCall(GrMethodCallExpression call, GroovyResolveResult result, GrClosureType returnType) {
580     final GrSignature signature = returnType.getSignature();
581     GrClosureSignature _signature;
582     if (signature instanceof GrClosureSignature) {
583       _signature = (GrClosureSignature)signature;
584     }
585     else {
586       final PsiType[] types = getArgumentTypes(call.getInvokedExpression(), true);
587       final Trinity<GrClosureSignature, GrClosureSignatureUtil.ArgInfo<PsiType>[], GrClosureSignatureUtil.ApplicabilityResult>
588         resultTrinity = types != null ? GrClosureSignatureUtil.getApplicableSignature(signature, types, call) : null;
589       _signature = resultTrinity != null ? resultTrinity.first : null;
590     }
591     if (_signature != null) {
592       return isRawType(_signature.getReturnType(), TypesUtil.composeSubstitutors(_signature.getSubstitutor(), result.getSubstitutor()));
593     }
594     return false;
595   }
596
597   public static boolean isRawFieldAccess(GrReferenceExpression ref) {
598     PsiElement element = null;
599     final GroovyResolveResult[] resolveResults = ref.multiResolve(false);
600     if (resolveResults.length == 0) return false;
601     final GroovyResolveResult resolveResult = resolveResults[0];
602     if (resolveResult != null) {
603       element = resolveResult.getElement();
604     }
605     if (element instanceof PsiField) {
606       return isRawType(((PsiField)element).getType(), resolveResult.getSubstitutor());
607     }
608     else if (element instanceof GrAccessorMethod) {
609       return isRawType(((GrAccessorMethod)element).getReturnType(), resolveResult.getSubstitutor());
610     }
611     return false;
612   }
613
614   private static boolean isRawIndexPropertyAccess(GrIndexProperty expr) {
615     final GrExpression qualifier = expr.getInvokedExpression();
616     final PsiType qualifierType = qualifier.getType();
617     if (qualifierType instanceof PsiClassType) {
618
619       if (InheritanceUtil.isInheritor(qualifierType, CommonClassNames.JAVA_UTIL_LIST)) {
620         return com.intellij.psi.util.PsiUtil.extractIterableTypeParameter(qualifierType, false) == null;
621       }
622
623       if (InheritanceUtil.isInheritor(qualifierType, CommonClassNames.JAVA_UTIL_MAP)) {
624         return com.intellij.psi.util.PsiUtil.substituteTypeParameter(qualifierType, CommonClassNames.JAVA_UTIL_MAP, 1, false) == null;
625       }
626       PsiClassType classType = (PsiClassType)qualifierType;
627       final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
628       GrExpression[] arguments = expr.getArgumentList().getExpressionArguments();
629       PsiType[] argTypes = PsiType.createArray(arguments.length);
630       for (int i = 0; i < arguments.length; i++) {
631         PsiType argType = arguments[i].getType();
632         if (argType == null) argType = TypesUtil.getJavaLangObject(expr);
633         argTypes[i] = argType;
634       }
635
636       MethodResolverProcessor processor = new MethodResolverProcessor("getAt", expr, false, qualifierType, argTypes, PsiType.EMPTY_ARRAY);
637
638       final PsiClass qClass = resolveResult.getElement();
639       final ResolveState state = ResolveState.initial().put(PsiSubstitutor.KEY, PsiSubstitutor.EMPTY);
640       if (qClass != null) {
641         qClass.processDeclarations(processor, state, null, expr);
642       }
643
644       ResolveUtil.processNonCodeMembers(qualifierType, processor, qualifier, state);
645       final GroovyResolveResult[] candidates = processor.getCandidates();
646       PsiType type = null;
647       if (candidates.length == 1) {
648         final PsiElement element = candidates[0].getElement();
649         if (element instanceof PsiMethod) {
650           type = getSmartReturnType((PsiMethod)element);
651         }
652       }
653       return isRawType(type, resolveResult.getSubstitutor());
654     }
655     return false;
656   }
657
658   public static boolean isRawClassMemberAccess(GrExpression expr) {
659     expr = (GrExpression)skipParentheses(expr, false);
660
661     if (expr instanceof GrMethodCallExpression) {
662       return isRawMethodCall((GrMethodCallExpression)expr);
663     }
664     if (expr instanceof GrReferenceExpression) {
665       return isRawFieldAccess((GrReferenceExpression)expr);
666     }
667     if (expr instanceof GrIndexProperty) {
668       return isRawIndexPropertyAccess((GrIndexProperty)expr);
669     }
670     return false;
671   }
672
673   public static boolean isRawType(@Nullable PsiType type, @NotNull PsiSubstitutor substitutor) {
674     if (type instanceof PsiClassType) {
675       final PsiClass returnClass = ((PsiClassType)type).resolve();
676       if (returnClass instanceof PsiTypeParameter) {
677         final PsiTypeParameter typeParameter = (PsiTypeParameter)returnClass;
678         return substitutor.substitute(typeParameter) == null;
679       }
680     }
681     return false;
682   }
683
684   public static boolean isWhiteSpaceOrLineFeed(PsiElement element) {
685     if (element == null) return false;
686     ASTNode node = element.getNode();
687     if (node == null) return false;
688     IElementType elementType = node.getElementType();
689     return elementType == GroovyTokenTypes.mNLS || elementType == TokenType.WHITE_SPACE;
690   }
691
692   public static boolean isNewLine(PsiElement element) {
693     return isWhiteSpaceOrLineFeed(element) && element.getText().contains("\n");
694   }
695
696   @Nullable
697   public static PsiElement getPrevNonSpace(@NotNull final PsiElement elem) {
698     PsiElement prevSibling = elem.getPrevSibling();
699     while (prevSibling instanceof PsiWhiteSpace) {
700       prevSibling = prevSibling.getPrevSibling();
701     }
702     return prevSibling;
703   }
704
705   @Nullable
706   public static PsiElement getNextNonSpace(final PsiElement elem) {
707     PsiElement nextSibling = elem.getNextSibling();
708     while (nextSibling instanceof PsiWhiteSpace) {
709       nextSibling = nextSibling.getNextSibling();
710     }
711     return nextSibling;
712   }
713
714   @NotNull
715   public static PsiIdentifier getJavaNameIdentifier(@NotNull GrNamedElement namedElement) {
716     final PsiElement element = namedElement.getNameIdentifierGroovy();
717     JavaIdentifier identifier = element.getUserData(NAME_IDENTIFIER);
718     if (identifier == null) {
719       //noinspection SynchronizationOnLocalVariableOrMethodParameter
720       synchronized (element) {
721         identifier = element.getUserData(NAME_IDENTIFIER);
722         if (identifier != null) {
723           return identifier;
724         }
725
726         identifier = new JavaIdentifier(element.getManager(), element);
727         element.putUserData(NAME_IDENTIFIER, identifier);
728       }
729     }
730     return identifier;
731   }
732
733   @Nullable
734   public static GrStatement findEnclosingStatement(@Nullable PsiElement context) {
735     while (context != null) {
736       if (isExpressionStatement(context)) return (GrStatement)context;
737       context = PsiTreeUtil.getParentOfType(context, GrStatement.class, true);
738     }
739     return null;
740   }
741
742   public static boolean isMethodCall(GrMethodCall call, String methodName) {
743     final GrExpression expression = call.getInvokedExpression();
744     return expression instanceof GrReferenceExpression && methodName.equals(expression.getText().trim());
745   }
746   public static boolean hasEnclosingInstanceInScope(@NotNull PsiClass clazz, @Nullable PsiElement scope, boolean isSuperClassAccepted) {
747     return findEnclosingInstanceClassInScope(clazz, scope, isSuperClassAccepted) != null;
748   }
749
750   public static PsiClass findEnclosingInstanceClassInScope(@NotNull PsiClass clazz, @Nullable PsiElement scope, boolean isInheritorOfClazzAccepted) {
751     PsiElement place = scope;
752     while (place != null && place != clazz && !(place instanceof PsiFile && place.isPhysical())) {
753       if (place instanceof PsiClass) {
754         if (isInheritorOfClazzAccepted) {
755           if (InheritanceUtil.isInheritorOrSelf((PsiClass)place, clazz, true)) return (PsiClass)place;
756         }
757         else {
758           if (clazz.getManager().areElementsEquivalent(place, clazz)) return (PsiClass)place;
759         }
760       }
761       if (place instanceof PsiModifierListOwner && ((PsiModifierListOwner)place).hasModifierProperty(PsiModifier.STATIC)) return null;
762       place = place.getContext();
763     }
764     if (clazz instanceof GroovyScriptClass && place == clazz.getContainingFile() || place == clazz) {
765       return clazz;
766     }
767     return null;
768   }
769
770
771   @Nullable
772   public static PsiElement skipWhitespacesAndComments(@Nullable PsiElement elem, boolean forward, boolean skipNLs) {
773     return skipSet(elem, forward, TokenSets.WHITE_SPACES_OR_COMMENTS, skipNLs);
774   }
775
776
777   @Nullable
778   public static PsiElement skipWhitespacesAndComments(@Nullable PsiElement elem, boolean forward) {
779     return skipSet(elem, forward, TokenSets.WHITE_SPACES_OR_COMMENTS, true);
780   }
781
782   private static PsiElement skipSet(PsiElement elem, boolean forward, TokenSet set, boolean skipNLs) {
783     while (elem != null &&
784            elem.getNode() != null &&
785            set.contains(elem.getNode().getElementType()) &&
786            (skipNLs || elem.getText().indexOf('\n') == -1)) {
787       if (forward) {
788         elem = elem.getNextSibling();
789       }
790       else {
791         elem = elem.getPrevSibling();
792       }
793     }
794     return elem;
795   }
796
797   @Nullable
798   public static PsiElement skipWhitespaces(@Nullable PsiElement elem, boolean forward) {
799     return skipSet(elem, forward, TokenSets.WHITE_SPACES_SET, true);
800   }
801
802
803   @Nullable
804   public static PsiType getSmartReturnType(@NotNull PsiMethod method) {
805     if (method instanceof GrMethod) {
806       return ((GrMethod)method).getInferredReturnType();
807     }
808     else if (method instanceof GrAccessorMethod) {
809       return ((GrAccessorMethod)method).getInferredReturnType();
810     }
811     else if (method instanceof GrGdkMethod) {
812       return getSmartReturnType(((GrGdkMethod)method).getStaticMethod());
813     }
814     else {
815       return method.getReturnType();
816     }
817   }
818
819   public static boolean isClosurePropertyGetter(PsiMethod method) {
820     String methodName = method.getName();
821     if (methodName.startsWith("get") && GroovyPropertyUtils.isGetterName(methodName)) { // exclude isXXX()
822       PsiModifierList modifiers = method.getModifierList();
823
824       if (!modifiers.hasModifierProperty(PsiModifier.STATIC)
825           && !modifiers.hasModifierProperty(PsiModifier.PRIVATE)
826           && !modifiers.hasModifierProperty(PsiModifier.PROTECTED)
827           && method.getParameterList().getParametersCount() == 0) {
828         final PsiType type = getSmartReturnType(method);
829         if (type != null && (TypesUtil.isClassType(type, CommonClassNames.JAVA_LANG_OBJECT) || TypesUtil.isClassType(type,
830                                                                                                                      GroovyCommonClassNames.GROOVY_LANG_CLOSURE))) {
831           return true;
832         }
833       }
834     }
835
836     return false;
837   }
838
839   public static boolean isMethodUsage(PsiElement element) {
840     if (element instanceof GrEnumConstant) return true;
841     if (!(element instanceof GrReferenceElement)) return false;
842     PsiElement parent = element.getParent();
843     if (parent instanceof GrCall) {
844       return true;
845     }
846     else if (parent instanceof GrAnonymousClassDefinition) {
847       return element.equals(((GrAnonymousClassDefinition)parent).getBaseClassReferenceGroovy());
848     }
849     return false;
850   }
851
852   @NotNull
853   public static GroovyResolveResult[] getConstructorCandidates(@NotNull PsiElement place,
854                                                                @NotNull GroovyResolveResult classCandidate,
855                                                                @Nullable PsiType[] argTypes) {
856     final PsiElement element = classCandidate.getElement();
857     if (!(element instanceof PsiClass)) return GroovyResolveResult.EMPTY_ARRAY;
858
859     PsiClass clazz = (PsiClass)element;
860     PsiSubstitutor substitutor = classCandidate.getSubstitutor();
861     return ResolveUtil.getAllClassConstructors(clazz, substitutor, argTypes, place);
862   }
863
864   public static boolean isAccessedForReading(GrExpression expr) {
865     return !isLValue(expr);
866   }
867
868   public static boolean isAccessedForWriting(GrExpression expr) {
869     return isLValue(expr) || isUsedInIncOrDec(expr);
870   }
871
872   public static boolean isUsedInIncOrDec(GrExpression expr) {
873     PsiElement parent = PsiTreeUtil.skipParentsOfType(expr, GrParenthesizedExpression.class);
874
875     if (parent instanceof GrUnaryExpression) {
876       IElementType tokenType = ((GrUnaryExpression)parent).getOperationTokenType();
877       return tokenType == GroovyTokenTypes.mINC || tokenType == GroovyTokenTypes.mDEC;
878     }
879     return false;
880   }
881
882   public static GrReferenceExpression qualifyMemberReference(GrReferenceExpression refExpr, PsiMember member, String name) {
883     assert refExpr.getQualifierExpression() == null;
884
885     final PsiClass clazz = member.getContainingClass();
886     assert clazz != null;
887
888     final PsiElement replaced;
889     if (member.hasModifierProperty(PsiModifier.STATIC)) {
890       final GrReferenceExpression newRefExpr = GroovyPsiElementFactory.getInstance(member.getProject())
891         .createReferenceExpressionFromText(clazz.getQualifiedName() + "." + name);
892       replaced = refExpr.replace(newRefExpr);
893     }
894     else {
895       final PsiClass containingClass = PsiTreeUtil.getParentOfType(refExpr, PsiClass.class);
896       if (member.getManager().areElementsEquivalent(containingClass, clazz)) {
897         final GrReferenceExpression newRefExpr = GroovyPsiElementFactory.getInstance(member.getProject())
898           .createReferenceExpressionFromText("this." + name);
899         replaced = refExpr.replace(newRefExpr);
900       }
901       else {
902         final GrReferenceExpression newRefExpr = GroovyPsiElementFactory.getInstance(member.getProject())
903           .createReferenceExpressionFromText(clazz.getName() + ".this." + name);
904         replaced = refExpr.replace(newRefExpr);
905       }
906     }
907     return (GrReferenceExpression)replaced;
908   }
909
910   public static GroovyResolveResult[] getConstructorCandidates(PsiClassType classType, PsiType[] argTypes, GroovyPsiElement context) {
911     final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
912     final PsiClass psiClass = resolveResult.getElement();
913     final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
914     if (psiClass == null) {
915       return GroovyResolveResult.EMPTY_ARRAY;
916     }
917
918     final GroovyResolveResult grResult = resolveResult instanceof GroovyResolveResult
919                                          ? (GroovyResolveResult)resolveResult
920                                          : new GroovyResolveResultImpl(psiClass, context, null, substitutor, true, true);
921     return getConstructorCandidates(context, grResult, argTypes);
922   }
923
924   @Nullable
925   public static PsiElement skipParentheses(@Nullable PsiElement element, boolean up) {
926     if (element == null) return null;
927     if (up) {
928       PsiElement parent;
929       while ((parent = element.getParent()) instanceof GrParenthesizedExpression) {
930         element = parent;
931       }
932       return element;
933     }
934     else {
935       while (element instanceof GrParenthesizedExpression) {
936         element = ((GrParenthesizedExpression)element).getOperand();
937       }
938       return element;
939     }
940   }
941
942   @NotNull
943   public static PsiElement skipParenthesesIfSensibly(@NotNull PsiElement element, boolean up) {
944     PsiElement res = skipParentheses(element, up);
945     return res == null ? element : res;
946   }
947
948
949   @Nullable
950   public static PsiElement getNamedArgumentValue(GrNamedArgument otherNamedArgument, String argumentName) {
951     PsiElement parent = otherNamedArgument.getParent();
952
953     if (!(parent instanceof GrNamedArgumentsOwner)) return null;
954
955     GrNamedArgument namedArgument = ((GrNamedArgumentsOwner)parent).findNamedArgument(argumentName);
956     if (namedArgument == null) return null;
957
958     return namedArgument.getExpression();
959   }
960
961   @NotNull
962   public static PsiClass getOriginalClass(@NotNull PsiClass aClass) {
963     PsiFile file = aClass.getContainingFile();
964     if (file == null) return aClass;
965
966     PsiFile originalFile = file.getOriginalFile();
967     if (originalFile == file) return aClass;
968
969     if (!(originalFile instanceof PsiClassOwner)) return aClass;
970
971     String name = aClass.getName();
972     if (name == null) return aClass;
973
974     for (PsiClass originalClass : ((PsiClassOwner)originalFile).getClasses()) {
975       if (name.equals(originalClass.getName())) {
976         return originalClass;
977       }
978     }
979
980     return aClass;
981   }
982
983
984   private static final String[] visibilityModifiers = new String[]{PsiModifier.PRIVATE, PsiModifier.PROTECTED, PsiModifier.PUBLIC};
985
986   public static void escalateVisibility(PsiMember owner, PsiElement place) {
987     PsiModifierList modifierList = owner.getModifierList();
988     LOG.assertTrue(modifierList != null);
989     final String visibilityModifier = VisibilityUtil.getVisibilityModifier(modifierList);
990     int index;
991     for (index = 0; index < visibilityModifiers.length; index++) {
992       String modifier = visibilityModifiers[index];
993       if (modifier.equals(visibilityModifier)) break;
994     }
995     for (; index < visibilityModifiers.length && !isAccessible(place, owner); index++) {
996       @PsiModifier.ModifierConstant
997       String modifier = visibilityModifiers[index];
998       com.intellij.psi.util.PsiUtil.setModifierProperty(owner, modifier, true);
999     }
1000   }
1001
1002   public static int getArgumentIndex(@NotNull GrCall call, @NotNull PsiElement argument) {
1003     GrArgumentList argumentList = call.getArgumentList();
1004     if (argumentList == null) return -1;
1005
1006     GrExpression[] expressionArguments = argumentList.getExpressionArguments();
1007
1008     for (int i = 0; i < expressionArguments.length; i++) {
1009       if (argument.equals(expressionArguments[i])) {
1010         int res = i;
1011
1012         if (argumentList.getNamedArguments().length > 0) {
1013           res++; // first argument is map defined by named arguments
1014         }
1015
1016         return res;
1017       }
1018     }
1019
1020     if (argument instanceof GrClosableBlock) {
1021       GrClosableBlock[] closureArgs = call.getClosureArguments();
1022
1023       for (int i = 0; i < closureArgs.length; i++) {
1024         if (argument.equals(closureArgs[i])) {
1025           int res = i + expressionArguments.length;
1026
1027           if (argumentList.getNamedArguments().length > 0) {
1028             res++; // first argument is map defined by named arguments
1029           }
1030
1031           return res;
1032         }
1033       }
1034
1035     }
1036
1037     return -1;
1038   }
1039
1040   /**
1041    * Returns all arguments passed to method. First argument is null if Named Arguments is present.
1042    */
1043   public static GrExpression[] getAllArguments(@NotNull GrCall call) {
1044     GrArgumentList argumentList = call.getArgumentList();
1045     if (argumentList == null) return GrExpression.EMPTY_ARRAY;
1046
1047     GrClosableBlock[] closureArguments = call.getClosureArguments();
1048     GrExpression[] expressionArguments = argumentList.getExpressionArguments();
1049     GrNamedArgument[] namedArguments = argumentList.getNamedArguments();
1050
1051     int length = expressionArguments.length + closureArguments.length;
1052     int k = 0;
1053     if (namedArguments.length > 0) {
1054       length++;
1055       k = 1;
1056     }
1057
1058     GrExpression[] res = new GrExpression[length];
1059     for (GrExpression expressionArgument : expressionArguments) {
1060       res[k++] = expressionArgument;
1061     }
1062
1063     for (GrClosableBlock closureArgument : closureArguments) {
1064       res[k++] = closureArgument;
1065     }
1066
1067     return res;
1068   }
1069
1070   public static GrNamedArgument[] getFirstMapNamedArguments(@NotNull GrCall grCall) {
1071     GrNamedArgument[] res = grCall.getNamedArguments();
1072     if (res.length > 0) return res;
1073
1074     GrExpression[] arguments = grCall.getExpressionArguments();
1075     if (arguments.length == 0) return GrNamedArgument.EMPTY_ARRAY;
1076
1077     PsiElement firstArg = arguments[0];
1078
1079     if (!(firstArg instanceof GrListOrMap)) return GrNamedArgument.EMPTY_ARRAY;
1080
1081     return ((GrListOrMap)firstArg).getNamedArguments();
1082   }
1083
1084   public static boolean isExpressionStatement(@Nullable PsiElement expr) {
1085     if (!(expr instanceof GrStatement)) return false;
1086
1087     final PsiElement parent = expr.getParent();
1088     if (parent instanceof GrControlFlowOwner || parent instanceof GrCaseSection) return true;
1089     if (parent instanceof GrLabeledStatement) return true;
1090     if (parent instanceof GrIfStatement &&
1091         (expr == ((GrIfStatement)parent).getThenBranch() || expr == ((GrIfStatement)parent).getElseBranch())) {
1092       return true;
1093     }
1094
1095     if (parent instanceof GrWhileStatement && expr == ((GrWhileStatement)parent).getBody()) {
1096       return true;
1097     }
1098     return false;
1099   }
1100
1101   @Nullable
1102   public static GrMethodCall getMethodCallByNamedParameter(GrNamedArgument namedArgument) {
1103     GrCall res = getCallByNamedParameter(namedArgument);
1104     if (res instanceof GrMethodCall) return (GrMethodCall)res;
1105
1106     return null;
1107   }
1108
1109   @Nullable
1110   public static GrCall getCallByNamedParameter(GrNamedArgument namedArgument) {
1111     PsiElement parent = namedArgument.getParent();
1112
1113     PsiElement eMethodCall;
1114
1115     if (parent instanceof GrArgumentList) {
1116       eMethodCall = parent.getParent();
1117     }
1118     else {
1119       if (!(parent instanceof GrListOrMap)) return null;
1120
1121       PsiElement eArgumentList = parent.getParent();
1122       if (!(eArgumentList instanceof GrArgumentList)) return null;
1123
1124       GrArgumentList argumentList = (GrArgumentList)eArgumentList;
1125
1126       if (argumentList.getNamedArguments().length > 0) return null;
1127       if (argumentList.getExpressionArgumentIndex((GrListOrMap)parent) != 0) return null;
1128
1129       eMethodCall = eArgumentList.getParent();
1130     }
1131
1132     if (!(eMethodCall instanceof GrCall)) return null;
1133
1134     return (GrCall)eMethodCall;
1135   }
1136
1137   public static String getAnnoAttributeValue(@NotNull PsiAnnotation annotation, final String attributeName, String defaultValue) {
1138     PsiAnnotationMemberValue value = annotation.findAttributeValue(attributeName);
1139     if (value instanceof GrExpression) {
1140       Object o = GroovyConstantExpressionEvaluator.evaluate((GrExpression)value);
1141       if (o instanceof String) {
1142         return (String)o;
1143       }
1144     }
1145     return defaultValue;
1146   }
1147
1148   public static boolean getAnnoAttributeValue(@NotNull PsiAnnotation annotation, final String attributeName, boolean defaultValue) {
1149     PsiAnnotationMemberValue value = annotation.findAttributeValue(attributeName);
1150     if (value instanceof GrExpression) {
1151       Object o = GroovyConstantExpressionEvaluator.evaluate((GrExpression)value);
1152       if (o instanceof Boolean) {
1153         return (Boolean)o;
1154       }
1155     }
1156     return defaultValue;
1157   }
1158
1159   public static boolean isExpressionUsed(PsiElement expr) {
1160     while (expr.getParent() instanceof GrParenthesizedExpression) expr = expr.getParent();
1161
1162     PsiElement parent = expr.getParent();
1163     if (parent instanceof GrBinaryExpression ||
1164         parent instanceof GrUnaryExpression ||
1165         parent instanceof GrConditionalExpression ||
1166         parent instanceof GrAssignmentExpression ||
1167         parent instanceof GrInstanceOfExpression ||
1168         parent instanceof GrSafeCastExpression ||
1169         parent instanceof GrTupleExpression ||
1170         parent instanceof GrArgumentList ||
1171         parent instanceof GrReturnStatement ||
1172         parent instanceof GrAssertStatement ||
1173         parent instanceof GrThrowStatement ||
1174         parent instanceof GrSwitchStatement ||
1175         parent instanceof GrVariable ||
1176         parent instanceof GrWhileStatement) {
1177       return true;
1178     }
1179
1180     if (parent instanceof GrReferenceExpression) {
1181       if (ResolveUtil.isClassReference(parent)) {
1182         parent = parent.getParent();
1183       }
1184       if (parent instanceof GrReferenceExpression) {
1185         PsiElement resolved = ((GrReferenceExpression)parent).resolve();
1186         if (resolved instanceof PsiMember) {
1187           PsiClass containingClass = ((PsiMember)resolved).getContainingClass();
1188           return containingClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(containingClass.getQualifiedName());
1189         }
1190       }
1191       return true;
1192     }
1193
1194     if (parent instanceof GrTraditionalForClause) {
1195       GrTraditionalForClause forClause = (GrTraditionalForClause)parent;
1196       return expr == forClause.getCondition();
1197     }
1198
1199     return isReturnStatement(expr);
1200   }
1201
1202   public static boolean isReturnStatement(@NotNull PsiElement statement) {
1203     final GrControlFlowOwner controlFlowOwner = ControlFlowUtils.findControlFlowOwner(statement);
1204     if (controlFlowOwner instanceof GrOpenBlock) {
1205       final PsiElement controlFlowOwnerParent = controlFlowOwner.getParent();
1206       if (controlFlowOwnerParent instanceof GrMethod && ((GrMethod)controlFlowOwnerParent).isConstructor()) {
1207         return false;
1208       }
1209       else if (controlFlowOwnerParent instanceof PsiMethod && PsiType.VOID.equals(((PsiMethod)controlFlowOwnerParent).getReturnType())) {
1210         return false;
1211       }
1212     }
1213     //noinspection SuspiciousMethodCalls
1214     return ControlFlowUtils.collectReturns(controlFlowOwner, true).contains(statement);
1215   }
1216
1217   @Nullable
1218   public static PsiClass getContainingNotInnerClass(@Nullable PsiElement element) {
1219     PsiClass domainClass = PsiTreeUtil.getParentOfType(element, PsiClass.class);
1220     if (domainClass == null) return null;
1221
1222     while (true) {
1223       PsiClass c = domainClass.getContainingClass();
1224       if (c == null) return domainClass;
1225       domainClass = c;
1226     }
1227   }
1228
1229   @NotNull
1230   public static ResolveResult getAccessObjectClass(GrExpression expression) {
1231     if (isThisOrSuperRef(expression)) return GroovyResolveResult.EMPTY_RESULT;
1232     PsiType type = expression.getType();
1233     if (type instanceof PsiClassType) {
1234       return ((PsiClassType)type).resolveGenerics();
1235     }
1236     if (type == null && expression instanceof GrReferenceExpression) {
1237       GroovyResolveResult resolveResult = ((GrReferenceExpression)expression).advancedResolve();
1238       if (resolveResult.getElement() instanceof PsiClass) {
1239         return resolveResult;
1240       }
1241     }
1242     return GroovyResolveResult.EMPTY_RESULT;
1243   }
1244
1245   public static boolean isReferenceWithoutQualifier(@Nullable PsiElement element, @NotNull String name) {
1246     if (!(element instanceof GrReferenceExpression)) return false;
1247
1248     GrReferenceExpression ref = (GrReferenceExpression)element;
1249
1250     return !ref.isQualified() && name.equals(ref.getReferenceName());
1251   }
1252
1253   public static boolean isProperty(@NotNull GrField field) {
1254     final PsiClass clazz = field.getContainingClass();
1255     if (clazz == null) return false;
1256     if (clazz.isInterface() && !GrTraitUtil.isTrait(clazz)) return false;
1257     final GrModifierList modifierList = field.getModifierList();
1258     return modifierList == null || !modifierList.hasExplicitVisibilityModifiers();
1259   }
1260
1261   public static boolean isConstructorHasRequiredParameters(@NotNull PsiMethod constructor) {
1262     LOG.assertTrue(constructor.isConstructor());
1263     final PsiParameter[] parameters = constructor.getParameterList().getParameters();
1264     for (PsiParameter parameter : parameters) {
1265       if (!(parameter instanceof GrParameter && ((GrParameter)parameter).isOptional())) return true;
1266     }
1267     return false;
1268   }
1269
1270   public static boolean isInMethodCallContext(PsiElement context) {
1271     return getArgumentsList(context) != null;
1272   }
1273
1274   @NotNull
1275   public static List<GrImportStatement> getValidImportStatements(final GroovyFile file) {
1276     final List<GrImportStatement> oldImports = new ArrayList<GrImportStatement>();
1277     for (GrImportStatement statement : file.getImportStatements()) {
1278       if (!ErrorUtil.containsError(statement)) {
1279         oldImports.add(statement);
1280       }
1281     }
1282     return oldImports;
1283   }
1284
1285   public static boolean isCompileStatic(PsiElement e) {
1286     PsiMember containingMember = PsiTreeUtil.getParentOfType(e, PsiMember.class, false, GrAnnotation.class);
1287     return containingMember != null && GroovyPsiManager.getInstance(containingMember.getProject()).isCompileStatic(containingMember);
1288   }
1289
1290   @Nullable
1291   public static PsiType extractIteratedType(GrForInClause forIn) {
1292     GrExpression iterated = forIn.getIteratedExpression();
1293     if (iterated == null) return null;
1294     return ClosureParameterEnhancer.findTypeForIteration(iterated, forIn);
1295   }
1296
1297   public static boolean isThisReference(@Nullable PsiElement expression) {
1298     return isThisOrSuperRef(expression, GroovyTokenTypes.kTHIS, false);
1299   }
1300
1301   public static boolean isSuperReference(@Nullable PsiElement expression) {
1302     return isThisOrSuperRef(expression, GroovyTokenTypes.kSUPER, true);
1303   }
1304
1305   private static boolean isThisOrSuperRef(PsiElement expression, IElementType token, boolean superClassAccepted) {
1306     if (!(expression instanceof GrReferenceExpression)) return false;
1307     GrReferenceExpression ref = (GrReferenceExpression)expression;
1308
1309     PsiElement nameElement = ref.getReferenceNameElement();
1310     if (nameElement == null) return false;
1311
1312     IElementType type = nameElement.getNode().getElementType();
1313     if (type != token) return false;
1314
1315     GrExpression qualifier = ref.getQualifier();
1316     if (qualifier == null) {
1317       return true;
1318     }
1319     else {
1320       PsiElement resolved = ref.resolve();
1321       if (resolved instanceof PsiClass) {
1322         if (hasEnclosingInstanceInScope(((PsiClass)resolved), ref, superClassAccepted)) return true;
1323         if (superClassAccepted && GrTraitUtil.isTrait((PsiClass)resolved) && scopeClassImplementsTrait(((PsiClass)resolved), ref)) return true;
1324       }
1325       return false;
1326     }
1327   }
1328
1329   public static boolean scopeClassImplementsTrait(@NotNull final PsiClass trait, @NotNull final PsiElement place) {
1330     GrTypeDefinition scopeClass = PsiTreeUtil.getParentOfType(place, GrTypeDefinition.class, true);
1331     return scopeClass != null && ContainerUtil.find(scopeClass.getSuperTypes(), new Condition<PsiClassType>() {
1332       @Override
1333       public boolean value(PsiClassType type) {
1334         return place.getManager().areElementsEquivalent(type.resolve(), trait);
1335       }
1336     }) != null;
1337   }
1338
1339   public static boolean isThisOrSuperRef(@Nullable PsiElement qualifier) {
1340     return qualifier instanceof GrReferenceExpression && (isThisReference(qualifier) || isSuperReference(qualifier));
1341   }
1342
1343   public static boolean isInstanceThisRef(PsiElement qualifier) {
1344     if (isThisReference(qualifier)) {
1345       GrReferenceExpression ref = (GrReferenceExpression)qualifier;
1346
1347       PsiElement resolved = ref.resolve();
1348       if (resolved == null) return false;
1349
1350       return hasEnclosingInstanceInScope((PsiClass)resolved, qualifier, false);
1351     }
1352     return false;
1353   }
1354
1355   public static boolean isLineFeed(@Nullable PsiElement e) {
1356     return e != null &&
1357            PsiImplUtil.isWhiteSpaceOrNls(e) &&
1358            (e.getText().indexOf('\n') >= 0 || e.getText().indexOf('\r') >= 0);
1359   }
1360
1361   public static boolean isSingleBindingVariant(GroovyResolveResult[] candidates) {
1362     return candidates.length == 1 && candidates[0].getElement() instanceof GrBindingVariable;
1363   }
1364
1365   @Nullable
1366   public static GrConstructorInvocation getConstructorInvocation(@NotNull GrMethod constructor) {
1367     assert constructor.isConstructor();
1368
1369     final GrOpenBlock body = constructor.getBlock();
1370     if (body == null) return null;
1371
1372     final GrStatement[] statements = body.getStatements();
1373     if (statements.length > 0 && statements[0] instanceof GrConstructorInvocation) {
1374       return ((GrConstructorInvocation)statements[0]);
1375     }
1376     else {
1377       return null;
1378     }
1379   }
1380
1381   public static boolean isDGMMethod(@Nullable PsiElement element) {
1382     if (!(element instanceof PsiMethod)) return false;
1383
1384     final PsiMethod method = element instanceof GrGdkMethod ? ((GrGdkMethod)element).getStaticMethod() : (PsiMethod)element;
1385     final PsiClass aClass = method.getContainingClass();
1386     if (aClass == null) return false;
1387
1388     final String qname = aClass.getQualifiedName();
1389     return GroovyCommonClassNames.GROOVY_EXTENSION_CLASSES.contains(qname);
1390   }
1391
1392   public static boolean isVoidMethodCall(@Nullable GrExpression expression) {
1393     if (expression instanceof GrMethodCall && PsiType.NULL.equals(expression.getType())) {
1394       final GroovyResolveResult resolveResult = ((GrMethodCall)expression).advancedResolve();
1395       final PsiType[] args = getArgumentTypes(((GrMethodCall)expression).getInvokedExpression(), true);
1396       return PsiType.VOID.equals(ResolveUtil.extractReturnTypeFromCandidate(resolveResult, expression, args));
1397     }
1398
1399     return false;
1400   }
1401
1402   public static boolean isVoidMethod(@NotNull PsiMethod method) {
1403     if (PsiType.VOID.equals(method.getReturnType())) {
1404       return true;
1405     }
1406
1407     if (method instanceof GrMethod && ((GrMethod)method).getReturnTypeElementGroovy() == null) {
1408       GrOpenBlock block = ((GrMethod)method).getBlock();
1409       if (block != null && isBlockReturnVoid(block)) {
1410         return true;
1411       }
1412     }
1413
1414     return false;
1415   }
1416
1417   public static boolean isBlockReturnVoid(@NotNull final GrCodeBlock block) {
1418     return CachedValuesManager.getCachedValue(block, new CachedValueProvider<Boolean>() {
1419       @Nullable
1420       @Override
1421       public Result<Boolean> compute() {
1422         return Result.create(ControlFlowUtils.visitAllExitPoints(block, new ControlFlowUtils.ExitPointVisitor() {
1423           @Override
1424           public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) {
1425             return returnValue == null || !(returnValue instanceof GrLiteral);
1426           }
1427         }), PsiModificationTracker.MODIFICATION_COUNT);
1428       }
1429     });
1430   }
1431
1432   public static boolean checkPsiElementsAreEqual(PsiElement l, PsiElement r) {
1433     if (!l.getText().equals(r.getText())) return false;
1434     if (l.getNode().getElementType() != r.getNode().getElementType()) return false;
1435
1436     final PsiElement[] lChildren = l.getChildren();
1437     final PsiElement[] rChildren = r.getChildren();
1438
1439     if (lChildren.length != rChildren.length) return false;
1440
1441     for (int i = 0; i < rChildren.length; i++) {
1442       if (!checkPsiElementsAreEqual(lChildren[i], rChildren[i])) return false;
1443     }
1444     return true;
1445   }
1446
1447   public static boolean isCall(GrReferenceExpression referenceExpression) {
1448     return referenceExpression.getParent() instanceof GrCall;
1449   }
1450
1451   public static boolean isLocalVariable(@Nullable PsiElement variable) {
1452     return variable instanceof GrVariable && !(variable instanceof GrField || variable instanceof GrParameter);
1453   }
1454
1455   public static boolean isLocalOrParameter(@Nullable PsiElement variable) {
1456     return variable instanceof GrVariable && !(variable instanceof GrField);
1457   }
1458
1459   @Nullable
1460   public static PsiElement getPreviousNonWhitespaceToken(PsiElement e) {
1461     PsiElement next = PsiTreeUtil.prevLeaf(e);
1462     while (next != null && next.getNode().getElementType() == TokenType.WHITE_SPACE) next = PsiTreeUtil.prevLeaf(next);
1463     return next;
1464   }
1465
1466   @Nullable
1467   public static Object getLabelValue(@Nullable GrArgumentLabel label) {
1468     if (label == null) return null;
1469     final PsiElement element = label.getNameElement();
1470     if (element instanceof GrExpression) {
1471       final Object value = JavaPsiFacade.getInstance(label.getProject()).getConstantEvaluationHelper().computeConstantExpression(element);
1472       if (value != null) return value;
1473     }
1474
1475     final IElementType elemType = element.getNode().getElementType();
1476     if (GroovyTokenTypes.mIDENT == elemType || TokenSets.KEYWORDS.contains(elemType)) {
1477       return element.getText();
1478     }
1479
1480     return GrLiteralImpl.getLiteralValue(element);
1481   }
1482 }