UseMethod precondition check, fails to detect the usage
First test pass, second test fails.
The only difference I can see is Map.keySet() returns the Set interface and ImmutableMap.keySet() returns an ImmutableSet.
@Test
void usesMethodDeepHierarchy() {
rewriteRun(
spec -> spec.recipe(toRecipe(() -> new UsesMethod<>("java.util.Set contains(..)"))),
java(
"""
import java.util.Map;
class Test {
void test() {
Map.of("1", 4, "2", 5).keySet().contains("3");
}
}
""",
"""
/*~~>*/import java.util.Map;
class Test {
void test() {
Map.of("1", 4, "2", 5).keySet().contains("3");
}
}
"""
)
);
}
@Test
void usesMethodDeepHierarchyExternalDep() {
rewriteRun(
spec -> spec.recipe(toRecipe(() -> new UsesMethod<>("java.util.Set contains(..)")))
.parser(JavaParser.fromJavaVersion().classpath("guava")),
java(
"""
import com.google.common.collect.ImmutableMap;
class Test {
void test() {
ImmutableMap.of("1", 4, "2", 5).keySet().contains("3");
}
}
""",
"""
/*~~>*/import com.google.common.collect.ImmutableMap;
class Test {
void test() {
ImmutableMap.of("1", 4, "2", 5).keySet().contains("3");
}
}
"""
)
);
}
Hmm; I indeed see the type information for that Guava contains being linked to
com.google.common.collect.ImmutableCollection contains(java.lang.Object), which fits in with their abstract override, which according to our type system is not an override (isOverride() returns false). That then likely factors in with the failed match here.
/cc @knutwannheden
This comes from a refaster template that generates the precondition:
return Preconditions.check(
Preconditions.and(
new UsesType<>("java.util.Map", true),
new UsesMethod<>("java.util.Map keySet(..)", true),
new UsesMethod<>("java.util.Set contains(..)", true)
),
javaVisitor
);
Set.contains() overrides the Collection.contains(), I'm not sure if we should add logic there to use the base method.
The precondition looks correct to me. If the user wanted to match Collection#contains(), then the input parameter should be a Collection and not a Set. But I wonder if we do this correctly when the type doesn't override a specific inherited method 🤔
As far as that isOverride() problem is concerned, that appears to be a bug.