Skip to content

Commit b063711

Browse files
graememorganError Prone Team
authored andcommitted
Improve TruthConstantAsserts to detect more constant-like expressions.
This reuses `ConstantExpressions`, but excludes non-static identifiers, given it's pretty darn common to assert on, say, a variable. PiperOrigin-RevId: 828437937
1 parent de35cc9 commit b063711

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

core/src/main/java/com/google/errorprone/bugpatterns/TruthConstantAsserts.java

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,18 @@
2525
import com.google.errorprone.BugPattern.StandardTags;
2626
import com.google.errorprone.VisitorState;
2727
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
28+
import com.google.errorprone.bugpatterns.threadsafety.ConstantExpressions;
29+
import com.google.errorprone.bugpatterns.threadsafety.ConstantExpressions.ConstantExpressionVisitor;
2830
import com.google.errorprone.fixes.SuggestedFix;
2931
import com.google.errorprone.matchers.Description;
3032
import com.google.errorprone.matchers.Matcher;
3133
import com.google.errorprone.util.ASTHelpers;
3234
import com.sun.source.tree.ExpressionTree;
3335
import com.sun.source.tree.MethodInvocationTree;
34-
import java.util.regex.Pattern;
36+
import com.sun.tools.javac.code.Symbol;
37+
import com.sun.tools.javac.code.Symbol.MethodSymbol;
38+
import java.util.concurrent.atomic.AtomicBoolean;
39+
import javax.inject.Inject;
3540

3641
/**
3742
* Points out if Truth Library assert is called on a constant.
@@ -47,14 +52,19 @@ public class TruthConstantAsserts extends BugChecker implements MethodInvocation
4752
private static final Matcher<ExpressionTree> ASSERT_THAT =
4853
staticMethod().onClass("com.google.common.truth.Truth").named("assertThat");
4954

50-
private static final Pattern EQ_NEQ = Pattern.compile("isEqualTo|isNotEqualTo");
51-
5255
private static final Matcher<ExpressionTree> TRUTH_SUBJECT_CALL =
5356
instanceMethod()
5457
.onDescendantOf("com.google.common.truth.Subject")
55-
.withNameMatching(EQ_NEQ)
58+
.namedAnyOf("isEqualTo", "isNotEqualTo")
5659
.withParameters("java.lang.Object");
5760

61+
private final ConstantExpressions constantExpressions;
62+
63+
@Inject
64+
TruthConstantAsserts(ConstantExpressions constantExpressions) {
65+
this.constantExpressions = constantExpressions;
66+
}
67+
5868
@Override
5969
public Description matchMethodInvocation(
6070
MethodInvocationTree methodInvocationTree, VisitorState state) {
@@ -76,15 +86,35 @@ public Description matchMethodInvocation(
7686
return Description.NO_MATCH;
7787
}
7888
// check that argument of assertThat is a constant
79-
if (ASTHelpers.constValue(expr) == null) {
89+
if (!constantIsh(expr, state)) {
8090
return Description.NO_MATCH;
8191
}
8292
// check that expectation isn't a constant
8393
ExpressionTree expectation = getOnlyElement(methodInvocationTree.getArguments());
84-
if (ASTHelpers.constValue(expectation) != null) {
94+
if (constantIsh(expectation, state)) {
8595
return Description.NO_MATCH;
8696
}
8797
SuggestedFix fix = SuggestedFix.swap(expr, expectation, state);
8898
return describeMatch(methodInvocationTree, fix);
8999
}
100+
101+
private boolean constantIsh(ExpressionTree tree, VisitorState state) {
102+
var constant = constantExpressions.constantExpression(tree, state).orElse(null);
103+
if (constant == null) {
104+
return false;
105+
}
106+
// Identifiers can be considered constants, but they're exactly what we usually assert on! So
107+
// don't consider them to be constants in this context.
108+
AtomicBoolean involvesIdentifiers = new AtomicBoolean();
109+
constant.accept(
110+
new ConstantExpressionVisitor() {
111+
@Override
112+
public void visitIdentifier(Symbol identifier) {
113+
if (!(identifier instanceof MethodSymbol)) {
114+
involvesIdentifiers.set(true);
115+
}
116+
}
117+
});
118+
return !involvesIdentifiers.get();
119+
}
90120
}

core/src/test/java/com/google/errorprone/bugpatterns/TruthConstantAssertsTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,24 @@ private static TruthConstantAssertsNegativeCases getObject() {
109109
""")
110110
.doTest();
111111
}
112+
113+
@Test
114+
public void positiveCase_viaImmutableList() {
115+
compilationHelper
116+
.addSourceLines(
117+
"Test.java",
118+
"""
119+
import static com.google.common.truth.Truth.assertThat;
120+
121+
import com.google.common.collect.ImmutableList;
122+
123+
public class Test {
124+
public void test(Object a) {
125+
// BUG: Diagnostic contains:
126+
assertThat(ImmutableList.of(1, 2, 3)).isEqualTo(a);
127+
}
128+
}
129+
""")
130+
.doTest();
131+
}
112132
}

0 commit comments

Comments
 (0)