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