[groovy] IDEA-207415: Support super constructor call in `pre` attribute
[idea/community.git] / plugins / groovy / groovy-psi / src / org / jetbrains / plugins / groovy / annotator / GroovyAnnotator.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package org.jetbrains.plugins.groovy.annotator;
3
4 import com.intellij.codeInsight.ClassUtil;
5 import com.intellij.codeInsight.generation.OverrideImplementExploreUtil;
6 import com.intellij.codeInsight.intention.IntentionAction;
7 import com.intellij.codeInsight.intention.QuickFixFactory;
8 import com.intellij.codeInspection.ProblemHighlightType;
9 import com.intellij.lang.ASTNode;
10 import com.intellij.lang.annotation.AnnotationBuilder;
11 import com.intellij.lang.annotation.AnnotationHolder;
12 import com.intellij.lang.annotation.HighlightSeverity;
13 import com.intellij.lang.injection.InjectedLanguageManager;
14 import com.intellij.openapi.diagnostic.Logger;
15 import com.intellij.openapi.editor.Document;
16 import com.intellij.openapi.module.Module;
17 import com.intellij.openapi.module.ModuleUtilCore;
18 import com.intellij.openapi.project.IndexNotReadyException;
19 import com.intellij.openapi.util.Condition;
20 import com.intellij.openapi.util.Pair;
21 import com.intellij.openapi.util.TextRange;
22 import com.intellij.openapi.util.text.StringUtil;
23 import com.intellij.psi.*;
24 import com.intellij.psi.impl.ExpressionConverter;
25 import com.intellij.psi.search.GlobalSearchScope;
26 import com.intellij.psi.search.searches.SuperMethodsSearch;
27 import com.intellij.psi.tree.IElementType;
28 import com.intellij.psi.util.*;
29 import com.intellij.util.IncorrectOperationException;
30 import com.intellij.util.ObjectUtils;
31 import com.intellij.util.VisibilityUtil;
32 import com.intellij.util.containers.ContainerUtil;
33 import com.intellij.util.containers.MultiMap;
34 import gnu.trove.THashSet;
35 import org.jetbrains.annotations.Contract;
36 import org.jetbrains.annotations.NotNull;
37 import org.jetbrains.annotations.Nullable;
38 import org.jetbrains.plugins.groovy.GroovyBundle;
39 import org.jetbrains.plugins.groovy.GroovyLanguage;
40 import org.jetbrains.plugins.groovy.annotator.checkers.AnnotationChecker;
41 import org.jetbrains.plugins.groovy.annotator.checkers.CustomAnnotationChecker;
42 import org.jetbrains.plugins.groovy.annotator.intentions.*;
43 import org.jetbrains.plugins.groovy.codeInspection.bugs.GrModifierFix;
44 import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
45 import org.jetbrains.plugins.groovy.highlighter.GroovySyntaxHighlighter;
46 import org.jetbrains.plugins.groovy.lang.documentation.GroovyPresentationUtil;
47 import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocComment;
48 import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocReferenceElement;
49 import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
50 import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
51 import org.jetbrains.plugins.groovy.lang.psi.*;
52 import org.jetbrains.plugins.groovy.lang.psi.api.GrBlockLambdaBody;
53 import org.jetbrains.plugins.groovy.lang.psi.api.GrFunctionalExpression;
54 import org.jetbrains.plugins.groovy.lang.psi.api.GrLambdaExpression;
55 import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
56 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
57 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier;
58 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
59 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.*;
60 import org.jetbrains.plugins.groovy.lang.psi.api.statements.*;
61 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
62 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
63 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
64 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
65 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
66 import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrBreakStatement;
67 import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrContinueStatement;
68 import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrFlowInterruptingStatement;
69 import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement;
70 import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrForInClause;
71 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
72 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.*;
73 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty;
74 import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
75 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.*;
76 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.*;
77 import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
78 import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition;
79 import org.jetbrains.plugins.groovy.lang.psi.api.types.*;
80 import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper;
81 import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtil;
82 import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
83 import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.modifiers.GrAnnotationCollector;
84 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
85 import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
86 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
87 import org.jetbrains.plugins.groovy.lang.psi.util.*;
88 import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
89 import org.jetbrains.plugins.groovy.lang.resolve.api.GroovyConstructorReference;
90 import org.jetbrains.plugins.groovy.lang.resolve.ast.GeneratedConstructorCollector;
91 import org.jetbrains.plugins.groovy.lang.resolve.ast.InheritConstructorContributor;
92 import org.jetbrains.plugins.groovy.lang.resolve.ast.contributor.SyntheticKeywordConstructorContributor;
93 import org.jetbrains.plugins.groovy.transformations.immutable.GrImmutableUtils;
94
95 import java.util.*;
96
97 import static com.intellij.psi.util.PsiTreeUtil.findChildOfType;
98 import static org.jetbrains.plugins.groovy.annotator.ImplKt.checkInnerClassReferenceFromInstanceContext;
99 import static org.jetbrains.plugins.groovy.annotator.ImplKt.checkUnresolvedCodeReference;
100 import static org.jetbrains.plugins.groovy.annotator.StringInjectionKt.getLineFeed;
101 import static org.jetbrains.plugins.groovy.annotator.UtilKt.*;
102 import static org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GroovyUnresolvedAccessChecker.checkUnresolvedReference;
103 import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.isInStaticCompilationContext;
104 import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtilKt.mayContainTypeArguments;
105 import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.findScriptField;
106 import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.isFieldDeclaration;
107
108 /**
109  * @author ven
110  */
111 public class GroovyAnnotator extends GroovyElementVisitor {
112   private static final Logger LOG = Logger.getInstance(GroovyAnnotator.class);
113
114   public static final Condition<PsiClass> IS_INTERFACE = aClass -> aClass.isInterface();
115   private static final Condition<PsiClass> IS_NOT_INTERFACE = aClass -> !aClass.isInterface();
116   public static final Condition<PsiClass> IS_TRAIT = aClass -> GrTraitUtil.isTrait(aClass);
117
118   private final AnnotationHolder myHolder;
119
120   public GroovyAnnotator(@NotNull AnnotationHolder holder) {
121     myHolder = holder;
122   }
123
124   @Override
125   public void visitTypeArgumentList(@NotNull GrTypeArgumentList typeArgumentList) {
126     PsiElement parent = typeArgumentList.getParent();
127     if (!(parent instanceof GrReferenceElement)) return;
128
129     if (parent instanceof GrCodeReferenceElement && !mayContainTypeArguments((GrCodeReferenceElement)parent)) {
130       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("type.argument.list.is.not.allowed.here")).create();
131       return;
132     }
133
134     final GroovyResolveResult resolveResult = ((GrReferenceElement)parent).advancedResolve();
135     final PsiElement resolved = resolveResult.getElement();
136     final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
137
138     if (resolved == null) return;
139
140     if (!(resolved instanceof PsiTypeParameterListOwner)) {
141       myHolder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle.message("type.argument.list.is.not.allowed.here")).create();
142       return;
143     }
144
145     if (typeArgumentList.isDiamond()) return;
146
147     final PsiTypeParameter[] parameters = ((PsiTypeParameterListOwner)resolved).getTypeParameters();
148     final GrTypeElement[] arguments = typeArgumentList.getTypeArgumentElements();
149
150     if (arguments.length != parameters.length) {
151       myHolder.newAnnotation(HighlightSeverity.WARNING,
152                                        GroovyBundle.message("wrong.number.of.type.arguments", arguments.length, parameters.length)).create();
153       return;
154     }
155
156     for (int i = 0; i < parameters.length; i++) {
157       PsiTypeParameter parameter = parameters[i];
158       final PsiClassType[] superTypes = parameter.getExtendsListTypes();
159       final PsiType argType = arguments[i].getType();
160       for (PsiClassType superType : superTypes) {
161         final PsiType substitutedSuper = substitutor.substitute(superType);
162         if (substitutedSuper != null && !substitutedSuper.isAssignableFrom(argType)) {
163           myHolder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle
164             .message("type.argument.0.is.not.in.its.bound.should.extend.1", argType.getCanonicalText(), superType.getCanonicalText())).range(arguments[i]).create();
165           break;
166         }
167       }
168     }
169   }
170
171   @Override
172   public void visitNamedArgument(@NotNull GrNamedArgument argument) {
173     PsiElement parent = argument.getParent();
174     if (parent instanceof GrArgumentList) {
175       final PsiElement pParent = parent.getParent();
176       if (pParent instanceof GrIndexProperty) {
177         myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("named.arguments.are.not.allowed.inside.index.operations")).create();
178       }
179     }
180   }
181
182   @Override
183   public void visitElement(@NotNull GroovyPsiElement element) {
184     if (element.getParent() instanceof GrDocReferenceElement) {
185       checkGrDocReferenceElement(myHolder, element);
186     }
187   }
188
189   @Override
190   public void visitTryStatement(@NotNull GrTryCatchStatement statement) {
191     final GrCatchClause[] clauses = statement.getCatchClauses();
192
193     if (statement.getResourceList() == null && clauses.length == 0 && statement.getFinallyClause() == null) {
194       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("try.without.catch.finally")).range(statement.getFirstChild()).create();
195       return;
196     }
197
198     List<PsiType> usedExceptions = new ArrayList<>();
199
200     for (GrCatchClause clause : clauses) {
201       final GrParameter parameter = clause.getParameter();
202       if (parameter == null) continue;
203
204       final GrTypeElement typeElement = parameter.getTypeElementGroovy();
205       PsiType type = typeElement != null ? typeElement.getType() : TypesUtil.createType(CommonClassNames.JAVA_LANG_EXCEPTION, statement);
206
207       if (typeElement instanceof GrDisjunctionTypeElement) {
208         final GrTypeElement[] elements = ((GrDisjunctionTypeElement)typeElement).getTypeElements();
209         final PsiType[] types = ContainerUtil.map2Array(elements, PsiType.class, GrTypeElement::getType);
210
211         List<PsiType> usedInsideDisjunction = new ArrayList<>();
212         for (int i = 0; i < types.length; i++) {
213           if (checkExceptionUsed(usedExceptions, parameter, elements[i], types[i])) {
214             usedInsideDisjunction.add(types[i]);
215             for (int j = 0; j < types.length; j++) {
216               if (i != j && types[j].isAssignableFrom(types[i])) {
217                 myHolder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle.message("unnecessary.type", types[i].getCanonicalText(),
218                                                                                    types[j].getCanonicalText())).range(elements[i])
219                   .withFix(new GrRemoveExceptionFix(true)).create();
220               }
221             }
222           }
223         }
224
225         usedExceptions.addAll(usedInsideDisjunction);
226       }
227       else {
228         if (checkExceptionUsed(usedExceptions, parameter, typeElement, type)) {
229           usedExceptions.add(type);
230         }
231       }
232     }
233   }
234
235   @Override
236   public void visitCatchClause(@NotNull GrCatchClause clause) {
237     final GrParameter parameter = clause.getParameter();
238     if (parameter == null) return;
239
240     final GrTypeElement typeElement = parameter.getTypeElementGroovy();
241     if (typeElement != null) {
242       final PsiType type = typeElement.getType();
243       if (type instanceof PsiClassType && ((PsiClassType)type).resolve() == null) return; //don't highlight unresolved types
244       final PsiClassType throwable = TypesUtil.createType(CommonClassNames.JAVA_LANG_THROWABLE, clause);
245       if (!throwable.isAssignableFrom(type)) {
246         myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("catch.statement.parameter.type.should.be.a.subclass.of.throwable")).range(typeElement).create();
247       }
248     }
249   }
250
251   @Override
252   public void visitDocComment(@NotNull GrDocComment comment) {
253     String text = comment.getText();
254     if (!text.endsWith("*/")) {
255       TextRange range = comment.getTextRange();
256       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("doc.end.expected")).range(new TextRange(range.getEndOffset() - 1, range.getEndOffset())).create();
257     }
258   }
259
260   @Override
261   public void visitVariableDeclaration(@NotNull GrVariableDeclaration variableDeclaration) {
262     checkDuplicateModifiers(myHolder, variableDeclaration.getModifierList(), null);
263     if (variableDeclaration.isTuple()) {
264       final GrModifierList list = variableDeclaration.getModifierList();
265
266       final PsiElement last = PsiUtil.skipWhitespacesAndComments(list.getLastChild(), false);
267       if (last != null) {
268         final IElementType type = last.getNode().getElementType();
269         if (type != GroovyTokenTypes.kDEF) {
270           myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("tuple.declaration.should.end.with.def.modifier")).range(list).create();
271         }
272       }
273       else {
274         myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("tuple.declaration.should.end.with.def.modifier")).range(list).create();
275       }
276     }
277     else {
278       GrTypeParameterList typeParameterList = findChildOfType(variableDeclaration, GrTypeParameterList.class);
279       if (typeParameterList != null) {
280         myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("type.parameters.are.unexpected")).range(typeParameterList).create();
281       }
282     }
283   }
284
285   private boolean checkExceptionUsed(List<PsiType> usedExceptions, GrParameter parameter, GrTypeElement typeElement, PsiType type) {
286     for (PsiType exception : usedExceptions) {
287       if (exception.isAssignableFrom(type)) {
288         myHolder.newAnnotation(HighlightSeverity.WARNING,
289                                          GroovyBundle.message("exception.0.has.already.been.caught", type.getCanonicalText()))
290           .range(typeElement != null ? typeElement : parameter.getNameIdentifierGroovy())
291           .withFix(new GrRemoveExceptionFix(parameter.getTypeElementGroovy() instanceof GrDisjunctionTypeElement)).create();
292         return false;
293       }
294     }
295     return true;
296   }
297
298   @Override
299   public void visitReferenceExpression(@NotNull final GrReferenceExpression referenceExpression) {
300     checkStringNameIdentifier(referenceExpression);
301     checkThisOrSuperReferenceExpression(referenceExpression, myHolder);
302     checkFinalFieldAccess(referenceExpression);
303     checkFinalParameterAccess(referenceExpression);
304
305     if (ResolveUtil.isKeyOfMap(referenceExpression)) {
306       PsiElement nameElement = referenceExpression.getReferenceNameElement();
307       LOG.assertTrue(nameElement != null);
308       myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(nameElement).textAttributes(GroovySyntaxHighlighter.MAP_KEY).create();
309     }
310     else if (ResolveUtil.isClassReference(referenceExpression)) {
311       PsiElement nameElement = referenceExpression.getReferenceNameElement();
312       LOG.assertTrue(nameElement != null);
313       myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(nameElement).textAttributes(GroovySyntaxHighlighter.KEYWORD).create();
314     }
315     else if (isInStaticCompilationContext(referenceExpression)) {
316       checkUnresolvedReference(referenceExpression, true, true, new UnresolvedReferenceAnnotatorSink(myHolder));
317     }
318   }
319
320   private void checkFinalParameterAccess(GrReferenceExpression ref) {
321     final PsiElement resolved = ref.resolve();
322
323     if (resolved instanceof GrParameter) {
324       final GrParameter parameter = (GrParameter)resolved;
325       if (parameter.isPhysical() && parameter.hasModifierProperty(PsiModifier.FINAL) && PsiUtil.isLValue(ref)) {
326         if (parameter.getDeclarationScope() instanceof PsiMethod) {
327           myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cannot.assign.a.value.to.final.parameter.0", parameter.getName())).create();
328         }
329       }
330     }
331   }
332
333   private void checkFinalFieldAccess(@NotNull GrReferenceExpression ref) {
334     final PsiElement resolved = ref.resolve();
335
336     if (resolved instanceof GrField && resolved.isPhysical() && ((GrField)resolved).hasModifierProperty(PsiModifier.FINAL) && PsiUtil.isLValue(ref)) {
337       final GrField field = (GrField)resolved;
338
339       final PsiClass containingClass = field.getContainingClass();
340       if (containingClass != null && PsiTreeUtil.isAncestor(containingClass, ref, true)) {
341         GrMember container = GrHighlightUtil.findClassMemberContainer(ref, containingClass);
342
343         if (field.hasModifierProperty(PsiModifier.STATIC)) {
344           if (container instanceof GrClassInitializer && ((GrClassInitializer)container).isStatic()) {
345             return;
346           }
347         }
348         else {
349           if (container instanceof GrMethod && ((GrMethod)container).isConstructor() ||
350               container instanceof GrClassInitializer && !((GrClassInitializer)container).isStatic()) {
351             return;
352           }
353         }
354
355         myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cannot.assign.a.value.to.final.field.0", field.getName())).create();
356       }
357     }
358   }
359
360   private void checkStringNameIdentifier(GrReferenceExpression ref) {
361     final PsiElement nameElement = ref.getReferenceNameElement();
362     if (nameElement == null) return;
363
364     final IElementType elementType = nameElement.getNode().getElementType();
365     if (GroovyTokenSets.STRING_LITERALS.contains(elementType)) {
366       checkStringLiteral(nameElement);
367     }
368     else if (elementType == GroovyTokenTypes.mREGEX_LITERAL || elementType == GroovyTokenTypes.mDOLLAR_SLASH_REGEX_LITERAL) {
369       checkRegexLiteral(nameElement);
370     }
371   }
372
373   @Override
374   public void visitTypeDefinition(@NotNull GrTypeDefinition typeDefinition) {
375     final PsiElement parent = typeDefinition.getParent();
376     if (!(typeDefinition.isAnonymous() ||
377           parent instanceof GrTypeDefinitionBody ||
378           parent instanceof GroovyFile ||
379           typeDefinition instanceof GrTypeParameter)) {
380       final TextRange range = GrHighlightUtil.getClassHeaderTextRange(typeDefinition);
381
382         myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("class.definition.is.not.expected.here")).range(range)
383       .withFix(new GrMoveClassToCorrectPlaceFix(typeDefinition)).create();
384     }
385     checkTypeDefinition(myHolder, typeDefinition);
386
387     checkImplementedMethodsOfClass(myHolder, typeDefinition);
388     checkConstructors(myHolder, typeDefinition);
389
390     checkAnnotationCollector(myHolder, typeDefinition);
391
392     checkSameNameMethodsWithDifferentAccessModifiers(myHolder, typeDefinition.getCodeMethods());
393     checkInheritorOfSelfTypes(myHolder, typeDefinition);
394   }
395
396   private static void checkInheritorOfSelfTypes(AnnotationHolder holder, GrTypeDefinition definition) {
397     if (!(definition instanceof GrClassDefinition)) return;
398     List<PsiClass> selfTypeClasses = GrTraitUtil.getSelfTypeClasses(definition);
399     for (PsiClass selfClass : selfTypeClasses) {
400       if (InheritanceUtil.isInheritorOrSelf(definition, selfClass, true)) continue;
401       String message = GroovyBundle.message("selfType.class.does.not.inherit", definition.getQualifiedName(), selfClass.getQualifiedName());
402       holder.newAnnotation(HighlightSeverity.ERROR, message).range(GrHighlightUtil.getClassHeaderTextRange(definition)).create();
403       break;
404     }
405   }
406
407   private static void checkSameNameMethodsWithDifferentAccessModifiers(AnnotationHolder holder, GrMethod[] methods) {
408     MultiMap<String, GrMethod> map = MultiMap.create();
409     for (GrMethod method : methods) {
410       if (!method.isConstructor()) {
411         map.putValue(method.getName(), method);
412       }
413     }
414
415     for (Map.Entry<String, Collection<GrMethod>> entry : map.entrySet()) {
416       Collection<GrMethod> collection = entry.getValue();
417       if (collection.size() > 1 && !sameAccessModifier(collection)) {
418         for (GrMethod method : collection) {
419           holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("mixing.private.and.public.protected.methods.of.the.same.name")).range(GrHighlightUtil.getMethodHeaderTextRange(method)).create();
420         }
421       }
422     }
423   }
424
425   private static boolean sameAccessModifier(Collection<GrMethod> collection) {
426     Iterator<GrMethod> iterator = collection.iterator();
427     GrMethod method = iterator.next();
428     boolean  privateAccess = PsiModifier.PRIVATE.equals(VisibilityUtil.getVisibilityModifier(method.getModifierList()));
429
430     while (iterator.hasNext()) {
431       GrMethod next = iterator.next();
432       if (privateAccess != PsiModifier.PRIVATE.equals(VisibilityUtil.getVisibilityModifier(next.getModifierList()))) {
433         return false;
434       }
435     }
436
437     return true;
438   }
439
440   private static void checkAnnotationCollector(AnnotationHolder holder, GrTypeDefinition definition) {
441     if (definition.isAnnotationType() &&
442         GrAnnotationCollector.findAnnotationCollector(definition) != null &&
443         definition.getCodeMethods().length > 0) {
444       holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.collector.cannot.have.attributes")).range(definition.getNameIdentifierGroovy()).create();
445     }
446   }
447
448   private static void checkConstructors(@NotNull AnnotationHolder holder, @NotNull GrTypeDefinition typeDefinition) {
449     if (typeDefinition.isEnum() || typeDefinition.isInterface() || typeDefinition.isAnonymous() || typeDefinition instanceof GrTypeParameter) return;
450     final PsiClass superClass = typeDefinition.getSuperClass();
451     if (superClass == null) return;
452
453     if (InheritConstructorContributor.hasInheritConstructorsAnnotation(typeDefinition)) return;
454
455     final PsiMethod[] constructors = typeDefinition.getCodeConstructors();
456     checkDefaultConstructors(holder, typeDefinition, superClass, constructors);
457     checkRecursiveConstructors(holder, constructors);
458   }
459
460   private static void checkDefaultConstructors(@NotNull AnnotationHolder holder,
461                                                @NotNull GrTypeDefinition typeDefinition,
462                                                @NotNull PsiClass superClass,
463                                                PsiMethod @NotNull[] constructors) {
464     PsiMethod defConstructor = getDefaultConstructor(superClass);
465     boolean needExplicitSuperCall = superClass.getConstructors().length != 0 && (defConstructor == null || !PsiUtil.isAccessible(typeDefinition, defConstructor));
466     if (!needExplicitSuperCall) return;
467     final String qName = superClass.getQualifiedName();
468
469     if (typeDefinition.getConstructors().length == 0) {
470       final TextRange range = GrHighlightUtil.getClassHeaderTextRange(typeDefinition);
471       holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("there.is.no.default.constructor.available.in.class.0", qName))
472         .range(range)
473         .withFix(QuickFixFactory.getInstance().createCreateConstructorMatchingSuperFix(typeDefinition)).create();
474     }
475
476     for (PsiMethod method : constructors) {
477       if (method instanceof GrMethod) {
478         final GrOpenBlock block = ((GrMethod)method).getBlock();
479         if (block == null) continue;
480         final GrStatement[] statements = block.getStatements();
481         if (statements.length > 0) {
482           if (statements[0] instanceof GrConstructorInvocation) continue;
483         }
484         holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("there.is.no.default.constructor.available.in.class.0", qName))
485           .range(GrHighlightUtil.getMethodHeaderTextRange(method)).create();
486       }
487     }
488
489     PsiAnnotation anno = typeDefinition.getAnnotation(GroovyCommonClassNames.GROOVY_TRANSFORM_TUPLE_CONSTRUCTOR);
490     if (anno == null) return;
491     GrClosableBlock block = GrAnnotationUtil.inferClosureAttribute(anno, "pre");
492     if (block == null) return;
493     GrStatement[] statements = block.getStatements();
494     if (!(statements.length != 0 &&
495           statements[0] instanceof GrMethodCall &&
496           SyntheticKeywordConstructorContributor.isSyntheticConstructorCall((GrMethodCall)statements[0]))) {
497       holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("there.is.no.default.constructor.available.in.class.0", qName))
498         .range(block).create();
499     }
500   }
501
502   @Override
503   public void visitEnumConstant(@NotNull GrEnumConstant enumConstant) {
504     super.visitEnumConstant(enumConstant);
505     final GrArgumentList argumentList = enumConstant.getArgumentList();
506
507     if (argumentList != null && PsiImplUtil.hasNamedArguments(argumentList) && !PsiImplUtil.hasExpressionArguments(argumentList)) {
508       final PsiMethod constructor = enumConstant.resolveConstructor();
509       if (constructor != null) {
510         if (!PsiUtil.isConstructorHasRequiredParameters(constructor)) {
511           myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle
512             .message("the.usage.of.a.map.entry.expression.to.initialize.an.enum.is.currently.not.supported")).range(argumentList).create();
513         }
514       }
515     }
516   }
517
518   private static void checkRecursiveConstructors(AnnotationHolder holder, PsiMethod[] constructors) {
519     Map<PsiMethod, PsiMethod> nodes = new HashMap<>(constructors.length);
520
521     Set<PsiMethod> set = ContainerUtil.set(constructors);
522
523     for (PsiMethod constructor : constructors) {
524       if (!(constructor instanceof GrMethod)) continue;
525
526       final GrOpenBlock block = ((GrMethod)constructor).getBlock();
527       if (block == null) continue;
528
529       final GrStatement[] statements = block.getStatements();
530       if (statements.length <= 0 || !(statements[0] instanceof GrConstructorInvocation)) continue;
531
532       final PsiMethod resolved = ((GrConstructorInvocation)statements[0]).resolveMethod();
533       if (!set.contains(resolved)) continue;
534
535       nodes.put(constructor, resolved);
536     }
537
538     Set<PsiMethod> checked = new HashSet<>();
539
540     Set<PsiMethod> current;
541     for (PsiMethod constructor : constructors) {
542       if (!checked.add(constructor)) continue;
543
544       current = new HashSet<>();
545       current.add(constructor);
546       for (constructor = nodes.get(constructor); constructor != null && current.add(constructor); constructor = nodes.get(constructor)) {
547         checked.add(constructor);
548       }
549
550       if (constructor != null) {
551         PsiMethod circleStart = constructor;
552         do {
553           holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("recursive.constructor.invocation")).range(GrHighlightUtil.getMethodHeaderTextRange(constructor)).create();
554           constructor = nodes.get(constructor);
555         }
556         while (constructor != circleStart);
557       }
558     }
559   }
560
561   @Override
562   public void visitUnaryExpression(@NotNull GrUnaryExpression expression) {
563     if (expression.getOperationTokenType() == GroovyTokenTypes.mINC ||
564         expression.getOperationTokenType() == GroovyTokenTypes.mDEC) {
565       GrExpression operand = expression.getOperand();
566       if (operand instanceof GrReferenceExpression && ((GrReferenceExpression)operand).getQualifier() == null) {
567         GrTraitTypeDefinition trait = PsiTreeUtil.getParentOfType(operand, GrTraitTypeDefinition.class);
568         if (trait != null) {
569           PsiElement resolved = ((GrReferenceExpression)operand).resolve();
570           if (resolved instanceof GrField && ((GrField)resolved).getContainingClass() instanceof GrTraitTypeDefinition) {
571             myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle
572               .message("0.expressions.on.trait.fields.properties.are.not.supported.in.traits", expression.getOperationToken().getText())).create();
573           }
574         }
575       }
576     }
577   }
578
579   @Override
580   public void visitOpenBlock(@NotNull GrOpenBlock block) {
581     PsiElement blockParent = block.getParent();
582     if (blockParent instanceof GrMethod) {
583       final GrMethod method = (GrMethod)blockParent;
584       if (GrTraitUtil.isMethodAbstract(method)) {
585         String message = GroovyBundle.message("abstract.methods.must.not.have.body");
586         AnnotationBuilder builder =
587           myHolder.newAnnotation(HighlightSeverity.ERROR, message);
588         registerMakeAbstractMethodNotAbstractFix(builder, method, true, message, block.getTextRange()).create();
589       }
590     }
591   }
592
593   @Override
594   public void visitField(@NotNull GrField field) {
595     super.visitField(field);
596     if (field.getTypeElementGroovy() == null && field.getContainingClass() instanceof GrAnnotationTypeDefinition) {
597       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.field.should.have.type.declaration")).range(field.getNameIdentifierGroovy()).create();
598     }
599     checkInitializer(field);
600   }
601
602   private void checkInitializer(@NotNull GrField field) {
603     PsiExpression initializer = field.getInitializer();
604     if (initializer == null) return;
605     PsiClass containingClass = field.getContainingClass();
606     if (containingClass == null) return;
607     PsiAnnotation tupleConstructor = containingClass.getAnnotation(GroovyCommonClassNames.GROOVY_TRANSFORM_TUPLE_CONSTRUCTOR);
608     if (tupleConstructor == null) return;
609     if (!Boolean.FALSE.equals(GrAnnotationUtil.inferBooleanAttribute(tupleConstructor, "defaults"))) return;
610     List<String> excludes = GeneratedConstructorCollector.getIdentifierList(tupleConstructor, "excludes");
611     List<String> includes = GeneratedConstructorCollector.getIdentifierList(tupleConstructor, "includes");
612     if ((excludes != null && !excludes.contains(field.getName())) || (includes != null && includes.contains(field.getName()))) {
613       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("initializers.are.forbidden.with.defaults"))
614         .range(initializer)
615         .create();
616     }
617   }
618
619   @Override
620   public void visitMethod(@NotNull GrMethod method) {
621     checkDuplicateMethod(method);
622     checkMethodWithTypeParamsShouldHaveReturnType(myHolder, method);
623     checkInnerMethod(myHolder, method);
624     checkOptionalParametersInAbstractMethod(myHolder, method);
625
626     checkConstructorOfImmutableClass(myHolder, method);
627     checkGetterOfImmutable(myHolder, method);
628
629     final PsiElement nameIdentifier = method.getNameIdentifierGroovy();
630     if (GroovyTokenSets.STRING_LITERALS.contains(nameIdentifier.getNode().getElementType())) {
631       checkStringLiteral(nameIdentifier);
632     }
633
634     GrOpenBlock block = method.getBlock();
635     if (block != null && TypeInferenceHelper.isTooComplexTooAnalyze(block)) {
636       myHolder.newAnnotation(HighlightSeverity.WEAK_WARNING, GroovyBundle.message("method.0.is.too.complex.too.analyze", method.getName())).range(nameIdentifier).create();
637     }
638
639     final PsiClass containingClass = method.getContainingClass();
640     if (method.isConstructor()) {
641       if (containingClass instanceof GrAnonymousClassDefinition) {
642         myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("constructors.are.not.allowed.in.anonymous.class")).range(nameIdentifier).create();
643       }
644       else if (containingClass != null && containingClass.isInterface()) {
645         myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("constructors.are.not.allowed.in.interface")).range(nameIdentifier).create();
646       }
647     }
648
649     if (method.getBlock() == null && !method.hasModifierProperty(PsiModifier.NATIVE) && !GrTraitUtil.isMethodAbstract(method)) {
650       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("not.abstract.method.should.have.body")).range(nameIdentifier).create();
651     }
652
653     checkOverridingMethod(myHolder, method);
654   }
655
656   private static void checkGetterOfImmutable(AnnotationHolder holder, GrMethod method) {
657     if (!GroovyPropertyUtils.isSimplePropertyGetter(method)) return;
658
659     PsiClass aClass = method.getContainingClass();
660     if (aClass == null) return;
661
662     if (!GrImmutableUtils.hasImmutableAnnotation(aClass)) return;
663
664     PsiField field = GroovyPropertyUtils.findFieldForAccessor(method, false);
665     if (!(field instanceof GrField)) return;
666
667     GrModifierList fieldModifierList = ((GrField)field).getModifierList();
668     if (fieldModifierList == null) return;
669
670     if (fieldModifierList.hasExplicitVisibilityModifiers()) return;
671
672     holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("repetitive.method.name.0", method.getName())).range(method.getNameIdentifierGroovy()).create();
673   }
674
675   private static void checkConstructorOfImmutableClass(AnnotationHolder holder, GrMethod method) {
676     if (!method.isConstructor()) return;
677
678     PsiClass aClass = method.getContainingClass();
679     if (aClass == null) return;
680
681     if (!GrImmutableUtils.hasImmutableAnnotation(aClass)) return;
682
683     holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("explicit.constructors.are.not.allowed.in.immutable.class")).range(method.getNameIdentifierGroovy()).create();
684   }
685
686   private static void checkOverridingMethod(@NotNull AnnotationHolder holder, @NotNull GrMethod method) {
687     final List<HierarchicalMethodSignature> signatures = method.getHierarchicalMethodSignature().getSuperSignatures();
688
689     for (HierarchicalMethodSignature signature : signatures) {
690       final PsiMethod superMethod = signature.getMethod();
691       if (superMethod.hasModifierProperty(PsiModifier.FINAL)) {
692
693         final String current = GroovyPresentationUtil.getSignaturePresentation(method.getSignature(PsiSubstitutor.EMPTY));
694         final String superPresentation = GroovyPresentationUtil.getSignaturePresentation(signature);
695         final String superQName = getQNameOfMember(superMethod);
696
697         holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("method.0.cannot.override.method.1.in.2.overridden.method.is.final", current, superPresentation, superQName)).range(GrHighlightUtil.getMethodHeaderTextRange(method)).create();
698
699         return;
700       }
701
702       final String currentModifier = VisibilityUtil.getVisibilityModifier(method.getModifierList());
703       final String superModifier = VisibilityUtil.getVisibilityModifier(superMethod.getModifierList());
704
705       if (PsiModifier.PUBLIC.equals(superModifier) && (PsiModifier.PROTECTED.equals(currentModifier) || PsiModifier.PRIVATE
706         .equals(currentModifier)) ||
707           PsiModifier.PROTECTED.equals(superModifier) && PsiModifier.PRIVATE.equals(currentModifier)) {
708         final String currentPresentation = GroovyPresentationUtil.getSignaturePresentation(method.getSignature(PsiSubstitutor.EMPTY));
709         final String superPresentation = GroovyPresentationUtil.getSignaturePresentation(signature);
710         final String superQName = getQNameOfMember(superMethod);
711
712         //noinspection MagicConstant
713         final PsiElement modifier = method.getModifierList().getModifier(currentModifier);
714         holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("method.0.cannot.have.weaker.access.privileges.1.than.2.in.3.4", currentPresentation, currentModifier, superPresentation, superQName, superModifier)).range(modifier != null ? modifier : method.getNameIdentifierGroovy()).create();
715       }
716     }
717   }
718
719   private static void checkMethodWithTypeParamsShouldHaveReturnType(AnnotationHolder holder, GrMethod method) {
720     final PsiTypeParameterList parameterList = method.getTypeParameterList();
721     if (parameterList != null) {
722       final GrTypeElement typeElement = method.getReturnTypeElementGroovy();
723       if (typeElement == null) {
724         final TextRange parameterListTextRange = parameterList.getTextRange();
725         final TextRange range = new TextRange(parameterListTextRange.getEndOffset(), parameterListTextRange.getEndOffset() + 1);
726         holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("method.with.type.parameters.should.have.return.type")).range(range).create();
727       }
728     }
729   }
730
731   private static void checkOptionalParametersInAbstractMethod(AnnotationHolder holder, GrMethod method) {
732     if (!method.hasModifierProperty(PsiModifier.ABSTRACT)) return;
733     if (!(method.getContainingClass() instanceof GrInterfaceDefinition)) return;
734
735     for (GrParameter parameter : method.getParameters()) {
736       GrExpression initializerGroovy = parameter.getInitializerGroovy();
737       if (initializerGroovy != null) {
738         PsiElement assignOperator = parameter.getNameIdentifierGroovy();
739         TextRange textRange =
740           new TextRange(assignOperator.getTextRange().getEndOffset(), initializerGroovy.getTextRange().getEndOffset());
741         holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("default.initializers.are.not.allowed.in.abstract.method")).range(textRange).create();
742       }
743     }
744   }
745
746   @Nullable
747   private static PsiMethod getDefaultConstructor(PsiClass clazz) {
748     final String className = clazz.getName();
749     if (className == null) return null;
750     final PsiMethod[] byName = clazz.findMethodsByName(className, true);
751     if (byName.length == 0) return null;
752     Outer:
753     for (PsiMethod method : byName) {
754       if (method.getParameterList().isEmpty()) return method;
755       if (!(method instanceof GrMethod)) continue;
756       final GrParameter[] parameters = ((GrMethod)method).getParameterList().getParameters();
757
758       for (GrParameter parameter : parameters) {
759         if (!parameter.isOptional()) continue Outer;
760       }
761       return method;
762     }
763     return null;
764   }
765
766
767   @Override
768   public void visitVariable(@NotNull GrVariable variable) {
769     checkName(variable);
770
771     PsiElement parent = variable.getParent();
772     if (parent instanceof GrForInClause) {
773       PsiElement delimiter = ((GrForInClause)parent).getDelimiter();
774       if (delimiter.getNode().getElementType() == GroovyTokenTypes.mCOLON) {
775         GrTypeElement typeElement = variable.getTypeElementGroovy();
776         GrModifierList modifierList = variable.getModifierList();
777         if (modifierList != null && typeElement == null && StringUtil.isEmptyOrSpaces(modifierList.getText())) {
778           myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle
779             .message("java.style.for.each.statement.requires.a.type.declaration")).range(variable.getNameIdentifierGroovy())
780           .withFix(new ReplaceDelimiterFix()).create();
781         }
782       }
783     }
784
785
786     PsiNamedElement duplicate = ResolveUtil.findDuplicate(variable);
787
788
789     if (duplicate instanceof GrVariable &&
790         (variable instanceof GrField || ResolveUtil.isScriptField(variable) || !(duplicate instanceof GrField))) {
791       final String key = duplicate instanceof GrField ? "field.already.defined" : "variable.already.defined";
792       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message(key, variable.getName())).range(variable.getNameIdentifierGroovy()).create();
793     }
794
795     PsiType type = variable.getDeclaredType();
796     if (type instanceof PsiEllipsisType && !isLastParameter(variable)) {
797       TextRange range = getEllipsisRange(variable);
798       if (range == null) {
799         range = getTypeRange(variable);
800       }
801       if (range != null) {
802         myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("ellipsis.type.is.not.allowed.here")).range(range).create();
803       }
804     }
805   }
806
807   @Nullable
808   private static TextRange getEllipsisRange(GrVariable variable) {
809     if (variable instanceof GrParameter) {
810       final PsiElement dots = ((GrParameter)variable).getEllipsisDots();
811       if (dots != null) {
812         return dots.getTextRange();
813       }
814     }
815     return null;
816   }
817
818   @Nullable
819   private static TextRange getTypeRange(GrVariable variable) {
820     GrTypeElement typeElement = variable.getTypeElementGroovy();
821     if (typeElement == null) return null;
822
823     PsiElement sibling = typeElement.getNextSibling();
824     if (sibling != null && sibling.getNode().getElementType() == GroovyTokenTypes.mTRIPLE_DOT) {
825       return new TextRange(typeElement.getTextRange().getStartOffset(), sibling.getTextRange().getEndOffset());
826     }
827
828     return typeElement.getTextRange();
829   }
830
831
832   private static boolean isLastParameter(PsiVariable variable) {
833     if (!(variable instanceof PsiParameter)) return false;
834
835     PsiElement parent = variable.getParent();
836     if (!(parent instanceof PsiParameterList)) return false;
837
838     PsiParameter[] parameters = ((PsiParameterList)parent).getParameters();
839
840     return parameters.length > 0 && parameters[parameters.length - 1] == variable;
841   }
842
843   private void checkName(GrVariable variable) {
844     if (!"$".equals(variable.getName())) return;
845     myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("incorrect.variable.name")).range(variable.getNameIdentifierGroovy()).create();
846   }
847
848   @Override
849   public void visitAssignmentExpression(@NotNull GrAssignmentExpression expression) {
850     GrExpression lValue = expression.getLValue();
851     if (!PsiUtil.mightBeLValue(lValue)) {
852       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("invalid.lvalue")).range(lValue).create();
853     }
854   }
855
856   @Override
857   public void visitReturnStatement(@NotNull GrReturnStatement returnStatement) {
858     final GrExpression value = returnStatement.getReturnValue();
859     if (value != null) {
860       final PsiType type = value.getType();
861       if (type != null) {
862         final GrParameterListOwner owner = PsiTreeUtil.getParentOfType(returnStatement, GrParameterListOwner.class);
863         if (owner instanceof PsiMethod) {
864           final PsiMethod method = (PsiMethod)owner;
865           if (method.isConstructor()) {
866             myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cannot.return.from.constructor")).range(value).create();
867           }
868           else {
869             final PsiType methodType = method.getReturnType();
870             if (methodType != null) {
871               if (PsiType.VOID.equals(methodType)) {
872                 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cannot.return.from.void.method")).range(value).create();
873               }
874             }
875           }
876         }
877       }
878     }
879   }
880
881   @Override
882   public void visitTypeParameterList(@NotNull GrTypeParameterList list) {
883     final PsiElement parent = list.getParent();
884     if (parent instanceof GrMethod && ((GrMethod)parent).isConstructor() ||
885         parent instanceof GrEnumTypeDefinition ||
886         parent instanceof GrAnnotationTypeDefinition) {
887       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("type.parameters.are.unexpected")).create();
888     }
889   }
890
891   @Override
892   public void visitListOrMap(@NotNull GrListOrMap listOrMap) {
893     final GroovyConstructorReference constructorReference = listOrMap.getConstructorReference();
894     if (constructorReference != null) {
895       final PsiElement lBracket = listOrMap.getLBrack();
896       myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(lBracket).textAttributes(GroovySyntaxHighlighter.LITERAL_CONVERSION).create();
897       final PsiElement rBracket = listOrMap.getRBrack();
898       if (rBracket != null) {
899         myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(rBracket).textAttributes(GroovySyntaxHighlighter.LITERAL_CONVERSION).create();
900       }
901     }
902
903     final GrNamedArgument[] namedArguments = listOrMap.getNamedArguments();
904     final GrExpression[] expressionArguments = listOrMap.getInitializers();
905
906     if (namedArguments.length != 0 && expressionArguments.length != 0) {
907       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("collection.literal.contains.named.argument.and.expression.items")).create();
908     }
909
910     checkNamedArgs(namedArguments, false);
911   }
912
913   @Override
914   public void visitClassTypeElement(@NotNull GrClassTypeElement typeElement) {
915     super.visitClassTypeElement(typeElement);
916
917     final GrCodeReferenceElement ref = typeElement.getReferenceElement();
918     final GrTypeArgumentList argList = ref.getTypeArgumentList();
919     if (argList == null) return;
920
921     final GrTypeElement[] elements = argList.getTypeArgumentElements();
922     for (GrTypeElement element : elements) {
923       checkTypeArgForPrimitive(element, GroovyBundle.message("primitive.type.parameters.are.not.allowed"));
924     }
925   }
926
927   @Override
928   public void visitCodeReferenceElement(@NotNull GrCodeReferenceElement refElement) {
929     if (refElement.getParent() instanceof GrAnnotation) {
930       PsiElement resolved = refElement.resolve();
931       if (resolved instanceof PsiClass && !((PsiClass)resolved).isAnnotationType() &&
932           GrAnnotationCollector.findAnnotationCollector((PsiClass)resolved) != null) {
933         myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).textAttributes(GroovySyntaxHighlighter.ANNOTATION).create();
934       }
935     }
936     checkUnresolvedCodeReference(refElement, myHolder);
937     checkInnerClassReferenceFromInstanceContext(refElement, myHolder);
938   }
939
940   @Override
941   public void visitTypeElement(@NotNull GrTypeElement typeElement) {
942     final PsiElement parent = typeElement.getParent();
943     if (!(parent instanceof GrMethod)) return;
944
945     if (parent instanceof GrAnnotationMethod) {
946       checkAnnotationAttributeType(typeElement, myHolder);
947     }
948     else if (((GrMethod)parent).isConstructor()) {
949       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("constructors.cannot.have.return.type")).create();
950     }
951     else {
952       checkMethodReturnType(((GrMethod)parent), typeElement, myHolder);
953     }
954   }
955
956   @Override
957   public void visitArrayTypeElement(@NotNull GrArrayTypeElement typeElement) {
958     GrTypeElement componentTypeElement = typeElement.getComponentTypeElement();
959     PsiType componentType = componentTypeElement.getType();
960     if (PsiType.VOID.equals(componentType)) {
961       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("illegal.type.void")).range(componentTypeElement).create();
962     }
963     else {
964       super.visitArrayTypeElement(typeElement);
965     }
966   }
967
968   @Override
969   public void visitModifierList(@NotNull GrModifierList modifierList) {
970     final PsiElement parent = modifierList.getParent();
971     if (parent instanceof GrMethod) {
972       checkMethodDefinitionModifiers(myHolder, (GrMethod)parent);
973     }
974     else if (parent instanceof GrTypeDefinition) {
975       checkTypeDefinitionModifiers(myHolder, (GrTypeDefinition)parent);
976     }
977     else if (parent instanceof GrVariableDeclaration) {
978       GrVariableDeclaration declaration = (GrVariableDeclaration)parent;
979       if (isFieldDeclaration(declaration)) {
980         checkFieldModifiers(myHolder, declaration);
981       }
982       else {
983         checkVariableModifiers(myHolder, declaration);
984       }
985     }
986     else if (parent instanceof GrClassInitializer) {
987       checkClassInitializerModifiers(myHolder, modifierList);
988     }
989   }
990
991   private static void checkClassInitializerModifiers(AnnotationHolder holder, GrModifierList modifierList) {
992     for (GrAnnotation annotation : modifierList.getAnnotations()) {
993       holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("initializer.cannot.have.annotations")).range(annotation).create();
994     }
995
996     for (@GrModifier.GrModifierConstant String modifier : GrModifier.GROOVY_MODIFIERS) {
997       if (PsiModifier.STATIC.equals(modifier)) continue;
998       checkModifierIsNotAllowed(modifierList, modifier, GroovyBundle.message("initializer.cannot.be.0", modifier), holder);
999     }
1000   }
1001
1002   @Override
1003   public void visitClassInitializer(@NotNull GrClassInitializer initializer) {
1004     final PsiClass aClass = initializer.getContainingClass();
1005     if (GrTraitUtil.isInterface(aClass)) {
1006       final TextRange range = GrHighlightUtil.getInitializerHeaderTextRange(initializer);
1007       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("initializers.are.not.allowed.in.interface")).range(range).create();
1008     }
1009   }
1010
1011   private static void checkFieldModifiers(AnnotationHolder holder, GrVariableDeclaration fieldDeclaration) {
1012     GrVariable[] variables = fieldDeclaration.getVariables();
1013     if (variables.length == 0) return;
1014
1015     GrVariable variable = variables[0];
1016     final GrField member = variable instanceof GrField ? (GrField)variable : findScriptField(variable);
1017     if (member == null) return;
1018
1019     final GrModifierList modifierList = fieldDeclaration.getModifierList();
1020
1021     checkAccessModifiers(holder, modifierList, member);
1022     checkDuplicateModifiers(holder, modifierList, member);
1023
1024     if (modifierList.hasExplicitModifier(PsiModifier.VOLATILE) && modifierList.hasExplicitModifier(PsiModifier.FINAL)) {
1025
1026       String message = GroovyBundle.message("illegal.combination.of.modifiers.volatile.and.final");
1027       AnnotationBuilder builder =
1028         holder.newAnnotation(HighlightSeverity.ERROR, message)
1029           .range(modifierList);
1030       builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.VOLATILE, true, false, GrModifierFix.MODIFIER_LIST), modifierList,
1031                        message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1032       builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.FINAL, true, false, GrModifierFix.MODIFIER_LIST), modifierList,
1033                        message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1034       builder.create();
1035     }
1036
1037     if (member.getContainingClass() instanceof GrInterfaceDefinition) {
1038       checkModifierIsNotAllowed(modifierList,
1039                                 PsiModifier.PRIVATE, GroovyBundle.message("interface.members.are.not.allowed.to.be", PsiModifier.PRIVATE), holder);
1040       checkModifierIsNotAllowed(modifierList, PsiModifier.PROTECTED, GroovyBundle.message("interface.members.are.not.allowed.to.be",
1041                                                                                           PsiModifier.PROTECTED),
1042                                 holder);
1043     }
1044   }
1045
1046   private static void checkAnnotationAttributeType(GrTypeElement element, AnnotationHolder holder) {
1047     if (element instanceof GrBuiltInTypeElement) return;
1048
1049     if (element instanceof GrArrayTypeElement) {
1050       checkAnnotationAttributeType(((GrArrayTypeElement)element).getComponentTypeElement(), holder);
1051       return;
1052     }
1053     else if (element instanceof GrClassTypeElement) {
1054       final PsiElement resolved = ((GrClassTypeElement)element).getReferenceElement().resolve();
1055       if (resolved instanceof PsiClass) {
1056         if (CommonClassNames.JAVA_LANG_STRING.equals(((PsiClass)resolved).getQualifiedName())) return;
1057         if (CommonClassNames.JAVA_LANG_CLASS.equals(((PsiClass)resolved).getQualifiedName())) return;
1058         if (((PsiClass)resolved).isAnnotationType()) return;
1059         if (((PsiClass)resolved).isEnum()) return;
1060       }
1061     }
1062
1063     holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("unexpected.attribute.type.0", element.getType())).range(element).create();
1064   }
1065
1066   static void checkMethodReturnType(PsiMethod method, PsiElement toHighlight, AnnotationHolder holder) {
1067     final HierarchicalMethodSignature signature = method.getHierarchicalMethodSignature();
1068     final List<HierarchicalMethodSignature> superSignatures = signature.getSuperSignatures();
1069
1070     PsiType returnType = signature.getSubstitutor().substitute(method.getReturnType());
1071
1072     for (HierarchicalMethodSignature superMethodSignature : superSignatures) {
1073       PsiMethod superMethod = superMethodSignature.getMethod();
1074       PsiType declaredReturnType = superMethod.getReturnType();
1075       PsiType superReturnType = superMethodSignature.getSubstitutor().substitute(declaredReturnType);
1076       if (PsiType.VOID.equals(superReturnType) && method instanceof GrMethod && ((GrMethod)method).getReturnTypeElementGroovy() == null) return;
1077       if (superMethodSignature.isRaw()) superReturnType = TypeConversionUtil.erasure(declaredReturnType);
1078       if (returnType == null || superReturnType == null || method == superMethod) continue;
1079       PsiClass superClass = superMethod.getContainingClass();
1080       if (superClass == null) continue;
1081       String highlightInfo = checkSuperMethodSignature(superMethod, superMethodSignature, superReturnType, method, signature, returnType);
1082       if (highlightInfo != null) {
1083         holder.newAnnotation(HighlightSeverity.ERROR, highlightInfo).range(toHighlight).create();
1084         return;
1085       }
1086     }
1087   }
1088
1089   @Nullable
1090   private static String checkSuperMethodSignature(@NotNull PsiMethod superMethod,
1091                                                   @NotNull MethodSignatureBackedByPsiMethod superMethodSignature,
1092                                                   @NotNull PsiType superReturnType,
1093                                                   @NotNull PsiMethod method,
1094                                                   @NotNull MethodSignatureBackedByPsiMethod methodSignature,
1095                                                   @NotNull PsiType returnType) {
1096     PsiType substitutedSuperReturnType = substituteSuperReturnType(superMethodSignature, methodSignature, superReturnType);
1097
1098     if (returnType.equals(substitutedSuperReturnType)) return null;
1099
1100     final PsiType rawReturnType = TypeConversionUtil.erasure(returnType);
1101     final PsiType rawSuperReturnType = TypeConversionUtil.erasure(substitutedSuperReturnType);
1102
1103     if (returnType instanceof PsiClassType && substitutedSuperReturnType instanceof PsiClassType) {
1104       if (TypeConversionUtil.isAssignable(rawSuperReturnType, rawReturnType)) {
1105         return null;
1106       }
1107     }
1108     else if (returnType instanceof PsiArrayType && superReturnType instanceof PsiArrayType) {
1109       if (rawReturnType.equals(rawSuperReturnType)) {
1110         return null;
1111       }
1112     }
1113
1114     String qName = getQNameOfMember(method);
1115     String baseQName = getQNameOfMember(superMethod);
1116     final String presentation = returnType.getCanonicalText() + " " + GroovyPresentationUtil.getSignaturePresentation(methodSignature);
1117     final String basePresentation =
1118       superReturnType.getCanonicalText() + " " + GroovyPresentationUtil.getSignaturePresentation(superMethodSignature);
1119     return GroovyBundle.message("return.type.is.incompatible", presentation, qName, basePresentation, baseQName);
1120   }
1121
1122   @NotNull
1123   private static PsiType substituteSuperReturnType(@NotNull MethodSignatureBackedByPsiMethod superMethodSignature,
1124                                                    @NotNull MethodSignatureBackedByPsiMethod methodSignature,
1125                                                    @NotNull PsiType superReturnType) {
1126     PsiType substitutedSuperReturnType;
1127     if (!superMethodSignature.isRaw() && superMethodSignature.equals(methodSignature)) { //see 8.4.5
1128       PsiSubstitutor unifyingSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature,
1129                                                                                                   superMethodSignature);
1130       substitutedSuperReturnType = unifyingSubstitutor == null
1131                                    ? superReturnType
1132                                    : unifyingSubstitutor.substitute(superMethodSignature.getSubstitutor().substitute(superReturnType));
1133     }
1134     else {
1135       substitutedSuperReturnType = TypeConversionUtil.erasure(superReturnType);
1136     }
1137     return substitutedSuperReturnType;
1138   }
1139
1140   @NotNull
1141   private static String getQNameOfMember(@NotNull PsiMember member) {
1142     final PsiClass aClass = member.getContainingClass();
1143     return getQName(aClass);
1144   }
1145
1146   @NotNull
1147   private static String getQName(@Nullable PsiClass aClass) {
1148     if (aClass instanceof PsiAnonymousClass) {
1149       return GroovyBundle.message("anonymous.class.derived.from.0", ((PsiAnonymousClass)aClass).getBaseClassType().getCanonicalText());
1150     }
1151     if (aClass != null) {
1152       final String qname = aClass.getQualifiedName();
1153       if (qname != null) {
1154         return qname;
1155       }
1156     }
1157     return "<null>";
1158   }
1159
1160
1161   private void checkTypeArgForPrimitive(@Nullable GrTypeElement element, @NotNull String message) {
1162     if (element == null || !(element.getType() instanceof PsiPrimitiveType)) return;
1163
1164     AnnotationBuilder builder = myHolder.newAnnotation(HighlightSeverity.ERROR, message).range(element);
1165     builder = registerLocalFix(builder, new GrReplacePrimitiveTypeWithWrapperFix(element), element, message, ProblemHighlightType.ERROR,
1166                      element.getTextRange());
1167     builder.create();
1168   }
1169
1170   @Override
1171   public void visitWildcardTypeArgument(@NotNull GrWildcardTypeArgument wildcardTypeArgument) {
1172     super.visitWildcardTypeArgument(wildcardTypeArgument);
1173
1174     checkTypeArgForPrimitive(wildcardTypeArgument.getBoundTypeElement(), GroovyBundle.message("primitive.bound.types.are.not.allowed"));
1175   }
1176
1177   private void highlightNamedArgs(GrNamedArgument[] namedArguments) {
1178     for (GrNamedArgument namedArgument : namedArguments) {
1179       final GrArgumentLabel label = namedArgument.getLabel();
1180       if (label != null && label.getExpression() == null && label.getNameElement().getNode().getElementType() != GroovyTokenTypes.mSTAR) {
1181         myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(label).textAttributes(GroovySyntaxHighlighter.MAP_KEY).create();
1182       }
1183     }
1184   }
1185
1186   private void checkNamedArgs(GrNamedArgument[] namedArguments, boolean forArgList) {
1187     highlightNamedArgs(namedArguments);
1188
1189     Set<Object> existingKeys = new HashSet<>();
1190     for (GrNamedArgument namedArgument : namedArguments) {
1191       GrArgumentLabel label = namedArgument.getLabel();
1192       Object value = PsiUtil.getLabelValue(label);
1193       if (value == null) continue;
1194       if (value == ObjectUtils.NULL) value = null;
1195       if (existingKeys.add(value)) continue;
1196       if (forArgList) {
1197         myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("duplicated.named.parameter", String.valueOf(value))).range(label).create();
1198       }
1199       else {
1200         myHolder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle.message("duplicate.element.in.the.map", String.valueOf(value))).range(label).create();
1201       }
1202     }
1203   }
1204
1205   @Override
1206   public void visitNewExpression(@NotNull GrNewExpression newExpression) {
1207     GrTypeArgumentList constructorTypeArguments = newExpression.getConstructorTypeArguments();
1208     if (constructorTypeArguments != null) {
1209       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("groovy.does.not.support.constructor.type.arguments")).range(constructorTypeArguments).create();
1210     }
1211
1212     final GrTypeElement typeElement = newExpression.getTypeElement();
1213
1214     if (typeElement instanceof GrBuiltInTypeElement) {
1215       if (newExpression.getArrayCount() == 0) {
1216         myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("create.instance.of.built-in.type")).range(typeElement).create();
1217       }
1218     }
1219
1220     if (newExpression.getArrayCount() > 0) return;
1221
1222     GrCodeReferenceElement refElement = newExpression.getReferenceElement();
1223     if (refElement == null) return;
1224
1225     final PsiElement element = refElement.resolve();
1226     if (element instanceof PsiClass) {
1227       PsiClass clazz = (PsiClass)element;
1228       if (clazz.hasModifierProperty(PsiModifier.ABSTRACT)) {
1229         if (newExpression.getAnonymousClassDefinition() == null) {
1230           String message = clazz.isInterface()
1231                            ? GroovyBundle.message("cannot.instantiate.interface", clazz.getName())
1232                            : GroovyBundle.message("cannot.instantiate.abstract.class", clazz.getName());
1233           myHolder.newAnnotation(HighlightSeverity.ERROR, message).range(refElement).create();
1234         }
1235       }
1236     }
1237   }
1238
1239   @Override
1240   public void visitArgumentList(@NotNull GrArgumentList list) {
1241     checkNamedArgs(list.getNamedArguments(), true);
1242   }
1243
1244   @Override
1245   public void visitBreakStatement(@NotNull GrBreakStatement breakStatement) {
1246     checkFlowInterruptStatement(breakStatement, myHolder);
1247   }
1248
1249   @Override
1250   public void visitContinueStatement(@NotNull GrContinueStatement continueStatement) {
1251     checkFlowInterruptStatement(continueStatement, myHolder);
1252   }
1253
1254   @Override
1255   public void visitPackageDefinition(@NotNull GrPackageDefinition packageDefinition) {
1256     final GrModifierList modifierList = packageDefinition.getAnnotationList();
1257     checkAnnotationList(myHolder, modifierList, GroovyBundle.message("package.definition.cannot.have.modifiers"));
1258   }
1259
1260   @Override
1261   public void visitLambdaExpression(@NotNull GrLambdaExpression expression) {
1262     super.visitLambdaExpression(expression);
1263
1264     PsiElement arrow = expression.getArrow();
1265     myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(arrow).textAttributes(GroovySyntaxHighlighter.LAMBDA_ARROW_AND_BRACES).create();
1266   }
1267
1268   @Override
1269   public void visitBlockLambdaBody(@NotNull GrBlockLambdaBody body) {
1270     super.visitBlockLambdaBody(body);
1271
1272     PsiElement lBrace = body.getLBrace();
1273     if (lBrace != null) {
1274       myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(lBrace).textAttributes(GroovySyntaxHighlighter.LAMBDA_ARROW_AND_BRACES).create();
1275     }
1276
1277     PsiElement rBrace = body.getRBrace();
1278     if (rBrace != null) {
1279       myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(rBrace).textAttributes(GroovySyntaxHighlighter.LAMBDA_ARROW_AND_BRACES).create();
1280     }
1281   }
1282
1283   @Override
1284   public void visitClosure(@NotNull GrClosableBlock closure) {
1285     super.visitClosure(closure);
1286
1287     myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(closure.getLBrace()).textAttributes(GroovySyntaxHighlighter.CLOSURE_ARROW_AND_BRACES).create();
1288     PsiElement rBrace = closure.getRBrace();
1289     if (rBrace != null) {
1290       myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(rBrace).textAttributes(GroovySyntaxHighlighter.CLOSURE_ARROW_AND_BRACES).create();
1291     }
1292     PsiElement closureArrow = closure.getArrow();
1293     if (closureArrow != null) {
1294       myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(closureArrow).textAttributes(GroovySyntaxHighlighter.CLOSURE_ARROW_AND_BRACES).create();
1295     }
1296
1297     if (TypeInferenceHelper.isTooComplexTooAnalyze(closure)) {
1298       int startOffset = closure.getTextRange().getStartOffset();
1299       int endOffset;
1300       PsiElement arrow = closure.getArrow();
1301       if (arrow != null) {
1302         endOffset = arrow.getTextRange().getEndOffset();
1303       }
1304       else {
1305         Document document = PsiDocumentManager.getInstance(closure.getProject()).getDocument(closure.getContainingFile());
1306         if (document == null) return;
1307         String text = document.getText();
1308         endOffset = Math.min(closure.getTextRange().getEndOffset(), text.indexOf('\n', startOffset));
1309       }
1310       myHolder.newAnnotation(HighlightSeverity.WEAK_WARNING, GroovyBundle.message("closure.is.too.complex.to.analyze")).range(new TextRange(startOffset, endOffset)).create();
1311     }
1312   }
1313
1314   @Override
1315   public void visitLiteralExpression(@NotNull GrLiteral literal) {
1316     final IElementType elementType = literal.getFirstChild().getNode().getElementType();
1317     if (GroovyTokenSets.STRING_LITERALS.contains(elementType)) {
1318       checkStringLiteral(literal);
1319     }
1320     else if (elementType == GroovyTokenTypes.mREGEX_LITERAL || elementType == GroovyTokenTypes.mDOLLAR_SLASH_REGEX_LITERAL) {
1321       checkRegexLiteral(literal.getFirstChild());
1322     }
1323   }
1324
1325   @Override
1326   public void visitRegexExpression(@NotNull GrRegex regex) {
1327     checkRegexLiteral(regex);
1328   }
1329
1330   private void checkRegexLiteral(PsiElement regex) {
1331     String[] parts;
1332     if (regex instanceof GrRegex) {
1333       parts = ((GrRegex)regex).getTextParts();
1334     }
1335     else {
1336       parts = new String[]{regex.getFirstChild().getNextSibling().getText()};
1337     }
1338
1339     for (String part : parts) {
1340       if (!GrStringUtil.parseRegexCharacters(part, new StringBuilder(part.length()), null, regex.getText().startsWith("/"))) {
1341         myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("illegal.escape.character.in.string.literal")).range(regex).create();
1342         return;
1343       }
1344     }
1345   }
1346
1347   @Override
1348   public void visitGStringExpression(@NotNull GrString gstring) {
1349     for (GrStringContent part : gstring.getContents()) {
1350       final String text = part.getText();
1351       if (!GrStringUtil.parseStringCharacters(text, new StringBuilder(text.length()), null)) {
1352         myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("illegal.escape.character.in.string.literal")).range(part).create();
1353         return;
1354       }
1355     }
1356
1357   }
1358
1359   @Override
1360   public void visitGStringInjection(@NotNull GrStringInjection injection) {
1361     if (((GrString)injection.getParent()).isPlainString()) {
1362       PsiElement lineFeed = getLineFeed(injection);
1363       if (lineFeed != null) {
1364         myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("injection.should.not.contain.line.feeds"))
1365           .range(lineFeed)
1366           .create();
1367       }
1368     }
1369   }
1370
1371   private void checkStringLiteral(PsiElement literal) {
1372     InjectedLanguageManager injectedLanguageManager = InjectedLanguageManager.getInstance(literal.getProject());
1373     String text;
1374     if (injectedLanguageManager.isInjectedFragment(literal.getContainingFile())) {
1375       text = injectedLanguageManager.getUnescapedText(literal);
1376     }
1377     else {
1378       text = literal.getText();
1379     }
1380     assert text != null;
1381
1382     StringBuilder builder = new StringBuilder(text.length());
1383     String quote = GrStringUtil.getStartQuote(text);
1384     if (quote.isEmpty()) return;
1385
1386     String substring = text.substring(quote.length());
1387     if (!GrStringUtil.parseStringCharacters(substring, new StringBuilder(text.length()), null)) {
1388       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("illegal.escape.character.in.string.literal")).range(literal).create();
1389       return;
1390     }
1391
1392     int[] offsets = new int[substring.length() + 1];
1393     boolean result = GrStringUtil.parseStringCharacters(substring, builder, offsets);
1394     LOG.assertTrue(result);
1395     if (!builder.toString().endsWith(quote) || substring.charAt(offsets[builder.length() - quote.length()]) == '\\') {
1396       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("string.end.expected")).create();
1397     }
1398   }
1399
1400   @Override
1401   public void visitForInClause(@NotNull GrForInClause forInClause) {
1402     final GrVariable var = forInClause.getDeclaredVariable();
1403     if (var == null) return;
1404     final GrModifierList modifierList = var.getModifierList();
1405     if (modifierList == null) return;
1406     final PsiElement[] modifiers = modifierList.getModifiers();
1407     for (PsiElement modifier : modifiers) {
1408       if (modifier instanceof PsiAnnotation) continue;
1409       final String modifierText = modifier.getText();
1410       if (PsiModifier.FINAL.equals(modifierText)) continue;
1411       if (GrModifier.DEF.equals(modifierText)) continue;
1412       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("not.allowed.modifier.in.for.in", modifierText)).range(modifier).create();
1413     }
1414   }
1415
1416   @Override
1417   public void visitFile(@NotNull GroovyFileBase file) {
1418     final PsiClass scriptClass = file.getScriptClass();
1419     if (scriptClass != null) {
1420       checkSameNameMethodsWithDifferentAccessModifiers(myHolder, file.getMethods());
1421     }
1422   }
1423
1424
1425   @Override
1426   public void visitAnnotation(@NotNull GrAnnotation annotation) {
1427     AnnotationChecker.checkApplicability(annotation, annotation.getOwner(), myHolder, annotation.getClassReference());
1428   }
1429
1430   @Override
1431   public void visitAnnotationArgumentList(@NotNull GrAnnotationArgumentList annotationArgumentList) {
1432     GrAnnotation parent = (GrAnnotation)annotationArgumentList.getParent();
1433     Pair<PsiElement, String> r = AnnotationChecker.checkAnnotationArgumentList(parent, myHolder);
1434     if (r != null && r.getFirst() != null && r.getSecond() != null) {
1435       myHolder.newAnnotation(HighlightSeverity.ERROR, r.getSecond()).range(r.getFirst()).create();
1436     }
1437   }
1438
1439   @Override
1440   public void visitAnnotationMethod(@NotNull GrAnnotationMethod annotationMethod) {
1441     super.visitAnnotationMethod(annotationMethod);
1442
1443     final PsiReferenceList list = annotationMethod.getThrowsList();
1444     if (list.getReferencedTypes().length > 0) {
1445       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("throws.clause.is.not.allowed.in.at.interface")).range(list).create();
1446     }
1447
1448     final GrAnnotationMemberValue value = annotationMethod.getDefaultValue();
1449     if (value == null) return;
1450
1451     final PsiType type = annotationMethod.getReturnType();
1452
1453     Pair.NonNull<PsiElement, String> result = CustomAnnotationChecker.checkAnnotationValueByType(value, type, false);
1454     if (result != null) {
1455       myHolder.newAnnotation(HighlightSeverity.ERROR, result.getSecond()).range(result.getFirst()).create();
1456     }
1457   }
1458
1459   @Override
1460   public void visitAnnotationNameValuePair(@NotNull GrAnnotationNameValuePair nameValuePair) {
1461     final PsiElement identifier = nameValuePair.getNameIdentifierGroovy();
1462     if (identifier == null) {
1463       final PsiElement parent = nameValuePair.getParent();
1464       if (parent instanceof GrAnnotationArgumentList) {
1465         final int count = ((GrAnnotationArgumentList)parent).getAttributes().length;
1466         if (count > 1) {
1467           myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("attribute.name.expected")).create();
1468         }
1469       }
1470     }
1471
1472     final GrAnnotationMemberValue value = nameValuePair.getValue();
1473     if (value != null) {
1474       checkAnnotationAttributeValue(value, value);
1475     }
1476   }
1477
1478   private boolean checkAnnotationAttributeValue(@Nullable GrAnnotationMemberValue value, @NotNull PsiElement toHighlight) {
1479     if (value == null) return false;
1480
1481     if (value instanceof GrLiteral) return false;
1482     if (value instanceof GrFunctionalExpression) return false;
1483     if (value instanceof GrAnnotation) return false;
1484
1485     if (value instanceof GrReferenceExpression) {
1486       PsiElement resolved = ((GrReferenceExpression)value).resolve();
1487       if (resolved instanceof PsiClass) return false;
1488       if (resolved instanceof PsiEnumConstant) return false;
1489       if (resolved == null && isClassReference(value)) return false;
1490
1491       if (resolved instanceof GrAccessorMethod) resolved = ((GrAccessorMethod)resolved).getProperty();
1492       if (resolved instanceof PsiField) {
1493         GrExpression initializer;
1494         try {
1495           if (resolved instanceof GrField) {
1496             initializer = ((GrField)resolved).getInitializerGroovy();
1497           }
1498           else {
1499             final PsiExpression _initializer = ((PsiField)resolved).getInitializer();
1500             initializer = _initializer != null
1501                           ? (GrExpression)ExpressionConverter.getExpression(_initializer, GroovyLanguage.INSTANCE, value.getProject())
1502                           : null;
1503           }
1504         }
1505         catch (IncorrectOperationException e) {
1506           initializer = null;
1507         }
1508
1509         if (initializer != null) {
1510           return checkAnnotationAttributeValue(initializer, toHighlight);
1511         }
1512       }
1513     }
1514     if (value instanceof GrAnnotationArrayInitializer) {
1515       for (GrAnnotationMemberValue expression : ((GrAnnotationArrayInitializer)value).getInitializers()) {
1516         if (checkAnnotationAttributeValue(expression, toHighlight)) return true;
1517       }
1518       return false;
1519     }
1520     if (value instanceof GrUnaryExpression) {
1521       final IElementType tokenType = ((GrUnaryExpression)value).getOperationTokenType();
1522       if (tokenType == GroovyTokenTypes.mMINUS || tokenType == GroovyTokenTypes.mPLUS) {
1523         return checkAnnotationAttributeValue(((GrUnaryExpression)value).getOperand(), toHighlight);
1524       }
1525     }
1526
1527     myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("expected.0.to.be.inline.constant", value.getText())).range(toHighlight).create();
1528     return true;
1529   }
1530
1531   private static boolean isClassReference(GrAnnotationMemberValue value) {
1532     if (value instanceof GrReferenceExpression) {
1533       final String referenceName = ((GrReferenceExpression)value).getReferenceName();
1534       if ("class".equals(referenceName)) {
1535         final GrExpression qualifier = ((GrReferenceExpression)value).getQualifier();
1536         if (qualifier instanceof GrReferenceExpression) {
1537           final PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
1538           if (resolved instanceof PsiClass) {
1539             return true;
1540           }
1541         }
1542       }
1543     }
1544
1545     return false;
1546   }
1547
1548   @Override
1549   public void visitImportStatement(@NotNull GrImportStatement importStatement) {
1550     checkAnnotationList(myHolder, importStatement.getAnnotationList(), GroovyBundle.message("import.statement.cannot.have.modifiers"));
1551   }
1552
1553   @Override
1554   public void visitExtendsClause(@NotNull GrExtendsClause extendsClause) {
1555     GrTypeDefinition typeDefinition = (GrTypeDefinition)extendsClause.getParent();
1556
1557     if (typeDefinition.isAnnotationType()) {
1558       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.types.may.not.have.extends.clause")).create();
1559     }
1560     else if (typeDefinition.isTrait()) {
1561       checkReferenceList(myHolder, extendsClause, IS_TRAIT, GroovyBundle.message("only.traits.expected.here"), null);
1562     }
1563     else if (typeDefinition.isInterface()) {
1564       checkReferenceList(myHolder, extendsClause, IS_INTERFACE, GroovyBundle.message("no.class.expected.here"), null);
1565     }
1566     else if (typeDefinition.isEnum()) {
1567       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("enums.may.not.have.extends.clause")).create();
1568     }
1569     else {
1570       checkReferenceList(myHolder, extendsClause, IS_NOT_INTERFACE, GroovyBundle.message("no.interface.expected.here"), new ChangeExtendsImplementsQuickFix(typeDefinition));
1571       checkForWildCards(myHolder, extendsClause);
1572     }
1573
1574   }
1575
1576   @Override
1577   public void visitImplementsClause(@NotNull GrImplementsClause implementsClause) {
1578     GrTypeDefinition typeDefinition = (GrTypeDefinition)implementsClause.getParent();
1579
1580     if (typeDefinition.isAnnotationType()) {
1581       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.types.may.not.have.implements.clause")).create();
1582     }
1583     else if (GrTraitUtil.isInterface(typeDefinition)) {
1584       myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("no.implements.clause.allowed.for.interface"))
1585         .withFix(new ChangeExtendsImplementsQuickFix(typeDefinition)).create();
1586     }
1587     else {
1588       checkReferenceList(myHolder, implementsClause, IS_INTERFACE, GroovyBundle.message("no.class.expected.here"), new ChangeExtendsImplementsQuickFix(typeDefinition));
1589       checkForWildCards(myHolder, implementsClause);
1590     }
1591   }
1592
1593   private static void checkReferenceList(@NotNull AnnotationHolder holder,
1594                                          @NotNull GrReferenceList list,
1595                                          @NotNull Condition<? super PsiClass> applicabilityCondition,
1596                                          @NotNull String message,
1597                                          @Nullable IntentionAction fix) {
1598     for (GrCodeReferenceElement refElement : list.getReferenceElementsGroovy()) {
1599       final PsiElement psiClass = refElement.resolve();
1600       if (psiClass instanceof PsiClass && !applicabilityCondition.value((PsiClass)psiClass)) {
1601         AnnotationBuilder builder = holder.newAnnotation(HighlightSeverity.ERROR, message).range(refElement);
1602         if (fix != null) {
1603           builder = builder.withFix(fix);
1604         }
1605         builder.create();
1606       }
1607     }
1608   }
1609
1610   private static void checkFlowInterruptStatement(GrFlowInterruptingStatement statement, AnnotationHolder holder) {
1611     final PsiElement label = statement.getLabelIdentifier();
1612
1613     if (label != null) {
1614       final GrLabeledStatement resolved = statement.resolveLabel();
1615       if (resolved == null) {
1616         holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("undefined.label", statement.getLabelName())).range(label).create();
1617       }
1618     }
1619
1620     final GrStatement targetStatement = statement.findTargetStatement();
1621     if (targetStatement == null) {
1622       if (statement instanceof GrContinueStatement && label == null) {
1623         holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("continue.outside.loop")).create();
1624       }
1625       else if (statement instanceof GrBreakStatement && label == null) {
1626         holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("break.outside.loop.or.switch")).create();
1627       }
1628     }
1629     if (statement instanceof GrBreakStatement && label != null && findFirstLoop(statement) == null) {
1630       holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("break.outside.loop")).create();
1631     }
1632   }
1633
1634   @Nullable
1635   private static GrLoopStatement findFirstLoop(GrFlowInterruptingStatement statement) {
1636     return PsiTreeUtil.getParentOfType(statement, GrLoopStatement.class, true, GrClosableBlock.class, GrMember.class, GroovyFile.class);
1637   }
1638
1639   private static void checkThisOrSuperReferenceExpression(final GrReferenceExpression ref, AnnotationHolder holder) {
1640     PsiElement nameElement = ref.getReferenceNameElement();
1641     if (nameElement == null) return;
1642
1643     IElementType elementType = nameElement.getNode().getElementType();
1644     if (!(elementType == GroovyTokenTypes.kSUPER || elementType == GroovyTokenTypes.kTHIS)) return;
1645
1646     final GrExpression qualifier = ref.getQualifier();
1647     if (qualifier instanceof GrReferenceExpression) {
1648       final PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
1649       if (resolved instanceof PsiClass) {
1650         GrTypeDefinition containingClass = PsiTreeUtil.getParentOfType(ref, GrTypeDefinition.class, true, GroovyFile.class);
1651
1652         if (elementType == GroovyTokenTypes.kSUPER && containingClass != null && GrTraitUtil.isTrait((PsiClass)resolved)) {
1653           PsiClassType[] superTypes = containingClass.getSuperTypes();
1654           if (ContainerUtil.find(superTypes, type -> ref.getManager().areElementsEquivalent(type.resolve(), resolved)) != null) {
1655             holder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(nameElement).textAttributes(GroovySyntaxHighlighter.KEYWORD).create();
1656             return; // reference to trait method
1657           }
1658         }
1659
1660         if (containingClass == null || containingClass.getContainingClass() == null && !containingClass.isAnonymous()) {
1661           holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("qualified.0.is.allowed.only.in.nested.or.inner.classes",
1662                                                                              nameElement.getText())).create();
1663           return;
1664         }
1665
1666         if (!PsiTreeUtil.isAncestor(resolved, ref, true)) {
1667           String qname = ((PsiClass)resolved).getQualifiedName();
1668           assert qname != null;
1669           holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("is.not.enclosing.class", qname)).create();
1670         }
1671       }
1672     }
1673     else if (qualifier == null) {
1674       if (elementType == GroovyTokenTypes.kSUPER) {
1675         final GrMember container = PsiTreeUtil.getParentOfType(ref, GrMethod.class, GrClassInitializer.class);
1676         if (container != null && container.hasModifierProperty(PsiModifier.STATIC)) {
1677           holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("super.cannot.be.used.in.static.context")).create();
1678         }
1679       }
1680     }
1681   }
1682
1683   private static void checkGrDocReferenceElement(AnnotationHolder holder, PsiElement element) {
1684     ASTNode node = element.getNode();
1685     if (node != null && TokenSets.BUILT_IN_TYPES.contains(node.getElementType())) {
1686       holder.newSilentAnnotation(HighlightSeverity.INFORMATION).textAttributes(GroovySyntaxHighlighter.KEYWORD).create();
1687     }
1688   }
1689
1690   private static void checkAnnotationList(AnnotationHolder holder, @NotNull GrModifierList modifierList, @NotNull String message) {
1691     final PsiElement[] modifiers = modifierList.getModifiers();
1692     for (PsiElement modifier : modifiers) {
1693       if (!(modifier instanceof PsiAnnotation)) {
1694         holder.newAnnotation(HighlightSeverity.ERROR, message).range(modifier).create();
1695       }
1696     }
1697   }
1698
1699   private static void checkImplementedMethodsOfClass(AnnotationHolder holder, GrTypeDefinition typeDefinition) {
1700     if (typeDefinition.hasModifierProperty(PsiModifier.ABSTRACT)) return;
1701     if (typeDefinition.isAnnotationType()) return;
1702     if (typeDefinition instanceof GrTypeParameter) return;
1703
1704
1705     PsiMethod abstractMethod = ClassUtil.getAnyAbstractMethod(typeDefinition);
1706     if (abstractMethod == null) return;
1707
1708     String notImplementedMethodName = abstractMethod.getName();
1709
1710     final TextRange range = GrHighlightUtil.getClassHeaderTextRange(typeDefinition);
1711     String message = GroovyBundle.message("method.is.not.implemented", notImplementedMethodName);
1712     AnnotationBuilder builder =
1713       holder.newAnnotation(HighlightSeverity.ERROR, message)
1714         .range(range);
1715     registerImplementsMethodsFix(typeDefinition, abstractMethod, builder, message, range).create();
1716   }
1717
1718   @Contract(pure = true)
1719   private static AnnotationBuilder registerImplementsMethodsFix(@NotNull GrTypeDefinition typeDefinition,
1720                                                                 @NotNull PsiMethod abstractMethod,
1721                                                                 @NotNull AnnotationBuilder builder,
1722                                                                 String message,
1723                                                                 TextRange range) {
1724     if (!OverrideImplementExploreUtil.getMethodsToOverrideImplement(typeDefinition, true).isEmpty()) {
1725       builder = builder.withFix(QuickFixFactory.getInstance().createImplementMethodsFix(typeDefinition));
1726     }
1727
1728     if (!JavaPsiFacade.getInstance(typeDefinition.getProject()).getResolveHelper().isAccessible(abstractMethod, typeDefinition, null)) {
1729       builder = registerLocalFix(builder, new GrModifierFix(abstractMethod, PsiModifier.PUBLIC, true, true, GrModifierFix.MODIFIER_LIST_OWNER), abstractMethod,
1730                        message, ProblemHighlightType.ERROR, range);
1731       builder = registerLocalFix(builder, new GrModifierFix(abstractMethod, PsiModifier.PROTECTED, true, true, GrModifierFix.MODIFIER_LIST_OWNER), abstractMethod,
1732                        message, ProblemHighlightType.ERROR, range);
1733     }
1734
1735     if (!(typeDefinition instanceof GrAnnotationTypeDefinition) && typeDefinition.getModifierList() != null) {
1736       builder = registerLocalFix(builder, new GrModifierFix(typeDefinition, PsiModifier.ABSTRACT, false, true, GrModifierFix.MODIFIER_LIST_OWNER), typeDefinition,
1737                        message, ProblemHighlightType.ERROR, range);
1738     }
1739     return builder;
1740   }
1741
1742   private static void checkInnerMethod(AnnotationHolder holder, GrMethod grMethod) {
1743     final PsiElement parent = grMethod.getParent();
1744     if (parent instanceof GrOpenBlock || parent instanceof GrClosableBlock || parent instanceof GrBlockLambdaBody) {
1745       holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("Inner.methods.are.not.supported")).range(grMethod.getNameIdentifierGroovy()).create();
1746     }
1747   }
1748
1749   @NotNull
1750   @Contract(pure=true)
1751   private static AnnotationBuilder registerMakeAbstractMethodNotAbstractFix(AnnotationBuilder builder,
1752                                                                             GrMethod method,
1753                                                                             boolean makeClassAbstract,
1754                                                                             String message, TextRange range) {
1755     if (method.getBlock() == null) {
1756       builder = builder.withFix(QuickFixFactory.getInstance().createAddMethodBodyFix(method));
1757     }
1758     else {
1759       builder = builder.withFix(QuickFixFactory.getInstance().createDeleteMethodBodyFix(method));
1760     }
1761
1762     GrModifierFix fix = new GrModifierFix(method, PsiModifier.ABSTRACT, false, false, GrModifierFix.MODIFIER_LIST_OWNER);
1763     builder = registerLocalFix(builder, fix, method, message, ProblemHighlightType.ERROR, range);
1764     if (makeClassAbstract) {
1765       final PsiClass containingClass = method.getContainingClass();
1766       if (containingClass != null) {
1767         final PsiModifierList list = containingClass.getModifierList();
1768         if (list != null && !list.hasModifierProperty(PsiModifier.ABSTRACT)) {
1769           builder = registerLocalFix(builder, new GrModifierFix(containingClass, PsiModifier.ABSTRACT, false, true, GrModifierFix.MODIFIER_LIST_OWNER), containingClass, message, ProblemHighlightType.ERROR, range);
1770         }
1771       }
1772     }
1773     return builder;
1774   }
1775
1776   private static void checkMethodDefinitionModifiers(AnnotationHolder holder, GrMethod method) {
1777     final GrModifierList modifiersList = method.getModifierList();
1778     checkAccessModifiers(holder, modifiersList, method);
1779     checkDuplicateModifiers(holder, modifiersList, method);
1780     checkOverrideAnnotation(holder, modifiersList, method);
1781
1782     checkModifierIsNotAllowed(modifiersList, PsiModifier.VOLATILE, GroovyBundle.message("method.has.incorrect.modifier.volatile"), holder);
1783
1784     checkForAbstractAndFinalCombination(holder, method, modifiersList);
1785
1786     //script methods
1787     boolean isMethodAbstract = modifiersList.hasExplicitModifier(PsiModifier.ABSTRACT);
1788     PsiElement modifierOrList = getModifierOrList(modifiersList, PsiModifier.ABSTRACT);
1789     if (method.getParent() instanceof GroovyFileBase) {
1790       if (isMethodAbstract) {
1791         String message = GroovyBundle.message("script.method.cannot.have.modifier.abstract");
1792         AnnotationBuilder builder =
1793           holder.newAnnotation(HighlightSeverity.ERROR, message)
1794             .range(modifierOrList);
1795         registerMakeAbstractMethodNotAbstractFix(builder, method, false, message, modifierOrList.getTextRange()).create();
1796       }
1797
1798       checkModifierIsNotAllowed(modifiersList, PsiModifier.NATIVE, GroovyBundle.message("script.cannot.have.modifier.native"), holder);
1799     }
1800     //type definition methods
1801     else if (method.getParent() != null && method.getParent().getParent() instanceof GrTypeDefinition) {
1802       GrTypeDefinition containingTypeDef = ((GrTypeDefinition)method.getParent().getParent());
1803
1804       if (containingTypeDef.isTrait()) {
1805         checkModifierIsNotAllowed(modifiersList, PsiModifier.PROTECTED, GroovyBundle.message("trait.method.cannot.be.protected"), holder);
1806       }
1807       //interface
1808       else if (containingTypeDef.isInterface()) {
1809         checkModifierIsNotAllowed(modifiersList, PsiModifier.STATIC, GroovyBundle.message("interface.must.have.no.static.method"), holder);
1810         checkModifierIsNotAllowed(modifiersList, PsiModifier.PRIVATE, GroovyBundle.message("interface.members.are.not.allowed.to.be", PsiModifier.PRIVATE), holder);
1811         checkModifierIsNotAllowed(modifiersList, PsiModifier.PROTECTED, GroovyBundle.message("interface.members.are.not.allowed.to.be", PsiModifier.PROTECTED), holder);
1812       }
1813       else if (containingTypeDef.isAnonymous()) {
1814         if (isMethodAbstract) {
1815           String message = GroovyBundle.message("anonymous.class.cannot.have.abstract.method");
1816           AnnotationBuilder builder =
1817             holder.newAnnotation(HighlightSeverity.ERROR, message).range(
1818               modifierOrList);
1819           registerMakeAbstractMethodNotAbstractFix(builder, method, false, message, modifierOrList.getTextRange()).create();
1820         }
1821       }
1822       //class
1823       else {
1824         PsiModifierList typeDefModifiersList = containingTypeDef.getModifierList();
1825         LOG.assertTrue(typeDefModifiersList != null, "modifiers list must be not null");
1826
1827         if (!typeDefModifiersList.hasModifierProperty(PsiModifier.ABSTRACT) && isMethodAbstract) {
1828
1829           String message = GroovyBundle.message("only.abstract.class.can.have.abstract.method");
1830           AnnotationBuilder builder =
1831             holder.newAnnotation(HighlightSeverity.ERROR, message)
1832               .range(modifiersList);
1833           registerMakeAbstractMethodNotAbstractFix(builder, method, true, message, modifierOrList.getTextRange()).create();
1834         }
1835       }
1836
1837       if (method.isConstructor()) {
1838         checkModifierIsNotAllowed(modifiersList, PsiModifier.STATIC, GroovyBundle.message("constructor.cannot.have.static.modifier"), holder);
1839       }
1840     }
1841
1842     if (method.hasModifierProperty(PsiModifier.NATIVE) && method.getBlock() != null) {
1843       String message = GroovyBundle.message("native.methods.cannot.have.body");
1844       PsiElement list = getModifierOrList(modifiersList, PsiModifier.NATIVE);
1845       AnnotationBuilder builder = holder.newAnnotation(HighlightSeverity.ERROR, message)
1846         .range(list);
1847       builder = registerLocalFix(builder, new GrModifierFix((PsiMember)modifiersList.getParent(), PsiModifier.NATIVE, true, false, GrModifierFix.MODIFIER_LIST), modifiersList,
1848                        message, ProblemHighlightType.ERROR, list.getTextRange());
1849       builder.withFix(QuickFixFactory.getInstance().createDeleteMethodBodyFix(method))
1850       .create();
1851     }
1852   }
1853
1854   private static void checkForAbstractAndFinalCombination(AnnotationHolder holder, GrMember member, GrModifierList modifiersList) {
1855     if (member.hasModifierProperty(PsiModifier.FINAL) && member.hasModifierProperty(PsiModifier.ABSTRACT)) {
1856       String message = GroovyBundle.message("illegal.combination.of.modifiers.abstract.and.final");
1857       AnnotationBuilder builder =
1858         holder.newAnnotation(HighlightSeverity.ERROR, message)
1859           .range(modifiersList);
1860       builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.FINAL, false, false, GrModifierFix.MODIFIER_LIST), modifiersList,
1861                        message, ProblemHighlightType.ERROR, modifiersList.getTextRange());
1862       builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.ABSTRACT, false, false, GrModifierFix.MODIFIER_LIST), modifiersList,
1863                        message, ProblemHighlightType.ERROR, modifiersList.getTextRange());
1864       builder.create();
1865     }
1866   }
1867
1868   @NotNull
1869   private static PsiElement getModifierOrList(@NotNull GrModifierList modifiersList, @GrModifier.GrModifierConstant final String modifier) {
1870     PsiElement m = modifiersList.getModifier(modifier);
1871     return m != null ? m : modifiersList;
1872   }
1873
1874   private static void checkOverrideAnnotation(AnnotationHolder holder, GrModifierList list, GrMethod method) {
1875     final PsiAnnotation overrideAnnotation = list.findAnnotation("java.lang.Override");
1876     if (overrideAnnotation == null) {
1877       return;
1878     }
1879     try {
1880       MethodSignatureBackedByPsiMethod superMethod = SuperMethodsSearch.search(method, null, true, false).findFirst();
1881       if (superMethod == null) {
1882         holder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle.message("method.does.not.override.super")).range(overrideAnnotation).create();
1883       }
1884     }
1885     catch (IndexNotReadyException ignored) {
1886       //nothing to do
1887     }
1888   }
1889
1890   private static void checkTypeDefinitionModifiers(AnnotationHolder holder, GrTypeDefinition typeDefinition) {
1891     GrModifierList modifiersList = typeDefinition.getModifierList();
1892
1893     if (modifiersList == null) return;
1894
1895     checkAccessModifiers(holder, modifiersList, typeDefinition);
1896     checkDuplicateModifiers(holder, modifiersList, typeDefinition);
1897
1898     PsiClassType[] extendsListTypes = typeDefinition.getExtendsListTypes();
1899
1900     for (PsiClassType classType : extendsListTypes) {
1901       PsiClass psiClass = classType.resolve();
1902
1903       if (psiClass != null && psiClass.hasModifierProperty(PsiModifier.FINAL)) {
1904         PsiElement identifierGroovy = typeDefinition.getNameIdentifierGroovy();
1905         String message = GroovyBundle.message("final.class.cannot.be.extended");
1906         AnnotationBuilder builder = holder.newAnnotation(HighlightSeverity.ERROR, message)
1907           .range(identifierGroovy);
1908         builder = registerLocalFix(builder, new GrModifierFix(typeDefinition, PsiModifier.FINAL, false, false, GrModifierFix.MODIFIER_LIST_OWNER), typeDefinition,
1909                          message, ProblemHighlightType.ERROR, identifierGroovy.getTextRange());
1910         builder.create();
1911       }
1912     }
1913
1914     if (!typeDefinition.isEnum()) {
1915       checkForAbstractAndFinalCombination(holder, typeDefinition, modifiersList);
1916     }
1917
1918     checkModifierIsNotAllowed(modifiersList, PsiModifier.TRANSIENT, GroovyBundle.message("modifier.transient.not.allowed.here"), holder);
1919     checkModifierIsNotAllowed(modifiersList, PsiModifier.VOLATILE, GroovyBundle.message("modifier.volatile.not.allowed.here"), holder);
1920
1921     if (typeDefinition.isInterface()) {
1922       checkModifierIsNotAllowed(modifiersList, PsiModifier.FINAL, GroovyBundle.message("interface.cannot.have.modifier.final"), holder);
1923     }
1924   }
1925
1926   private static void checkDuplicateModifiers(AnnotationHolder holder, @NotNull GrModifierList list, PsiMember member) {
1927     final PsiElement[] modifiers = list.getModifiers();
1928     Set<String> set = new THashSet<>(modifiers.length);
1929     for (PsiElement modifier : modifiers) {
1930       if (modifier instanceof GrAnnotation) continue;
1931       @GrModifier.GrModifierConstant String name = modifier.getText();
1932       if (set.contains(name)) {
1933         String message = GroovyBundle.message("duplicate.modifier", name);
1934         AnnotationBuilder builder =
1935           holder.newAnnotation(HighlightSeverity.ERROR, message).range(list);
1936         if (member != null) {
1937           builder = registerLocalFix(builder, new GrModifierFix(member, name, false, false, GrModifierFix.MODIFIER_LIST), list, message,
1938                            ProblemHighlightType.ERROR, list.getTextRange());
1939         }
1940         builder.create();
1941       }
1942       else {
1943         set.add(name);
1944       }
1945     }
1946   }
1947
1948   private static void checkAccessModifiers(AnnotationHolder holder, @NotNull GrModifierList modifierList, PsiMember member) {
1949     boolean hasPrivate = modifierList.hasExplicitModifier(PsiModifier.PRIVATE);
1950     boolean hasPublic = modifierList.hasExplicitModifier(PsiModifier.PUBLIC);
1951     boolean hasProtected = modifierList.hasExplicitModifier(PsiModifier.PROTECTED);
1952
1953     if (hasPrivate && hasPublic || hasPrivate && hasProtected || hasPublic && hasProtected) {
1954       String message = GroovyBundle.message("illegal.combination.of.modifiers");
1955       AnnotationBuilder builder =
1956         holder.newAnnotation(HighlightSeverity.ERROR, message).range(modifierList);
1957       if (hasPrivate) {
1958         builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.PRIVATE, false, false, GrModifierFix.MODIFIER_LIST), modifierList,
1959                          message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1960       }
1961       if (hasProtected) {
1962         builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.PROTECTED, false, false, GrModifierFix.MODIFIER_LIST), modifierList,
1963                          message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1964       }
1965       if (hasPublic) {
1966         builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.PUBLIC, false, false, GrModifierFix.MODIFIER_LIST), modifierList,
1967                          message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1968       }
1969       builder.create();
1970     }
1971     else if (member instanceof PsiClass &&
1972              member.getContainingClass() == null &&
1973              GroovyConfigUtils.getInstance().isVersionAtLeast(member, GroovyConfigUtils.GROOVY2_0)) {
1974       checkModifierIsNotAllowed(modifierList, PsiModifier.PRIVATE, GroovyBundle.message("top.level.class.may.not.have.private.modifier"), holder);
1975       checkModifierIsNotAllowed(modifierList, PsiModifier.PROTECTED, GroovyBundle.message("top.level.class.may.not.have.protected.modifier"), holder);
1976     }
1977   }
1978
1979   private void checkDuplicateMethod(@NotNull GrMethod method) {
1980     PsiClass clazz = method.getContainingClass();
1981     if (clazz == null) return;
1982     GrReflectedMethod[] reflectedMethods = method.getReflectedMethods();
1983     if (reflectedMethods.length == 0) {
1984       doCheckDuplicateMethod(method, clazz);
1985     }
1986     else {
1987       for (GrReflectedMethod reflectedMethod : reflectedMethods) {
1988         doCheckDuplicateMethod(reflectedMethod, clazz);
1989       }
1990     }
1991   }
1992
1993   private void doCheckDuplicateMethod(@NotNull GrMethod method, @NotNull PsiClass clazz) {
1994     Set<MethodSignature> duplicatedSignatures = GrClassImplUtil.getDuplicatedSignatures(clazz);
1995     if (duplicatedSignatures.isEmpty()) return; // optimization
1996
1997     PsiSubstitutor substitutor = JavaPsiFacade.getElementFactory(method.getProject()).createRawSubstitutor(method);
1998     MethodSignature signature = method.getSignature(substitutor);
1999     if (!duplicatedSignatures.contains(signature)) return;
2000
2001     String signaturePresentation = GroovyPresentationUtil.getSignaturePresentation(signature);
2002     GrMethod original = method instanceof GrReflectedMethod ? ((GrReflectedMethod)method).getBaseMethod() : method;
2003     myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("method.duplicate", signaturePresentation, clazz.getName())).range(GrHighlightUtil.getMethodHeaderTextRange(original)).create();
2004   }
2005
2006   private static void checkTypeDefinition(AnnotationHolder holder, @NotNull GrTypeDefinition typeDefinition) {
2007     if (typeDefinition.isAnonymous()) {
2008       PsiClass superClass = ((PsiAnonymousClass)typeDefinition).getBaseClassType().resolve();
2009       if (superClass instanceof GrTypeDefinition && ((GrTypeDefinition)superClass).isTrait()) {
2010         holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("anonymous.classes.cannot.be.created.from.traits")).range(typeDefinition.getNameIdentifierGroovy()).create();
2011       }
2012     }
2013     if (typeDefinition.isAnnotationType() && typeDefinition.getContainingClass() != null) {
2014       holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.type.cannot.be.inner")).range(typeDefinition.getNameIdentifierGroovy()).create();
2015     }
2016
2017     if (!typeDefinition.hasModifierProperty(PsiModifier.STATIC)
2018         && (typeDefinition.getContainingClass() != null || typeDefinition instanceof GrAnonymousClassDefinition)) {
2019       GrTypeDefinition owner = PsiTreeUtil.getParentOfType(typeDefinition, GrTypeDefinition.class);
2020       if (owner instanceof GrTraitTypeDefinition) {
2021         holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("non.static.classes.not.allowed")).range(typeDefinition.getNameIdentifierGroovy()).create();
2022       }
2023     }
2024
2025     checkDuplicateClass(typeDefinition, holder);
2026
2027     checkCyclicInheritance(holder, typeDefinition);
2028   }
2029
2030   private static void checkCyclicInheritance(AnnotationHolder holder,
2031                                              @NotNull GrTypeDefinition typeDefinition) {
2032     final PsiClass psiClass = InheritanceUtil.getCircularClass(typeDefinition);
2033     if (psiClass != null) {
2034       String qname = psiClass.getQualifiedName();
2035       assert qname != null;
2036       holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cyclic.inheritance.involving.0", qname)).range(GrHighlightUtil.getClassHeaderTextRange(typeDefinition)).create();
2037     }
2038   }
2039
2040   private static void checkForWildCards(AnnotationHolder holder, @Nullable GrReferenceList clause) {
2041     if (clause == null) return;
2042     final GrCodeReferenceElement[] elements = clause.getReferenceElementsGroovy();
2043     for (GrCodeReferenceElement element : elements) {
2044       final GrTypeArgumentList list = element.getTypeArgumentList();
2045       if (list != null) {
2046         for (GrTypeElement type : list.getTypeArgumentElements()) {
2047           if (type instanceof GrWildcardTypeArgument) {
2048             holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("wildcards.are.not.allowed.in.extends.list")).range(type).create();
2049           }
2050         }
2051       }
2052     }
2053   }
2054
2055   private static void checkDuplicateClass(GrTypeDefinition typeDefinition, AnnotationHolder holder) {
2056     final PsiClass containingClass = typeDefinition.getContainingClass();
2057     String name = typeDefinition.getName();
2058     if (containingClass != null) {
2059       final String containingClassName = containingClass.getName();
2060       if (containingClassName != null && containingClassName.equals(name)) {
2061         holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("duplicate.inner.class", name)).range(typeDefinition.getNameIdentifierGroovy()).create();
2062       }
2063     }
2064     final String qName = typeDefinition.getQualifiedName();
2065     if (qName != null) {
2066       JavaPsiFacade facade = JavaPsiFacade.getInstance(typeDefinition.getProject());
2067       GlobalSearchScope scope = inferClassScopeForSearchingDuplicates(typeDefinition);
2068       final PsiClass[] classes = facade.findClasses(qName, scope);
2069       if (classes.length > 1) {
2070         String packageName = getPackageName(typeDefinition);
2071
2072         if (!isScriptGeneratedClass(classes)) {
2073           holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("duplicate.class", name, packageName)).range(typeDefinition.getNameIdentifierGroovy()).create();
2074         }
2075         else {
2076           holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("script.generated.with.same.name", qName)).range(typeDefinition.getNameIdentifierGroovy()).create();
2077         }
2078       }
2079     }
2080   }
2081
2082   private static GlobalSearchScope inferClassScopeForSearchingDuplicates(GrTypeDefinition typeDefinition) {
2083     GlobalSearchScope defaultScope = typeDefinition.getResolveScope();
2084
2085     PsiFile file = typeDefinition.getContainingFile();
2086     if (file instanceof GroovyFile && ((GroovyFile)file).isScript()) {
2087       Module module = ModuleUtilCore.findModuleForPsiElement(file);
2088       if (module != null) {
2089         return defaultScope.intersectWith(module.getModuleScope());
2090       }
2091     }
2092     return defaultScope;
2093   }
2094
2095   private static String getPackageName(GrTypeDefinition typeDefinition) {
2096     final PsiFile file = typeDefinition.getContainingFile();
2097     String packageName = "<default package>";
2098     if (file instanceof GroovyFile) {
2099       final String name = ((GroovyFile)file).getPackageName();
2100       if (!name.isEmpty()) packageName = name;
2101     }
2102     return packageName;
2103   }
2104
2105   private static boolean isScriptGeneratedClass(PsiClass[] allClasses) {
2106     return allClasses.length == 2 && (allClasses[0] instanceof GroovyScriptClass || allClasses[1] instanceof GroovyScriptClass);
2107   }
2108 }
2109