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.transformations.immutable.GrImmutableUtils;
96 import static com.intellij.psi.util.PsiTreeUtil.findChildOfType;
97 import static org.jetbrains.plugins.groovy.annotator.ImplKt.checkInnerClassReferenceFromInstanceContext;
98 import static org.jetbrains.plugins.groovy.annotator.ImplKt.checkUnresolvedCodeReference;
99 import static org.jetbrains.plugins.groovy.annotator.StringInjectionKt.getLineFeed;
100 import static org.jetbrains.plugins.groovy.annotator.UtilKt.*;
101 import static org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GroovyUnresolvedAccessChecker.checkUnresolvedReference;
102 import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.isInStaticCompilationContext;
103 import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtilKt.mayContainTypeArguments;
104 import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.findScriptField;
105 import static org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.isFieldDeclaration;
110 public class GroovyAnnotator extends GroovyElementVisitor {
111 private static final Logger LOG = Logger.getInstance(GroovyAnnotator.class);
113 public static final Condition<PsiClass> IS_INTERFACE = aClass -> aClass.isInterface();
114 private static final Condition<PsiClass> IS_NOT_INTERFACE = aClass -> !aClass.isInterface();
115 public static final Condition<PsiClass> IS_TRAIT = aClass -> GrTraitUtil.isTrait(aClass);
117 private final AnnotationHolder myHolder;
119 public GroovyAnnotator(@NotNull AnnotationHolder holder) {
124 public void visitTypeArgumentList(@NotNull GrTypeArgumentList typeArgumentList) {
125 PsiElement parent = typeArgumentList.getParent();
126 if (!(parent instanceof GrReferenceElement)) return;
128 if (parent instanceof GrCodeReferenceElement && !mayContainTypeArguments((GrCodeReferenceElement)parent)) {
129 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("type.argument.list.is.not.allowed.here")).create();
133 final GroovyResolveResult resolveResult = ((GrReferenceElement)parent).advancedResolve();
134 final PsiElement resolved = resolveResult.getElement();
135 final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
137 if (resolved == null) return;
139 if (!(resolved instanceof PsiTypeParameterListOwner)) {
140 myHolder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle.message("type.argument.list.is.not.allowed.here")).create();
144 if (typeArgumentList.isDiamond()) return;
146 final PsiTypeParameter[] parameters = ((PsiTypeParameterListOwner)resolved).getTypeParameters();
147 final GrTypeElement[] arguments = typeArgumentList.getTypeArgumentElements();
149 if (arguments.length != parameters.length) {
150 myHolder.newAnnotation(HighlightSeverity.WARNING,
151 GroovyBundle.message("wrong.number.of.type.arguments", arguments.length, parameters.length)).create();
155 for (int i = 0; i < parameters.length; i++) {
156 PsiTypeParameter parameter = parameters[i];
157 final PsiClassType[] superTypes = parameter.getExtendsListTypes();
158 final PsiType argType = arguments[i].getType();
159 for (PsiClassType superType : superTypes) {
160 final PsiType substitutedSuper = substitutor.substitute(superType);
161 if (substitutedSuper != null && !substitutedSuper.isAssignableFrom(argType)) {
162 myHolder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle
163 .message("type.argument.0.is.not.in.its.bound.should.extend.1", argType.getCanonicalText(), superType.getCanonicalText())).range(arguments[i]).create();
171 public void visitNamedArgument(@NotNull GrNamedArgument argument) {
172 PsiElement parent = argument.getParent();
173 if (parent instanceof GrArgumentList) {
174 final PsiElement pParent = parent.getParent();
175 if (pParent instanceof GrIndexProperty) {
176 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("named.arguments.are.not.allowed.inside.index.operations")).create();
182 public void visitElement(@NotNull GroovyPsiElement element) {
183 if (element.getParent() instanceof GrDocReferenceElement) {
184 checkGrDocReferenceElement(myHolder, element);
189 public void visitTryStatement(@NotNull GrTryCatchStatement statement) {
190 final GrCatchClause[] clauses = statement.getCatchClauses();
192 if (statement.getResourceList() == null && clauses.length == 0 && statement.getFinallyClause() == null) {
193 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("try.without.catch.finally")).range(statement.getFirstChild()).create();
197 List<PsiType> usedExceptions = new ArrayList<>();
199 for (GrCatchClause clause : clauses) {
200 final GrParameter parameter = clause.getParameter();
201 if (parameter == null) continue;
203 final GrTypeElement typeElement = parameter.getTypeElementGroovy();
204 PsiType type = typeElement != null ? typeElement.getType() : TypesUtil.createType(CommonClassNames.JAVA_LANG_EXCEPTION, statement);
206 if (typeElement instanceof GrDisjunctionTypeElement) {
207 final GrTypeElement[] elements = ((GrDisjunctionTypeElement)typeElement).getTypeElements();
208 final PsiType[] types = ContainerUtil.map2Array(elements, PsiType.class, GrTypeElement::getType);
210 List<PsiType> usedInsideDisjunction = new ArrayList<>();
211 for (int i = 0; i < types.length; i++) {
212 if (checkExceptionUsed(usedExceptions, parameter, elements[i], types[i])) {
213 usedInsideDisjunction.add(types[i]);
214 for (int j = 0; j < types.length; j++) {
215 if (i != j && types[j].isAssignableFrom(types[i])) {
216 myHolder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle.message("unnecessary.type", types[i].getCanonicalText(),
217 types[j].getCanonicalText())).range(elements[i])
218 .withFix(new GrRemoveExceptionFix(true)).create();
224 usedExceptions.addAll(usedInsideDisjunction);
227 if (checkExceptionUsed(usedExceptions, parameter, typeElement, type)) {
228 usedExceptions.add(type);
235 public void visitCatchClause(@NotNull GrCatchClause clause) {
236 final GrParameter parameter = clause.getParameter();
237 if (parameter == null) return;
239 final GrTypeElement typeElement = parameter.getTypeElementGroovy();
240 if (typeElement != null) {
241 final PsiType type = typeElement.getType();
242 if (type instanceof PsiClassType && ((PsiClassType)type).resolve() == null) return; //don't highlight unresolved types
243 final PsiClassType throwable = TypesUtil.createType(CommonClassNames.JAVA_LANG_THROWABLE, clause);
244 if (!throwable.isAssignableFrom(type)) {
245 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("catch.statement.parameter.type.should.be.a.subclass.of.throwable")).range(typeElement).create();
251 public void visitDocComment(@NotNull GrDocComment comment) {
252 String text = comment.getText();
253 if (!text.endsWith("*/")) {
254 TextRange range = comment.getTextRange();
255 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("doc.end.expected")).range(new TextRange(range.getEndOffset() - 1, range.getEndOffset())).create();
260 public void visitVariableDeclaration(@NotNull GrVariableDeclaration variableDeclaration) {
261 checkDuplicateModifiers(myHolder, variableDeclaration.getModifierList(), null);
262 if (variableDeclaration.isTuple()) {
263 final GrModifierList list = variableDeclaration.getModifierList();
265 final PsiElement last = PsiUtil.skipWhitespacesAndComments(list.getLastChild(), false);
267 final IElementType type = last.getNode().getElementType();
268 if (type != GroovyTokenTypes.kDEF) {
269 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("tuple.declaration.should.end.with.def.modifier")).range(list).create();
273 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("tuple.declaration.should.end.with.def.modifier")).range(list).create();
277 GrTypeParameterList typeParameterList = findChildOfType(variableDeclaration, GrTypeParameterList.class);
278 if (typeParameterList != null) {
279 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("type.parameters.are.unexpected")).range(typeParameterList).create();
284 private boolean checkExceptionUsed(List<PsiType> usedExceptions, GrParameter parameter, GrTypeElement typeElement, PsiType type) {
285 for (PsiType exception : usedExceptions) {
286 if (exception.isAssignableFrom(type)) {
287 myHolder.newAnnotation(HighlightSeverity.WARNING,
288 GroovyBundle.message("exception.0.has.already.been.caught", type.getCanonicalText()))
289 .range(typeElement != null ? typeElement : parameter.getNameIdentifierGroovy())
290 .withFix(new GrRemoveExceptionFix(parameter.getTypeElementGroovy() instanceof GrDisjunctionTypeElement)).create();
298 public void visitReferenceExpression(@NotNull final GrReferenceExpression referenceExpression) {
299 checkStringNameIdentifier(referenceExpression);
300 checkThisOrSuperReferenceExpression(referenceExpression, myHolder);
301 checkFinalFieldAccess(referenceExpression);
302 checkFinalParameterAccess(referenceExpression);
304 if (ResolveUtil.isKeyOfMap(referenceExpression)) {
305 PsiElement nameElement = referenceExpression.getReferenceNameElement();
306 LOG.assertTrue(nameElement != null);
307 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(nameElement).textAttributes(GroovySyntaxHighlighter.MAP_KEY).create();
309 else if (ResolveUtil.isClassReference(referenceExpression)) {
310 PsiElement nameElement = referenceExpression.getReferenceNameElement();
311 LOG.assertTrue(nameElement != null);
312 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(nameElement).textAttributes(GroovySyntaxHighlighter.KEYWORD).create();
314 else if (isInStaticCompilationContext(referenceExpression)) {
315 checkUnresolvedReference(referenceExpression, true, true, new UnresolvedReferenceAnnotatorSink(myHolder));
319 private void checkFinalParameterAccess(GrReferenceExpression ref) {
320 final PsiElement resolved = ref.resolve();
322 if (resolved instanceof GrParameter) {
323 final GrParameter parameter = (GrParameter)resolved;
324 if (parameter.isPhysical() && parameter.hasModifierProperty(PsiModifier.FINAL) && PsiUtil.isLValue(ref)) {
325 if (parameter.getDeclarationScope() instanceof PsiMethod) {
326 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cannot.assign.a.value.to.final.parameter.0", parameter.getName())).create();
332 private void checkFinalFieldAccess(@NotNull GrReferenceExpression ref) {
333 final PsiElement resolved = ref.resolve();
335 if (resolved instanceof GrField && resolved.isPhysical() && ((GrField)resolved).hasModifierProperty(PsiModifier.FINAL) && PsiUtil.isLValue(ref)) {
336 final GrField field = (GrField)resolved;
338 final PsiClass containingClass = field.getContainingClass();
339 if (containingClass != null && PsiTreeUtil.isAncestor(containingClass, ref, true)) {
340 GrMember container = GrHighlightUtil.findClassMemberContainer(ref, containingClass);
342 if (field.hasModifierProperty(PsiModifier.STATIC)) {
343 if (container instanceof GrClassInitializer && ((GrClassInitializer)container).isStatic()) {
348 if (container instanceof GrMethod && ((GrMethod)container).isConstructor() ||
349 container instanceof GrClassInitializer && !((GrClassInitializer)container).isStatic()) {
354 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cannot.assign.a.value.to.final.field.0", field.getName())).create();
359 private void checkStringNameIdentifier(GrReferenceExpression ref) {
360 final PsiElement nameElement = ref.getReferenceNameElement();
361 if (nameElement == null) return;
363 final IElementType elementType = nameElement.getNode().getElementType();
364 if (GroovyTokenSets.STRING_LITERALS.contains(elementType)) {
365 checkStringLiteral(nameElement);
367 else if (elementType == GroovyTokenTypes.mREGEX_LITERAL || elementType == GroovyTokenTypes.mDOLLAR_SLASH_REGEX_LITERAL) {
368 checkRegexLiteral(nameElement);
373 public void visitTypeDefinition(@NotNull GrTypeDefinition typeDefinition) {
374 final PsiElement parent = typeDefinition.getParent();
375 if (!(typeDefinition.isAnonymous() ||
376 parent instanceof GrTypeDefinitionBody ||
377 parent instanceof GroovyFile ||
378 typeDefinition instanceof GrTypeParameter)) {
379 final TextRange range = GrHighlightUtil.getClassHeaderTextRange(typeDefinition);
381 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("class.definition.is.not.expected.here")).range(range)
382 .withFix(new GrMoveClassToCorrectPlaceFix(typeDefinition)).create();
384 checkTypeDefinition(myHolder, typeDefinition);
386 checkImplementedMethodsOfClass(myHolder, typeDefinition);
387 checkConstructors(myHolder, typeDefinition);
389 checkAnnotationCollector(myHolder, typeDefinition);
391 checkSameNameMethodsWithDifferentAccessModifiers(myHolder, typeDefinition.getCodeMethods());
392 checkInheritorOfSelfTypes(myHolder, typeDefinition);
395 private static void checkInheritorOfSelfTypes(AnnotationHolder holder, GrTypeDefinition definition) {
396 if (!(definition instanceof GrClassDefinition)) return;
397 List<PsiClass> selfTypeClasses = GrTraitUtil.getSelfTypeClasses(definition);
398 for (PsiClass selfClass : selfTypeClasses) {
399 if (InheritanceUtil.isInheritorOrSelf(definition, selfClass, true)) continue;
400 String message = GroovyBundle.message("selfType.class.does.not.inherit", definition.getQualifiedName(), selfClass.getQualifiedName());
401 holder.newAnnotation(HighlightSeverity.ERROR, message).range(GrHighlightUtil.getClassHeaderTextRange(definition)).create();
406 private static void checkSameNameMethodsWithDifferentAccessModifiers(AnnotationHolder holder, GrMethod[] methods) {
407 MultiMap<String, GrMethod> map = MultiMap.create();
408 for (GrMethod method : methods) {
409 if (!method.isConstructor()) {
410 map.putValue(method.getName(), method);
414 for (Map.Entry<String, Collection<GrMethod>> entry : map.entrySet()) {
415 Collection<GrMethod> collection = entry.getValue();
416 if (collection.size() > 1 && !sameAccessModifier(collection)) {
417 for (GrMethod method : collection) {
418 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("mixing.private.and.public.protected.methods.of.the.same.name")).range(GrHighlightUtil.getMethodHeaderTextRange(method)).create();
424 private static boolean sameAccessModifier(Collection<GrMethod> collection) {
425 Iterator<GrMethod> iterator = collection.iterator();
426 GrMethod method = iterator.next();
427 boolean privateAccess = PsiModifier.PRIVATE.equals(VisibilityUtil.getVisibilityModifier(method.getModifierList()));
429 while (iterator.hasNext()) {
430 GrMethod next = iterator.next();
431 if (privateAccess != PsiModifier.PRIVATE.equals(VisibilityUtil.getVisibilityModifier(next.getModifierList()))) {
439 private static void checkAnnotationCollector(AnnotationHolder holder, GrTypeDefinition definition) {
440 if (definition.isAnnotationType() &&
441 GrAnnotationCollector.findAnnotationCollector(definition) != null &&
442 definition.getCodeMethods().length > 0) {
443 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.collector.cannot.have.attributes")).range(definition.getNameIdentifierGroovy()).create();
447 private static void checkConstructors(AnnotationHolder holder, GrTypeDefinition typeDefinition) {
448 if (typeDefinition.isEnum() || typeDefinition.isInterface() || typeDefinition.isAnonymous() || typeDefinition instanceof GrTypeParameter) return;
449 final PsiClass superClass = typeDefinition.getSuperClass();
450 if (superClass == null) return;
452 if (InheritConstructorContributor.hasInheritConstructorsAnnotation(typeDefinition)) return;
454 PsiMethod defConstructor = getDefaultConstructor(superClass);
455 boolean hasImplicitDefConstructor = superClass.getConstructors().length == 0;
457 final PsiMethod[] constructors = typeDefinition.getCodeConstructors();
458 final String qName = superClass.getQualifiedName();
459 if (constructors.length == 0) {
460 if (!hasImplicitDefConstructor && (defConstructor == null || !PsiUtil.isAccessible(typeDefinition, defConstructor))) {
461 final TextRange range = GrHighlightUtil.getClassHeaderTextRange(typeDefinition);
462 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("there.is.no.default.constructor.available.in.class.0", qName)).range(range)
463 .withFix(QuickFixFactory.getInstance().createCreateConstructorMatchingSuperFix(typeDefinition)).create();
467 for (PsiMethod method : constructors) {
468 if (method instanceof GrMethod) {
469 final GrOpenBlock block = ((GrMethod)method).getBlock();
470 if (block == null) continue;
471 final GrStatement[] statements = block.getStatements();
472 if (statements.length > 0) {
473 if (statements[0] instanceof GrConstructorInvocation) continue;
476 if (!hasImplicitDefConstructor && (defConstructor == null || !PsiUtil.isAccessible(typeDefinition, defConstructor))) {
477 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("there.is.no.default.constructor.available.in.class.0", qName)).range(GrHighlightUtil.getMethodHeaderTextRange(method)).create();
482 checkRecursiveConstructors(holder, constructors);
486 public void visitEnumConstant(@NotNull GrEnumConstant enumConstant) {
487 super.visitEnumConstant(enumConstant);
488 final GrArgumentList argumentList = enumConstant.getArgumentList();
490 if (argumentList != null && PsiImplUtil.hasNamedArguments(argumentList) && !PsiImplUtil.hasExpressionArguments(argumentList)) {
491 final PsiMethod constructor = enumConstant.resolveConstructor();
492 if (constructor != null) {
493 if (!PsiUtil.isConstructorHasRequiredParameters(constructor)) {
494 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle
495 .message("the.usage.of.a.map.entry.expression.to.initialize.an.enum.is.currently.not.supported")).range(argumentList).create();
501 private static void checkRecursiveConstructors(AnnotationHolder holder, PsiMethod[] constructors) {
502 Map<PsiMethod, PsiMethod> nodes = new HashMap<>(constructors.length);
504 Set<PsiMethod> set = ContainerUtil.set(constructors);
506 for (PsiMethod constructor : constructors) {
507 if (!(constructor instanceof GrMethod)) continue;
509 final GrOpenBlock block = ((GrMethod)constructor).getBlock();
510 if (block == null) continue;
512 final GrStatement[] statements = block.getStatements();
513 if (statements.length <= 0 || !(statements[0] instanceof GrConstructorInvocation)) continue;
515 final PsiMethod resolved = ((GrConstructorInvocation)statements[0]).resolveMethod();
516 if (!set.contains(resolved)) continue;
518 nodes.put(constructor, resolved);
521 Set<PsiMethod> checked = new HashSet<>();
523 Set<PsiMethod> current;
524 for (PsiMethod constructor : constructors) {
525 if (!checked.add(constructor)) continue;
527 current = new HashSet<>();
528 current.add(constructor);
529 for (constructor = nodes.get(constructor); constructor != null && current.add(constructor); constructor = nodes.get(constructor)) {
530 checked.add(constructor);
533 if (constructor != null) {
534 PsiMethod circleStart = constructor;
536 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("recursive.constructor.invocation")).range(GrHighlightUtil.getMethodHeaderTextRange(constructor)).create();
537 constructor = nodes.get(constructor);
539 while (constructor != circleStart);
545 public void visitUnaryExpression(@NotNull GrUnaryExpression expression) {
546 if (expression.getOperationTokenType() == GroovyTokenTypes.mINC ||
547 expression.getOperationTokenType() == GroovyTokenTypes.mDEC) {
548 GrExpression operand = expression.getOperand();
549 if (operand instanceof GrReferenceExpression && ((GrReferenceExpression)operand).getQualifier() == null) {
550 GrTraitTypeDefinition trait = PsiTreeUtil.getParentOfType(operand, GrTraitTypeDefinition.class);
552 PsiElement resolved = ((GrReferenceExpression)operand).resolve();
553 if (resolved instanceof GrField && ((GrField)resolved).getContainingClass() instanceof GrTraitTypeDefinition) {
554 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle
555 .message("0.expressions.on.trait.fields.properties.are.not.supported.in.traits", expression.getOperationToken().getText())).create();
563 public void visitOpenBlock(@NotNull GrOpenBlock block) {
564 PsiElement blockParent = block.getParent();
565 if (blockParent instanceof GrMethod) {
566 final GrMethod method = (GrMethod)blockParent;
567 if (GrTraitUtil.isMethodAbstract(method)) {
568 String message = GroovyBundle.message("abstract.methods.must.not.have.body");
569 AnnotationBuilder builder =
570 myHolder.newAnnotation(HighlightSeverity.ERROR, message);
571 registerMakeAbstractMethodNotAbstractFix(builder, method, true, message, block.getTextRange()).create();
577 public void visitField(@NotNull GrField field) {
578 super.visitField(field);
579 if (field.getTypeElementGroovy() == null && field.getContainingClass() instanceof GrAnnotationTypeDefinition) {
580 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.field.should.have.type.declaration")).range(field.getNameIdentifierGroovy()).create();
582 checkInitializer(field);
585 private void checkInitializer(@NotNull GrField field) {
586 PsiExpression initializer = field.getInitializer();
587 if (initializer == null) return;
588 PsiClass containingClass = field.getContainingClass();
589 if (containingClass == null) return;
590 PsiAnnotation tupleConstructor = containingClass.getAnnotation(GroovyCommonClassNames.GROOVY_TRANSFORM_TUPLE_CONSTRUCTOR);
591 if (tupleConstructor == null) return;
592 if (!Boolean.FALSE.equals(GrAnnotationUtil.inferBooleanAttribute(tupleConstructor, "defaults"))) return;
593 List<String> excludes = GeneratedConstructorCollector.getIdentifierList(tupleConstructor, "excludes");
594 List<String> includes = GeneratedConstructorCollector.getIdentifierList(tupleConstructor, "includes");
595 if ((excludes != null && !excludes.contains(field.getName())) || (includes != null && includes.contains(field.getName()))) {
596 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("initializers.are.forbidden.with.defaults"))
603 public void visitMethod(@NotNull GrMethod method) {
604 checkDuplicateMethod(method);
605 checkMethodWithTypeParamsShouldHaveReturnType(myHolder, method);
606 checkInnerMethod(myHolder, method);
607 checkOptionalParametersInAbstractMethod(myHolder, method);
609 checkConstructorOfImmutableClass(myHolder, method);
610 checkGetterOfImmutable(myHolder, method);
612 final PsiElement nameIdentifier = method.getNameIdentifierGroovy();
613 if (GroovyTokenSets.STRING_LITERALS.contains(nameIdentifier.getNode().getElementType())) {
614 checkStringLiteral(nameIdentifier);
617 GrOpenBlock block = method.getBlock();
618 if (block != null && TypeInferenceHelper.isTooComplexTooAnalyze(block)) {
619 myHolder.newAnnotation(HighlightSeverity.WEAK_WARNING, GroovyBundle.message("method.0.is.too.complex.too.analyze", method.getName())).range(nameIdentifier).create();
622 final PsiClass containingClass = method.getContainingClass();
623 if (method.isConstructor()) {
624 if (containingClass instanceof GrAnonymousClassDefinition) {
625 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("constructors.are.not.allowed.in.anonymous.class")).range(nameIdentifier).create();
627 else if (containingClass != null && containingClass.isInterface()) {
628 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("constructors.are.not.allowed.in.interface")).range(nameIdentifier).create();
632 if (method.getBlock() == null && !method.hasModifierProperty(PsiModifier.NATIVE) && !GrTraitUtil.isMethodAbstract(method)) {
633 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("not.abstract.method.should.have.body")).range(nameIdentifier).create();
636 checkOverridingMethod(myHolder, method);
639 private static void checkGetterOfImmutable(AnnotationHolder holder, GrMethod method) {
640 if (!GroovyPropertyUtils.isSimplePropertyGetter(method)) return;
642 PsiClass aClass = method.getContainingClass();
643 if (aClass == null) return;
645 if (!GrImmutableUtils.hasImmutableAnnotation(aClass)) return;
647 PsiField field = GroovyPropertyUtils.findFieldForAccessor(method, false);
648 if (!(field instanceof GrField)) return;
650 GrModifierList fieldModifierList = ((GrField)field).getModifierList();
651 if (fieldModifierList == null) return;
653 if (fieldModifierList.hasExplicitVisibilityModifiers()) return;
655 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("repetitive.method.name.0", method.getName())).range(method.getNameIdentifierGroovy()).create();
658 private static void checkConstructorOfImmutableClass(AnnotationHolder holder, GrMethod method) {
659 if (!method.isConstructor()) return;
661 PsiClass aClass = method.getContainingClass();
662 if (aClass == null) return;
664 if (!GrImmutableUtils.hasImmutableAnnotation(aClass)) return;
666 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("explicit.constructors.are.not.allowed.in.immutable.class")).range(method.getNameIdentifierGroovy()).create();
669 private static void checkOverridingMethod(@NotNull AnnotationHolder holder, @NotNull GrMethod method) {
670 final List<HierarchicalMethodSignature> signatures = method.getHierarchicalMethodSignature().getSuperSignatures();
672 for (HierarchicalMethodSignature signature : signatures) {
673 final PsiMethod superMethod = signature.getMethod();
674 if (superMethod.hasModifierProperty(PsiModifier.FINAL)) {
676 final String current = GroovyPresentationUtil.getSignaturePresentation(method.getSignature(PsiSubstitutor.EMPTY));
677 final String superPresentation = GroovyPresentationUtil.getSignaturePresentation(signature);
678 final String superQName = getQNameOfMember(superMethod);
680 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("method.0.cannot.override.method.1.in.2.overridden.method.is.final", current, superPresentation, superQName)).range(GrHighlightUtil.getMethodHeaderTextRange(method)).create();
685 final String currentModifier = VisibilityUtil.getVisibilityModifier(method.getModifierList());
686 final String superModifier = VisibilityUtil.getVisibilityModifier(superMethod.getModifierList());
688 if (PsiModifier.PUBLIC.equals(superModifier) && (PsiModifier.PROTECTED.equals(currentModifier) || PsiModifier.PRIVATE
689 .equals(currentModifier)) ||
690 PsiModifier.PROTECTED.equals(superModifier) && PsiModifier.PRIVATE.equals(currentModifier)) {
691 final String currentPresentation = GroovyPresentationUtil.getSignaturePresentation(method.getSignature(PsiSubstitutor.EMPTY));
692 final String superPresentation = GroovyPresentationUtil.getSignaturePresentation(signature);
693 final String superQName = getQNameOfMember(superMethod);
695 //noinspection MagicConstant
696 final PsiElement modifier = method.getModifierList().getModifier(currentModifier);
697 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("method.0.cannot.have.weaker.access.privileges.1.than.2.in.3.4", currentPresentation, currentModifier, superPresentation, superQName, superModifier)).range(modifier != null ? modifier : method.getNameIdentifierGroovy()).create();
702 private static void checkMethodWithTypeParamsShouldHaveReturnType(AnnotationHolder holder, GrMethod method) {
703 final PsiTypeParameterList parameterList = method.getTypeParameterList();
704 if (parameterList != null) {
705 final GrTypeElement typeElement = method.getReturnTypeElementGroovy();
706 if (typeElement == null) {
707 final TextRange parameterListTextRange = parameterList.getTextRange();
708 final TextRange range = new TextRange(parameterListTextRange.getEndOffset(), parameterListTextRange.getEndOffset() + 1);
709 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("method.with.type.parameters.should.have.return.type")).range(range).create();
714 private static void checkOptionalParametersInAbstractMethod(AnnotationHolder holder, GrMethod method) {
715 if (!method.hasModifierProperty(PsiModifier.ABSTRACT)) return;
716 if (!(method.getContainingClass() instanceof GrInterfaceDefinition)) return;
718 for (GrParameter parameter : method.getParameters()) {
719 GrExpression initializerGroovy = parameter.getInitializerGroovy();
720 if (initializerGroovy != null) {
721 PsiElement assignOperator = parameter.getNameIdentifierGroovy();
722 TextRange textRange =
723 new TextRange(assignOperator.getTextRange().getEndOffset(), initializerGroovy.getTextRange().getEndOffset());
724 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("default.initializers.are.not.allowed.in.abstract.method")).range(textRange).create();
730 private static PsiMethod getDefaultConstructor(PsiClass clazz) {
731 final String className = clazz.getName();
732 if (className == null) return null;
733 final PsiMethod[] byName = clazz.findMethodsByName(className, true);
734 if (byName.length == 0) return null;
736 for (PsiMethod method : byName) {
737 if (method.getParameterList().isEmpty()) return method;
738 if (!(method instanceof GrMethod)) continue;
739 final GrParameter[] parameters = ((GrMethod)method).getParameterList().getParameters();
741 for (GrParameter parameter : parameters) {
742 if (!parameter.isOptional()) continue Outer;
751 public void visitVariable(@NotNull GrVariable variable) {
754 PsiElement parent = variable.getParent();
755 if (parent instanceof GrForInClause) {
756 PsiElement delimiter = ((GrForInClause)parent).getDelimiter();
757 if (delimiter.getNode().getElementType() == GroovyTokenTypes.mCOLON) {
758 GrTypeElement typeElement = variable.getTypeElementGroovy();
759 GrModifierList modifierList = variable.getModifierList();
760 if (modifierList != null && typeElement == null && StringUtil.isEmptyOrSpaces(modifierList.getText())) {
761 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle
762 .message("java.style.for.each.statement.requires.a.type.declaration")).range(variable.getNameIdentifierGroovy())
763 .withFix(new ReplaceDelimiterFix()).create();
769 PsiNamedElement duplicate = ResolveUtil.findDuplicate(variable);
772 if (duplicate instanceof GrVariable &&
773 (variable instanceof GrField || ResolveUtil.isScriptField(variable) || !(duplicate instanceof GrField))) {
774 final String key = duplicate instanceof GrField ? "field.already.defined" : "variable.already.defined";
775 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message(key, variable.getName())).range(variable.getNameIdentifierGroovy()).create();
778 PsiType type = variable.getDeclaredType();
779 if (type instanceof PsiEllipsisType && !isLastParameter(variable)) {
780 TextRange range = getEllipsisRange(variable);
782 range = getTypeRange(variable);
785 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("ellipsis.type.is.not.allowed.here")).range(range).create();
791 private static TextRange getEllipsisRange(GrVariable variable) {
792 if (variable instanceof GrParameter) {
793 final PsiElement dots = ((GrParameter)variable).getEllipsisDots();
795 return dots.getTextRange();
802 private static TextRange getTypeRange(GrVariable variable) {
803 GrTypeElement typeElement = variable.getTypeElementGroovy();
804 if (typeElement == null) return null;
806 PsiElement sibling = typeElement.getNextSibling();
807 if (sibling != null && sibling.getNode().getElementType() == GroovyTokenTypes.mTRIPLE_DOT) {
808 return new TextRange(typeElement.getTextRange().getStartOffset(), sibling.getTextRange().getEndOffset());
811 return typeElement.getTextRange();
815 private static boolean isLastParameter(PsiVariable variable) {
816 if (!(variable instanceof PsiParameter)) return false;
818 PsiElement parent = variable.getParent();
819 if (!(parent instanceof PsiParameterList)) return false;
821 PsiParameter[] parameters = ((PsiParameterList)parent).getParameters();
823 return parameters.length > 0 && parameters[parameters.length - 1] == variable;
826 private void checkName(GrVariable variable) {
827 if (!"$".equals(variable.getName())) return;
828 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("incorrect.variable.name")).range(variable.getNameIdentifierGroovy()).create();
832 public void visitAssignmentExpression(@NotNull GrAssignmentExpression expression) {
833 GrExpression lValue = expression.getLValue();
834 if (!PsiUtil.mightBeLValue(lValue)) {
835 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("invalid.lvalue")).range(lValue).create();
840 public void visitReturnStatement(@NotNull GrReturnStatement returnStatement) {
841 final GrExpression value = returnStatement.getReturnValue();
843 final PsiType type = value.getType();
845 final GrParameterListOwner owner = PsiTreeUtil.getParentOfType(returnStatement, GrParameterListOwner.class);
846 if (owner instanceof PsiMethod) {
847 final PsiMethod method = (PsiMethod)owner;
848 if (method.isConstructor()) {
849 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cannot.return.from.constructor")).range(value).create();
852 final PsiType methodType = method.getReturnType();
853 if (methodType != null) {
854 if (PsiType.VOID.equals(methodType)) {
855 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cannot.return.from.void.method")).range(value).create();
865 public void visitTypeParameterList(@NotNull GrTypeParameterList list) {
866 final PsiElement parent = list.getParent();
867 if (parent instanceof GrMethod && ((GrMethod)parent).isConstructor() ||
868 parent instanceof GrEnumTypeDefinition ||
869 parent instanceof GrAnnotationTypeDefinition) {
870 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("type.parameters.are.unexpected")).create();
875 public void visitListOrMap(@NotNull GrListOrMap listOrMap) {
876 final GroovyConstructorReference constructorReference = listOrMap.getConstructorReference();
877 if (constructorReference != null) {
878 final PsiElement lBracket = listOrMap.getLBrack();
879 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(lBracket).textAttributes(GroovySyntaxHighlighter.LITERAL_CONVERSION).create();
880 final PsiElement rBracket = listOrMap.getRBrack();
881 if (rBracket != null) {
882 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(rBracket).textAttributes(GroovySyntaxHighlighter.LITERAL_CONVERSION).create();
886 final GrNamedArgument[] namedArguments = listOrMap.getNamedArguments();
887 final GrExpression[] expressionArguments = listOrMap.getInitializers();
889 if (namedArguments.length != 0 && expressionArguments.length != 0) {
890 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("collection.literal.contains.named.argument.and.expression.items")).create();
893 checkNamedArgs(namedArguments, false);
897 public void visitClassTypeElement(@NotNull GrClassTypeElement typeElement) {
898 super.visitClassTypeElement(typeElement);
900 final GrCodeReferenceElement ref = typeElement.getReferenceElement();
901 final GrTypeArgumentList argList = ref.getTypeArgumentList();
902 if (argList == null) return;
904 final GrTypeElement[] elements = argList.getTypeArgumentElements();
905 for (GrTypeElement element : elements) {
906 checkTypeArgForPrimitive(element, GroovyBundle.message("primitive.type.parameters.are.not.allowed"));
911 public void visitCodeReferenceElement(@NotNull GrCodeReferenceElement refElement) {
912 if (refElement.getParent() instanceof GrAnnotation) {
913 PsiElement resolved = refElement.resolve();
914 if (resolved instanceof PsiClass && !((PsiClass)resolved).isAnnotationType() &&
915 GrAnnotationCollector.findAnnotationCollector((PsiClass)resolved) != null) {
916 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).textAttributes(GroovySyntaxHighlighter.ANNOTATION).create();
919 checkUnresolvedCodeReference(refElement, myHolder);
920 checkInnerClassReferenceFromInstanceContext(refElement, myHolder);
924 public void visitTypeElement(@NotNull GrTypeElement typeElement) {
925 final PsiElement parent = typeElement.getParent();
926 if (!(parent instanceof GrMethod)) return;
928 if (parent instanceof GrAnnotationMethod) {
929 checkAnnotationAttributeType(typeElement, myHolder);
931 else if (((GrMethod)parent).isConstructor()) {
932 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("constructors.cannot.have.return.type")).create();
935 checkMethodReturnType(((GrMethod)parent), typeElement, myHolder);
940 public void visitArrayTypeElement(@NotNull GrArrayTypeElement typeElement) {
941 GrTypeElement componentTypeElement = typeElement.getComponentTypeElement();
942 PsiType componentType = componentTypeElement.getType();
943 if (PsiType.VOID.equals(componentType)) {
944 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("illegal.type.void")).range(componentTypeElement).create();
947 super.visitArrayTypeElement(typeElement);
952 public void visitModifierList(@NotNull GrModifierList modifierList) {
953 final PsiElement parent = modifierList.getParent();
954 if (parent instanceof GrMethod) {
955 checkMethodDefinitionModifiers(myHolder, (GrMethod)parent);
957 else if (parent instanceof GrTypeDefinition) {
958 checkTypeDefinitionModifiers(myHolder, (GrTypeDefinition)parent);
960 else if (parent instanceof GrVariableDeclaration) {
961 GrVariableDeclaration declaration = (GrVariableDeclaration)parent;
962 if (isFieldDeclaration(declaration)) {
963 checkFieldModifiers(myHolder, declaration);
966 checkVariableModifiers(myHolder, declaration);
969 else if (parent instanceof GrClassInitializer) {
970 checkClassInitializerModifiers(myHolder, modifierList);
974 private static void checkClassInitializerModifiers(AnnotationHolder holder, GrModifierList modifierList) {
975 for (GrAnnotation annotation : modifierList.getAnnotations()) {
976 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("initializer.cannot.have.annotations")).range(annotation).create();
979 for (@GrModifier.GrModifierConstant String modifier : GrModifier.GROOVY_MODIFIERS) {
980 if (PsiModifier.STATIC.equals(modifier)) continue;
981 checkModifierIsNotAllowed(modifierList, modifier, GroovyBundle.message("initializer.cannot.be.0", modifier), holder);
986 public void visitClassInitializer(@NotNull GrClassInitializer initializer) {
987 final PsiClass aClass = initializer.getContainingClass();
988 if (GrTraitUtil.isInterface(aClass)) {
989 final TextRange range = GrHighlightUtil.getInitializerHeaderTextRange(initializer);
990 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("initializers.are.not.allowed.in.interface")).range(range).create();
994 private static void checkFieldModifiers(AnnotationHolder holder, GrVariableDeclaration fieldDeclaration) {
995 GrVariable[] variables = fieldDeclaration.getVariables();
996 if (variables.length == 0) return;
998 GrVariable variable = variables[0];
999 final GrField member = variable instanceof GrField ? (GrField)variable : findScriptField(variable);
1000 if (member == null) return;
1002 final GrModifierList modifierList = fieldDeclaration.getModifierList();
1004 checkAccessModifiers(holder, modifierList, member);
1005 checkDuplicateModifiers(holder, modifierList, member);
1007 if (modifierList.hasExplicitModifier(PsiModifier.VOLATILE) && modifierList.hasExplicitModifier(PsiModifier.FINAL)) {
1009 String message = GroovyBundle.message("illegal.combination.of.modifiers.volatile.and.final");
1010 AnnotationBuilder builder =
1011 holder.newAnnotation(HighlightSeverity.ERROR, message)
1012 .range(modifierList);
1013 builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.VOLATILE, true, false, GrModifierFix.MODIFIER_LIST), modifierList,
1014 message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1015 builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.FINAL, true, false, GrModifierFix.MODIFIER_LIST), modifierList,
1016 message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1020 if (member.getContainingClass() instanceof GrInterfaceDefinition) {
1021 checkModifierIsNotAllowed(modifierList,
1022 PsiModifier.PRIVATE, GroovyBundle.message("interface.members.are.not.allowed.to.be", PsiModifier.PRIVATE), holder);
1023 checkModifierIsNotAllowed(modifierList, PsiModifier.PROTECTED, GroovyBundle.message("interface.members.are.not.allowed.to.be",
1024 PsiModifier.PROTECTED),
1029 private static void checkAnnotationAttributeType(GrTypeElement element, AnnotationHolder holder) {
1030 if (element instanceof GrBuiltInTypeElement) return;
1032 if (element instanceof GrArrayTypeElement) {
1033 checkAnnotationAttributeType(((GrArrayTypeElement)element).getComponentTypeElement(), holder);
1036 else if (element instanceof GrClassTypeElement) {
1037 final PsiElement resolved = ((GrClassTypeElement)element).getReferenceElement().resolve();
1038 if (resolved instanceof PsiClass) {
1039 if (CommonClassNames.JAVA_LANG_STRING.equals(((PsiClass)resolved).getQualifiedName())) return;
1040 if (CommonClassNames.JAVA_LANG_CLASS.equals(((PsiClass)resolved).getQualifiedName())) return;
1041 if (((PsiClass)resolved).isAnnotationType()) return;
1042 if (((PsiClass)resolved).isEnum()) return;
1046 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("unexpected.attribute.type.0", element.getType())).range(element).create();
1049 static void checkMethodReturnType(PsiMethod method, PsiElement toHighlight, AnnotationHolder holder) {
1050 final HierarchicalMethodSignature signature = method.getHierarchicalMethodSignature();
1051 final List<HierarchicalMethodSignature> superSignatures = signature.getSuperSignatures();
1053 PsiType returnType = signature.getSubstitutor().substitute(method.getReturnType());
1055 for (HierarchicalMethodSignature superMethodSignature : superSignatures) {
1056 PsiMethod superMethod = superMethodSignature.getMethod();
1057 PsiType declaredReturnType = superMethod.getReturnType();
1058 PsiType superReturnType = superMethodSignature.getSubstitutor().substitute(declaredReturnType);
1059 if (PsiType.VOID.equals(superReturnType) && method instanceof GrMethod && ((GrMethod)method).getReturnTypeElementGroovy() == null) return;
1060 if (superMethodSignature.isRaw()) superReturnType = TypeConversionUtil.erasure(declaredReturnType);
1061 if (returnType == null || superReturnType == null || method == superMethod) continue;
1062 PsiClass superClass = superMethod.getContainingClass();
1063 if (superClass == null) continue;
1064 String highlightInfo = checkSuperMethodSignature(superMethod, superMethodSignature, superReturnType, method, signature, returnType);
1065 if (highlightInfo != null) {
1066 holder.newAnnotation(HighlightSeverity.ERROR, highlightInfo).range(toHighlight).create();
1073 private static String checkSuperMethodSignature(@NotNull PsiMethod superMethod,
1074 @NotNull MethodSignatureBackedByPsiMethod superMethodSignature,
1075 @NotNull PsiType superReturnType,
1076 @NotNull PsiMethod method,
1077 @NotNull MethodSignatureBackedByPsiMethod methodSignature,
1078 @NotNull PsiType returnType) {
1079 PsiType substitutedSuperReturnType = substituteSuperReturnType(superMethodSignature, methodSignature, superReturnType);
1081 if (returnType.equals(substitutedSuperReturnType)) return null;
1083 final PsiType rawReturnType = TypeConversionUtil.erasure(returnType);
1084 final PsiType rawSuperReturnType = TypeConversionUtil.erasure(substitutedSuperReturnType);
1086 if (returnType instanceof PsiClassType && substitutedSuperReturnType instanceof PsiClassType) {
1087 if (TypeConversionUtil.isAssignable(rawSuperReturnType, rawReturnType)) {
1091 else if (returnType instanceof PsiArrayType && superReturnType instanceof PsiArrayType) {
1092 if (rawReturnType.equals(rawSuperReturnType)) {
1097 String qName = getQNameOfMember(method);
1098 String baseQName = getQNameOfMember(superMethod);
1099 final String presentation = returnType.getCanonicalText() + " " + GroovyPresentationUtil.getSignaturePresentation(methodSignature);
1100 final String basePresentation =
1101 superReturnType.getCanonicalText() + " " + GroovyPresentationUtil.getSignaturePresentation(superMethodSignature);
1102 return GroovyBundle.message("return.type.is.incompatible", presentation, qName, basePresentation, baseQName);
1106 private static PsiType substituteSuperReturnType(@NotNull MethodSignatureBackedByPsiMethod superMethodSignature,
1107 @NotNull MethodSignatureBackedByPsiMethod methodSignature,
1108 @NotNull PsiType superReturnType) {
1109 PsiType substitutedSuperReturnType;
1110 if (!superMethodSignature.isRaw() && superMethodSignature.equals(methodSignature)) { //see 8.4.5
1111 PsiSubstitutor unifyingSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature,
1112 superMethodSignature);
1113 substitutedSuperReturnType = unifyingSubstitutor == null
1115 : unifyingSubstitutor.substitute(superMethodSignature.getSubstitutor().substitute(superReturnType));
1118 substitutedSuperReturnType = TypeConversionUtil.erasure(superReturnType);
1120 return substitutedSuperReturnType;
1124 private static String getQNameOfMember(@NotNull PsiMember member) {
1125 final PsiClass aClass = member.getContainingClass();
1126 return getQName(aClass);
1130 private static String getQName(@Nullable PsiClass aClass) {
1131 if (aClass instanceof PsiAnonymousClass) {
1132 return GroovyBundle.message("anonymous.class.derived.from.0", ((PsiAnonymousClass)aClass).getBaseClassType().getCanonicalText());
1134 if (aClass != null) {
1135 final String qname = aClass.getQualifiedName();
1136 if (qname != null) {
1144 private void checkTypeArgForPrimitive(@Nullable GrTypeElement element, @NotNull String message) {
1145 if (element == null || !(element.getType() instanceof PsiPrimitiveType)) return;
1147 AnnotationBuilder builder = myHolder.newAnnotation(HighlightSeverity.ERROR, message).range(element);
1148 builder = registerLocalFix(builder, new GrReplacePrimitiveTypeWithWrapperFix(element), element, message, ProblemHighlightType.ERROR,
1149 element.getTextRange());
1154 public void visitWildcardTypeArgument(@NotNull GrWildcardTypeArgument wildcardTypeArgument) {
1155 super.visitWildcardTypeArgument(wildcardTypeArgument);
1157 checkTypeArgForPrimitive(wildcardTypeArgument.getBoundTypeElement(), GroovyBundle.message("primitive.bound.types.are.not.allowed"));
1160 private void highlightNamedArgs(GrNamedArgument[] namedArguments) {
1161 for (GrNamedArgument namedArgument : namedArguments) {
1162 final GrArgumentLabel label = namedArgument.getLabel();
1163 if (label != null && label.getExpression() == null && label.getNameElement().getNode().getElementType() != GroovyTokenTypes.mSTAR) {
1164 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(label).textAttributes(GroovySyntaxHighlighter.MAP_KEY).create();
1169 private void checkNamedArgs(GrNamedArgument[] namedArguments, boolean forArgList) {
1170 highlightNamedArgs(namedArguments);
1172 Set<Object> existingKeys = new HashSet<>();
1173 for (GrNamedArgument namedArgument : namedArguments) {
1174 GrArgumentLabel label = namedArgument.getLabel();
1175 Object value = PsiUtil.getLabelValue(label);
1176 if (value == null) continue;
1177 if (value == ObjectUtils.NULL) value = null;
1178 if (existingKeys.add(value)) continue;
1180 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("duplicated.named.parameter", String.valueOf(value))).range(label).create();
1183 myHolder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle.message("duplicate.element.in.the.map", String.valueOf(value))).range(label).create();
1189 public void visitNewExpression(@NotNull GrNewExpression newExpression) {
1190 GrTypeArgumentList constructorTypeArguments = newExpression.getConstructorTypeArguments();
1191 if (constructorTypeArguments != null) {
1192 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("groovy.does.not.support.constructor.type.arguments")).range(constructorTypeArguments).create();
1195 final GrTypeElement typeElement = newExpression.getTypeElement();
1197 if (typeElement instanceof GrBuiltInTypeElement) {
1198 if (newExpression.getArrayCount() == 0) {
1199 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("create.instance.of.built-in.type")).range(typeElement).create();
1203 if (newExpression.getArrayCount() > 0) return;
1205 GrCodeReferenceElement refElement = newExpression.getReferenceElement();
1206 if (refElement == null) return;
1208 final PsiElement element = refElement.resolve();
1209 if (element instanceof PsiClass) {
1210 PsiClass clazz = (PsiClass)element;
1211 if (clazz.hasModifierProperty(PsiModifier.ABSTRACT)) {
1212 if (newExpression.getAnonymousClassDefinition() == null) {
1213 String message = clazz.isInterface()
1214 ? GroovyBundle.message("cannot.instantiate.interface", clazz.getName())
1215 : GroovyBundle.message("cannot.instantiate.abstract.class", clazz.getName());
1216 myHolder.newAnnotation(HighlightSeverity.ERROR, message).range(refElement).create();
1223 public void visitArgumentList(@NotNull GrArgumentList list) {
1224 checkNamedArgs(list.getNamedArguments(), true);
1228 public void visitBreakStatement(@NotNull GrBreakStatement breakStatement) {
1229 checkFlowInterruptStatement(breakStatement, myHolder);
1233 public void visitContinueStatement(@NotNull GrContinueStatement continueStatement) {
1234 checkFlowInterruptStatement(continueStatement, myHolder);
1238 public void visitPackageDefinition(@NotNull GrPackageDefinition packageDefinition) {
1239 final GrModifierList modifierList = packageDefinition.getAnnotationList();
1240 checkAnnotationList(myHolder, modifierList, GroovyBundle.message("package.definition.cannot.have.modifiers"));
1244 public void visitLambdaExpression(@NotNull GrLambdaExpression expression) {
1245 super.visitLambdaExpression(expression);
1247 PsiElement arrow = expression.getArrow();
1248 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(arrow).textAttributes(GroovySyntaxHighlighter.LAMBDA_ARROW_AND_BRACES).create();
1252 public void visitBlockLambdaBody(@NotNull GrBlockLambdaBody body) {
1253 super.visitBlockLambdaBody(body);
1255 PsiElement lBrace = body.getLBrace();
1256 if (lBrace != null) {
1257 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(lBrace).textAttributes(GroovySyntaxHighlighter.LAMBDA_ARROW_AND_BRACES).create();
1260 PsiElement rBrace = body.getRBrace();
1261 if (rBrace != null) {
1262 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(rBrace).textAttributes(GroovySyntaxHighlighter.LAMBDA_ARROW_AND_BRACES).create();
1267 public void visitClosure(@NotNull GrClosableBlock closure) {
1268 super.visitClosure(closure);
1270 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(closure.getLBrace()).textAttributes(GroovySyntaxHighlighter.CLOSURE_ARROW_AND_BRACES).create();
1271 PsiElement rBrace = closure.getRBrace();
1272 if (rBrace != null) {
1273 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(rBrace).textAttributes(GroovySyntaxHighlighter.CLOSURE_ARROW_AND_BRACES).create();
1275 PsiElement closureArrow = closure.getArrow();
1276 if (closureArrow != null) {
1277 myHolder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(closureArrow).textAttributes(GroovySyntaxHighlighter.CLOSURE_ARROW_AND_BRACES).create();
1280 if (TypeInferenceHelper.isTooComplexTooAnalyze(closure)) {
1281 int startOffset = closure.getTextRange().getStartOffset();
1283 PsiElement arrow = closure.getArrow();
1284 if (arrow != null) {
1285 endOffset = arrow.getTextRange().getEndOffset();
1288 Document document = PsiDocumentManager.getInstance(closure.getProject()).getDocument(closure.getContainingFile());
1289 if (document == null) return;
1290 String text = document.getText();
1291 endOffset = Math.min(closure.getTextRange().getEndOffset(), text.indexOf('\n', startOffset));
1293 myHolder.newAnnotation(HighlightSeverity.WEAK_WARNING, GroovyBundle.message("closure.is.too.complex.to.analyze")).range(new TextRange(startOffset, endOffset)).create();
1298 public void visitLiteralExpression(@NotNull GrLiteral literal) {
1299 final IElementType elementType = literal.getFirstChild().getNode().getElementType();
1300 if (GroovyTokenSets.STRING_LITERALS.contains(elementType)) {
1301 checkStringLiteral(literal);
1303 else if (elementType == GroovyTokenTypes.mREGEX_LITERAL || elementType == GroovyTokenTypes.mDOLLAR_SLASH_REGEX_LITERAL) {
1304 checkRegexLiteral(literal.getFirstChild());
1309 public void visitRegexExpression(@NotNull GrRegex regex) {
1310 checkRegexLiteral(regex);
1313 private void checkRegexLiteral(PsiElement regex) {
1315 if (regex instanceof GrRegex) {
1316 parts = ((GrRegex)regex).getTextParts();
1319 parts = new String[]{regex.getFirstChild().getNextSibling().getText()};
1322 for (String part : parts) {
1323 if (!GrStringUtil.parseRegexCharacters(part, new StringBuilder(part.length()), null, regex.getText().startsWith("/"))) {
1324 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("illegal.escape.character.in.string.literal")).range(regex).create();
1331 public void visitGStringExpression(@NotNull GrString gstring) {
1332 for (GrStringContent part : gstring.getContents()) {
1333 final String text = part.getText();
1334 if (!GrStringUtil.parseStringCharacters(text, new StringBuilder(text.length()), null)) {
1335 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("illegal.escape.character.in.string.literal")).range(part).create();
1343 public void visitGStringInjection(@NotNull GrStringInjection injection) {
1344 if (((GrString)injection.getParent()).isPlainString()) {
1345 PsiElement lineFeed = getLineFeed(injection);
1346 if (lineFeed != null) {
1347 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("injection.should.not.contain.line.feeds"))
1354 private void checkStringLiteral(PsiElement literal) {
1355 InjectedLanguageManager injectedLanguageManager = InjectedLanguageManager.getInstance(literal.getProject());
1357 if (injectedLanguageManager.isInjectedFragment(literal.getContainingFile())) {
1358 text = injectedLanguageManager.getUnescapedText(literal);
1361 text = literal.getText();
1363 assert text != null;
1365 StringBuilder builder = new StringBuilder(text.length());
1366 String quote = GrStringUtil.getStartQuote(text);
1367 if (quote.isEmpty()) return;
1369 String substring = text.substring(quote.length());
1370 if (!GrStringUtil.parseStringCharacters(substring, new StringBuilder(text.length()), null)) {
1371 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("illegal.escape.character.in.string.literal")).range(literal).create();
1375 int[] offsets = new int[substring.length() + 1];
1376 boolean result = GrStringUtil.parseStringCharacters(substring, builder, offsets);
1377 LOG.assertTrue(result);
1378 if (!builder.toString().endsWith(quote) || substring.charAt(offsets[builder.length() - quote.length()]) == '\\') {
1379 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("string.end.expected")).create();
1384 public void visitForInClause(@NotNull GrForInClause forInClause) {
1385 final GrVariable var = forInClause.getDeclaredVariable();
1386 if (var == null) return;
1387 final GrModifierList modifierList = var.getModifierList();
1388 if (modifierList == null) return;
1389 final PsiElement[] modifiers = modifierList.getModifiers();
1390 for (PsiElement modifier : modifiers) {
1391 if (modifier instanceof PsiAnnotation) continue;
1392 final String modifierText = modifier.getText();
1393 if (PsiModifier.FINAL.equals(modifierText)) continue;
1394 if (GrModifier.DEF.equals(modifierText)) continue;
1395 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("not.allowed.modifier.in.for.in", modifierText)).range(modifier).create();
1400 public void visitFile(@NotNull GroovyFileBase file) {
1401 final PsiClass scriptClass = file.getScriptClass();
1402 if (scriptClass != null) {
1403 checkSameNameMethodsWithDifferentAccessModifiers(myHolder, file.getMethods());
1409 public void visitAnnotation(@NotNull GrAnnotation annotation) {
1410 AnnotationChecker.checkApplicability(annotation, annotation.getOwner(), myHolder, annotation.getClassReference());
1414 public void visitAnnotationArgumentList(@NotNull GrAnnotationArgumentList annotationArgumentList) {
1415 GrAnnotation parent = (GrAnnotation)annotationArgumentList.getParent();
1416 Pair<PsiElement, String> r = AnnotationChecker.checkAnnotationArgumentList(parent, myHolder);
1417 if (r != null && r.getFirst() != null && r.getSecond() != null) {
1418 myHolder.newAnnotation(HighlightSeverity.ERROR, r.getSecond()).range(r.getFirst()).create();
1423 public void visitAnnotationMethod(@NotNull GrAnnotationMethod annotationMethod) {
1424 super.visitAnnotationMethod(annotationMethod);
1426 final PsiReferenceList list = annotationMethod.getThrowsList();
1427 if (list.getReferencedTypes().length > 0) {
1428 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("throws.clause.is.not.allowed.in.at.interface")).range(list).create();
1431 final GrAnnotationMemberValue value = annotationMethod.getDefaultValue();
1432 if (value == null) return;
1434 final PsiType type = annotationMethod.getReturnType();
1436 Pair.NonNull<PsiElement, String> result = CustomAnnotationChecker.checkAnnotationValueByType(value, type, false);
1437 if (result != null) {
1438 myHolder.newAnnotation(HighlightSeverity.ERROR, result.getSecond()).range(result.getFirst()).create();
1443 public void visitAnnotationNameValuePair(@NotNull GrAnnotationNameValuePair nameValuePair) {
1444 final PsiElement identifier = nameValuePair.getNameIdentifierGroovy();
1445 if (identifier == null) {
1446 final PsiElement parent = nameValuePair.getParent();
1447 if (parent instanceof GrAnnotationArgumentList) {
1448 final int count = ((GrAnnotationArgumentList)parent).getAttributes().length;
1450 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("attribute.name.expected")).create();
1455 final GrAnnotationMemberValue value = nameValuePair.getValue();
1456 if (value != null) {
1457 checkAnnotationAttributeValue(value, value);
1461 private boolean checkAnnotationAttributeValue(@Nullable GrAnnotationMemberValue value, @NotNull PsiElement toHighlight) {
1462 if (value == null) return false;
1464 if (value instanceof GrLiteral) return false;
1465 if (value instanceof GrFunctionalExpression) return false;
1466 if (value instanceof GrAnnotation) return false;
1468 if (value instanceof GrReferenceExpression) {
1469 PsiElement resolved = ((GrReferenceExpression)value).resolve();
1470 if (resolved instanceof PsiClass) return false;
1471 if (resolved instanceof PsiEnumConstant) return false;
1472 if (resolved == null && isClassReference(value)) return false;
1474 if (resolved instanceof GrAccessorMethod) resolved = ((GrAccessorMethod)resolved).getProperty();
1475 if (resolved instanceof PsiField) {
1476 GrExpression initializer;
1478 if (resolved instanceof GrField) {
1479 initializer = ((GrField)resolved).getInitializerGroovy();
1482 final PsiExpression _initializer = ((PsiField)resolved).getInitializer();
1483 initializer = _initializer != null
1484 ? (GrExpression)ExpressionConverter.getExpression(_initializer, GroovyLanguage.INSTANCE, value.getProject())
1488 catch (IncorrectOperationException e) {
1492 if (initializer != null) {
1493 return checkAnnotationAttributeValue(initializer, toHighlight);
1497 if (value instanceof GrAnnotationArrayInitializer) {
1498 for (GrAnnotationMemberValue expression : ((GrAnnotationArrayInitializer)value).getInitializers()) {
1499 if (checkAnnotationAttributeValue(expression, toHighlight)) return true;
1503 if (value instanceof GrUnaryExpression) {
1504 final IElementType tokenType = ((GrUnaryExpression)value).getOperationTokenType();
1505 if (tokenType == GroovyTokenTypes.mMINUS || tokenType == GroovyTokenTypes.mPLUS) {
1506 return checkAnnotationAttributeValue(((GrUnaryExpression)value).getOperand(), toHighlight);
1510 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("expected.0.to.be.inline.constant", value.getText())).range(toHighlight).create();
1514 private static boolean isClassReference(GrAnnotationMemberValue value) {
1515 if (value instanceof GrReferenceExpression) {
1516 final String referenceName = ((GrReferenceExpression)value).getReferenceName();
1517 if ("class".equals(referenceName)) {
1518 final GrExpression qualifier = ((GrReferenceExpression)value).getQualifier();
1519 if (qualifier instanceof GrReferenceExpression) {
1520 final PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
1521 if (resolved instanceof PsiClass) {
1532 public void visitImportStatement(@NotNull GrImportStatement importStatement) {
1533 checkAnnotationList(myHolder, importStatement.getAnnotationList(), GroovyBundle.message("import.statement.cannot.have.modifiers"));
1537 public void visitExtendsClause(@NotNull GrExtendsClause extendsClause) {
1538 GrTypeDefinition typeDefinition = (GrTypeDefinition)extendsClause.getParent();
1540 if (typeDefinition.isAnnotationType()) {
1541 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.types.may.not.have.extends.clause")).create();
1543 else if (typeDefinition.isTrait()) {
1544 checkReferenceList(myHolder, extendsClause, IS_TRAIT, GroovyBundle.message("only.traits.expected.here"), null);
1546 else if (typeDefinition.isInterface()) {
1547 checkReferenceList(myHolder, extendsClause, IS_INTERFACE, GroovyBundle.message("no.class.expected.here"), null);
1549 else if (typeDefinition.isEnum()) {
1550 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("enums.may.not.have.extends.clause")).create();
1553 checkReferenceList(myHolder, extendsClause, IS_NOT_INTERFACE, GroovyBundle.message("no.interface.expected.here"), new ChangeExtendsImplementsQuickFix(typeDefinition));
1554 checkForWildCards(myHolder, extendsClause);
1560 public void visitImplementsClause(@NotNull GrImplementsClause implementsClause) {
1561 GrTypeDefinition typeDefinition = (GrTypeDefinition)implementsClause.getParent();
1563 if (typeDefinition.isAnnotationType()) {
1564 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.types.may.not.have.implements.clause")).create();
1566 else if (GrTraitUtil.isInterface(typeDefinition)) {
1567 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("no.implements.clause.allowed.for.interface"))
1568 .withFix(new ChangeExtendsImplementsQuickFix(typeDefinition)).create();
1571 checkReferenceList(myHolder, implementsClause, IS_INTERFACE, GroovyBundle.message("no.class.expected.here"), new ChangeExtendsImplementsQuickFix(typeDefinition));
1572 checkForWildCards(myHolder, implementsClause);
1576 private static void checkReferenceList(@NotNull AnnotationHolder holder,
1577 @NotNull GrReferenceList list,
1578 @NotNull Condition<? super PsiClass> applicabilityCondition,
1579 @NotNull String message,
1580 @Nullable IntentionAction fix) {
1581 for (GrCodeReferenceElement refElement : list.getReferenceElementsGroovy()) {
1582 final PsiElement psiClass = refElement.resolve();
1583 if (psiClass instanceof PsiClass && !applicabilityCondition.value((PsiClass)psiClass)) {
1584 AnnotationBuilder builder = holder.newAnnotation(HighlightSeverity.ERROR, message).range(refElement);
1586 builder = builder.withFix(fix);
1593 private static void checkFlowInterruptStatement(GrFlowInterruptingStatement statement, AnnotationHolder holder) {
1594 final PsiElement label = statement.getLabelIdentifier();
1596 if (label != null) {
1597 final GrLabeledStatement resolved = statement.resolveLabel();
1598 if (resolved == null) {
1599 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("undefined.label", statement.getLabelName())).range(label).create();
1603 final GrStatement targetStatement = statement.findTargetStatement();
1604 if (targetStatement == null) {
1605 if (statement instanceof GrContinueStatement && label == null) {
1606 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("continue.outside.loop")).create();
1608 else if (statement instanceof GrBreakStatement && label == null) {
1609 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("break.outside.loop.or.switch")).create();
1612 if (statement instanceof GrBreakStatement && label != null && findFirstLoop(statement) == null) {
1613 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("break.outside.loop")).create();
1618 private static GrLoopStatement findFirstLoop(GrFlowInterruptingStatement statement) {
1619 return PsiTreeUtil.getParentOfType(statement, GrLoopStatement.class, true, GrClosableBlock.class, GrMember.class, GroovyFile.class);
1622 private static void checkThisOrSuperReferenceExpression(final GrReferenceExpression ref, AnnotationHolder holder) {
1623 PsiElement nameElement = ref.getReferenceNameElement();
1624 if (nameElement == null) return;
1626 IElementType elementType = nameElement.getNode().getElementType();
1627 if (!(elementType == GroovyTokenTypes.kSUPER || elementType == GroovyTokenTypes.kTHIS)) return;
1629 final GrExpression qualifier = ref.getQualifier();
1630 if (qualifier instanceof GrReferenceExpression) {
1631 final PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
1632 if (resolved instanceof PsiClass) {
1633 GrTypeDefinition containingClass = PsiTreeUtil.getParentOfType(ref, GrTypeDefinition.class, true, GroovyFile.class);
1635 if (elementType == GroovyTokenTypes.kSUPER && containingClass != null && GrTraitUtil.isTrait((PsiClass)resolved)) {
1636 PsiClassType[] superTypes = containingClass.getSuperTypes();
1637 if (ContainerUtil.find(superTypes, type -> ref.getManager().areElementsEquivalent(type.resolve(), resolved)) != null) {
1638 holder.newSilentAnnotation(HighlightSeverity.INFORMATION).range(nameElement).textAttributes(GroovySyntaxHighlighter.KEYWORD).create();
1639 return; // reference to trait method
1643 if (containingClass == null || containingClass.getContainingClass() == null && !containingClass.isAnonymous()) {
1644 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("qualified.0.is.allowed.only.in.nested.or.inner.classes",
1645 nameElement.getText())).create();
1649 if (!PsiTreeUtil.isAncestor(resolved, ref, true)) {
1650 String qname = ((PsiClass)resolved).getQualifiedName();
1651 assert qname != null;
1652 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("is.not.enclosing.class", qname)).create();
1656 else if (qualifier == null) {
1657 if (elementType == GroovyTokenTypes.kSUPER) {
1658 final GrMember container = PsiTreeUtil.getParentOfType(ref, GrMethod.class, GrClassInitializer.class);
1659 if (container != null && container.hasModifierProperty(PsiModifier.STATIC)) {
1660 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("super.cannot.be.used.in.static.context")).create();
1666 private static void checkGrDocReferenceElement(AnnotationHolder holder, PsiElement element) {
1667 ASTNode node = element.getNode();
1668 if (node != null && TokenSets.BUILT_IN_TYPES.contains(node.getElementType())) {
1669 holder.newSilentAnnotation(HighlightSeverity.INFORMATION).textAttributes(GroovySyntaxHighlighter.KEYWORD).create();
1673 private static void checkAnnotationList(AnnotationHolder holder, @NotNull GrModifierList modifierList, @NotNull String message) {
1674 final PsiElement[] modifiers = modifierList.getModifiers();
1675 for (PsiElement modifier : modifiers) {
1676 if (!(modifier instanceof PsiAnnotation)) {
1677 holder.newAnnotation(HighlightSeverity.ERROR, message).range(modifier).create();
1682 private static void checkImplementedMethodsOfClass(AnnotationHolder holder, GrTypeDefinition typeDefinition) {
1683 if (typeDefinition.hasModifierProperty(PsiModifier.ABSTRACT)) return;
1684 if (typeDefinition.isAnnotationType()) return;
1685 if (typeDefinition instanceof GrTypeParameter) return;
1688 PsiMethod abstractMethod = ClassUtil.getAnyAbstractMethod(typeDefinition);
1689 if (abstractMethod == null) return;
1691 String notImplementedMethodName = abstractMethod.getName();
1693 final TextRange range = GrHighlightUtil.getClassHeaderTextRange(typeDefinition);
1694 String message = GroovyBundle.message("method.is.not.implemented", notImplementedMethodName);
1695 AnnotationBuilder builder =
1696 holder.newAnnotation(HighlightSeverity.ERROR, message)
1698 registerImplementsMethodsFix(typeDefinition, abstractMethod, builder, message, range).create();
1701 @Contract(pure = true)
1702 private static AnnotationBuilder registerImplementsMethodsFix(@NotNull GrTypeDefinition typeDefinition,
1703 @NotNull PsiMethod abstractMethod,
1704 @NotNull AnnotationBuilder builder,
1707 if (!OverrideImplementExploreUtil.getMethodsToOverrideImplement(typeDefinition, true).isEmpty()) {
1708 builder = builder.withFix(QuickFixFactory.getInstance().createImplementMethodsFix(typeDefinition));
1711 if (!JavaPsiFacade.getInstance(typeDefinition.getProject()).getResolveHelper().isAccessible(abstractMethod, typeDefinition, null)) {
1712 builder = registerLocalFix(builder, new GrModifierFix(abstractMethod, PsiModifier.PUBLIC, true, true, GrModifierFix.MODIFIER_LIST_OWNER), abstractMethod,
1713 message, ProblemHighlightType.ERROR, range);
1714 builder = registerLocalFix(builder, new GrModifierFix(abstractMethod, PsiModifier.PROTECTED, true, true, GrModifierFix.MODIFIER_LIST_OWNER), abstractMethod,
1715 message, ProblemHighlightType.ERROR, range);
1718 if (!(typeDefinition instanceof GrAnnotationTypeDefinition) && typeDefinition.getModifierList() != null) {
1719 builder = registerLocalFix(builder, new GrModifierFix(typeDefinition, PsiModifier.ABSTRACT, false, true, GrModifierFix.MODIFIER_LIST_OWNER), typeDefinition,
1720 message, ProblemHighlightType.ERROR, range);
1725 private static void checkInnerMethod(AnnotationHolder holder, GrMethod grMethod) {
1726 final PsiElement parent = grMethod.getParent();
1727 if (parent instanceof GrOpenBlock || parent instanceof GrClosableBlock || parent instanceof GrBlockLambdaBody) {
1728 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("Inner.methods.are.not.supported")).range(grMethod.getNameIdentifierGroovy()).create();
1733 @Contract(pure=true)
1734 private static AnnotationBuilder registerMakeAbstractMethodNotAbstractFix(AnnotationBuilder builder,
1736 boolean makeClassAbstract,
1737 String message, TextRange range) {
1738 if (method.getBlock() == null) {
1739 builder = builder.withFix(QuickFixFactory.getInstance().createAddMethodBodyFix(method));
1742 builder = builder.withFix(QuickFixFactory.getInstance().createDeleteMethodBodyFix(method));
1745 GrModifierFix fix = new GrModifierFix(method, PsiModifier.ABSTRACT, false, false, GrModifierFix.MODIFIER_LIST_OWNER);
1746 builder = registerLocalFix(builder, fix, method, message, ProblemHighlightType.ERROR, range);
1747 if (makeClassAbstract) {
1748 final PsiClass containingClass = method.getContainingClass();
1749 if (containingClass != null) {
1750 final PsiModifierList list = containingClass.getModifierList();
1751 if (list != null && !list.hasModifierProperty(PsiModifier.ABSTRACT)) {
1752 builder = registerLocalFix(builder, new GrModifierFix(containingClass, PsiModifier.ABSTRACT, false, true, GrModifierFix.MODIFIER_LIST_OWNER), containingClass, message, ProblemHighlightType.ERROR, range);
1759 private static void checkMethodDefinitionModifiers(AnnotationHolder holder, GrMethod method) {
1760 final GrModifierList modifiersList = method.getModifierList();
1761 checkAccessModifiers(holder, modifiersList, method);
1762 checkDuplicateModifiers(holder, modifiersList, method);
1763 checkOverrideAnnotation(holder, modifiersList, method);
1765 checkModifierIsNotAllowed(modifiersList, PsiModifier.VOLATILE, GroovyBundle.message("method.has.incorrect.modifier.volatile"), holder);
1767 checkForAbstractAndFinalCombination(holder, method, modifiersList);
1770 boolean isMethodAbstract = modifiersList.hasExplicitModifier(PsiModifier.ABSTRACT);
1771 PsiElement modifierOrList = getModifierOrList(modifiersList, PsiModifier.ABSTRACT);
1772 if (method.getParent() instanceof GroovyFileBase) {
1773 if (isMethodAbstract) {
1774 String message = GroovyBundle.message("script.method.cannot.have.modifier.abstract");
1775 AnnotationBuilder builder =
1776 holder.newAnnotation(HighlightSeverity.ERROR, message)
1777 .range(modifierOrList);
1778 registerMakeAbstractMethodNotAbstractFix(builder, method, false, message, modifierOrList.getTextRange()).create();
1781 checkModifierIsNotAllowed(modifiersList, PsiModifier.NATIVE, GroovyBundle.message("script.cannot.have.modifier.native"), holder);
1783 //type definition methods
1784 else if (method.getParent() != null && method.getParent().getParent() instanceof GrTypeDefinition) {
1785 GrTypeDefinition containingTypeDef = ((GrTypeDefinition)method.getParent().getParent());
1787 if (containingTypeDef.isTrait()) {
1788 checkModifierIsNotAllowed(modifiersList, PsiModifier.PROTECTED, GroovyBundle.message("trait.method.cannot.be.protected"), holder);
1791 else if (containingTypeDef.isInterface()) {
1792 checkModifierIsNotAllowed(modifiersList, PsiModifier.STATIC, GroovyBundle.message("interface.must.have.no.static.method"), holder);
1793 checkModifierIsNotAllowed(modifiersList, PsiModifier.PRIVATE, GroovyBundle.message("interface.members.are.not.allowed.to.be", PsiModifier.PRIVATE), holder);
1794 checkModifierIsNotAllowed(modifiersList, PsiModifier.PROTECTED, GroovyBundle.message("interface.members.are.not.allowed.to.be", PsiModifier.PROTECTED), holder);
1796 else if (containingTypeDef.isAnonymous()) {
1797 if (isMethodAbstract) {
1798 String message = GroovyBundle.message("anonymous.class.cannot.have.abstract.method");
1799 AnnotationBuilder builder =
1800 holder.newAnnotation(HighlightSeverity.ERROR, message).range(
1802 registerMakeAbstractMethodNotAbstractFix(builder, method, false, message, modifierOrList.getTextRange()).create();
1807 PsiModifierList typeDefModifiersList = containingTypeDef.getModifierList();
1808 LOG.assertTrue(typeDefModifiersList != null, "modifiers list must be not null");
1810 if (!typeDefModifiersList.hasModifierProperty(PsiModifier.ABSTRACT) && isMethodAbstract) {
1812 String message = GroovyBundle.message("only.abstract.class.can.have.abstract.method");
1813 AnnotationBuilder builder =
1814 holder.newAnnotation(HighlightSeverity.ERROR, message)
1815 .range(modifiersList);
1816 registerMakeAbstractMethodNotAbstractFix(builder, method, true, message, modifierOrList.getTextRange()).create();
1820 if (method.isConstructor()) {
1821 checkModifierIsNotAllowed(modifiersList, PsiModifier.STATIC, GroovyBundle.message("constructor.cannot.have.static.modifier"), holder);
1825 if (method.hasModifierProperty(PsiModifier.NATIVE) && method.getBlock() != null) {
1826 String message = GroovyBundle.message("native.methods.cannot.have.body");
1827 PsiElement list = getModifierOrList(modifiersList, PsiModifier.NATIVE);
1828 AnnotationBuilder builder = holder.newAnnotation(HighlightSeverity.ERROR, message)
1830 builder = registerLocalFix(builder, new GrModifierFix((PsiMember)modifiersList.getParent(), PsiModifier.NATIVE, true, false, GrModifierFix.MODIFIER_LIST), modifiersList,
1831 message, ProblemHighlightType.ERROR, list.getTextRange());
1832 builder.withFix(QuickFixFactory.getInstance().createDeleteMethodBodyFix(method))
1837 private static void checkForAbstractAndFinalCombination(AnnotationHolder holder, GrMember member, GrModifierList modifiersList) {
1838 if (member.hasModifierProperty(PsiModifier.FINAL) && member.hasModifierProperty(PsiModifier.ABSTRACT)) {
1839 String message = GroovyBundle.message("illegal.combination.of.modifiers.abstract.and.final");
1840 AnnotationBuilder builder =
1841 holder.newAnnotation(HighlightSeverity.ERROR, message)
1842 .range(modifiersList);
1843 builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.FINAL, false, false, GrModifierFix.MODIFIER_LIST), modifiersList,
1844 message, ProblemHighlightType.ERROR, modifiersList.getTextRange());
1845 builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.ABSTRACT, false, false, GrModifierFix.MODIFIER_LIST), modifiersList,
1846 message, ProblemHighlightType.ERROR, modifiersList.getTextRange());
1852 private static PsiElement getModifierOrList(@NotNull GrModifierList modifiersList, @GrModifier.GrModifierConstant final String modifier) {
1853 PsiElement m = modifiersList.getModifier(modifier);
1854 return m != null ? m : modifiersList;
1857 private static void checkOverrideAnnotation(AnnotationHolder holder, GrModifierList list, GrMethod method) {
1858 final PsiAnnotation overrideAnnotation = list.findAnnotation("java.lang.Override");
1859 if (overrideAnnotation == null) {
1863 MethodSignatureBackedByPsiMethod superMethod = SuperMethodsSearch.search(method, null, true, false).findFirst();
1864 if (superMethod == null) {
1865 holder.newAnnotation(HighlightSeverity.WARNING, GroovyBundle.message("method.does.not.override.super")).range(overrideAnnotation).create();
1868 catch (IndexNotReadyException ignored) {
1873 private static void checkTypeDefinitionModifiers(AnnotationHolder holder, GrTypeDefinition typeDefinition) {
1874 GrModifierList modifiersList = typeDefinition.getModifierList();
1876 if (modifiersList == null) return;
1878 checkAccessModifiers(holder, modifiersList, typeDefinition);
1879 checkDuplicateModifiers(holder, modifiersList, typeDefinition);
1881 PsiClassType[] extendsListTypes = typeDefinition.getExtendsListTypes();
1883 for (PsiClassType classType : extendsListTypes) {
1884 PsiClass psiClass = classType.resolve();
1886 if (psiClass != null && psiClass.hasModifierProperty(PsiModifier.FINAL)) {
1887 PsiElement identifierGroovy = typeDefinition.getNameIdentifierGroovy();
1888 String message = GroovyBundle.message("final.class.cannot.be.extended");
1889 AnnotationBuilder builder = holder.newAnnotation(HighlightSeverity.ERROR, message)
1890 .range(identifierGroovy);
1891 builder = registerLocalFix(builder, new GrModifierFix(typeDefinition, PsiModifier.FINAL, false, false, GrModifierFix.MODIFIER_LIST_OWNER), typeDefinition,
1892 message, ProblemHighlightType.ERROR, identifierGroovy.getTextRange());
1897 if (!typeDefinition.isEnum()) {
1898 checkForAbstractAndFinalCombination(holder, typeDefinition, modifiersList);
1901 checkModifierIsNotAllowed(modifiersList, PsiModifier.TRANSIENT, GroovyBundle.message("modifier.transient.not.allowed.here"), holder);
1902 checkModifierIsNotAllowed(modifiersList, PsiModifier.VOLATILE, GroovyBundle.message("modifier.volatile.not.allowed.here"), holder);
1904 if (typeDefinition.isInterface()) {
1905 checkModifierIsNotAllowed(modifiersList, PsiModifier.FINAL, GroovyBundle.message("interface.cannot.have.modifier.final"), holder);
1909 private static void checkDuplicateModifiers(AnnotationHolder holder, @NotNull GrModifierList list, PsiMember member) {
1910 final PsiElement[] modifiers = list.getModifiers();
1911 Set<String> set = new THashSet<>(modifiers.length);
1912 for (PsiElement modifier : modifiers) {
1913 if (modifier instanceof GrAnnotation) continue;
1914 @GrModifier.GrModifierConstant String name = modifier.getText();
1915 if (set.contains(name)) {
1916 String message = GroovyBundle.message("duplicate.modifier", name);
1917 AnnotationBuilder builder =
1918 holder.newAnnotation(HighlightSeverity.ERROR, message).range(list);
1919 if (member != null) {
1920 builder = registerLocalFix(builder, new GrModifierFix(member, name, false, false, GrModifierFix.MODIFIER_LIST), list, message,
1921 ProblemHighlightType.ERROR, list.getTextRange());
1931 private static void checkAccessModifiers(AnnotationHolder holder, @NotNull GrModifierList modifierList, PsiMember member) {
1932 boolean hasPrivate = modifierList.hasExplicitModifier(PsiModifier.PRIVATE);
1933 boolean hasPublic = modifierList.hasExplicitModifier(PsiModifier.PUBLIC);
1934 boolean hasProtected = modifierList.hasExplicitModifier(PsiModifier.PROTECTED);
1936 if (hasPrivate && hasPublic || hasPrivate && hasProtected || hasPublic && hasProtected) {
1937 String message = GroovyBundle.message("illegal.combination.of.modifiers");
1938 AnnotationBuilder builder =
1939 holder.newAnnotation(HighlightSeverity.ERROR, message).range(modifierList);
1941 builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.PRIVATE, false, false, GrModifierFix.MODIFIER_LIST), modifierList,
1942 message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1945 builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.PROTECTED, false, false, GrModifierFix.MODIFIER_LIST), modifierList,
1946 message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1949 builder = registerLocalFix(builder, new GrModifierFix(member, PsiModifier.PUBLIC, false, false, GrModifierFix.MODIFIER_LIST), modifierList,
1950 message, ProblemHighlightType.ERROR, modifierList.getTextRange());
1954 else if (member instanceof PsiClass &&
1955 member.getContainingClass() == null &&
1956 GroovyConfigUtils.getInstance().isVersionAtLeast(member, GroovyConfigUtils.GROOVY2_0)) {
1957 checkModifierIsNotAllowed(modifierList, PsiModifier.PRIVATE, GroovyBundle.message("top.level.class.may.not.have.private.modifier"), holder);
1958 checkModifierIsNotAllowed(modifierList, PsiModifier.PROTECTED, GroovyBundle.message("top.level.class.may.not.have.protected.modifier"), holder);
1962 private void checkDuplicateMethod(@NotNull GrMethod method) {
1963 PsiClass clazz = method.getContainingClass();
1964 if (clazz == null) return;
1965 GrReflectedMethod[] reflectedMethods = method.getReflectedMethods();
1966 if (reflectedMethods.length == 0) {
1967 doCheckDuplicateMethod(method, clazz);
1970 for (GrReflectedMethod reflectedMethod : reflectedMethods) {
1971 doCheckDuplicateMethod(reflectedMethod, clazz);
1976 private void doCheckDuplicateMethod(@NotNull GrMethod method, @NotNull PsiClass clazz) {
1977 Set<MethodSignature> duplicatedSignatures = GrClassImplUtil.getDuplicatedSignatures(clazz);
1978 if (duplicatedSignatures.isEmpty()) return; // optimization
1980 PsiSubstitutor substitutor = JavaPsiFacade.getElementFactory(method.getProject()).createRawSubstitutor(method);
1981 MethodSignature signature = method.getSignature(substitutor);
1982 if (!duplicatedSignatures.contains(signature)) return;
1984 String signaturePresentation = GroovyPresentationUtil.getSignaturePresentation(signature);
1985 GrMethod original = method instanceof GrReflectedMethod ? ((GrReflectedMethod)method).getBaseMethod() : method;
1986 myHolder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("method.duplicate", signaturePresentation, clazz.getName())).range(GrHighlightUtil.getMethodHeaderTextRange(original)).create();
1989 private static void checkTypeDefinition(AnnotationHolder holder, @NotNull GrTypeDefinition typeDefinition) {
1990 if (typeDefinition.isAnonymous()) {
1991 PsiClass superClass = ((PsiAnonymousClass)typeDefinition).getBaseClassType().resolve();
1992 if (superClass instanceof GrTypeDefinition && ((GrTypeDefinition)superClass).isTrait()) {
1993 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("anonymous.classes.cannot.be.created.from.traits")).range(typeDefinition.getNameIdentifierGroovy()).create();
1996 if (typeDefinition.isAnnotationType() && typeDefinition.getContainingClass() != null) {
1997 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("annotation.type.cannot.be.inner")).range(typeDefinition.getNameIdentifierGroovy()).create();
2000 if (!typeDefinition.hasModifierProperty(PsiModifier.STATIC)
2001 && (typeDefinition.getContainingClass() != null || typeDefinition instanceof GrAnonymousClassDefinition)) {
2002 GrTypeDefinition owner = PsiTreeUtil.getParentOfType(typeDefinition, GrTypeDefinition.class);
2003 if (owner instanceof GrTraitTypeDefinition) {
2004 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("non.static.classes.not.allowed")).range(typeDefinition.getNameIdentifierGroovy()).create();
2008 checkDuplicateClass(typeDefinition, holder);
2010 checkCyclicInheritance(holder, typeDefinition);
2013 private static void checkCyclicInheritance(AnnotationHolder holder,
2014 @NotNull GrTypeDefinition typeDefinition) {
2015 final PsiClass psiClass = InheritanceUtil.getCircularClass(typeDefinition);
2016 if (psiClass != null) {
2017 String qname = psiClass.getQualifiedName();
2018 assert qname != null;
2019 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("cyclic.inheritance.involving.0", qname)).range(GrHighlightUtil.getClassHeaderTextRange(typeDefinition)).create();
2023 private static void checkForWildCards(AnnotationHolder holder, @Nullable GrReferenceList clause) {
2024 if (clause == null) return;
2025 final GrCodeReferenceElement[] elements = clause.getReferenceElementsGroovy();
2026 for (GrCodeReferenceElement element : elements) {
2027 final GrTypeArgumentList list = element.getTypeArgumentList();
2029 for (GrTypeElement type : list.getTypeArgumentElements()) {
2030 if (type instanceof GrWildcardTypeArgument) {
2031 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("wildcards.are.not.allowed.in.extends.list")).range(type).create();
2038 private static void checkDuplicateClass(GrTypeDefinition typeDefinition, AnnotationHolder holder) {
2039 final PsiClass containingClass = typeDefinition.getContainingClass();
2040 String name = typeDefinition.getName();
2041 if (containingClass != null) {
2042 final String containingClassName = containingClass.getName();
2043 if (containingClassName != null && containingClassName.equals(name)) {
2044 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("duplicate.inner.class", name)).range(typeDefinition.getNameIdentifierGroovy()).create();
2047 final String qName = typeDefinition.getQualifiedName();
2048 if (qName != null) {
2049 JavaPsiFacade facade = JavaPsiFacade.getInstance(typeDefinition.getProject());
2050 GlobalSearchScope scope = inferClassScopeForSearchingDuplicates(typeDefinition);
2051 final PsiClass[] classes = facade.findClasses(qName, scope);
2052 if (classes.length > 1) {
2053 String packageName = getPackageName(typeDefinition);
2055 if (!isScriptGeneratedClass(classes)) {
2056 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("duplicate.class", name, packageName)).range(typeDefinition.getNameIdentifierGroovy()).create();
2059 holder.newAnnotation(HighlightSeverity.ERROR, GroovyBundle.message("script.generated.with.same.name", qName)).range(typeDefinition.getNameIdentifierGroovy()).create();
2065 private static GlobalSearchScope inferClassScopeForSearchingDuplicates(GrTypeDefinition typeDefinition) {
2066 GlobalSearchScope defaultScope = typeDefinition.getResolveScope();
2068 PsiFile file = typeDefinition.getContainingFile();
2069 if (file instanceof GroovyFile && ((GroovyFile)file).isScript()) {
2070 Module module = ModuleUtilCore.findModuleForPsiElement(file);
2071 if (module != null) {
2072 return defaultScope.intersectWith(module.getModuleScope());
2075 return defaultScope;
2078 private static String getPackageName(GrTypeDefinition typeDefinition) {
2079 final PsiFile file = typeDefinition.getContainingFile();
2080 String packageName = "<default package>";
2081 if (file instanceof GroovyFile) {
2082 final String name = ((GroovyFile)file).getPackageName();
2083 if (!name.isEmpty()) packageName = name;
2088 private static boolean isScriptGeneratedClass(PsiClass[] allClasses) {
2089 return allClasses.length == 2 && (allClasses[0] instanceof GroovyScriptClass || allClasses[1] instanceof GroovyScriptClass);