mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
Introduce StreamMapTo{Double,Int,Long}Sum Refaster rules (#497)
As well as a new `IsLambdaExpressionOrMethodReference` matcher.
This commit is contained in:
@@ -10,6 +10,7 @@ import com.google.common.collect.Streams;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Matches;
|
||||
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
|
||||
import com.google.errorprone.refaster.annotation.Placeholder;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
@@ -19,10 +20,14 @@ import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.ToDoubleFunction;
|
||||
import java.util.function.ToIntFunction;
|
||||
import java.util.function.ToLongFunction;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsLambdaExpressionOrMethodReference;
|
||||
|
||||
/** Refaster rules related to expressions dealing with {@link Stream}s. */
|
||||
@OnlineDocumentation
|
||||
@@ -379,4 +384,46 @@ final class StreamRules {
|
||||
return stream.allMatch(e -> test(e));
|
||||
}
|
||||
}
|
||||
|
||||
static final class StreamMapToIntSum<T> {
|
||||
@BeforeTemplate
|
||||
int before(
|
||||
Stream<T> stream,
|
||||
@Matches(IsLambdaExpressionOrMethodReference.class) Function<? super T, Integer> mapper) {
|
||||
return stream.map(mapper).reduce(0, Integer::sum);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(Stream<T> stream, ToIntFunction<T> mapper) {
|
||||
return stream.mapToInt(mapper).sum();
|
||||
}
|
||||
}
|
||||
|
||||
static final class StreamMapToDoubleSum<T> {
|
||||
@BeforeTemplate
|
||||
double before(
|
||||
Stream<T> stream,
|
||||
@Matches(IsLambdaExpressionOrMethodReference.class) Function<? super T, Double> mapper) {
|
||||
return stream.map(mapper).reduce(0.0, Double::sum);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
double after(Stream<T> stream, ToDoubleFunction<T> mapper) {
|
||||
return stream.mapToDouble(mapper).sum();
|
||||
}
|
||||
}
|
||||
|
||||
static final class StreamMapToLongSum<T> {
|
||||
@BeforeTemplate
|
||||
long before(
|
||||
Stream<T> stream,
|
||||
@Matches(IsLambdaExpressionOrMethodReference.class) Function<? super T, Long> mapper) {
|
||||
return stream.map(mapper).reduce(0L, Long::sum);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
long after(Stream<T> stream, ToLongFunction<T> mapper) {
|
||||
return stream.mapToLong(mapper).sum();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Streams;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
@@ -138,4 +139,28 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
boolean testStreamAllMatch2() {
|
||||
return Stream.of("foo").noneMatch(s -> !s.isBlank());
|
||||
}
|
||||
|
||||
ImmutableSet<Integer> testStreamMapToIntSum() {
|
||||
Function<String, Integer> parseIntFunction = Integer::parseInt;
|
||||
return ImmutableSet.of(
|
||||
Stream.of(1).map(i -> i * 2).reduce(0, Integer::sum),
|
||||
Stream.of("2").map(Integer::parseInt).reduce(0, Integer::sum),
|
||||
Stream.of("3").map(parseIntFunction).reduce(0, Integer::sum));
|
||||
}
|
||||
|
||||
ImmutableSet<Double> testStreamMapToDoubleSum() {
|
||||
Function<String, Double> parseDoubleFunction = Double::parseDouble;
|
||||
return ImmutableSet.of(
|
||||
Stream.of(1).map(i -> i * 2.0).reduce(0.0, Double::sum),
|
||||
Stream.of("2").map(Double::parseDouble).reduce(0.0, Double::sum),
|
||||
Stream.of("3").map(parseDoubleFunction).reduce(0.0, Double::sum));
|
||||
}
|
||||
|
||||
ImmutableSet<Long> testStreamMapToLongSum() {
|
||||
Function<String, Long> parseLongFunction = Long::parseLong;
|
||||
return ImmutableSet.of(
|
||||
Stream.of(1).map(i -> i * 2L).reduce(0L, Long::sum),
|
||||
Stream.of("2").map(Long::parseLong).reduce(0L, Long::sum),
|
||||
Stream.of("3").map(parseLongFunction).reduce(0L, Long::sum));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.google.common.collect.Streams;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
@@ -137,4 +138,28 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
boolean testStreamAllMatch2() {
|
||||
return Stream.of("foo").allMatch(s -> s.isBlank());
|
||||
}
|
||||
|
||||
ImmutableSet<Integer> testStreamMapToIntSum() {
|
||||
Function<String, Integer> parseIntFunction = Integer::parseInt;
|
||||
return ImmutableSet.of(
|
||||
Stream.of(1).mapToInt(i -> i * 2).sum(),
|
||||
Stream.of("2").mapToInt(Integer::parseInt).sum(),
|
||||
Stream.of("3").map(parseIntFunction).reduce(0, Integer::sum));
|
||||
}
|
||||
|
||||
ImmutableSet<Double> testStreamMapToDoubleSum() {
|
||||
Function<String, Double> parseDoubleFunction = Double::parseDouble;
|
||||
return ImmutableSet.of(
|
||||
Stream.of(1).mapToDouble(i -> i * 2.0).sum(),
|
||||
Stream.of("2").mapToDouble(Double::parseDouble).sum(),
|
||||
Stream.of("3").map(parseDoubleFunction).reduce(0.0, Double::sum));
|
||||
}
|
||||
|
||||
ImmutableSet<Long> testStreamMapToLongSum() {
|
||||
Function<String, Long> parseLongFunction = Long::parseLong;
|
||||
return ImmutableSet.of(
|
||||
Stream.of(1).mapToLong(i -> i * 2L).sum(),
|
||||
Stream.of("2").mapToLong(Long::parseLong).sum(),
|
||||
Stream.of("3").map(parseLongFunction).reduce(0L, Long::sum));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package tech.picnic.errorprone.refaster.matchers;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.LambdaExpressionTree;
|
||||
import com.sun.source.tree.MemberReferenceTree;
|
||||
|
||||
/** A matcher of lambda expressions and method references. */
|
||||
public final class IsLambdaExpressionOrMethodReference implements Matcher<ExpressionTree> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Instantiates a new {@link IsLambdaExpressionOrMethodReference} instance. */
|
||||
public IsLambdaExpressionOrMethodReference() {}
|
||||
|
||||
@Override
|
||||
public boolean matches(ExpressionTree tree, VisitorState state) {
|
||||
return tree instanceof LambdaExpressionTree || tree instanceof MemberReferenceTree;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
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 IsLambdaExpressionOrMethodReferenceTest {
|
||||
@Test
|
||||
void matches() {
|
||||
CompilationTestHelper.newInstance(MatcherTestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.google.common.base.Predicates;",
|
||||
"import java.util.function.Function;",
|
||||
"import java.util.function.Predicate;",
|
||||
"",
|
||||
"class A {",
|
||||
" boolean negative1() {",
|
||||
" return true;",
|
||||
" }",
|
||||
"",
|
||||
" String negative2() {",
|
||||
" return new String(new byte[0]);",
|
||||
" }",
|
||||
"",
|
||||
" Predicate<String> negative3() {",
|
||||
" return Predicates.alwaysTrue();",
|
||||
" }",
|
||||
"",
|
||||
" Predicate<String> positive1() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return str -> true;",
|
||||
" }",
|
||||
"",
|
||||
" Predicate<String> positive2() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return str -> {",
|
||||
" return true;",
|
||||
" };",
|
||||
" }",
|
||||
"",
|
||||
" Predicate<String> positive3() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return String::isEmpty;",
|
||||
" }",
|
||||
"",
|
||||
" Function<byte[], String> positive4() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return String::new;",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
/** A {@link BugChecker} that simply delegates to {@link IsLambdaExpressionOrMethodReference}. */
|
||||
@BugPattern(
|
||||
summary = "Flags expressions matched by `IsLambdaExpressionOrMethodReference`",
|
||||
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 IsLambdaExpressionOrMethodReference());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user