mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
Compare commits
5 Commits
v0.22.0
...
mohamedsam
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81cdf54402 | ||
|
|
c78aa417f4 | ||
|
|
58426baa80 | ||
|
|
b3b0656666 | ||
|
|
10b19a3cab |
@@ -55,6 +55,7 @@ import reactor.util.function.Tuple2;
|
||||
import tech.picnic.errorprone.refaster.annotation.Description;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsEmpty;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsFunctionReturningMono;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsIdentityOperation;
|
||||
import tech.picnic.errorprone.refaster.matchers.ThrowsCheckedException;
|
||||
|
||||
@@ -548,6 +549,152 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't unnecessarily transform a {@link Flux#using(Callable, Function)} to a mono, instead use
|
||||
* the equivalent API provided by {@link Mono}.
|
||||
*/
|
||||
static final class MonoUsing<
|
||||
D extends AutoCloseable, T, P extends Publisher<? extends T>, M extends Mono<? extends T>> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(
|
||||
Callable<D> resourceSupplier,
|
||||
@Matches(IsFunctionReturningMono.class) Function<D, P> sourceSupplier) {
|
||||
return Flux.using(resourceSupplier, sourceSupplier).single();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(Callable<D> resourceSupplier, Function<D, M> sourceSupplier) {
|
||||
return Mono.using(resourceSupplier, sourceSupplier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't unnecessarily transform a {@link Flux#using(Callable, Function, boolean)} to a mono,
|
||||
* instead use the equivalent API provided by {@link Mono}.
|
||||
*/
|
||||
static final class MonoUsingEager<
|
||||
D extends AutoCloseable, T, P extends Publisher<? extends T>, M extends Mono<? extends T>> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(
|
||||
Callable<D> resourceSupplier,
|
||||
@Matches(IsFunctionReturningMono.class) Function<D, P> sourceSupplier,
|
||||
boolean eager) {
|
||||
return Flux.using(resourceSupplier, sourceSupplier, eager).single();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(Callable<D> resourceSupplier, Function<D, M> sourceSupplier, boolean eager) {
|
||||
return Mono.using(resourceSupplier, sourceSupplier, eager);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't unnecessarily transform a {@link Flux#using(Callable, Function, Consumer)} to a mono,
|
||||
* instead use the equivalent API provided by {@link Mono}.
|
||||
*/
|
||||
static final class MonoUsing2<
|
||||
D, T, P extends Publisher<? extends T>, M extends Mono<? extends T>> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(
|
||||
Callable<D> resourceSupplier,
|
||||
@Matches(IsFunctionReturningMono.class) Function<D, P> sourceSupplier,
|
||||
Consumer<D> resourceCleanup) {
|
||||
return Flux.using(resourceSupplier, sourceSupplier, resourceCleanup).single();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(
|
||||
Callable<D> resourceSupplier, Function<D, M> sourceSupplier, Consumer<D> resourceCleanup) {
|
||||
return Mono.using(resourceSupplier, sourceSupplier, resourceCleanup);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't unnecessarily transform a {@link Flux#using(Callable, Function, Consumer, boolean)} to a
|
||||
* mono, instead use the equivalent API provided by {@link Mono}.
|
||||
*/
|
||||
static final class MonoUsing2Eager<
|
||||
D, T, P extends Publisher<? extends T>, M extends Mono<? extends T>> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(
|
||||
Callable<D> resourceSupplier,
|
||||
@Matches(IsFunctionReturningMono.class) Function<D, P> sourceSupplier,
|
||||
Consumer<D> resourceCleanup,
|
||||
boolean eager) {
|
||||
return Flux.using(resourceSupplier, sourceSupplier, resourceCleanup, eager).single();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(
|
||||
Callable<D> resourceSupplier,
|
||||
Function<D, M> sourceSupplier,
|
||||
Consumer<D> resourceCleanup,
|
||||
boolean eager) {
|
||||
return Mono.using(resourceSupplier, sourceSupplier, resourceCleanup, eager);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't unnecessarily transform a {@link Flux#usingWhen(Publisher, Function, Function)} to a
|
||||
* mono, instead use the equivalent API provided by {@link Mono}.
|
||||
*/
|
||||
static final class MonoUsingWhen<
|
||||
D,
|
||||
T,
|
||||
P extends Publisher<? extends T>,
|
||||
P2 extends Publisher<?>,
|
||||
M extends Mono<? extends T>> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(
|
||||
Publisher<D> resourceSupplier,
|
||||
@Matches(IsFunctionReturningMono.class) Function<D, P> resourceClosure,
|
||||
Function<D, P2> asyncCleanup) {
|
||||
return Flux.usingWhen(resourceSupplier, resourceClosure, asyncCleanup).single();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(
|
||||
Publisher<D> resourceSupplier,
|
||||
Function<D, M> resourceClosure,
|
||||
Function<D, P2> asyncCleanup) {
|
||||
return Mono.usingWhen(resourceSupplier, resourceClosure, asyncCleanup);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't unnecessarily transform a {@link Flux#usingWhen(Publisher, Function, Function,
|
||||
* BiFunction, Function)} to a mono, instead use the equivalent API provided by {@link Mono}.
|
||||
*/
|
||||
static final class MonoUsingWhen2<
|
||||
D,
|
||||
T,
|
||||
P extends Publisher<? extends T>,
|
||||
P2 extends Publisher<?>,
|
||||
M extends Mono<? extends T>> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(
|
||||
Publisher<D> resourceSupplier,
|
||||
@Matches(IsFunctionReturningMono.class) Function<D, P> resourceClosure,
|
||||
Function<D, P2> asyncComplete,
|
||||
BiFunction<D, ? super Throwable, P2> asyncError,
|
||||
Function<D, P2> asyncCancel) {
|
||||
return Flux.usingWhen(
|
||||
resourceSupplier, resourceClosure, asyncComplete, asyncError, asyncCancel)
|
||||
.single();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(
|
||||
Publisher<D> resourceSupplier,
|
||||
Function<D, M> resourceClosure,
|
||||
Function<D, P2> asyncComplete,
|
||||
BiFunction<D, ? super Throwable, ? extends Publisher<?>> asyncError,
|
||||
Function<D, P2> asyncCancel) {
|
||||
return Mono.usingWhen(
|
||||
resourceSupplier, resourceClosure, asyncComplete, asyncError, asyncCancel);
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily pass an empty publisher to {@link Flux#switchIfEmpty(Publisher)}. */
|
||||
static final class FluxSwitchIfEmptyOfEmptyPublisher<T> {
|
||||
@BeforeTemplate
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -210,6 +211,57 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Mono.just(1).flux().single();
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<String>> testMonoUsing() {
|
||||
return ImmutableSet.of(
|
||||
Flux.using(() -> new ByteArrayInputStream(new byte[] {}), s -> Mono.just("foo")).single(),
|
||||
Flux.using(() -> new ByteArrayInputStream(new byte[] {}), s -> Flux.just("bar")).single());
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<String>> testMonoUsingEager() {
|
||||
return ImmutableSet.of(
|
||||
Flux.using(() -> new ByteArrayInputStream(new byte[] {}), s -> Mono.just("foo"), false)
|
||||
.single(),
|
||||
Flux.using(() -> new ByteArrayInputStream(new byte[] {}), s -> Flux.just("bar"), false)
|
||||
.single());
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<String>> testMonoUsing2() {
|
||||
return ImmutableSet.of(
|
||||
Flux.using(() -> "foo", foo -> Mono.just("bar"), foo -> {}).single(),
|
||||
Flux.using(() -> "foo", foo -> Flux.just("bar"), foo -> {}).single());
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<String>> testMonoUsing2Eager() {
|
||||
return ImmutableSet.of(
|
||||
Flux.using(() -> "foo", foo -> Mono.just("bar"), foo -> {}, false).single(),
|
||||
Flux.using(() -> "foo", foo -> Flux.just("bar"), foo -> {}, false).single());
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<String>> testMonoUsingWhen() {
|
||||
return ImmutableSet.of(
|
||||
Flux.usingWhen(Mono.just("foo"), foo -> Mono.just("bar"), foo -> Mono.just("baz")).single(),
|
||||
Flux.usingWhen(Mono.just("foo"), foo -> Flux.just("bar"), foo -> Mono.just("baz"))
|
||||
.single());
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<String>> testMonoUsingWhen2() {
|
||||
return ImmutableSet.of(
|
||||
Flux.usingWhen(
|
||||
Mono.just("foo"),
|
||||
foo -> Mono.just("bar"),
|
||||
foo -> Mono.just("baz"),
|
||||
(foo, e) -> Mono.just("qux"),
|
||||
foo -> Mono.just("thud"))
|
||||
.single(),
|
||||
Flux.usingWhen(
|
||||
Mono.just("foo"),
|
||||
foo -> Flux.just("bar"),
|
||||
foo -> Mono.just("baz"),
|
||||
(foo, e) -> Mono.just("qux"),
|
||||
foo -> Mono.just("thud"))
|
||||
.single());
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxSwitchIfEmptyOfEmptyPublisher() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).switchIfEmpty(Mono.empty()), Flux.just(2).switchIfEmpty(Flux.empty()));
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -209,6 +210,55 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Mono.just(1).single();
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<String>> testMonoUsing() {
|
||||
return ImmutableSet.of(
|
||||
Mono.using(() -> new ByteArrayInputStream(new byte[] {}), s -> Mono.just("foo")),
|
||||
Flux.using(() -> new ByteArrayInputStream(new byte[] {}), s -> Flux.just("bar")).single());
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<String>> testMonoUsingEager() {
|
||||
return ImmutableSet.of(
|
||||
Mono.using(() -> new ByteArrayInputStream(new byte[] {}), s -> Mono.just("foo"), false),
|
||||
Flux.using(() -> new ByteArrayInputStream(new byte[] {}), s -> Flux.just("bar"), false)
|
||||
.single());
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<String>> testMonoUsing2() {
|
||||
return ImmutableSet.of(
|
||||
Mono.using(() -> "foo", foo -> Mono.just("bar"), foo -> {}),
|
||||
Flux.using(() -> "foo", foo -> Flux.just("bar"), foo -> {}).single());
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<String>> testMonoUsing2Eager() {
|
||||
return ImmutableSet.of(
|
||||
Mono.using(() -> "foo", foo -> Mono.just("bar"), foo -> {}, false),
|
||||
Flux.using(() -> "foo", foo -> Flux.just("bar"), foo -> {}, false).single());
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<String>> testMonoUsingWhen() {
|
||||
return ImmutableSet.of(
|
||||
Mono.usingWhen(Mono.just("foo"), foo -> Mono.just("bar"), foo -> Mono.just("baz")),
|
||||
Flux.usingWhen(Mono.just("foo"), foo -> Flux.just("bar"), foo -> Mono.just("baz"))
|
||||
.single());
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<String>> testMonoUsingWhen2() {
|
||||
return ImmutableSet.of(
|
||||
Mono.usingWhen(
|
||||
Mono.just("foo"),
|
||||
foo -> Mono.just("bar"),
|
||||
foo -> Mono.just("baz"),
|
||||
(foo, e) -> Mono.just("qux"),
|
||||
foo -> Mono.just("thud")),
|
||||
Flux.usingWhen(
|
||||
Mono.just("foo"),
|
||||
foo -> Flux.just("bar"),
|
||||
foo -> Mono.just("baz"),
|
||||
(foo, e) -> Mono.just("qux"),
|
||||
foo -> Mono.just("thud"))
|
||||
.single());
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxSwitchIfEmptyOfEmptyPublisher() {
|
||||
return ImmutableSet.of(Flux.just(1), Flux.just(2));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package tech.picnic.errorprone.refaster.matchers;
|
||||
|
||||
import static com.google.errorprone.matchers.Matchers.isSameType;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.suppliers.Suppliers;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.LambdaExpressionTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.tree.Tree.Kind;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A matcher of lambda expressions that are of type {@code java.util.function.Function} that returns
|
||||
* a {@code reactor.core.publisher.Mono}.
|
||||
*/
|
||||
public final class IsFunctionReturningMono implements Matcher<ExpressionTree> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<Tree> MONO_TYPE =
|
||||
isSameType(Suppliers.typeFromString("reactor.core.publisher.Mono"));
|
||||
private static final Matcher<Tree> FUNCTION_TYPE =
|
||||
isSameType(Suppliers.typeFromString(Function.class.getCanonicalName()));
|
||||
|
||||
/** Instantiates a new {@link IsFunctionReturningMono} instance. */
|
||||
public IsFunctionReturningMono() {}
|
||||
|
||||
@Override
|
||||
public boolean matches(ExpressionTree tree, VisitorState state) {
|
||||
if (tree.getKind() != Kind.LAMBDA_EXPRESSION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LambdaExpressionTree lambdaExpressionTree = (LambdaExpressionTree) tree;
|
||||
return MONO_TYPE.matches(lambdaExpressionTree.getBody(), state)
|
||||
&& FUNCTION_TYPE.matches(lambdaExpressionTree, state);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package tech.picnic.errorprone.refaster.matchers;
|
||||
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class IsFunctionReturningMonoTest {
|
||||
@Test
|
||||
void matches() {
|
||||
CompilationTestHelper.newInstance(MatcherTestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.function.Function;",
|
||||
"import java.util.function.Supplier;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"class A {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Function<String, Mono<String>> positive = s -> Mono.just(s);",
|
||||
"",
|
||||
" Function<String, Flux<String>> negative = s -> Flux.just(s);",
|
||||
"",
|
||||
" Supplier<Mono<String>> negative2 = () -> Mono.just(\"s\");",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
/** A {@link BugChecker} that simply delegates to {@link IsFunctionReturningMono}. */
|
||||
@BugPattern(summary = "Flags expressions matched by `IsFunctionReturningMono`", severity = ERROR)
|
||||
public static final class MatcherTestChecker extends AbstractMatcherTestChecker {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// XXX: This is a false positive reported by Checkstyle. See
|
||||
// https://github.com/checkstyle/checkstyle/issues/10161#issuecomment-1242732120.
|
||||
@SuppressWarnings("RedundantModifier")
|
||||
public MatcherTestChecker() {
|
||||
super(new IsFunctionReturningMono());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user