IDEA-52183: If groovy library added to a project 'Method getMetaClass is not implemen...
[fedora-idea.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / annotator / GroovyAnnotator.java
blob35707bf19cdf15ba0f525ed24cf6457654b41857
1 /*
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;
82 import java.util.*;
84 /**
85 * @author ven
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) {
100 myHolder = holder;
101 ((GroovyPsiElement)element).accept(this);
102 myHolder = null;
106 @Override
107 public void visitElement(GroovyPsiElement element) {
108 if (element.getParent() instanceof GrDocReferenceElement) {
109 checkGrDocReferenceElement(myHolder, element);
111 else {
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());
122 @Override
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) {
132 return;
135 checkSingleResolvedElement(myHolder, refElement, resolveResult, true);
139 @Override
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()));
163 else {
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);
180 else {
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);
196 else {
197 registerStaticImportFix(referenceExpression, annotation);
200 else {
201 if (qualifier.getType() == null) {
202 return;
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)) {
214 return;
217 annotation.registerFix(new GroovyStaticImportMethodFix((GrCall)referenceExpression.getParent()));
220 @Override
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);
230 @Override
231 public void visitMethod(GrMethod method) {
232 checkMethodDefinitionModifiers(myHolder, method);
233 checkInnerMethod(myHolder, method);
236 @Override
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"));
261 @Override
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)) {
273 myHolder
274 .createWarningAnnotation(variable.getNameIdentifierGroovy(), GroovyBundle.message("field.already.defined", variable.getName()));
276 else {
277 final String key = duplicate instanceof GrField ? "field.already.defined" : "variable.already.defined";
278 myHolder.createErrorAnnotation(variable.getNameIdentifierGroovy(), GroovyBundle.message(key, variable.getName()));
283 @Override
284 public void visitAssignmentExpression(GrAssignmentExpression expression) {
285 GrExpression lValue = expression.getLValue();
286 if (!PsiUtil.mightBeLVlaue(lValue)) {
287 myHolder.createErrorAnnotation(lValue, GroovyBundle.message("invalid.lvalue"));
291 @Override
292 public void visitReturnStatement(GrReturnStatement returnStatement) {
293 final GrExpression value = returnStatement.getReturnValue();
294 if (value != null) {
295 final PsiType type = value.getType();
296 if (type != null) {
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"));
303 else {
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"));
316 @Override
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);
345 @Override
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);
360 return;
362 if (newExpression.getQualifier() != null) {
363 if (clazz.hasModifierProperty(GrModifier.STATIC)) {
364 myHolder.createErrorAnnotation(newExpression, GroovyBundle.message("qualified.new.of.static.class"));
366 } else {
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);
380 else {
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);
389 else {
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);
403 @Override
404 public void visitDocMethodReference(GrDocMethodReference reference) {
405 checkGrDocMemberReference(reference, myHolder);
408 @Override
409 public void visitDocFieldReference(GrDocFieldReference reference) {
410 checkGrDocMemberReference(reference, myHolder);
413 @Override
414 public void visitConstructorInvocation(GrConstructorInvocation invocation) {
415 final GroovyResolveResult resolveResult = invocation.resolveConstructorGenerics();
416 if (resolveResult != null) {
417 checkMethodApplicability(resolveResult, invocation.getThisOrSuperKeyword(), myHolder);
419 else {
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);
426 else {
427 final PsiClass clazz = invocation.getDelegatedClass();
428 if (clazz != null) {
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);
440 @Override
441 public void visitBreakStatement(GrBreakStatement breakStatement) {
442 checkFlowInterruptStatement(breakStatement, myHolder);
445 @Override
446 public void visitContinueStatement(GrContinueStatement continueStatement) {
447 checkFlowInterruptStatement(continueStatement, myHolder);
450 @Override
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));
458 @Override
459 public void visitPackageDefinition(GrPackageDefinition packageDefinition) {
460 //todo: if reference isn't resolved it construct package definition
461 final PsiFile file = packageDefinition.getContainingFile();
462 assert file != null;
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"));
479 @Override
480 public void visitSuperExpression(GrSuperReferenceExpression superExpression) {
481 checkThisOrSuperReferenceExpression(superExpression, myHolder);
484 @Override
485 public void visitThisExpression(GrThisReferenceExpression thisExpression) {
486 checkThisOrSuperReferenceExpression(thisExpression, myHolder);
489 @Override
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"));
504 @Override
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));
521 @Override
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);
536 @Override
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();
544 if (label != null) {
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"));
565 @Nullable
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()));
580 else {
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()));
587 } else {
588 holder.createErrorAnnotation(expression, GroovyBundle.message("is.not.enclosing.class", ((PsiClass)resolved).getQualifiedName()));
591 else {
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"));
610 @Nullable
611 private static PsiElement findModifierStatic(GrMember grMember) {
612 final GrModifierList list = grMember.getModifierList();
613 if (list == null) {
614 return null;
617 for (PsiElement modifier : list.getModifiers()) {
618 if (GrModifier.STATIC.equals(modifier.getText())) {
619 return modifier;
622 return null;
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);
686 //script methods
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());
702 //interface
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()) {
714 //enumeration
715 //todo
717 else if (containingTypeDef.isAnnotationType()) {
718 //annotation
719 //todo
721 else if (containingTypeDef.isAnonymous()) {
722 //anonymous class
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"));
734 else {
735 //class
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;
762 /**** class ****/
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();
892 if (qName != null) {
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));
902 else {
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;
917 return packageName;
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));
947 return;
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();
994 VirtualFile file;
995 if (containingFile != null) {
996 file = containingFile.getVirtualFile();
997 if (file == null) return;
999 else {
1000 return;
1003 if (QuickfixUtil.isCall(referenceExpression)) {
1004 annotation.registerFix(new DynamicMethodFix(referenceExpression), referenceExpression.getTextRange());
1006 else {
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);
1017 return;
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);
1050 String message;
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);
1057 else {
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);
1068 return false;
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
1081 return true;
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) {
1091 return true;
1094 return false;
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);
1111 else {
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"));
1143 else {
1144 holder.createWarningAnnotation(nameElement, GroovyBundle.message("property.name.expected"));
1147 else {
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,
1188 PsiManager manager,
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;
1196 return true;
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))) {
1203 return;
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));
1216 else {
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++) {
1251 if (i > 0) {
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;
1269 @Override
1270 public boolean execute(PsiElement element, ResolveState state) {
1271 if (borderPassed) {
1272 return false;
1274 return super.execute(element, state);
1277 @Override
1278 public void handleEvent(Event event, Object associated) {
1279 if (event == ResolveUtil.DECLARATION_SCOPE_PASSED) {
1280 borderPassed = true;
1282 super.handleEvent(event, associated);