SideEffectChecker: mark all assert* methods as having exceptional effect

SideEffectChecker#mayHaveExceptionalSideEffect extracted
Fixes IDEA-174418
This commit is contained in:
Tagir Valeev
2017-06-15 11:14:45 +07:00
parent e76364769c
commit 9fbfbdacce
3 changed files with 30 additions and 8 deletions
@@ -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) {
@@ -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();
@@ -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;
}
}