ignore inferred annotation in @NotNull propagation to overridden methods

This commit is contained in:
peter
2014-07-10 10:35:56 +02:00
parent 1b75318697
commit fbb28259a1
9 changed files with 45 additions and 37 deletions
@@ -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<Boolean> 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;
}
}
@@ -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;
@@ -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;
}
}
@@ -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());
}
@@ -35,4 +35,6 @@ public abstract class InferredAnnotationsManager {
@NotNull
public abstract PsiAnnotation[] findInferredAnnotations(@NotNull PsiModifierListOwner listOwner);
public abstract boolean isInferredAnnotation(@NotNull PsiAnnotation annotation);
}
@@ -94,10 +94,15 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
@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<Element>
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();
}
@@ -16,7 +16,6 @@ class MyClass {
return super.clone();
}
@NotNull
@Override
public String toString() {
return super.toString();
@@ -16,7 +16,6 @@ class A {
return super.clone();
}
@NotNull
@Override
public String toString() {
return super.toString();
@@ -27,7 +27,6 @@ class MyClass<T> implements A<T> {
return super.clone();
}
@NotNull
@Override
public String toString() {
return super.toString();