2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org
.jetbrains
.plugins
.groovy
.annotator
;
19 import com
.intellij
.codeInspection
.ProblemHighlightType
;
20 import com
.intellij
.lang
.ASTNode
;
21 import com
.intellij
.lang
.annotation
.Annotation
;
22 import com
.intellij
.lang
.annotation
.AnnotationHolder
;
23 import com
.intellij
.lang
.annotation
.Annotator
;
24 import com
.intellij
.openapi
.diagnostic
.Logger
;
25 import com
.intellij
.openapi
.util
.TextRange
;
26 import com
.intellij
.openapi
.util
.text
.StringUtil
;
27 import com
.intellij
.openapi
.vfs
.VirtualFile
;
28 import com
.intellij
.psi
.*;
29 import com
.intellij
.psi
.infos
.CandidateInfo
;
30 import com
.intellij
.psi
.search
.GlobalSearchScope
;
31 import com
.intellij
.psi
.util
.PsiTreeUtil
;
32 import gnu
.trove
.TObjectHashingStrategy
;
33 import org
.jetbrains
.annotations
.NotNull
;
34 import org
.jetbrains
.annotations
.Nullable
;
35 import org
.jetbrains
.plugins
.groovy
.GroovyBundle
;
36 import org
.jetbrains
.plugins
.groovy
.annotator
.intentions
.*;
37 import org
.jetbrains
.plugins
.groovy
.annotator
.intentions
.dynamic
.DynamicMethodFix
;
38 import org
.jetbrains
.plugins
.groovy
.annotator
.intentions
.dynamic
.DynamicPropertyFix
;
39 import org
.jetbrains
.plugins
.groovy
.codeInspection
.GroovyImportsTracker
;
40 import org
.jetbrains
.plugins
.groovy
.config
.GroovyConfigUtils
;
41 import org
.jetbrains
.plugins
.groovy
.highlighter
.DefaultHighlighter
;
42 import org
.jetbrains
.plugins
.groovy
.intentions
.utils
.DuplicatesUtil
;
43 import org
.jetbrains
.plugins
.groovy
.lang
.groovydoc
.psi
.api
.*;
44 import org
.jetbrains
.plugins
.groovy
.lang
.lexer
.GroovyTokenTypes
;
45 import org
.jetbrains
.plugins
.groovy
.lang
.lexer
.TokenSets
;
46 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.*;
47 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.GroovyResolveResult
;
48 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.auxiliary
.GrListOrMap
;
49 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.auxiliary
.modifiers
.GrModifier
;
50 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.auxiliary
.modifiers
.GrModifierList
;
51 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.*;
52 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.arguments
.GrArgumentLabel
;
53 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.arguments
.GrArgumentList
;
54 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.arguments
.GrNamedArgument
;
55 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.blocks
.GrClosableBlock
;
56 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.blocks
.GrOpenBlock
;
57 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.branch
.GrBreakStatement
;
58 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.branch
.GrContinueStatement
;
59 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.branch
.GrFlowInterruptingStatement
;
60 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.branch
.GrReturnStatement
;
61 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.clauses
.GrForInClause
;
62 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.*;
63 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.literals
.GrLiteral
;
64 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.expressions
.path
.GrMethodCallExpression
;
65 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.typedef
.*;
66 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.typedef
.members
.GrMember
;
67 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.typedef
.members
.GrMethod
;
68 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.toplevel
.imports
.GrImportStatement
;
69 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.toplevel
.packaging
.GrPackageDefinition
;
70 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.types
.GrCodeReferenceElement
;
71 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.types
.GrTypeParameter
;
72 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.util
.GrVariableDeclarationOwner
;
73 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.GrClosureType
;
74 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.statements
.expressions
.TypesUtil
;
75 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.synthetic
.GroovyScriptClass
;
76 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.util
.PsiUtil
;
77 import org
.jetbrains
.plugins
.groovy
.lang
.resolve
.ResolveUtil
;
78 import org
.jetbrains
.plugins
.groovy
.lang
.resolve
.processors
.PropertyResolverProcessor
;
79 import org
.jetbrains
.plugins
.groovy
.overrideImplement
.GroovyOverrideImplementUtil
;
80 import org
.jetbrains
.plugins
.groovy
.overrideImplement
.quickFix
.ImplementMethodsQuickFix
;
87 public class GroovyAnnotator
extends GroovyElementVisitor
implements Annotator
{
88 private static final Logger LOG
= Logger
.getInstance("org.jetbrains.plugins.groovy.annotator.GroovyAnnotator");
90 private AnnotationHolder myHolder
;
92 private static boolean isDocCommentElement(PsiElement element
) {
93 if (element
== null) return false;
94 ASTNode node
= element
.getNode();
95 return node
!= null && PsiTreeUtil
.getParentOfType(element
, GrDocComment
.class) != null || element
instanceof GrDocComment
;
98 public void annotate(@NotNull PsiElement element
, @NotNull AnnotationHolder holder
) {
99 if (element
instanceof GroovyPsiElement
) {
101 ((GroovyPsiElement
)element
).accept(this);
107 public void visitElement(GroovyPsiElement element
) {
108 if (element
.getParent() instanceof GrDocReferenceElement
) {
109 checkGrDocReferenceElement(myHolder
, element
);
112 final ASTNode node
= element
.getNode();
113 if (!(element
instanceof PsiWhiteSpace
) &&
114 !GroovyTokenTypes
.COMMENT_SET
.contains(node
.getElementType()) &&
115 element
.getContainingFile() instanceof GroovyFile
&&
116 !isDocCommentElement(element
)) {
117 GroovyImportsTracker
.getInstance(element
.getProject()).markFileAnnotated((GroovyFile
)element
.getContainingFile());
123 public void visitCodeReferenceElement(GrCodeReferenceElement refElement
) {
124 final PsiElement parent
= refElement
.getParent();
125 GroovyResolveResult resolveResult
= refElement
.advancedResolve();
126 highlightAnnotation(myHolder
, refElement
, resolveResult
);
127 registerUsedImport(refElement
, resolveResult
);
128 highlightAnnotation(myHolder
, refElement
, resolveResult
);
129 if (refElement
.getReferenceName() != null) {
131 if (parent
instanceof GrImportStatement
&& ((GrImportStatement
)parent
).isStatic() && refElement
.multiResolve(false).length
> 0) {
135 checkSingleResolvedElement(myHolder
, refElement
, resolveResult
, true);
140 public void visitReferenceExpression(GrReferenceExpression referenceExpression
) {
141 GroovyResolveResult resolveResult
= referenceExpression
.advancedResolve();
142 GroovyResolveResult
[] results
= referenceExpression
.multiResolve(false); //cached
143 for (GroovyResolveResult result
: results
) {
144 registerUsedImport(referenceExpression
, result
);
147 PsiElement resolved
= resolveResult
.getElement();
148 final PsiElement parent
= referenceExpression
.getParent();
149 if (resolved
!= null) {
150 if (resolved
instanceof PsiMember
) {
151 highlightMemberResolved(myHolder
, referenceExpression
, ((PsiMember
)resolved
));
153 if (!resolveResult
.isAccessible()) {
154 String message
= GroovyBundle
.message("cannot.access", referenceExpression
.getReferenceName());
155 myHolder
.createWarningAnnotation(referenceExpression
.getReferenceNameElement(), message
);
157 if (!resolveResult
.isStaticsOK() && resolved
instanceof PsiModifierListOwner
) {
158 if (!((PsiModifierListOwner
)resolved
).hasModifierProperty(GrModifier
.STATIC
)) {
159 myHolder
.createWarningAnnotation(referenceExpression
, GroovyBundle
.message("cannot.reference.nonstatic", referenceExpression
.getReferenceName()));
164 GrExpression qualifier
= referenceExpression
.getQualifierExpression();
165 if (qualifier
== null && isDeclarationAssignment(referenceExpression
)) return;
167 if (parent
instanceof GrReferenceExpression
&& "class".equals(((GrReferenceExpression
)parent
).getReferenceName())) {
168 checkSingleResolvedElement(myHolder
, referenceExpression
, resolveResult
, false);
172 if (parent
instanceof GrCall
) {
173 if (resolved
== null && results
.length
> 0) {
174 resolved
= results
[0].getElement();
175 resolveResult
= results
[0];
177 if (resolved
instanceof PsiMethod
&& resolved
.getUserData(GrMethod
.BUILDER_METHOD
) == null) {
178 checkMethodApplicability(resolveResult
, referenceExpression
, myHolder
);
181 checkClosureApplicability(resolveResult
, referenceExpression
.getType(), referenceExpression
, myHolder
);
184 if (isDeclarationAssignment(referenceExpression
) || resolved
instanceof PsiPackage
) return;
186 if (resolved
== null) {
187 PsiElement refNameElement
= referenceExpression
.getReferenceNameElement();
188 PsiElement elt
= refNameElement
== null ? referenceExpression
: refNameElement
;
189 Annotation annotation
= myHolder
.createInfoAnnotation(elt
, null);
190 final GrExpression qualifier
= referenceExpression
.getQualifierExpression();
191 if (qualifier
== null) {
192 if (!(parent
instanceof GrCall
)) {
193 registerCreateClassByTypeFix(referenceExpression
, annotation
);
194 registerAddImportFixes(referenceExpression
, annotation
);
197 registerStaticImportFix(referenceExpression
, annotation
);
201 if (qualifier
.getType() == null) {
205 registerReferenceFixes(referenceExpression
, annotation
);
206 annotation
.setTextAttributes(DefaultHighlighter
.UNRESOLVED_ACCESS
);
210 private static void registerStaticImportFix(GrReferenceExpression referenceExpression
, Annotation annotation
) {
211 final String referenceName
= referenceExpression
.getReferenceName();
212 //noinspection ConstantConditions
213 if (StringUtil
.isEmpty(referenceName
)) {
217 annotation
.registerFix(new GroovyStaticImportMethodFix((GrCall
)referenceExpression
.getParent()));
221 public void visitTypeDefinition(GrTypeDefinition typeDefinition
) {
222 checkTypeDefinition(myHolder
, typeDefinition
);
223 checkTypeDefinitionModifiers(myHolder
, typeDefinition
);
225 final GrTypeDefinitionBody body
= typeDefinition
.getBody();
226 if (body
!= null) checkDuplicateMethod(body
.getGroovyMethods(), myHolder
);
227 checkImplementedMethodsOfClass(myHolder
, typeDefinition
);
231 public void visitMethod(GrMethod method
) {
232 checkMethodDefinitionModifiers(myHolder
, method
);
233 checkInnerMethod(myHolder
, method
);
237 public void visitVariableDeclaration(GrVariableDeclaration variableDeclaration
) {
239 PsiElement parent
= variableDeclaration
.getParent();
240 assert parent
!= null;
242 PsiElement typeDef
= parent
.getParent();
243 if (typeDef
!= null && typeDef
instanceof GrTypeDefinition
) {
244 PsiModifierList modifiersList
= variableDeclaration
.getModifierList();
245 checkAccessModifiers(myHolder
, modifiersList
);
247 if (modifiersList
.hasExplicitModifier(GrModifier
.VOLATILE
) && modifiersList
.hasExplicitModifier(GrModifier
.FINAL
)) {
248 myHolder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("illegal.combination.of.modifiers.volatile.and.final"));
251 if (modifiersList
.hasExplicitModifier(GrModifier
.NATIVE
)) {
252 myHolder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("variable.cannot.be.native"));
255 if (modifiersList
.hasExplicitModifier(GrModifier
.ABSTRACT
)) {
256 myHolder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("variable.cannot.be.abstract"));
262 public void visitVariable(GrVariable variable
) {
263 if (variable
instanceof GrMember
) {
264 highlightMember(myHolder
, ((GrMember
)variable
));
265 checkStaticDeclarationsInInnerClass((GrMember
)variable
, myHolder
);
267 PropertyResolverProcessor processor
= new DuplicateVariablesProcessor(variable
);
268 final GroovyPsiElement duplicate
=
269 ResolveUtil
.resolveExistingElement(variable
, processor
, GrVariable
.class, GrReferenceExpression
.class);
271 if (duplicate
instanceof GrVariable
) {
272 if (duplicate
instanceof GrField
&& !(variable
instanceof GrField
)) {
274 .createWarningAnnotation(variable
.getNameIdentifierGroovy(), GroovyBundle
.message("field.already.defined", variable
.getName()));
277 final String key
= duplicate
instanceof GrField ?
"field.already.defined" : "variable.already.defined";
278 myHolder
.createErrorAnnotation(variable
.getNameIdentifierGroovy(), GroovyBundle
.message(key
, variable
.getName()));
284 public void visitAssignmentExpression(GrAssignmentExpression expression
) {
285 GrExpression lValue
= expression
.getLValue();
286 if (!PsiUtil
.mightBeLVlaue(lValue
)) {
287 myHolder
.createErrorAnnotation(lValue
, GroovyBundle
.message("invalid.lvalue"));
292 public void visitReturnStatement(GrReturnStatement returnStatement
) {
293 final GrExpression value
= returnStatement
.getReturnValue();
295 final PsiType type
= value
.getType();
297 final GrParametersOwner owner
= PsiTreeUtil
.getParentOfType(returnStatement
, GrMethod
.class, GrClosableBlock
.class);
298 if (owner
instanceof PsiMethod
) {
299 final PsiMethod method
= (PsiMethod
)owner
;
300 if (method
.isConstructor()) {
301 myHolder
.createErrorAnnotation(value
, GroovyBundle
.message("cannot.return.from.constructor"));
304 final PsiType methodType
= method
.getReturnType();
305 if (methodType
!= null) {
306 if (PsiType
.VOID
.equals(methodType
)) {
307 myHolder
.createErrorAnnotation(value
, GroovyBundle
.message("cannot.return.from.void.method"));
317 public void visitListOrMap(GrListOrMap listOrMap
) {
318 final Map
<GrNamedArgument
, List
<GrNamedArgument
>> map
= DuplicatesUtil
.factorDuplicates(listOrMap
.getNamedArguments(), new TObjectHashingStrategy
<GrNamedArgument
>() {
319 public int computeHashCode(GrNamedArgument arg
) {
320 final GrArgumentLabel label
= arg
.getLabel();
321 if (label
== null) return 0;
322 final String name
= label
.getName();
323 if (name
== null) return 0;
324 return name
.hashCode();
327 public boolean equals(GrNamedArgument arg1
, GrNamedArgument arg2
) {
328 final GrArgumentLabel label1
= arg1
.getLabel();
329 final GrArgumentLabel label2
= arg2
.getLabel();
330 if (label1
== null || label2
== null) {
331 return label1
== null && label2
== null;
333 final String name1
= label1
.getName();
334 final String name2
= label2
.getName();
335 if (name1
== null || name2
== null) {
336 return name1
== null && name2
== null;
338 return name1
.equals(name2
);
342 processDuplicates(map
, myHolder
);
346 public void visitNewExpression(GrNewExpression newExpression
) {
347 if (newExpression
.getArrayCount() > 0) return;
348 GrCodeReferenceElement refElement
= newExpression
.getReferenceElement();
349 if (refElement
== null) return;
350 final PsiElement element
= refElement
.resolve();
351 if (element
instanceof PsiClass
) {
352 PsiClass clazz
= (PsiClass
)element
;
353 if (clazz
.hasModifierProperty(GrModifier
.ABSTRACT
)) {
354 if (newExpression
.getAnonymousClassDefinition() == null) {
355 String message
= clazz
.isInterface()
356 ? GroovyBundle
.message("cannot.instantiate.interface", clazz
.getName())
357 : GroovyBundle
.message("cannot.instantiate.abstract.class", clazz
.getName());
358 myHolder
.createErrorAnnotation(refElement
, message
);
362 if (newExpression
.getQualifier() != null) {
363 if (clazz
.hasModifierProperty(GrModifier
.STATIC
)) {
364 myHolder
.createErrorAnnotation(newExpression
, GroovyBundle
.message("qualified.new.of.static.class"));
367 final PsiClass outerClass
= clazz
.getContainingClass();
368 if (com
.intellij
.psi
.util
.PsiUtil
.isInnerClass(clazz
) && !PsiUtil
.hasEnclosingInstanceInScope(outerClass
, newExpression
, true)) {
369 myHolder
.createErrorAnnotation(newExpression
, GroovyBundle
.message("cannot.reference.nonstatic", clazz
.getQualifiedName()));
374 final GroovyResolveResult constructorResolveResult
= newExpression
.resolveConstructorGenerics();
375 if (constructorResolveResult
.getElement() != null) {
376 checkMethodApplicability(constructorResolveResult
, refElement
, myHolder
);
377 final GrArgumentList argList
= newExpression
.getArgumentList();
378 if (argList
!= null && argList
.getExpressionArguments().length
== 0) checkDefaultMapConstructor(myHolder
, argList
, constructorResolveResult
);
381 final GroovyResolveResult
[] results
= newExpression
.multiResolveConstructor();
382 final GrArgumentList argList
= newExpression
.getArgumentList();
383 PsiElement toHighlight
= argList
!= null ? argList
: refElement
.getReferenceNameElement();
385 if (results
.length
> 0) {
386 String message
= GroovyBundle
.message("ambiguous.constructor.call");
387 myHolder
.createWarningAnnotation(toHighlight
, message
);
390 if (element
instanceof PsiClass
) {
391 //default constructor invocation
392 PsiType
[] argumentTypes
= PsiUtil
.getArgumentTypes(refElement
, true, true);
393 if (argumentTypes
!= null && argumentTypes
.length
> 0) {
394 String message
= GroovyBundle
.message("cannot.find.default.constructor", ((PsiClass
)element
).getName());
395 myHolder
.createWarningAnnotation(toHighlight
, message
);
397 else checkDefaultMapConstructor(myHolder
, argList
, constructorResolveResult
);
404 public void visitDocMethodReference(GrDocMethodReference reference
) {
405 checkGrDocMemberReference(reference
, myHolder
);
409 public void visitDocFieldReference(GrDocFieldReference reference
) {
410 checkGrDocMemberReference(reference
, myHolder
);
414 public void visitConstructorInvocation(GrConstructorInvocation invocation
) {
415 final GroovyResolveResult resolveResult
= invocation
.resolveConstructorGenerics();
416 if (resolveResult
!= null) {
417 checkMethodApplicability(resolveResult
, invocation
.getThisOrSuperKeyword(), myHolder
);
420 final GroovyResolveResult
[] results
= invocation
.multiResolveConstructor();
421 final GrArgumentList argList
= invocation
.getArgumentList();
422 if (results
.length
> 0) {
423 String message
= GroovyBundle
.message("ambiguous.constructor.call");
424 myHolder
.createWarningAnnotation(argList
, message
);
427 final PsiClass clazz
= invocation
.getDelegatedClass();
429 //default constructor invocation
430 PsiType
[] argumentTypes
= PsiUtil
.getArgumentTypes(invocation
.getThisOrSuperKeyword(), true, true);
431 if (argumentTypes
!= null && argumentTypes
.length
> 0) {
432 String message
= GroovyBundle
.message("cannot.find.default.constructor", clazz
.getName());
433 myHolder
.createWarningAnnotation(argList
, message
);
441 public void visitBreakStatement(GrBreakStatement breakStatement
) {
442 checkFlowInterruptStatement(breakStatement
, myHolder
);
446 public void visitContinueStatement(GrContinueStatement continueStatement
) {
447 checkFlowInterruptStatement(continueStatement
, myHolder
);
451 public void visitLabeledStatement(GrLabeledStatement labeledStatement
) {
452 final String name
= labeledStatement
.getLabelName();
453 if (ResolveUtil
.resolveLabeledStatement(name
, labeledStatement
, true) != null) {
454 myHolder
.createWarningAnnotation(labeledStatement
.getLabel(), GroovyBundle
.message("label.already.used", name
));
459 public void visitPackageDefinition(GrPackageDefinition packageDefinition
) {
460 //todo: if reference isn't resolved it construct package definition
461 final PsiFile file
= packageDefinition
.getContainingFile();
464 PsiDirectory psiDirectory
= file
.getContainingDirectory();
465 if (psiDirectory
!= null) {
466 PsiPackage aPackage
= JavaDirectoryService
.getInstance().getPackage(psiDirectory
);
467 if (aPackage
!= null) {
468 String packageName
= aPackage
.getQualifiedName();
469 if (!packageDefinition
.getPackageName().equals(packageName
)) {
470 final Annotation annotation
= myHolder
.createWarningAnnotation(packageDefinition
, "wrong package name");
471 annotation
.registerFix(new ChangePackageQuickFix((GroovyFile
)packageDefinition
.getContainingFile(), packageName
));
475 final GrModifierList modifierList
= packageDefinition
.getAnnotationList();
476 checkAnnotationList(myHolder
, modifierList
, GroovyBundle
.message("package.definition.cannot.have.modifiers"));
480 public void visitSuperExpression(GrSuperReferenceExpression superExpression
) {
481 checkThisOrSuperReferenceExpression(superExpression
, myHolder
);
485 public void visitThisExpression(GrThisReferenceExpression thisExpression
) {
486 checkThisOrSuperReferenceExpression(thisExpression
, myHolder
);
490 public void visitLiteralExpression(GrLiteral literal
) {
491 String text
= literal
.getText();
492 if (text
.startsWith("'''")) {
493 if (text
.length() < 6 || !text
.endsWith("'''")) {
494 myHolder
.createErrorAnnotation(literal
, GroovyBundle
.message("string.end.expected"));
497 else if (text
.startsWith("'")) {
498 if (text
.length() < 2 || !text
.endsWith("'")) {
499 myHolder
.createErrorAnnotation(literal
, GroovyBundle
.message("string.end.expected"));
505 public void visitForInClause(GrForInClause forInClause
) {
506 final GrVariable
[] declaredVariables
= forInClause
.getDeclaredVariables();
507 if (declaredVariables
.length
< 1) return;
508 final GrVariable variable
= declaredVariables
[0];
509 final GrModifierList modifierList
= ((GrModifierList
)variable
.getModifierList());
510 if (modifierList
== null) return;
511 final PsiElement
[] modifiers
= modifierList
.getModifiers();
512 for (PsiElement modifier
: modifiers
) {
513 if (modifier
instanceof PsiAnnotation
) continue;
514 final String modifierText
= modifier
.getText();
515 if (GrModifier
.FINAL
.equals(modifierText
)) continue;
516 if (GrModifier
.DEF
.equals(modifierText
)) continue;
517 myHolder
.createErrorAnnotation(modifier
, GroovyBundle
.message("not.allowed.modifier.in.forin", modifierText
));
522 public void visitFile(GroovyFileBase file
) {
523 if (!file
.isScript()) return;
525 List
<GrMethod
> methods
= new ArrayList
<GrMethod
>();
527 for (GrTopLevelDefintion topLevelDefinition
: file
.getTopLevelDefinitions()) {
528 if (topLevelDefinition
instanceof GrMethod
) {
529 methods
.add(((GrMethod
)topLevelDefinition
));
533 checkDuplicateMethod(methods
.toArray(new GrMethod
[methods
.size()]), myHolder
);
537 public void visitImportStatement(GrImportStatement importStatement
) {
538 checkAnnotationList(myHolder
, importStatement
.getAnnotationList(), GroovyBundle
.message("import.statement.cannot.have.modifiers"));
541 private static void checkFlowInterruptStatement(GrFlowInterruptingStatement statement
, AnnotationHolder holder
) {
542 final PsiElement label
= statement
.getLabelIdentifier();
545 final GrLabeledStatement resolved
= statement
.resolveLabel();
546 if (resolved
== null) {
547 holder
.createErrorAnnotation(label
, GroovyBundle
.message("undefined.label", statement
.getLabelName()));
551 final GrStatement targetStatement
= statement
.findTargetStatement();
552 if (targetStatement
== null) {
553 if (statement
instanceof GrContinueStatement
&& label
== null) {
554 holder
.createErrorAnnotation(statement
, GroovyBundle
.message("continue.outside.loop"));
556 else if (statement
instanceof GrBreakStatement
&& label
== null) {
557 holder
.createErrorAnnotation(statement
, GroovyBundle
.message("break.outside.loop.or.switch"));
560 if (statement
instanceof GrBreakStatement
&& label
!= null && findFirstLoop(statement
) == null) {
561 holder
.createErrorAnnotation(statement
, GroovyBundle
.message("break.outside.loop"));
566 private static GrLoopStatement
findFirstLoop(GrFlowInterruptingStatement statement
) {
567 return PsiTreeUtil
.getParentOfType(statement
, GrLoopStatement
.class, true, GrClosableBlock
.class, GrMember
.class, GroovyFile
.class);
570 private static void checkThisOrSuperReferenceExpression(GrExpression expression
, AnnotationHolder holder
) {
571 final GrReferenceExpression qualifier
= expression
instanceof GrThisReferenceExpression
572 ?
((GrThisReferenceExpression
)expression
).getQualifier()
573 : ((GrSuperReferenceExpression
)expression
).getQualifier();
574 if (qualifier
== null) {
575 final GrMethod method
= PsiTreeUtil
.getParentOfType(expression
, GrMethod
.class);
576 if (method
!= null && method
.hasModifierProperty(GrModifier
.STATIC
)) {
577 holder
.createErrorAnnotation(expression
, GroovyBundle
.message("cannot.reference.nonstatic", expression
.getText()));
581 final PsiElement resolved
= qualifier
.resolve();
582 if (resolved
instanceof PsiClass
) {
583 if (PsiTreeUtil
.isAncestor(resolved
, expression
, true)) {
584 if (!PsiUtil
.hasEnclosingInstanceInScope((PsiClass
)resolved
, expression
, true)) {
585 holder
.createErrorAnnotation(expression
, GroovyBundle
.message("cannot.reference.nonstatic", expression
.getText()));
588 holder
.createErrorAnnotation(expression
, GroovyBundle
.message("is.not.enclosing.class", ((PsiClass
)resolved
).getQualifiedName()));
592 holder
.createErrorAnnotation(qualifier
, GroovyBundle
.message("unknown.class", qualifier
.getText()));
597 private static void checkStaticDeclarationsInInnerClass(GrMember classMember
, AnnotationHolder holder
) {
598 final PsiClass containingClass
= classMember
.getContainingClass();
599 if (containingClass
== null) return;
600 if (com
.intellij
.psi
.util
.PsiUtil
.isInnerClass(containingClass
)) {
601 if (classMember
.hasModifierProperty(GrModifier
.STATIC
)) {
602 final PsiElement modifier
= findModifierStatic(classMember
);
603 if (modifier
!= null) {
604 holder
.createErrorAnnotation(modifier
, GroovyBundle
.message("cannot.have.static.declarations"));
611 private static PsiElement
findModifierStatic(GrMember grMember
) {
612 final GrModifierList list
= grMember
.getModifierList();
617 for (PsiElement modifier
: list
.getModifiers()) {
618 if (GrModifier
.STATIC
.equals(modifier
.getText())) {
625 private static void checkGrDocReferenceElement(AnnotationHolder holder
, PsiElement element
) {
626 ASTNode node
= element
.getNode();
627 if (node
!= null && TokenSets
.BUILT_IN_TYPE
.contains(node
.getElementType())) {
628 Annotation annotation
= holder
.createInfoAnnotation(element
, null);
629 annotation
.setTextAttributes(DefaultHighlighter
.KEYWORD
);
633 private static void checkAnnotationList(AnnotationHolder holder
, @Nullable GrModifierList modifierList
, String message
) {
634 if (modifierList
== null) return;
635 final PsiElement
[] modifiers
= modifierList
.getModifiers();
636 for (PsiElement modifier
: modifiers
) {
637 if (!(modifier
instanceof PsiAnnotation
)) {
638 holder
.createErrorAnnotation(modifier
, message
);
643 private static void checkImplementedMethodsOfClass(AnnotationHolder holder
, GrTypeDefinition typeDefinition
) {
644 if (typeDefinition
.hasModifierProperty(GrModifier
.ABSTRACT
)) return;
645 if (typeDefinition
.isEnum() || typeDefinition
.isAnnotationType()) return;
646 if (typeDefinition
instanceof GrTypeParameter
) return;
648 Collection
<CandidateInfo
> collection
= GroovyOverrideImplementUtil
.getMethodsToImplement(typeDefinition
);
649 if (collection
.isEmpty()) return;
651 final PsiElement element
= collection
.iterator().next().getElement();
652 assert element
instanceof PsiNamedElement
;
653 String notImplementedMethodName
= ((PsiNamedElement
)element
).getName();
655 final int startOffset
= typeDefinition
.getTextOffset();
656 int endOffset
= typeDefinition
.getNameIdentifierGroovy().getTextRange().getEndOffset();
657 final Annotation annotation
= holder
.createErrorAnnotation(new TextRange(startOffset
, endOffset
),
658 GroovyBundle
.message("method.is.not.implemented", notImplementedMethodName
));
659 registerImplementsMethodsFix(typeDefinition
, annotation
);
662 private static void registerImplementsMethodsFix(GrTypeDefinition typeDefinition
, Annotation annotation
) {
663 annotation
.registerFix(new ImplementMethodsQuickFix(typeDefinition
));
666 private static void checkInnerMethod(AnnotationHolder holder
, GrMethod grMethod
) {
667 final PsiElement parent
= grMethod
.getParent();
668 if (parent
instanceof GrOpenBlock
|| parent
instanceof GrClosableBlock
) {
669 holder
.createErrorAnnotation(grMethod
.getNameIdentifierGroovy(), GroovyBundle
.message("Inner.methods.are.not.supported"));
673 protected static void processDuplicates(Map
<GrNamedArgument
, List
<GrNamedArgument
>> map
, AnnotationHolder holder
) {
674 for (List
<GrNamedArgument
> args
: map
.values()) {
675 for (int i
= 1; i
< args
.size(); i
++) {
676 GrNamedArgument namedArgument
= args
.get(i
);
677 holder
.createWarningAnnotation(namedArgument
, GroovyBundle
.message("duplicate.element.in.the.map"));
682 private static void checkMethodDefinitionModifiers(AnnotationHolder holder
, GrMethod method
) {
683 final PsiModifierList modifiersList
= method
.getModifierList();
684 checkAccessModifiers(holder
, modifiersList
);
687 boolean isMethodAbstract
= modifiersList
.hasExplicitModifier(GrModifier
.ABSTRACT
);
688 final boolean isMethodStatic
= modifiersList
.hasExplicitModifier(GrModifier
.STATIC
);
689 if (method
.getParent() instanceof GroovyFileBase
) {
690 if (isMethodAbstract
) {
691 holder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("script.cannot.have.modifier.abstract"));
694 if (modifiersList
.hasExplicitModifier(GrModifier
.NATIVE
)) {
695 holder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("script.cannot.have.modifier.native"));
698 else //type definition methods
699 if (method
.getParent() != null && method
.getParent().getParent() instanceof GrTypeDefinition
) {
700 GrTypeDefinition containingTypeDef
= ((GrTypeDefinition
)method
.getParent().getParent());
703 if (containingTypeDef
.isInterface()) {
704 if (isMethodStatic
) {
705 holder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("interface.must.have.no.static.method"));
708 if (modifiersList
.hasExplicitModifier(GrModifier
.PRIVATE
)) {
709 holder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("interface.must.have.no.private.method"));
713 else if (containingTypeDef
.isEnum()) {
717 else if (containingTypeDef
.isAnnotationType()) {
721 else if (containingTypeDef
.isAnonymous()) {
723 if (isMethodStatic
) {
724 holder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("static.declaration.in.inner.class"));
726 if (method
.isConstructor()) {
727 holder
.createErrorAnnotation(method
.getNameIdentifierGroovy(),
728 GroovyBundle
.message("constructors.are.not.allowed.in.anonymous.class"));
730 if (isMethodAbstract
) {
731 holder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("not.abstract.class.cannot.have.abstract.method"));
736 PsiModifierList typeDefModifiersList
= containingTypeDef
.getModifierList();
737 LOG
.assertTrue(typeDefModifiersList
!= null, "modifiers list must be not null");
739 if (!typeDefModifiersList
.hasExplicitModifier(GrModifier
.ABSTRACT
)) {
740 if (isMethodAbstract
) {
741 holder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("not.abstract.class.cannot.have.abstract.method"));
745 if (!isMethodAbstract
) {
746 if (method
.getBlock() == null) {
747 holder
.createErrorAnnotation(method
.getNameIdentifierGroovy(), GroovyBundle
.message("not.abstract.method.should.have.body"));
750 if (isMethodStatic
) {
751 checkStaticDeclarationsInInnerClass(method
, holder
);
757 private static void checkTypeDefinitionModifiers(AnnotationHolder holder
, GrTypeDefinition typeDefinition
) {
758 PsiModifierList modifiersList
= typeDefinition
.getModifierList();
760 if (modifiersList
== null) return;
763 checkAccessModifiers(holder
, modifiersList
);
765 PsiClassType
[] extendsListTypes
= typeDefinition
.getExtendsListTypes();
767 for (PsiClassType classType
: extendsListTypes
) {
768 PsiClass psiClass
= classType
.resolve();
770 if (psiClass
!= null) {
771 PsiModifierList modifierList
= psiClass
.getModifierList();
772 if (modifierList
!= null) {
773 if (modifierList
.hasExplicitModifier(GrModifier
.FINAL
)) {
774 holder
.createErrorAnnotation(typeDefinition
.getNameIdentifierGroovy(), GroovyBundle
.message("final.class.cannot.be.extended"));
780 if (modifiersList
.hasExplicitModifier(GrModifier
.ABSTRACT
) && modifiersList
.hasExplicitModifier(GrModifier
.FINAL
)) {
781 holder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("illegal.combination.of.modifiers.abstract.and.final"));
784 if (modifiersList
.hasExplicitModifier(GrModifier
.TRANSIENT
)) {
785 holder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("modifier.transient.not.allowed.here"));
787 if (modifiersList
.hasExplicitModifier(GrModifier
.VOLATILE
)) {
788 holder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("modifier.volatile.not.allowed.here"));
791 /**** interface ****/
792 if (typeDefinition
.isInterface()) {
793 if (modifiersList
.hasExplicitModifier(GrModifier
.FINAL
)) {
794 holder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("intarface.cannot.have.modifier.final"));
797 if (modifiersList
.hasExplicitModifier(GrModifier
.VOLATILE
)) {
798 holder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("modifier.volatile.not.allowed.here"));
801 if (modifiersList
.hasExplicitModifier(GrModifier
.TRANSIENT
)) {
802 holder
.createErrorAnnotation(modifiersList
, GroovyBundle
.message("modifier.transient.not.allowed.here"));
806 checkStaticDeclarationsInInnerClass(typeDefinition
, holder
);
809 private static void checkAccessModifiers(AnnotationHolder holder
, @NotNull PsiModifierList modifierList
) {
810 boolean hasPrivate
= modifierList
.hasExplicitModifier(GrModifier
.PRIVATE
);
811 boolean hasPublic
= modifierList
.hasExplicitModifier(GrModifier
.PUBLIC
);
812 boolean hasProtected
= modifierList
.hasExplicitModifier(GrModifier
.PROTECTED
);
814 if (hasPrivate
&& hasPublic
|| hasPrivate
&& hasProtected
|| hasPublic
&& hasProtected
) {
815 holder
.createErrorAnnotation(modifierList
, GroovyBundle
.message("illegal.combination.of.modifiers"));
819 private static void checkDuplicateMethod(GrMethod
[] methods
, AnnotationHolder holder
) {
820 final Map
<GrMethod
, List
<GrMethod
>> map
= DuplicatesUtil
.factorDuplicates(methods
, new TObjectHashingStrategy
<GrMethod
>() {
821 public int computeHashCode(GrMethod method
) {
822 return method
.getSignature(PsiSubstitutor
.EMPTY
).hashCode();
825 public boolean equals(GrMethod method1
, GrMethod method2
) {
826 return method1
.getSignature(PsiSubstitutor
.EMPTY
).equals(method2
.getSignature(PsiSubstitutor
.EMPTY
));
829 processMethodDuplicates(map
, holder
);
832 protected static void processMethodDuplicates(Map
<GrMethod
, List
<GrMethod
>> map
, AnnotationHolder holder
) {
833 HashSet
<GrMethod
> duplicateMethodsWarning
= new HashSet
<GrMethod
>();
834 HashSet
<GrMethod
> duplicateMethodsErrors
= new HashSet
<GrMethod
>();
836 DuplicatesUtil
.collectMethodDuplicates(map
, duplicateMethodsWarning
, duplicateMethodsErrors
);
838 for (GrMethod duplicateMethod
: duplicateMethodsErrors
) {
839 holder
.createErrorAnnotation(duplicateMethod
.getNameIdentifierGroovy(),
840 GroovyBundle
.message("repetitive.method.name.signature.and.return.type"));
843 for (GrMethod duplicateMethod
: duplicateMethodsWarning
) {
844 holder
.createWarningAnnotation(duplicateMethod
.getNameIdentifierGroovy(), GroovyBundle
.message("repetitive.method.name.signature"));
849 private static void checkTypeDefinition(AnnotationHolder holder
, GrTypeDefinition typeDefinition
) {
850 final GroovyConfigUtils configUtils
= GroovyConfigUtils
.getInstance();
851 if (typeDefinition
.isAnnotationType()) {
852 Annotation annotation
= holder
.createInfoAnnotation(typeDefinition
.getNameIdentifierGroovy(), null);
853 annotation
.setTextAttributes(DefaultHighlighter
.ANNOTATION
);
855 else if (typeDefinition
.isAnonymous()) {
856 if (!configUtils
.isAtLeastGroovy1_7(typeDefinition
)) {
857 holder
.createErrorAnnotation(typeDefinition
.getNameIdentifierGroovy(),
858 GroovyBundle
.message("anonymous.classes.are.not.supported", configUtils
.getSDKVersion(typeDefinition
)));
861 else if (typeDefinition
.getContainingClass() != null && !(typeDefinition
instanceof GrEnumTypeDefinition
)) {
862 if (!configUtils
.isAtLeastGroovy1_7(typeDefinition
)) {
863 holder
.createErrorAnnotation(typeDefinition
.getNameIdentifierGroovy(),
864 GroovyBundle
.message("inner.classes.are.not.supported", configUtils
.getSDKVersion(typeDefinition
)));
868 final GrImplementsClause implementsClause
= typeDefinition
.getImplementsClause();
869 final GrExtendsClause extendsClause
= typeDefinition
.getExtendsClause();
871 if (implementsClause
!= null) {
872 checkForImplementingClass(holder
, extendsClause
, implementsClause
, ((GrTypeDefinition
)implementsClause
.getParent()));
875 if (extendsClause
!= null) {
876 checkForExtendingInterface(holder
, extendsClause
, implementsClause
, ((GrTypeDefinition
)extendsClause
.getParent()));
879 checkDuplicateClass(typeDefinition
, holder
);
882 private static void checkDuplicateClass(GrTypeDefinition typeDefinition
, AnnotationHolder holder
) {
883 final PsiClass containingClass
= typeDefinition
.getContainingClass();
884 if (containingClass
!= null) {
885 final String containingClassName
= containingClass
.getName();
886 if (containingClassName
!= null && containingClassName
.equals(typeDefinition
.getName())) {
887 holder
.createErrorAnnotation(typeDefinition
.getNameIdentifierGroovy(),
888 GroovyBundle
.message("duplicate.inner.class", typeDefinition
.getName()));
891 final String qName
= typeDefinition
.getQualifiedName();
893 final PsiClass
[] classes
=
894 JavaPsiFacade
.getInstance(typeDefinition
.getProject()).findClasses(qName
, typeDefinition
.getResolveScope());
895 if (classes
.length
> 1) {
896 String packageName
= getPackageName(typeDefinition
);
898 if (!isScriptGeneratedClass(classes
)) {
899 holder
.createErrorAnnotation(typeDefinition
.getNameIdentifierGroovy(),
900 GroovyBundle
.message("duplicate.class", typeDefinition
.getName(), packageName
));
903 holder
.createErrorAnnotation(typeDefinition
.getNameIdentifierGroovy(),
904 GroovyBundle
.message("script.generated.with.same.name", qName
));
910 private static String
getPackageName(GrTypeDefinition typeDefinition
) {
911 final PsiFile file
= typeDefinition
.getContainingFile();
912 String packageName
= "<default package>";
913 if (file
instanceof GroovyFile
) {
914 final String name
= ((GroovyFile
)file
).getPackageName();
915 if (name
.length() > 0) packageName
= name
;
920 private static boolean isScriptGeneratedClass(PsiClass
[] allClasses
) {
921 return allClasses
.length
== 2 && (allClasses
[0] instanceof GroovyScriptClass
|| allClasses
[1] instanceof GroovyScriptClass
);
924 private static void checkForExtendingInterface(AnnotationHolder holder
,
925 GrExtendsClause extendsClause
,
926 GrImplementsClause implementsClause
,
927 GrTypeDefinition myClass
) {
928 for (GrCodeReferenceElement ref
: extendsClause
.getReferenceElements()) {
929 final PsiElement clazz
= ref
.resolve();
930 if (clazz
== null) continue;
932 if (myClass
.isInterface() && clazz
instanceof PsiClass
&& !((PsiClass
)clazz
).isInterface()) {
933 final Annotation annotation
= holder
.createErrorAnnotation(ref
, GroovyBundle
.message("class.is.not.expected.here"));
934 annotation
.registerFix(new ChangeExtendsImplementsQuickFix(extendsClause
, implementsClause
));
939 private static void checkForImplementingClass(AnnotationHolder holder
,
940 GrExtendsClause extendsClause
,
941 GrImplementsClause implementsClause
,
942 GrTypeDefinition myClass
) {
943 if (myClass
.isInterface()) {
944 final Annotation annotation
=
945 holder
.createErrorAnnotation(implementsClause
, GroovyBundle
.message("interface.cannot.contain.implements.clause"));
946 annotation
.registerFix(new ChangeExtendsImplementsQuickFix(extendsClause
, implementsClause
));
950 for (GrCodeReferenceElement ref
: implementsClause
.getReferenceElements()) {
951 final PsiElement clazz
= ref
.resolve();
952 if (clazz
== null) continue;
954 if (!((PsiClass
)clazz
).isInterface()) {
955 final Annotation annotation
= holder
.createErrorAnnotation(ref
, GroovyBundle
.message("interface.expected.here"));
956 annotation
.registerFix(new ChangeExtendsImplementsQuickFix(extendsClause
, implementsClause
));
961 private static void checkGrDocMemberReference(final GrDocMemberReference reference
, AnnotationHolder holder
) {
962 PsiElement resolved
= reference
.resolve();
963 if (resolved
== null) {
964 Annotation annotation
= holder
.createErrorAnnotation(reference
, GroovyBundle
.message("cannot.resolve", reference
.getReferenceName()));
965 annotation
.setHighlightType(ProblemHighlightType
.LIKE_UNKNOWN_SYMBOL
);
969 private static void registerReferenceFixes(GrReferenceExpression refExpr
, Annotation annotation
) {
970 PsiClass targetClass
= QuickfixUtil
.findTargetClass(refExpr
);
971 if (targetClass
== null) return;
973 addDynamicAnnotation(annotation
, refExpr
);
974 if (targetClass
instanceof GrMemberOwner
) {
975 if (!(targetClass
instanceof GroovyScriptClass
)) {
976 annotation
.registerFix(new CreateFieldFromUsageFix(refExpr
, (GrMemberOwner
)targetClass
));
979 if (refExpr
.getParent() instanceof GrCall
&& refExpr
.getParent() instanceof GrExpression
) {
980 annotation
.registerFix(new CreateMethodFromUsageFix(refExpr
, (GrMemberOwner
)targetClass
));
984 if (!refExpr
.isQualified()) {
985 GrVariableDeclarationOwner owner
= PsiTreeUtil
.getParentOfType(refExpr
, GrVariableDeclarationOwner
.class);
986 if (!(owner
instanceof GroovyFileBase
) || ((GroovyFileBase
)owner
).isScript()) {
987 annotation
.registerFix(new CreateLocalVariableFromUsageFix(refExpr
, owner
));
992 private static void addDynamicAnnotation(Annotation annotation
, GrReferenceExpression referenceExpression
) {
993 final PsiFile containingFile
= referenceExpression
.getContainingFile();
995 if (containingFile
!= null) {
996 file
= containingFile
.getVirtualFile();
997 if (file
== null) return;
1003 if (QuickfixUtil
.isCall(referenceExpression
)) {
1004 annotation
.registerFix(new DynamicMethodFix(referenceExpression
), referenceExpression
.getTextRange());
1007 annotation
.registerFix(new DynamicPropertyFix(referenceExpression
), referenceExpression
.getTextRange());
1011 private static void highlightMemberResolved(AnnotationHolder holder
, GrReferenceExpression refExpr
, PsiMember member
) {
1012 boolean isStatic
= member
.hasModifierProperty(GrModifier
.STATIC
);
1013 Annotation annotation
= holder
.createInfoAnnotation(refExpr
.getReferenceNameElement(), null);
1015 if (member
instanceof PsiField
) {
1016 annotation
.setTextAttributes(isStatic ? DefaultHighlighter
.STATIC_FIELD
: DefaultHighlighter
.INSTANCE_FIELD
);
1019 if (member
instanceof PsiMethod
) {
1020 annotation
.setTextAttributes(!isStatic ? DefaultHighlighter
.METHOD_CALL
: DefaultHighlighter
.STATIC_METHOD_ACCESS
);
1025 private static void registerUsedImport(GrReferenceElement referenceElement
, GroovyResolveResult resolveResult
) {
1026 GroovyPsiElement context
= resolveResult
.getCurrentFileResolveContext();
1027 if (context
instanceof GrImportStatement
) {
1028 PsiFile file
= referenceElement
.getContainingFile();
1029 if (file
instanceof GroovyFile
) {
1030 GroovyImportsTracker importsTracker
= GroovyImportsTracker
.getInstance(referenceElement
.getProject());
1031 importsTracker
.registerImportUsed((GrImportStatement
)context
);
1036 private static void checkMethodApplicability(GroovyResolveResult methodResolveResult
, PsiElement place
, AnnotationHolder holder
) {
1037 final PsiElement element
= methodResolveResult
.getElement();
1038 if (!(element
instanceof PsiMethod
)) return;
1039 final PsiMethod method
= (PsiMethod
)element
;
1040 PsiType
[] argumentTypes
= PsiUtil
.getArgumentTypes(place
, method
.isConstructor(), true);
1041 if (argumentTypes
!= null &&
1042 !PsiUtil
.isApplicable(argumentTypes
, method
, methodResolveResult
.getSubstitutor(),
1043 methodResolveResult
.getCurrentFileResolveContext() instanceof GrMethodCallExpression
)) {
1044 PsiElement elementToHighlight
= PsiUtil
.getArgumentsElement(place
);
1045 if (elementToHighlight
== null) {
1046 elementToHighlight
= place
;
1049 final String typesString
= buildArgTypesList(argumentTypes
);
1051 final PsiClass containingClass
= method
.getContainingClass();
1052 if (containingClass
!= null) {
1053 final PsiClassType containingType
= JavaPsiFacade
.getInstance(method
.getProject()).getElementFactory()
1054 .createType(containingClass
, methodResolveResult
.getSubstitutor());
1055 message
= GroovyBundle
.message("cannot.apply.method1", method
.getName(), containingType
.getInternalCanonicalText(), typesString
);
1058 message
= GroovyBundle
.message("cannot.apply.method.or.closure", method
.getName(), typesString
);
1060 holder
.createWarningAnnotation(elementToHighlight
, message
);
1064 public static boolean isDeclarationAssignment(GrReferenceExpression refExpr
) {
1065 if (isAssignmentLhs(refExpr
)) {
1066 return isExpandoQualified(refExpr
);
1071 private static boolean isAssignmentLhs(GrReferenceExpression refExpr
) {
1072 return refExpr
.getParent() instanceof GrAssignmentExpression
&&
1073 refExpr
.equals(((GrAssignmentExpression
)refExpr
.getParent()).getLValue());
1076 private static boolean isExpandoQualified(GrReferenceExpression refExpr
) {
1077 final GrExpression qualifier
= refExpr
.getQualifierExpression();
1078 if (qualifier
== null) {
1079 final PsiClass clazz
= PsiTreeUtil
.getParentOfType(refExpr
, PsiClass
.class);
1080 if (clazz
== null) { //script
1083 return false; //in class, a property should normally be defined, so it's not a declaration
1086 final PsiType type
= qualifier
.getType();
1087 if (type
instanceof PsiClassType
) {
1088 final PsiClassType classType
= (PsiClassType
)type
;
1089 final PsiClass psiClass
= classType
.resolve();
1090 if (psiClass
instanceof GroovyScriptClass
) {
1097 private static void checkSingleResolvedElement(AnnotationHolder holder
, GrReferenceElement refElement
, GroovyResolveResult resolveResult
, boolean highlightError
) {
1098 final PsiElement resolved
= resolveResult
.getElement();
1099 if (resolved
== null) {
1100 String message
= GroovyBundle
.message("cannot.resolve", refElement
.getReferenceName());
1102 // Register quickfix
1103 final PsiElement nameElement
= refElement
.getReferenceNameElement();
1104 final PsiElement toHighlight
= nameElement
!= null ? nameElement
: refElement
;
1106 final Annotation annotation
;
1107 if (highlightError
) {
1108 annotation
= holder
.createErrorAnnotation(toHighlight
, message
);
1109 annotation
.setHighlightType(ProblemHighlightType
.LIKE_UNKNOWN_SYMBOL
);
1112 annotation
= holder
.createInfoAnnotation(toHighlight
, message
);
1114 // todo implement for nested classes
1115 if (refElement
.getQualifier() == null) {
1116 registerCreateClassByTypeFix(refElement
, annotation
);
1117 registerAddImportFixes(refElement
, annotation
);
1120 else if (!resolveResult
.isAccessible()) {
1121 String message
= GroovyBundle
.message("cannot.access", refElement
.getReferenceName());
1122 holder
.createWarningAnnotation(refElement
.getReferenceNameElement(), message
);
1126 private static void checkDefaultMapConstructor(AnnotationHolder holder
,
1127 GrArgumentList argList
,
1128 GroovyResolveResult constructorResolveResult
) {
1129 if (argList
!= null) {
1130 final GrNamedArgument
[] args
= argList
.getNamedArguments();
1131 for (GrNamedArgument arg
: args
) {
1132 final GrArgumentLabel label
= arg
.getLabel();
1133 if (label
== null) continue;
1134 if (label
.getName() == null) {
1135 final PsiElement nameElement
= label
.getNameElement();
1136 if (nameElement
instanceof GrExpression
) {
1137 final PsiType stringType
=
1138 JavaPsiFacade
.getElementFactory(arg
.getProject()).createTypeFromText(CommonClassNames
.JAVA_LANG_STRING
, arg
);
1139 if (!TypesUtil
.isAssignable(stringType
, ((GrExpression
)nameElement
).getType(), arg
.getManager(), arg
.getResolveScope())) {
1140 holder
.createWarningAnnotation(nameElement
, GroovyBundle
.message("property.name.expected"));
1144 holder
.createWarningAnnotation(nameElement
, GroovyBundle
.message("property.name.expected"));
1148 final PsiElement resolved
= label
.resolve();
1149 if (resolved
== null) {
1150 final Annotation annotation
= holder
.createWarningAnnotation(label
, GroovyBundle
.message("no.such.property", label
.getName()));
1152 PsiElement element
= constructorResolveResult
.getElement();
1153 if (element
instanceof PsiMember
) {
1154 element
= ((PsiMember
)element
).getContainingClass();
1156 if (element
instanceof GrMemberOwner
) {
1157 annotation
.registerFix(new CreateFieldFromConstructorLabelFix((GrMemberOwner
)element
, label
.getNamedArgument()));
1159 if (element
instanceof PsiClass
) {
1160 annotation
.registerFix(new DynamicPropertyFix(label
, (PsiClass
)element
));
1168 private static void checkClosureApplicability(GroovyResolveResult resolveResult
, PsiType type
, PsiElement place
, AnnotationHolder holder
) {
1169 final PsiElement element
= resolveResult
.getElement();
1170 if (!(element
instanceof GrVariable
)) return;
1171 if (!(type
instanceof GrClosureType
)) return;
1172 final GrVariable variable
= (GrVariable
)element
;
1173 PsiType
[] argumentTypes
= PsiUtil
.getArgumentTypes(place
, false, true);
1174 if (argumentTypes
== null) return;
1176 final PsiType
[] paramTypes
= PsiUtil
.skipOptionalClosureParameters(argumentTypes
.length
, (GrClosureType
)type
);
1177 if (!areTypesCompatibleForCallingClosure(argumentTypes
, paramTypes
, place
.getManager(), place
.getResolveScope())) {
1178 final String typesString
= buildArgTypesList(argumentTypes
);
1179 String message
= GroovyBundle
.message("cannot.apply.method.or.closure", variable
.getName(), typesString
);
1180 PsiElement elementToHighlight
= PsiUtil
.getArgumentsElement(place
);
1181 if (elementToHighlight
== null) elementToHighlight
= place
;
1182 holder
.createWarningAnnotation(elementToHighlight
, message
);
1186 private static boolean areTypesCompatibleForCallingClosure(PsiType
[] argumentTypes
,
1187 PsiType
[] paramTypes
,
1189 GlobalSearchScope resolveScope
) {
1190 if (argumentTypes
.length
!= paramTypes
.length
) return false;
1191 for (int i
= 0; i
< argumentTypes
.length
; i
++) {
1192 final PsiType paramType
= TypesUtil
.boxPrimitiveType(paramTypes
[i
], manager
, resolveScope
);
1193 final PsiType argType
= argumentTypes
[i
];
1194 if (!TypesUtil
.isAssignableByMethodCallConversion(paramType
, argType
, manager
, resolveScope
)) return false;
1199 private static void registerAddImportFixes(GrReferenceElement refElement
, Annotation annotation
) {
1200 final String referenceName
= refElement
.getReferenceName();
1201 //noinspection ConstantConditions
1202 if (StringUtil
.isEmpty(referenceName
) || Character
.isLowerCase(referenceName
.charAt(0))) {
1206 annotation
.registerFix(new GroovyAddImportAction(refElement
));
1209 private static void registerCreateClassByTypeFix(GrReferenceElement refElement
, Annotation annotation
) {
1210 GrPackageDefinition packageDefinition
= PsiTreeUtil
.getParentOfType(refElement
, GrPackageDefinition
.class);
1211 if (packageDefinition
== null && refElement
.getQualifier() == null) {
1212 PsiElement parent
= refElement
.getParent();
1213 if (parent
instanceof GrNewExpression
) {
1214 annotation
.registerFix(CreateClassFix
.createClassFromNewAction((GrNewExpression
)parent
));
1217 annotation
.registerFix(CreateClassFix
.createClassFixAction(refElement
));
1222 private static void highlightMember(AnnotationHolder holder
, GrMember member
) {
1223 if (member
instanceof GrField
) {
1224 GrField field
= (GrField
)member
;
1225 PsiElement identifier
= field
.getNameIdentifierGroovy();
1226 final boolean isStatic
= field
.hasModifierProperty(GrModifier
.STATIC
);
1227 holder
.createInfoAnnotation(identifier
, null).setTextAttributes(isStatic ? DefaultHighlighter
.STATIC_FIELD
: DefaultHighlighter
.INSTANCE_FIELD
);
1231 private static void highlightAnnotation(AnnotationHolder holder
, PsiElement refElement
, GroovyResolveResult result
) {
1232 PsiElement element
= result
.getElement();
1233 PsiElement parent
= refElement
.getParent();
1234 if (element
instanceof PsiClass
&& ((PsiClass
)element
).isAnnotationType() && !(parent
instanceof GrImportStatement
)) {
1235 Annotation annotation
= holder
.createInfoAnnotation(parent
, null);
1236 annotation
.setTextAttributes(DefaultHighlighter
.ANNOTATION
);
1237 GroovyPsiElement context
= result
.getCurrentFileResolveContext();
1238 if (context
instanceof GrImportStatement
) {
1239 annotation
= holder
.createInfoAnnotation(((GrImportStatement
)context
).getImportReference(), null);
1240 annotation
.setTextAttributes(DefaultHighlighter
.ANNOTATION
);
1247 private static String
buildArgTypesList(PsiType
[] argTypes
) {
1248 StringBuilder builder
= new StringBuilder();
1249 builder
.append("(");
1250 for (int i
= 0; i
< argTypes
.length
; i
++) {
1252 builder
.append(", ");
1254 PsiType argType
= argTypes
[i
];
1255 builder
.append(argType
!= null ? argType
.getInternalCanonicalText() : "?");
1257 builder
.append(")");
1258 return builder
.toString();
1261 private static class DuplicateVariablesProcessor
extends PropertyResolverProcessor
{
1262 boolean borderPassed
;
1264 public DuplicateVariablesProcessor(GrVariable variable
) {
1265 super(variable
.getName(), variable
);
1266 borderPassed
= false;
1270 public boolean execute(PsiElement element
, ResolveState state
) {
1274 return super.execute(element
, state
);
1278 public void handleEvent(Event event
, Object associated
) {
1279 if (event
== ResolveUtil
.DECLARATION_SCOPE_PASSED
) {
1280 borderPassed
= true;
1282 super.handleEvent(event
, associated
);