mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 15:49:33 +00:00
Compare commits
29 Commits
ibabiankou
...
sschroever
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a698c7e6a0 | ||
|
|
b8e22ffef0 | ||
|
|
17035a1623 | ||
|
|
e7dacd19d7 | ||
|
|
e64af1dde0 | ||
|
|
a58630bccf | ||
|
|
9ab5bbe042 | ||
|
|
4ca75c6cf6 | ||
|
|
7883b31eb6 | ||
|
|
ef751ce785 | ||
|
|
130c3d0bc3 | ||
|
|
c89e3905bf | ||
|
|
21421ce753 | ||
|
|
c39d1251d2 | ||
|
|
9bc732b4fe | ||
|
|
74100b6c41 | ||
|
|
624f2ce753 | ||
|
|
967017eed9 | ||
|
|
b06945b833 | ||
|
|
ef562c1644 | ||
|
|
efbde936dc | ||
|
|
c57653dd5b | ||
|
|
12b03e95b1 | ||
|
|
c2f24ac739 | ||
|
|
4f5ea8beac | ||
|
|
21646ffcb1 | ||
|
|
c58dceb9df | ||
|
|
90ef2f4042 | ||
|
|
459a498d6c |
37
.github/workflows/build.yaml
vendored
Normal file
37
.github/workflows/build.yaml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: Build and verify
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
jdk: [ 11.0.16, 17.0.4 ]
|
||||
steps:
|
||||
# We run the build twice for each supported JDK: once against the
|
||||
# original Error Prone release, using only Error Prone checks available
|
||||
# on Maven Central, and once against the Picnic Error Prone fork,
|
||||
# additionally enabling all checks defined in this project and any
|
||||
# Error Prone checks available only from other artifact repositories.
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3.0.2
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v3.4.1
|
||||
with:
|
||||
java-version: ${{ matrix.jdk }}
|
||||
distribution: temurin
|
||||
cache: maven
|
||||
- name: Display build environment details
|
||||
run: mvn --version
|
||||
- name: Build project against vanilla Error Prone
|
||||
run: mvn -T1C install
|
||||
- name: Build project with self-check against Error Prone fork
|
||||
run: mvn -T1C clean verify -Perror-prone-fork -Pnon-maven-central -Pself-check -s settings.xml
|
||||
- name: Remove installed project artifacts
|
||||
run: mvn build-helper:remove-project-artifact
|
||||
|
||||
# XXX: Enable Codecov once we "go public".
|
||||
# XXX: Enable SonarCloud once we "go public".
|
||||
@@ -1,3 +1,6 @@
|
||||
-XX:ReservedCodeCacheSize=512m
|
||||
-XX:SoftRefLRUPolicyMSPerMB=10
|
||||
-XX:+UseParallelGC
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
|
||||
--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
|
||||
|
||||
1
.mvn/maven.config
Normal file
1
.mvn/maven.config
Normal file
@@ -0,0 +1 @@
|
||||
--batch-mode --errors --strict-checksums
|
||||
38
.travis.yml
38
.travis.yml
@@ -1,38 +0,0 @@
|
||||
---
|
||||
dist: bionic
|
||||
language: java
|
||||
jdk: openjdk11
|
||||
addons:
|
||||
sonarcloud:
|
||||
organization: picnic-technologies
|
||||
token: "${SONARCLOUD_TOKEN}"
|
||||
install:
|
||||
- mvn io.takari:maven:wrapper
|
||||
script:
|
||||
# We run the build twice: once against the original Error Prone release,
|
||||
# using only Error Prone checks available on Maven Central, and once against
|
||||
# the Picnic Error Prone fork, additionally enabling all checks defined in
|
||||
# this project and any Error Prone checks available only from other artifact
|
||||
# repositories.
|
||||
- ./mvnw clean install
|
||||
- ./mvnw clean install -Perror-prone-fork -Pnon-maven-central -Pself-check -s settings.xml
|
||||
# XXX: Enable SonarCloud once we "go public".
|
||||
# ./mvnw jacoco:prepare-agent surefire:test jacoco:report sonar:sonar
|
||||
- ./mvnw jacoco:prepare-agent surefire:test jacoco:report
|
||||
before_cache:
|
||||
# Don't cache the artifacts we just generated, for multiple reasons: (1) we
|
||||
# shouldn't need them next time around and (2) if we do, that indicates a
|
||||
# dependency issue which might otherwise go unnoticed until next time we bump
|
||||
# the project's version (i.e., when tagging).
|
||||
- find "${HOME}/.m2/repository" -depth -name '*-SNAPSHOT' -exec rm -r '{}' \;
|
||||
cache:
|
||||
directories:
|
||||
# The local Maven repository in which third party dependencies are stored.
|
||||
- ${HOME}/.m2/repository
|
||||
# The Takari Maven Wrapper's storage for downloaded Maven distributions.
|
||||
- ${HOME}/.m2/wrapper
|
||||
# The SonarQube analysis cache.
|
||||
- ${HOME}/.sonar/cache
|
||||
# XXX: Enable Codecov once we "go public".
|
||||
#after_success:
|
||||
# - bash <(curl -s https://codecov.io/bash)
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<version>0.1.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-contrib</artifactId>
|
||||
@@ -41,15 +41,13 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>refaster-compiler</artifactId>
|
||||
<!-- This dependency is declared only as a hint to Maven that
|
||||
compilation depends on it; see the `maven-compiler-plugin`'s
|
||||
`annotationProcessorPaths` configuration below. -->
|
||||
<artifactId>refaster-support</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>refaster-support</artifactId>
|
||||
<artifactId>refaster-test-support</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
@@ -145,6 +143,11 @@
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.immutables</groupId>
|
||||
<artifactId>value-annotations</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
@@ -205,15 +208,6 @@
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.spotify.fmt</groupId>
|
||||
<artifactId>fmt-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<additionalSourceDirectories>
|
||||
<additionalSourceDirectory>${basedir}/src/test/resources</additionalSourceDirectory>
|
||||
</additionalSourceDirectories>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
|
||||
@@ -25,12 +25,11 @@ import javax.lang.model.element.AnnotationValue;
|
||||
/** A {@link BugChecker} which flags ambiguous {@code @JsonCreator}s in enums. */
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "AmbiguousJsonCreator",
|
||||
summary = "`JsonCreator.Mode` should be set for single-argument creators",
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = LIKELY_ERROR)
|
||||
public final class AmbiguousJsonCreatorCheck extends BugChecker implements AnnotationTreeMatcher {
|
||||
public final class AmbiguousJsonCreator extends BugChecker implements AnnotationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<AnnotationTree> IS_JSON_CREATOR_ANNOTATION =
|
||||
isType("com.fasterxml.jackson.annotation.JsonCreator");
|
||||
@@ -30,12 +30,11 @@ import com.sun.source.tree.MethodInvocationTree;
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "AssertJIsNull",
|
||||
summary = "Prefer `.isNull()` over `.isEqualTo(null)`",
|
||||
linkType = NONE,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class AssertJIsNullCheck extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
public final class AssertJIsNull extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<MethodInvocationTree> ASSERT_IS_EQUAL_TO_NULL =
|
||||
allOf(
|
||||
@@ -27,12 +27,11 @@ import java.util.List;
|
||||
/** A {@link BugChecker} which flags redundant {@code @Autowired} constructor annotations. */
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "AutowiredConstructor",
|
||||
summary = "Omit `@Autowired` on a class' sole constructor, as it is redundant",
|
||||
linkType = NONE,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class AutowiredConstructorCheck extends BugChecker implements ClassTreeMatcher {
|
||||
public final class AutowiredConstructor extends BugChecker implements ClassTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final MultiMatcher<Tree, AnnotationTree> AUTOWIRED_ANNOTATION =
|
||||
annotations(AT_LEAST_ONE, isType("org.springframework.beans.factory.annotation.Autowired"));
|
||||
@@ -25,25 +25,24 @@ import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/** A {@link BugChecker} which flags annotations that could be written more concisely. */
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "CanonicalAnnotationSyntax",
|
||||
summary = "Omit redundant syntax from annotation declarations",
|
||||
linkType = NONE,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class CanonicalAnnotationSyntaxCheck extends BugChecker
|
||||
implements AnnotationTreeMatcher {
|
||||
public final class CanonicalAnnotationSyntax extends BugChecker implements AnnotationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Pattern TRAILING_ARRAY_COMMA = Pattern.compile(",\\s*}$");
|
||||
private static final ImmutableSet<BiFunction<AnnotationTree, VisitorState, Optional<Fix>>>
|
||||
FIX_FACTORIES =
|
||||
ImmutableSet.of(
|
||||
CanonicalAnnotationSyntaxCheck::dropRedundantParentheses,
|
||||
CanonicalAnnotationSyntaxCheck::dropRedundantValueAttribute,
|
||||
CanonicalAnnotationSyntaxCheck::dropRedundantCurlies);
|
||||
CanonicalAnnotationSyntax::dropRedundantParentheses,
|
||||
CanonicalAnnotationSyntax::dropRedundantValueAttribute,
|
||||
CanonicalAnnotationSyntax::dropRedundantCurlies);
|
||||
|
||||
@Override
|
||||
public Description matchAnnotation(AnnotationTree tree, VisitorState state) {
|
||||
@@ -103,7 +102,8 @@ public final class CanonicalAnnotationSyntaxCheck extends BugChecker
|
||||
return Optional.of(
|
||||
SuggestedFix.replace(
|
||||
arg,
|
||||
simplifyAttributeValue(expr, state).orElseGet(() -> Util.treeToString(expr, state))));
|
||||
simplifyAttributeValue(expr, state)
|
||||
.orElseGet(() -> SourceCode.treeToString(expr, state))));
|
||||
}
|
||||
|
||||
private static Optional<Fix> dropRedundantCurlies(AnnotationTree tree, VisitorState state) {
|
||||
@@ -138,11 +138,11 @@ public final class CanonicalAnnotationSyntaxCheck extends BugChecker
|
||||
private static Optional<String> simplifySingletonArray(NewArrayTree array, VisitorState state) {
|
||||
return Optional.of(array.getInitializers())
|
||||
.filter(initializers -> initializers.size() == 1)
|
||||
.map(initializers -> Util.treeToString(initializers.get(0), state));
|
||||
.map(initializers -> SourceCode.treeToString(initializers.get(0), state));
|
||||
}
|
||||
|
||||
private static Optional<String> dropTrailingComma(NewArrayTree array, VisitorState state) {
|
||||
String src = Util.treeToString(array, state);
|
||||
String src = SourceCode.treeToString(array, state);
|
||||
return Optional.of(TRAILING_ARRAY_COMMA.matcher(src))
|
||||
.filter(Matcher::find)
|
||||
.map(m -> src.substring(0, m.start()) + '}');
|
||||
@@ -27,14 +27,12 @@ import java.util.stream.Collector;
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "CollectorMutability",
|
||||
summary =
|
||||
"Avoid `Collectors.to{List,Map,Set}` in favour of alternatives that emphasize (im)mutability",
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = FRAGILE_CODE)
|
||||
public final class CollectorMutabilityCheck extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
public final class CollectorMutability extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> COLLECTOR_METHOD =
|
||||
staticMethod().onClass("java.util.stream.Collectors");
|
||||
@@ -20,18 +20,16 @@ import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import java.util.Optional;
|
||||
|
||||
/** A {@link BugChecker} which flags empty methods that seemingly can simply be deleted. */
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "EmptyMethod",
|
||||
summary = "Empty method can likely be deleted",
|
||||
linkType = NONE,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class EmptyMethodCheck extends BugChecker implements MethodTreeMatcher {
|
||||
public final class EmptyMethod extends BugChecker implements MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<Tree> PERMITTED_ANNOTATION =
|
||||
annotations(
|
||||
@@ -48,8 +46,7 @@ public final class EmptyMethodCheck extends BugChecker implements MethodTreeMatc
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
MethodSymbol sym = ASTHelpers.getSymbol(tree);
|
||||
if (sym == null || ASTHelpers.methodCanBeOverridden(sym)) {
|
||||
if (ASTHelpers.methodCanBeOverridden(ASTHelpers.getSymbol(tree))) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
@@ -49,12 +49,11 @@ import java.util.Optional;
|
||||
// Windows; TBD.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "ErrorProneTestHelperSourceFormat",
|
||||
summary = "Test code should follow the Google Java style",
|
||||
linkType = NONE,
|
||||
severity = SUGGESTION,
|
||||
tags = STYLE)
|
||||
public final class ErrorProneTestHelperSourceFormatCheck extends BugChecker
|
||||
public final class ErrorProneTestHelperSourceFormat extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Formatter FORMATTER = new Formatter();
|
||||
@@ -35,13 +35,11 @@ import java.util.stream.Stream;
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "ExplicitEnumOrdering",
|
||||
summary = "Make sure `Ordering#explicit` lists all of an enum's values",
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = FRAGILE_CODE)
|
||||
public final class ExplicitEnumOrderingCheck extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
public final class ExplicitEnumOrdering extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> EXPLICIT_ORDERING =
|
||||
staticMethod().onClass(Ordering.class.getName()).named("explicit");
|
||||
@@ -73,7 +71,7 @@ public final class ExplicitEnumOrderingCheck extends BugChecker
|
||||
.collect(
|
||||
collectingAndThen(
|
||||
toImmutableSetMultimap(Symbol::asType, Symbol::toString),
|
||||
ExplicitEnumOrderingCheck::getMissingEnumValues));
|
||||
ExplicitEnumOrdering::getMissingEnumValues));
|
||||
}
|
||||
|
||||
private static ImmutableSet<String> getMissingEnumValues(
|
||||
@@ -40,14 +40,13 @@ import reactor.core.publisher.Flux;
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "FluxFlatMapUsage",
|
||||
summary =
|
||||
"`Flux#flatMap` and `Flux#flatMapSequential` have subtle semantics; "
|
||||
+ "please use `Flux#concatMap` or explicitly specify the desired amount of concurrency",
|
||||
linkType = NONE,
|
||||
severity = ERROR,
|
||||
tags = LIKELY_ERROR)
|
||||
public final class FluxFlatMapUsageCheck extends BugChecker
|
||||
public final class FluxFlatMapUsage extends BugChecker
|
||||
implements MethodInvocationTreeMatcher, MemberReferenceTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String MAX_CONCURRENCY_ARG_NAME = "MAX_CONCURRENCY";
|
||||
@@ -32,6 +32,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} which flags string concatenations that produce a format string; in such
|
||||
@@ -49,12 +50,11 @@ import javax.annotation.Nullable;
|
||||
// invocations, as necessary.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "FormatStringConcatenation",
|
||||
summary = "Defer string concatenation to the invoked method",
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class FormatStringConcatenationCheck extends BugChecker
|
||||
public final class FormatStringConcatenation extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
@@ -250,7 +250,7 @@ public final class FormatStringConcatenationCheck extends BugChecker
|
||||
return state.getConstantExpression(formatString.toString())
|
||||
+ ", "
|
||||
+ formatArguments.stream()
|
||||
.map(tree -> Util.treeToString(tree, state))
|
||||
.map(tree -> SourceCode.treeToString(tree, state))
|
||||
.collect(joining(", "));
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/** A {@link BugChecker} that flags redundant identity conversions. */
|
||||
// XXX: Consider detecting cases where a flagged expression is passed to a method, and where removal
|
||||
@@ -34,13 +35,11 @@ import java.util.List;
|
||||
// the target method such a modification may change the code's semantics or performance.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "IdentityConversion",
|
||||
summary = "Avoid or clarify identity conversions",
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class IdentityConversionCheck extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
public final class IdentityConversion extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> IS_CONVERSION_METHOD =
|
||||
anyOf(
|
||||
@@ -95,7 +94,7 @@ public final class IdentityConversionCheck extends BugChecker
|
||||
.setMessage(
|
||||
"This method invocation appears redundant; remove it or suppress this warning and "
|
||||
+ "add a comment explaining its purpose")
|
||||
.addFix(SuggestedFix.replace(tree, Util.treeToString(sourceTree, state)))
|
||||
.addFix(SuggestedFix.replace(tree, SourceCode.treeToString(sourceTree, state)))
|
||||
.addFix(SuggestedFixes.addSuppressWarnings(state, canonicalName()))
|
||||
.build();
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.NONE;
|
||||
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.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.enclosingClass;
|
||||
import static com.google.errorprone.matchers.Matchers.hasAnnotation;
|
||||
import static com.google.errorprone.matchers.Matchers.hasModifier;
|
||||
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
|
||||
import static com.google.errorprone.matchers.Matchers.methodReturns;
|
||||
import static com.google.errorprone.matchers.Matchers.not;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
|
||||
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.sun.source.tree.MethodTree;
|
||||
import java.util.SortedSet;
|
||||
import javax.lang.model.element.Modifier;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} which flags {@link SortedSet} property declarations inside
|
||||
* {@code @Value.Immutable}- and {@code @Value.Modifiable}-annotated types that lack a
|
||||
* {@code @Value.NaturalOrder} or {@code @Value.ReverseOrder} annotation.
|
||||
*
|
||||
* <p>Without such an annotation:
|
||||
*
|
||||
* <ul>
|
||||
* <li>deserialization of the enclosing type requires that the associated JSON property is
|
||||
* present, contrary to the way in which Immutables handles other collection properties; and
|
||||
* <li>different instances may use different comparator implementations (e.g. deserialization
|
||||
* would default to natural order sorting), potentially leading to subtle bugs.
|
||||
* </ul>
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary =
|
||||
"`SortedSet` properties of a `@Value.Immutable` or `@Value.Modifiable` type must be "
|
||||
+ "annotated with `@Value.NaturalOrder` or `@Value.ReverseOrder`",
|
||||
linkType = NONE,
|
||||
severity = ERROR,
|
||||
tags = LIKELY_ERROR)
|
||||
public final class ImmutablesSortedSetComparator extends BugChecker implements MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<MethodTree> METHOD_LACKS_ANNOTATION =
|
||||
allOf(
|
||||
methodReturns(isSubtypeOf(SortedSet.class)),
|
||||
anyOf(
|
||||
allOf(
|
||||
hasModifier(Modifier.ABSTRACT),
|
||||
enclosingClass(
|
||||
anyOf(
|
||||
hasAnnotation("org.immutables.value.Value.Immutable"),
|
||||
hasAnnotation("org.immutables.value.Value.Modifiable")))),
|
||||
hasAnnotation("org.immutables.value.Value.Default")),
|
||||
not(
|
||||
anyOf(
|
||||
hasAnnotation("org.immutables.value.Value.NaturalOrder"),
|
||||
hasAnnotation("org.immutables.value.Value.ReverseOrder"))));
|
||||
|
||||
@Override
|
||||
public Description matchMethod(MethodTree tree, VisitorState state) {
|
||||
if (!METHOD_LACKS_ANNOTATION.matches(tree, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
SuggestedFix.Builder builder = SuggestedFix.builder();
|
||||
String valueTypeIdentifier =
|
||||
SuggestedFixes.qualifyType(state, builder, "org.immutables.value.Value");
|
||||
return describeMatch(
|
||||
tree,
|
||||
builder.prefixWith(tree, String.format("@%s.NaturalOrder ", valueTypeIdentifier)).build());
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import static com.google.errorprone.matchers.Matchers.enclosingClass;
|
||||
import static com.google.errorprone.matchers.Matchers.hasModifier;
|
||||
import static com.google.errorprone.matchers.Matchers.isType;
|
||||
import static java.util.function.Predicate.not;
|
||||
import static tech.picnic.errorprone.bugpatterns.JavaKeywords.isReservedKeyword;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.JavaKeywords.isReservedKeyword;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -36,6 +36,7 @@ import com.sun.tools.javac.code.Symbol;
|
||||
import java.util.Optional;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.Name;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/** A {@link BugChecker} which flags non-canonical JUnit method declarations. */
|
||||
// XXX: Consider introducing a class-level check which enforces that test classes:
|
||||
@@ -45,12 +46,11 @@ import javax.lang.model.element.Name;
|
||||
// XXX: If implemented, the current logic could flag only `private` JUnit methods.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "JUnitMethodDeclaration",
|
||||
summary = "JUnit method declaration can likely be improved",
|
||||
linkType = NONE,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class JUnitMethodDeclarationCheck extends BugChecker implements MethodTreeMatcher {
|
||||
public final class JUnitMethodDeclaration extends BugChecker implements MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String TEST_PREFIX = "test";
|
||||
private static final ImmutableSet<Modifier> ILLEGAL_MODIFIERS =
|
||||
@@ -171,13 +171,12 @@ public final class JUnitMethodDeclarationCheck extends BugChecker implements Met
|
||||
}
|
||||
|
||||
private static CharSequence getStaticImportSimpleName(Tree tree, VisitorState state) {
|
||||
String source = Util.treeToString(tree, state);
|
||||
String source = SourceCode.treeToString(tree, state);
|
||||
return source.subSequence(source.lastIndexOf('.') + 1, source.length());
|
||||
}
|
||||
|
||||
private static Optional<String> tryCanonicalizeMethodName(MethodTree tree) {
|
||||
return Optional.ofNullable(ASTHelpers.getSymbol(tree))
|
||||
.map(sym -> sym.getQualifiedName().toString())
|
||||
return Optional.of(ASTHelpers.getSymbol(tree).getQualifiedName().toString())
|
||||
.filter(name -> name.startsWith(TEST_PREFIX))
|
||||
.map(name -> name.substring(TEST_PREFIX.length()))
|
||||
.filter(not(String::isEmpty))
|
||||
@@ -38,6 +38,8 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import javax.annotation.Nullable;
|
||||
import tech.picnic.errorprone.bugpatterns.util.AnnotationAttributeMatcher;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} which flags annotation array listings which aren't sorted lexicographically.
|
||||
@@ -47,12 +49,11 @@ import javax.annotation.Nullable;
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "LexicographicalAnnotationAttributeListing",
|
||||
summary = "Where possible, sort annotation array attributes lexicographically",
|
||||
linkType = NONE,
|
||||
severity = SUGGESTION,
|
||||
tags = STYLE)
|
||||
public final class LexicographicalAnnotationAttributeListingCheck extends BugChecker
|
||||
public final class LexicographicalAnnotationAttributeListing extends BugChecker
|
||||
implements AnnotationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final ImmutableSet<String> BLACKLISTED_ANNOTATIONS =
|
||||
@@ -61,24 +62,27 @@ public final class LexicographicalAnnotationAttributeListingCheck extends BugChe
|
||||
"com.fasterxml.jackson.annotation.JsonPropertyOrder#value",
|
||||
"io.swagger.annotations.ApiImplicitParams#value",
|
||||
"io.swagger.v3.oas.annotations.Parameters#value",
|
||||
"javax.xml.bind.annotation.XmlType#propOrder");
|
||||
"javax.xml.bind.annotation.XmlType#propOrder",
|
||||
"org.springframework.context.annotation.PropertySource#value",
|
||||
"org.springframework.test.context.TestPropertySource#locations",
|
||||
"org.springframework.test.context.TestPropertySource#value");
|
||||
private static final String FLAG_PREFIX = "LexicographicalAnnotationAttributeListing:";
|
||||
private static final String INCLUDED_ANNOTATIONS_FLAG = FLAG_PREFIX + "Includes";
|
||||
private static final String EXCLUDED_ANNOTATIONS_FLAG = FLAG_PREFIX + "Excludes";
|
||||
|
||||
private final AnnotationAttributeMatcher matcher;
|
||||
|
||||
/** Instantiates the default {@link LexicographicalAnnotationAttributeListingCheck}. */
|
||||
public LexicographicalAnnotationAttributeListingCheck() {
|
||||
/** Instantiates the default {@link LexicographicalAnnotationAttributeListing}. */
|
||||
public LexicographicalAnnotationAttributeListing() {
|
||||
this(ErrorProneFlags.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a customized {@link LexicographicalAnnotationAttributeListingCheck}.
|
||||
* Instantiates a customized {@link LexicographicalAnnotationAttributeListing}.
|
||||
*
|
||||
* @param flags Any provided command line flags.
|
||||
*/
|
||||
public LexicographicalAnnotationAttributeListingCheck(ErrorProneFlags flags) {
|
||||
public LexicographicalAnnotationAttributeListing(ErrorProneFlags flags) {
|
||||
matcher = createAnnotationAttributeMatcher(flags);
|
||||
}
|
||||
|
||||
@@ -129,7 +133,7 @@ public final class LexicographicalAnnotationAttributeListingCheck extends BugChe
|
||||
/* The elements aren't sorted. Suggest the sorted alternative. */
|
||||
String suggestion =
|
||||
desiredOrdering.stream()
|
||||
.map(expr -> Util.treeToString(expr, state))
|
||||
.map(expr -> SourceCode.treeToString(expr, state))
|
||||
.collect(joining(", ", "{", "}"));
|
||||
return Optional.of(SuggestedFix.builder().replace(array, suggestion));
|
||||
}
|
||||
@@ -174,21 +178,21 @@ public final class LexicographicalAnnotationAttributeListingCheck extends BugChe
|
||||
new TreeScanner<Void, Void>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Void visitIdentifier(IdentifierTree node, Void ctx) {
|
||||
public Void visitIdentifier(IdentifierTree node, @Nullable Void ctx) {
|
||||
nodes.add(tokenize(node));
|
||||
return super.visitIdentifier(node, ctx);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Void visitLiteral(LiteralTree node, Void ctx) {
|
||||
public Void visitLiteral(LiteralTree node, @Nullable Void ctx) {
|
||||
nodes.add(tokenize(node));
|
||||
return super.visitLiteral(node, ctx);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Void visitPrimitiveType(PrimitiveTypeTree node, Void ctx) {
|
||||
public Void visitPrimitiveType(PrimitiveTypeTree node, @Nullable Void ctx) {
|
||||
nodes.add(tokenize(node));
|
||||
return super.visitPrimitiveType(node, ctx);
|
||||
}
|
||||
@@ -198,7 +202,7 @@ public final class LexicographicalAnnotationAttributeListingCheck extends BugChe
|
||||
* Tokens are split on `=` so that e.g. inline Spring property declarations are properly
|
||||
* sorted by key, then value.
|
||||
*/
|
||||
return ImmutableList.copyOf(Util.treeToString(node, state).split("=", -1));
|
||||
return ImmutableList.copyOf(SourceCode.treeToString(node, state).split("=", -1));
|
||||
}
|
||||
}.scan(array, null);
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags annotations that are not lexicographically sorted.
|
||||
@@ -29,12 +30,11 @@ import java.util.Optional;
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "LexicographicalAnnotationListing",
|
||||
summary = "Sort annotations lexicographically where possible",
|
||||
linkType = NONE,
|
||||
severity = SUGGESTION,
|
||||
tags = STYLE)
|
||||
public final class LexicographicalAnnotationListingCheck extends BugChecker
|
||||
public final class LexicographicalAnnotationListing extends BugChecker
|
||||
implements MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -60,7 +60,7 @@ public final class LexicographicalAnnotationListingCheck extends BugChecker
|
||||
private static ImmutableList<? extends AnnotationTree> sort(
|
||||
List<? extends AnnotationTree> annotations, VisitorState state) {
|
||||
return annotations.stream()
|
||||
.sorted(comparing(annotation -> Util.treeToString(annotation, state)))
|
||||
.sorted(comparing(annotation -> SourceCode.treeToString(annotation, state)))
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
@@ -72,7 +72,8 @@ public final class LexicographicalAnnotationListingCheck extends BugChecker
|
||||
originalAnnotations.stream(),
|
||||
sortedAnnotations.stream(),
|
||||
(original, replacement) ->
|
||||
SuggestedFix.builder().replace(original, Util.treeToString(replacement, state)))
|
||||
SuggestedFix.builder()
|
||||
.replace(original, SourceCode.treeToString(replacement, state)))
|
||||
.reduce(SuggestedFix.Builder::merge)
|
||||
.map(SuggestedFix.Builder::build);
|
||||
}
|
||||
@@ -51,13 +51,11 @@ import javax.lang.model.element.Name;
|
||||
// Palantir's `LambdaMethodReference` check seems to suffer a similar issue at this time.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "MethodReferenceUsage",
|
||||
summary = "Prefer method references over lambda expressions",
|
||||
linkType = NONE,
|
||||
severity = SUGGESTION,
|
||||
tags = STYLE)
|
||||
public final class MethodReferenceUsageCheck extends BugChecker
|
||||
implements LambdaExpressionTreeMatcher {
|
||||
public final class MethodReferenceUsage extends BugChecker implements LambdaExpressionTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
@@ -102,6 +100,8 @@ public final class MethodReferenceUsageCheck extends BugChecker
|
||||
.flatMap(statements -> constructMethodRef(lambdaExpr, statements.get(0)));
|
||||
}
|
||||
|
||||
// XXX: Replace nested `Optional` usage.
|
||||
@SuppressWarnings("NestedOptionals")
|
||||
private static Optional<SuggestedFix.Builder> constructMethodRef(
|
||||
LambdaExpressionTree lambdaExpr, MethodInvocationTree subTree) {
|
||||
return matchArguments(lambdaExpr, subTree)
|
||||
@@ -158,6 +158,8 @@ public final class MethodReferenceUsageCheck extends BugChecker
|
||||
return constructFix(lambdaExpr, lhsType.tsym, subTree.getIdentifier());
|
||||
}
|
||||
|
||||
// XXX: Refactor or replace inner `Optional` with a custom type.
|
||||
@SuppressWarnings("NestedOptionals")
|
||||
private static Optional<Optional<Name>> matchArguments(
|
||||
LambdaExpressionTree lambdaExpr, MethodInvocationTree subTree) {
|
||||
ImmutableList<Name> expectedArguments = getVariables(lambdaExpr);
|
||||
@@ -24,12 +24,11 @@ import com.sun.source.tree.Tree;
|
||||
/** A {@link BugChecker} that flags likely missing Refaster annotations. */
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "MissingRefasterAnnotation",
|
||||
summary = "The Refaster template contains a method without any Refaster annotations",
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = LIKELY_ERROR)
|
||||
public final class MissingRefasterAnnotationCheck extends BugChecker implements ClassTreeMatcher {
|
||||
public final class MissingRefasterAnnotation extends BugChecker implements ClassTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final MultiMatcher<Tree, AnnotationTree> REFASTER_ANNOTATION =
|
||||
annotations(
|
||||
@@ -17,6 +17,7 @@ import com.google.errorprone.matchers.Matcher;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import java.util.List;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} which flags method invocations for which all arguments are wrapped using
|
||||
@@ -24,12 +25,11 @@ import java.util.List;
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "MockitoStubbing",
|
||||
summary = "Don't unnecessarily use Mockito's `eq(...)`",
|
||||
linkType = NONE,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class MockitoStubbingCheck extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
public final class MockitoStubbing extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> MOCKITO_EQ_METHOD =
|
||||
staticMethod().onClass("org.mockito.ArgumentMatchers").named("eq");
|
||||
@@ -45,7 +45,7 @@ public final class MockitoStubbingCheck extends BugChecker implements MethodInvo
|
||||
for (ExpressionTree arg : arguments) {
|
||||
suggestedFix.replace(
|
||||
arg,
|
||||
Util.treeToString(
|
||||
SourceCode.treeToString(
|
||||
Iterables.getOnlyElement(((MethodInvocationTree) arg).getArguments()), state));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.NONE;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.FRAGILE_CODE;
|
||||
|
||||
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;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.suppliers.Supplier;
|
||||
import com.google.errorprone.suppliers.Suppliers;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/** A {@link BugChecker} which flags nesting of {@link Optional Optionals}. */
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary =
|
||||
"Avoid nesting `Optional`s inside `Optional`s; the resultant code is hard to reason about",
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = FRAGILE_CODE)
|
||||
public final class NestedOptionals extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Supplier<Type> OPTIONAL = Suppliers.typeFromClass(Optional.class);
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
return isOptionalOfOptional(tree, state) ? describeMatch(tree) : Description.NO_MATCH;
|
||||
}
|
||||
|
||||
private static boolean isOptionalOfOptional(Tree tree, VisitorState state) {
|
||||
Type optionalType = OPTIONAL.get(state);
|
||||
Type type = ASTHelpers.getType(tree);
|
||||
if (!ASTHelpers.isSubtype(type, optionalType, state)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Type> typeArguments = type.getTypeArguments();
|
||||
return !typeArguments.isEmpty()
|
||||
&& ASTHelpers.isSubtype(Iterables.getOnlyElement(typeArguments), optionalType, state);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.NONE;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
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.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import java.util.function.BiFunction;
|
||||
import reactor.core.publisher.Mono;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} which flags {@link Mono} operations that are known to be vacuous, given that
|
||||
* they are invoked on a {@link Mono} that is known not to complete empty.
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Avoid vacuous operations on known non-empty `Mono`s",
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = SIMPLIFICATION)
|
||||
// XXX: This check does not simplify `someFlux.defaultIfEmpty(T).{defaultIfEmpty(T),hasElements()}`,
|
||||
// as `someFlux.defaultIfEmpty(T)` yields a `Flux` rather than a `Mono`. Consider adding support for
|
||||
// these cases.
|
||||
// XXX: Given more advanced analysis many more expressions could be flagged. Consider
|
||||
// `Mono.just(someValue)`, `Flux.just(someNonEmptySequence)`,
|
||||
// `someMono.switchIfEmpty(someProvablyNonEmptyMono)` and many other variants.
|
||||
// XXX: Consider implementing a similar check for `Publisher`s that are known to complete without
|
||||
// emitting a value (e.g. `Mono.empty()`, `someFlux.then()`, ...), or known not to complete normally
|
||||
// (`Mono.never()`, `someFlux.repeat()`, `Mono.error(...)`, ...). The latter category could
|
||||
// potentially be split out further.
|
||||
public final class NonEmptyMono extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> MONO_SIZE_CHECK =
|
||||
instanceMethod()
|
||||
.onDescendantOf("reactor.core.publisher.Mono")
|
||||
.namedAnyOf("defaultIfEmpty", "single", "switchIfEmpty");
|
||||
private static final Matcher<ExpressionTree> NON_EMPTY_MONO =
|
||||
anyOf(
|
||||
instanceMethod()
|
||||
.onDescendantOf("reactor.core.publisher.Flux")
|
||||
.namedAnyOf(
|
||||
"all",
|
||||
"any",
|
||||
"collect",
|
||||
"collectList",
|
||||
"collectMap",
|
||||
"collectMultimap",
|
||||
"collectSortedList",
|
||||
"count",
|
||||
"elementAt",
|
||||
"hasElement",
|
||||
"hasElements",
|
||||
"last",
|
||||
"reduceWith",
|
||||
"single"),
|
||||
instanceMethod()
|
||||
.onDescendantOf("reactor.core.publisher.Flux")
|
||||
.named("reduce")
|
||||
.withParameters(Object.class.getName(), BiFunction.class.getName()),
|
||||
instanceMethod()
|
||||
.onDescendantOf("reactor.core.publisher.Mono")
|
||||
.namedAnyOf("defaultIfEmpty", "hasElement", "single"));
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
if (!MONO_SIZE_CHECK.matches(tree, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
|
||||
if (!NON_EMPTY_MONO.matches(receiver, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
return describeMatch(
|
||||
tree, SuggestedFix.replace(tree, SourceCode.treeToString(receiver, state)));
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import static com.google.errorprone.BugPattern.StandardTags.PERFORMANCE;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
|
||||
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
|
||||
import static java.util.function.Predicate.not;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
@@ -32,6 +31,7 @@ import java.util.Comparator;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} which flags {@code Comparator#comparing*} invocations that can be replaced
|
||||
@@ -41,15 +41,13 @@ import java.util.stream.Stream;
|
||||
// specific types.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "PrimitiveComparison",
|
||||
summary =
|
||||
"Ensure invocations of `Comparator#comparing{,Double,Int,Long}` match the return type"
|
||||
+ " of the provided function",
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = PERFORMANCE)
|
||||
public final class PrimitiveComparisonCheck extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
public final class PrimitiveComparison extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> STATIC_COMPARISON_METHOD =
|
||||
anyOf(
|
||||
@@ -85,16 +83,15 @@ public final class PrimitiveComparisonCheck extends BugChecker
|
||||
|
||||
private static Optional<Fix> attemptMethodInvocationReplacement(
|
||||
MethodInvocationTree tree, Type cmpType, boolean isStatic, VisitorState state) {
|
||||
return Optional.ofNullable(ASTHelpers.getSymbol(tree))
|
||||
.map(methodSymbol -> methodSymbol.getSimpleName().toString())
|
||||
.flatMap(
|
||||
actualMethodName ->
|
||||
Optional.of(getPreferredMethod(cmpType, isStatic, state))
|
||||
.filter(not(actualMethodName::equals)))
|
||||
.map(
|
||||
preferredMethodName ->
|
||||
prefixTypeArgumentsIfRelevant(preferredMethodName, tree, cmpType, state))
|
||||
.map(preferredMethodName -> suggestFix(tree, preferredMethodName, state));
|
||||
String actualMethodName = ASTHelpers.getSymbol(tree).getSimpleName().toString();
|
||||
String preferredMethodName = getPreferredMethod(cmpType, isStatic, state);
|
||||
if (actualMethodName.equals(preferredMethodName)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(
|
||||
suggestFix(
|
||||
tree, prefixTypeArgumentsIfRelevant(preferredMethodName, tree, cmpType, state), state));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,7 +113,7 @@ public final class PrimitiveComparisonCheck extends BugChecker
|
||||
|
||||
String typeArguments =
|
||||
Stream.concat(
|
||||
Stream.of(Util.treeToString(tree.getTypeArguments().get(0), state)),
|
||||
Stream.of(SourceCode.treeToString(tree.getTypeArguments().get(0), state)),
|
||||
Stream.of(cmpType.tsym.getSimpleName())
|
||||
.filter(u -> "comparing".equals(preferredMethodName)))
|
||||
.collect(joining(", ", "<", ">"));
|
||||
@@ -171,7 +168,7 @@ public final class PrimitiveComparisonCheck extends BugChecker
|
||||
case MEMBER_SELECT:
|
||||
MemberSelectTree ms = (MemberSelectTree) tree.getMethodSelect();
|
||||
return SuggestedFix.replace(
|
||||
ms, Util.treeToString(ms.getExpression(), state) + '.' + preferredMethodName);
|
||||
ms, SourceCode.treeToString(ms.getExpression(), state) + '.' + preferredMethodName);
|
||||
default:
|
||||
throw new VerifyException("Unexpected type of expression: " + expr.getKind());
|
||||
}
|
||||
@@ -41,16 +41,17 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import tech.picnic.errorprone.bugpatterns.util.MethodMatcherFactory;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/** A {@link BugChecker} which flags redundant explicit string conversions. */
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "RedundantStringConversion",
|
||||
summary = "Avoid redundant string conversions when possible",
|
||||
linkType = NONE,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class RedundantStringConversionCheck extends BugChecker
|
||||
public final class RedundantStringConversion extends BugChecker
|
||||
implements BinaryTreeMatcher, CompoundAssignmentTreeMatcher, MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String FLAG_PREFIX = "RedundantStringConversion:";
|
||||
@@ -157,17 +158,17 @@ public final class RedundantStringConversionCheck extends BugChecker
|
||||
|
||||
private final Matcher<ExpressionTree> conversionMethodMatcher;
|
||||
|
||||
/** Instantiates the default {@link RedundantStringConversionCheck}. */
|
||||
public RedundantStringConversionCheck() {
|
||||
/** Instantiates the default {@link RedundantStringConversion}. */
|
||||
public RedundantStringConversion() {
|
||||
this(ErrorProneFlags.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a customized {@link RedundantStringConversionCheck}.
|
||||
* Instantiates a customized {@link RedundantStringConversion}.
|
||||
*
|
||||
* @param flags Any provided command line flags.
|
||||
*/
|
||||
public RedundantStringConversionCheck(ErrorProneFlags flags) {
|
||||
public RedundantStringConversion(ErrorProneFlags flags) {
|
||||
conversionMethodMatcher = createConversionMethodMatcher(flags);
|
||||
}
|
||||
|
||||
@@ -326,7 +327,7 @@ public final class RedundantStringConversionCheck extends BugChecker
|
||||
return trySimplify(tree, state, filter)
|
||||
.map(
|
||||
replacement ->
|
||||
SuggestedFix.builder().replace(tree, Util.treeToString(replacement, state)));
|
||||
SuggestedFix.builder().replace(tree, SourceCode.treeToString(replacement, state)));
|
||||
}
|
||||
|
||||
private Optional<ExpressionTree> trySimplify(
|
||||
@@ -350,7 +351,7 @@ public final class RedundantStringConversionCheck extends BugChecker
|
||||
default:
|
||||
throw new IllegalStateException(
|
||||
"Cannot simplify method call with two or more arguments: "
|
||||
+ Util.treeToString(tree, state));
|
||||
+ SourceCode.treeToString(tree, state));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,7 +364,7 @@ public final class RedundantStringConversionCheck extends BugChecker
|
||||
return Optional.of(methodInvocation.getMethodSelect())
|
||||
.filter(methodSelect -> methodSelect.getKind() == Kind.MEMBER_SELECT)
|
||||
.map(methodSelect -> ((MemberSelectTree) methodSelect).getExpression())
|
||||
.filter(expr -> !"super".equals(Util.treeToString(expr, state)));
|
||||
.filter(expr -> !"super".equals(SourceCode.treeToString(expr, state)));
|
||||
}
|
||||
|
||||
private static Optional<ExpressionTree> trySimplifyUnaryMethod(
|
||||
@@ -16,6 +16,7 @@ import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} which flags unnecessary {@link Refaster#anyOf(Object[])} usages.
|
||||
@@ -25,13 +26,11 @@ import com.sun.source.tree.MethodInvocationTree;
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "RefasterAnyOfUsage",
|
||||
summary = "`Refaster#anyOf` should be passed at least two parameters",
|
||||
linkType = NONE,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class RefasterAnyOfUsageCheck extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
public final class RefasterAnyOfUsage extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> REFASTER_ANY_OF =
|
||||
staticMethod().onClass(Refaster.class.getName()).named("anyOf");
|
||||
@@ -46,7 +45,8 @@ public final class RefasterAnyOfUsageCheck extends BugChecker
|
||||
case 1:
|
||||
return describeMatch(
|
||||
tree,
|
||||
SuggestedFix.replace(tree, Util.treeToString(tree.getArguments().get(0), state)));
|
||||
SuggestedFix.replace(
|
||||
tree, SourceCode.treeToString(tree.getArguments().get(0), state)));
|
||||
default:
|
||||
/* Handled below. */
|
||||
}
|
||||
@@ -30,12 +30,11 @@ import com.sun.source.tree.Tree;
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "RequestMappingAnnotation",
|
||||
summary = "Make sure all `@RequestMapping` method parameters are annotated",
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = LIKELY_ERROR)
|
||||
public final class RequestMappingAnnotationCheck extends BugChecker implements MethodTreeMatcher {
|
||||
public final class RequestMappingAnnotation extends BugChecker implements MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String ANN_PACKAGE_PREFIX = "org.springframework.web.bind.annotation.";
|
||||
// XXX: Generalize this logic to fully support Spring meta-annotations, then update the class
|
||||
@@ -64,6 +63,7 @@ public final class RequestMappingAnnotationCheck extends BugChecker implements M
|
||||
AT_LEAST_ONE,
|
||||
anyOf(
|
||||
isType(ANN_PACKAGE_PREFIX + "PathVariable"),
|
||||
isType(ANN_PACKAGE_PREFIX + "RequestAttribute"),
|
||||
isType(ANN_PACKAGE_PREFIX + "RequestBody"),
|
||||
isType(ANN_PACKAGE_PREFIX + "RequestHeader"),
|
||||
isType(ANN_PACKAGE_PREFIX + "RequestParam"))),
|
||||
@@ -24,12 +24,11 @@ import com.sun.source.tree.VariableTree;
|
||||
/** A {@link BugChecker} which flags {@code @RequestParam} parameters with an unsupported type. */
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "RequestParamType",
|
||||
summary = "`@RequestParam` does not support `ImmutableCollection` and `ImmutableMap` subtypes",
|
||||
linkType = NONE,
|
||||
severity = ERROR,
|
||||
tags = LIKELY_ERROR)
|
||||
public final class RequestParamTypeCheck extends BugChecker implements VariableTreeMatcher {
|
||||
public final class RequestParamType extends BugChecker implements VariableTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<VariableTree> HAS_UNSUPPORTED_REQUEST_PARAM =
|
||||
allOf(
|
||||
@@ -32,12 +32,11 @@ import com.sun.source.tree.Tree;
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "ScheduledTransactionTrace",
|
||||
summary = "Scheduled operation must start a new New Relic transaction",
|
||||
linkType = NONE,
|
||||
severity = ERROR,
|
||||
tags = LIKELY_ERROR)
|
||||
public final class ScheduledTransactionTraceCheck extends BugChecker implements MethodTreeMatcher {
|
||||
public final class ScheduledTransactionTrace extends BugChecker implements MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String TRACE_ANNOTATION_FQCN = "com.newrelic.api.agent.Trace";
|
||||
private static final Matcher<Tree> IS_SCHEDULED =
|
||||
@@ -22,6 +22,7 @@ import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.Tree.Kind;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/** A {@link BugChecker} which flags SLF4J usages that are likely to be in error. */
|
||||
// XXX: The special-casing of Throwable applies only to SLF4J 1.6.0+; see
|
||||
@@ -31,13 +32,11 @@ import java.util.Optional;
|
||||
// preconditions, ...
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "Slf4jLogStatement",
|
||||
summary = "Make sure SLF4J log statements contain proper placeholders with matching arguments",
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = LIKELY_ERROR)
|
||||
public final class Slf4jLogStatementCheck extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
public final class Slf4jLogStatement extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> MARKER = isSubtypeOf("org.slf4j.Marker");
|
||||
private static final Matcher<ExpressionTree> THROWABLE = isSubtypeOf(Throwable.class);
|
||||
@@ -114,7 +113,7 @@ public final class Slf4jLogStatementCheck extends BugChecker
|
||||
* replaced at this usage site.
|
||||
*/
|
||||
description.addFix(
|
||||
SuggestedFix.replace(tree, Util.treeToString(tree, state).replace("%s", "{}")));
|
||||
SuggestedFix.replace(tree, SourceCode.treeToString(tree, state).replace("%s", "{}")));
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -25,6 +25,8 @@ import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.NewArrayTree;
|
||||
import com.sun.source.tree.Tree.Kind;
|
||||
import java.util.Optional;
|
||||
import tech.picnic.errorprone.bugpatterns.util.AnnotationAttributeMatcher;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} which flags {@code @RequestMapping} annotations that can be written more
|
||||
@@ -32,13 +34,12 @@ import java.util.Optional;
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "SpringMvcAnnotation",
|
||||
summary =
|
||||
"Prefer the conciseness of `@{Get,Put,Post,Delete,Patch}Mapping` over `@RequestMapping`",
|
||||
linkType = NONE,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class SpringMvcAnnotationCheck extends BugChecker implements AnnotationTreeMatcher {
|
||||
public final class SpringMvcAnnotation extends BugChecker implements AnnotationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String ANN_PACKAGE_PREFIX = "org.springframework.web.bind.annotation.";
|
||||
private static final AnnotationAttributeMatcher ARGUMENT_SELECTOR =
|
||||
@@ -92,7 +93,7 @@ public final class SpringMvcAnnotationCheck extends BugChecker implements Annota
|
||||
private static String extractMethod(ExpressionTree expr, VisitorState state) {
|
||||
switch (expr.getKind()) {
|
||||
case IDENTIFIER:
|
||||
return Util.treeToString(expr, state);
|
||||
return SourceCode.treeToString(expr, state);
|
||||
case MEMBER_SELECT:
|
||||
return ((MemberSelectTree) expr).getIdentifier().toString();
|
||||
default:
|
||||
@@ -105,7 +106,7 @@ public final class SpringMvcAnnotationCheck extends BugChecker implements Annota
|
||||
String newArguments =
|
||||
tree.getArguments().stream()
|
||||
.filter(not(argToRemove::equals))
|
||||
.map(arg -> Util.treeToString(arg, state))
|
||||
.map(arg -> SourceCode.treeToString(arg, state))
|
||||
.collect(joining(", "));
|
||||
|
||||
return SuggestedFix.builder()
|
||||
@@ -45,12 +45,11 @@ import java.util.Optional;
|
||||
// - Likely any of `*.{ZERO, ONE, MIX, MAX, MIN_VALUE, MAX_VALUE}`.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "StaticImport",
|
||||
summary = "Identifier should be statically imported",
|
||||
linkType = NONE,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class StaticImportCheck extends BugChecker implements MemberSelectTreeMatcher {
|
||||
public final class StaticImport extends BugChecker implements MemberSelectTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
@@ -67,6 +66,7 @@ public final class StaticImportCheck extends BugChecker implements MemberSelectT
|
||||
"com.google.errorprone.BugPattern.LinkType",
|
||||
"com.google.errorprone.BugPattern.SeverityLevel",
|
||||
"com.google.errorprone.BugPattern.StandardTags",
|
||||
"com.google.errorprone.matchers.Matchers",
|
||||
"com.google.errorprone.refaster.ImportPolicy",
|
||||
"com.mongodb.client.model.Accumulators",
|
||||
"com.mongodb.client.model.Aggregates",
|
||||
@@ -29,13 +29,12 @@ import java.time.LocalTime;
|
||||
/** A {@link BugChecker} which flags illegal time-zone related operations. */
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
name = "TimeZoneUsage",
|
||||
summary =
|
||||
"Derive the current time from an existing `Clock` Spring bean, and don't rely on a `Clock`'s time zone",
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = FRAGILE_CODE)
|
||||
public final class TimeZoneUsageCheck extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
public final class TimeZoneUsage extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> BANNED_TIME_METHOD =
|
||||
anyOf(
|
||||
@@ -1,4 +1,4 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
@@ -28,7 +28,7 @@ import java.util.stream.Stream;
|
||||
* <p>This class allows one to define a whitelist or blacklist of annotations or their attributes.
|
||||
* Annotations are identified by their fully qualified name.
|
||||
*/
|
||||
final class AnnotationAttributeMatcher implements Serializable {
|
||||
public final class AnnotationAttributeMatcher implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final boolean complement;
|
||||
@@ -59,7 +59,7 @@ final class AnnotationAttributeMatcher implements Serializable {
|
||||
* @param exclusions The listed annotations or annotation attributes are not matched.
|
||||
* @return A non-{@code null} {@link AnnotationAttributeMatcher}.
|
||||
*/
|
||||
static AnnotationAttributeMatcher create(
|
||||
public static AnnotationAttributeMatcher create(
|
||||
Optional<? extends List<String>> inclusions, Iterable<String> exclusions) {
|
||||
Set<String> includedWholeTypes = new HashSet<>();
|
||||
Set<String> excludedWholeTypes = new HashSet<>();
|
||||
@@ -97,7 +97,13 @@ final class AnnotationAttributeMatcher implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
Stream<? extends ExpressionTree> extractMatchingArguments(AnnotationTree tree) {
|
||||
/**
|
||||
* Returns the subset of arguments of the given {@link AnnotationTree} matched by this instance.
|
||||
*
|
||||
* @param tree The annotation AST node to be inspected.
|
||||
* @return Any matching annotation arguments.
|
||||
*/
|
||||
public Stream<? extends ExpressionTree> extractMatchingArguments(AnnotationTree tree) {
|
||||
Type type = ASTHelpers.getType(tree.getAnnotationType());
|
||||
if (type == null) {
|
||||
return Stream.empty();
|
||||
@@ -1,9 +1,10 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
final class JavaKeywords {
|
||||
/** Utility class that can be used to identify reserved keywords of the Java language. */
|
||||
public final class JavaKeywords {
|
||||
/**
|
||||
* List of all reserved keywords in the Java language.
|
||||
*
|
||||
@@ -95,17 +96,33 @@ final class JavaKeywords {
|
||||
|
||||
private JavaKeywords() {}
|
||||
|
||||
/** Tells whether the given string is a reserved keyword in the Java language. */
|
||||
/**
|
||||
* Tells whether the given string is a reserved keyword in the Java language.
|
||||
*
|
||||
* @param str The string of interest.
|
||||
* @return {@code true} if the given string is a reserved keyword in the Java language.
|
||||
*/
|
||||
public static boolean isReservedKeyword(String str) {
|
||||
return RESERVED_KEYWORDS.contains(str);
|
||||
}
|
||||
|
||||
/** Tells whether the given string is a contextual keyword in the Java language. */
|
||||
/**
|
||||
* Tells whether the given string is a contextual keyword in the Java language.
|
||||
*
|
||||
* @param str The string of interest.
|
||||
* @return {@code true} if the given string is a contextual keyword in the Java language.
|
||||
*/
|
||||
public static boolean isContextualKeyword(String str) {
|
||||
return CONTEXTUAL_KEYWORDS.contains(str);
|
||||
}
|
||||
|
||||
/** Tells whether the given string is a reserved or contextual keyword in the Java language. */
|
||||
/**
|
||||
* Tells whether the given string is a reserved or contextual keyword in the Java language.
|
||||
*
|
||||
* @param str The string of interest.
|
||||
* @return {@code true} if the given string is a reserved or contextual keyword in the Java
|
||||
* language.
|
||||
*/
|
||||
public static boolean isKeyword(String str) {
|
||||
return ALL_KEYWORDS.contains(str);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
@@ -15,13 +15,20 @@ import java.util.regex.Pattern;
|
||||
/** A method invocation expression {@link Matcher} factory. */
|
||||
// XXX: Document better. The expressions accepted here could also be defined using `MethodMatchers`.
|
||||
// So explain why this class is still useful.
|
||||
final class MethodMatcherFactory {
|
||||
public final class MethodMatcherFactory {
|
||||
private static final Splitter ARGUMENT_TYPE_SPLITTER =
|
||||
Splitter.on(',').trimResults().omitEmptyStrings();
|
||||
private static final Pattern METHOD_SIGNATURE =
|
||||
Pattern.compile("([^\\s#(,)]+)#([^\\s#(,)]+)\\(((?:[^\\s#(,)]+(?:,[^\\s#(,)]+)*)?)\\)");
|
||||
|
||||
Matcher<ExpressionTree> create(Collection<String> signatures) {
|
||||
/**
|
||||
* Creates a {@link Matcher} of methods with any of the given signatures.
|
||||
*
|
||||
* @param signatures The method signatures of interest.
|
||||
* @return A new {@link Matcher} which accepts invocation expressions of any method identified by
|
||||
* the given signatures.
|
||||
*/
|
||||
public Matcher<ExpressionTree> create(Collection<String> signatures) {
|
||||
return anyOf(
|
||||
signatures.stream()
|
||||
.map(MethodMatcherFactory::createMethodMatcher)
|
||||
@@ -1,19 +1,26 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.sun.source.tree.Tree;
|
||||
|
||||
/**
|
||||
* A collection of Error Prone utility methods for dealing with the source code representation of
|
||||
* AST nodes.
|
||||
*/
|
||||
// XXX: Can we locate this code in a better place? Maybe contribute it upstream?
|
||||
final class Util {
|
||||
private Util() {}
|
||||
public final class SourceCode {
|
||||
private SourceCode() {}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the given {@link Tree}, preferring the original source code
|
||||
* (if available) over its prettified representation.
|
||||
*
|
||||
* @param tree The AST node of interest.
|
||||
* @param state A {@link VisitorState} describing the context in which the given {@link Tree} is
|
||||
* found.
|
||||
* @return A non-{@code null} string.
|
||||
*/
|
||||
static String treeToString(Tree tree, VisitorState state) {
|
||||
public static String treeToString(Tree tree, VisitorState state) {
|
||||
String src = state.getSourceForNode(tree);
|
||||
return src != null ? src : tree.toString();
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/** Auxiliary utilities for use by Error Prone checks. */
|
||||
@com.google.errorprone.annotations.CheckReturnValue
|
||||
@javax.annotation.ParametersAreNonnullByDefault
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
@@ -59,6 +59,27 @@ final class AssertJThrowingCallableTemplates {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIllegalArgumentExceptionHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByIllegalArgumentException" /* Matches strictly more specific expressions. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
|
||||
return assertThatIllegalArgumentException()
|
||||
.isThrownBy(throwingCallable)
|
||||
.withMessage(message, parameters);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(
|
||||
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage(message, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIllegalArgumentExceptionHasMessageStartingWith {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
@@ -148,6 +169,27 @@ final class AssertJThrowingCallableTemplates {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIllegalStateExceptionHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByIllegalStateException" /* Matches strictly more specific expressions. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
|
||||
return assertThatIllegalStateException()
|
||||
.isThrownBy(throwingCallable)
|
||||
.withMessage(message, parameters);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(
|
||||
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage(message, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIllegalStateExceptionHasMessageStartingWith {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
@@ -235,6 +277,27 @@ final class AssertJThrowingCallableTemplates {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByNullPointerExceptionHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByNullPointerException" /* Matches strictly more specific expressions. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
|
||||
return assertThatNullPointerException()
|
||||
.isThrownBy(throwingCallable)
|
||||
.withMessage(message, parameters);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(
|
||||
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(NullPointerException.class)
|
||||
.hasMessage(message, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByNullPointerExceptionHasMessageStartingWith {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
@@ -284,6 +347,25 @@ final class AssertJThrowingCallableTemplates {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIOExceptionHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByIOException" /* Matches strictly more specific expressions. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
|
||||
return assertThatIOException().isThrownBy(throwingCallable).withMessage(message, parameters);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(
|
||||
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(IOException.class)
|
||||
.hasMessage(message, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownBy {
|
||||
@BeforeTemplate
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
@@ -321,6 +403,32 @@ final class AssertJThrowingCallableTemplates {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownBy" /* Matches strictly more specific expressions. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
Class<? extends Throwable> exceptionType,
|
||||
ThrowingCallable throwingCallable,
|
||||
String message,
|
||||
@Repeated Object parameters) {
|
||||
return assertThatExceptionOfType(exceptionType)
|
||||
.isThrownBy(throwingCallable)
|
||||
.withMessage(message, parameters);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(
|
||||
Class<? extends Throwable> exceptionType,
|
||||
ThrowingCallable throwingCallable,
|
||||
String message,
|
||||
@Repeated Object parameters) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(exceptionType)
|
||||
.hasMessage(message, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Drop this template in favour of a generic Error Prone check which flags
|
||||
// `String.format(...)` arguments to a wide range of format methods.
|
||||
static final class AbstractThrowableAssertHasMessage {
|
||||
|
||||
@@ -15,6 +15,7 @@ import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.stream.Stream;
|
||||
@@ -129,31 +130,32 @@ final class CollectionTemplates {
|
||||
}
|
||||
}
|
||||
|
||||
static final class CollectionRemoveAllFromCollectionBlock<T, S extends T> {
|
||||
static final class SetRemoveAllCollection<T, S extends T> {
|
||||
@BeforeTemplate
|
||||
void before(Collection<T> removeTo, Collection<S> elementsToRemove) {
|
||||
elementsToRemove.forEach(removeTo::remove);
|
||||
void before(Set<T> removeFrom, Collection<S> elementsToRemove) {
|
||||
elementsToRemove.forEach(removeFrom::remove);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
void before2(Collection<T> removeTo, Collection<S> elementsToRemove) {
|
||||
void before2(Set<T> removeFrom, Collection<S> elementsToRemove) {
|
||||
for (T element : elementsToRemove) {
|
||||
removeTo.remove(element);
|
||||
removeFrom.remove(element);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: This method is identical to `before2` except for the loop type. Make Refaster smarter so
|
||||
// that this is supported out of the box.
|
||||
// that this is supported out of the box. After doing so, also drop the `S extends T` type
|
||||
// constraint; ideally this check applies to any `S`.
|
||||
@BeforeTemplate
|
||||
void before3(Collection<T> removeTo, Collection<S> elementsToRemove) {
|
||||
void before3(Set<T> removeFrom, Collection<S> elementsToRemove) {
|
||||
for (S element : elementsToRemove) {
|
||||
removeTo.remove(element);
|
||||
removeFrom.remove(element);
|
||||
}
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(Collection<T> removeTo, Collection<S> elementsToRemove) {
|
||||
removeTo.removeAll(elementsToRemove);
|
||||
void after(Set<T> removeFrom, Collection<S> elementsToRemove) {
|
||||
removeFrom.removeAll(elementsToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ final class EqualityTemplates {
|
||||
* remaining reference-based equality checks.
|
||||
*/
|
||||
// XXX: This Refaster rule is the topic of https://github.com/google/error-prone/issues/559. We
|
||||
// work around the issue by selecting the "largest replacements". See RefasterCheck.
|
||||
// work around the issue by selecting the "largest replacements". See the `Refaster` check.
|
||||
@BeforeTemplate
|
||||
boolean before(T a, T b) {
|
||||
return Refaster.anyOf(a.equals(b), Objects.equals(a, b));
|
||||
@@ -34,9 +34,8 @@ final class EqualityTemplates {
|
||||
}
|
||||
|
||||
/** Prefer {@link Object#equals(Object)} over the equivalent lambda function. */
|
||||
// XXX: As it stands, this rule is a special case of what `MethodReferenceUsageCheck` tries to
|
||||
// achieve. If/when `MethodReferenceUsageCheck` becomes production ready, we should simply drop
|
||||
// this check.
|
||||
// XXX: As it stands, this rule is a special case of what `MethodReferenceUsage` tries to achieve.
|
||||
// If/when `MethodReferenceUsage` becomes production ready, we should simply drop this check.
|
||||
// XXX: Alternatively, the rule should be replaced with a plugin which also identifies cases where
|
||||
// the arguments are swapped but simplification is possible anyway, by virtue of `v` being
|
||||
// non-null.
|
||||
|
||||
@@ -192,7 +192,7 @@ final class ImmutableMapTemplates {
|
||||
|
||||
// XXX: Instead of `Map.Entry::getKey` we could also match `e -> e.getKey()`. But for some
|
||||
// reason Refaster doesn't handle that case. This doesn't matter if we roll out use of
|
||||
// `MethodReferenceUsageCheck`. Same observation applies to a lot of other Refaster checks.
|
||||
// `MethodReferenceUsage`. Same observation applies to a lot of other Refaster checks.
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NullAway")
|
||||
ImmutableMap<K, V2> before(Map<K, V1> map) {
|
||||
|
||||
@@ -113,7 +113,7 @@ final class OptionalTemplates {
|
||||
/** Prefer {@link Optional#filter(Predicate)} over usage of the ternary operator. */
|
||||
// XXX: This rule may introduce a compilation error: the `test` expression may reference a
|
||||
// non-effectively final variable, which is not allowed in the replacement lambda expression.
|
||||
// Maybe our RefasterCheck should test `compilesWithFix`?
|
||||
// Maybe our `Refaster` checker should test `compilesWithFix`?
|
||||
abstract static class TernaryOperatorOptionalPositiveFiltering<T> {
|
||||
@Placeholder
|
||||
abstract boolean test(T value);
|
||||
@@ -133,7 +133,7 @@ final class OptionalTemplates {
|
||||
/** Prefer {@link Optional#filter(Predicate)} over usage of the ternary operator. */
|
||||
// XXX: This rule may introduce a compilation error: the `test` expression may reference a
|
||||
// non-effectively final variable, which is not allowed in the replacement lambda expression.
|
||||
// Maybe our RefasterCheck should test `compilesWithFix`?
|
||||
// Maybe our `Refaster` checker should test `compilesWithFix`?
|
||||
abstract static class TernaryOperatorOptionalNegativeFiltering<T> {
|
||||
@Placeholder
|
||||
abstract boolean test(T value);
|
||||
@@ -239,9 +239,16 @@ final class OptionalTemplates {
|
||||
}
|
||||
}
|
||||
|
||||
/** Within a stream's map operation unconditional {@link Optional#get()} calls can be avoided. */
|
||||
// XXX: An alternative approach is to `.flatMap(Optional::stream)`. That may be a bit longer, but
|
||||
// yield nicer code. Think about it.
|
||||
/**
|
||||
* Within a stream's map operation unconditional {@link Optional#orElseThrow()} calls can be
|
||||
* avoided.
|
||||
*
|
||||
* <p><strong>Warning:</strong> this rewrite rule is not completely behavior preserving. The
|
||||
* original code throws an exception if the mapping operation does not produce a value, while the
|
||||
* replacement does not.
|
||||
*/
|
||||
// XXX: An alternative approach is to use `.flatMap(Optional::stream)`. That may be a bit longer,
|
||||
// but yields nicer code. Think about it.
|
||||
abstract static class StreamMapToOptionalGet<T, S> {
|
||||
@Placeholder
|
||||
abstract Optional<S> toOptionalFunction(@MayOptionallyUse T element);
|
||||
@@ -311,6 +318,7 @@ final class OptionalTemplates {
|
||||
/** Prefer {@link Optional#or(Supplier)} over more verbose alternatives. */
|
||||
abstract static class OptionalOrOtherOptional<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedOptionals" /* Auto-fix for the `NestedOptionals` check. */)
|
||||
Optional<T> before(Optional<T> optional1, Optional<T> optional2) {
|
||||
// XXX: Note that rewriting the first and third variant will change the code's behavior if
|
||||
// `optional2` has side-effects.
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
package tech.picnic.errorprone.refastertemplates;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Flowable;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Supplier;
|
||||
import org.assertj.core.util.Streams;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.adapter.rxjava.RxJava2Adapter;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/** Refaster templates which replace RxJava expressions with equivalent Reactor assertions. */
|
||||
// XXX: Document the approach and any limitations; see the `TestNGToAssertJTemplates` documentation.
|
||||
// XXX: Document that the templates use `Completable` rather than `CompletableSource`, etc.
|
||||
// XXX: Have separate files for Completable, Maybe, Single, Flowable?
|
||||
final class RxJavaToReactorTemplates {
|
||||
private RxJavaToReactorTemplates() {}
|
||||
|
||||
// XXX: Handle array and varargs cases.
|
||||
// XXX: Simplify rule with `Completable.amb(Arrays.asList(sources))`?
|
||||
static final class CompletableAmbArray {
|
||||
@BeforeTemplate
|
||||
Completable before(Completable... sources) {
|
||||
return Completable.ambArray(sources);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Completable after(Completable... sources) {
|
||||
return Mono.firstWithSignal(
|
||||
Arrays.stream(sources)
|
||||
.map(RxJava2Adapter::completableToMono)
|
||||
.collect(toImmutableList()))
|
||||
.as(RxJava2Adapter::monoToCompletable);
|
||||
}
|
||||
}
|
||||
|
||||
static final class CompletableAmb {
|
||||
@BeforeTemplate
|
||||
Completable before(Iterable<? extends Completable> sources) {
|
||||
return Completable.amb(sources);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Completable after(Iterable<? extends Completable> sources) {
|
||||
return Mono.firstWithSignal(
|
||||
Streams.stream(sources)
|
||||
.map(RxJava2Adapter::completableToMono)
|
||||
.collect(toImmutableList()))
|
||||
.as(RxJava2Adapter::monoToCompletable);
|
||||
}
|
||||
}
|
||||
|
||||
static final class CompletableComplete {
|
||||
@BeforeTemplate
|
||||
Completable before() {
|
||||
return Completable.complete();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Completable after() {
|
||||
return Mono.empty().as(RxJava2Adapter::monoToCompletable);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Handle array and varargs cases.
|
||||
// XXX: Simplify rule with `Completable.amb(Arrays.asList(sources))`?
|
||||
static final class CompletableConcatArray {
|
||||
@BeforeTemplate
|
||||
Completable before(Completable... sources) {
|
||||
return Completable.concatArray(sources);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Completable after(Completable... sources) {
|
||||
return Flux.concat(
|
||||
Arrays.stream(sources)
|
||||
.map(RxJava2Adapter::completableToMono)
|
||||
.collect(toImmutableList()))
|
||||
.then()
|
||||
.as(RxJava2Adapter::monoToCompletable);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Simplify rule with `Completable.concat(Flux.fromIterable(sources))`?
|
||||
static final class CompletableConcatIterable {
|
||||
@BeforeTemplate
|
||||
Completable before(Iterable<? extends Completable> sources) {
|
||||
return Completable.concat(sources);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Completable after(Iterable<? extends Completable> sources) {
|
||||
return Flux.concat(Flux.fromIterable(sources).map(RxJava2Adapter::completableToMono))
|
||||
.then()
|
||||
.as(RxJava2Adapter::monoToCompletable);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Simplify rule with `Completable.concat(sources, 2)`?
|
||||
// XXX: Arguably we should, since the Reactor prefetch is `Queues.XS_BUFFER_SIZE`.
|
||||
static final class CompletableConcatPublisher {
|
||||
@BeforeTemplate
|
||||
Completable before(Publisher<? extends Completable> sources) {
|
||||
return Completable.concat(sources);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Completable after(Publisher<? extends Completable> sources) {
|
||||
return Flux.concat(Flux.from(sources).map(RxJava2Adapter::completableToMono))
|
||||
.then()
|
||||
.as(RxJava2Adapter::monoToCompletable);
|
||||
}
|
||||
}
|
||||
|
||||
static final class CompletableConcatPublisherPrefetch {
|
||||
@BeforeTemplate
|
||||
Completable before(Publisher<? extends Completable> sources, int prefetch) {
|
||||
return Completable.concat(sources, prefetch);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Completable after(Publisher<? extends Completable> sources, int prefetch) {
|
||||
return Flux.concat(Flux.from(sources).map(RxJava2Adapter::completableToMono), prefetch)
|
||||
.then()
|
||||
.as(RxJava2Adapter::monoToCompletable);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Migrate `Completable#create(CompletableOnSubscribe)`
|
||||
|
||||
// XXX: Migrate `Completable#unsafeCreate(CompletableSource)`
|
||||
|
||||
static final class CompletableDefer {
|
||||
@BeforeTemplate
|
||||
Completable before(Callable<? extends Completable> completableSupplier) {
|
||||
return Completable.defer(completableSupplier);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Completable after(Callable<? extends Completable> completableSupplier) {
|
||||
return Mono.defer(
|
||||
() ->
|
||||
RxJava2ReactorMigrationUtil.getUnchecked(completableSupplier)
|
||||
.as(RxJava2Adapter::completableToMono))
|
||||
.as(RxJava2Adapter::monoToCompletable);
|
||||
}
|
||||
}
|
||||
|
||||
static final class CompletableErrorDeferred {
|
||||
@BeforeTemplate
|
||||
Completable before(Callable<? extends Throwable> errorSupplier) {
|
||||
return Completable.error(errorSupplier);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Completable after(Callable<? extends Throwable> errorSupplier) {
|
||||
return Mono.error(RxJava2ReactorMigrationUtil.callableAsSupplier(errorSupplier))
|
||||
.as(RxJava2Adapter::monoToCompletable);
|
||||
}
|
||||
}
|
||||
|
||||
static final class CompletableError {
|
||||
@BeforeTemplate
|
||||
Completable before(Throwable error) {
|
||||
return Completable.error(error);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Completable after(Throwable error) {
|
||||
return Mono.error(error).as(RxJava2Adapter::monoToCompletable);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Migrate `Completable#fromAction(Action)`
|
||||
|
||||
static final class CompletableFromCallable<T> {
|
||||
@BeforeTemplate
|
||||
Completable before(Callable<T> callable) {
|
||||
return Completable.fromCallable(callable);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Completable after(Callable<T> callable) {
|
||||
return Mono.fromSupplier(RxJava2ReactorMigrationUtil.callableAsSupplier(callable))
|
||||
.as(RxJava2Adapter::monoToCompletable);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Also handle `Future`s that don't extend `CompletableFuture`.
|
||||
static final class CompletableFromFuture<T> {
|
||||
@BeforeTemplate
|
||||
Completable before(CompletableFuture<T> future) {
|
||||
return Completable.fromFuture(future);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Completable after(CompletableFuture<T> future) {
|
||||
return Mono.fromFuture(future).as(RxJava2Adapter::monoToCompletable);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Next up: migrate `Completable#fromMaybe(Maybe)`
|
||||
|
||||
// XXX: Move to a separate Maven module.
|
||||
static final class RxJava2ReactorMigrationUtil {
|
||||
private RxJava2ReactorMigrationUtil() {}
|
||||
|
||||
// XXX: Rename.
|
||||
// XXX: Introduce Refaster rules to drop this wrapper when possible.
|
||||
static <T> T getUnchecked(Callable<T> callable) {
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Callable threw checked exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Rename.
|
||||
// XXX: Introduce Refaster rules to drop this wrapper when possible.
|
||||
static <T> Supplier<T> callableAsSupplier(Callable<T> callable) {
|
||||
return () -> {
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Callable threw checked exception", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static <T, U, R> BiFunction<? super T, ? super U, ? extends R> toJdkBiFunction(
|
||||
io.reactivex.functions.BiFunction<? super T, ? super U, ? extends R> biFunction) {
|
||||
return (t, u) -> {
|
||||
try {
|
||||
return biFunction.apply(t, u);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("BiFunction threw checked exception", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////// FLOWABLE - MOVE!
|
||||
|
||||
static final class FlowableCombineLatest<T1, T2, R> {
|
||||
@BeforeTemplate
|
||||
Flowable<R> before(
|
||||
Publisher<? extends T1> publisher1,
|
||||
Publisher<? extends T2> publisher2,
|
||||
io.reactivex.functions.BiFunction<? super T1, ? super T2, ? extends R> combiner) {
|
||||
return Flowable.combineLatest(publisher1, publisher2, combiner);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flowable<R> after(
|
||||
Publisher<? extends T1> publisher1,
|
||||
Publisher<? extends T2> publisher2,
|
||||
io.reactivex.functions.BiFunction<? super T1, ? super T2, ? extends R> combiner) {
|
||||
// XXX: Generic type parameters are specified to appease IDEA; review.
|
||||
return RxJava2Adapter.fluxToFlowable(
|
||||
Flux.<T1, T2, R>combineLatest(
|
||||
publisher1, publisher2, RxJava2ReactorMigrationUtil.toJdkBiFunction(combiner)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,14 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class AmbiguousJsonCreatorCheckTest {
|
||||
final class AmbiguousJsonCreatorTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(AmbiguousJsonCreatorCheck.class, getClass())
|
||||
CompilationTestHelper.newInstance(AmbiguousJsonCreator.class, getClass())
|
||||
.expectErrorMessage(
|
||||
"X",
|
||||
containsPattern("`JsonCreator.Mode` should be set for single-argument creators"));
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(AmbiguousJsonCreatorCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(AmbiguousJsonCreator.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -6,11 +6,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class AssertJIsNullCheckTest {
|
||||
final class AssertJIsNullTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(AssertJIsNullCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(AssertJIsNull.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(AssertJIsNullCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(AssertJIsNull.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class AutowiredConstructorCheckTest {
|
||||
final class AutowiredConstructorTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(AutowiredConstructorCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(AutowiredConstructor.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(AutowiredConstructorCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(AutowiredConstructor.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class CanonicalAnnotationSyntaxCheckTest {
|
||||
final class CanonicalAnnotationSyntaxTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(CanonicalAnnotationSyntaxCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(CanonicalAnnotationSyntax.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(CanonicalAnnotationSyntaxCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(CanonicalAnnotationSyntax.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -7,11 +7,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class CollectorMutabilityCheckTest {
|
||||
final class CollectorMutabilityTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(CollectorMutabilityCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(CollectorMutability.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(CollectorMutabilityCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(CollectorMutability.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class EmptyMethodCheckTest {
|
||||
final class EmptyMethodTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(EmptyMethodCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(EmptyMethod.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(EmptyMethodCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(EmptyMethod.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -5,12 +5,12 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class ErrorProneTestHelperSourceFormatCheckTest {
|
||||
final class ErrorProneTestHelperSourceFormatTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(ErrorProneTestHelperSourceFormatCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(ErrorProneTestHelperSourceFormat.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(
|
||||
ErrorProneTestHelperSourceFormatCheck.class, getClass());
|
||||
ErrorProneTestHelperSourceFormat.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -20,13 +20,13 @@ final class ErrorProneTestHelperSourceFormatCheckTest {
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import tech.picnic.errorprone.bugpatterns.EmptyMethodCheck;",
|
||||
"import tech.picnic.errorprone.bugpatterns.EmptyMethod;",
|
||||
"",
|
||||
"class A {",
|
||||
" private final CompilationTestHelper compilationTestHelper =",
|
||||
" CompilationTestHelper.newInstance(EmptyMethodCheck.class, getClass());",
|
||||
" CompilationTestHelper.newInstance(EmptyMethod.class, getClass());",
|
||||
" private final BugCheckerRefactoringTestHelper refactoringTestHelper =",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(EmptyMethodCheck.class, getClass());",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(EmptyMethod.class, getClass());",
|
||||
"",
|
||||
" void m() {",
|
||||
" compilationTestHelper",
|
||||
@@ -69,13 +69,13 @@ final class ErrorProneTestHelperSourceFormatCheckTest {
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import tech.picnic.errorprone.bugpatterns.EmptyMethodCheck;",
|
||||
"import tech.picnic.errorprone.bugpatterns.EmptyMethod;",
|
||||
"",
|
||||
"class A {",
|
||||
" private final CompilationTestHelper compilationTestHelper =",
|
||||
" CompilationTestHelper.newInstance(EmptyMethodCheck.class, getClass());",
|
||||
" CompilationTestHelper.newInstance(EmptyMethod.class, getClass());",
|
||||
" private final BugCheckerRefactoringTestHelper refactoringTestHelper =",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(EmptyMethodCheck.class, getClass());",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(EmptyMethod.class, getClass());",
|
||||
"",
|
||||
" void m() {",
|
||||
" compilationTestHelper",
|
||||
@@ -111,13 +111,13 @@ final class ErrorProneTestHelperSourceFormatCheckTest {
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import tech.picnic.errorprone.bugpatterns.EmptyMethodCheck;",
|
||||
"import tech.picnic.errorprone.bugpatterns.EmptyMethod;",
|
||||
"",
|
||||
"class A {",
|
||||
" private final CompilationTestHelper compilationTestHelper =",
|
||||
" CompilationTestHelper.newInstance(EmptyMethodCheck.class, getClass());",
|
||||
" CompilationTestHelper.newInstance(EmptyMethod.class, getClass());",
|
||||
" private final BugCheckerRefactoringTestHelper refactoringTestHelper =",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(EmptyMethodCheck.class, getClass());",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(EmptyMethod.class, getClass());",
|
||||
"",
|
||||
" void m() {",
|
||||
" compilationTestHelper",
|
||||
@@ -3,12 +3,12 @@ package tech.picnic.errorprone.bugpatterns;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class ExplicitEnumOrderingCheckTest {
|
||||
final class ExplicitEnumOrderingTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(ExplicitEnumOrderingCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(ExplicitEnumOrdering.class, getClass());
|
||||
|
||||
@Test
|
||||
void Identification() {
|
||||
void identification() {
|
||||
compilationTestHelper
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
@@ -7,11 +7,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class FluxFlatMapUsageCheckTest {
|
||||
final class FluxFlatMapUsageTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(FluxFlatMapUsageCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(FluxFlatMapUsage.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
newInstance(FluxFlatMapUsageCheck.class, getClass());
|
||||
newInstance(FluxFlatMapUsage.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class FormatStringConcatenationCheckTest {
|
||||
final class FormatStringConcatenationTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(FormatStringConcatenationCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(FormatStringConcatenation.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(FormatStringConcatenationCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(FormatStringConcatenation.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -6,11 +6,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class IdentityConversionCheckTest {
|
||||
final class IdentityConversionTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(IdentityConversionCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(IdentityConversion.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(IdentityConversionCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(IdentityConversion.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -0,0 +1,182 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class ImmutablesSortedSetComparatorTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(ImmutablesSortedSetComparator.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(ImmutablesSortedSetComparator.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
compilationTestHelper
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ContiguousSet;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import com.google.common.collect.ImmutableSortedSet;",
|
||||
"import java.util.NavigableSet;",
|
||||
"import java.util.Set;",
|
||||
"import java.util.SortedSet;",
|
||||
"import java.util.TreeSet;",
|
||||
"import org.immutables.value.Value;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @Value.Immutable",
|
||||
" interface ImmutableInterface {",
|
||||
" Set<String> set();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" SortedSet<String> sortedSet();",
|
||||
"",
|
||||
" @Value.NaturalOrder",
|
||||
" SortedSet<String> sortedSet2();",
|
||||
" }",
|
||||
"",
|
||||
" @Value.Modifiable",
|
||||
" interface ModifiableInterfaceWithDefaults {",
|
||||
" @Value.Default",
|
||||
" default Set<Integer> set() {",
|
||||
" return new TreeSet<>();",
|
||||
" }",
|
||||
"",
|
||||
" @Value.Default",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" default NavigableSet<Integer> navigableSet() {",
|
||||
" return new TreeSet<>();",
|
||||
" }",
|
||||
"",
|
||||
" @Value.Default",
|
||||
" @Value.ReverseOrder",
|
||||
" default NavigableSet<Integer> navigableSet2() {",
|
||||
" return new TreeSet<>();",
|
||||
" }",
|
||||
"",
|
||||
" default NavigableSet<Integer> nonPropertyNavigableSet() {",
|
||||
" return new TreeSet<>();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" interface NonImmutablesInterface {",
|
||||
" SortedSet<String> sortedSet();",
|
||||
" }",
|
||||
"",
|
||||
" @Value.Immutable",
|
||||
" abstract class AbstractImmutableWithDefaults {",
|
||||
" @Value.Default",
|
||||
" ImmutableSet<Integer> immutableSet() {",
|
||||
" return ImmutableSet.of();",
|
||||
" }",
|
||||
"",
|
||||
" @Value.Default",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableSortedSet<String> immutableSortedSet() {",
|
||||
" return ImmutableSortedSet.of();",
|
||||
" }",
|
||||
"",
|
||||
" @Value.Default",
|
||||
" @Value.NaturalOrder",
|
||||
" ImmutableSortedSet<String> immutableSortedSet2() {",
|
||||
" return ImmutableSortedSet.of();",
|
||||
" }",
|
||||
"",
|
||||
" ImmutableSortedSet<String> nonPropertyImmutableSortedSet() {",
|
||||
" return ImmutableSortedSet.of();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" @Value.Modifiable",
|
||||
" abstract class AbstractModifiable {",
|
||||
" abstract ImmutableSet<Integer> immutableSet();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" abstract ContiguousSet<Integer> contiguousSet();",
|
||||
"",
|
||||
" @Value.ReverseOrder",
|
||||
" abstract ContiguousSet<Integer> contiguousSet2();",
|
||||
" }",
|
||||
"",
|
||||
" abstract class AbstractNonImmutables {",
|
||||
" abstract SortedSet<Integer> sortedSet();",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
refactoringTestHelper
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ImmutableSortedSet;",
|
||||
"import java.util.SortedSet;",
|
||||
"import org.immutables.value.Value;",
|
||||
"",
|
||||
"@Value.Immutable",
|
||||
"abstract class A {",
|
||||
" abstract ImmutableSortedSet<String> sortedSet();",
|
||||
"",
|
||||
" @Value.Modifiable",
|
||||
" interface B {",
|
||||
" SortedSet<String> sortedSet();",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ImmutableSortedSet;",
|
||||
"import java.util.SortedSet;",
|
||||
"import org.immutables.value.Value;",
|
||||
"",
|
||||
"@Value.Immutable",
|
||||
"abstract class A {",
|
||||
" @Value.NaturalOrder",
|
||||
" abstract ImmutableSortedSet<String> sortedSet();",
|
||||
"",
|
||||
" @Value.Modifiable",
|
||||
" interface B {",
|
||||
" @Value.NaturalOrder",
|
||||
" SortedSet<String> sortedSet();",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacementWithImportClash() {
|
||||
refactoringTestHelper
|
||||
.addInputLines(
|
||||
"MySpringService.java",
|
||||
"import com.google.common.collect.ImmutableSortedSet;",
|
||||
"import org.springframework.beans.factory.annotation.Value;",
|
||||
"",
|
||||
"class MySpringService {",
|
||||
" MySpringService(@Value(\"${someProperty}\") String prop) {}",
|
||||
" ;",
|
||||
"",
|
||||
" @org.immutables.value.Value.Immutable",
|
||||
" interface A {",
|
||||
" ImmutableSortedSet<String> sortedSet();",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"MySpringService.java",
|
||||
"import com.google.common.collect.ImmutableSortedSet;",
|
||||
"import org.springframework.beans.factory.annotation.Value;",
|
||||
"",
|
||||
"class MySpringService {",
|
||||
" MySpringService(@Value(\"${someProperty}\") String prop) {}",
|
||||
" ;",
|
||||
"",
|
||||
" @org.immutables.value.Value.Immutable",
|
||||
" interface A {",
|
||||
" @org.immutables.value.Value.NaturalOrder",
|
||||
" ImmutableSortedSet<String> sortedSet();",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class JUnitMethodDeclarationCheckTest {
|
||||
final class JUnitMethodDeclarationTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(JUnitMethodDeclarationCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(JUnitMethodDeclaration.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(JUnitMethodDeclarationCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(JUnitMethodDeclaration.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -6,20 +6,19 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class LexicographicalAnnotationAttributeListingCheckTest {
|
||||
final class LexicographicalAnnotationAttributeListingTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(
|
||||
LexicographicalAnnotationAttributeListingCheck.class, getClass());
|
||||
LexicographicalAnnotationAttributeListing.class, getClass());
|
||||
private final CompilationTestHelper restrictedCompilationTestHelper =
|
||||
CompilationTestHelper.newInstance(
|
||||
LexicographicalAnnotationAttributeListingCheck.class, getClass())
|
||||
CompilationTestHelper.newInstance(LexicographicalAnnotationAttributeListing.class, getClass())
|
||||
.setArgs(
|
||||
ImmutableList.of(
|
||||
"-XepOpt:LexicographicalAnnotationAttributeListing:Includes=pkg.A.Foo,pkg.A.Bar",
|
||||
"-XepOpt:LexicographicalAnnotationAttributeListing:Excludes=pkg.A.Bar#value"));
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(
|
||||
LexicographicalAnnotationAttributeListingCheck.class, getClass());
|
||||
LexicographicalAnnotationAttributeListing.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -36,6 +35,8 @@ final class LexicographicalAnnotationAttributeListingCheckTest {
|
||||
"import io.swagger.v3.oas.annotations.Parameters;",
|
||||
"import java.math.RoundingMode;",
|
||||
"import javax.xml.bind.annotation.XmlType;",
|
||||
"import org.springframework.context.annotation.PropertySource;",
|
||||
"import org.springframework.test.context.TestPropertySource;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @interface Foo {",
|
||||
@@ -145,14 +146,23 @@ final class LexicographicalAnnotationAttributeListingCheckTest {
|
||||
" A secondEndpoint();",
|
||||
"",
|
||||
" @XmlType(propOrder = {\"field2\", \"field1\"})",
|
||||
" class Dummy {}",
|
||||
" class XmlTypeDummy {}",
|
||||
"",
|
||||
" @PropertySource({\"field2\", \"field1\"})",
|
||||
" class PropertySourceDummy {}",
|
||||
"",
|
||||
" @TestPropertySource(locations = {\"field2\", \"field1\"})",
|
||||
" class FirstTestPropertySourceDummy {}",
|
||||
"",
|
||||
" @TestPropertySource({\"field2\", \"field1\"})",
|
||||
" class SecondTestPropertySourceDummy {}",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
// XXX: Note that in the output below in one instance redundant `value =` assignments are
|
||||
// introduced. Avoiding that might make the code too complex. Instead, users can have the
|
||||
// `CanonicalAnnotationSyntaxCheck` correct the situation in a subsequent run.
|
||||
// `CanonicalAnnotationSyntax` checker correct the situation in a subsequent run.
|
||||
@Test
|
||||
void replacement() {
|
||||
refactoringTestHelper
|
||||
@@ -7,14 +7,14 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class LexicographicalAnnotationListingCheckTest {
|
||||
final class LexicographicalAnnotationListingTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(LexicographicalAnnotationListingCheck.class, getClass())
|
||||
CompilationTestHelper.newInstance(LexicographicalAnnotationListing.class, getClass())
|
||||
.expectErrorMessage(
|
||||
"X", containsPattern("Sort annotations lexicographically where possible"));
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(
|
||||
LexicographicalAnnotationListingCheck.class, getClass());
|
||||
LexicographicalAnnotationListing.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class MethodReferenceUsageCheckTest {
|
||||
final class MethodReferenceUsageTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(MethodReferenceUsageCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(MethodReferenceUsage.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(MethodReferenceUsageCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(MethodReferenceUsage.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -5,9 +5,9 @@ import static com.google.common.base.Predicates.containsPattern;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class MissingRefasterAnnotationCheckTest {
|
||||
final class MissingRefasterAnnotationTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(MissingRefasterAnnotationCheck.class, getClass())
|
||||
CompilationTestHelper.newInstance(MissingRefasterAnnotation.class, getClass())
|
||||
.expectErrorMessage(
|
||||
"X",
|
||||
containsPattern(
|
||||
@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class MockitoStubbingCheckTest {
|
||||
final class MockitoStubbingTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(MockitoStubbingCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(MockitoStubbing.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(MockitoStubbingCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(MockitoStubbing.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -0,0 +1,42 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class NestedOptionalsTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(NestedOptionals.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
compilationTestHelper
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.Optional;",
|
||||
"import java.util.stream.Stream;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Optional.empty();",
|
||||
" Optional.of(1);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Optional.of(Optional.empty());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Optional.of(Optional.of(1));",
|
||||
"",
|
||||
" Optional.ofNullable(null);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Optional.ofNullable((Optional) null);",
|
||||
"",
|
||||
" Optional.of(\"foo\").map(String::length);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Optional.of(\"foo\").map(Optional::of);",
|
||||
"",
|
||||
" Stream.of(\"foo\").findFirst();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Stream.of(\"foo\").map(Optional::of).findFirst();",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode.TEXT_MATCH;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class NonEmptyMonoTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(NonEmptyMono.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(NonEmptyMono.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
compilationTestHelper
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static com.google.common.collect.ImmutableList.toImmutableList;",
|
||||
"import static java.util.function.Function.identity;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableMap;",
|
||||
"import java.util.ArrayList;",
|
||||
"import java.util.HashMap;",
|
||||
"import java.util.List;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Mono.just(1).defaultIfEmpty(2);",
|
||||
" Mono.just(1).single();",
|
||||
" Mono.just(1).switchIfEmpty(Mono.just(2));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).all(x -> true).defaultIfEmpty(true);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).any(x -> true).single();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collect(toImmutableList()).switchIfEmpty(Mono.just(ImmutableList.of()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collect(ArrayList::new, List::add).defaultIfEmpty(new ArrayList<>());",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectList().single();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectMap(identity()).switchIfEmpty(Mono.just(ImmutableMap.of()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectMap(identity(), identity()).defaultIfEmpty(ImmutableMap.of());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectMap(identity(), identity(), HashMap::new).single();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectMultimap(identity()).switchIfEmpty(Mono.just(ImmutableMap.of()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectMultimap(identity(), identity()).defaultIfEmpty(ImmutableMap.of());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectMultimap(identity(), identity(), HashMap::new).single();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectSortedList().defaultIfEmpty(ImmutableList.of());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectSortedList((o1, o2) -> 0).single();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).count().switchIfEmpty(Mono.just(2L));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).elementAt(0).defaultIfEmpty(1);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).elementAt(0, 2).single();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).hasElement(2).switchIfEmpty(Mono.just(true));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).hasElements().defaultIfEmpty(true);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).last().single();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).last(2).switchIfEmpty(Mono.just(3));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).reduceWith(() -> 0, Integer::sum).defaultIfEmpty(2);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).single().single();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).single(2).switchIfEmpty(Mono.just(3));",
|
||||
"",
|
||||
" Flux.just(1).reduce(Integer::sum).defaultIfEmpty(2);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).reduce(2, Integer::sum).single();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.just(1).defaultIfEmpty(1).switchIfEmpty(Mono.just(2));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.just(1).hasElement().defaultIfEmpty(true);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.just(1).single().single();",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
refactoringTestHelper
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static com.google.common.collect.ImmutableList.toImmutableList;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Flux.just(1).collect(toImmutableList()).single();",
|
||||
" Flux.just(1).collect(toImmutableList()).defaultIfEmpty(ImmutableList.of());",
|
||||
" Flux.just(1).collect(toImmutableList()).switchIfEmpty(Mono.just(ImmutableList.of()));",
|
||||
"",
|
||||
" Mono.just(2).hasElement().single();",
|
||||
" Mono.just(2).hasElement().defaultIfEmpty(true);",
|
||||
" Mono.just(2).hasElement().switchIfEmpty(Mono.just(true));",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static com.google.common.collect.ImmutableList.toImmutableList;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Flux.just(1).collect(toImmutableList());",
|
||||
" Flux.just(1).collect(toImmutableList());",
|
||||
" Flux.just(1).collect(toImmutableList());",
|
||||
"",
|
||||
" Mono.just(2).hasElement();",
|
||||
" Mono.just(2).hasElement();",
|
||||
" Mono.just(2).hasElement();",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class PrimitiveComparisonCheckTest {
|
||||
final class PrimitiveComparisonTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(PrimitiveComparisonCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(PrimitiveComparison.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(PrimitiveComparisonCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(PrimitiveComparison.class, getClass());
|
||||
|
||||
// XXX: There are no tests for multiple replacements within the same expression:
|
||||
// - Error Prone doesn't currently support this, it seems.
|
||||
@@ -9,16 +9,16 @@ import org.junit.jupiter.api.Test;
|
||||
// XXX: The tests below show that `String.valueOf((String) null)` may be simplified, but
|
||||
// `String.valueOf(null)` may not. That is because the latter matches `String#valueOf(char[])`. We
|
||||
// could special-case `null` arguments, but that doesn't seem worth the trouble.
|
||||
final class RedundantStringConversionCheckTest {
|
||||
final class RedundantStringConversionTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(RedundantStringConversionCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass());
|
||||
private final CompilationTestHelper customizedCompilationTestHelper =
|
||||
CompilationTestHelper.newInstance(RedundantStringConversionCheck.class, getClass())
|
||||
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
|
||||
.setArgs(
|
||||
ImmutableList.of(
|
||||
"-XepOpt:RedundantStringConversion:ExtraConversionMethods=java.lang.Enum#name(),A#name(),A.B#toString(int)"));
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(RedundantStringConversionCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(RedundantStringConversion.class, getClass());
|
||||
|
||||
@Test
|
||||
void identificationOfIdentityTransformation() {
|
||||
@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class RefasterAnyOfUsageCheckTest {
|
||||
final class RefasterAnyOfUsageTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(RefasterAnyOfUsageCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(RefasterAnyOfUsage.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(RefasterAnyOfUsageCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(RefasterAnyOfUsage.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -1,191 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.common.collect.ImmutableSetMultimap.toImmutableSetMultimap;
|
||||
import static java.util.function.Function.identity;
|
||||
import static java.util.function.Predicate.not;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSetMultimap;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.ComparisonFailure;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
final class RefasterCheckTest {
|
||||
/** The names of all Refaster template groups defined in this module. */
|
||||
private static final ImmutableSet<String> TEMPLATE_GROUPS =
|
||||
ImmutableSet.of(
|
||||
"AssertJ",
|
||||
"AssertJBigDecimal",
|
||||
"AssertJBigInteger",
|
||||
"AssertJBoolean",
|
||||
"AssertJByte",
|
||||
"AssertJCharSequence",
|
||||
"AssertJDouble",
|
||||
"AssertJEnumerable",
|
||||
"AssertJFloat",
|
||||
"AssertJInteger",
|
||||
"AssertJLong",
|
||||
"AssertJNumber",
|
||||
"AssertJMap",
|
||||
"AssertJObject",
|
||||
"AssertJOptional",
|
||||
"AssertJShort",
|
||||
"AssertJString",
|
||||
"AssertJThrowingCallable",
|
||||
"Assorted",
|
||||
"BigDecimal",
|
||||
"Collection",
|
||||
"Comparator",
|
||||
"DoubleStream",
|
||||
"Equality",
|
||||
"ImmutableList",
|
||||
"ImmutableListMultimap",
|
||||
"ImmutableMap",
|
||||
"ImmutableMultiset",
|
||||
"ImmutableSet",
|
||||
"ImmutableSetMultimap",
|
||||
"ImmutableSortedMap",
|
||||
"ImmutableSortedMultiset",
|
||||
"ImmutableSortedSet",
|
||||
"IntStream",
|
||||
"JUnit",
|
||||
"LongStream",
|
||||
"MapEntry",
|
||||
"Mockito",
|
||||
"Multimap",
|
||||
"Null",
|
||||
"Optional",
|
||||
"Primitive",
|
||||
"Reactor",
|
||||
"RxJava2Adapter",
|
||||
"Stream",
|
||||
"String",
|
||||
"TestNGToAssertJ",
|
||||
"Time",
|
||||
"WebClient");
|
||||
/**
|
||||
* Matches the parts of the fully-qualified name of a template class that should be removed in
|
||||
* order to produce the associated {@link #TEMPLATE_GROUPS template group name}.
|
||||
*/
|
||||
private static final Pattern TEMPLATE_FQCN_TRIM_FOR_GROUP_NAME =
|
||||
Pattern.compile(".*\\.|Templates\\$.*");
|
||||
/**
|
||||
* A mapping from template group names to associated template names.
|
||||
*
|
||||
* <p>In effect, the values correspond to nested classes that represent individual Refaster
|
||||
* templates, while the keys correspond to the associated top-level "aggregator" classes.
|
||||
*/
|
||||
private static final ImmutableSetMultimap<String, String> TEMPLATES_BY_GROUP =
|
||||
indexTemplateNamesByGroup(RefasterCheck.ALL_CODE_TRANSFORMERS.get().keySet());
|
||||
|
||||
/** Returns every known template group name as a parameterized test argument. */
|
||||
@SuppressWarnings("UnusedMethod" /* Used as a `@MethodSource`. */)
|
||||
private static Stream<Arguments> templateGroupsUnderTest() {
|
||||
// XXX: Drop the filter once we have added tests for AssertJ!
|
||||
return TEMPLATES_BY_GROUP.keySet().stream().filter(not("AssertJ"::equals)).map(Arguments::of);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns every known (template group name, template name) pair as a parameterized test argument.
|
||||
*/
|
||||
@SuppressWarnings("UnusedMethod" /* Used as a `@MethodSource`. */)
|
||||
private static Stream<Arguments> templatesUnderTest() {
|
||||
// XXX: Drop the filter once we have added tests for AssertJ!
|
||||
return TEMPLATES_BY_GROUP.entries().stream()
|
||||
.filter(e -> !"AssertJ".equals(e.getKey()))
|
||||
.map(e -> arguments(e.getKey(), e.getValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that {@link RefasterCheck#loadAllCodeTransformers} finds at least one code transformer
|
||||
* for all of the {@link #TEMPLATE_GROUPS}.
|
||||
*
|
||||
* <p>This test is just as much about ensuring that {@link #TEMPLATE_GROUPS} is exhaustive, so
|
||||
* that in turn {@link #replacement}'s coverage is exhaustive.
|
||||
*/
|
||||
@Test
|
||||
void loadAllCodeTransformers() {
|
||||
assertThat(TEMPLATES_BY_GROUP.keySet()).hasSameElementsAs(TEMPLATE_GROUPS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies for each of the {@link #TEMPLATE_GROUPS} that the associated code transformers have
|
||||
* the desired effect.
|
||||
*/
|
||||
@MethodSource("templateGroupsUnderTest")
|
||||
@ParameterizedTest
|
||||
void replacement(String group) {
|
||||
verifyRefactoring(group, namePattern(group));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that all loaded Refaster templates are covered by at least one test.
|
||||
*
|
||||
* <p>Note that this doesn't guarantee full coverage: this test cannot ascertain that all {@link
|
||||
* com.google.errorprone.refaster.Refaster#anyOf} branches are tested. Idem for {@link
|
||||
* com.google.errorprone.refaster.annotation.BeforeTemplate} methods in case there are multiple .
|
||||
*/
|
||||
@MethodSource("templatesUnderTest")
|
||||
@ParameterizedTest
|
||||
void coverage(String group, String template) {
|
||||
assertThatCode(() -> verifyRefactoring(group, namePattern(group, template)))
|
||||
.withFailMessage(
|
||||
"Template %s does not affect the tests for group %s; is it tested?", template, group)
|
||||
.isInstanceOf(ComparisonFailure.class);
|
||||
}
|
||||
|
||||
private static ImmutableSetMultimap<String, String> indexTemplateNamesByGroup(
|
||||
ImmutableSet<String> templateNames) {
|
||||
return templateNames.stream()
|
||||
.collect(
|
||||
toImmutableSetMultimap(
|
||||
n -> TEMPLATE_FQCN_TRIM_FOR_GROUP_NAME.matcher(n).replaceAll(""), identity()));
|
||||
}
|
||||
|
||||
private static String namePattern(String groupName, String excludedTemplate) {
|
||||
return "(?!" + Pattern.quote(excludedTemplate) + ')' + namePattern(groupName);
|
||||
}
|
||||
|
||||
private static String namePattern(String groupName) {
|
||||
return Pattern.compile(Pattern.quote(groupName)) + "Templates.*";
|
||||
}
|
||||
|
||||
private void verifyRefactoring(String groupName, String templateNamePattern) {
|
||||
createRestrictedRefactoringTestHelper(templateNamePattern)
|
||||
.addInput(groupName + "TemplatesTestInput.java")
|
||||
.addOutput(groupName + "TemplatesTestOutput.java")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
private BugCheckerRefactoringTestHelper createRestrictedRefactoringTestHelper(
|
||||
String namePattern) {
|
||||
return BugCheckerRefactoringTestHelper.newInstance(
|
||||
RefasterCheck.class, getRefasterTemplateCollectionClass())
|
||||
.setArgs("-XepOpt:Refaster:NamePattern=" + namePattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an arbitrary Refaster template collection class inside the {@code
|
||||
* tech.picnic.errorprone.refastertemplates} package, enabling {@link
|
||||
* BugCheckerRefactoringTestHelper} to load test resources from said package.
|
||||
*/
|
||||
private Class<?> getRefasterTemplateCollectionClass() {
|
||||
try {
|
||||
return Class.forName(
|
||||
"tech.picnic.errorprone.refastertemplates.AssortedTemplates",
|
||||
/* initialize= */ false,
|
||||
getClass().getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalStateException("Failed to load Refaster template collection class", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,9 @@ package tech.picnic.errorprone.bugpatterns;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class RequestMappingAnnotationCheckTest {
|
||||
final class RequestMappingAnnotationTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(RequestMappingAnnotationCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(RequestMappingAnnotation.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -25,6 +25,7 @@ final class RequestMappingAnnotationCheckTest {
|
||||
"import org.springframework.web.bind.annotation.PathVariable;",
|
||||
"import org.springframework.web.bind.annotation.PostMapping;",
|
||||
"import org.springframework.web.bind.annotation.PutMapping;",
|
||||
"import org.springframework.web.bind.annotation.RequestAttribute;",
|
||||
"import org.springframework.web.bind.annotation.RequestBody;",
|
||||
"import org.springframework.web.bind.annotation.RequestHeader;",
|
||||
"import org.springframework.web.bind.annotation.RequestMapping;",
|
||||
@@ -47,12 +48,15 @@ final class RequestMappingAnnotationCheckTest {
|
||||
" A properPathVariable(@PathVariable String param);",
|
||||
"",
|
||||
" @PatchMapping",
|
||||
" A properRequestBody(@RequestBody String body);",
|
||||
" A properRequestAttribute(@RequestAttribute String attribute);",
|
||||
"",
|
||||
" @PostMapping",
|
||||
" A properRequestHeader(@RequestHeader String header);",
|
||||
" A properRequestBody(@RequestBody String body);",
|
||||
"",
|
||||
" @PutMapping",
|
||||
" A properRequestHeader(@RequestHeader String header);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properRequestParam(@RequestParam String param);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
@@ -3,9 +3,9 @@ package tech.picnic.errorprone.bugpatterns;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class RequestParamTypeCheckTest {
|
||||
final class RequestParamTypeTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(RequestParamTypeCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(RequestParamType.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class ScheduledTransactionTraceCheckTest {
|
||||
final class ScheduledTransactionTraceTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(ScheduledTransactionTraceCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(ScheduledTransactionTrace.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(ScheduledTransactionTraceCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(ScheduledTransactionTrace.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class Slf4jLogStatementCheckTest {
|
||||
final class Slf4JLogStatementTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(Slf4jLogStatementCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(Slf4jLogStatement.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(Slf4jLogStatementCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(Slf4jLogStatement.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class SpringMvcAnnotationCheckTest {
|
||||
final class SpringMvcAnnotationTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(SpringMvcAnnotationCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(SpringMvcAnnotation.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(SpringMvcAnnotationCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(SpringMvcAnnotation.class, getClass());
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
@@ -7,28 +7,28 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class StaticImportCheckTest {
|
||||
final class StaticImportTest {
|
||||
private final CompilationTestHelper compilationTestHelper =
|
||||
CompilationTestHelper.newInstance(StaticImportCheck.class, getClass());
|
||||
CompilationTestHelper.newInstance(StaticImport.class, getClass());
|
||||
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
|
||||
BugCheckerRefactoringTestHelper.newInstance(StaticImportCheck.class, getClass());
|
||||
BugCheckerRefactoringTestHelper.newInstance(StaticImport.class, getClass());
|
||||
|
||||
@Test
|
||||
void candidateMethodsAreNotRedundant() {
|
||||
assertThat(StaticImportCheck.STATIC_IMPORT_CANDIDATE_MEMBERS.keySet())
|
||||
.doesNotContainAnyElementsOf(StaticImportCheck.STATIC_IMPORT_CANDIDATE_TYPES);
|
||||
assertThat(StaticImport.STATIC_IMPORT_CANDIDATE_MEMBERS.keySet())
|
||||
.doesNotContainAnyElementsOf(StaticImport.STATIC_IMPORT_CANDIDATE_TYPES);
|
||||
}
|
||||
|
||||
@Test
|
||||
void exemptedMembersAreNotVacuous() {
|
||||
assertThat(StaticImportCheck.STATIC_IMPORT_EXEMPTED_MEMBERS.keySet())
|
||||
.isSubsetOf(StaticImportCheck.STATIC_IMPORT_CANDIDATE_TYPES);
|
||||
assertThat(StaticImport.STATIC_IMPORT_EXEMPTED_MEMBERS.keySet())
|
||||
.isSubsetOf(StaticImport.STATIC_IMPORT_CANDIDATE_TYPES);
|
||||
}
|
||||
|
||||
@Test
|
||||
void exemptedMembersAreNotRedundant() {
|
||||
assertThat(StaticImportCheck.STATIC_IMPORT_EXEMPTED_MEMBERS.values())
|
||||
.doesNotContainAnyElementsOf(StaticImportCheck.STATIC_IMPORT_EXEMPTED_IDENTIFIERS);
|
||||
assertThat(StaticImport.STATIC_IMPORT_EXEMPTED_MEMBERS.values())
|
||||
.doesNotContainAnyElementsOf(StaticImport.STATIC_IMPORT_EXEMPTED_IDENTIFIERS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -180,7 +180,6 @@ final class StaticImportCheckTest {
|
||||
" @DateTimeFormat(iso = ISO.TIME) String time) {}",
|
||||
"",
|
||||
" @BugPattern(",
|
||||
" name = \"TestBugPattern\",",
|
||||
" summary = \"\",",
|
||||
" linkType = BugPattern.LinkType.NONE,",
|
||||
" severity = SeverityLevel.SUGGESTION,",
|
||||
@@ -264,12 +263,7 @@ final class StaticImportCheckTest {
|
||||
" @DateTimeFormat(iso = DATE_TIME) String dateTime,",
|
||||
" @DateTimeFormat(iso = TIME) String time) {}",
|
||||
"",
|
||||
" @BugPattern(",
|
||||
" name = \"TestBugPattern\",",
|
||||
" summary = \"\",",
|
||||
" linkType = NONE,",
|
||||
" severity = SUGGESTION,",
|
||||
" tags = SIMPLIFICATION)",
|
||||
" @BugPattern(summary = \"\", linkType = NONE, severity = SUGGESTION, tags = SIMPLIFICATION)",
|
||||
" static final class TestBugPattern {}",
|
||||
"",
|
||||
" @SpringBootTest(webEnvironment = RANDOM_PORT)",
|
||||
@@ -5,9 +5,9 @@ import static com.google.common.base.Predicates.containsPattern;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class TimeZoneUsageCheckTest {
|
||||
final class TimeZoneUsageTest {
|
||||
private final CompilationTestHelper compilationHelper =
|
||||
CompilationTestHelper.newInstance(TimeZoneUsageCheck.class, getClass())
|
||||
CompilationTestHelper.newInstance(TimeZoneUsage.class, getClass())
|
||||
.expectErrorMessage(
|
||||
"X",
|
||||
containsPattern(
|
||||
@@ -1,4 +1,4 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
@@ -17,10 +17,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
final class MethodMatcherFactoryTest {
|
||||
/** A {@link BugChecker} which flags method invocations matched by {@link #TEST_MATCHER}. */
|
||||
@BugPattern(
|
||||
name = "MatchedMethodsFlagger",
|
||||
severity = SUGGESTION,
|
||||
summary = "Flags methods matched by the test matcher.")
|
||||
@BugPattern(severity = SUGGESTION, summary = "Flags methods matched by the test matcher.")
|
||||
public static final class MatchedMethodsFlagger extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -0,0 +1,81 @@
|
||||
package tech.picnic.errorprone.refastertemplates;
|
||||
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateCollection;
|
||||
|
||||
final class RefasterTemplatesTest {
|
||||
/** The names of all Refaster template groups defined in this module. */
|
||||
private static final ImmutableSet<Class<?>> TEMPLATE_COLLECTIONS =
|
||||
ImmutableSet.of(
|
||||
AssertJTemplates.class,
|
||||
AssertJBigDecimalTemplates.class,
|
||||
AssertJBigIntegerTemplates.class,
|
||||
AssertJBooleanTemplates.class,
|
||||
AssertJByteTemplates.class,
|
||||
AssertJCharSequenceTemplates.class,
|
||||
AssertJDoubleTemplates.class,
|
||||
AssertJEnumerableTemplates.class,
|
||||
AssertJFloatTemplates.class,
|
||||
AssertJIntegerTemplates.class,
|
||||
AssertJLongTemplates.class,
|
||||
AssertJNumberTemplates.class,
|
||||
AssertJMapTemplates.class,
|
||||
AssertJObjectTemplates.class,
|
||||
AssertJOptionalTemplates.class,
|
||||
AssertJShortTemplates.class,
|
||||
AssertJStringTemplates.class,
|
||||
AssertJThrowingCallableTemplates.class,
|
||||
AssortedTemplates.class,
|
||||
BigDecimalTemplates.class,
|
||||
CollectionTemplates.class,
|
||||
ComparatorTemplates.class,
|
||||
DoubleStreamTemplates.class,
|
||||
EqualityTemplates.class,
|
||||
ImmutableListTemplates.class,
|
||||
ImmutableListMultimapTemplates.class,
|
||||
ImmutableMapTemplates.class,
|
||||
ImmutableMultisetTemplates.class,
|
||||
ImmutableSetTemplates.class,
|
||||
ImmutableSetMultimapTemplates.class,
|
||||
ImmutableSortedMapTemplates.class,
|
||||
ImmutableSortedMultisetTemplates.class,
|
||||
ImmutableSortedSetTemplates.class,
|
||||
IntStreamTemplates.class,
|
||||
JUnitTemplates.class,
|
||||
LongStreamTemplates.class,
|
||||
MapEntryTemplates.class,
|
||||
MockitoTemplates.class,
|
||||
MultimapTemplates.class,
|
||||
NullTemplates.class,
|
||||
OptionalTemplates.class,
|
||||
PrimitiveTemplates.class,
|
||||
ReactorTemplates.class,
|
||||
RxJava2AdapterTemplates.class,
|
||||
StreamTemplates.class,
|
||||
StringTemplates.class,
|
||||
TestNGToAssertJTemplates.class,
|
||||
TimeTemplates.class,
|
||||
WebClientTemplates.class);
|
||||
|
||||
// XXX: Create a JUnit extension to automatically discover the template collections in a given
|
||||
// context to make sure the list is exhaustive.
|
||||
private static Stream<Arguments> validateTemplateCollectionTestCases() {
|
||||
// XXX: Drop the filter once we have added tests for AssertJ! We can then also replace this
|
||||
// method with `@ValueSource(classes = {...})`.
|
||||
return TEMPLATE_COLLECTIONS.stream()
|
||||
.filter(not(AssertJTemplates.class::equals))
|
||||
.map(Arguments::arguments);
|
||||
}
|
||||
|
||||
@MethodSource("validateTemplateCollectionTestCases")
|
||||
@ParameterizedTest
|
||||
void validateTemplateCollection(Class<?> clazz) {
|
||||
RefasterTemplateCollection.validate(clazz);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import static org.assertj.core.data.Percentage.withPercentage;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.math.BigDecimal;
|
||||
import org.assertj.core.api.AbstractBigDecimalAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJBigDecimalTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -7,6 +7,7 @@ import static org.assertj.core.data.Percentage.withPercentage;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.math.BigDecimal;
|
||||
import org.assertj.core.api.AbstractBigDecimalAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJBigDecimalTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -7,6 +7,7 @@ import static org.assertj.core.data.Percentage.withPercentage;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.math.BigInteger;
|
||||
import org.assertj.core.api.AbstractBigIntegerAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJBigIntegerTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -7,6 +7,7 @@ import static org.assertj.core.data.Percentage.withPercentage;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.math.BigInteger;
|
||||
import org.assertj.core.api.AbstractBigIntegerAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJBigIntegerTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractBooleanAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJBooleanTemplatesTest implements RefasterTemplateTestCase {
|
||||
AbstractBooleanAssert<?> testAbstractBooleanAssertIsEqualTo() {
|
||||
|
||||
@@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractBooleanAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJBooleanTemplatesTest implements RefasterTemplateTestCase {
|
||||
AbstractBooleanAssert<?> testAbstractBooleanAssertIsEqualTo() {
|
||||
|
||||
@@ -6,6 +6,7 @@ import static org.assertj.core.data.Percentage.withPercentage;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractByteAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJByteTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,7 @@ import static org.assertj.core.data.Percentage.withPercentage;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractByteAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJByteTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJCharSequenceTemplatesTest implements RefasterTemplateTestCase {
|
||||
void testAssertThatCharSequenceIsEmpty() {
|
||||
|
||||
@@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJCharSequenceTemplatesTest implements RefasterTemplateTestCase {
|
||||
void testAssertThatCharSequenceIsEmpty() {
|
||||
|
||||
@@ -6,6 +6,7 @@ import static org.assertj.core.data.Percentage.withPercentage;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractDoubleAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJDoubleTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,7 @@ import static org.assertj.core.data.Percentage.withPercentage;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractDoubleAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJDoubleTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -5,6 +5,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import org.assertj.core.api.EnumerableAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJEnumableTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -5,6 +5,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import org.assertj.core.api.EnumerableAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJEnumableTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,7 @@ import static org.assertj.core.data.Percentage.withPercentage;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractFloatAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJFloatTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,7 @@ import static org.assertj.core.data.Percentage.withPercentage;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractFloatAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJFloatTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,7 @@ import static org.assertj.core.data.Percentage.withPercentage;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractIntegerAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJIntegerTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,7 @@ import static org.assertj.core.data.Percentage.withPercentage;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractIntegerAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJIntegerTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,7 @@ import static org.assertj.core.data.Percentage.withPercentage;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractLongAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJLongTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,7 @@ import static org.assertj.core.data.Percentage.withPercentage;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.assertj.core.api.AbstractLongAssert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
|
||||
|
||||
final class AssertJLongTemplatesTest implements RefasterTemplateTestCase {
|
||||
@Override
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user