Skip to content

Commit

Permalink
* Implement the Mono type matcher preserving generic type
Browse files Browse the repository at this point in the history
  • Loading branch information
DimaLegeza committed Nov 29, 2023
1 parent bed01cc commit ea5a706
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.type;

import com.google.auto.service.AutoService;
import com.google.common.collect.Iterables;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
Expand All @@ -26,6 +27,7 @@
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree;

/**
* A {@link BugChecker} that flags usages of Mono.zip(Mono, Mono) and Mono.zipWith(Mono) with
Expand Down Expand Up @@ -68,7 +70,7 @@ public final class MonoZipOfMonoVoidUsage extends BugChecker
instanceMethod().onDescendantOf(MONO).named("zipWith"),
toType(MethodInvocationTree.class, staticMethod().onClass(MONO).named("empty"))),
allOf(
instanceMethod().onExactClass(MONO_VOID_TYPE).named("zipWith"),
onClassWithMethodName(MONO_VOID_TYPE, "zipWith"),
toType(MethodInvocationTree.class, hasArgumentOfType(MONO))));

// On Mono.zip, at least one element should match empty in order to proceed.
Expand Down Expand Up @@ -96,6 +98,28 @@ public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState
.build();
}

private static Matcher<ExpressionTree> onClassWithMethodName(
Supplier<Type> genericDesiredType, String methodName) {
return (tree, state) -> {
JCTree.JCFieldAccess methodExecuted =
(JCTree.JCFieldAccess) ((JCTree.JCMethodInvocation) tree).getMethodSelect();
Type type = methodExecuted.selected.type;
String invokedMethodName = methodExecuted.getIdentifier().toString();
return invokedMethodName.equals(methodName)

Check warning on line 108 in error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/MonoZipOfMonoVoidUsage.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to a lambda on line 108 without causing a test to fail

removed conditional - replaced equality check with false in 1st lambda in onClassWithMethodName (covered by 1 tests RemoveConditionalMutator_EQUAL_ELSE)
&& hasSameGenericType(type, genericDesiredType.get(state), state);

Check warning on line 109 in error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/MonoZipOfMonoVoidUsage.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to a lambda on line 109 without causing a test to fail

removed conditional - replaced equality check with false in 1st lambda in onClassWithMethodName (covered by 1 tests RemoveConditionalMutator_EQUAL_ELSE)
};
}

private static Matcher<MethodInvocationTree> hasArgumentOfType(
Supplier<Type> genericDesiredType) {
return (tree, state) ->
tree.getArguments().stream()
.anyMatch(
arg ->
hasSameGenericType(
ASTHelpers.getType(arg), genericDesiredType.get(state), state));
}

/**
* We need to extract real types from the generics because {@link ASTHelpers} cannot distinguish
* Mono&lt;Integer&gt; and Mono&lt;Void&gt; and reports those being the same.
Expand All @@ -112,14 +136,10 @@ public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState
*
* <p>In this case we will always have only one parameter.
*/
private static Matcher<MethodInvocationTree> hasArgumentOfType(Supplier<Type> type) {
return (tree, state) ->
tree.getArguments().stream()
.anyMatch(
arg -> {
Type argumentType = ASTHelpers.getType(arg).allparams().get(0);
Type requiredType = type.get(state).allparams().get(0);
return isSameType(argumentType, requiredType, state);
});
private static boolean hasSameGenericType(
Type genericArgumentType, Type genericDesiredType, VisitorState state) {
Type argumentType = Iterables.getOnlyElement(genericArgumentType.allparams());
Type requiredType = Iterables.getOnlyElement(genericDesiredType.allparams());
return isSameType(argumentType, requiredType, state);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ void identification() {
" // BUG: Diagnostic contains:",
" Mono.zip(a, a);",
" Mono.zip(e, e);",
// TODO: Should not be reported though
" // BUG: Diagnostic contains:",
" e.zipWith(e);",
" // BUG: Diagnostic contains:",
" Mono.zip(d, c, b, a);",
Expand Down

0 comments on commit ea5a706

Please sign in to comment.