turn off contract inference for overrideable methods; hopefully, not forever (IDEA-127518)

This commit is contained in:
peter
2014-07-18 15:34:11 +02:00
parent 49a119a0e7
commit 5379b771ca
5 changed files with 44 additions and 13 deletions
@@ -17,17 +17,20 @@ package com.intellij.codeInsight;
import com.intellij.codeInspection.bytecodeAnalysis.ProjectBytecodeAnalysis;
import com.intellij.codeInspection.dataFlow.ContractInference;
import com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer;
import com.intellij.codeInspection.dataFlow.MethodContract;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifierListOwner;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import static com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT;
public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
@Nullable
@Override
@@ -37,7 +40,7 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
return fromBytecode;
}
if (listOwner instanceof PsiMethod && ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotationFQN)) {
if (listOwner instanceof PsiMethod && ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotationFQN) && !PsiUtil.canBeOverriden((PsiMethod)listOwner)) {
List<MethodContract> contracts = ContractInference.inferContracts((PsiMethod)listOwner);
if (!contracts.isEmpty()) {
return ProjectBytecodeAnalysis.getInstance(listOwner.getProject()).createContractAnnotation("\"" + StringUtil.join(contracts, "; ") + "\"");
@@ -50,19 +53,25 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
@NotNull
@Override
public PsiAnnotation[] findInferredAnnotations(@NotNull PsiModifierListOwner listOwner) {
List<PsiAnnotation> result = ContainerUtil.newArrayList();
PsiAnnotation[] fromBytecode = ProjectBytecodeAnalysis.getInstance(listOwner.getProject()).findInferredAnnotations(listOwner);
if (fromBytecode.length > 0) {
return fromBytecode;
}
if (listOwner instanceof PsiMethod) {
List<MethodContract> contracts = ContractInference.inferContracts((PsiMethod)listOwner);
if (!contracts.isEmpty()) {
return new PsiAnnotation[]{ProjectBytecodeAnalysis.getInstance(listOwner.getProject()).createContractAnnotation("\"" + StringUtil.join(contracts, "; ") + "\"")};
for (PsiAnnotation annotation : fromBytecode) {
if (!ORG_JETBRAINS_ANNOTATIONS_CONTRACT.equals(annotation.getQualifiedName()) ||
!(listOwner instanceof PsiMethod) ||
!PsiUtil.canBeOverriden((PsiMethod)listOwner)) {
result.add(annotation);
}
}
return PsiAnnotation.EMPTY_ARRAY;
if (listOwner instanceof PsiMethod && !PsiUtil.canBeOverriden((PsiMethod)listOwner)) {
List<MethodContract> contracts = ContractInference.inferContracts((PsiMethod)listOwner);
if (!contracts.isEmpty()) {
result.add(ProjectBytecodeAnalysis.getInstance(listOwner.getProject())
.createContractAnnotation("\"" + StringUtil.join(contracts, "; ") + "\""));
}
}
return result.isEmpty() ? PsiAnnotation.EMPTY_ARRAY : result.toArray(new PsiAnnotation[result.size()]);
}
@Override
@@ -0,0 +1,21 @@
import org.jetbrains.annotations.Nullable;
class Doo {
boolean isMaybeNotNull(@Nullable Object o) {
return o != null;
}
void foo(@Nullable String s) {
if (isMaybeNotNull(s)) {
System.out.println(<warning descr="Method invocation 's.length()' may produce 'java.lang.NullPointerException'">s.length()</warning>);
}
}
}
class DooImpl extends Doo {
boolean isMaybeNotNull(@Nullable Object o) {
return hashCode() == 42;
}
}
@@ -2,7 +2,7 @@ import org.jetbrains.annotations.Nullable;
class Doo {
boolean isNotNull(@Nullable Object o) {
static boolean isNotNull(@Nullable Object o) {
return o != null;
}
@@ -277,7 +277,7 @@ class ContractInferenceFromSourceTest extends LightCodeInsightFixtureTestCase {
}
private List<String> inferContracts(String method) {
def clazz = myFixture.addClass("class Foo { $method }")
def clazz = myFixture.addClass("final class Foo { $method }")
return ContractInference.inferContracts(clazz.methods[0]).collect { it as String }
}
}
@@ -251,6 +251,7 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase {
public void testRootThrowableCause() { doTest(); }
public void testUseInferredContracts() { doTest(); }
public void testContractInferenceBewareOverriding() { doTest(); }
public void testNumberComparisonsWhenValueIsKnown() { doTest(); }