All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tech.picnic.errorprone.bugpatterns.FluxImplicitBlock Maven / Gradle / Ivy

There is a newer version: 0.19.1
Show newest version
package tech.picnic.errorprone.bugpatterns;

import static com.google.common.base.Preconditions.checkState;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.CONCURRENCY;
import static com.google.errorprone.BugPattern.StandardTags.PERFORMANCE;
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;

import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
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;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Supplier;
import com.google.errorprone.suppliers.Suppliers;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.util.Position;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import tech.picnic.errorprone.utils.ThirdPartyLibrary;

/**
 * A {@link BugChecker} that flags {@link reactor.core.publisher.Flux} operator usages that may
 * implicitly cause the calling thread to be blocked.
 *
 * 

Note that the methods flagged here are not themselves blocking, but iterating over the * resulting {@link Iterable} or {@link Stream} may be. */ @AutoService(BugChecker.class) @BugPattern( summary = "Avoid iterating over `Flux`es in an implicitly blocking manner", link = BUG_PATTERNS_BASE_URL + "FluxImplicitBlock", linkType = CUSTOM, severity = WARNING, tags = {CONCURRENCY, PERFORMANCE}) public final class FluxImplicitBlock extends BugChecker implements MethodInvocationTreeMatcher { private static final long serialVersionUID = 1L; private static final Matcher FLUX_WITH_IMPLICIT_BLOCK = instanceMethod() .onDescendantOf("reactor.core.publisher.Flux") .namedAnyOf("toIterable", "toStream") .withNoParameters(); private static final Supplier STREAM = Suppliers.typeFromString(Stream.class.getCanonicalName()); /** Instantiates a new {@link FluxImplicitBlock} instance. */ public FluxImplicitBlock() {} @Override public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { if (!FLUX_WITH_IMPLICIT_BLOCK.matches(tree, state)) { return Description.NO_MATCH; } Description.Builder description = buildDescription(tree).addFix(SuggestedFixes.addSuppressWarnings(state, canonicalName())); if (ThirdPartyLibrary.GUAVA.isIntroductionAllowed(state)) { description.addFix( suggestBlockingElementCollection( tree, ImmutableList.class.getCanonicalName() + ".toImmutableList", state)); } description.addFix( suggestBlockingElementCollection( tree, Collectors.class.getCanonicalName() + ".toList", state)); return description.build(); } private static SuggestedFix suggestBlockingElementCollection( MethodInvocationTree tree, String fullyQualifiedCollectorMethod, VisitorState state) { SuggestedFix.Builder importSuggestion = SuggestedFix.builder(); String replacementMethodInvocation = SuggestedFixes.qualifyStaticImport(fullyQualifiedCollectorMethod, importSuggestion, state); boolean isStream = ASTHelpers.isSubtype(ASTHelpers.getResultType(tree), STREAM.get(state), state); String replacement = String.format( ".collect(%s()).block()%s", replacementMethodInvocation, isStream ? ".stream()" : ""); return importSuggestion.merge(replaceMethodInvocation(tree, replacement, state)).build(); } private static SuggestedFix.Builder replaceMethodInvocation( MethodInvocationTree tree, String replacement, VisitorState state) { int startPosition = state.getEndPosition(ASTHelpers.getReceiver(tree)); int endPosition = state.getEndPosition(tree); checkState( startPosition != Position.NOPOS && endPosition != Position.NOPOS, "Cannot locate method to be replaced in source code"); return SuggestedFix.builder().replace(startPosition, endPosition, replacement); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy