diff --git a/check_api/src/main/java/com/google/errorprone/matchers/method/MethodMatcherImpl.java b/check_api/src/main/java/com/google/errorprone/matchers/method/MethodMatcherImpl.java index 8183348eb18..7997e973bfd 100644 --- a/check_api/src/main/java/com/google/errorprone/matchers/method/MethodMatcherImpl.java +++ b/check_api/src/main/java/com/google/errorprone/matchers/method/MethodMatcherImpl.java @@ -38,6 +38,7 @@ import com.google.errorprone.suppliers.Suppliers; import com.google.errorprone.util.ASTHelpers; import com.sun.source.tree.ExpressionTree; +import com.sun.tools.javac.code.Symbol.VarSymbol; import com.sun.tools.javac.code.Type; import java.util.Iterator; import java.util.List; @@ -220,8 +221,6 @@ public MethodNameMatcher withNameMatching(Pattern pattern) { @Override public MethodSignatureMatcher withSignature(String signature) { - // TODO(cushon): build a way to match signatures (including varargs ones!) that doesn't - // rely on MethodSymbol#toString(). return append( (m, s) -> m.sym().getSimpleName().contentEquals(signature) @@ -267,6 +266,32 @@ public ParameterMatcher withParametersOfType(Supplier first, Supplier expected) { + return append( + (method, state) -> { + List actual = method.sym().getParameters(); + if (actual.size() != Iterables.size(expected)) { + return false; + } + Iterator ax = actual.iterator(); + Iterator bx = expected.iterator(); + while (ax.hasNext()) { + VarSymbol parameter = ax.next(); + if (!bx.next().matches(parameter, parameter.type, state)) { + return false; + } + } + return true; + }); + } + @Override public ConstructorClassMatcher forClass(TypePredicate predicate) { return append((m, s) -> predicate.apply(m.ownerType(), s)); diff --git a/check_api/src/main/java/com/google/errorprone/matchers/method/MethodMatchers.java b/check_api/src/main/java/com/google/errorprone/matchers/method/MethodMatchers.java index aa185fc67d3..08a4026e554 100644 --- a/check_api/src/main/java/com/google/errorprone/matchers/method/MethodMatchers.java +++ b/check_api/src/main/java/com/google/errorprone/matchers/method/MethodMatchers.java @@ -18,6 +18,7 @@ import com.google.errorprone.matchers.Matcher; import com.google.errorprone.predicates.TypePredicate; +import com.google.errorprone.predicates.TypePredicates; import com.google.errorprone.suppliers.Supplier; import com.sun.source.tree.ExpressionTree; import com.sun.tools.javac.code.Type; @@ -189,6 +190,24 @@ public interface MethodNameMatcher extends MethodMatcher { /** Match methods whose formal parameters have the given types. */ ParameterMatcher withParametersOfType(Supplier first, Supplier... rest); + + /** + * Match methods whose formal parameters have the given types. + * + *

Unlike other methods for matching on parameters which consider erased types, this method + * provides access to generic types. Note also that other methods like {@link + * TypePredicates#isExactType} still only compare erased types. + */ + ParameterMatcher withParametersMatching(ParameterPredicate first, ParameterPredicate... rest); + + /** + * Match methods whose formal parameters have the given types. + * + *

Unlike other methods for matching on parameters which consider erased types, this method + * provides access to generic types. Note also that other methods like {@link + * TypePredicates#isExactType} still only compare erased types. + */ + ParameterMatcher withParametersMatching(Iterable parameters); } /** diff --git a/check_api/src/main/java/com/google/errorprone/matchers/method/ParameterPredicate.java b/check_api/src/main/java/com/google/errorprone/matchers/method/ParameterPredicate.java new file mode 100644 index 00000000000..6919c21033f --- /dev/null +++ b/check_api/src/main/java/com/google/errorprone/matchers/method/ParameterPredicate.java @@ -0,0 +1,27 @@ +/* + * Copyright 2026 The Error Prone Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.errorprone.matchers.method; + +import com.google.errorprone.VisitorState; +import com.sun.tools.javac.code.Symbol.VarSymbol; +import com.sun.tools.javac.code.Type; + +/** A predicate on a method or constructor parameter. */ +public interface ParameterPredicate { + + boolean matches(VarSymbol parameter, Type type, VisitorState state); +} diff --git a/check_api/src/main/java/com/google/errorprone/matchers/method/ParameterPredicates.java b/check_api/src/main/java/com/google/errorprone/matchers/method/ParameterPredicates.java new file mode 100644 index 00000000000..8c3a515a20d --- /dev/null +++ b/check_api/src/main/java/com/google/errorprone/matchers/method/ParameterPredicates.java @@ -0,0 +1,74 @@ +/* + * Copyright 2026 The Error Prone Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.errorprone.matchers.method; + +import static com.google.common.base.Preconditions.checkState; + +import com.google.errorprone.predicates.TypePredicate; +import com.sun.tools.javac.code.Symbol.MethodSymbol; +import com.sun.tools.javac.code.Symbol.TypeVariableSymbol; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.TypeTag; +import java.util.List; + +/** Utility methods for creating {@link ParameterPredicate} instances. */ +public final class ParameterPredicates { + + public static ParameterPredicate of(TypePredicate predicate) { + return (parameter, type, state) -> predicate.apply(type, state); + } + + public static ParameterPredicate varargsOf(ParameterPredicate predicate) { + return (parameter, type, state) -> { + MethodSymbol method = (MethodSymbol) parameter.owner; + if (!method.isVarArgs()) { + return false; + } + if (method.getParameters().getLast() != parameter) { + return false; + } + Type componentType = state.getTypes().elemtype(type); + return predicate.matches(parameter, componentType, state); + }; + } + + public static ParameterPredicate arrayOf(ParameterPredicate predicate) { + return (parameter, type, state) -> { + if (!type.hasTag(TypeTag.ARRAY)) { + return false; + } + Type componentType = state.getTypes().elemtype(type); + return predicate.matches(parameter, componentType, state); + }; + } + + // TODO: cushon - add methods like nthTypeParameter(2) or typeParameterNamed("X") as needed + public static ParameterPredicate onlyTypeParameter() { + return (parameter, type, state) -> { + MethodSymbol method = (MethodSymbol) parameter.owner; + List typeParameters = method.getTypeParameters(); + checkState( + typeParameters.size() == 1, + "Expected method %s to have exactly one type parameter, but found %s", + method, + typeParameters); + return type.hasTag(TypeTag.TYPEVAR) && type.tsym == typeParameters.getFirst(); + }; + } + + private ParameterPredicates() {} +} diff --git a/check_api/src/main/java/com/google/errorprone/suppliers/Suppliers.java b/check_api/src/main/java/com/google/errorprone/suppliers/Suppliers.java index c9dc3a6800a..c8ba5de58cf 100644 --- a/check_api/src/main/java/com/google/errorprone/suppliers/Suppliers.java +++ b/check_api/src/main/java/com/google/errorprone/suppliers/Suppliers.java @@ -130,12 +130,16 @@ public static Supplier typeFromClass(Class inputClass) { public static final Supplier LONG_TYPE = state -> state.getSymtab().longType; + public static final Supplier FLOAT_TYPE = state -> state.getSymtab().floatType; + public static final Supplier DOUBLE_TYPE = state -> state.getSymtab().doubleType; public static final Supplier CHAR_TYPE = state -> state.getSymtab().charType; public static final Supplier OBJECT_TYPE = state -> state.getSymtab().objectType; + public static final Supplier CLASS_TYPE = state -> state.getSymtab().classType; + public static final Supplier EXCEPTION_TYPE = state -> state.getSymtab().exceptionType; public static final Supplier THROWABLE_TYPE = state -> state.getSymtab().throwableType; diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/ArrayFillIncompatibleType.java b/core/src/main/java/com/google/errorprone/bugpatterns/ArrayFillIncompatibleType.java index 1c95a7d850e..73bbe6007ef 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/ArrayFillIncompatibleType.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/ArrayFillIncompatibleType.java @@ -19,6 +19,9 @@ import static com.google.errorprone.BugPattern.SeverityLevel.ERROR; import static com.google.errorprone.matchers.Matchers.anyOf; import static com.google.errorprone.matchers.Matchers.staticMethod; +import static com.google.errorprone.suppliers.Suppliers.INT_TYPE; +import static com.google.errorprone.suppliers.Suppliers.OBJECT_TYPE; +import static com.google.errorprone.suppliers.Suppliers.arrayOf; import com.google.common.collect.Iterables; import com.google.errorprone.BugPattern; @@ -46,10 +49,12 @@ public class ArrayFillIncompatibleType extends BugChecker implements MethodInvoc anyOf( staticMethod() .onClass("java.util.Arrays") - .withSignature("fill(java.lang.Object[],java.lang.Object)"), + .named("fill") + .withParametersOfType(arrayOf(OBJECT_TYPE), OBJECT_TYPE), staticMethod() .onClass("java.util.Arrays") - .withSignature("fill(java.lang.Object[],int,int,java.lang.Object)")); + .named("fill") + .withParametersOfType(arrayOf(OBJECT_TYPE), INT_TYPE, INT_TYPE, OBJECT_TYPE)); @Override public Description matchMethodInvocation( diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/CollectionToArraySafeParameter.java b/core/src/main/java/com/google/errorprone/bugpatterns/CollectionToArraySafeParameter.java index df38dcca2c1..713cf8f5127 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/CollectionToArraySafeParameter.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/CollectionToArraySafeParameter.java @@ -19,6 +19,8 @@ import static com.google.errorprone.BugPattern.SeverityLevel.ERROR; import static com.google.errorprone.matchers.Description.NO_MATCH; import static com.google.errorprone.matchers.Matchers.instanceMethod; +import static com.google.errorprone.matchers.method.ParameterPredicates.arrayOf; +import static com.google.errorprone.matchers.method.ParameterPredicates.onlyTypeParameter; import static com.google.errorprone.util.ASTHelpers.getType; import com.google.errorprone.BugPattern; @@ -47,7 +49,10 @@ public class CollectionToArraySafeParameter extends BugChecker implements MethodInvocationTreeMatcher { private static final Matcher TO_ARRAY_MATCHER = - instanceMethod().onDescendantOf("java.util.Collection").withSignature("toArray(T[])"); + instanceMethod() + .onDescendantOf("java.util.Collection") + .named("toArray") + .withParametersMatching(arrayOf(onlyTypeParameter())); @Override public Description matchMethodInvocation( diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/ExpectedExceptionChecker.java b/core/src/main/java/com/google/errorprone/bugpatterns/ExpectedExceptionChecker.java index 72a29289a42..9a032d9e2ab 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/ExpectedExceptionChecker.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/ExpectedExceptionChecker.java @@ -28,6 +28,7 @@ import static com.google.errorprone.matchers.Matchers.toType; import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod; import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod; +import static com.google.errorprone.suppliers.Suppliers.CLASS_TYPE; import static com.google.errorprone.util.ASTHelpers.getStartPosition; import static com.google.errorprone.util.ASTHelpers.getUpperBound; import static com.google.errorprone.util.ASTHelpers.isSubtype; @@ -77,15 +78,10 @@ public class ExpectedExceptionChecker extends BugChecker implements MethodTreeMa .withNameMatching(Pattern.compile("expect.*"))); static final Matcher IS_A = - anyOf( - staticMethod() - .onClassAny( - "org.hamcrest.Matchers", "org.hamcrest.CoreMatchers", "org.hamcrest.core.Is") - .withSignature("isA(java.lang.Class)"), - staticMethod() - .onClassAny( - "org.hamcrest.Matchers", "org.hamcrest.CoreMatchers", "org.hamcrest.core.Is") - .withSignature("isA(java.lang.Class)")); + staticMethod() + .onClassAny("org.hamcrest.Matchers", "org.hamcrest.CoreMatchers", "org.hamcrest.core.Is") + .named("isA") + .withParametersOfType(CLASS_TYPE); static final Matcher FAIL_MATCHER = anyOf( diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/RobolectricShadowDirectlyOn.java b/core/src/main/java/com/google/errorprone/bugpatterns/RobolectricShadowDirectlyOn.java index 8500c20eff2..f4460ace42a 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/RobolectricShadowDirectlyOn.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/RobolectricShadowDirectlyOn.java @@ -20,6 +20,9 @@ import static com.google.errorprone.BugPattern.SeverityLevel.WARNING; import static com.google.errorprone.fixes.SuggestedFixes.qualifyType; import static com.google.errorprone.matchers.Description.NO_MATCH; +import static com.google.errorprone.matchers.method.ParameterPredicates.onlyTypeParameter; +import static com.google.errorprone.predicates.TypePredicates.isExactType; +import static com.google.errorprone.suppliers.Suppliers.CLASS_TYPE; import static com.google.errorprone.util.ASTHelpers.getReceiver; import static com.google.errorprone.util.ASTHelpers.getSymbol; import static java.util.stream.Collectors.joining; @@ -32,6 +35,7 @@ import com.google.errorprone.matchers.Description; import com.google.errorprone.matchers.Matcher; import com.google.errorprone.matchers.method.MethodMatchers; +import com.google.errorprone.matchers.method.ParameterPredicates; import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.MemberSelectTree; import com.sun.source.tree.MethodInvocationTree; @@ -49,7 +53,9 @@ public class RobolectricShadowDirectlyOn extends BugChecker implements MethodInv private static final Matcher MATCHER = MethodMatchers.staticMethod() .onClass("org.robolectric.shadow.api.Shadow") - .withSignature("directlyOn(T,java.lang.Class)"); + .named("directlyOn") + .withParametersMatching( + onlyTypeParameter(), ParameterPredicates.of(isExactType(CLASS_TYPE))); @Override public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/UnnecessarySetDefault.java b/core/src/main/java/com/google/errorprone/bugpatterns/UnnecessarySetDefault.java index f3a2e22e4b1..f8bf82bdd0a 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/UnnecessarySetDefault.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/UnnecessarySetDefault.java @@ -21,6 +21,8 @@ import static com.google.errorprone.matchers.Description.NO_MATCH; import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod; import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod; +import static com.google.errorprone.suppliers.Suppliers.CLASS_TYPE; +import static com.google.errorprone.suppliers.Suppliers.OBJECT_TYPE; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.CharMatcher; @@ -68,7 +70,8 @@ public class UnnecessarySetDefault extends BugChecker implements MethodInvocatio private static final Matcher SET_DEFAULT = instanceMethod() .onExactClass("com.google.common.testing.NullPointerTester") - .withSignature("setDefault(java.lang.Class,T)"); + .named("setDefault") + .withParametersOfType(CLASS_TYPE, OBJECT_TYPE); @VisibleForTesting static final ImmutableMap> DEFAULTS = diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/flogger/FloggerArgumentToString.java b/core/src/main/java/com/google/errorprone/bugpatterns/flogger/FloggerArgumentToString.java index 0246e36895c..b63c7553a3a 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/flogger/FloggerArgumentToString.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/flogger/FloggerArgumentToString.java @@ -28,6 +28,17 @@ import static com.google.errorprone.matchers.Matchers.toType; import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod; import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod; +import static com.google.errorprone.predicates.TypePredicates.isExactType; +import static com.google.errorprone.predicates.TypePredicates.isPrimitive; +import static com.google.errorprone.suppliers.Suppliers.BOOLEAN_TYPE; +import static com.google.errorprone.suppliers.Suppliers.BYTE_TYPE; +import static com.google.errorprone.suppliers.Suppliers.CHAR_TYPE; +import static com.google.errorprone.suppliers.Suppliers.DOUBLE_TYPE; +import static com.google.errorprone.suppliers.Suppliers.FLOAT_TYPE; +import static com.google.errorprone.suppliers.Suppliers.INT_TYPE; +import static com.google.errorprone.suppliers.Suppliers.LONG_TYPE; +import static com.google.errorprone.suppliers.Suppliers.OBJECT_TYPE; +import static com.google.errorprone.suppliers.Suppliers.SHORT_TYPE; import static com.google.errorprone.util.ASTHelpers.getReceiver; import static com.google.errorprone.util.ASTHelpers.getType; @@ -40,6 +51,8 @@ import com.google.errorprone.fixes.SuggestedFix; import com.google.errorprone.matchers.Description; import com.google.errorprone.matchers.Matcher; +import com.google.errorprone.matchers.method.ParameterPredicates; +import com.google.errorprone.predicates.TypePredicates; import com.google.errorprone.suppliers.Supplier; import com.google.errorprone.util.ASTHelpers; import com.sun.source.tree.ExpressionTree; @@ -142,19 +155,12 @@ Parameter unwrap(MethodInvocationTree invocation, char placeholder) { // Consider carefully if it's worth doing the char[] variant (Will we format char[] exactly // as the corresponding String? How often is it used?) STRING_VALUE_OF( - anyOf( - Stream.of( - "valueOf(boolean)", - "valueOf(char)", - "valueOf(int)", - "valueOf(long)", - "valueOf(float)", - "valueOf(double)", - "valueOf(java.lang.Object)") - .map( - signature -> - instanceMethod().onExactClass("java.lang.String").withSignature(signature)) - .collect(toImmutableList()))) { + instanceMethod() + .onExactClass("java.lang.String") + .named("valueOf") + .withParametersMatching( + ParameterPredicates.of( + TypePredicates.anyOf(isPrimitive(), isExactType(OBJECT_TYPE))))) { @Override Parameter unwrap(MethodInvocationTree invocation, char placeholder) { @@ -164,19 +170,24 @@ Parameter unwrap(MethodInvocationTree invocation, char placeholder) { // Unwrap things like: Integer.toString(n) --> n STATIC_TO_STRING( anyOf( - ImmutableMap., String>builder() - .put(Boolean.class, "toString(boolean)") - .put(Character.class, "toString(char)") - .put(Byte.class, "toString(byte)") - .put(Short.class, "toString(short)") - .put(Integer.class, "toString(int)") - .put(Long.class, "toString(long)") - .put(Float.class, "toString(float)") - .put(Double.class, "toString(double)") + ImmutableMap., Supplier>builder() + .put(Boolean.class, BOOLEAN_TYPE) + .put(Character.class, CHAR_TYPE) + .put(Byte.class, BYTE_TYPE) + .put(Short.class, SHORT_TYPE) + .put(Integer.class, INT_TYPE) + .put(Long.class, LONG_TYPE) + .put(Float.class, FLOAT_TYPE) + .put(Double.class, DOUBLE_TYPE) .buildOrThrow() .entrySet() .stream() - .map(e -> staticMethod().onClass(e.getKey().getName()).withSignature(e.getValue())) + .map( + e -> + staticMethod() + .onClass(e.getKey().getName()) + .named("toString") + .withParametersOfType(e.getValue())) .collect(toImmutableList()))) { @Override @@ -188,19 +199,24 @@ Parameter unwrap(MethodInvocationTree invocation, char placeholder) { // Note that we could also unwrap unboxing, but this has the effect of removing a null check. STATIC_VALUE_OF( anyOf( - ImmutableMap., String>builder() - .put(Boolean.class, "valueOf(boolean)") - .put(Character.class, "valueOf(char)") - .put(Byte.class, "valueOf(byte)") - .put(Short.class, "valueOf(short)") - .put(Integer.class, "valueOf(int)") - .put(Long.class, "valueOf(long)") - .put(Float.class, "valueOf(float)") - .put(Double.class, "valueOf(double)") + ImmutableMap., Supplier>builder() + .put(Boolean.class, BOOLEAN_TYPE) + .put(Character.class, CHAR_TYPE) + .put(Byte.class, BYTE_TYPE) + .put(Short.class, SHORT_TYPE) + .put(Integer.class, INT_TYPE) + .put(Long.class, LONG_TYPE) + .put(Float.class, FLOAT_TYPE) + .put(Double.class, DOUBLE_TYPE) .buildOrThrow() .entrySet() .stream() - .map(e -> staticMethod().onClass(e.getKey().getName()).withSignature(e.getValue())) + .map( + e -> + staticMethod() + .onClass(e.getKey().getName()) + .named("valueOf") + .withParametersOfType(e.getValue())) .collect(toImmutableList()))) { @Override @@ -236,13 +252,18 @@ Parameter unwrap(MethodInvocationTree invocation, char placeholder) { }, STATIC_TO_HEX_STRING( anyOf( - ImmutableMap., String>builder() - .put(Integer.class, "toHexString(int)") - .put(Long.class, "toHexString(long)") + ImmutableMap., Supplier>builder() + .put(Integer.class, INT_TYPE) + .put(Long.class, LONG_TYPE) .buildOrThrow() .entrySet() .stream() - .map(e -> staticMethod().onClass(e.getKey().getName()).withSignature(e.getValue())) + .map( + e -> + staticMethod() + .onClass(e.getKey().getName()) + .named("toHexString") + .withParametersOfType(e.getValue())) .collect(toImmutableList()))) { @Override diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/formatstring/FormatStringUtils.java b/core/src/main/java/com/google/errorprone/bugpatterns/formatstring/FormatStringUtils.java index cc987de1128..291cb266023 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/formatstring/FormatStringUtils.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/formatstring/FormatStringUtils.java @@ -19,6 +19,9 @@ import static com.google.errorprone.matchers.Matchers.anyOf; import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod; import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod; +import static com.google.errorprone.predicates.TypePredicates.isExactType; +import static com.google.errorprone.suppliers.Suppliers.OBJECT_TYPE; +import static com.google.errorprone.suppliers.Suppliers.STRING_TYPE; import static com.google.errorprone.util.ASTHelpers.getSymbol; import static com.google.errorprone.util.ASTHelpers.hasAnnotation; import static com.google.errorprone.util.ASTHelpers.isSameType; @@ -28,6 +31,7 @@ import com.google.common.collect.ImmutableList; import com.google.errorprone.VisitorState; import com.google.errorprone.matchers.Matcher; +import com.google.errorprone.matchers.method.ParameterPredicates; import com.google.errorprone.util.ASTHelpers; import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.MethodInvocationTree; @@ -55,11 +59,17 @@ public final class FormatStringUtils { // Exclude zero-arg java.io.Console.readPassword from format methods. instanceMethod() .onExactClass("java.io.Console") - .withSignature("readPassword(java.lang.String,java.lang.Object...)"), + .named("readPassword") + .withParametersMatching( + ParameterPredicates.of(isExactType(STRING_TYPE)), + ParameterPredicates.varargsOf(ParameterPredicates.of(isExactType(OBJECT_TYPE)))), // Exclude zero-arg method java.io.Console.readLine from format methods. instanceMethod() .onExactClass("java.io.Console") - .withSignature("readLine(java.lang.String,java.lang.Object...)")); + .named("readLine") + .withParametersMatching( + ParameterPredicates.of(isExactType(STRING_TYPE)), + ParameterPredicates.varargsOf(ParameterPredicates.of(isExactType(OBJECT_TYPE))))); private static final Matcher FORMATTED_METHOD = instanceMethod().onExactClass("java.lang.String").named("formatted"); diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/inject/guice/BindingToUnqualifiedCommonType.java b/core/src/main/java/com/google/errorprone/bugpatterns/inject/guice/BindingToUnqualifiedCommonType.java index 2d0eef4f004..5affd29f72b 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/inject/guice/BindingToUnqualifiedCommonType.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/inject/guice/BindingToUnqualifiedCommonType.java @@ -29,6 +29,7 @@ import static com.google.errorprone.matchers.Matchers.methodReturns; import static com.google.errorprone.matchers.Matchers.not; import static com.google.errorprone.matchers.Matchers.receiverOfInvocation; +import static com.google.errorprone.suppliers.Suppliers.CLASS_TYPE; import com.google.errorprone.BugPattern; import com.google.errorprone.VisitorState; @@ -104,13 +105,11 @@ public class BindingToUnqualifiedCommonType extends BugChecker .namedAnyOf("to", "toInstance", "toProvider", "toConstructor"), receiverOfInvocation( methodInvocation( - anyOf( - instanceMethod() - .onDescendantOf("com.google.inject.AbstractModule") - .withSignature("bind(java.lang.Class)"), - instanceMethod() - .onDescendantOf("com.google.inject.Binder") - .withSignature("bind(java.lang.Class)")), + instanceMethod() + .onDescendantOfAny( + "com.google.inject.AbstractModule", "com.google.inject.Binder") + .named("bind") + .withParametersOfType(CLASS_TYPE), MatchType.ALL, classLiteral(IS_SIMPLE_TYPE))));