Skip to content

Commit 10f5424

Browse files
cushonError Prone Team
authored andcommitted
FormatStringShouldUsePlaceholders shouldn't rewrite calls with a pass-through varargs Object[] argument
PiperOrigin-RevId: 834775942
1 parent 3ef3d79 commit 10f5424

File tree

6 files changed

+56
-16
lines changed

6 files changed

+56
-16
lines changed

check_api/src/main/java/com/google/errorprone/suppliers/Suppliers.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,15 @@ public Type get(VisitorState state) {
266266
};
267267
}
268268

269+
public static final Supplier<Type> OBJECT_TYPE_ARRAY =
270+
arrayOf(
271+
new Supplier<Type>() {
272+
@Override
273+
public Type get(VisitorState state) {
274+
return state.getSymtab().objectType;
275+
}
276+
});
277+
269278
public static ImmutableList<Supplier<Type>> fromStrings(Iterable<String> types) {
270279
return ImmutableList.copyOf(
271280
Iterables.transform(

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@
2626
import static com.google.errorprone.matchers.Matchers.instanceMethod;
2727
import static com.google.errorprone.matchers.Matchers.receiverOfInvocation;
2828
import static com.google.errorprone.matchers.Matchers.staticMethod;
29-
import static com.google.errorprone.suppliers.Suppliers.OBJECT_TYPE;
30-
import static com.google.errorprone.suppliers.Suppliers.arrayOf;
29+
import static com.google.errorprone.suppliers.Suppliers.OBJECT_TYPE_ARRAY;
3130
import static com.google.errorprone.util.ASTHelpers.getReceiver;
3231
import static com.google.errorprone.util.ASTHelpers.getSymbol;
3332
import static com.google.errorprone.util.MoreAnnotations.getAnnotationValue;
@@ -179,7 +178,7 @@ public Void visitAssignment(AssignmentTree tree, Void unused) {
179178
staticMethod()
180179
.onClass("org.mockito.Mockito")
181180
.named("mock")
182-
.withParametersOfType(ImmutableList.of(arrayOf(OBJECT_TYPE))));
181+
.withParametersOfType(ImmutableList.of(OBJECT_TYPE_ARRAY)));
183182

184183
private static final Matcher<MethodInvocationTree> DO_CALL_REAL_METHOD =
185184
anyOf(

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static com.google.errorprone.matchers.Matchers.anyOf;
2121
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
2222
import static com.google.errorprone.suppliers.Suppliers.OBJECT_TYPE;
23+
import static com.google.errorprone.suppliers.Suppliers.OBJECT_TYPE_ARRAY;
2324
import static com.google.errorprone.suppliers.Suppliers.arrayOf;
2425
import static com.google.errorprone.suppliers.Suppliers.typeFromString;
2526

@@ -63,7 +64,7 @@ public final class DistinctVarargsChecker extends BugChecker
6364
staticMethod()
6465
.onClass("com.google.common.collect.Ordering")
6566
.named("explicit")
66-
.withParametersOfType(ImmutableList.of(OBJECT_TYPE, arrayOf(OBJECT_TYPE))));
67+
.withParametersOfType(ImmutableList.of(OBJECT_TYPE, OBJECT_TYPE_ARRAY)));
6768
private static final Matcher<ExpressionTree> EVEN_PARITY_DISTINCT_ARG_MATCHER =
6869
anyOf(
6970
// ImmutableMap.of is covered by AlwaysThrows.

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
2525
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
2626
import static com.google.errorprone.suppliers.Suppliers.OBJECT_TYPE;
27-
import static com.google.errorprone.suppliers.Suppliers.arrayOf;
27+
import static com.google.errorprone.suppliers.Suppliers.OBJECT_TYPE_ARRAY;
2828
import static com.google.errorprone.util.ASTHelpers.getType;
2929
import static com.google.errorprone.util.TargetType.targetType;
3030
import static com.sun.source.tree.Tree.Kind.NULL_LITERAL;
@@ -137,54 +137,54 @@ private static Type targetTypElementType(VisitorState state) {
137137
* A single parameter whose erasure is type {@code Object[]}. This includes {@code Object...} and
138138
* (when {@code <T>} is an unbounded type parameter) {@code T[]}.
139139
*/
140-
private static final ImmutableList<Supplier<Type>> JUST_OBJECT_ARRAY =
141-
ImmutableList.of(arrayOf(OBJECT_TYPE));
140+
private static final ImmutableList<Supplier<Type>> JUST_OBJECT_TYPE_ARRAY =
141+
ImmutableList.of(OBJECT_TYPE_ARRAY);
142142

143143
private static final Matcher<ExpressionTree> METHOD_WITH_SOLE_PARAMETER_OBJECT_VARARGS =
144144
instanceMethod()
145145
.onDescendantOf("com.google.common.truth.Subject")
146146
.named("containsExactly")
147-
.withParametersOfType(JUST_OBJECT_ARRAY);
147+
.withParametersOfType(JUST_OBJECT_TYPE_ARRAY);
148148

149149
private static final Matcher<ExpressionTree> METHOD_WITH_SECOND_PARAMETER_OBJECT_VARARGS =
150150
instanceMethod()
151151
.onDescendantOf("com.google.common.reflect.Invokable")
152152
.named("invoke")
153-
.withParametersOfType(ImmutableList.of(OBJECT_TYPE, arrayOf(OBJECT_TYPE)));
153+
.withParametersOfType(ImmutableList.of(OBJECT_TYPE, OBJECT_TYPE_ARRAY));
154154

155155
// TODO: b/429160687 - Also cover the methods in UsingCorrespondence.
156156

157157
private static final Matcher<ExpressionTree> METHOD_WITH_THIRD_PARAMETER_OBJECT_VARARGS =
158158
instanceMethod()
159159
.onDescendantOf("com.google.common.truth.Subject")
160160
.namedAnyOf("containsAnyOf", "containsAtLeast", "containsNoneOf", "isAnyOf", "isNoneOf")
161-
.withParametersOfType(ImmutableList.of(OBJECT_TYPE, OBJECT_TYPE, arrayOf(OBJECT_TYPE)));
161+
.withParametersOfType(ImmutableList.of(OBJECT_TYPE, OBJECT_TYPE, OBJECT_TYPE_ARRAY));
162162

163163
private static final Matcher<ExpressionTree> METHOD_WITH_SOLE_PARAMETER_GENERIC_VARARGS =
164164
anyOf(
165165
staticMethod()
166166
.onClass("com.google.common.collect.AndroidAccessToCompactDataStructures")
167167
.namedAnyOf("newCompactHashSet", "newCompactLinkedHashSet")
168-
.withParametersOfType(JUST_OBJECT_ARRAY),
168+
.withParametersOfType(JUST_OBJECT_TYPE_ARRAY),
169169
staticMethod()
170170
.onClassAny(
171171
"com.google.common.collect.CompactHashSet",
172172
"com.google.common.collect.CompactLinkedHashSet")
173173
.named("create")
174-
.withParametersOfType(JUST_OBJECT_ARRAY),
174+
.withParametersOfType(JUST_OBJECT_TYPE_ARRAY),
175175
staticMethod()
176176
.onClassAny(
177177
"com.google.common.collect.Iterables", "com.google.common.collect.Iterators")
178178
.namedAnyOf("cycle", "forArray")
179-
.withParametersOfType(JUST_OBJECT_ARRAY),
179+
.withParametersOfType(JUST_OBJECT_TYPE_ARRAY),
180180
staticMethod()
181181
.onClass("com.google.common.collect.Lists")
182182
.namedAnyOf("newArrayList", "newLinkedList")
183-
.withParametersOfType(JUST_OBJECT_ARRAY),
183+
.withParametersOfType(JUST_OBJECT_TYPE_ARRAY),
184184
staticMethod()
185185
.onClass("com.google.common.collect.Sets")
186186
.namedAnyOf("newHashSet", "newLinkedHashSet")
187-
.withParametersOfType(JUST_OBJECT_ARRAY),
187+
.withParametersOfType(JUST_OBJECT_TYPE_ARRAY),
188188
staticMethod().onClass("java.util.Arrays").named("asList"),
189189
staticMethod()
190190
.onClass("java.util.stream.Stream")
@@ -196,5 +196,5 @@ private static Type targetTypElementType(VisitorState state) {
196196
* (Similarly, we may or may not need to call `withParametersOfType` for the other
197197
* cases above in which overloads exist, but we do anyway.)
198198
*/
199-
.withParametersOfType(JUST_OBJECT_ARRAY));
199+
.withParametersOfType(JUST_OBJECT_TYPE_ARRAY));
200200
}

core/src/main/java/com/google/errorprone/bugpatterns/formatstring/FormatStringShouldUsePlaceholders.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717
package com.google.errorprone.bugpatterns.formatstring;
1818

1919
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
20+
import static com.google.errorprone.suppliers.Suppliers.OBJECT_TYPE_ARRAY;
2021
import static com.google.errorprone.util.ASTHelpers.getStartPosition;
22+
import static com.google.errorprone.util.ASTHelpers.getType;
23+
import static com.google.errorprone.util.ASTHelpers.isSameType;
2124

2225
import com.google.common.collect.ImmutableList;
2326
import com.google.errorprone.BugPattern;
@@ -88,6 +91,10 @@ public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState
8891
if (arguments.isEmpty()) {
8992
return Description.NO_MATCH;
9093
}
94+
if (arguments.size() == 2
95+
&& isSameType(getType(arguments.get(1)), OBJECT_TYPE_ARRAY.get(state), state)) {
96+
return Description.NO_MATCH;
97+
}
9198
ExpressionTree formatString = arguments.getFirst();
9299

93100
// If the value is a compile-time constant, either it has no concatenations or the

core/src/test/java/com/google/errorprone/bugpatterns/formatstring/FormatStringShouldUsePlaceholdersTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,30 @@ public void checkPositionIndex(int i, int j) {
143143
Preconditions.checkPositionIndex(i, j + 10);
144144
}
145145
}
146+
""")
147+
.expectUnchanged()
148+
.doTest();
149+
}
150+
151+
@Test
152+
public void negativeVarargs() {
153+
refactoringHelper
154+
.addInputLines(
155+
"Test.java",
156+
"""
157+
import com.google.common.base.Preconditions;
158+
import java.util.ArrayList;
159+
import java.util.List;
160+
import java.util.Collections;
161+
162+
public class Test {
163+
public void checkPositionIndex(int i, String moreFormat, Object moreArgs) {
164+
List<Object> args = new ArrayList<>();
165+
args.add(i);
166+
Collections.addAll(args, moreArgs);
167+
Preconditions.checkArgument(false, String.format("%s: %s" + moreFormat, args.toArray()));
168+
}
169+
}
146170
""")
147171
.expectUnchanged()
148172
.doTest();

0 commit comments

Comments
 (0)