diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/MonoZipOfMonoVoidUsage.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/MonoZipOfMonoVoidUsage.java index e9995a980a4..9dfc8e9e53a 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/MonoZipOfMonoVoidUsage.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/MonoZipOfMonoVoidUsage.java @@ -4,12 +4,14 @@ import static com.google.errorprone.BugPattern.SeverityLevel.ERROR; import static com.google.errorprone.BugPattern.StandardTags.LIKELY_ERROR; import static com.google.errorprone.matchers.Matchers.allOf; +import static com.google.errorprone.matchers.Matchers.anyMethod; import static com.google.errorprone.matchers.Matchers.anyOf; -import static com.google.errorprone.matchers.Matchers.staticMethod; import static com.google.errorprone.matchers.Matchers.toType; import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod; import static java.util.stream.Collectors.joining; import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL; +import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.generic; +import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.type; import com.google.auto.service.AutoService; import com.google.common.collect.ImmutableList; @@ -17,6 +19,8 @@ import com.google.errorprone.BugPattern; import com.google.errorprone.VisitorState; import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.bugpatterns.BugChecker.MemberReferenceTreeMatcher; +import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; import com.google.errorprone.fixes.SuggestedFix; import com.google.errorprone.fixes.SuggestedFixes; import com.google.errorprone.matchers.Description; @@ -33,26 +37,26 @@ /** Bla. */ @AutoService(BugChecker.class) @BugPattern( - summary = - "`Flux#flatMap` and `Flux#flatMapSequential` have subtle semantics; " - + "please use `Flux#concatMap` or explicitly specify the desired amount of concurrency", + summary = "XXX: Write this.", link = BUG_PATTERNS_BASE_URL + "MonoZipOfMonoVoidUsage", linkType = CUSTOM, severity = ERROR, tags = LIKELY_ERROR) public final class MonoZipOfMonoVoidUsage extends BugChecker - implements BugChecker.MethodInvocationTreeMatcher, BugChecker.MemberReferenceTreeMatcher { + implements MethodInvocationTreeMatcher, MemberReferenceTreeMatcher { private static final long serialVersionUID = 1L; private static final Supplier MONO = Suppliers.typeFromString("reactor.core.publisher.Mono"); private static final Supplier EMPTY_MONO = Suppliers.typeFromString("reactor.core.publisher.MonoEmpty"); + private static final Supplier MONO_VOID = + VisitorState.memoize(generic(type("reactor.core.publisher.Mono"), type("java.lang.Void"))); // On Mono.zip, at least one element should match empty in order to proceed. - private static final Matcher STATIC_MONO_ZIP = + private static final Matcher MONO_ZIP_AND_WITH = anyOf( - staticMethod().onClass(MONO).named("zip"), - toType(MethodInvocationTree.class, hasArgumentOfType(EMPTY_MONO))); + anyMethod().onClass("reactor.core.publisher.Mono").namedAnyOf("zip", "zipWith"), + toType(MethodInvocationTree.class, hasArgumentOfType(MONO_VOID))); // On mono.zipWith, argument should match empty in order to proceed. private static final Matcher DYNAMIC_MONO_ZIP = allOf( @@ -67,30 +71,32 @@ public final class MonoZipOfMonoVoidUsage extends BugChecker // On emptyMono.zipWith, argument should match empty in order to proceed. private static final Matcher DYNAMIC_EMPTY_MONO_WITH_EMPTY_PARAM_ZIP = - allOf( - instanceMethod().onDescendantOf(EMPTY_MONO).named("zipWith"), - toType(MethodInvocationTree.class, hasArgumentOfType(EMPTY_MONO))); + allOf( + instanceMethod().onDescendantOf(EMPTY_MONO).named("zipWith"), + toType(MethodInvocationTree.class, hasArgumentOfType(EMPTY_MONO))); - private static final Matcher MONO_ZIP = - anyOf( - DYNAMIC_MONO_ZIP, - DYNAMIC_EMPTY_MONO_WITH_NON_EMPTY_PARAM_ZIP, - DYNAMIC_EMPTY_MONO_WITH_EMPTY_PARAM_ZIP, - STATIC_MONO_ZIP - ); + // private static final Matcher MONO_ZIP = + // anyOf( + // DYNAMIC_MONO_ZIP, + // DYNAMIC_EMPTY_MONO_WITH_NON_EMPTY_PARAM_ZIP, + // DYNAMIC_EMPTY_MONO_WITH_EMPTY_PARAM_ZIP, + // MONO_ZIP_AND_WITH); /** Instantiates a new {@link MonoZipOfMonoVoidUsage} instance. */ public MonoZipOfMonoVoidUsage() {} @Override public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { - if (!MONO_ZIP.matches(tree, state)) { + if (!MONO_ZIP_AND_WITH.matches(tree, state)) { return Description.NO_MATCH; } Description.Builder description = buildDescription(tree); - if (STATIC_MONO_ZIP.matches(tree, state)) { + // ASTHelpers.getType(tree.getArguments().get(0)) + // MoreTypes.generic(MoreTypes.type("reactor.core.publisher.Mono"), + // MoreTypes.type("java.lang.Void")).get(state) + if (MONO_ZIP_AND_WITH.matches(tree, state)) { ImmutableList arguments = ImmutableList.copyOf(tree.getArguments()); String replacement = @@ -115,7 +121,7 @@ public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState @Override public Description matchMemberReference(MemberReferenceTree tree, VisitorState state) { - if (!MONO_ZIP.matches(tree, state)) { + if (!MONO_ZIP_AND_WITH.matches(tree, state)) { return Description.NO_MATCH; } diff --git a/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/MonoZipOfMonoVoidUsageTest.java b/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/MonoZipOfMonoVoidUsageTest.java index 08f23f91f05..40a238baae5 100644 --- a/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/MonoZipOfMonoVoidUsageTest.java +++ b/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/MonoZipOfMonoVoidUsageTest.java @@ -4,7 +4,6 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode; import com.google.errorprone.CompilationTestHelper; import org.junit.jupiter.api.Test; -import reactor.core.publisher.Mono; final class MonoZipOfMonoVoidUsageTest { @Test @@ -17,6 +16,7 @@ void identification() { "class A {", " void m() {", " Mono a = Mono.empty();", + " Mono.empty().zipWith(a);", " Mono b = Mono.empty();", " Mono c = Mono.just(1);", " // BUG: Diagnostic contains:", @@ -29,6 +29,7 @@ void identification() { " Mono.zip(Mono.empty(), Mono.empty());", " // BUG: Diagnostic contains:", " Mono.zip(a, c, b);", + "", " }", "}") .doTest();