don't return inferred annotations that will be neglected anyway (e.g. on overrideable methods)

This commit is contained in:
peter
2014-12-03 17:40:04 +01:00
parent 590c6bfc19
commit e5d728e7a4
7 changed files with 42 additions and 70 deletions
@@ -48,22 +48,22 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
}
}
if (!ignoreInference(listOwner, annotationFQN)) {
PsiAnnotation fromBytecode = ProjectBytecodeAnalysis.getInstance(myProject).findInferredAnnotation(listOwner, annotationFQN);
if (fromBytecode != null) {
return fromBytecode;
}
if (ignoreInference(listOwner, annotationFQN)) {
return null;
}
PsiAnnotation fromBytecode = ProjectBytecodeAnalysis.getInstance(myProject).findInferredAnnotation(listOwner, annotationFQN);
if (fromBytecode != null) {
return fromBytecode;
}
if (canInferFromSource(listOwner)) {
//noinspection ConstantConditions
PsiMethod method = (PsiMethod)listOwner;
if (listOwner instanceof PsiMethod) {
if (ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotationFQN)) {
return getInferredContractAnnotation(method);
return getInferredContractAnnotation((PsiMethod)listOwner);
}
if ((AnnotationUtil.NOT_NULL.equals(annotationFQN) || AnnotationUtil.NULLABLE.equals(annotationFQN))) {
PsiAnnotation anno = getInferredNullityAnnotation(method);
PsiAnnotation anno = getInferredNullityAnnotation((PsiMethod)listOwner);
return anno == null ? null : annotationFQN.equals(anno.getQualifiedName()) ? anno : null;
}
}
@@ -79,6 +79,9 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
@Override
public boolean ignoreInference(@NotNull PsiModifierListOwner owner, @Nullable String annotationFQN) {
if (owner instanceof PsiMethod && PsiUtil.canBeOverriden((PsiMethod)owner)) {
return true;
}
if (ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotationFQN) && hasHardcodedContracts(owner)) {
return true;
}
@@ -138,10 +141,6 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
return ProjectBytecodeAnalysis.getInstance(myProject).createContractAnnotation(attrs);
}
private static boolean canInferFromSource(PsiModifierListOwner listOwner) {
return listOwner instanceof PsiMethod && !PsiUtil.canBeOverriden((PsiMethod)listOwner);
}
@NotNull
@Override
public PsiAnnotation[] findInferredAnnotations(@NotNull PsiModifierListOwner listOwner) {
@@ -150,17 +149,24 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
PsiAnnotation[] fromBytecode = ProjectBytecodeAnalysis.getInstance(myProject).findInferredAnnotations(listOwner);
for (PsiAnnotation annotation : fromBytecode) {
if (!ignoreInference(listOwner, annotation.getQualifiedName())) {
if (!ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotation.getQualifiedName()) || canInferFromSource(listOwner)) {
result.add(annotation);
}
result.add(annotation);
}
}
if (canInferFromSource(listOwner)) {
if (listOwner instanceof PsiMethod) {
PsiAnnotation hardcoded = getHardcodedContractAnnotation((PsiMethod)listOwner);
ContainerUtil.addIfNotNull(result, hardcoded != null ? hardcoded : getInferredContractAnnotation((PsiMethod)listOwner));
ContainerUtil.addIfNotNull(result, getInferredNullityAnnotation((PsiMethod)listOwner));
if (hardcoded != null) {
result.add(hardcoded);
} else if (!ignoreInference(listOwner, ORG_JETBRAINS_ANNOTATIONS_CONTRACT)) {
ContainerUtil.addIfNotNull(result, getInferredContractAnnotation((PsiMethod)listOwner));
}
if (!ignoreInference(listOwner, AnnotationUtil.NOT_NULL) || !ignoreInference(listOwner, AnnotationUtil.NULLABLE)) {
PsiAnnotation annotation = getInferredNullityAnnotation((PsiMethod)listOwner);
if (annotation != null && !ignoreInference(listOwner, annotation.getQualifiedName())) {
result.add(annotation);
}
}
}
return result.isEmpty() ? PsiAnnotation.EMPTY_ARRAY : result.toArray(new PsiAnnotation[result.size()]);
@@ -1490,10 +1490,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
final PsiAnnotation contractAnno = findContractAnnotation(method);
final int paramCount = method.getParameterList().getParametersCount();
if (contractAnno != null) {
if (AnnotationUtil.isInferredAnnotation(contractAnno) && PsiUtil.canBeOverriden(method)) {
return Collections.emptyList();
}
return CachedValuesManager.getCachedValue(contractAnno, new CachedValueProvider<List<MethodContract>>() {
@Nullable
@Override
@@ -24,7 +24,6 @@ import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizableStringList;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jdom.Element;
@@ -168,30 +167,16 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
myDefaultNotNull = defaultNotNull;
}
private static boolean skipAnnotation(@NotNull PsiAnnotation annotation, @NotNull PsiModifierListOwner owner) {
return owner instanceof PsiMethod &&
PsiUtil.canBeOverriden((PsiMethod)owner) &&
AnnotationUtil.isInferredAnnotation(annotation) &&
AnnotationUtil.NOT_NULL.equals(annotation.getQualifiedName());
}
@Nullable
private PsiAnnotation findNullabilityAnnotation(@NotNull PsiModifierListOwner owner, boolean checkBases, boolean nullable) {
Set<String> qNames = ContainerUtil.newHashSet(nullable ? getNullables() : getNotNulls());
PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, qNames);
if (annotation != null && !skipAnnotation(annotation, owner)) {
PsiAnnotation annotation = checkBases && (owner instanceof PsiClass || owner instanceof PsiMethod)
? AnnotationUtil.findAnnotationInHierarchy(owner, qNames)
: AnnotationUtil.findAnnotation(owner, qNames);
if (annotation != null) {
return annotation;
}
if (checkBases && owner instanceof PsiMethod) {
for (PsiModifierListOwner superOwner : AnnotationUtil.getSuperAnnotationOwners(owner)) {
annotation = AnnotationUtil.findAnnotation(superOwner, qNames);
if (annotation != null && !skipAnnotation(annotation, superOwner)) {
return annotation;
}
}
}
PsiType type = getOwnerType(owner);
if (type == null || TypeConversionUtil.isPrimitiveAndNotNull(type)) return null;
@@ -317,7 +302,6 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
}
try {
//noinspection deprecation
DefaultJDOMExternalizer.writeExternal(this, component);
}
catch (WriteExternalException e) {
@@ -329,7 +313,6 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
@Override
public void loadState(Element state) {
try {
//noinspection deprecation
DefaultJDOMExternalizer.readExternal(this, state);
if (myNullables.isEmpty()) {
Collections.addAll(myNullables, DEFAULT_NULLABLES);
@@ -2346,11 +2346,6 @@
<item name="java.lang.System void checkKey(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="java.lang.System void exit(int)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_ -&gt; fail&quot;"/>
</annotation>
</item>
<item name="java.lang.System void setProperties(java.util.Properties) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -3834,18 +3834,12 @@
<item name="org.apache.commons.lang.Validate void notEmpty(java.util.Map, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<!-- hardcoded start -->
<item name="org.apache.commons.lang.Validate void notNull(java.lang.Object)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="value = &quot;null -&gt; fail&quot;, pure = true"/>
</annotation>
<item name="org.apache.commons.lang.Validate void notNull(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="org.apache.commons.lang.Validate void notNull(java.lang.Object, java.lang.String)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="value = &quot;null, _ -&gt; fail&quot;, pure = true"/>
</annotation>
<item name="org.apache.commons.lang.Validate void notNull(java.lang.Object, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<!-- hardcoded end -->
<item name="org.apache.commons.lang.WordUtils WordUtils()">
<annotation name="org.jetbrains.annotations.Contract">
<val val="pure=true"/>
@@ -17,7 +17,6 @@ package com.intellij.codeInspection.bytecodeAnalysis;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.ExternalAnnotationsManager;
import com.intellij.codeInsight.InferredAnnotationsManager;
import com.intellij.codeInsight.daemon.GutterMark;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.projectRoots.Sdk;
@@ -257,7 +256,7 @@ public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestC
@Nullable
private PsiAnnotation findInferredAnnotation(PsiModifierListOwner owner, String fqn) {
return InferredAnnotationsManager.getInstance(myModule.getProject()).findInferredAnnotation(owner, fqn);
return ProjectBytecodeAnalysis.getInstance(getProject()).findInferredAnnotation(owner, fqn);
}
@Nullable
@@ -16,7 +16,6 @@
package com.intellij.codeInspection.bytecodeAnalysis;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.InferredAnnotationsManager;
import com.intellij.codeInspection.bytecodeAnalysis.asm.LeakingParameters;
import com.intellij.codeInspection.bytecodeAnalysis.data.*;
import com.intellij.openapi.util.io.FileUtil;
@@ -48,7 +47,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
public static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName();
private final String myClassesProjectRelativePath = "/classes/" + Test01.class.getPackage().getName().replace('.', '/');
private JavaPsiFacade myJavaPsiFacade;
private InferredAnnotationsManager myInferredAnnotationsManager;
private ProjectBytecodeAnalysis myBytecodeAnalysisService;
private MessageDigest myMessageDigest;
@@ -56,7 +55,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
protected void setUp() throws Exception {
super.setUp();
myJavaPsiFacade = JavaPsiFacade.getInstance(myModule.getProject());
myInferredAnnotationsManager = InferredAnnotationsManager.getInstance(myModule.getProject());
myBytecodeAnalysisService = ProjectBytecodeAnalysis.getInstance(myModule.getProject());
myMessageDigest = MessageDigest.getInstance("MD5");
setUpDataClasses();
}
@@ -131,7 +130,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
params: for (int i = 0; i < annotations.length; i++) {
Annotation[] parameterAnnotations = annotations[i];
PsiParameter psiParameter = psiMethod.getParameterList().getParameters()[i];
PsiAnnotation inferredAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiParameter, AnnotationUtil.NOT_NULL);
PsiAnnotation inferredAnnotation = myBytecodeAnalysisService.findInferredAnnotation(psiParameter, AnnotationUtil.NOT_NULL);
for (Annotation parameterAnnotation : parameterAnnotations) {
if (parameterAnnotation.annotationType() == ExpectNotNull.class) {
assertNotNull(javaMethod.toString() + " " + i, inferredAnnotation);
@@ -143,13 +142,13 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
// not-null result
ExpectNotNull expectedAnnotation = javaMethod.getAnnotation(ExpectNotNull.class);
PsiAnnotation actualAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiMethod, AnnotationUtil.NOT_NULL);
PsiAnnotation actualAnnotation = myBytecodeAnalysisService.findInferredAnnotation(psiMethod, AnnotationUtil.NOT_NULL);
assertEquals(javaMethod.toString(), expectedAnnotation == null, actualAnnotation == null);
// contracts
ExpectContract expectedContract = javaMethod.getAnnotation(ExpectContract.class);
PsiAnnotation actualContract = myInferredAnnotationsManager.findInferredAnnotation(psiMethod, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
PsiAnnotation actualContract = myBytecodeAnalysisService.findInferredAnnotation(psiMethod, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
String expectedText = expectedContract == null ? "null" : expectedContract.toString();
String inferredText = actualContract == null ? "null" : actualContract.getText();