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;
4 import com.intellij.codeInsight.ClassUtil;
5 import com.intellij.codeInsight.generation.OverrideImplementExploreUtil;
6 import com.intellij.codeInsight.intention.IntentionAction;
7 import com.intellij.codeInsight.intention.QuickFixFactory;
8 import com.intellij.codeInspection.ProblemHighlightType;
9 import com.intellij.lang.ASTNode;
10 import com.intellij.lang.annotation.AnnotationBuilder;
11 import com.intellij.lang.annotation.AnnotationHolder;
12 import com.intellij.lang.annotation.HighlightSeverity;
13 import com.intellij.lang.injection.InjectedLanguageManager;
14 import com.intellij.openapi.diagnostic.Logger;
15 import com.intellij.openapi.editor.Document;
16 import com.intellij.openapi.module.Module;
17 import com.intellij.openapi.module.ModuleUtilCore;
18 import com.intellij.openapi.project.IndexNotReadyException;
19 import com.intellij.openapi.util.Condition;
20 import com.intellij.openapi.util.Pair;
21 import com.intellij.openapi.util.TextRange;
22 import com.intellij.openapi.util.text.StringUtil;
23 import com.intellij.psi.*;
24 import com.intellij.psi.impl.ExpressionConverter;
25 import com.intellij.psi.search.GlobalSearchScope;
26 import com.intellij.psi.search.searches.SuperMethodsSearch;
27 import com.intellij.psi.tree.IElementType;
28 import com.intellij.psi.util.*;
29 import com.intellij.util.IncorrectOperationException;
30 import com.intellij.util.ObjectUtils;
31 import com.intellij.util.VisibilityUtil;
32 import com.intellij.util.containers.ContainerUtil;
33 import com.intellij.util.containers.MultiMap;
34 import gnu.trove.THashSet;
35 import org.jetbrains.annotations.Contract;
36 import org.jetbrains.annotations.NotNull;
37 import org.jetbrains.annotations.Nullable;
38 import org.jetbrains.plugins.groovy.GroovyBundle;
39 import org.jetbrains.plugins.groovy.GroovyLanguage;
40 import org.jetbrains.plugins.groovy.annotator.checkers.AnnotationChecker;
41 import org.jetbrains.plugins.groovy.annotator.checkers.CustomAnnotationChecker;
42 import org.jetbrains.plugins.groovy.annotator.intentions.*;
43 import org.jetbrains.plugins.groovy.codeInspection.bugs.GrModifierFix;
44 import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
45 import org.jetbrains.plugins.groovy.highlighter.GroovySyntaxHighlighter;
46 import org.jetbrains.plugins.groovy.lang.documentation.GroovyPresentationUtil;
47 import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocComment;
48 import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocReferenceElement;
49 import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
50 import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
51 import org.jetbrains.plugins.groovy.lang.psi.*;
52 import org.jetbrains.plugins.groovy.lang.psi.api.GrBlockLambdaBody;
53 import org.jetbrains.plugins.groovy.lang.psi.api.GrFunctionalExpression;
54 import org.jetbrains.plugins.groovy.lang.psi.api.GrLambdaExpression;
55 import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
56 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
57 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier;
58 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
59 import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.*;
60 import org.jetbrains.plugins.groovy.lang.psi.api.statements.*;
61 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
62 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
63 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
64 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
65 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
66 import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrBreakStatement;
67 import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrContinueStatement;
68 import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrFlowInterruptingStatement;
69 import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement;
70 import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrForInClause;
71 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
72 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.*;
73 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty;
74 import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
75 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.*;
76 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.*;
77 import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
78 import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition;
79 import org.jetbrains.plugins.groovy.lang.psi.api.types.*;
80 import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper;
81 import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtil;
82 import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
83 import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.modifiers.GrAnnotationCollector;
84 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
85 import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
86 import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
87 import org.jetbrains.plugins.groovy.lang.psi.util.*;
88 import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
89 import org.jetbrains.plugins.groovy.lang.resolve.api.GroovyConstructorReference;
90 import org.jetbrains.plugins.groovy.lang.resolve.ast.GeneratedConstructorCollector;
91 import org.jetbrains.plugins.groovy.lang.resolve.ast.InheritConstructorContributor;
92 import org.jetbrains.plugins.groovy.lang.resolve.ast.contributor.SyntheticKeywordConstructorContributor;
93 import org.jetbrains.plugins.groovy.transformations.immutable.GrImmutableUtils;
97 import static com.intellij.psi.util.PsiTreeUtil.findChildOfType;
98 import static org.jetbrains.plugins.groovy.annotator.ImplKt.checkInnerClassReferenceFromInstanceContext;
99 import static org.jetbrains.plugins.groovy.annotator.ImplKt.checkUnresolvedCodeReference;
100 import static org.jetbrains.plugins.groovy.annotator.StringInjectionKt.getLineFeed;
101 import static org.jetbrains.plugins.groovy.annotator.UtilKt.*;
102 import static org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GroovyUnresolvedAccessChecker.checkUnresolvedReference;
103 import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.isInStaticCompilationContext;
104 import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtilKt.mayContainTypeArguments;
105 import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.findScriptField;
106 import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.isFieldDeclaration;
111 public class GroovyAnnotator extends GroovyElementVisitor {
112 private static final Logger LOG = Logger.getInstance(GroovyAnnotator.class);
114 public static final Condition<PsiClass> IS_INTERFACE = aClass -> aClass.isInterface();
115 private static final Condition<PsiClass> IS_NOT_INTERFACE = aClass -> !aClass.isInterface();
116 public static final Condition<PsiClass> IS_TRAIT = aClass -> GrTraitUtil.isTrait(aClass);
118 private final AnnotationHolder myHolder;
120 public GroovyAnnotator(@NotNull AnnotationHolder holder) {
125 public void visitTypeArgumentList(@NotNull GrTypeArgumentList typeArgumentList) {
126 PsiElement parent = typeArgumentList.getParent();
127 if (!(parent instanceof GrReferenceElement)) return;
129 if (parent instanceof GrCodeReferenceElement && !mayContainTypeArguments((GrCodeReferenceElement)parent)) {
130 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("type.argument.list.is.not.allowed.here")).create();
134 final GroovyResolveResult resolveResult = ((GrReferenceElement)parent).advancedResolve();
135 final PsiElement resolved = resolveResult.getElement();
136 final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
138 if (resolved == null) return;
140 if (!(resolved instanceof PsiTypeParameterListOwner)) {
141 myHolder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle.message("type.argument.list.is.not.allowed.here")).create();
145 if (typeArgumentList.isDiamond()) return;
147 final PsiTypeParameter[] parameters = ((PsiTypeParameterListOwner)resolved).getTypeParameters();
148 final GrTypeElement[] arguments = typeArgumentList.getTypeArgumentElements();
150 if (arguments.length != parameters.length) {
151 myHolder.newAnnotation(HighlightSeverity.WARNING,
152 GroovyBundle.message("wrong.number.of.type.arguments", arguments.length, parameters.length)).create();
156 for (int i = 0; i < parameters.length; i++) {
157 PsiTypeParameter parameter = parameters[i];
158 final PsiClassType[] superTypes = parameter.getExtendsListTypes();
159 final PsiType argType = arguments[i].getType();
160 for (PsiClassType superType : superTypes) {
161 final PsiType substitutedSuper = substitutor.substitute(superType);
162 if (substitutedSuper != null && !substitutedSuper.isAssignableFrom(argType)) {
163 myHolder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle
164 .message("type.argument.0.is.not.in.its.bound.should.extend.1", argType.getCanonicalText(), superType.getCanonicalText())).range(arguments[i]).create();
172 public void visitNamedArgument(@NotNull GrNamedArgument argument) {
173 PsiElement parent = argument.getParent();
174 if (parent instanceof GrArgumentList) {
175 final PsiElement pParent = parent.getParent();
176 if (pParent instanceof GrIndexProperty) {
177 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("named.arguments.are.not.allowed.inside.index.operations")).create();
183 public void visitElement(@NotNull GroovyPsiElement element) {
184 if (element.getParent() instanceof GrDocReferenceElement) {
185 checkGrDocReferenceElement(myHolder, element);
190 public void visitTryStatement(@NotNull GrTryCatchStatement statement) {
191 final GrCatchClause[] clauses = statement.getCatchClauses();
193 if (statement.getResourceList() == null && clauses.length == 0 && statement.getFinallyClause() == null) {
194 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("try.without.catch.finally")).range(statement.getFirstChild()).create();
198 List<PsiType> usedExceptions = new ArrayList<>();
200 for (GrCatchClause clause : clauses) {
201 final GrParameter parameter = clause.getParameter();
202 if (parameter == null) continue;
204 final GrTypeElement typeElement = parameter.getTypeElementGroovy();
205 PsiType type = typeElement != null ? typeElement.getType() : TypesUtil.createType(CommonClassNames.JAVA_LANG_EXCEPTION, statement);
207 if (typeElement instanceof GrDisjunctionTypeElement) {
208 final GrTypeElement[] elements = ((GrDisjunctionTypeElement)typeElement).getTypeElements();
209 final PsiType[] types = ContainerUtil.map2Array(elements, PsiType.class, GrTypeElement::getType);
211 List<PsiType> usedInsideDisjunction = new ArrayList<>();
212 for (int i = 0; i < types.length; i++) {
213 if (checkExceptionUsed(usedExceptions, parameter, elements[i], types[i])) {
214 usedInsideDisjunction.add(types[i]);
215 for (int j = 0; j < types.length; j++) {
216 if (i != j && types[j].isAssignableFrom(types[i])) {
217 myHolder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle.message("unnecessary.type", types[i].getCanonicalText(),
218 types[j].getCanonicalText())).range(elements[i])
219 .withFix(new GrRemoveExceptionFix(true)).create();
225 usedExceptions.addAll(usedInsideDisjunction);
228 if (checkExceptionUsed(usedExceptions, parameter, typeElement, type)) {
229 usedExceptions.add(type);
236 public void visitCatchClause(@NotNull GrCatchClause clause) {
237 final GrParameter parameter = clause.getParameter();
238 if (parameter == null) return;
240 final GrTypeElement typeElement = parameter.getTypeElementGroovy();
241 if (typeElement != null) {
242 final PsiType type = typeElement.getType();
243 if (type instanceof PsiClassType && ((PsiClassType)type).resolve() == null) return; //don't highlight unresolved types
244 final PsiClassType throwable = TypesUtil.createType(CommonClassNames.JAVA_LANG_THROWABLE, clause);
245 if (!throwable.isAssignableFrom(type)) {
246 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("catch.statement.parameter.type.should.be.a.subclass.of.throwable")).range(typeElement).create();
252 public void visitDocComment(@NotNull GrDocComment comment) {
253 String text = comment.getText();
254 if (!text.endsWith("*/")) {
255 TextRange range = comment.getTextRange();
256 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("doc.end.expected")).range(new TextRange(range.getEndOffset() - 1, range.getEndOffset())).create();
261 public void visitVariableDeclaration(@NotNull GrVariableDeclaration variableDeclaration) {
262 checkDuplicateModifiers(myHolder, variableDeclaration.getModifierList(), null);
263 if (variableDeclaration.isTuple()) {
264 final GrModifierList list = variableDeclaration.getModifierList();
266 final PsiElement last = PsiUtil.skipWhitespacesAndComments(list.getLastChild(), false);
268 final IElementType type = last.getNode().getElementType();
269 if (type != GroovyTokenTypes.kDEF) {
270 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("tuple.declaration.should.end.with.def.modifier")).range(list).create();
274 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("tuple.declaration.should.end.with.def.modifier")).range(list).create();
278 GrTypeParameterList typeParameterList = findChildOfType(variableDeclaration, GrTypeParameterList.class);
279 if (typeParameterList != null) {
280 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("type.parameters.are.unexpected")).range(typeParameterList).create();
285 private boolean checkExceptionUsed(List<PsiType> usedExceptions, GrParameter parameter, GrTypeElement typeElement, PsiType type) {
286 for (PsiType exception : usedExceptions) {
287 if (exception.isAssignableFrom(type)) {
288 myHolder.newAnnotation(HighlightSeverity.WARNING,
289 GroovyBundle.message("exception.0.has.already.been.caught", type.getCanonicalText()))
290 .range(typeElement != null ? typeElement : parameter.getNameIdentifierGroovy())
291 .withFix(new GrRemoveExceptionFix(parameter.getTypeElementGroovy() instanceof GrDisjunctionTypeElement)).create();
299 public void visitReferenceExpression(@NotNull final GrReferenceExpression referenceExpression) {
300 checkStringNameIdentifier(referenceExpression);
301 checkThisOrSuperReferenceExpression(referenceExpression, myHolder);
302 checkFinalFieldAccess(referenceExpression);
303 checkFinalParameterAccess(referenceExpression);
305 if (ResolveUtil.isKeyOfMap(referenceExpression)) {
306 PsiElement nameElement = referenceExpression.getReferenceNameElement();
307 LOG.assertTrue(nameElement != null);
308 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(nameElement).textAttributes(GroovySyntaxHighlighter.MAP_KEY).create();
310 else if (ResolveUtil.isClassReference(referenceExpression)) {
311 PsiElement nameElement = referenceExpression.getReferenceNameElement();
312 LOG.assertTrue(nameElement != null);
313 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(nameElement).textAttributes(GroovySyntaxHighlighter.KEYWORD).create();
315 else if (isInStaticCompilationContext(referenceExpression)) {
316 checkUnresolvedReference(referenceExpression, true, true, new UnresolvedReferenceAnnotatorSink(myHolder));
320 private void checkFinalParameterAccess(GrReferenceExpression ref) {
321 final PsiElement resolved = ref.resolve();
323 if (resolved instanceof GrParameter) {
324 final GrParameter parameter = (GrParameter)resolved;
325 if (parameter.isPhysical() && parameter.hasModifierProperty(PsiModifier.FINAL) && PsiUtil.isLValue(ref)) {
326 if (parameter.getDeclarationScope() instanceof PsiMethod) {
327 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cannot.assign.a.value.to.final.parameter.0", parameter.getName())).create();
333 private void checkFinalFieldAccess(@NotNull GrReferenceExpression ref) {
334 final PsiElement resolved = ref.resolve();
336 if (resolved instanceof GrField && resolved.isPhysical() && ((GrField)resolved).hasModifierProperty(PsiModifier.FINAL) && PsiUtil.isLValue(ref)) {
337 final GrField field = (GrField)resolved;
339 final PsiClass containingClass = field.getContainingClass();
340 if (containingClass != null && PsiTreeUtil.isAncestor(containingClass, ref, true)) {
341 GrMember container = GrHighlightUtil.findClassMemberContainer(ref, containingClass);
343 if (field.hasModifierProperty(PsiModifier.STATIC)) {
344 if (container instanceof GrClassInitializer && ((GrClassInitializer)container).isStatic()) {
349 if (container instanceof GrMethod && ((GrMethod)container).isConstructor() ||
350 container instanceof GrClassInitializer && !((GrClassInitializer)container).isStatic()) {
355 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cannot.assign.a.value.to.final.field.0", field.getName())).create();
360 private void checkStringNameIdentifier(GrReferenceExpression ref) {
361 final PsiElement nameElement = ref.getReferenceNameElement();
362 if (nameElement == null) return;
364 final IElementType elementType = nameElement.getNode().getElementType();
365 if (GroovyTokenSets.STRING_LITERALS.contains(elementType)) {
366 checkStringLiteral(nameElement);
368 else if (elementType == GroovyTokenTypes.mREGEX_LITERAL || elementType == GroovyTokenTypes.mDOLLAR_SLASH_REGEX_LITERAL) {
369 checkRegexLiteral(nameElement);
374 public void visitTypeDefinition(@NotNull GrTypeDefinition typeDefinition) {
375 final PsiElement parent = typeDefinition.getParent();
376 if (!(typeDefinition.isAnonymous() ||
377 parent instanceof GrTypeDefinitionBody ||
378 parent instanceof GroovyFile ||
379 typeDefinition instanceof GrTypeParameter)) {
380 final TextRange range = GrHighlightUtil.getClassHeaderTextRange(typeDefinition);
382 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("class.definition.is.not.expected.here")).range(range)
383 .withFix(new GrMoveClassToCorrectPlaceFix(typeDefinition)).create();
385 checkTypeDefinition(myHolder, typeDefinition);
387 checkImplementedMethodsOfClass(myHolder, typeDefinition);
388 checkConstructors(myHolder, typeDefinition);
390 checkAnnotationCollector(myHolder, typeDefinition);
392 checkSameNameMethodsWithDifferentAccessModifiers(myHolder, typeDefinition.getCodeMethods());
393 checkInheritorOfSelfTypes(myHolder, typeDefinition);
396 private static void checkInheritorOfSelfTypes(AnnotationHolder holder, GrTypeDefinition definition) {
397 if (!(definition instanceof GrClassDefinition)) return;
398 List<PsiClass> selfTypeClasses = GrTraitUtil.getSelfTypeClasses(definition);
399 for (PsiClass selfClass : selfTypeClasses) {
400 if (InheritanceUtil.isInheritorOrSelf(definition, selfClass, true)) continue;
401 String message = GroovyBundle.message("selfType.class.does.not.inherit", definition.getQualifiedName(), selfClass.getQualifiedName());
402 holder.newAnnotation(HighlightSeverity.ERROR, message).range(GrHighlightUtil.getClassHeaderTextRange(definition)).create();
407 private static void checkSameNameMethodsWithDifferentAccessModifiers(AnnotationHolder holder, GrMethod[] methods) {
408 MultiMap<String, GrMethod> map = MultiMap.create();
409 for (GrMethod method : methods) {
410 if (!method.isConstructor()) {
411 map.putValue(method.getName(), method);
415 for (Map.Entry<String, Collection<GrMethod>> entry : map.entrySet()) {
416 Collection<GrMethod> collection = entry.getValue();
417 if (collection.size() > 1 && !sameAccessModifier(collection)) {
418 for (GrMethod method : collection) {
419 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("mixing.private.and.public.protected.methods.of.the.same.name")).range(GrHighlightUtil.getMethodHeaderTextRange(method)).create();
425 private static boolean sameAccessModifier(Collection<GrMethod> collection) {
426 Iterator<GrMethod> iterator = collection.iterator();
427 GrMethod method = iterator.next();
428 boolean privateAccess = PsiModifier.PRIVATE.equals(VisibilityUtil.getVisibilityModifier(method.getModifierList()));
430 while (iterator.hasNext()) {
431 GrMethod next = iterator.next();
432 if (privateAccess != PsiModifier.PRIVATE.equals(VisibilityUtil.getVisibilityModifier(next.getModifierList()))) {
440 private static void checkAnnotationCollector(AnnotationHolder holder, GrTypeDefinition definition) {
441 if (definition.isAnnotationType() &&
442 GrAnnotationCollector.findAnnotationCollector(definition) != null &&
443 definition.getCodeMethods().length > 0) {
444 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.collector.cannot.have.attributes")).range(definition.getNameIdentifierGroovy()).create();
448 private static void checkConstructors(@NotNull AnnotationHolder holder, @NotNull GrTypeDefinition typeDefinition) {
449 if (typeDefinition.isEnum() || typeDefinition.isInterface() || typeDefinition.isAnonymous() || typeDefinition instanceof GrTypeParameter) return;
450 final PsiClass superClass = typeDefinition.getSuperClass();
451 if (superClass == null) return;
453 if (InheritConstructorContributor.hasInheritConstructorsAnnotation(typeDefinition)) return;
455 final PsiMethod[] constructors = typeDefinition.getCodeConstructors();
456 checkDefaultConstructors(holder, typeDefinition, superClass, constructors);
457 checkRecursiveConstructors(holder, constructors);
460 private static void checkDefaultConstructors(@NotNull AnnotationHolder holder,
461 @NotNull GrTypeDefinition typeDefinition,
462 @NotNull PsiClass superClass,
463 PsiMethod @NotNull[] constructors) {
464 PsiMethod defConstructor = getDefaultConstructor(superClass);
465 boolean needExplicitSuperCall = superClass.getConstructors().length != 0 && (defConstructor == null || !PsiUtil.isAccessible(typeDefinition, defConstructor));
466 if (!needExplicitSuperCall) return;
467 final String qName = superClass.getQualifiedName();
469 if (typeDefinition.getConstructors().length == 0) {
470 final TextRange range = GrHighlightUtil.getClassHeaderTextRange(typeDefinition);
471 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("there.is.no.default.constructor.available.in.class.0", qName))
473 .withFix(QuickFixFactory.getInstance().createCreateConstructorMatchingSuperFix(typeDefinition)).create();
476 for (PsiMethod method : constructors) {
477 if (method instanceof GrMethod) {
478 final GrOpenBlock block = ((GrMethod)method).getBlock();
479 if (block == null) continue;
480 final GrStatement[] statements = block.getStatements();
481 if (statements.length > 0) {
482 if (statements[0] instanceof GrConstructorInvocation) continue;
484 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("there.is.no.default.constructor.available.in.class.0", qName))
485 .range(GrHighlightUtil.getMethodHeaderTextRange(method)).create();
489 PsiAnnotation anno = typeDefinition.getAnnotation(GroovyCommonClassNames.GROOVY_TRANSFORM_TUPLE_CONSTRUCTOR);
490 if (anno == null) return;
491 GrClosableBlock block = GrAnnotationUtil.inferClosureAttribute(anno, "pre");
492 if (block == null) return;
493 GrStatement[] statements = block.getStatements();
494 if (!(statements.length != 0 &&
495 statements[0] instanceof GrMethodCall &&
496 SyntheticKeywordConstructorContributor.isSyntheticConstructorCall((GrMethodCall)statements[0]))) {
497 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("there.is.no.default.constructor.available.in.class.0", qName))
498 .range(block).create();
503 public void visitEnumConstant(@NotNull GrEnumConstant enumConstant) {
504 super.visitEnumConstant(enumConstant);
505 final GrArgumentList argumentList = enumConstant.getArgumentList();
507 if (argumentList != null && PsiImplUtil.hasNamedArguments(argumentList) && !PsiImplUtil.hasExpressionArguments(argumentList)) {
508 final PsiMethod constructor = enumConstant.resolveConstructor();
509 if (constructor != null) {
510 if (!PsiUtil.isConstructorHasRequiredParameters(constructor)) {
511 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle
512 .message("the.usage.of.a.map.entry.expression.to.initialize.an.enum.is.currently.not.supported")).range(argumentList).create();
518 private static void checkRecursiveConstructors(AnnotationHolder holder, PsiMethod[] constructors) {
519 Map<PsiMethod, PsiMethod> nodes = new HashMap<>(constructors.length);
521 Set<PsiMethod> set = ContainerUtil.set(constructors);
523 for (PsiMethod constructor : constructors) {
524 if (!(constructor instanceof GrMethod)) continue;
526 final GrOpenBlock block = ((GrMethod)constructor).getBlock();
527 if (block == null) continue;
529 final GrStatement[] statements = block.getStatements();
530 if (statements.length <= 0 || !(statements[0] instanceof GrConstructorInvocation)) continue;
532 final PsiMethod resolved = ((GrConstructorInvocation)statements[0]).resolveMethod();
533 if (!set.contains(resolved)) continue;
535 nodes.put(constructor, resolved);
538 Set<PsiMethod> checked = new HashSet<>();
540 Set<PsiMethod> current;
541 for (PsiMethod constructor : constructors) {
542 if (!checked.add(constructor)) continue;
544 current = new HashSet<>();
545 current.add(constructor);
546 for (constructor = nodes.get(constructor); constructor != null && current.add(constructor); constructor = nodes.get(constructor)) {
547 checked.add(constructor);
550 if (constructor != null) {
551 PsiMethod circleStart = constructor;
553 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("recursive.constructor.invocation")).range(GrHighlightUtil.getMethodHeaderTextRange(constructor)).create();
554 constructor = nodes.get(constructor);
556 while (constructor != circleStart);
562 public void visitUnaryExpression(@NotNull GrUnaryExpression expression) {
563 if (expression.getOperationTokenType() == GroovyTokenTypes.mINC ||
564 expression.getOperationTokenType() == GroovyTokenTypes.mDEC) {
565 GrExpression operand = expression.getOperand();
566 if (operand instanceof GrReferenceExpression && ((GrReferenceExpression)operand).getQualifier() == null) {
567 GrTraitTypeDefinition trait = PsiTreeUtil.getParentOfType(operand, GrTraitTypeDefinition.class);
569 PsiElement resolved = ((GrReferenceExpression)operand).resolve();
570 if (resolved instanceof GrField && ((GrField)resolved).getContainingClass() instanceof GrTraitTypeDefinition) {
571 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle
572 .message("0.expressions.on.trait.fields.properties.are.not.supported.in.traits", expression.getOperationToken().getText())).create();
580 public void visitOpenBlock(@NotNull GrOpenBlock block) {
581 PsiElement blockParent = block.getParent();
582 if (blockParent instanceof GrMethod) {
583 final GrMethod method = (GrMethod)blockParent;
584 if (GrTraitUtil.isMethodAbstract(method)) {
585 String message = GroovyBundle.message("abstract.methods.must.not.have.body");
586 AnnotationBuilder builder =
587 myHolder.newAnnotation(HighlightSeverity.ERROR, message);
588 registerMakeAbstractMethodNotAbstractFix(builder, method, true, message, block.getTextRange()).create();
594 public void visitField(@NotNull GrField field) {
595 super.visitField(field);
596 if (field.getTypeElementGroovy() == null && field.getContainingClass() instanceof GrAnnotationTypeDefinition) {
597 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.field.should.have.type.declaration")).range(field.getNameIdentifierGroovy()).create();
599 checkInitializer(field);
602 private void checkInitializer(@NotNull GrField field) {
603 PsiExpression initializer = field.getInitializer();
604 if (initializer == null) return;
605 PsiClass containingClass = field.getContainingClass();
606 if (containingClass == null) return;
607 PsiAnnotation tupleConstructor = containingClass.getAnnotation(GroovyCommonClassNames.GROOVY_TRANSFORM_TUPLE_CONSTRUCTOR);
608 if (tupleConstructor == null) return;
609 if (!Boolean.FALSE.equals(GrAnnotationUtil.inferBooleanAttribute(tupleConstructor, "defaults"))) return;
610 List<String> excludes = GeneratedConstructorCollector.getIdentifierList(tupleConstructor, "excludes");
611 List<String> includes = GeneratedConstructorCollector.getIdentifierList(tupleConstructor, "includes");
612 if ((excludes != null && !excludes.contains(field.getName())) || (includes != null && includes.contains(field.getName()))) {
613 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("initializers.are.forbidden.with.defaults"))
620 public void visitMethod(@NotNull GrMethod method) {
621 checkDuplicateMethod(method);
622 checkMethodWithTypeParamsShouldHaveReturnType(myHolder, method);
623 checkInnerMethod(myHolder, method);
624 checkOptionalParametersInAbstractMethod(myHolder, method);
626 checkConstructorOfImmutableClass(myHolder, method);
627 checkGetterOfImmutable(myHolder, method);
629 final PsiElement nameIdentifier = method.getNameIdentifierGroovy();
630 if (GroovyTokenSets.STRING_LITERALS.contains(nameIdentifier.getNode().getElementType())) {
631 checkStringLiteral(nameIdentifier);
634 GrOpenBlock block = method.getBlock();
635 if (block != null && TypeInferenceHelper.isTooComplexTooAnalyze(block)) {
636 myHolder.newAnnotation(HighlightSeverity.WEAK_WARNING, GroovyBundle.message("method.0.is.too.complex.too.analyze", method.getName())).range(nameIdentifier).create();
639 final PsiClass containingClass = method.getContainingClass();
640 if (method.isConstructor()) {
641 if (containingClass instanceof GrAnonymousClassDefinition) {
642 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("constructors.are.not.allowed.in.anonymous.class")).range(nameIdentifier).create();
644 else if (containingClass != null && containingClass.isInterface()) {
645 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("constructors.are.not.allowed.in.interface")).range(nameIdentifier).create();
649 if (method.getBlock() == null && !method.hasModifierProperty(PsiModifier.NATIVE) && !GrTraitUtil.isMethodAbstract(method)) {
650 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("not.abstract.method.should.have.body")).range(nameIdentifier).create();
653 checkOverridingMethod(myHolder, method);
656 private static void checkGetterOfImmutable(AnnotationHolder holder, GrMethod method) {
657 if (!GroovyPropertyUtils.isSimplePropertyGetter(method)) return;
659 PsiClass aClass = method.getContainingClass();
660 if (aClass == null) return;
662 if (!GrImmutableUtils.hasImmutableAnnotation(aClass)) return;
664 PsiField field = GroovyPropertyUtils.findFieldForAccessor(method, false);
665 if (!(field instanceof GrField)) return;
667 GrModifierList fieldModifierList = ((GrField)field).getModifierList();
668 if (fieldModifierList == null) return;
670 if (fieldModifierList.hasExplicitVisibilityModifiers()) return;
672 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("repetitive.method.name.0", method.getName())).range(method.getNameIdentifierGroovy()).create();
675 private static void checkConstructorOfImmutableClass(AnnotationHolder holder, GrMethod method) {
676 if (!method.isConstructor()) return;
678 PsiClass aClass = method.getContainingClass();
679 if (aClass == null) return;
681 if (!GrImmutableUtils.hasImmutableAnnotation(aClass)) return;
683 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("explicit.constructors.are.not.allowed.in.immutable.class")).range(method.getNameIdentifierGroovy()).create();
686 private static void checkOverridingMethod(@NotNull AnnotationHolder holder, @NotNull GrMethod method) {
687 final List<HierarchicalMethodSignature> signatures = method.getHierarchicalMethodSignature().getSuperSignatures();
689 for (HierarchicalMethodSignature signature : signatures) {
690 final PsiMethod superMethod = signature.getMethod();
691 if (superMethod.hasModifierProperty(PsiModifier.FINAL)) {
693 final String current = GroovyPresentationUtil.getSignaturePresentation(method.getSignature(PsiSubstitutor.EMPTY));
694 final String superPresentation = GroovyPresentationUtil.getSignaturePresentation(signature);
695 final String superQName = getQNameOfMember(superMethod);
697 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("method.0.cannot.override.method.1.in.2.overridden.method.is.final", current, superPresentation, superQName)).range(GrHighlightUtil.getMethodHeaderTextRange(method)).create();
702 final String currentModifier = VisibilityUtil.getVisibilityModifier(method.getModifierList());
703 final String superModifier = VisibilityUtil.getVisibilityModifier(superMethod.getModifierList());
705 if (PsiModifier.PUBLIC.equals(superModifier) && (PsiModifier.PROTECTED.equals(currentModifier) || PsiModifier.PRIVATE
706 .equals(currentModifier)) ||
707 PsiModifier.PROTECTED.equals(superModifier) && PsiModifier.PRIVATE.equals(currentModifier)) {
708 final String currentPresentation = GroovyPresentationUtil.getSignaturePresentation(method.getSignature(PsiSubstitutor.EMPTY));
709 final String superPresentation = GroovyPresentationUtil.getSignaturePresentation(signature);
710 final String superQName = getQNameOfMember(superMethod);
712 //noinspection MagicConstant
713 final PsiElement modifier = method.getModifierList().getModifier(currentModifier);
714 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("method.0.cannot.have.weaker.access.privileges.1.than.2.in.3.4", currentPresentation, currentModifier, superPresentation, superQName, superModifier)).range(modifier != null ? modifier : method.getNameIdentifierGroovy()).create();
719 private static void checkMethodWithTypeParamsShouldHaveReturnType(AnnotationHolder holder, GrMethod method) {
720 final PsiTypeParameterList parameterList = method.getTypeParameterList();
721 if (parameterList != null) {
722 final GrTypeElement typeElement = method.getReturnTypeElementGroovy();
723 if (typeElement == null) {
724 final TextRange parameterListTextRange = parameterList.getTextRange();
725 final TextRange range = new TextRange(parameterListTextRange.getEndOffset(), parameterListTextRange.getEndOffset() + 1);
726 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("method.with.type.parameters.should.have.return.type")).range(range).create();
731 private static void checkOptionalParametersInAbstractMethod(AnnotationHolder holder, GrMethod method) {
732 if (!method.hasModifierProperty(PsiModifier.ABSTRACT)) return;
733 if (!(method.getContainingClass() instanceof GrInterfaceDefinition)) return;
735 for (GrParameter parameter : method.getParameters()) {
736 GrExpression initializerGroovy = parameter.getInitializerGroovy();
737 if (initializerGroovy != null) {
738 PsiElement assignOperator = parameter.getNameIdentifierGroovy();
739 TextRange textRange =
740 new TextRange(assignOperator.getTextRange().getEndOffset(), initializerGroovy.getTextRange().getEndOffset());
741 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("default.initializers.are.not.allowed.in.abstract.method")).range(textRange).create();
747 private static PsiMethod getDefaultConstructor(PsiClass clazz) {
748 final String className = clazz.getName();
749 if (className == null) return null;
750 final PsiMethod[] byName = clazz.findMethodsByName(className, true);
751 if (byName.length == 0) return null;
753 for (PsiMethod method : byName) {
754 if (method.getParameterList().isEmpty()) return method;
755 if (!(method instanceof GrMethod)) continue;
756 final GrParameter[] parameters = ((GrMethod)method).getParameterList().getParameters();
758 for (GrParameter parameter : parameters) {
759 if (!parameter.isOptional()) continue Outer;
768 public void visitVariable(@NotNull GrVariable variable) {
771 PsiElement parent = variable.getParent();
772 if (parent instanceof GrForInClause) {
773 PsiElement delimiter = ((GrForInClause)parent).getDelimiter();
774 if (delimiter.getNode().getElementType() == GroovyTokenTypes.mCOLON) {
775 GrTypeElement typeElement = variable.getTypeElementGroovy();
776 GrModifierList modifierList = variable.getModifierList();
777 if (modifierList != null && typeElement == null && StringUtil.isEmptyOrSpaces(modifierList.getText())) {
778 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle
779 .message("java.style.for.each.statement.requires.a.type.declaration")).range(variable.getNameIdentifierGroovy())
780 .withFix(new ReplaceDelimiterFix()).create();
786 PsiNamedElement duplicate = ResolveUtil.findDuplicate(variable);
789 if (duplicate instanceof GrVariable &&
790 (variable instanceof GrField || ResolveUtil.isScriptField(variable) || !(duplicate instanceof GrField))) {
791 final String key = duplicate instanceof GrField ? "field.already.defined" : "variable.already.defined";
792 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message(key, variable.getName())).range(variable.getNameIdentifierGroovy()).create();
795 PsiType type = variable.getDeclaredType();
796 if (type instanceof PsiEllipsisType && !isLastParameter(variable)) {
797 TextRange range = getEllipsisRange(variable);
799 range = getTypeRange(variable);
802 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("ellipsis.type.is.not.allowed.here")).range(range).create();
808 private static TextRange getEllipsisRange(GrVariable variable) {
809 if (variable instanceof GrParameter) {
810 final PsiElement dots = ((GrParameter)variable).getEllipsisDots();
812 return dots.getTextRange();
819 private static TextRange getTypeRange(GrVariable variable) {
820 GrTypeElement typeElement = variable.getTypeElementGroovy();
821 if (typeElement == null) return null;
823 PsiElement sibling = typeElement.getNextSibling();
824 if (sibling != null && sibling.getNode().getElementType() == GroovyTokenTypes.mTRIPLE_DOT) {
825 return new TextRange(typeElement.getTextRange().getStartOffset(), sibling.getTextRange().getEndOffset());
828 return typeElement.getTextRange();
832 private static boolean isLastParameter(PsiVariable variable) {
833 if (!(variable instanceof PsiParameter)) return false;
835 PsiElement parent = variable.getParent();
836 if (!(parent instanceof PsiParameterList)) return false;
838 PsiParameter[] parameters = ((PsiParameterList)parent).getParameters();
840 return parameters.length > 0 && parameters[parameters.length - 1] == variable;
843 private void checkName(GrVariable variable) {
844 if (!"$".equals(variable.getName())) return;
845 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("incorrect.variable.name")).range(variable.getNameIdentifierGroovy()).create();
849 public void visitAssignmentExpression(@NotNull GrAssignmentExpression expression) {
850 GrExpression lValue = expression.getLValue();
851 if (!PsiUtil.mightBeLValue(lValue)) {
852 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("invalid.lvalue")).range(lValue).create();
857 public void visitReturnStatement(@NotNull GrReturnStatement returnStatement) {
858 final GrExpression value = returnStatement.getReturnValue();
860 final PsiType type = value.getType();
862 final GrParameterListOwner owner = PsiTreeUtil.getParentOfType(returnStatement, GrParameterListOwner.class);
863 if (owner instanceof PsiMethod) {
864 final PsiMethod method = (PsiMethod)owner;
865 if (method.isConstructor()) {
866 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cannot.return.from.constructor")).range(value).create();
869 final PsiType methodType = method.getReturnType();
870 if (methodType != null) {
871 if (PsiType.VOID.equals(methodType)) {
872 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cannot.return.from.void.method")).range(value).create();
882 public void visitTypeParameterList(@NotNull GrTypeParameterList list) {
883 final PsiElement parent = list.getParent();
884 if (parent instanceof GrMethod && ((GrMethod)parent).isConstructor() ||
885 parent instanceof GrEnumTypeDefinition ||
886 parent instanceof GrAnnotationTypeDefinition) {
887 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("type.parameters.are.unexpected")).create();
892 public void visitListOrMap(@NotNull GrListOrMap listOrMap) {
893 final GroovyConstructorReference constructorReference = listOrMap.getConstructorReference();
894 if (constructorReference != null) {
895 final PsiElement lBracket = listOrMap.getLBrack();
896 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(lBracket).textAttributes(GroovySyntaxHighlighter.LITERAL_CONVERSION).create();
897 final PsiElement rBracket = listOrMap.getRBrack();
898 if (rBracket != null) {
899 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(rBracket).textAttributes(GroovySyntaxHighlighter.LITERAL_CONVERSION).create();
903 final GrNamedArgument[] namedArguments = listOrMap.getNamedArguments();
904 final GrExpression[] expressionArguments = listOrMap.getInitializers();
906 if (namedArguments.length != 0 && expressionArguments.length != 0) {
907 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("collection.literal.contains.named.argument.and.expression.items")).create();
910 checkNamedArgs(namedArguments, false);
914 public void visitClassTypeElement(@NotNull GrClassTypeElement typeElement) {
915 super.visitClassTypeElement(typeElement);
917 final GrCodeReferenceElement ref = typeElement.getReferenceElement();
918 final GrTypeArgumentList argList = ref.getTypeArgumentList();
919 if (argList == null) return;
921 final GrTypeElement[] elements = argList.getTypeArgumentElements();
922 for (GrTypeElement element : elements) {
923 checkTypeArgForPrimitive(element, GroovyBundle.message("primitive.type.parameters.are.not.allowed"));
928 public void visitCodeReferenceElement(@NotNull GrCodeReferenceElement refElement) {
929 if (refElement.getParent() instanceof GrAnnotation) {
930 PsiElement resolved = refElement.resolve();
931 if (resolved instanceof PsiClass && !((PsiClass)resolved).isAnnotationType() &&
932 GrAnnotationCollector.findAnnotationCollector((PsiClass)resolved) != null) {
933 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).textAttributes(GroovySyntaxHighlighter.ANNOTATION).create();
936 checkUnresolvedCodeReference(refElement, myHolder);
937 checkInnerClassReferenceFromInstanceContext(refElement, myHolder);
941 public void visitTypeElement(@NotNull GrTypeElement typeElement) {
942 final PsiElement parent = typeElement.getParent();
943 if (!(parent instanceof GrMethod)) return;
945 if (parent instanceof GrAnnotationMethod) {
946 checkAnnotationAttributeType(typeElement, myHolder);
948 else if (((GrMethod)parent).isConstructor()) {
949 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("constructors.cannot.have.return.type")).create();
952 checkMethodReturnType(((GrMethod)parent), typeElement, myHolder);
957 public void visitArrayTypeElement(@NotNull GrArrayTypeElement typeElement) {
958 GrTypeElement componentTypeElement = typeElement.getComponentTypeElement();
959 PsiType componentType = componentTypeElement.getType();
960 if (PsiType.VOID.equals(componentType)) {
961 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("illegal.type.void")).range(componentTypeElement).create();
964 super.visitArrayTypeElement(typeElement);
969 public void visitModifierList(@NotNull GrModifierList modifierList) {
970 final PsiElement parent = modifierList.getParent();
971 if (parent instanceof GrMethod) {
972 checkMethodDefinitionModifiers(myHolder, (GrMethod)parent);
974 else if (parent instanceof GrTypeDefinition) {
975 checkTypeDefinitionModifiers(myHolder, (GrTypeDefinition)parent);
977 else if (parent instanceof GrVariableDeclaration) {
978 GrVariableDeclaration declaration = (GrVariableDeclaration)parent;
979 if (isFieldDeclaration(declaration)) {
980 checkFieldModifiers(myHolder, declaration);
983 checkVariableModifiers(myHolder, declaration);
986 else if (parent instanceof GrClassInitializer) {
987 checkClassInitializerModifiers(myHolder, modifierList);
991 private static void checkClassInitializerModifiers(AnnotationHolder holder, GrModifierList modifierList) {
992 for (GrAnnotation annotation : modifierList.getAnnotations()) {
993 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("initializer.cannot.have.annotations")).range(annotation).create();
996 for (@GrModifier.GrModifierConstant String modifier : GrModifier.GROOVY_MODIFIERS) {
997 if (PsiModifier.STATIC.equals(modifier)) continue;
998 checkModifierIsNotAllowed(modifierList, modifier, GroovyBundle.message("initializer.cannot.be.0", modifier), holder);
1003 public void visitClassInitializer(@NotNull GrClassInitializer initializer) {
1004 final PsiClass aClass = initializer.getContainingClass();
1005 if (GrTraitUtil.isInterface(aClass)) {
1006 final TextRange range = GrHighlightUtil.getInitializerHeaderTextRange(initializer);
1007 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("initializers.are.not.allowed.in.interface")).range(range).create();
1011 private static void checkFieldModifiers(AnnotationHolder holder, GrVariableDeclaration fieldDeclaration) {
1012 GrVariable[] variables = fieldDeclaration.getVariables();
1013 if (variables.length == 0) return;
1015 GrVariable variable = variables[0];
1016 final GrField member = variable instanceof GrField ? (GrField)variable : findScriptField(variable);
1017 if (member == null) return;
1019 final GrModifierList modifierList = fieldDeclaration.getModifierList();
1021 checkAccessModifiers(holder, modifierList, member);
1022 checkDuplicateModifiers(holder, modifierList, member);
1024 if (modifierList.hasExplicitModifier(PsiModifier.VOLATILE) && modifierList.hasExplicitModifier(PsiModifier.FINAL)) {
1026 String message = GroovyBundle.message("illegal.combination.of.modifiers.volatile.and.final");
1027 AnnotationBuilder builder =
1028 holder.newAnnotation(HighlightSeverity.ERROR, message)
1029 .range(modifierList);
1030 builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.VOLATILE, true, false, GrModifierFix.MODIFIER_LIST), modifierList,
1031 message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1032 builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.FINAL, true, false, GrModifierFix.MODIFIER_LIST), modifierList,
1033 message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1037 if (member.getContainingClass() instanceof GrInterfaceDefinition) {
1038 checkModifierIsNotAllowed(modifierList,
1039 PsiModifier.PRIVATE, GroovyBundle.message("interface.members.are.not.allowed.to.be", PsiModifier.PRIVATE), holder);
1040 checkModifierIsNotAllowed(modifierList, PsiModifier.PROTECTED, GroovyBundle.message("interface.members.are.not.allowed.to.be",
1041 PsiModifier.PROTECTED),
1046 private static void checkAnnotationAttributeType(GrTypeElement element, AnnotationHolder holder) {
1047 if (element instanceof GrBuiltInTypeElement) return;
1049 if (element instanceof GrArrayTypeElement) {
1050 checkAnnotationAttributeType(((GrArrayTypeElement)element).getComponentTypeElement(), holder);
1053 else if (element instanceof GrClassTypeElement) {
1054 final PsiElement resolved = ((GrClassTypeElement)element).getReferenceElement().resolve();
1055 if (resolved instanceof PsiClass) {
1056 if (CommonClassNames.JAVA_LANG_STRING.equals(((PsiClass)resolved).getQualifiedName())) return;
1057 if (CommonClassNames.JAVA_LANG_CLASS.equals(((PsiClass)resolved).getQualifiedName())) return;
1058 if (((PsiClass)resolved).isAnnotationType()) return;
1059 if (((PsiClass)resolved).isEnum()) return;
1063 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("unexpected.attribute.type.0", element.getType())).range(element).create();
1066 static void checkMethodReturnType(PsiMethod method, PsiElement toHighlight, AnnotationHolder holder) {
1067 final HierarchicalMethodSignature signature = method.getHierarchicalMethodSignature();
1068 final List<HierarchicalMethodSignature> superSignatures = signature.getSuperSignatures();
1070 PsiType returnType = signature.getSubstitutor().substitute(method.getReturnType());
1072 for (HierarchicalMethodSignature superMethodSignature : superSignatures) {
1073 PsiMethod superMethod = superMethodSignature.getMethod();
1074 PsiType declaredReturnType = superMethod.getReturnType();
1075 PsiType superReturnType = superMethodSignature.getSubstitutor().substitute(declaredReturnType);
1076 if (PsiType.VOID.equals(superReturnType) && method instanceof GrMethod && ((GrMethod)method).getReturnTypeElementGroovy() == null) return;
1077 if (superMethodSignature.isRaw()) superReturnType = TypeConversionUtil.erasure(declaredReturnType);
1078 if (returnType == null || superReturnType == null || method == superMethod) continue;
1079 PsiClass superClass = superMethod.getContainingClass();
1080 if (superClass == null) continue;
1081 String highlightInfo = checkSuperMethodSignature(superMethod, superMethodSignature, superReturnType, method, signature, returnType);
1082 if (highlightInfo != null) {
1083 holder.newAnnotation(HighlightSeverity.ERROR, highlightInfo).range(toHighlight).create();
1090 private static String checkSuperMethodSignature(@NotNull PsiMethod superMethod,
1091 @NotNull MethodSignatureBackedByPsiMethod superMethodSignature,
1092 @NotNull PsiType superReturnType,
1093 @NotNull PsiMethod method,
1094 @NotNull MethodSignatureBackedByPsiMethod methodSignature,
1095 @NotNull PsiType returnType) {
1096 PsiType substitutedSuperReturnType = substituteSuperReturnType(superMethodSignature, methodSignature, superReturnType);
1098 if (returnType.equals(substitutedSuperReturnType)) return null;
1100 final PsiType rawReturnType = TypeConversionUtil.erasure(returnType);
1101 final PsiType rawSuperReturnType = TypeConversionUtil.erasure(substitutedSuperReturnType);
1103 if (returnType instanceof PsiClassType && substitutedSuperReturnType instanceof PsiClassType) {
1104 if (TypeConversionUtil.isAssignable(rawSuperReturnType, rawReturnType)) {
1108 else if (returnType instanceof PsiArrayType && superReturnType instanceof PsiArrayType) {
1109 if (rawReturnType.equals(rawSuperReturnType)) {
1114 String qName = getQNameOfMember(method);
1115 String baseQName = getQNameOfMember(superMethod);
1116 final String presentation = returnType.getCanonicalText() + " " + GroovyPresentationUtil.getSignaturePresentation(methodSignature);
1117 final String basePresentation =
1118 superReturnType.getCanonicalText() + " " + GroovyPresentationUtil.getSignaturePresentation(superMethodSignature);
1119 return GroovyBundle.message("return.type.is.incompatible", presentation, qName, basePresentation, baseQName);
1123 private static PsiType substituteSuperReturnType(@NotNull MethodSignatureBackedByPsiMethod superMethodSignature,
1124 @NotNull MethodSignatureBackedByPsiMethod methodSignature,
1125 @NotNull PsiType superReturnType) {
1126 PsiType substitutedSuperReturnType;
1127 if (!superMethodSignature.isRaw() && superMethodSignature.equals(methodSignature)) { //see 8.4.5
1128 PsiSubstitutor unifyingSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature,
1129 superMethodSignature);
1130 substitutedSuperReturnType = unifyingSubstitutor == null
1132 : unifyingSubstitutor.substitute(superMethodSignature.getSubstitutor().substitute(superReturnType));
1135 substitutedSuperReturnType = TypeConversionUtil.erasure(superReturnType);
1137 return substitutedSuperReturnType;
1141 private static String getQNameOfMember(@NotNull PsiMember member) {
1142 final PsiClass aClass = member.getContainingClass();
1143 return getQName(aClass);
1147 private static String getQName(@Nullable PsiClass aClass) {
1148 if (aClass instanceof PsiAnonymousClass) {
1149 return GroovyBundle.message("anonymous.class.derived.from.0", ((PsiAnonymousClass)aClass).getBaseClassType().getCanonicalText());
1151 if (aClass != null) {
1152 final String qname = aClass.getQualifiedName();
1153 if (qname != null) {
1161 private void checkTypeArgForPrimitive(@Nullable GrTypeElement element, @NotNull String message) {
1162 if (element == null || !(element.getType() instanceof PsiPrimitiveType)) return;
1164 AnnotationBuilder builder = myHolder.newAnnotation(HighlightSeverity.ERROR, message).range(element);
1165 builder = registerLocalFix(builder, new GrReplacePrimitiveTypeWithWrapperFix(element), element, message, ProblemHighlightType.ERROR,
1166 element.getTextRange());
1171 public void visitWildcardTypeArgument(@NotNull GrWildcardTypeArgument wildcardTypeArgument) {
1172 super.visitWildcardTypeArgument(wildcardTypeArgument);
1174 checkTypeArgForPrimitive(wildcardTypeArgument.getBoundTypeElement(), GroovyBundle.message("primitive.bound.types.are.not.allowed"));
1177 private void highlightNamedArgs(GrNamedArgument[] namedArguments) {
1178 for (GrNamedArgument namedArgument : namedArguments) {
1179 final GrArgumentLabel label = namedArgument.getLabel();
1180 if (label != null && label.getExpression() == null && label.getNameElement().getNode().getElementType() != GroovyTokenTypes.mSTAR) {
1181 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(label).textAttributes(GroovySyntaxHighlighter.MAP_KEY).create();
1186 private void checkNamedArgs(GrNamedArgument[] namedArguments, boolean forArgList) {
1187 highlightNamedArgs(namedArguments);
1189 Set<Object> existingKeys = new HashSet<>();
1190 for (GrNamedArgument namedArgument : namedArguments) {
1191 GrArgumentLabel label = namedArgument.getLabel();
1192 Object value = PsiUtil.getLabelValue(label);
1193 if (value == null) continue;
1194 if (value == ObjectUtils.NULL) value = null;
1195 if (existingKeys.add(value)) continue;
1197 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("duplicated.named.parameter", String.valueOf(value))).range(label).create();
1200 myHolder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle.message("duplicate.element.in.the.map", String.valueOf(value))).range(label).create();
1206 public void visitNewExpression(@NotNull GrNewExpression newExpression) {
1207 GrTypeArgumentList constructorTypeArguments = newExpression.getConstructorTypeArguments();
1208 if (constructorTypeArguments != null) {
1209 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("groovy.does.not.support.constructor.type.arguments")).range(constructorTypeArguments).create();
1212 final GrTypeElement typeElement = newExpression.getTypeElement();
1214 if (typeElement instanceof GrBuiltInTypeElement) {
1215 if (newExpression.getArrayCount() == 0) {
1216 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("create.instance.of.built-in.type")).range(typeElement).create();
1220 if (newExpression.getArrayCount() > 0) return;
1222 GrCodeReferenceElement refElement = newExpression.getReferenceElement();
1223 if (refElement == null) return;
1225 final PsiElement element = refElement.resolve();
1226 if (element instanceof PsiClass) {
1227 PsiClass clazz = (PsiClass)element;
1228 if (clazz.hasModifierProperty(PsiModifier.ABSTRACT)) {
1229 if (newExpression.getAnonymousClassDefinition() == null) {
1230 String message = clazz.isInterface()
1231 ? GroovyBundle.message("cannot.instantiate.interface", clazz.getName())
1232 : GroovyBundle.message("cannot.instantiate.abstract.class", clazz.getName());
1233 myHolder.newAnnotation(HighlightSeverity.ERROR, message).range(refElement).create();
1240 public void visitArgumentList(@NotNull GrArgumentList list) {
1241 checkNamedArgs(list.getNamedArguments(), true);
1245 public void visitBreakStatement(@NotNull GrBreakStatement breakStatement) {
1246 checkFlowInterruptStatement(breakStatement, myHolder);
1250 public void visitContinueStatement(@NotNull GrContinueStatement continueStatement) {
1251 checkFlowInterruptStatement(continueStatement, myHolder);
1255 public void visitPackageDefinition(@NotNull GrPackageDefinition packageDefinition) {
1256 final GrModifierList modifierList = packageDefinition.getAnnotationList();
1257 checkAnnotationList(myHolder, modifierList, GroovyBundle.message("package.definition.cannot.have.modifiers"));
1261 public void visitLambdaExpression(@NotNull GrLambdaExpression expression) {
1262 super.visitLambdaExpression(expression);
1264 PsiElement arrow = expression.getArrow();
1265 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(arrow).textAttributes(GroovySyntaxHighlighter.LAMBDA_ARROW_AND_BRACES).create();
1269 public void visitBlockLambdaBody(@NotNull GrBlockLambdaBody body) {
1270 super.visitBlockLambdaBody(body);
1272 PsiElement lBrace = body.getLBrace();
1273 if (lBrace != null) {
1274 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(lBrace).textAttributes(GroovySyntaxHighlighter.LAMBDA_ARROW_AND_BRACES).create();
1277 PsiElement rBrace = body.getRBrace();
1278 if (rBrace != null) {
1279 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(rBrace).textAttributes(GroovySyntaxHighlighter.LAMBDA_ARROW_AND_BRACES).create();
1284 public void visitClosure(@NotNull GrClosableBlock closure) {
1285 super.visitClosure(closure);
1287 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(closure.getLBrace()).textAttributes(GroovySyntaxHighlighter.CLOSURE_ARROW_AND_BRACES).create();
1288 PsiElement rBrace = closure.getRBrace();
1289 if (rBrace != null) {
1290 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(rBrace).textAttributes(GroovySyntaxHighlighter.CLOSURE_ARROW_AND_BRACES).create();
1292 PsiElement closureArrow = closure.getArrow();
1293 if (closureArrow != null) {
1294 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(closureArrow).textAttributes(GroovySyntaxHighlighter.CLOSURE_ARROW_AND_BRACES).create();
1297 if (TypeInferenceHelper.isTooComplexTooAnalyze(closure)) {
1298 int startOffset = closure.getTextRange().getStartOffset();
1300 PsiElement arrow = closure.getArrow();
1301 if (arrow != null) {
1302 endOffset = arrow.getTextRange().getEndOffset();
1305 Document document = PsiDocumentManager.getInstance(closure.getProject()).getDocument(closure.getContainingFile());
1306 if (document == null) return;
1307 String text = document.getText();
1308 endOffset = Math.min(closure.getTextRange().getEndOffset(), text.indexOf('\n', startOffset));
1310 myHolder.newAnnotation(HighlightSeverity.WEAK_WARNING, GroovyBundle.message("closure.is.too.complex.to.analyze")).range(new TextRange(startOffset, endOffset)).create();
1315 public void visitLiteralExpression(@NotNull GrLiteral literal) {
1316 final IElementType elementType = literal.getFirstChild().getNode().getElementType();
1317 if (GroovyTokenSets.STRING_LITERALS.contains(elementType)) {
1318 checkStringLiteral(literal);
1320 else if (elementType == GroovyTokenTypes.mREGEX_LITERAL || elementType == GroovyTokenTypes.mDOLLAR_SLASH_REGEX_LITERAL) {
1321 checkRegexLiteral(literal.getFirstChild());
1326 public void visitRegexExpression(@NotNull GrRegex regex) {
1327 checkRegexLiteral(regex);
1330 private void checkRegexLiteral(PsiElement regex) {
1332 if (regex instanceof GrRegex) {
1333 parts = ((GrRegex)regex).getTextParts();
1336 parts = new String[]{regex.getFirstChild().getNextSibling().getText()};
1339 for (String part : parts) {
1340 if (!GrStringUtil.parseRegexCharacters(part, new StringBuilder(part.length()), null, regex.getText().startsWith("/"))) {
1341 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("illegal.escape.character.in.string.literal")).range(regex).create();
1348 public void visitGStringExpression(@NotNull GrString gstring) {
1349 for (GrStringContent part : gstring.getContents()) {
1350 final String text = part.getText();
1351 if (!GrStringUtil.parseStringCharacters(text, new StringBuilder(text.length()), null)) {
1352 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("illegal.escape.character.in.string.literal")).range(part).create();
1360 public void visitGStringInjection(@NotNull GrStringInjection injection) {
1361 if (((GrString)injection.getParent()).isPlainString()) {
1362 PsiElement lineFeed = getLineFeed(injection);
1363 if (lineFeed != null) {
1364 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("injection.should.not.contain.line.feeds"))
1371 private void checkStringLiteral(PsiElement literal) {
1372 InjectedLanguageManager injectedLanguageManager = InjectedLanguageManager.getInstance(literal.getProject());
1374 if (injectedLanguageManager.isInjectedFragment(literal.getContainingFile())) {
1375 text = injectedLanguageManager.getUnescapedText(literal);
1378 text = literal.getText();
1380 assert text != null;
1382 StringBuilder builder = new StringBuilder(text.length());
1383 String quote = GrStringUtil.getStartQuote(text);
1384 if (quote.isEmpty()) return;
1386 String substring = text.substring(quote.length());
1387 if (!GrStringUtil.parseStringCharacters(substring, new StringBuilder(text.length()), null)) {
1388 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("illegal.escape.character.in.string.literal")).range(literal).create();
1392 int[] offsets = new int[substring.length() + 1];
1393 boolean result = GrStringUtil.parseStringCharacters(substring, builder, offsets);
1394 LOG.assertTrue(result);
1395 if (!builder.toString().endsWith(quote) || substring.charAt(offsets[builder.length() - quote.length()]) == '\\') {
1396 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("string.end.expected")).create();
1401 public void visitForInClause(@NotNull GrForInClause forInClause) {
1402 final GrVariable var = forInClause.getDeclaredVariable();
1403 if (var == null) return;
1404 final GrModifierList modifierList = var.getModifierList();
1405 if (modifierList == null) return;
1406 final PsiElement[] modifiers = modifierList.getModifiers();
1407 for (PsiElement modifier : modifiers) {
1408 if (modifier instanceof PsiAnnotation) continue;
1409 final String modifierText = modifier.getText();
1410 if (PsiModifier.FINAL.equals(modifierText)) continue;
1411 if (GrModifier.DEF.equals(modifierText)) continue;
1412 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("not.allowed.modifier.in.for.in", modifierText)).range(modifier).create();
1417 public void visitFile(@NotNull GroovyFileBase file) {
1418 final PsiClass scriptClass = file.getScriptClass();
1419 if (scriptClass != null) {
1420 checkSameNameMethodsWithDifferentAccessModifiers(myHolder, file.getMethods());
1426 public void visitAnnotation(@NotNull GrAnnotation annotation) {
1427 AnnotationChecker.checkApplicability(annotation, annotation.getOwner(), myHolder, annotation.getClassReference());
1431 public void visitAnnotationArgumentList(@NotNull GrAnnotationArgumentList annotationArgumentList) {
1432 GrAnnotation parent = (GrAnnotation)annotationArgumentList.getParent();
1433 Pair<PsiElement, String> r = AnnotationChecker.checkAnnotationArgumentList(parent, myHolder);
1434 if (r != null && r.getFirst() != null && r.getSecond() != null) {
1435 myHolder.newAnnotation(HighlightSeverity.ERROR, r.getSecond()).range(r.getFirst()).create();
1440 public void visitAnnotationMethod(@NotNull GrAnnotationMethod annotationMethod) {
1441 super.visitAnnotationMethod(annotationMethod);
1443 final PsiReferenceList list = annotationMethod.getThrowsList();
1444 if (list.getReferencedTypes().length > 0) {
1445 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("throws.clause.is.not.allowed.in.at.interface")).range(list).create();
1448 final GrAnnotationMemberValue value = annotationMethod.getDefaultValue();
1449 if (value == null) return;
1451 final PsiType type = annotationMethod.getReturnType();
1453 Pair.NonNull<PsiElement, String> result = CustomAnnotationChecker.checkAnnotationValueByType(value, type, false);
1454 if (result != null) {
1455 myHolder.newAnnotation(HighlightSeverity.ERROR, result.getSecond()).range(result.getFirst()).create();
1460 public void visitAnnotationNameValuePair(@NotNull GrAnnotationNameValuePair nameValuePair) {
1461 final PsiElement identifier = nameValuePair.getNameIdentifierGroovy();
1462 if (identifier == null) {
1463 final PsiElement parent = nameValuePair.getParent();
1464 if (parent instanceof GrAnnotationArgumentList) {
1465 final int count = ((GrAnnotationArgumentList)parent).getAttributes().length;
1467 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("attribute.name.expected")).create();
1472 final GrAnnotationMemberValue value = nameValuePair.getValue();
1473 if (value != null) {
1474 checkAnnotationAttributeValue(value, value);
1478 private boolean checkAnnotationAttributeValue(@Nullable GrAnnotationMemberValue value, @NotNull PsiElement toHighlight) {
1479 if (value == null) return false;
1481 if (value instanceof GrLiteral) return false;
1482 if (value instanceof GrFunctionalExpression) return false;
1483 if (value instanceof GrAnnotation) return false;
1485 if (value instanceof GrReferenceExpression) {
1486 PsiElement resolved = ((GrReferenceExpression)value).resolve();
1487 if (resolved instanceof PsiClass) return false;
1488 if (resolved instanceof PsiEnumConstant) return false;
1489 if (resolved == null && isClassReference(value)) return false;
1491 if (resolved instanceof GrAccessorMethod) resolved = ((GrAccessorMethod)resolved).getProperty();
1492 if (resolved instanceof PsiField) {
1493 GrExpression initializer;
1495 if (resolved instanceof GrField) {
1496 initializer = ((GrField)resolved).getInitializerGroovy();
1499 final PsiExpression _initializer = ((PsiField)resolved).getInitializer();
1500 initializer = _initializer != null
1501 ? (GrExpression)ExpressionConverter.getExpression(_initializer, GroovyLanguage.INSTANCE, value.getProject())
1505 catch (IncorrectOperationException e) {
1509 if (initializer != null) {
1510 return checkAnnotationAttributeValue(initializer, toHighlight);
1514 if (value instanceof GrAnnotationArrayInitializer) {
1515 for (GrAnnotationMemberValue expression : ((GrAnnotationArrayInitializer)value).getInitializers()) {
1516 if (checkAnnotationAttributeValue(expression, toHighlight)) return true;
1520 if (value instanceof GrUnaryExpression) {
1521 final IElementType tokenType = ((GrUnaryExpression)value).getOperationTokenType();
1522 if (tokenType == GroovyTokenTypes.mMINUS || tokenType == GroovyTokenTypes.mPLUS) {
1523 return checkAnnotationAttributeValue(((GrUnaryExpression)value).getOperand(), toHighlight);
1527 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("expected.0.to.be.inline.constant", value.getText())).range(toHighlight).create();
1531 private static boolean isClassReference(GrAnnotationMemberValue value) {
1532 if (value instanceof GrReferenceExpression) {
1533 final String referenceName = ((GrReferenceExpression)value).getReferenceName();
1534 if ("class".equals(referenceName)) {
1535 final GrExpression qualifier = ((GrReferenceExpression)value).getQualifier();
1536 if (qualifier instanceof GrReferenceExpression) {
1537 final PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
1538 if (resolved instanceof PsiClass) {
1549 public void visitImportStatement(@NotNull GrImportStatement importStatement) {
1550 checkAnnotationList(myHolder, importStatement.getAnnotationList(), GroovyBundle.message("import.statement.cannot.have.modifiers"));
1554 public void visitExtendsClause(@NotNull GrExtendsClause extendsClause) {
1555 GrTypeDefinition typeDefinition = (GrTypeDefinition)extendsClause.getParent();
1557 if (typeDefinition.isAnnotationType()) {
1558 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.types.may.not.have.extends.clause")).create();
1560 else if (typeDefinition.isTrait()) {
1561 checkReferenceList(myHolder, extendsClause, IS_TRAIT, GroovyBundle.message("only.traits.expected.here"), null);
1563 else if (typeDefinition.isInterface()) {
1564 checkReferenceList(myHolder, extendsClause, IS_INTERFACE, GroovyBundle.message("no.class.expected.here"), null);
1566 else if (typeDefinition.isEnum()) {
1567 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("enums.may.not.have.extends.clause")).create();
1570 checkReferenceList(myHolder, extendsClause, IS_NOT_INTERFACE, GroovyBundle.message("no.interface.expected.here"), new ChangeExtendsImplementsQuickFix(typeDefinition));
1571 checkForWildCards(myHolder, extendsClause);
1577 public void visitImplementsClause(@NotNull GrImplementsClause implementsClause) {
1578 GrTypeDefinition typeDefinition = (GrTypeDefinition)implementsClause.getParent();
1580 if (typeDefinition.isAnnotationType()) {
1581 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.types.may.not.have.implements.clause")).create();
1583 else if (GrTraitUtil.isInterface(typeDefinition)) {
1584 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("no.implements.clause.allowed.for.interface"))
1585 .withFix(new ChangeExtendsImplementsQuickFix(typeDefinition)).create();
1588 checkReferenceList(myHolder, implementsClause, IS_INTERFACE, GroovyBundle.message("no.class.expected.here"), new ChangeExtendsImplementsQuickFix(typeDefinition));
1589 checkForWildCards(myHolder, implementsClause);
1593 private static void checkReferenceList(@NotNull AnnotationHolder holder,
1594 @NotNull GrReferenceList list,
1595 @NotNull Condition<? super PsiClass> applicabilityCondition,
1596 @NotNull String message,
1597 @Nullable IntentionAction fix) {
1598 for (GrCodeReferenceElement refElement : list.getReferenceElementsGroovy()) {
1599 final PsiElement psiClass = refElement.resolve();
1600 if (psiClass instanceof PsiClass && !applicabilityCondition.value((PsiClass)psiClass)) {
1601 AnnotationBuilder builder = holder.newAnnotation(HighlightSeverity.ERROR, message).range(refElement);
1603 builder = builder.withFix(fix);
1610 private static void checkFlowInterruptStatement(GrFlowInterruptingStatement statement, AnnotationHolder holder) {
1611 final PsiElement label = statement.getLabelIdentifier();
1613 if (label != null) {
1614 final GrLabeledStatement resolved = statement.resolveLabel();
1615 if (resolved == null) {
1616 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("undefined.label", statement.getLabelName())).range(label).create();
1620 final GrStatement targetStatement = statement.findTargetStatement();
1621 if (targetStatement == null) {
1622 if (statement instanceof GrContinueStatement && label == null) {
1623 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("continue.outside.loop")).create();
1625 else if (statement instanceof GrBreakStatement && label == null) {
1626 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("break.outside.loop.or.switch")).create();
1629 if (statement instanceof GrBreakStatement && label != null && findFirstLoop(statement) == null) {
1630 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("break.outside.loop")).create();
1635 private static GrLoopStatement findFirstLoop(GrFlowInterruptingStatement statement) {
1636 return PsiTreeUtil.getParentOfType(statement, GrLoopStatement.class, true, GrClosableBlock.class, GrMember.class, GroovyFile.class);
1639 private static void checkThisOrSuperReferenceExpression(final GrReferenceExpression ref, AnnotationHolder holder) {
1640 PsiElement nameElement = ref.getReferenceNameElement();
1641 if (nameElement == null) return;
1643 IElementType elementType = nameElement.getNode().getElementType();
1644 if (!(elementType == GroovyTokenTypes.kSUPER || elementType == GroovyTokenTypes.kTHIS)) return;
1646 final GrExpression qualifier = ref.getQualifier();
1647 if (qualifier instanceof GrReferenceExpression) {
1648 final PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
1649 if (resolved instanceof PsiClass) {
1650 GrTypeDefinition containingClass = PsiTreeUtil.getParentOfType(ref, GrTypeDefinition.class, true, GroovyFile.class);
1652 if (elementType == GroovyTokenTypes.kSUPER && containingClass != null && GrTraitUtil.isTrait((PsiClass)resolved)) {
1653 PsiClassType[] superTypes = containingClass.getSuperTypes();
1654 if (ContainerUtil.find(superTypes, type -> ref.getManager().areElementsEquivalent(type.resolve(), resolved)) != null) {
1655 holder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(nameElement).textAttributes(GroovySyntaxHighlighter.KEYWORD).create();
1656 return; // reference to trait method
1660 if (containingClass == null || containingClass.getContainingClass() == null && !containingClass.isAnonymous()) {
1661 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("qualified.0.is.allowed.only.in.nested.or.inner.classes",
1662 nameElement.getText())).create();
1666 if (!PsiTreeUtil.isAncestor(resolved, ref, true)) {
1667 String qname = ((PsiClass)resolved).getQualifiedName();
1668 assert qname != null;
1669 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("is.not.enclosing.class", qname)).create();
1673 else if (qualifier == null) {
1674 if (elementType == GroovyTokenTypes.kSUPER) {
1675 final GrMember container = PsiTreeUtil.getParentOfType(ref, GrMethod.class, GrClassInitializer.class);
1676 if (container != null && container.hasModifierProperty(PsiModifier.STATIC)) {
1677 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("super.cannot.be.used.in.static.context")).create();
1683 private static void checkGrDocReferenceElement(AnnotationHolder holder, PsiElement element) {
1684 ASTNode node = element.getNode();
1685 if (node != null && TokenSets.BUILT_IN_TYPES.contains(node.getElementType())) {
1686 holder.newSilentAnnotation(HighlightSeverity.INFORMATION).textAttributes(GroovySyntaxHighlighter.KEYWORD).create();
1690 private static void checkAnnotationList(AnnotationHolder holder, @NotNull GrModifierList modifierList, @NotNull String message) {
1691 final PsiElement[] modifiers = modifierList.getModifiers();
1692 for (PsiElement modifier : modifiers) {
1693 if (!(modifier instanceof PsiAnnotation)) {
1694 holder.newAnnotation(HighlightSeverity.ERROR, message).range(modifier).create();
1699 private static void checkImplementedMethodsOfClass(AnnotationHolder holder, GrTypeDefinition typeDefinition) {
1700 if (typeDefinition.hasModifierProperty(PsiModifier.ABSTRACT)) return;
1701 if (typeDefinition.isAnnotationType()) return;
1702 if (typeDefinition instanceof GrTypeParameter) return;
1705 PsiMethod abstractMethod = ClassUtil.getAnyAbstractMethod(typeDefinition);
1706 if (abstractMethod == null) return;
1708 String notImplementedMethodName = abstractMethod.getName();
1710 final TextRange range = GrHighlightUtil.getClassHeaderTextRange(typeDefinition);
1711 String message = GroovyBundle.message("method.is.not.implemented", notImplementedMethodName);
1712 AnnotationBuilder builder =
1713 holder.newAnnotation(HighlightSeverity.ERROR, message)
1715 registerImplementsMethodsFix(typeDefinition, abstractMethod, builder, message, range).create();
1718 @Contract(pure = true)
1719 private static AnnotationBuilder registerImplementsMethodsFix(@NotNull GrTypeDefinition typeDefinition,
1720 @NotNull PsiMethod abstractMethod,
1721 @NotNull AnnotationBuilder builder,
1724 if (!OverrideImplementExploreUtil.getMethodsToOverrideImplement(typeDefinition, true).isEmpty()) {
1725 builder = builder.withFix(QuickFixFactory.getInstance().createImplementMethodsFix(typeDefinition));
1728 if (!JavaPsiFacade.getInstance(typeDefinition.getProject()).getResolveHelper().isAccessible(abstractMethod, typeDefinition, null)) {
1729 builder = registerLocalFix(builder, new GrModifierFix(abstractMethod, PsiModifier.PUBLIC, true, true, GrModifierFix.MODIFIER_LIST_OWNER), abstractMethod,
1730 message, ProblemHighlightType.ERROR, range);
1731 builder = registerLocalFix(builder, new GrModifierFix(abstractMethod, PsiModifier.PROTECTED, true, true, GrModifierFix.MODIFIER_LIST_OWNER), abstractMethod,
1732 message, ProblemHighlightType.ERROR, range);
1735 if (!(typeDefinition instanceof GrAnnotationTypeDefinition) && typeDefinition.getModifierList() != null) {
1736 builder = registerLocalFix(builder, new GrModifierFix(typeDefinition, PsiModifier.ABSTRACT, false, true, GrModifierFix.MODIFIER_LIST_OWNER), typeDefinition,
1737 message, ProblemHighlightType.ERROR, range);
1742 private static void checkInnerMethod(AnnotationHolder holder, GrMethod grMethod) {
1743 final PsiElement parent = grMethod.getParent();
1744 if (parent instanceof GrOpenBlock || parent instanceof GrClosableBlock || parent instanceof GrBlockLambdaBody) {
1745 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("Inner.methods.are.not.supported")).range(grMethod.getNameIdentifierGroovy()).create();
1750 @Contract(pure=true)
1751 private static AnnotationBuilder registerMakeAbstractMethodNotAbstractFix(AnnotationBuilder builder,
1753 boolean makeClassAbstract,
1754 String message, TextRange range) {
1755 if (method.getBlock() == null) {
1756 builder = builder.withFix(QuickFixFactory.getInstance().createAddMethodBodyFix(method));
1759 builder = builder.withFix(QuickFixFactory.getInstance().createDeleteMethodBodyFix(method));
1762 GrModifierFix fix = new GrModifierFix(method, PsiModifier.ABSTRACT, false, false, GrModifierFix.MODIFIER_LIST_OWNER);
1763 builder = registerLocalFix(builder, fix, method, message, ProblemHighlightType.ERROR, range);
1764 if (makeClassAbstract) {
1765 final PsiClass containingClass = method.getContainingClass();
1766 if (containingClass != null) {
1767 final PsiModifierList list = containingClass.getModifierList();
1768 if (list != null && !list.hasModifierProperty(PsiModifier.ABSTRACT)) {
1769 builder = registerLocalFix(builder, new GrModifierFix(containingClass, PsiModifier.ABSTRACT, false, true, GrModifierFix.MODIFIER_LIST_OWNER), containingClass, message, ProblemHighlightType.ERROR, range);
1776 private static void checkMethodDefinitionModifiers(AnnotationHolder holder, GrMethod method) {
1777 final GrModifierList modifiersList = method.getModifierList();
1778 checkAccessModifiers(holder, modifiersList, method);
1779 checkDuplicateModifiers(holder, modifiersList, method);
1780 checkOverrideAnnotation(holder, modifiersList, method);
1782 checkModifierIsNotAllowed(modifiersList, PsiModifier.VOLATILE, GroovyBundle.message("method.has.incorrect.modifier.volatile"), holder);
1784 checkForAbstractAndFinalCombination(holder, method, modifiersList);
1787 boolean isMethodAbstract = modifiersList.hasExplicitModifier(PsiModifier.ABSTRACT);
1788 PsiElement modifierOrList = getModifierOrList(modifiersList, PsiModifier.ABSTRACT);
1789 if (method.getParent() instanceof GroovyFileBase) {
1790 if (isMethodAbstract) {
1791 String message = GroovyBundle.message("script.method.cannot.have.modifier.abstract");
1792 AnnotationBuilder builder =
1793 holder.newAnnotation(HighlightSeverity.ERROR, message)
1794 .range(modifierOrList);
1795 registerMakeAbstractMethodNotAbstractFix(builder, method, false, message, modifierOrList.getTextRange()).create();
1798 checkModifierIsNotAllowed(modifiersList, PsiModifier.NATIVE, GroovyBundle.message("script.cannot.have.modifier.native"), holder);
1800 //type definition methods
1801 else if (method.getParent() != null && method.getParent().getParent() instanceof GrTypeDefinition) {
1802 GrTypeDefinition containingTypeDef = ((GrTypeDefinition)method.getParent().getParent());
1804 if (containingTypeDef.isTrait()) {
1805 checkModifierIsNotAllowed(modifiersList, PsiModifier.PROTECTED, GroovyBundle.message("trait.method.cannot.be.protected"), holder);
1808 else if (containingTypeDef.isInterface()) {
1809 checkModifierIsNotAllowed(modifiersList, PsiModifier.STATIC, GroovyBundle.message("interface.must.have.no.static.method"), holder);
1810 checkModifierIsNotAllowed(modifiersList, PsiModifier.PRIVATE, GroovyBundle.message("interface.members.are.not.allowed.to.be", PsiModifier.PRIVATE), holder);
1811 checkModifierIsNotAllowed(modifiersList, PsiModifier.PROTECTED, GroovyBundle.message("interface.members.are.not.allowed.to.be", PsiModifier.PROTECTED), holder);
1813 else if (containingTypeDef.isAnonymous()) {
1814 if (isMethodAbstract) {
1815 String message = GroovyBundle.message("anonymous.class.cannot.have.abstract.method");
1816 AnnotationBuilder builder =
1817 holder.newAnnotation(HighlightSeverity.ERROR, message).range(
1819 registerMakeAbstractMethodNotAbstractFix(builder, method, false, message, modifierOrList.getTextRange()).create();
1824 PsiModifierList typeDefModifiersList = containingTypeDef.getModifierList();
1825 LOG.assertTrue(typeDefModifiersList != null, "modifiers list must be not null");
1827 if (!typeDefModifiersList.hasModifierProperty(PsiModifier.ABSTRACT) && isMethodAbstract) {
1829 String message = GroovyBundle.message("only.abstract.class.can.have.abstract.method");
1830 AnnotationBuilder builder =
1831 holder.newAnnotation(HighlightSeverity.ERROR, message)
1832 .range(modifiersList);
1833 registerMakeAbstractMethodNotAbstractFix(builder, method, true, message, modifierOrList.getTextRange()).create();
1837 if (method.isConstructor()) {
1838 checkModifierIsNotAllowed(modifiersList, PsiModifier.STATIC, GroovyBundle.message("constructor.cannot.have.static.modifier"), holder);
1842 if (method.hasModifierProperty(PsiModifier.NATIVE) && method.getBlock() != null) {
1843 String message = GroovyBundle.message("native.methods.cannot.have.body");
1844 PsiElement list = getModifierOrList(modifiersList, PsiModifier.NATIVE);
1845 AnnotationBuilder builder = holder.newAnnotation(HighlightSeverity.ERROR, message)
1847 builder = registerLocalFix(builder, new GrModifierFix((PsiMember)modifiersList.getParent(), PsiModifier.NATIVE, true, false, GrModifierFix.MODIFIER_LIST), modifiersList,
1848 message, ProblemHighlightType.ERROR, list.getTextRange());
1849 builder.withFix(QuickFixFactory.getInstance().createDeleteMethodBodyFix(method))
1854 private static void checkForAbstractAndFinalCombination(AnnotationHolder holder, GrMember member, GrModifierList modifiersList) {
1855 if (member.hasModifierProperty(PsiModifier.FINAL) && member.hasModifierProperty(PsiModifier.ABSTRACT)) {
1856 String message = GroovyBundle.message("illegal.combination.of.modifiers.abstract.and.final");
1857 AnnotationBuilder builder =
1858 holder.newAnnotation(HighlightSeverity.ERROR, message)
1859 .range(modifiersList);
1860 builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.FINAL, false, false, GrModifierFix.MODIFIER_LIST), modifiersList,
1861 message, ProblemHighlightType.ERROR, modifiersList.getTextRange());
1862 builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.ABSTRACT, false, false, GrModifierFix.MODIFIER_LIST), modifiersList,
1863 message, ProblemHighlightType.ERROR, modifiersList.getTextRange());
1869 private static PsiElement getModifierOrList(@NotNull GrModifierList modifiersList, @GrModifier.GrModifierConstant final String modifier) {
1870 PsiElement m = modifiersList.getModifier(modifier);
1871 return m != null ? m : modifiersList;
1874 private static void checkOverrideAnnotation(AnnotationHolder holder, GrModifierList list, GrMethod method) {
1875 final PsiAnnotation overrideAnnotation = list.findAnnotation("java.lang.Override");
1876 if (overrideAnnotation == null) {
1880 MethodSignatureBackedByPsiMethod superMethod = SuperMethodsSearch.search(method, null, true, false).findFirst();
1881 if (superMethod == null) {
1882 holder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle.message("method.does.not.override.super")).range(overrideAnnotation).create();
1885 catch (IndexNotReadyException ignored) {
1890 private static void checkTypeDefinitionModifiers(AnnotationHolder holder, GrTypeDefinition typeDefinition) {
1891 GrModifierList modifiersList = typeDefinition.getModifierList();
1893 if (modifiersList == null) return;
1895 checkAccessModifiers(holder, modifiersList, typeDefinition);
1896 checkDuplicateModifiers(holder, modifiersList, typeDefinition);
1898 PsiClassType[] extendsListTypes = typeDefinition.getExtendsListTypes();
1900 for (PsiClassType classType : extendsListTypes) {
1901 PsiClass psiClass = classType.resolve();
1903 if (psiClass != null && psiClass.hasModifierProperty(PsiModifier.FINAL)) {
1904 PsiElement identifierGroovy = typeDefinition.getNameIdentifierGroovy();
1905 String message = GroovyBundle.message("final.class.cannot.be.extended");
1906 AnnotationBuilder builder = holder.newAnnotation(HighlightSeverity.ERROR, message)
1907 .range(identifierGroovy);
1908 builder = registerLocalFix(builder, new GrModifierFix(typeDefinition, PsiModifier.FINAL, false, false, GrModifierFix.MODIFIER_LIST_OWNER), typeDefinition,
1909 message, ProblemHighlightType.ERROR, identifierGroovy.getTextRange());
1914 if (!typeDefinition.isEnum()) {
1915 checkForAbstractAndFinalCombination(holder, typeDefinition, modifiersList);
1918 checkModifierIsNotAllowed(modifiersList, PsiModifier.TRANSIENT, GroovyBundle.message("modifier.transient.not.allowed.here"), holder);
1919 checkModifierIsNotAllowed(modifiersList, PsiModifier.VOLATILE, GroovyBundle.message("modifier.volatile.not.allowed.here"), holder);
1921 if (typeDefinition.isInterface()) {
1922 checkModifierIsNotAllowed(modifiersList, PsiModifier.FINAL, GroovyBundle.message("interface.cannot.have.modifier.final"), holder);
1926 private static void checkDuplicateModifiers(AnnotationHolder holder, @NotNull GrModifierList list, PsiMember member) {
1927 final PsiElement[] modifiers = list.getModifiers();
1928 Set<String> set = new THashSet<>(modifiers.length);
1929 for (PsiElement modifier : modifiers) {
1930 if (modifier instanceof GrAnnotation) continue;
1931 @GrModifier.GrModifierConstant String name = modifier.getText();
1932 if (set.contains(name)) {
1933 String message = GroovyBundle.message("duplicate.modifier", name);
1934 AnnotationBuilder builder =
1935 holder.newAnnotation(HighlightSeverity.ERROR, message).range(list);
1936 if (member != null) {
1937 builder = registerLocalFix(builder, new GrModifierFix(member, name, false, false, GrModifierFix.MODIFIER_LIST), list, message,
1938 ProblemHighlightType.ERROR, list.getTextRange());
1948 private static void checkAccessModifiers(AnnotationHolder holder, @NotNull GrModifierList modifierList, PsiMember member) {
1949 boolean hasPrivate = modifierList.hasExplicitModifier(PsiModifier.PRIVATE);
1950 boolean hasPublic = modifierList.hasExplicitModifier(PsiModifier.PUBLIC);
1951 boolean hasProtected = modifierList.hasExplicitModifier(PsiModifier.PROTECTED);
1953 if (hasPrivate && hasPublic || hasPrivate && hasProtected || hasPublic && hasProtected) {
1954 String message = GroovyBundle.message("illegal.combination.of.modifiers");
1955 AnnotationBuilder builder =
1956 holder.newAnnotation(HighlightSeverity.ERROR, message).range(modifierList);
1958 builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.PRIVATE, false, false, GrModifierFix.MODIFIER_LIST), modifierList,
1959 message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1962 builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.PROTECTED, false, false, GrModifierFix.MODIFIER_LIST), modifierList,
1963 message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1966 builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.PUBLIC, false, false, GrModifierFix.MODIFIER_LIST), modifierList,
1967 message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1971 else if (member instanceof PsiClass &&
1972 member.getContainingClass() == null &&
1973 GroovyConfigUtils.getInstance().isVersionAtLeast(member, GroovyConfigUtils.GROOVY2_0)) {
1974 checkModifierIsNotAllowed(modifierList, PsiModifier.PRIVATE, GroovyBundle.message("top.level.class.may.not.have.private.modifier"), holder);
1975 checkModifierIsNotAllowed(modifierList, PsiModifier.PROTECTED, GroovyBundle.message("top.level.class.may.not.have.protected.modifier"), holder);
1979 private void checkDuplicateMethod(@NotNull GrMethod method) {
1980 PsiClass clazz = method.getContainingClass();
1981 if (clazz == null) return;
1982 GrReflectedMethod[] reflectedMethods = method.getReflectedMethods();
1983 if (reflectedMethods.length == 0) {
1984 doCheckDuplicateMethod(method, clazz);
1987 for (GrReflectedMethod reflectedMethod : reflectedMethods) {
1988 doCheckDuplicateMethod(reflectedMethod, clazz);
1993 private void doCheckDuplicateMethod(@NotNull GrMethod method, @NotNull PsiClass clazz) {
1994 Set<MethodSignature> duplicatedSignatures = GrClassImplUtil.getDuplicatedSignatures(clazz);
1995 if (duplicatedSignatures.isEmpty()) return; // optimization
1997 PsiSubstitutor substitutor = JavaPsiFacade.getElementFactory(method.getProject()).createRawSubstitutor(method);
1998 MethodSignature signature = method.getSignature(substitutor);
1999 if (!duplicatedSignatures.contains(signature)) return;
2001 String signaturePresentation = GroovyPresentationUtil.getSignaturePresentation(signature);
2002 GrMethod original = method instanceof GrReflectedMethod ? ((GrReflectedMethod)method).getBaseMethod() : method;
2003 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("method.duplicate", signaturePresentation, clazz.getName())).range(GrHighlightUtil.getMethodHeaderTextRange(original)).create();
2006 private static void checkTypeDefinition(AnnotationHolder holder, @NotNull GrTypeDefinition typeDefinition) {
2007 if (typeDefinition.isAnonymous()) {
2008 PsiClass superClass = ((PsiAnonymousClass)typeDefinition).getBaseClassType().resolve();
2009 if (superClass instanceof GrTypeDefinition && ((GrTypeDefinition)superClass).isTrait()) {
2010 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("anonymous.classes.cannot.be.created.from.traits")).range(typeDefinition.getNameIdentifierGroovy()).create();
2013 if (typeDefinition.isAnnotationType() && typeDefinition.getContainingClass() != null) {
2014 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.type.cannot.be.inner")).range(typeDefinition.getNameIdentifierGroovy()).create();
2017 if (!typeDefinition.hasModifierProperty(PsiModifier.STATIC)
2018 && (typeDefinition.getContainingClass() != null || typeDefinition instanceof GrAnonymousClassDefinition)) {
2019 GrTypeDefinition owner = PsiTreeUtil.getParentOfType(typeDefinition, GrTypeDefinition.class);
2020 if (owner instanceof GrTraitTypeDefinition) {
2021 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("non.static.classes.not.allowed")).range(typeDefinition.getNameIdentifierGroovy()).create();
2025 checkDuplicateClass(typeDefinition, holder);
2027 checkCyclicInheritance(holder, typeDefinition);
2030 private static void checkCyclicInheritance(AnnotationHolder holder,
2031 @NotNull GrTypeDefinition typeDefinition) {
2032 final PsiClass psiClass = InheritanceUtil.getCircularClass(typeDefinition);
2033 if (psiClass != null) {
2034 String qname = psiClass.getQualifiedName();
2035 assert qname != null;
2036 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cyclic.inheritance.involving.0", qname)).range(GrHighlightUtil.getClassHeaderTextRange(typeDefinition)).create();
2040 private static void checkForWildCards(AnnotationHolder holder, @Nullable GrReferenceList clause) {
2041 if (clause == null) return;
2042 final GrCodeReferenceElement[] elements = clause.getReferenceElementsGroovy();
2043 for (GrCodeReferenceElement element : elements) {
2044 final GrTypeArgumentList list = element.getTypeArgumentList();
2046 for (GrTypeElement type : list.getTypeArgumentElements()) {
2047 if (type instanceof GrWildcardTypeArgument) {
2048 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("wildcards.are.not.allowed.in.extends.list")).range(type).create();
2055 private static void checkDuplicateClass(GrTypeDefinition typeDefinition, AnnotationHolder holder) {
2056 final PsiClass containingClass = typeDefinition.getContainingClass();
2057 String name = typeDefinition.getName();
2058 if (containingClass != null) {
2059 final String containingClassName = containingClass.getName();
2060 if (containingClassName != null && containingClassName.equals(name)) {
2061 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("duplicate.inner.class", name)).range(typeDefinition.getNameIdentifierGroovy()).create();
2064 final String qName = typeDefinition.getQualifiedName();
2065 if (qName != null) {
2066 JavaPsiFacade facade = JavaPsiFacade.getInstance(typeDefinition.getProject());
2067 GlobalSearchScope scope = inferClassScopeForSearchingDuplicates(typeDefinition);
2068 final PsiClass[] classes = facade.findClasses(qName, scope);
2069 if (classes.length > 1) {
2070 String packageName = getPackageName(typeDefinition);
2072 if (!isScriptGeneratedClass(classes)) {
2073 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("duplicate.class", name, packageName)).range(typeDefinition.getNameIdentifierGroovy()).create();
2076 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("script.generated.with.same.name", qName)).range(typeDefinition.getNameIdentifierGroovy()).create();
2082 private static GlobalSearchScope inferClassScopeForSearchingDuplicates(GrTypeDefinition typeDefinition) {
2083 GlobalSearchScope defaultScope = typeDefinition.getResolveScope();
2085 PsiFile file = typeDefinition.getContainingFile();
2086 if (file instanceof GroovyFile && ((GroovyFile)file).isScript()) {
2087 Module module = ModuleUtilCore.findModuleForPsiElement(file);
2088 if (module != null) {
2089 return defaultScope.intersectWith(module.getModuleScope());
2092 return defaultScope;
2095 private static String getPackageName(GrTypeDefinition typeDefinition) {
2096 final PsiFile file = typeDefinition.getContainingFile();
2097 String packageName = "<default package>";
2098 if (file instanceof GroovyFile) {
2099 final String name = ((GroovyFile)file).getPackageName();
2100 if (!name.isEmpty()) packageName = name;
2105 private static boolean isScriptGeneratedClass(PsiClass[] allClasses) {
2106 return allClasses.length == 2 && (allClasses[0] instanceof GroovyScriptClass || allClasses[1] instanceof GroovyScriptClass);