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