From be5e2c5a5a261cacbc870d635cba474eb0fff43c Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 1 Oct 2014 18:36:01 +0200 Subject: [PATCH] contract checker: relax fail result validation to accept every call as a potential hazard, and don't continue with dfa --- .../codeInspection/dataFlow/ContractChecker.java | 11 ++++++----- .../dataFlow/contractCheck/NestedCallsMayThrow.java | 8 ++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractChecker.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractChecker.java index 7fad6fddd121..213468e89b5c 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractChecker.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractChecker.java @@ -38,7 +38,6 @@ class ContractChecker extends DataFlowRunner { private final Set myViolations = ContainerUtil.newHashSet(); private final Set myNonViolations = ContainerUtil.newHashSet(); private final Set myFailures = ContainerUtil.newHashSet(); - private final Set myCalls = ContainerUtil.newHashSet(); ContractChecker(PsiMethod method, PsiCodeBlock body, MethodContract contract, final boolean onTheFly) { super(body); @@ -105,11 +104,13 @@ class ContractChecker extends DataFlowRunner { } if (instruction instanceof MethodCallInstruction && - ((MethodCallInstruction)instruction).getMethodType() == MethodCallInstruction.MethodType.REGULAR_METHOD_CALL) { - ContainerUtil.addIfNotNull(myCalls, ((MethodCallInstruction)instruction).getCallExpression()); + ((MethodCallInstruction)instruction).getMethodType() == MethodCallInstruction.MethodType.REGULAR_METHOD_CALL && + myContract.returnValue == MethodContract.ValueConstraint.THROW_EXCEPTION) { + ContainerUtil.addIfNotNull(myFailures, ((MethodCallInstruction)instruction).getCallExpression()); + return DfaInstructionState.EMPTY_ARRAY; } - return super.acceptInstruction(visitor, instructionState); + return super.acceptInstruction(visitor, instructionState); } @@ -125,7 +126,7 @@ class ContractChecker extends DataFlowRunner { for (PsiElement element : myFailures) { errors.put(element, "Contract clause '" + myContract + "' is violated: exception might be thrown instead of returning " + myContract.returnValue); } - } else if (myFailures.isEmpty() && errors.isEmpty() && myCalls.isEmpty()) { + } else if (myFailures.isEmpty() && errors.isEmpty()) { PsiIdentifier nameIdentifier = myMethod.getNameIdentifier(); errors.put(nameIdentifier != null ? nameIdentifier : myMethod, "Contract clause '" + myContract + "' is violated: no exception is thrown"); diff --git a/java/java-tests/testData/inspection/dataFlow/contractCheck/NestedCallsMayThrow.java b/java/java-tests/testData/inspection/dataFlow/contractCheck/NestedCallsMayThrow.java index 073e3fab1bec..c7d15603047c 100644 --- a/java/java-tests/testData/inspection/dataFlow/contractCheck/NestedCallsMayThrow.java +++ b/java/java-tests/testData/inspection/dataFlow/contractCheck/NestedCallsMayThrow.java @@ -25,6 +25,14 @@ class Foo { failNatively(); } } + + @Contract("null->fail") + public Object assertNotNull(Object o) { + if (o == null) { + failNatively(); + } + return o; + } native void failNatively();