summaryrefslogtreecommitdiff
path: root/java/java-impl/src/com/intellij/codeInsight
diff options
context:
space:
mode:
Diffstat (limited to 'java/java-impl/src/com/intellij/codeInsight')
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java135
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java1
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java1
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java4
4 files changed, 129 insertions, 12 deletions
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java
index 98b582f73545..69398342cff4 100644
--- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java
@@ -30,6 +30,7 @@ import com.intellij.patterns.ElementPattern;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.source.PsiClassReferenceType;
+import com.intellij.psi.impl.source.PsiImmediateClassType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
@@ -38,6 +39,7 @@ import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -172,10 +174,38 @@ public class AnnotationsHighlightUtil {
PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement();
if (nameRef == null) continue;
PsiElement aClass = nameRef.resolve();
- if (resolved.equals(aClass)) {
+ if (!resolved.equals(aClass)) continue;
+
+ if (!PsiUtil.isLanguageLevel8OrHigher(annotationToCheck)) {
String description = JavaErrorMessages.message("annotation.duplicate.annotation");
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create();
}
+
+ PsiClass annotationType = (PsiClass)resolved;
+ PsiAnnotation metaAnno = PsiImplUtil.findAnnotation(annotationType.getModifierList(), CommonClassNames.JAVA_LANG_ANNOTATION_REPEATABLE);
+ if (metaAnno == null) {
+ String explanation = JavaErrorMessages.message("annotation.non.repeatable", annotationType.getQualifiedName());
+ String description = JavaErrorMessages.message("annotation.duplicate.explained", explanation);
+ return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create();
+ }
+
+ String explanation = doCheckRepeatableAnnotation(metaAnno);
+ if (explanation != null) {
+ String description = JavaErrorMessages.message("annotation.duplicate.explained", explanation);
+ return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create();
+ }
+
+ PsiClass collector = getRepeatableCollector(metaAnno);
+ if (collector != null) {
+ String collectorName = collector.getQualifiedName();
+ if (collectorName != null) {
+ PsiAnnotation collectorAnno = owner.findAnnotation(collectorName);
+ if (collectorAnno != null) {
+ String description = JavaErrorMessages.message("annotation.collector.wrong.place", collectorName);
+ return annotationError(collectorAnno, description);
+ }
+ }
+ }
}
return null;
@@ -458,9 +488,11 @@ public class AnnotationsHighlightUtil {
public static HighlightInfo checkTargetAnnotationDuplicates(PsiAnnotation annotation) {
PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement();
if (nameRef == null) return null;
+
PsiElement resolved = nameRef.resolve();
- if (!(resolved instanceof PsiClass) ||
- !CommonClassNames.TARGET_ANNOTATION_FQ_NAME.equals(((PsiClass) resolved).getQualifiedName())) return null;
+ if (!(resolved instanceof PsiClass) || !CommonClassNames.JAVA_LANG_ANNOTATION_TARGET.equals(((PsiClass)resolved).getQualifiedName())) {
+ return null;
+ }
PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
if (attributes.length < 1) return null;
@@ -483,6 +515,7 @@ public class AnnotationsHighlightUtil {
return null;
}
+ @Nullable
public static HighlightInfo checkFunctionalInterface(PsiAnnotation annotation) {
final String errorMessage = LambdaUtil.checkFunctionalInterface(annotation);
if (errorMessage != null) {
@@ -491,6 +524,90 @@ public class AnnotationsHighlightUtil {
return null;
}
+ @Nullable
+ public static HighlightInfo checkRepeatableAnnotation(PsiAnnotation annotation) {
+ String qualifiedName = annotation.getQualifiedName();
+ if (!CommonClassNames.JAVA_LANG_ANNOTATION_REPEATABLE.equals(qualifiedName)) return null;
+
+ String description = doCheckRepeatableAnnotation(annotation);
+ if (description != null) {
+ PsiAnnotationMemberValue collectorRef = PsiImplUtil.findAttributeValue(annotation, null);
+ if (collectorRef != null) {
+ return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(collectorRef).descriptionAndTooltip(description).create();
+ }
+ }
+
+ return null;
+ }
+
+ @Nullable
+ private static String doCheckRepeatableAnnotation(PsiAnnotation annotation) {
+ PsiAnnotationOwner owner = annotation.getOwner();
+ if (!(owner instanceof PsiModifierList)) return null;
+ PsiElement target = ((PsiModifierList)owner).getParent();
+ if (!(target instanceof PsiClass) || !((PsiClass)target).isAnnotationType()) return null;
+ PsiClass collector = getRepeatableCollector(annotation);
+ if (collector == null) return null;
+
+ PsiMethod[] methods = collector.findMethodsByName("value", false);
+ if (methods.length == 0) {
+ return JavaErrorMessages.message("annotation.container.no.value", collector.getQualifiedName());
+ }
+
+ if (methods.length == 1) {
+ PsiType expected = new PsiImmediateClassType((PsiClass)target, PsiSubstitutor.EMPTY).createArrayType();
+ if (!expected.equals(methods[0].getReturnType())) {
+ return JavaErrorMessages.message("annotation.container.bad.type", collector.getQualifiedName(), HighlightUtil.formatType(expected));
+ }
+ }
+
+ RetentionPolicy targetPolicy = getRetentionPolicy((PsiClass)target);
+ if (targetPolicy != null) {
+ RetentionPolicy collectorPolicy = getRetentionPolicy(collector);
+ if (collectorPolicy != null && targetPolicy.compareTo(collectorPolicy) > 0) {
+ return JavaErrorMessages.message("annotation.container.low.retention", collector.getQualifiedName(), collectorPolicy);
+ }
+ }
+
+ return null;
+ }
+
+ @Nullable
+ private static PsiClass getRepeatableCollector(PsiAnnotation annotation) {
+ PsiAnnotationMemberValue collectorRef = PsiImplUtil.findAttributeValue(annotation, null);
+ if (!(collectorRef instanceof PsiClassObjectAccessExpression)) return null;
+ PsiType collectorType = ((PsiClassObjectAccessExpression)collectorRef).getOperand().getType();
+ if (!(collectorType instanceof PsiClassType)) return null;
+ PsiClass collector = ((PsiClassType)collectorType).resolve();
+ if (collector == null || !collector.isAnnotationType()) return null;
+ return collector;
+ }
+
+ @Nullable
+ private static RetentionPolicy getRetentionPolicy(PsiClass annotation) {
+ PsiModifierList modifierList = annotation.getModifierList();
+ if (modifierList != null) {
+ PsiAnnotation retentionAnno = modifierList.findAnnotation(CommonClassNames.JAVA_LANG_ANNOTATION_RETENTION);
+ if (retentionAnno == null) return RetentionPolicy.CLASS;
+
+ PsiAnnotationMemberValue policyRef = PsiImplUtil.findAttributeValue(retentionAnno, null);
+ if (policyRef instanceof PsiReference) {
+ PsiElement field = ((PsiReference)policyRef).resolve();
+ if (field instanceof PsiEnumConstant) {
+ String name = ((PsiEnumConstant)field).getName();
+ try {
+ return RetentionPolicy.valueOf(name);
+ }
+ catch (Exception e) {
+ LOG.warn("Unknown policy: " + name);
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
public static class AnnotationReturnTypeVisitor extends PsiTypeVisitor<Boolean> {
public static final AnnotationReturnTypeVisitor INSTANCE = new AnnotationReturnTypeVisitor();
@Override
@@ -514,15 +631,15 @@ public class AnnotationsHighlightUtil {
public Boolean visitClassType(PsiClassType classType) {
if (classType.getParameters().length > 0) {
PsiClassType rawType = classType.rawType();
- if (rawType.equalsToText("java.lang.Class")) {
- return Boolean.TRUE;
- }
- return Boolean.FALSE;
+ return rawType.equalsToText(CommonClassNames.JAVA_LANG_CLASS);
}
+
PsiClass aClass = classType.resolve();
- if (aClass != null && (aClass.isAnnotationType() || aClass.isEnum())) return Boolean.TRUE;
+ if (aClass != null && (aClass.isAnnotationType() || aClass.isEnum())) {
+ return Boolean.TRUE;
+ }
- return classType.equalsToText("java.lang.Class") || classType.equalsToText("java.lang.String") ? Boolean.TRUE : Boolean.FALSE;
+ return classType.equalsToText(CommonClassNames.JAVA_LANG_CLASS) || classType.equalsToText(CommonClassNames.JAVA_LANG_STRING);
}
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java
index 3b6ef960f407..9e6f8a85cedb 100644
--- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java
@@ -183,6 +183,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkDuplicateAnnotations(annotation));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkForeignInnerClassesUsed(annotation));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkFunctionalInterface(annotation));
+ if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkRepeatableAnnotation(annotation));
}
@Override
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java
index dfc477ac173d..79c7dd9ecca0 100644
--- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java
@@ -311,7 +311,6 @@ public class SimplifyBooleanExpressionFix implements IntentionAction {
}
catch (IncorrectOperationException e) {
resultExpression = null;
- LOG.error("lExpr: " + lExpr.getText() + "; op: " + javaToken.getText() + "; rExpr: " + operand.getText() + "; top: " + expression.getText());
}
}
else {
diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java
index 98d8894c7034..f12fe42d4824 100644
--- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java
+++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -477,7 +477,7 @@ public class GenerateMembersUtil {
else {
JVMElementFactory factory = JVMElementFactories.requireFactory(targetParam.getLanguage(), targetParam.getProject());
for (PsiAnnotation annotation : sourceModifierList.getAnnotations()) {
- targetModifierList.add(factory.createAnnotationFromText(annotation.getText(), targetParam));
+ targetModifierList.add(factory.createAnnotationFromText(annotation.getText(), sourceParam));
}
for (@PsiModifier.ModifierConstant String m : PsiModifier.MODIFIERS) {
targetModifierList.setModifierProperty(m, sourceParam.hasModifierProperty(m));