From fbb28259a1c949aad54d39943fc0c340e70cf244 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 8 Jul 2014 10:49:11 +0200 Subject: [PATCH] ignore inferred annotation in @NotNull propagation to overridden methods --- .../ProjectBytecodeAnalysis.java | 35 ++++++------------- .../nullable/NullableStuffInspectionBase.java | 11 ++++-- .../InferredAnnotationsManagerImpl.java | 7 +++- .../generation/OverrideImplementUtil.java | 10 +++--- .../InferredAnnotationsManager.java | 2 ++ .../codeInsight/NullableNotNullManager.java | 14 ++++++-- ...CollapsedInCaseOfAnonymousClasses-out.java | 1 - .../smartType/NewAnonymousFunction-out.java | 1 - .../afterOverrideExtensionMethods.java | 1 - 9 files changed, 45 insertions(+), 37 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java index 6d034f8fcf47..5831f8eafab7 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java @@ -17,9 +17,7 @@ package com.intellij.codeInspection.bytecodeAnalysis; import com.intellij.ProjectTopics; import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.lang.PsiBuilder; -import com.intellij.lang.java.parser.JavaParser; -import com.intellij.lang.java.parser.JavaParserUtil; +import com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; @@ -28,12 +26,11 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ContentIterator; import com.intellij.openapi.roots.ModuleRootAdapter; import com.intellij.openapi.roots.ModuleRootEvent; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.ModificationTracker; import com.intellij.openapi.util.NotNullLazyKey; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; -import com.intellij.psi.impl.source.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.ProjectScope; import com.intellij.psi.util.CachedValueProvider; @@ -54,15 +51,8 @@ import java.util.Collection; */ public class ProjectBytecodeAnalysis extends AbstractProjectComponent { public static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.bytecodeAnalysis"); + public static final Key INFERRED_ANNOTATION = Key.create("INFERRED_ANNOTATION"); private static final PsiAnnotation[] NO_DATA = new PsiAnnotation[0]; - private static final CharTableImpl charTable = new CharTableImpl(); - private static final JavaParserUtil.ParserWrapper ANNOTATION = new JavaParserUtil.ParserWrapper() { - @Override - public void parse(final PsiBuilder builder) { - JavaParser.INSTANCE.getDeclarationParser().parseAnnotation(builder); - } - }; - private final PsiManager myPsiManager; private volatile Annotations myAnnotations = null; @@ -73,9 +63,8 @@ public class ProjectBytecodeAnalysis extends AbstractProjectComponent { return INSTANCE_KEY.getValue(project); } - public ProjectBytecodeAnalysis(Project project, PsiManager psiManager) { + public ProjectBytecodeAnalysis(Project project) { super(project); - myPsiManager = psiManager; final MessageBusConnection connection = myProject.getMessageBus().connect(); connection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() { @@ -191,7 +180,7 @@ public class ProjectBytecodeAnalysis extends AbstractProjectComponent { if (notNull && contractValue != null) { return new PsiAnnotation[]{ getNotNullAnnotation(), - createAnnotationFromText("@org.jetbrains.annotations.Contract(" + contractValue + ")") + createAnnotationFromText("@" + ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT + "(" + contractValue + ")") }; } else if (notNull) { @@ -201,7 +190,7 @@ public class ProjectBytecodeAnalysis extends AbstractProjectComponent { } else if (contractValue != null) { return new PsiAnnotation[]{ - createAnnotationFromText("@org.jetbrains.annotations.Contract(" + contractValue + ")") + createAnnotationFromText("@" + ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT + "(" + contractValue + ")") }; } else { @@ -281,14 +270,10 @@ public class ProjectBytecodeAnalysis extends AbstractProjectComponent { } @NotNull - PsiAnnotation createAnnotationFromText(@NotNull final String text) throws IncorrectOperationException { - synchronized (charTable) { - final DummyHolder holder = DummyHolderFactory.createHolder(myPsiManager, - new JavaDummyElement(text, ANNOTATION, LanguageLevel.HIGHEST), null, - charTable); - final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); - return (PsiAnnotation) element; - } + private PsiAnnotation createAnnotationFromText(@NotNull final String text) throws IncorrectOperationException { + PsiAnnotation annotation = JavaPsiFacade.getElementFactory(myProject).createAnnotationFromText(text, null); + annotation.putUserData(INFERRED_ANNOTATION, Boolean.TRUE); + return annotation; } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java index 38f8d46fe10c..4dc89f7b22d5 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/NullableStuffInspectionBase.java @@ -16,6 +16,7 @@ package com.intellij.codeInspection.nullable; import com.intellij.codeInsight.AnnotationUtil; +import com.intellij.codeInsight.InferredAnnotationsManager; import com.intellij.codeInsight.NullableNotNullManager; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInsight.intention.AddAnnotationPsiFix; @@ -282,7 +283,7 @@ public class NullableStuffInspectionBase extends BaseJavaBatchLocalInspectionToo if (!reported_nullable_method_overrides_notnull && REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE && annotated.isDeclaredNullable - && NullableNotNullManager.isNotNull(superMethod)) { + && isNotNullNotInferred(superMethod)) { reported_nullable_method_overrides_notnull = true; final PsiAnnotation annotation = AnnotationUtil.findAnnotation(method, nullableManager.getNullables(), true); holder.registerProblem(annotation != null ? annotation : method.getNameIdentifier(), @@ -293,7 +294,7 @@ public class NullableStuffInspectionBase extends BaseJavaBatchLocalInspectionToo && REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL && !annotated.isDeclaredNullable && !annotated.isDeclaredNotNull - && NullableNotNullManager.isNotNull(superMethod)) { + && isNotNullNotInferred(superMethod)) { reported_not_annotated_method_overrides_notnull = true; final String defaultNotNull = nullableManager.getDefaultNotNull(); final String[] annotationsToRemove = ArrayUtil.toStringArray(nullableManager.getNullables()); @@ -415,6 +416,12 @@ public class NullableStuffInspectionBase extends BaseJavaBatchLocalInspectionToo } } + private static boolean isNotNullNotInferred(@NotNull PsiMethod superMethod) { + Project project = superMethod.getProject(); + PsiAnnotation notNull = NullableNotNullManager.getInstance(project).getNotNullAnnotation(superMethod); + return notNull != null && !InferredAnnotationsManager.getInstance(project).isInferredAnnotation(notNull); + } + @NotNull private static LocalQuickFix[] wrapFix(LocalQuickFix fix) { if (fix == null) return LocalQuickFix.EMPTY_ARRAY; diff --git a/java/java-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java b/java/java-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java index 92f161f16fb2..9fe870aadd6b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java @@ -28,9 +28,14 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager { return listOwner.getProject().getComponent(ProjectBytecodeAnalysis.class).findInferredAnnotation(listOwner, annotationFQN); } - @Nullable + @NotNull @Override public PsiAnnotation[] findInferredAnnotations(@NotNull PsiModifierListOwner listOwner) { return listOwner.getProject().getComponent(ProjectBytecodeAnalysis.class).findInferredAnnotations(listOwner); } + + @Override + public boolean isInferredAnnotation(@NotNull PsiAnnotation annotation) { + return annotation.getUserData(ProjectBytecodeAnalysis.INFERRED_ANNOTATION) != null; + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java index d8df67367790..341540dc87dc 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java @@ -15,10 +15,7 @@ */ package com.intellij.codeInsight.generation; -import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.codeInsight.CodeInsightActionHandler; -import com.intellij.codeInsight.CodeInsightBundle; -import com.intellij.codeInsight.MethodImplementor; +import com.intellij.codeInsight.*; import com.intellij.codeInsight.intention.AddAnnotationFix; import com.intellij.codeInsight.intention.AddAnnotationPsiFix; import com.intellij.featureStatistics.FeatureUsageTracker; @@ -259,6 +256,11 @@ public class OverrideImplementUtil extends OverrideImplementExploreUtil { for (String annotation : each.getAnnotations(project)) { if (moduleScope != null && facade.findClass(annotation, moduleScope) == null) continue; if (AnnotationUtil.isAnnotated(overridden, annotation, false, false) && !AnnotationUtil.isAnnotated(method, annotation, false, false)) { + PsiAnnotation psiAnnotation = AnnotationUtil.findAnnotation(overridden, annotation); + if (psiAnnotation != null && InferredAnnotationsManager.getInstance(project).isInferredAnnotation(psiAnnotation)) { + continue; + } + AddAnnotationPsiFix.removePhysicalAnnotations(method, each.annotationsToRemove(project, annotation)); AddAnnotationPsiFix.addPhysicalAnnotation(annotation, PsiNameValuePair.EMPTY_ARRAY, method.getModifierList()); } diff --git a/java/java-psi-api/src/com/intellij/codeInsight/InferredAnnotationsManager.java b/java/java-psi-api/src/com/intellij/codeInsight/InferredAnnotationsManager.java index a53caa219478..b3fbfe7547cf 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/InferredAnnotationsManager.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/InferredAnnotationsManager.java @@ -35,4 +35,6 @@ public abstract class InferredAnnotationsManager { @NotNull public abstract PsiAnnotation[] findInferredAnnotations(@NotNull PsiModifierListOwner listOwner); + + public abstract boolean isInferredAnnotation(@NotNull PsiAnnotation annotation); } diff --git a/java/java-psi-api/src/com/intellij/codeInsight/NullableNotNullManager.java b/java/java-psi-api/src/com/intellij/codeInsight/NullableNotNullManager.java index 192d19c31958..b5ccb269aa1d 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/NullableNotNullManager.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/NullableNotNullManager.java @@ -94,10 +94,15 @@ public class NullableNotNullManager implements PersistentStateComponent @Nullable public String getNullable(PsiModifierListOwner owner) { - PsiAnnotation annotation = findNullabilityAnnotation(owner, false, true); + PsiAnnotation annotation = getNullableAnnotation(owner); return annotation == null ? null : annotation.getQualifiedName(); } + @Nullable + public PsiAnnotation getNullableAnnotation(PsiModifierListOwner owner) { + return findNullabilityAnnotation(owner, false, true); + } + public void setDefaultNullable(@NotNull String defaultNullable) { LOG.assertTrue(getNullables().contains(defaultNullable)); myDefaultNullable = defaultNullable; @@ -107,9 +112,14 @@ public class NullableNotNullManager implements PersistentStateComponent return myDefaultNotNull; } + @Nullable + public PsiAnnotation getNotNullAnnotation(PsiModifierListOwner owner) { + return findNullabilityAnnotation(owner, false, false); + } + @Nullable public String getNotNull(PsiModifierListOwner owner) { - PsiAnnotation annotation = findNullabilityAnnotation(owner, false, false); + PsiAnnotation annotation = getNotNullAnnotation(owner); return annotation == null ? null : annotation.getQualifiedName(); } diff --git a/java/java-tests/testData/codeInsight/completion/smartType/DiamondNotCollapsedInCaseOfAnonymousClasses-out.java b/java/java-tests/testData/codeInsight/completion/smartType/DiamondNotCollapsedInCaseOfAnonymousClasses-out.java index 6c1b5b5e9c54..75920b24bebf 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/DiamondNotCollapsedInCaseOfAnonymousClasses-out.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/DiamondNotCollapsedInCaseOfAnonymousClasses-out.java @@ -16,7 +16,6 @@ class MyClass { return super.clone(); } - @NotNull @Override public String toString() { return super.toString(); diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NewAnonymousFunction-out.java b/java/java-tests/testData/codeInsight/completion/smartType/NewAnonymousFunction-out.java index e95a164c7c3e..78916255ed3a 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/NewAnonymousFunction-out.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/NewAnonymousFunction-out.java @@ -16,7 +16,6 @@ class A { return super.clone(); } - @NotNull @Override public String toString() { return super.toString(); diff --git a/java/java-tests/testData/codeInsight/overrideImplement/afterOverrideExtensionMethods.java b/java/java-tests/testData/codeInsight/overrideImplement/afterOverrideExtensionMethods.java index 15cacfeddd76..43c9a16301ce 100644 --- a/java/java-tests/testData/codeInsight/overrideImplement/afterOverrideExtensionMethods.java +++ b/java/java-tests/testData/codeInsight/overrideImplement/afterOverrideExtensionMethods.java @@ -27,7 +27,6 @@ class MyClass implements A { return super.clone(); } - @NotNull @Override public String toString() { return super.toString();