diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index 68ac7f694f7c..b8dd18eb5295 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -1414,11 +1414,22 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { return false; } + PsiMethod method = expression.resolveMethod(); + if (method == null) { + return false; + } + + final int paramCount = method.getParameterList().getParametersCount(); + boolean varArgs = method.isVarArgs(); final PsiExpression[] args = expression.getArgumentList().getExpressions(); + if (varArgs && args.length < paramCount - 1 || !varArgs && args.length != paramCount) { + return false; + } + List contracts = ContainerUtil.findAll(_contracts, new Condition() { @Override public boolean value(MethodContract contract) { - return args.length == contract.arguments.length; + return paramCount == contract.arguments.length; } }); if (contracts.isEmpty()) { @@ -1428,6 +1439,12 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { for (PsiExpression arg : args) { arg.accept(this); } + if (varArgs) { + for (int i = 0; i < args.length - paramCount + 1; i++) { + addInstruction(new PopInstruction()); + } + pushUnknown(); + } if (contracts.size() > 1) { addInstruction(new DupInstruction(args.length, contracts.size() - 1)); diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ContractVarargs.java b/java/java-tests/testData/inspection/dataFlow/fixture/ContractVarargs.java new file mode 100644 index 000000000000..0c5e43d8a038 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ContractVarargs.java @@ -0,0 +1,30 @@ +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class Contracts { + + public void simpleFail(@Nullable String message) { + notBlank(message); + log(message); + } + + @Contract("_->fail") + private void notBlank(@Nullable Object message) { + + } + + @Contract("_,_,_->fail") + private void notBlank(@Nullable Object o, String message, Object... args) { + + } + + public void varargFail(@Nullable String message) { + notBlank(message, "Message should not be blank"); + log(message); // highlighted + } + + public void log(@NotNull String message) { + System.out.println(message); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index f636c11b37ab..ddec53269a1c 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -274,6 +274,7 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase { public void testContractWithNullable() { doTest(); } public void testContractPreservesUnknownNullability() { doTest(); } public void testContractSeveralClauses() { doTest(); } + public void testContractVarargs() { doTest(); } public void testBoxingImpliesNotNull() { doTest(); } public void testLargeIntegersAreNotEqualWhenBoxed() { doTest(); }