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 4e8f91d67f55..3964ad4992cc 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionBase.java @@ -17,7 +17,6 @@ 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.openapi.roots.ProjectFileIndex; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; @@ -34,6 +33,7 @@ import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.callMatcher.CallMatcher; import com.siyeh.ig.psiutils.LibraryUtil; import com.siyeh.ig.psiutils.MethodMatcher; +import com.siyeh.ig.psiutils.SideEffectChecker; import org.intellij.lang.annotations.Pattern; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @@ -228,8 +228,7 @@ public class IgnoreResultOfCallInspectionBase extends BaseInspection { final boolean honorInferred = Registry.is("ide.ignore.call.result.inspection.honor.inferred.pure"); if (!honorInferred && AnnotationUtil.isInferredAnnotation(anno)) return false; return Boolean.TRUE.equals(AnnotationUtil.getBooleanAttributeValue(anno, "pure")) && - ControlFlowAnalyzer.getMethodCallContracts(method, null).stream() - .noneMatch(c -> c.getReturnValue() == MethodContract.ValueConstraint.THROW_EXCEPTION); + !SideEffectChecker.mayHaveExceptionalSideEffect(method); } private void registerMethodCallOrRefError(PsiExpression call, PsiClass aClass) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java index 661b2ce4af8b..4efa924cc3d0 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java @@ -126,11 +126,7 @@ public class SideEffectChecker { protected boolean isPure(PsiMethod method) { if (method == null) return false; if (PropertyUtil.isSimpleGetter(method)) return true; - if (ControlFlowAnalyzer.isPure(method)) { - return ControlFlowAnalyzer.getMethodContracts(method).stream() - .noneMatch(mc -> mc.returnValue == MethodContract.ValueConstraint.THROW_EXCEPTION); - } - return false; + return ControlFlowAnalyzer.isPure(method) && !mayHaveExceptionalSideEffect(method); } @Override @@ -202,6 +198,21 @@ public class SideEffectChecker { } } + /** + * Returns true if given method function is likely to throw an exception (e.g. "assertEquals"). In some cases this means that + * the method call should be preserved in source code even if it's pure (i.e. does not change the program state). + * + * @param method a method to check + * @return true if the method has exceptional side effect + */ + public static boolean mayHaveExceptionalSideEffect(PsiMethod method) { + if (method.getName().startsWith("assert")) { + return true; + } + return ControlFlowAnalyzer.getMethodContracts(method).stream() + .anyMatch(mc -> mc.returnValue == MethodContract.ValueConstraint.THROW_EXCEPTION); + } + private static boolean isSideEffectFreeConstructor(@NotNull PsiNewExpression newExpression) { PsiJavaCodeReferenceElement classReference = newExpression.getClassReference(); PsiClass aClass = classReference == null ? null : (PsiClass)classReference.resolve(); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_string_builder_query_update/MismatchedStringBuilderQueryUpdate.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_string_builder_query_update/MismatchedStringBuilderQueryUpdate.java index 51d7fcbf9fe1..fc631bb1a370 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_string_builder_query_update/MismatchedStringBuilderQueryUpdate.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_string_builder_query_update/MismatchedStringBuilderQueryUpdate.java @@ -19,6 +19,13 @@ import java.util.*; public class MismatchedStringBuilderQueryUpdate { + public void testAssert() { + StringBuilder finished = new StringBuilder(); + + finished.append("3 "); + Assert.assertEquals("expected", finished.toString()); + } + void foo() { final StringBuilder b = new StringBuilder(); b.append(""); @@ -115,3 +122,8 @@ class EnumConstant { SomeEnum(StringBuilder sb) {} } } +class Assert { + static Object assertEquals(Object a, Object b) { + return a; + } +} \ No newline at end of file