diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionBase.java index 38b54343dd73..565366c2fecb 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionBase.java @@ -17,6 +17,8 @@ package com.siyeh.ig.bugs; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer; +import com.intellij.codeInspection.dataFlow.MethodContract; +import com.intellij.codeInspection.dataFlow.StandardMethodContract; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.registry.Registry; @@ -173,6 +175,18 @@ public class IgnoreResultOfCallInspectionBase extends BaseInspection { if (anno != null && (honorInferred || !AnnotationUtil.isInferredAnnotation(anno)) && Boolean.TRUE.equals(AnnotationUtil.getBooleanAttributeValue(anno, "pure"))) { + String text = AnnotationUtil.getStringAttributeValue(anno, null); + if (text != null) { + try { + if (StandardMethodContract.parseContract(text).stream() + .anyMatch(c -> c.getReturnValue() == MethodContract.ValueConstraint.THROW_EXCEPTION)) { + return; + } + } + catch (StandardMethodContract.ParseException ignored) { + } + } + registerMethodCallOrRefError(call, aClass); return; } diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionTest.groovy b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionTest.groovy index fbebb3bb59cf..5b5729522049 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionTest.groovy +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionTest.groovy @@ -16,9 +16,10 @@ package com.siyeh.ig.bugs import com.intellij.codeInspection.LocalInspectionTool +import com.intellij.openapi.util.registry.Registry import com.siyeh.ig.LightInspectionTestCase -@SuppressWarnings("ResultOfMethodCallIgnored") +@SuppressWarnings(["ResultOfMethodCallIgnored", "UnusedReturnValue"]) class IgnoreResultOfCallInspectionTest extends LightInspectionTestCase { @Override @@ -98,7 +99,7 @@ class IgnoreResultOfCallInspectionTest extends LightInspectionTestCase { " final java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(\"baaaa\");\n" + " final java.util.regex.Matcher matcher = pattern.matcher(\"babaaaaaaaa\");\n" + " matcher./*Result of 'Matcher.find()' is ignored*/find/**/();\n" + - " matcher.notify();\n" + + " matcher.notifyAll();\n" + " }\n" + "}\n") } @@ -166,6 +167,29 @@ class IgnoreResultOfCallInspectionTest extends LightInspectionTestCase { "}") } + void testInference() { + Registry.get("ide.ignore.call.result.inspection.honor.inferred.pure").setValue(true, getTestRootDisposable()) + doTest("""class Test { + private static T checkNotNull(T reference) { + if (reference == null) { + throw new NullPointerException(); + } + return reference; + } + + private static String twice(String s) { + return s+s; + } + + void test(String string) { + checkNotNull(string); + /*Result of 'Test.twice()' is ignored*/twice/**/("foo"); + /*Result of 'Test.twice()' is ignored*/twice/**/("bar"); + } +} +""") + } + void testPureMethod() { doTest """ import org.jetbrains.annotations.Contract; @@ -176,7 +200,7 @@ class Util { } class C { - { + static { Util./*Result of 'Util.util()' is ignored*/util/**/(); } } @@ -193,7 +217,7 @@ class Util { } class C { - { + static { Runnable r = () -> Util./*Result of 'Util.util()' is ignored*/util/**/(); Runnable r1 = Util::/*Result of 'Util.util()' is ignored*/util/**/; }