Compare commits

...

43 Commits

Author SHA1 Message Date
Stephan Schroevers
62d144550d WIP Try baseline-error-prone 2021-07-25 14:05:28 +02:00
Stephan Schroevers
d014fed400 Deduplicate Refaster templates 2021-07-24 23:20:26 +02:00
Stephan Schroevers
1357f60fbc Introduce refaster-support module
This new module is meant to expose helper logic for use with Refaster
templates. For a start, one can now use e.g.
`@NotMatches(IsArray.class)`.
2021-07-24 23:20:25 +02:00
Stephan Schroevers
03abbbf99c Introduce RefasterAnyOfUsageCheck 2021-07-24 17:08:08 +02:00
Stephan Schroevers
9b845782c2 Cleanup and add package-info.java files 2021-07-24 16:55:46 +02:00
Stephan Schroevers
08ce33fb19 Upgrade, fix typo 2021-07-24 12:18:00 +02:00
Stephan Schroevers
182724bc8e Upgrade dependencies 2021-07-23 08:00:18 +02:00
Stephan Schroevers
e9d361713a Upgrade Error Prone, deduplicate version configuration 2021-07-23 07:55:47 +02:00
Stephan Schroevers
b754880556 Assorted upgrades 2021-07-18 14:59:30 +02:00
Stephan Schroevers
affd5c7b93 Support self-application of the checks 2021-07-18 14:59:30 +02:00
Stephan Schroevers
d86611e66a TimeZoneUsageCheck should not flag Instant.now(clock)
Users _should_ rewrite that to `clock.instant()`, and indeed we have a
Refaster check for that.
2021-07-18 11:04:36 +02:00
Stephan Schroevers
2d6100a679 Further nudge to AssertJ 2021-07-18 10:46:47 +02:00
Stephan Schroevers
912797a55a Bintray is no more; Palantir now deploys to Maven Central 2021-07-18 10:46:47 +02:00
Stephan Schroevers
d097f31124 Assorted upgrades 2021-06-26 10:45:33 +02:00
Stephan Schroevers
eb05582f79 Assorted upgrades 2021-06-19 16:33:24 +02:00
Stephan Schroevers
964fc35b71 Upgrades 2021-05-29 18:04:57 +02:00
Stephan Schroevers
ddc05bf88c Assorted upgrades 2021-05-15 13:07:54 +02:00
Stephan Schroevers
24afa6a755 Some improvements from oss-parent 2021-04-24 00:00:10 +02:00
Stephan Schroevers
8e97121bdf Upgrade dependency 2021-04-23 22:37:19 +02:00
Stephan Schroevers
567c81a93d Upgrade to Error Prone 2.6.0 2021-04-23 22:20:11 +02:00
Stephan Schroevers
c0bfac7b4c Upgrades, some syncing with other parent 2021-04-22 15:10:58 +02:00
Rick Ossendrijver
28138f35eb Assorted upgrades (#15) 2021-04-19 09:51:25 +02:00
Stephan Schroevers
a9b691b856 Assorted upgrades 2021-04-06 17:35:38 +02:00
Ivan Fedorov
acfe87fbc4 Flag Ordering#explicit invocations listing a subset of an enum's values (#14) 2021-03-30 08:19:08 +02:00
Stephan Schroevers
091a6eee7a Fix the fork configuration 2021-03-30 08:04:01 +02:00
Stephan Schroevers
3c06e3ead3 Some consistency changes 2021-03-28 17:28:00 +02:00
Stephan Schroevers
3ecab2f4b9 Reduce memory assigned to Surefire
We may need to reintroduce this change in the future, but for now we can
keep the configuration in sync with other parent POMs.
2021-03-28 15:05:09 +02:00
Stephan Schroevers
4b3e79667d Address deprecations in the upcoming release 2021-03-28 15:05:09 +02:00
Stephan Schroevers
6505535525 Upgrades 2021-03-27 15:28:20 +01:00
Stephan Schroevers
e48bbf3a44 Upgrade to Error Prone 2.5.1 2021-03-27 15:03:50 +01:00
Stephan Schroevers
3391468746 Assorted upgrades 2021-03-20 19:03:37 +01:00
Stephan Schroevers
10172c426d Assorted upgrades 2021-03-14 10:15:00 +01:00
Stephan Schroevers
f2737b4fe9 Fix MissingRefasterAnnotationCheck 2021-03-11 16:37:22 +01:00
Anna Dvorkin
f9a1c82d68 PRP-10968 Flag discouraged time zone-dependent APIs (#9) 2021-03-01 23:08:19 +01:00
Halil İbrahim Şener
cbc886d0c2 PSM-442 Flag likely-wrong @JsonCreator usages (#2) 2021-03-01 18:50:58 +01:00
Rick Ossendrijver
e4e3aded84 Flag methods that appear to lack a Refaster annotation (#13) 2021-02-28 16:29:51 +01:00
Rick Ossendrijver
e84d0e1059 Flag unordered annotation declarations (#11) 2021-02-28 14:42:44 +01:00
Stephan Schroevers
5e763d06d0 Assorted upgrades 2021-02-27 08:22:07 +01:00
Stephan Schroevers
ec05456c96 Choose Arrays.stream over Stream.of 2021-02-27 08:22:07 +01:00
Phil Werli
f53c47b56f PSM-585 Flag controller method parameters lacking annotations (#4) 2021-02-15 20:45:26 +01:00
Rick Ossendrijver
8a4c6e1209 Drop deprecated @BugPattern parameter and fix typos (#12) 2021-02-15 16:41:02 +01:00
Rick Ossendrijver
89033e2216 Add a few ImmutableCollection Refaster templates (#8) 2021-02-14 14:57:00 +01:00
Stephan Schroevers
4dc955a976 Assorted upgrades 2021-02-14 13:40:38 +01:00
104 changed files with 2218 additions and 713 deletions

View File

@@ -11,10 +11,11 @@ install:
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 Error Prone checks
# available from other artifact repositories.
# 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 -s settings.xml
- ./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

View File

@@ -47,6 +47,10 @@
`annotationProcessorPaths` configuration below. -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>refaster-support</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
@@ -102,6 +106,11 @@
<artifactId>swagger-annotations</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
@@ -196,12 +205,28 @@
<artifactId>refaster-resource-compiler</artifactId>
<version>${project.version}</version>
</path>
<path>
<groupId>${project.groupId}</groupId>
<artifactId>refaster-support</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs combine.children="append">
<arg>-Xplugin:RefasterRuleResourceCompiler</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<configuration>
<ignoredUnusedDeclaredDependencies>
<!-- XXX: Figure out why the plugin thinks this
dependency is unused. -->
<ignoredUnusedDeclaredDependency>${project.groupId}:refaster-support</ignoredUnusedDeclaredDependency>
</ignoredUnusedDeclaredDependencies>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>

View File

@@ -0,0 +1,68 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.matchers.Matchers.isType;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
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.AnnotationTree;
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;
import java.util.Map;
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 = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.LIKELY_ERROR)
public final class AmbiguousJsonCreatorCheck 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");
@Override
public Description matchAnnotation(AnnotationTree tree, VisitorState state) {
if (!IS_JSON_CREATOR_ANNOTATION.matches(tree, state)) {
return Description.NO_MATCH;
}
ClassTree clazz = state.findEnclosing(ClassTree.class);
if (clazz == null || clazz.getKind() != Tree.Kind.ENUM) {
return Description.NO_MATCH;
}
MethodTree method = state.findEnclosing(MethodTree.class);
if (method == null || method.getParameters().size() != 1) {
return Description.NO_MATCH;
}
boolean customMode =
ASTHelpers.getAnnotationMirror(tree).getElementValues().entrySet().stream()
.filter(entry -> entry.getKey().getSimpleName().contentEquals("mode"))
.map(Map.Entry::getValue)
.map(AnnotationValue::getValue)
.filter(Symbol.VarSymbol.class::isInstance)
.map(Symbol.VarSymbol.class::cast)
.anyMatch(varSymbol -> !varSymbol.getSimpleName().contentEquals("DEFAULT"));
return customMode
? Description.NO_MATCH
: describeMatch(
tree, SuggestedFix.replace(tree, "@JsonCreator(mode = JsonCreator.Mode.DELEGATING)"));
}
}

View File

@@ -8,7 +8,6 @@ import com.google.auto.service.AutoService;
import com.google.common.collect.Iterables;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.ProvidesFix;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
@@ -31,8 +30,7 @@ import java.util.List;
summary = "Omit `@Autowired` on a class' sole constructor, as it is redundant",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION,
providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION)
tags = StandardTags.SIMPLIFICATION)
public final class AutowiredConstructorCheck extends BugChecker implements ClassTreeMatcher {
private static final long serialVersionUID = 1L;
private static final MultiMatcher<Tree, AnnotationTree> AUTOWIRED_ANNOTATION =

View File

@@ -4,7 +4,6 @@ import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.ProvidesFix;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
@@ -33,8 +32,7 @@ import java.util.regex.Pattern;
summary = "Omit redundant syntax from annotation declarations",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION,
providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION)
tags = StandardTags.SIMPLIFICATION)
public final class CanonicalAnnotationSyntaxCheck extends BugChecker
implements AnnotationTreeMatcher {
private static final long serialVersionUID = 1L;

View File

@@ -28,11 +28,10 @@ import com.sun.tools.javac.code.Symbol.MethodSymbol;
summary = "Empty method can likely be deleted",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION,
providesFix = BugPattern.ProvidesFix.REQUIRES_HUMAN_ATTENTION)
tags = StandardTags.SIMPLIFICATION)
public final class EmptyMethodCheck extends BugChecker implements MethodTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<Tree> HAS_PERMITTED_ANNOTATION =
private static final Matcher<Tree> PERMITTED_ANNOTATION =
annotations(
AT_LEAST_ONE,
anyOf(isType("java.lang.Override"), isType("org.aspectj.lang.annotation.Pointcut")));
@@ -42,7 +41,7 @@ public final class EmptyMethodCheck extends BugChecker implements MethodTreeMatc
if (tree.getBody() == null
|| !tree.getBody().getStatements().isEmpty()
|| ASTHelpers.containsComments(tree, state)
|| HAS_PERMITTED_ANNOTATION.matches(tree, state)) {
|| PERMITTED_ANNOTATION.matches(tree, state)) {
return Description.NO_MATCH;
}

View File

@@ -0,0 +1,91 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.ImmutableSetMultimap.toImmutableSetMultimap;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import static java.util.stream.Collectors.collectingAndThen;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
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.matchers.Matcher;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
/**
* A {@link BugChecker} which flags {@link Ordering#explicit(Object, Object[])}} invocations listing
* a subset of an enum type's values.
*/
@AutoService(BugChecker.class)
@BugPattern(
name = "ExplicitEnumOrdering",
summary = "Make sure `Ordering#explicit` lists all of an enum's values",
linkType = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.FRAGILE_CODE)
public final class ExplicitEnumOrderingCheck extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> EXPLICIT_ORDERING =
staticMethod().onClass(Ordering.class.getName()).named("explicit");
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (!EXPLICIT_ORDERING.matches(tree, state)) {
return Description.NO_MATCH;
}
ImmutableSet<String> missingEnumValues = getMissingEnumValues(tree.getArguments());
if (missingEnumValues.isEmpty()) {
return Description.NO_MATCH;
}
return buildDescription(tree)
.setMessage(
String.format(
"Explicit ordering lacks some enum values: %s",
String.join(", ", missingEnumValues)))
.build();
}
private static ImmutableSet<String> getMissingEnumValues(
List<? extends ExpressionTree> expressions) {
return expressions.stream()
.map(ASTHelpers::getSymbol)
.filter(Symbol::isEnum)
.collect(
collectingAndThen(
toImmutableSetMultimap(Symbol::asType, Symbol::toString),
ExplicitEnumOrderingCheck::getMissingEnumValues));
}
private static ImmutableSet<String> getMissingEnumValues(
ImmutableSetMultimap<Type, String> valuesByType) {
return Multimaps.asMap(valuesByType).entrySet().stream()
.flatMap(e -> getMissingEnumValues(e.getKey(), e.getValue()))
.collect(toImmutableSet());
}
private static Stream<String> getMissingEnumValues(Type enumType, Set<String> values) {
Symbol.TypeSymbol typeSymbol = enumType.asElement();
return Sets.difference(ASTHelpers.enumValues(typeSymbol), values).stream()
.map(v -> String.format("%s.%s", typeSymbol.getSimpleName(), v));
}
}

View File

@@ -43,15 +43,15 @@ public final class JUnitMethodDeclarationCheck extends BugChecker implements Met
private static final String TEST_PREFIX = "test";
private static final ImmutableSet<Modifier> ILLEGAL_MODIFIERS =
ImmutableSet.of(Modifier.PRIVATE, Modifier.PROTECTED, Modifier.PUBLIC);
private static final MultiMatcher<MethodTree, AnnotationTree> IS_OVERRIDE_METHOD =
private static final MultiMatcher<MethodTree, AnnotationTree> OVERRIDE_METHOD =
annotations(AT_LEAST_ONE, isType("java.lang.Override"));
private static final MultiMatcher<MethodTree, AnnotationTree> IS_TEST_METHOD =
private static final MultiMatcher<MethodTree, AnnotationTree> TEST_METHOD =
annotations(
AT_LEAST_ONE,
anyOf(
isType("org.junit.jupiter.api.Test"),
hasMetaAnnotation("org.junit.jupiter.api.TestTemplate")));
private static final MultiMatcher<MethodTree, AnnotationTree> IS_SETUP_OR_TEARDOWN_METHOD =
private static final MultiMatcher<MethodTree, AnnotationTree> SETUP_OR_TEARDOWN_METHOD =
annotations(
AT_LEAST_ONE,
anyOf(
@@ -64,12 +64,12 @@ public final class JUnitMethodDeclarationCheck extends BugChecker implements Met
public Description matchMethod(MethodTree tree, VisitorState state) {
// XXX: Perhaps we should also skip analysis of non-`private` non-`final` methods in abstract
// classes?
if (IS_OVERRIDE_METHOD.matches(tree, state)) {
if (OVERRIDE_METHOD.matches(tree, state)) {
return Description.NO_MATCH;
}
boolean isTestMethod = IS_TEST_METHOD.matches(tree, state);
if (!isTestMethod && !IS_SETUP_OR_TEARDOWN_METHOD.matches(tree, state)) {
boolean isTestMethod = TEST_METHOD.matches(tree, state);
if (!isTestMethod && !SETUP_OR_TEARDOWN_METHOD.matches(tree, state)) {
return Description.NO_MATCH;
}
@@ -102,7 +102,7 @@ public final class JUnitMethodDeclarationCheck extends BugChecker implements Met
private static Matcher<AnnotationTree> hasMetaAnnotation(String annotationClassName) {
TypePredicate typePredicate = hasAnnotation(annotationClassName);
return (tree, state) -> {
Symbol sym = ASTHelpers.getDeclaredSymbol(tree);
Symbol sym = ASTHelpers.getSymbol(tree);
return sym != null && typePredicate.apply(sym.type, state);
};
}

View File

@@ -1,5 +1,6 @@
package tech.picnic.errorprone.bugpatterns;
import static java.util.Comparator.comparing;
import static java.util.Comparator.naturalOrder;
import static java.util.stream.Collectors.joining;
@@ -9,7 +10,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.ProvidesFix;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.ErrorProneFlags;
@@ -32,7 +32,6 @@ import com.sun.source.tree.Tree.Kind;
import com.sun.source.util.TreeScanner;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
@@ -51,8 +50,7 @@ import java.util.stream.Stream;
summary = "Where possible, sort annotation array attributes lexicographically",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.STYLE,
providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION)
tags = StandardTags.STYLE)
public final class LexicographicalAnnotationAttributeListingCheck extends BugChecker
implements AnnotationTreeMatcher {
private static final long serialVersionUID = 1L;
@@ -155,7 +153,7 @@ public final class LexicographicalAnnotationAttributeListingCheck extends BugChe
// XXX: Perhaps we should use `Collator` with `.setStrength(Collator.PRIMARY)` and
// `getCollationKey`. Not clear whether that's worth the hassle at this point.
return ImmutableList.sortedCopyOf(
Comparator.comparing(
comparing(
e -> getStructure(e, state),
Comparators.lexicographical(
Comparators.lexicographical(

View File

@@ -0,0 +1,79 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static java.util.Comparator.comparing;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
import com.google.errorprone.fixes.Fix;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.MethodTree;
import java.util.List;
import java.util.Optional;
/**
* A {@link BugChecker} that flags annotations that are not lexicographically sorted.
*
* <p>The idea behind this checker is that maintaining a sorted sequence simplifies conflict
* resolution, and can even avoid it if two branches add the same annotation.
*/
@AutoService(BugChecker.class)
@BugPattern(
name = "LexicographicalAnnotationListing",
summary = "Sort annotations lexicographically where possible",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.STYLE)
public final class LexicographicalAnnotationListingCheck extends BugChecker
implements MethodTreeMatcher {
private static final long serialVersionUID = 1L;
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
List<? extends AnnotationTree> originalOrdering = tree.getModifiers().getAnnotations();
if (originalOrdering.size() < 2) {
return Description.NO_MATCH;
}
ImmutableList<? extends AnnotationTree> sortedAnnotations = sort(originalOrdering, state);
if (originalOrdering.equals(sortedAnnotations)) {
return Description.NO_MATCH;
}
Optional<Fix> fix = tryFixOrdering(originalOrdering, sortedAnnotations, state);
Description.Builder description = buildDescription(tree);
fix.ifPresent(description::addFix);
return description.build();
}
private static ImmutableList<? extends AnnotationTree> sort(
List<? extends AnnotationTree> annotations, VisitorState state) {
return annotations.stream()
.sorted(comparing(annotation -> Util.treeToString(annotation, state)))
.collect(toImmutableList());
}
private static Optional<Fix> tryFixOrdering(
List<? extends AnnotationTree> originalAnnotations,
ImmutableList<? extends AnnotationTree> sortedAnnotations,
VisitorState state) {
return Streams.zip(
originalAnnotations.stream(),
sortedAnnotations.stream(),
(original, replacement) ->
SuggestedFix.builder().replace(original, Util.treeToString(replacement, state)))
.reduce(SuggestedFix.Builder::merge)
.map(SuggestedFix.Builder::build);
}
}

View File

@@ -7,7 +7,6 @@ import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.ProvidesFix;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
@@ -48,14 +47,15 @@ import javax.lang.model.element.Name;
// black-and-white. Maybe we can more closely approximate it?
// XXX: With Java 9's introduction of `Predicate.not`, we could write many lambda expressions to
// `not(some::reference)`.
// XXX: This check is extremely inefficient due to its reliance on `SuggestedFixes.compilesWithFix`.
// 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 = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.STYLE,
providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION)
tags = StandardTags.STYLE)
public final class MethodReferenceUsageCheck extends BugChecker
implements LambdaExpressionTreeMatcher {
private static final long serialVersionUID = 1L;

View File

@@ -0,0 +1,55 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE;
import static com.google.errorprone.matchers.Matchers.annotations;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.isType;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.MultiMatcher;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
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 = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.LIKELY_ERROR)
public final class MissingRefasterAnnotationCheck extends BugChecker implements ClassTreeMatcher {
private static final long serialVersionUID = 1L;
private static final MultiMatcher<Tree, AnnotationTree> REFASTER_ANNOTATION =
annotations(
AT_LEAST_ONE,
anyOf(
isType("com.google.errorprone.refaster.annotation.Placeholder"),
isType("com.google.errorprone.refaster.annotation.BeforeTemplate"),
isType("com.google.errorprone.refaster.annotation.AfterTemplate")));
@Override
public Description matchClass(ClassTree tree, VisitorState state) {
long methodTypes =
tree.getMembers().stream()
.filter(member -> member.getKind() == Tree.Kind.METHOD)
.map(MethodTree.class::cast)
.filter(method -> !ASTHelpers.isGeneratedConstructor(method))
.map(method -> REFASTER_ANNOTATION.matches(method, state))
.distinct()
.count();
return methodTypes < 2 ? Description.NO_MATCH : buildDescription(tree).build();
}
}

View File

@@ -9,7 +9,6 @@ import com.google.auto.service.AutoService;
import com.google.common.base.VerifyException;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.ProvidesFix;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
@@ -47,12 +46,11 @@ import java.util.function.Function;
+ " of the provided function",
linkType = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.PERFORMANCE,
providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION)
tags = StandardTags.PERFORMANCE)
public final class PrimitiveComparisonCheck extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> STATIC_COMPARISION_METHOD =
private static final Matcher<ExpressionTree> STATIC_COMPARISON_METHOD =
anyOf(
staticMethod()
.onClass(Comparator.class.getName())
@@ -61,7 +59,7 @@ public final class PrimitiveComparisonCheck extends BugChecker
.onClass(Comparator.class.getName())
.named("comparing")
.withParameters(Function.class.getName()));
private static final Matcher<ExpressionTree> INSTANCE_COMPARISION_METHOD =
private static final Matcher<ExpressionTree> INSTANCE_COMPARISON_METHOD =
anyOf(
instanceMethod()
.onDescendantOf(Comparator.class.getName())
@@ -73,8 +71,8 @@ public final class PrimitiveComparisonCheck extends BugChecker
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
boolean isStatic = STATIC_COMPARISION_METHOD.matches(tree, state);
if (!isStatic && !INSTANCE_COMPARISION_METHOD.matches(tree, state)) {
boolean isStatic = STATIC_COMPARISON_METHOD.matches(tree, state);
if (!isStatic && !INSTANCE_COMPARISON_METHOD.matches(tree, state)) {
return Description.NO_MATCH;
}

View File

@@ -2,7 +2,7 @@ package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.matchers.Matchers.allOf;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.isNonNull;
import static com.google.errorprone.matchers.Matchers.isNonNullUsingDataflow;
import static com.google.errorprone.matchers.Matchers.isSameType;
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
import static com.google.errorprone.matchers.Matchers.not;
@@ -13,7 +13,6 @@ import com.google.auto.service.AutoService;
import com.google.common.collect.Iterables;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.ProvidesFix;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.ErrorProneFlags;
@@ -50,8 +49,7 @@ import java.util.Optional;
summary = "Avoid redundant string conversions when possible",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION,
providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION)
tags = StandardTags.SIMPLIFICATION)
public final class RedundantStringConversionCheck extends BugChecker
implements BinaryTreeMatcher, CompoundAssignmentTreeMatcher, MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
@@ -66,7 +64,8 @@ public final class RedundantStringConversionCheck extends BugChecker
private static final Matcher<ExpressionTree> MARKER = isSubtypeOf("org.slf4j.Marker");
private static final Matcher<ExpressionTree> STRING = isSameType(String.class);
private static final Matcher<ExpressionTree> THROWABLE = isSubtypeOf(Throwable.class);
private static final Matcher<ExpressionTree> NON_NULL_STRING = allOf(STRING, isNonNull());
private static final Matcher<ExpressionTree> NON_NULL_STRING =
allOf(STRING, isNonNullUsingDataflow());
private static final Matcher<ExpressionTree> NOT_FORMATTABLE =
not(isSubtypeOf(Formattable.class));
private static final Matcher<ExpressionTree> WELL_KNOWN_STRING_CONVERSION_METHODS =

View File

@@ -0,0 +1,57 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
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.refaster.Refaster;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
/**
* A {@link BugChecker} which flags unnecessary {@link Refaster#anyOf(Object[])} usages.
*
* <p>Note that this logic can't be implemented as a Refaster template, as the {@link Refaster}
* class is treated specially.
*/
@AutoService(BugChecker.class)
@BugPattern(
name = "RefasterAnyOfUsage",
summary = "`Refaster#anyOf` should be passed at least two parameters",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION)
public final class RefasterAnyOfUsageCheck 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");
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (REFASTER_ANY_OF.matches(tree, state)) {
switch (tree.getArguments().size()) {
case 0:
// We can't safely fix this case; dropping the expression may produce non-compilable code.
return describeMatch(tree);
case 1:
return describeMatch(
tree,
SuggestedFix.replace(tree, Util.treeToString(tree.getArguments().get(0), state)));
default:
/* Handled below. */
}
}
return Description.NO_MATCH;
}
}

View File

@@ -2,21 +2,24 @@ package tech.picnic.errorprone.bugpatterns;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableRangeSet.toImmutableRangeSet;
import static java.util.Objects.requireNonNullElseGet;
import static java.util.function.Predicate.not;
import com.google.auto.service.AutoService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableRangeSet;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
import com.google.common.collect.TreeRangeSet;
import com.google.common.reflect.ClassPath;
import com.google.common.reflect.ClassPath.ResourceInfo;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.ProvidesFix;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.CodeTransformer;
@@ -40,8 +43,8 @@ import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.stream.Stream;
@@ -59,12 +62,15 @@ import java.util.stream.Stream;
summary = "Write idiomatic code when possible",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION,
providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION)
tags = StandardTags.SIMPLIFICATION)
public final class RefasterCheck extends BugChecker implements CompilationUnitTreeMatcher {
private static final long serialVersionUID = 1L;
private static final String REFASTER_TEMPLATE_SUFFIX = ".refaster";
private static final String INCLUDED_TEMPLATES_PATTERN_FLAG = "Refaster:NamePattern";
private static final long serialVersionUID = 1L;
@VisibleForTesting
static final Supplier<ImmutableListMultimap<String, CodeTransformer>> ALL_CODE_TRANSFORMERS =
Suppliers.memoize(RefasterCheck::loadAllCodeTransformers);
private final CodeTransformer codeTransformer;
@@ -79,20 +85,21 @@ public final class RefasterCheck extends BugChecker implements CompilationUnitTr
* @param flags Any provided command line flags.
*/
public RefasterCheck(ErrorProneFlags flags) {
codeTransformer = createCompositeCodeTransformer(flags, loadAllCodeTransformers());
}
@VisibleForTesting
RefasterCheck(
ErrorProneFlags flags, ImmutableListMultimap<String, CodeTransformer> allTransformers) {
codeTransformer = createCompositeCodeTransformer(flags, allTransformers);
codeTransformer = createCompositeCodeTransformer(flags);
}
@Override
public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) {
/* First, collect all matches. */
List<Description> matches = new ArrayList<>();
codeTransformer.apply(state.getPath(), new SubContext(state.context), matches::add);
try {
codeTransformer.apply(state.getPath(), new SubContext(state.context), matches::add);
} catch (LinkageError e) {
// XXX: This `try/catch` block handles the issue described and resolved in
// https://github.com/google/error-prone/pull/2456. Drop this block once that change is
// released.
return Description.NO_MATCH;
}
/* Then apply them. */
applyMatches(matches, ((JCCompilationUnit) tree).endPositions, state);
@@ -143,6 +150,7 @@ public final class RefasterCheck extends BugChecker implements CompilationUnitTr
Description description, EndPosTable endPositions) {
return getReplacements(description, endPositions)
.map(Replacement::range)
.filter(not(Range::isEmpty))
.collect(toImmutableRangeSet());
}
@@ -151,8 +159,8 @@ public final class RefasterCheck extends BugChecker implements CompilationUnitTr
return description.fixes.stream().flatMap(fix -> fix.getReplacements(endPositions).stream());
}
private static CodeTransformer createCompositeCodeTransformer(
ErrorProneFlags flags, ImmutableListMultimap<String, CodeTransformer> allTransformers) {
private static CodeTransformer createCompositeCodeTransformer(ErrorProneFlags flags) {
ImmutableListMultimap<String, CodeTransformer> allTransformers = ALL_CODE_TRANSFORMERS.get();
return CompositeCodeTransformer.compose(
flags
.get(INCLUDED_TEMPLATES_PATTERN_FLAG)
@@ -169,8 +177,7 @@ public final class RefasterCheck extends BugChecker implements CompilationUnitTr
.collect(toImmutableList());
}
@VisibleForTesting
static ImmutableListMultimap<String, CodeTransformer> loadAllCodeTransformers() {
private static ImmutableListMultimap<String, CodeTransformer> loadAllCodeTransformers() {
ImmutableListMultimap.Builder<String, CodeTransformer> transformers =
ImmutableListMultimap.builder();
@@ -188,8 +195,8 @@ public final class RefasterCheck extends BugChecker implements CompilationUnitTr
private static ImmutableSet<ResourceInfo> getClassPathResources() {
try {
return ClassPath.from(
Objects.requireNonNullElseGet(
RefasterCheck.class.getClassLoader(), () -> ClassLoader.getSystemClassLoader()))
requireNonNullElseGet(
RefasterCheck.class.getClassLoader(), ClassLoader::getSystemClassLoader))
.getResources();
} catch (IOException e) {
throw new UncheckedIOException("Failed to scan classpath for resources", e);
@@ -211,7 +218,9 @@ public final class RefasterCheck extends BugChecker implements CompilationUnitTr
private static Optional<CodeTransformer> loadCodeTransformer(ResourceInfo resource) {
try (InputStream in = resource.url().openStream();
ObjectInputStream ois = new ObjectInputStream(in)) {
return Optional.of((CodeTransformer) ois.readObject());
@SuppressWarnings("BanSerializableRead" /* Part of the Refaster API. */)
CodeTransformer codeTransformer = (CodeTransformer) ois.readObject();
return Optional.of(codeTransformer);
} catch (NoSuchElementException e) {
/* For some reason we can't load the resource. Skip it. */
// XXX: Should we log this?

View File

@@ -0,0 +1,88 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.ALL;
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE;
import static com.google.errorprone.matchers.Matchers.annotations;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.isSameType;
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
import static com.google.errorprone.matchers.Matchers.isType;
import static com.google.errorprone.matchers.Matchers.methodHasParameters;
import static com.google.errorprone.matchers.Matchers.not;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
/**
* A {@link BugChecker} which flags {@code @RequestMapping} methods that have one or more parameters
* that appear to lack a relevant annotation.
*
* <p>Matched mappings are {@code @{Delete,Get,Patch,Post,Put,Request}Mapping}.
*/
@AutoService(BugChecker.class)
@BugPattern(
name = "RequestMappingAnnotation",
summary = "Make sure all `@RequestMapping` method parameters are annotated",
linkType = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.LIKELY_ERROR)
public final class RequestMappingAnnotationCheck 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
// documentation.
private static final Matcher<Tree> HAS_MAPPING_ANNOTATION =
annotations(
AT_LEAST_ONE,
anyOf(
isType(ANN_PACKAGE_PREFIX + "DeleteMapping"),
isType(ANN_PACKAGE_PREFIX + "GetMapping"),
isType(ANN_PACKAGE_PREFIX + "PatchMapping"),
isType(ANN_PACKAGE_PREFIX + "PostMapping"),
isType(ANN_PACKAGE_PREFIX + "PutMapping"),
isType(ANN_PACKAGE_PREFIX + "RequestMapping")));
// XXX: Add other parameters as necessary. See
// https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-arguments.
private static final Matcher<MethodTree> LACKS_PARAMETER_ANNOTATION =
not(
methodHasParameters(
ALL,
anyOf(
annotations(
AT_LEAST_ONE,
anyOf(
isType(ANN_PACKAGE_PREFIX + "PathVariable"),
isType(ANN_PACKAGE_PREFIX + "RequestBody"),
isType(ANN_PACKAGE_PREFIX + "RequestHeader"),
isType(ANN_PACKAGE_PREFIX + "RequestParam"))),
isSameType("java.io.InputStream"),
isSameType("javax.servlet.http.HttpServletRequest"),
isSameType("javax.servlet.http.HttpServletResponse"),
isSameType("org.springframework.http.HttpMethod"),
isSubtypeOf("org.springframework.web.context.request.WebRequest"))));
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
// XXX: Auto-add `@RequestParam` where applicable.
// XXX: What about the `PurchasingProposerRequestParams` in POM? Implies `@RequestBody`?
// (Documentation doesn't mention this, IIUC.)
return HAS_MAPPING_ANNOTATION.matches(tree, state)
&& LACKS_PARAMETER_ANNOTATION.matches(tree, state)
? buildDescription(tree)
.setMessage(
"Not all parameters of this request mapping method are annotated; this may be a mistake. "
+ "If the unannotated parameters represent query string parameters, annotate them with `@RequestParam`.")
.build()
: Description.NO_MATCH;
}
}

View File

@@ -8,7 +8,6 @@ import com.google.auto.service.AutoService;
import com.google.common.base.Splitter;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.ProvidesFix;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
@@ -36,8 +35,7 @@ import java.util.Optional;
summary = "Make sure SLF4J log statements contain proper placeholders with matching arguments",
linkType = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.LIKELY_ERROR,
providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION)
tags = StandardTags.LIKELY_ERROR)
public final class Slf4jLogStatementCheck extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;

View File

@@ -10,7 +10,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.ProvidesFix;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
@@ -38,8 +37,7 @@ import java.util.Optional;
"Prefer the conciseness of `@{Get,Put,Post,Delete,Patch}Mapping` over `@RequestMapping`",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION,
providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION)
tags = StandardTags.SIMPLIFICATION)
public final class SpringMvcAnnotationCheck extends BugChecker implements AnnotationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final String ANN_PACKAGE_PREFIX = "org.springframework.web.bind.annotation.";

View File

@@ -1,5 +1,7 @@
package tech.picnic.errorprone.bugpatterns;
import static java.util.Objects.requireNonNull;
import com.google.auto.service.AutoService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
@@ -20,7 +22,6 @@ import com.google.errorprone.matchers.Description;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
import java.util.Objects;
import java.util.Optional;
/** A {@link BugChecker} which flags methods that can and should be statically imported. */
@@ -44,8 +45,7 @@ import java.util.Optional;
summary = "Method should be statically imported",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION,
providesFix = BugPattern.ProvidesFix.REQUIRES_HUMAN_ATTENTION)
tags = StandardTags.SIMPLIFICATION)
public final class StaticImportCheck extends BugChecker implements MemberSelectTreeMatcher {
private static final long serialVersionUID = 1L;
@@ -141,8 +141,7 @@ public final class StaticImportCheck extends BugChecker implements MemberSelectT
private static boolean isCandidate(VisitorState state) {
Tree parentTree =
Objects.requireNonNull(
state.getPath().getParentPath(), "MemberSelectTree lacks enclosing node")
requireNonNull(state.getPath().getParentPath(), "MemberSelectTree lacks enclosing node")
.getLeaf();
switch (parentTree.getKind()) {
case IMPORT:

View File

@@ -0,0 +1,62 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
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.matchers.Matcher;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import java.time.Clock;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
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 = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.FRAGILE_CODE)
public final class TimeZoneUsageCheck extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> BANNED_TIME_METHOD =
anyOf(
instanceMethod().onDescendantOf(Clock.class.getName()).namedAnyOf("getZone", "withZone"),
staticMethod()
.onClass(Clock.class.getName())
.namedAnyOf(
"system",
"systemDefaultZone",
"systemUTC",
"tickMillis",
"tickMinutes",
"tickSeconds"),
staticMethod()
.onClassAny(
LocalDate.class.getName(),
LocalDateTime.class.getName(),
LocalTime.class.getName())
.named("now"),
staticMethod().onClassAny(Instant.class.getName()).named("now").withParameters());
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
return BANNED_TIME_METHOD.matches(tree, state)
? buildDescription(tree).build()
: Description.NO_MATCH;
}
}

View File

@@ -1,7 +1,4 @@
/** Picnic Error Prone Contrib checks. */
@CheckReturnValue
@ParametersAreNonnullByDefault
@com.google.errorprone.annotations.CheckReturnValue
@javax.annotation.ParametersAreNonnullByDefault
package tech.picnic.errorprone.bugpatterns;
import com.google.errorprone.annotations.CheckReturnValue;
import javax.annotation.ParametersAreNonnullByDefault;

View File

@@ -16,6 +16,7 @@ import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.NotMatches;
import com.google.errorprone.refaster.annotation.Repeated;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.ArrayList;
@@ -51,6 +52,7 @@ import org.assertj.core.api.ObjectEnumerableAssert;
import org.assertj.core.api.OptionalDoubleAssert;
import org.assertj.core.api.OptionalIntAssert;
import org.assertj.core.api.OptionalLongAssert;
import tech.picnic.errorprone.refaster.util.IsArray;
/** Refaster templates related to AssertJ expressions and statements. */
// XXX: Most `AbstractIntegerAssert` rules can also be applied for other primitive types. Generate
@@ -338,8 +340,14 @@ final class AssertJTemplates {
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element))),
iterAssert.containsExactlyInAnyOrder(element));
ImmutableMultiset.of(element))));
}
@BeforeTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> before2(
ObjectEnumerableAssert<?, S> iterAssert, @NotMatches(IsArray.class) T element) {
return iterAssert.containsExactlyInAnyOrder(element);
}
@AfterTemplate
@@ -352,13 +360,12 @@ final class AssertJTemplates {
static final class ObjectEnumerableContainsOneDistinctElement<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T element) {
return Refaster.anyOf(
iterAssert.hasSameElementsAs(
Refaster.anyOf(
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element))));
return iterAssert.hasSameElementsAs(
Refaster.anyOf(
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element)));
}
@AfterTemplate
@@ -371,13 +378,12 @@ final class AssertJTemplates {
static final class ObjectEnumerableIsSubsetOfOneElement<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T element) {
return Refaster.anyOf(
iterAssert.isSubsetOf(
Refaster.anyOf(
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element))));
return iterAssert.isSubsetOf(
Refaster.anyOf(
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element)));
}
@AfterTemplate
@@ -395,8 +401,8 @@ final class AssertJTemplates {
@BeforeTemplate
void before(Iterable<E> iterable) {
Refaster.anyOf(
assertThat(iterable).hasSize(0),
assertThat(iterable.iterator().hasNext()).isFalse(),
assertThat(Iterables.size(iterable)).isEqualTo(0),
assertThat(Iterables.size(iterable)).isEqualTo(0L),
assertThat(Iterables.size(iterable)).isNotPositive());
}
@@ -405,7 +411,6 @@ final class AssertJTemplates {
void before(Collection<E> iterable) {
Refaster.anyOf(
assertThat(iterable.isEmpty()).isTrue(),
assertThat(iterable.size()).isEqualTo(0),
assertThat(iterable.size()).isEqualTo(0L),
assertThat(iterable.size()).isNotPositive());
}
@@ -602,8 +607,8 @@ final class AssertJTemplates {
@BeforeTemplate
void before(Map<K, V> map) {
Refaster.anyOf(
assertThat(map).hasSize(0),
assertThat(map.isEmpty()).isTrue(),
assertThat(map.size()).isEqualTo(0),
assertThat(map.size()).isEqualTo(0L),
assertThat(map.size()).isNotPositive());
}
@@ -775,18 +780,21 @@ final class AssertJTemplates {
// XXX: This rule assumes the `collector` doesn't completely discard certain values.
static final class AssertThatStreamContainsAnyOfVarArgs<S, T extends S, U extends T> {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsAnyOf" /* Varargs converted to array. */)
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector)).containsAnyOf(Refaster.asVarargs(elements));
}
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsAnyOf" /* Varargs converted to array. */)
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector)).containsAnyOf(Refaster.asVarargs(elements));
}
@AfterTemplate
@SuppressWarnings("ObjectEnumerableContainsOneElement" /* Not a true singleton. */)
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).containsAnyOf(elements);
@@ -838,12 +846,14 @@ final class AssertJTemplates {
// XXX: This rule assumes the `collector` doesn't completely discard certain values.
static final class AssertThatStreamContainsVarArgs<S, T extends S, U extends T> {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContains" /* Varargs converted to array. */)
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector)).contains(Refaster.asVarargs(elements));
}
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContains" /* Varargs converted to array. */)
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector)).contains(Refaster.asVarargs(elements));
@@ -889,6 +899,7 @@ final class AssertJTemplates {
// XXX: This rule assumes the `collector` doesn't completely discard certain values.
static final class AssertThatStreamContainsExactlyVarargs<S, T extends S, U extends T> {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsExactly" /* Varargs converted to array. */)
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector)).containsExactly(Refaster.asVarargs(elements));
@@ -947,6 +958,7 @@ final class AssertJTemplates {
// XXX: This rule assumes the `collector` doesn't completely discard certain values.
static final class AssertThatStreamContainsExactlyInAnyOrderVarArgs<S, T extends S, U extends T> {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsExactlyInAnyOrder" /* Varargs converted to array. */)
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector))
@@ -954,6 +966,7 @@ final class AssertJTemplates {
}
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsExactlyInAnyOrder" /* Varargs converted to array. */)
IterableAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends Multiset<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector))
@@ -961,6 +974,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@SuppressWarnings("ObjectEnumerableContainsExactlyOneElement" /* Not a true singleton. */)
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).containsExactlyInAnyOrder(elements);
@@ -991,12 +1005,14 @@ final class AssertJTemplates {
// XXX: This rule assumes the `collector` doesn't completely discard certain values.
static final class AssertThatStreamContainsSequenceVarArgs<S, T extends S, U extends T> {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsSequence" /* Varargs converted to array. */)
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector)).containsSequence(Refaster.asVarargs(elements));
}
@AfterTemplate
@SuppressWarnings("ObjectEnumerableContainsOneElement" /* Not a true singleton. */)
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).containsSequence(elements);
@@ -1027,6 +1043,7 @@ final class AssertJTemplates {
// XXX: This rule assumes the `collector` doesn't completely discard certain values.
static final class AssertThatStreamContainsSubsequenceVarArgs<S, T extends S, U extends T> {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsSubsequence" /* Varargs converted to array. */)
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector))
@@ -1034,6 +1051,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@SuppressWarnings("ObjectEnumerableContainsOneElement" /* Not a true singleton. */)
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).containsSubsequence(elements);
@@ -1085,12 +1103,14 @@ final class AssertJTemplates {
// XXX: This rule assumes the `collector` doesn't completely discard certain values.
static final class AssertThatStreamDoesNotContainVarArgs<S, T extends S, U extends T> {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamDoesNotContain" /* Varargs converted to array. */)
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector)).doesNotContain(Refaster.asVarargs(elements));
}
@BeforeTemplate
@SuppressWarnings("AssertThatStreamDoesNotContain" /* Varargs converted to array. */)
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector)).doesNotContain(Refaster.asVarargs(elements));
@@ -1127,6 +1147,7 @@ final class AssertJTemplates {
// XXX: This rule assumes the `collector` doesn't completely discard certain values.
static final class AssertThatStreamDoesNotContainSequenceVarArgs<S, T extends S, U extends T> {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamDoesNotContainSequence" /* Varargs converted to array. */)
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector))
@@ -1134,6 +1155,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@SuppressWarnings("ObjectEnumerableDoesNotContainOneElement" /* Not a true singleton. */)
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).doesNotContainSequence(elements);
@@ -1185,12 +1207,14 @@ final class AssertJTemplates {
// XXX: This rule assumes the `collector` doesn't completely discard certain values.
static final class AssertThatStreamContainsOnlyVarArgs<S, T extends S, U extends T> {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsOnly" /* Varargs converted to array. */)
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector)).containsOnly(Refaster.asVarargs(elements));
}
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsOnly" /* Varargs converted to array. */)
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector)).containsOnly(Refaster.asVarargs(elements));
@@ -1239,12 +1263,14 @@ final class AssertJTemplates {
// XXX: This rule assumes the `collector` doesn't completely discard certain values.
static final class AssertThatStreamIsSubsetOfVarArgs<S, T extends S, U extends T> {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamIsSubsetOf" /* Varargs converted to array. */)
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector)).isSubsetOf(Refaster.asVarargs(elements));
}
@BeforeTemplate
@SuppressWarnings("AssertThatStreamIsSubsetOf" /* Varargs converted to array. */)
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector)).isSubsetOf(Refaster.asVarargs(elements));

View File

@@ -1,9 +1,10 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.common.base.Preconditions.checkElementIndex;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Sets.toImmutableEnumSet;
import static java.util.Objects.checkIndex;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@@ -38,12 +39,12 @@ final class AssortedTemplates {
static final class CheckIndex {
@BeforeTemplate
int before(int index, int size) {
return Preconditions.checkElementIndex(index, size);
return checkElementIndex(index, size);
}
@AfterTemplate
int after(int index, int size) {
return Objects.checkIndex(index, size);
return checkIndex(index, size);
}
}
@@ -62,14 +63,14 @@ final class AssortedTemplates {
}
static final class MapGetOrNull<K, V, L> {
@Nullable
@BeforeTemplate
@Nullable
V before(Map<K, V> map, L key) {
return map.getOrDefault(key, null);
}
@Nullable
@AfterTemplate
@Nullable
V after(Map<K, V> map, L key) {
return map.get(key);
}
@@ -107,8 +108,8 @@ final class AssortedTemplates {
Streams.stream(iterator).findAny().orElse(defaultValue));
}
@Nullable
@AfterTemplate
@Nullable
T after(Iterator<T> iterator, T defaultValue) {
return Iterators.getNext(iterator, defaultValue);
}
@@ -256,11 +257,6 @@ final class AssortedTemplates {
//
// @BeforeTemplate
// void before(Supplier<T> supplier) {
// anyStatement(supplier::get);
// }
//
// @BeforeTemplate
// void before2(Supplier<T> supplier) {
// anyStatement(() -> supplier.get());
// }
//

View File

@@ -10,11 +10,13 @@ import com.google.errorprone.refaster.annotation.AlsoNegation;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NavigableSet;
import java.util.Optional;
import java.util.Queue;
import java.util.SortedSet;
import java.util.function.IntFunction;
import java.util.stream.Stream;
/** Refaster templates related to expressions dealing with (arbitrary) collections. */
@@ -37,6 +39,11 @@ final class CollectionTemplates {
Iterables.isEmpty(collection));
}
@BeforeTemplate
boolean before(ImmutableCollection<T> collection) {
return collection.asList().isEmpty();
}
@AfterTemplate
@AlsoNegation
boolean after(Collection<T> collection) {
@@ -51,6 +58,11 @@ final class CollectionTemplates {
return Iterables.size(collection);
}
@BeforeTemplate
int before(ImmutableCollection<T> collection) {
return collection.asList().size();
}
@AfterTemplate
int after(Collection<T> collection) {
return collection.size();
@@ -146,8 +158,10 @@ final class CollectionTemplates {
}
/** Prefer {@link ArrayList#ArrayList(Collection)} over the Guava alternative. */
// XXX: Drop this template if we adopt `baseline-error-prone`.
static final class NewArrayListFromCollection<T> {
@BeforeTemplate
@SuppressWarnings("PreferCollectionConstructors")
ArrayList<T> before(Collection<T> collection) {
return Lists.newArrayList(collection);
}
@@ -175,16 +189,6 @@ final class CollectionTemplates {
* Don't call {@link ImmutableCollection#asList()} if the result is going to be streamed; stream
* directly.
*/
// XXX: Similar rules could be implemented for the following variants:
// collection.asList().contains(null);
// collection.asList().isEmpty();
// collection.asList().iterator();
// collection.asList().parallelStream();
// collection.asList().size();
// collection.asList().toArray();
// collection.asList().toArray(Object[]::new);
// collection.asList().toArray(new Object[0]);
// collection.asList().toString();
static final class ImmutableCollectionAsListToStream<T> {
@BeforeTemplate
Stream<T> before(ImmutableCollection<T> collection) {
@@ -197,6 +201,121 @@ final class CollectionTemplates {
}
}
/**
* Don't call {@link ImmutableCollection#asList()} if {@link Collection#contains(Object)} is
* called on the result; call it directly.
*/
static final class ImmutableCollectionContains<T, S> {
@BeforeTemplate
boolean before(ImmutableCollection<T> collection, S elem) {
return collection.asList().contains(elem);
}
@AfterTemplate
boolean after(ImmutableCollection<T> collection, S elem) {
return collection.contains(elem);
}
}
/**
* Don't call {@link ImmutableCollection#asList()} if {@link ImmutableCollection#parallelStream()}
* is called on the result; call it directly.
*/
static final class ImmutableCollectionParallelStream<T> {
@BeforeTemplate
Stream<T> before(ImmutableCollection<T> collection) {
return collection.asList().parallelStream();
}
@AfterTemplate
Stream<T> after(ImmutableCollection<T> collection) {
return collection.parallelStream();
}
}
/**
* Don't call {@link ImmutableCollection#asList()} if {@link ImmutableCollection#toString()} is
* called on the result; call it directly.
*/
static final class ImmutableCollectionToString<T> {
@BeforeTemplate
String before(ImmutableCollection<T> collection) {
return collection.asList().toString();
}
@AfterTemplate
String after(ImmutableCollection<T> collection) {
return collection.toString();
}
}
/** Prefer calling {@link Collection#toArray()} over more contrived alternatives. */
static final class CollectionToArray<T> {
@BeforeTemplate
Object[] before(Collection<T> collection, int size) {
return Refaster.anyOf(
collection.toArray(new Object[size]), collection.toArray(Object[]::new));
}
@BeforeTemplate
Object[] before(ImmutableCollection<T> collection) {
return collection.asList().toArray();
}
@AfterTemplate
Object[] after(Collection<T> collection) {
return collection.toArray();
}
}
/**
* Don't call {@link ImmutableCollection#asList()} if {@link
* ImmutableCollection#toArray(Object[])}` is called on the result; call it directly.
*/
static final class ImmutableCollectionToArrayWithArray<T, S> {
@BeforeTemplate
Object[] before(ImmutableCollection<T> collection, S[] array) {
return collection.asList().toArray(array);
}
@AfterTemplate
Object[] after(ImmutableCollection<T> collection, S[] array) {
return collection.toArray(array);
}
}
/**
* Don't call {@link ImmutableCollection#asList()} if {@link
* ImmutableCollection#toArray(IntFunction)}} is called on the result; call it directly.
*/
static final class ImmutableCollectionToArrayWithGenerator<T, S> {
@BeforeTemplate
S[] before(ImmutableCollection<T> collection, IntFunction<S[]> generator) {
return collection.asList().toArray(generator);
}
@AfterTemplate
S[] after(ImmutableCollection<T> collection, IntFunction<S[]> generator) {
return collection.toArray(generator);
}
}
/**
* Don't call {@link ImmutableCollection#asList()} if {@link ImmutableCollection#iterator()} is
* called on the result; call it directly.
*/
static final class ImmutableCollectionIterator<T> {
@BeforeTemplate
Iterator<T> before(ImmutableCollection<T> collection) {
return collection.asList().iterator();
}
@AfterTemplate
Iterator<T> after(ImmutableCollection<T> collection) {
return collection.iterator();
}
}
/**
* Don't use the ternary operator to extract the first element of a possibly-empty {@link
* Collection} as an {@link Optional}.

View File

@@ -1,5 +1,10 @@
package tech.picnic.errorprone.refastertemplates;
import static java.util.Comparator.comparing;
import static java.util.Comparator.comparingDouble;
import static java.util.Comparator.comparingInt;
import static java.util.Comparator.comparingLong;
import static java.util.Comparator.naturalOrder;
import static java.util.Comparator.reverseOrder;
import static java.util.function.Function.identity;
@@ -29,14 +34,13 @@ final class ComparatorTemplates {
@BeforeTemplate
Comparator<T> before() {
return Refaster.anyOf(
Comparator.comparing(Refaster.anyOf(identity(), v -> v)),
Comparator.<T>reverseOrder().reversed());
comparing(Refaster.anyOf(identity(), v -> v)), Comparator.<T>reverseOrder().reversed());
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
Comparator<T> after() {
return Comparator.naturalOrder();
return naturalOrder();
}
}
@@ -58,7 +62,7 @@ final class ComparatorTemplates {
// XXX: Drop the `Refaster.anyOf` if/when we decide to rewrite one to the other.
@BeforeTemplate
Comparator<T> before(Comparator<T> cmp) {
return Comparator.comparing(Refaster.anyOf(identity(), v -> v), cmp);
return comparing(Refaster.anyOf(identity(), v -> v), cmp);
}
@AfterTemplate
@@ -72,7 +76,7 @@ final class ComparatorTemplates {
static final class ThenComparing<S, T extends Comparable<? super T>> {
@BeforeTemplate
Comparator<S> before(Comparator<S> cmp, Function<? super S, ? extends T> function) {
return cmp.thenComparing(Comparator.comparing(function));
return cmp.thenComparing(comparing(function));
}
@AfterTemplate
@@ -85,7 +89,7 @@ final class ComparatorTemplates {
static final class ThenComparingReversed<S, T extends Comparable<? super T>> {
@BeforeTemplate
Comparator<S> before(Comparator<S> cmp, Function<? super S, ? extends T> function) {
return cmp.thenComparing(Comparator.comparing(function).reversed());
return cmp.thenComparing(comparing(function).reversed());
}
@AfterTemplate
@@ -100,7 +104,7 @@ final class ComparatorTemplates {
@BeforeTemplate
Comparator<S> before(
Comparator<S> cmp, Function<? super S, ? extends T> function, Comparator<? super T> cmp2) {
return cmp.thenComparing(Comparator.comparing(function, cmp2));
return cmp.thenComparing(comparing(function, cmp2));
}
@AfterTemplate
@@ -115,7 +119,7 @@ final class ComparatorTemplates {
@BeforeTemplate
Comparator<S> before(
Comparator<S> cmp, Function<? super S, ? extends T> function, Comparator<? super T> cmp2) {
return cmp.thenComparing(Comparator.comparing(function, cmp2).reversed());
return cmp.thenComparing(comparing(function, cmp2).reversed());
}
@AfterTemplate
@@ -129,7 +133,7 @@ final class ComparatorTemplates {
static final class ThenComparingDouble<T> {
@BeforeTemplate
Comparator<T> before(Comparator<T> cmp, ToDoubleFunction<? super T> function) {
return cmp.thenComparing(Comparator.comparingDouble(function));
return cmp.thenComparing(comparingDouble(function));
}
@AfterTemplate
@@ -142,7 +146,7 @@ final class ComparatorTemplates {
static final class ThenComparingInt<T> {
@BeforeTemplate
Comparator<T> before(Comparator<T> cmp, ToIntFunction<? super T> function) {
return cmp.thenComparing(Comparator.comparingInt(function));
return cmp.thenComparing(comparingInt(function));
}
@AfterTemplate
@@ -155,7 +159,7 @@ final class ComparatorTemplates {
static final class ThenComparingLong<T> {
@BeforeTemplate
Comparator<T> before(Comparator<T> cmp, ToLongFunction<? super T> function) {
return cmp.thenComparing(Comparator.comparingLong(function));
return cmp.thenComparing(comparingLong(function));
}
@AfterTemplate
@@ -178,7 +182,7 @@ final class ComparatorTemplates {
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
Comparator<T> after(Comparator<T> cmp) {
return cmp.thenComparing(Comparator.naturalOrder());
return cmp.thenComparing(naturalOrder());
}
}

View File

@@ -233,10 +233,7 @@ final class DoubleStreamTemplates {
static final class DoubleStreamAllMatch {
@BeforeTemplate
boolean before(DoubleStream stream, DoublePredicate predicate) {
return Refaster.anyOf(
stream.noneMatch(predicate.negate()),
!stream.anyMatch(predicate.negate()),
stream.filter(predicate.negate()).findAny().isEmpty());
return stream.noneMatch(predicate.negate());
}
@AfterTemplate
@@ -251,10 +248,7 @@ final class DoubleStreamTemplates {
@BeforeTemplate
boolean before(DoubleStream stream) {
return Refaster.anyOf(
stream.noneMatch(e -> !test(e)),
!stream.anyMatch(e -> !test(e)),
stream.filter(e -> !test(e)).findAny().isEmpty());
return stream.noneMatch(e -> !test(e));
}
@AfterTemplate

View File

@@ -4,7 +4,6 @@ import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.NoAutoboxing;
import java.util.Objects;
import java.util.function.Predicate;
@@ -12,26 +11,9 @@ import java.util.function.Predicate;
final class EqualityTemplates {
private EqualityTemplates() {}
/** Prefer primitive/reference-based quality for primitives and enums. */
static final class PrimitiveOrReferenceEquality {
@NoAutoboxing
@BeforeTemplate
boolean before(boolean a, boolean b) {
return Objects.equals(a, b);
}
@NoAutoboxing
@BeforeTemplate
boolean before(long a, long b) {
return Objects.equals(a, b);
}
@NoAutoboxing
@BeforeTemplate
boolean before(double a, double b) {
return Objects.equals(a, b);
}
/** Prefer reference-based quality for enums. */
// Primitive value comparisons are not listed, because Error Prone flags those out of the box.
static final class PrimitiveOrReferenceEquality<T extends Enum<T>> {
/**
* Enums can be compared by reference. It is safe to do so even in the face of refactorings,
* because if the type is ever converted to a non-enum, then Error-Prone will complain about any
@@ -40,13 +22,13 @@ final class EqualityTemplates {
// 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.
@BeforeTemplate
<T extends Enum<T>> boolean before(T a, T b) {
boolean before(T a, T b) {
return Refaster.anyOf(a.equals(b), Objects.equals(a, b));
}
@AlsoNegation
@AfterTemplate
boolean after(boolean a, boolean b) {
@AlsoNegation
boolean after(T a, T b) {
return a == b;
}
}

View File

@@ -56,10 +56,7 @@ final class ImmutableListMultimapTemplates {
static final class EmptyImmutableListMultimap<K, V> {
@BeforeTemplate
ImmutableMultimap<K, V> before() {
return Refaster.anyOf(
ImmutableListMultimap.<K, V>builder().build(),
ImmutableMultimap.<K, V>builder().build(),
ImmutableMultimap.of());
return Refaster.anyOf(ImmutableListMultimap.<K, V>builder().build(), ImmutableMultimap.of());
}
@AfterTemplate
@@ -80,7 +77,6 @@ final class ImmutableListMultimapTemplates {
ImmutableMultimap<K, V> before(K key, V value) {
return Refaster.anyOf(
ImmutableListMultimap.<K, V>builder().put(key, value).build(),
ImmutableMultimap.<K, V>builder().put(key, value).build(),
ImmutableMultimap.of(key, value));
}
@@ -99,9 +95,8 @@ final class ImmutableListMultimapTemplates {
ImmutableMultimap<K, V> before(Map.Entry<? extends K, ? extends V> entry) {
return Refaster.anyOf(
ImmutableListMultimap.<K, V>builder().put(entry).build(),
Stream.of(entry).collect(toImmutableListMultimap(Map.Entry::getKey, Map.Entry::getValue)),
ImmutableMultimap.<K, V>builder().put(entry).build(),
ImmutableMultimap.of(entry.getKey(), entry.getValue()));
Stream.of(entry)
.collect(toImmutableListMultimap(Map.Entry::getKey, Map.Entry::getValue)));
}
@AfterTemplate
@@ -118,8 +113,7 @@ final class ImmutableListMultimapTemplates {
ImmutableListMultimap.copyOf(iterable.entries()),
ImmutableListMultimap.<K, V>builder().putAll(iterable).build(),
ImmutableMultimap.copyOf(iterable),
ImmutableMultimap.copyOf(iterable.entries()),
ImmutableMultimap.<K, V>builder().putAll(iterable).build());
ImmutableMultimap.copyOf(iterable.entries()));
}
@BeforeTemplate
@@ -129,7 +123,6 @@ final class ImmutableListMultimapTemplates {
ImmutableListMultimap.<K, V>builder().putAll(iterable).build(),
Streams.stream(iterable)
.collect(toImmutableListMultimap(Map.Entry::getKey, Map.Entry::getValue)),
ImmutableMultimap.<K, V>builder().putAll(iterable).build(),
ImmutableMultimap.copyOf(iterable));
}

View File

@@ -76,13 +76,11 @@ final class ImmutableListTemplates {
* Prefer {@link ImmutableList#copyOf(Iterable)} and variants over more contrived alternatives.
*/
static final class IterableToImmutableList<T> {
// XXX: Drop the inner `Refaster.anyOf` if/when we introduce a rule to choose between one and
// the other.
@BeforeTemplate
ImmutableList<T> before(T[] iterable) {
return Refaster.anyOf(
ImmutableList.<T>builder().add(iterable).build(),
Refaster.anyOf(Stream.of(iterable), Arrays.stream(iterable)).collect(toImmutableList()));
Arrays.stream(iterable).collect(toImmutableList()));
}
@BeforeTemplate
@@ -120,7 +118,6 @@ final class ImmutableListTemplates {
ImmutableList<T> before(Stream<T> stream) {
return Refaster.anyOf(
ImmutableList.copyOf(stream.iterator()),
ImmutableList.copyOf(stream::iterator),
stream.collect(collectingAndThen(toList(), ImmutableList::copyOf)));
}

View File

@@ -54,14 +54,11 @@ final class ImmutableMultisetTemplates {
* alternatives.
*/
static final class IterableToImmutableMultiset<T> {
// XXX: Drop the inner `Refaster.anyOf` if/when we introduce a rule to choose between one and
// the other.
@BeforeTemplate
ImmutableMultiset<T> before(T[] iterable) {
return Refaster.anyOf(
ImmutableMultiset.<T>builder().add(iterable).build(),
Refaster.anyOf(Stream.of(iterable), Arrays.stream(iterable))
.collect(toImmutableMultiset()));
Arrays.stream(iterable).collect(toImmutableMultiset()));
}
@BeforeTemplate
@@ -95,7 +92,6 @@ final class ImmutableMultisetTemplates {
ImmutableMultiset<T> before(Stream<T> stream) {
return Refaster.anyOf(
ImmutableMultiset.copyOf(stream.iterator()),
ImmutableMultiset.copyOf(stream::iterator),
stream.collect(collectingAndThen(toList(), ImmutableMultiset::copyOf)));
}

View File

@@ -72,13 +72,11 @@ final class ImmutableSetTemplates {
/** Prefer {@link ImmutableSet#copyOf(Iterable)} and variants over more contrived alternatives. */
static final class IterableToImmutableSet<T> {
// XXX: Drop the inner `Refaster.anyOf` if/when we introduce a rule to choose between one and
// the other.
@BeforeTemplate
ImmutableSet<T> before(T[] iterable) {
return Refaster.anyOf(
ImmutableSet.<T>builder().add(iterable).build(),
Refaster.anyOf(Stream.of(iterable), Arrays.stream(iterable)).collect(toImmutableSet()));
Arrays.stream(iterable).collect(toImmutableSet()));
}
@BeforeTemplate
@@ -116,7 +114,6 @@ final class ImmutableSetTemplates {
ImmutableSet<T> before(Stream<T> stream) {
return Refaster.anyOf(
ImmutableSet.copyOf(stream.iterator()),
ImmutableSet.copyOf(stream::iterator),
stream.distinct().collect(toImmutableSet()),
stream.collect(collectingAndThen(toList(), ImmutableSet::copyOf)),
stream.collect(collectingAndThen(toSet(), ImmutableSet::copyOf)));

View File

@@ -92,14 +92,11 @@ final class ImmutableSortedMultisetTemplates {
// XXX: There's also a variant with a custom Comparator. (And some special cases with
// `reverseOrder`.) Worth the hassle?
static final class IterableToImmutableSortedMultiset<T extends Comparable<? super T>> {
// XXX: Drop the inner `Refaster.anyOf` if/when we introduce a rule to choose between one and
// the other.
@BeforeTemplate
ImmutableMultiset<T> before(T[] iterable) {
return Refaster.anyOf(
ImmutableSortedMultiset.<T>naturalOrder().add(iterable).build(),
Refaster.anyOf(Stream.of(iterable), Arrays.stream(iterable))
.collect(toImmutableSortedMultiset(naturalOrder())));
Arrays.stream(iterable).collect(toImmutableSortedMultiset(naturalOrder())));
}
@BeforeTemplate
@@ -139,7 +136,6 @@ final class ImmutableSortedMultisetTemplates {
ImmutableSortedMultiset<T> before(Stream<T> stream) {
return Refaster.anyOf(
ImmutableSortedMultiset.copyOf(stream.iterator()),
ImmutableSortedMultiset.copyOf(stream::iterator),
stream.collect(collectingAndThen(toList(), ImmutableSortedMultiset::copyOf)));
}

View File

@@ -90,14 +90,11 @@ final class ImmutableSortedSetTemplates {
// XXX: There's also a variant with a custom Comparator. (And some special cases with
// `reverseOrder`.) Worth the hassle?
static final class IterableToImmutableSortedSet<T extends Comparable<? super T>> {
// XXX: Drop the inner `Refaster.anyOf` if/when we introduce a rule to choose between one and
// the other.
@BeforeTemplate
ImmutableSet<T> before(T[] iterable) {
return Refaster.anyOf(
ImmutableSortedSet.<T>naturalOrder().add(iterable).build(),
Refaster.anyOf(Stream.of(iterable), Arrays.stream(iterable))
.collect(toImmutableSortedSet(naturalOrder())));
Arrays.stream(iterable).collect(toImmutableSortedSet(naturalOrder())));
}
@BeforeTemplate
@@ -139,7 +136,6 @@ final class ImmutableSortedSetTemplates {
ImmutableSortedSet<T> before(Stream<T> stream) {
return Refaster.anyOf(
ImmutableSortedSet.copyOf(stream.iterator()),
ImmutableSortedSet.copyOf(stream::iterator),
stream.collect(collectingAndThen(toList(), ImmutableSortedSet::copyOf)));
}

View File

@@ -246,10 +246,7 @@ final class IntStreamTemplates {
static final class IntStreamAllMatch {
@BeforeTemplate
boolean before(IntStream stream, IntPredicate predicate) {
return Refaster.anyOf(
stream.noneMatch(predicate.negate()),
!stream.anyMatch(predicate.negate()),
stream.filter(predicate.negate()).findAny().isEmpty());
return stream.noneMatch(predicate.negate());
}
@AfterTemplate
@@ -264,10 +261,7 @@ final class IntStreamTemplates {
@BeforeTemplate
boolean before(IntStream stream) {
return Refaster.anyOf(
stream.noneMatch(e -> !test(e)),
!stream.anyMatch(e -> !test(e)),
stream.filter(e -> !test(e)).findAny().isEmpty());
return stream.noneMatch(e -> !test(e));
}
@AfterTemplate

View File

@@ -246,10 +246,7 @@ final class LongStreamTemplates {
static final class LongStreamAllMatch {
@BeforeTemplate
boolean before(LongStream stream, LongPredicate predicate) {
return Refaster.anyOf(
stream.noneMatch(predicate.negate()),
!stream.anyMatch(predicate.negate()),
stream.filter(predicate.negate()).findAny().isEmpty());
return stream.noneMatch(predicate.negate());
}
@AfterTemplate
@@ -264,10 +261,7 @@ final class LongStreamTemplates {
@BeforeTemplate
boolean before(LongStream stream) {
return Refaster.anyOf(
stream.noneMatch(e -> !test(e)),
!stream.anyMatch(e -> !test(e)),
stream.filter(e -> !test(e)).findAny().isEmpty());
return stream.noneMatch(e -> !test(e));
}
@AfterTemplate

View File

@@ -1,5 +1,10 @@
package tech.picnic.errorprone.refastertemplates;
import static java.util.Comparator.comparing;
import static java.util.Comparator.naturalOrder;
import static java.util.Map.Entry.comparingByKey;
import static java.util.Map.Entry.comparingByValue;
import com.google.common.collect.Maps;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
@@ -42,15 +47,13 @@ final class MapEntryTemplates {
static final class MapEntryComparingByKey<K extends Comparable<? super K>, V> {
@BeforeTemplate
Comparator<Map.Entry<K, V>> before() {
return Refaster.anyOf(
Comparator.comparing(Map.Entry::getKey),
Map.Entry.comparingByKey(Comparator.naturalOrder()));
return Refaster.anyOf(comparing(Map.Entry::getKey), comparingByKey(naturalOrder()));
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
Comparator<Map.Entry<K, V>> after() {
return Map.Entry.comparingByKey();
return comparingByKey();
}
}
@@ -58,13 +61,13 @@ final class MapEntryTemplates {
static final class MapEntryComparingByKeyWithCustomComparator<K, V> {
@BeforeTemplate
Comparator<Map.Entry<K, V>> before(Comparator<? super K> cmp) {
return Comparator.comparing(Map.Entry::getKey, cmp);
return comparing(Map.Entry::getKey, cmp);
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
Comparator<Map.Entry<K, V>> after(Comparator<? super K> cmp) {
return Map.Entry.comparingByKey(cmp);
return comparingByKey(cmp);
}
}
@@ -73,15 +76,13 @@ final class MapEntryTemplates {
static final class MapEntryComparingByValue<K, V extends Comparable<? super V>> {
@BeforeTemplate
Comparator<Map.Entry<K, V>> before() {
return Refaster.anyOf(
Comparator.comparing(Map.Entry::getValue),
Map.Entry.comparingByValue(Comparator.naturalOrder()));
return Refaster.anyOf(comparing(Map.Entry::getValue), comparingByValue(naturalOrder()));
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
Comparator<Map.Entry<K, V>> after() {
return Map.Entry.comparingByValue();
return comparingByValue();
}
}
@@ -89,13 +90,13 @@ final class MapEntryTemplates {
static final class MapEntryComparingByValueWithCustomComparator<K, V> {
@BeforeTemplate
Comparator<Map.Entry<K, V>> before(Comparator<? super V> cmp) {
return Comparator.comparing(Map.Entry::getValue, cmp);
return comparing(Map.Entry::getValue, cmp);
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
Comparator<Map.Entry<K, V>> after(Comparator<? super V> cmp) {
return Map.Entry.comparingByValue(cmp);
return comparingByValue(cmp);
}
}
}

View File

@@ -1,5 +1,7 @@
package tech.picnic.errorprone.refastertemplates;
import static java.util.Objects.requireNonNullElse;
import com.google.common.base.MoreObjects;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.annotation.AfterTemplate;
@@ -24,7 +26,7 @@ final class NullTemplates {
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
T after(T first, T second) {
return Objects.requireNonNullElse(first, second);
return requireNonNullElse(first, second);
}
}

View File

@@ -20,10 +20,10 @@ final class OptionalTemplates {
private OptionalTemplates() {}
static final class OptionalOfNullable<T> {
@BeforeTemplate
// XXX: Refaster should be smart enough to also rewrite occurrences in which there are
// parentheses around the null check, but that's currently not the case. Try to fix that.
// XXX: This is a special case of `TernaryOperatorOptionalNegativeFiltering`.
@BeforeTemplate
@SuppressWarnings("TernaryOperatorOptionalNegativeFiltering" /* Special case. */)
Optional<T> before(T object) {
return object == null ? Optional.empty() : Optional.of(object);
}
@@ -167,6 +167,7 @@ final class OptionalTemplates {
*/
abstract static class MapOptionalToBoolean<T> {
@BeforeTemplate
@SuppressWarnings("OptionalOrElseMethodInvocation")
boolean before(Optional<T> optional, Function<? super T, Boolean> predicate) {
return optional.map(predicate).orElse(Refaster.anyOf(false, Boolean.FALSE));
}
@@ -317,6 +318,7 @@ final class OptionalTemplates {
/** Prefer {@link Optional#or(Supplier)} over more verbose alternatives. */
abstract static class OptionalOrOtherOptional<T> {
@BeforeTemplate
@SuppressWarnings("OptionalOrElseGetValue")
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.

View File

@@ -77,7 +77,7 @@ final class ReactorTemplates {
static final class MonoErrorSupplier<T, E extends Throwable> {
@BeforeTemplate
Mono<T> before(Supplier<E> supplier) {
return Refaster.anyOf(Mono.error(supplier::get), Mono.error(() -> supplier.get()));
return Mono.error(() -> supplier.get());
}
@AfterTemplate
@@ -94,7 +94,7 @@ final class ReactorTemplates {
static final class FluxErrorSupplier<T, E extends Throwable> {
@BeforeTemplate
Flux<T> before(Supplier<E> supplier) {
return Refaster.anyOf(Flux.error(supplier::get), Flux.error(() -> supplier.get()));
return Flux.error(() -> supplier.get());
}
@AfterTemplate

View File

@@ -12,6 +12,7 @@ import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
import java.util.Optional;
@@ -23,19 +24,6 @@ import java.util.stream.Stream;
final class StreamTemplates {
private StreamTemplates() {}
/** Prefer {@link Stream#empty()} over less clear alternatives. */
static final class EmptyStream<T> {
@BeforeTemplate
Stream<T> before() {
return Stream.of();
}
@AfterTemplate
Stream<T> after() {
return Stream.empty();
}
}
/** Prefer {@link Stream#ofNullable(Object)} over more contrived alternatives. */
static final class StreamOfNullable<T> {
@BeforeTemplate
@@ -50,6 +38,22 @@ final class StreamTemplates {
}
}
/**
* Prefer {@link Arrays#stream(Object[])} over {@link Stream#of(Object[])}, as the former is
* clearer.
*/
static final class StreamOfArray<T> {
@BeforeTemplate
Stream<T> before(T[] array) {
return Stream.of(array);
}
@AfterTemplate
Stream<T> after(T[] array) {
return Arrays.stream(array);
}
}
/** Don't unnecessarily call {@link Streams#concat(Stream...)}. */
static final class ConcatOneStream<T> {
@BeforeTemplate
@@ -277,10 +281,7 @@ final class StreamTemplates {
static final class StreamAllMatch<T> {
@BeforeTemplate
boolean before(Stream<T> stream, Predicate<? super T> predicate) {
return Refaster.anyOf(
stream.noneMatch(Refaster.anyOf(not(predicate), predicate.negate())),
!stream.anyMatch(Refaster.anyOf(not(predicate), predicate.negate())),
stream.filter(Refaster.anyOf(not(predicate), predicate.negate())).findAny().isEmpty());
return stream.noneMatch(Refaster.anyOf(not(predicate), predicate.negate()));
}
@AfterTemplate
@@ -295,10 +296,7 @@ final class StreamTemplates {
@BeforeTemplate
boolean before(Stream<T> stream) {
return Refaster.anyOf(
stream.noneMatch(e -> !test(e)),
!stream.anyMatch(e -> !test(e)),
stream.filter(e -> !test(e)).findAny().isEmpty());
return stream.noneMatch(e -> !test(e));
}
@AfterTemplate

View File

@@ -1,5 +1,6 @@
package tech.picnic.errorprone.refastertemplates;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.joining;
import com.google.common.base.Joiner;
@@ -10,11 +11,9 @@ import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Optional;
import java.util.stream.Stream;
/** Refaster templates related to expressions dealing with {@link String}s. */
// XXX: Should we prefer `s -> !s.isEmpty()` or `not(String::isEmpty)`?
@@ -82,12 +81,10 @@ final class StringTemplates {
// XXX: Joiner#join(@Nullable Object first, @Nullable Object second, Object... rest) isn't
// rewritten.
static final class JoinStrings {
// XXX: Drop the inner `Refaster.anyOf` if/when we decide to rewrite one to the other.
@BeforeTemplate
String before(String delimiter, CharSequence[] elements) {
return Refaster.anyOf(
Joiner.on(delimiter).join(elements),
Refaster.anyOf(Stream.of(elements), Arrays.stream(elements)).collect(joining(delimiter)));
Joiner.on(delimiter).join(elements), Arrays.stream(elements).collect(joining(delimiter)));
}
@BeforeTemplate
@@ -125,7 +122,7 @@ final class StringTemplates {
static final class Utf8EncodedLength {
@BeforeTemplate
int before(String str) {
return str.getBytes(StandardCharsets.UTF_8).length;
return str.getBytes(UTF_8).length;
}
@AfterTemplate

View File

@@ -16,6 +16,7 @@ import static org.testng.Assert.assertThrows;
import static org.testng.Assert.assertTrue;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.DoNotCall;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -81,6 +82,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@DoNotCall
void after() {
throw new AssertionError();
}

View File

@@ -43,10 +43,10 @@ final class TimeTemplates {
static final class UtcConstant {
@BeforeTemplate
ZoneId before() {
// `ZoneId.of("Z")` is not listed, because Error Prone flags it out of the box.
return Refaster.anyOf(
ZoneId.of("GMT"),
ZoneId.of("UTC"),
ZoneId.of("Z"),
ZoneId.of("+0"),
ZoneId.of("-0"),
ZoneOffset.UTC.normalized(),
@@ -62,11 +62,13 @@ final class TimeTemplates {
/** Use {@link Clock#systemUTC()} when possible. */
static final class UtcClock {
@BeforeTemplate
@SuppressWarnings("TimeZoneUsage")
Clock before() {
return Clock.system(ZoneOffset.UTC);
}
@AfterTemplate
@SuppressWarnings("TimeZoneUsage")
Clock after() {
return Clock.systemUTC();
}
@@ -96,8 +98,8 @@ final class TimeTemplates {
return a.compareTo(b) < 0;
}
@AlsoNegation
@AfterTemplate
@AlsoNegation
boolean after(Instant a, Instant b) {
return a.isBefore(b);
}
@@ -113,8 +115,8 @@ final class TimeTemplates {
return a.compareTo(b) > 0;
}
@AlsoNegation
@AfterTemplate
@AlsoNegation
boolean after(Instant a, Instant b) {
return a.isAfter(b);
}
@@ -162,8 +164,8 @@ final class TimeTemplates {
return a.compareTo(b) < 0;
}
@AlsoNegation
@AfterTemplate
@AlsoNegation
boolean after(ChronoLocalDate a, ChronoLocalDate b) {
return a.isBefore(b);
}
@@ -179,8 +181,8 @@ final class TimeTemplates {
return a.compareTo(b) > 0;
}
@AlsoNegation
@AfterTemplate
@AlsoNegation
boolean after(ChronoLocalDate a, ChronoLocalDate b) {
return a.isAfter(b);
}
@@ -196,8 +198,8 @@ final class TimeTemplates {
return a.compareTo(b) < 0;
}
@AlsoNegation
@AfterTemplate
@AlsoNegation
boolean after(ChronoLocalDateTime<?> a, ChronoLocalDateTime<?> b) {
return a.isBefore(b);
}
@@ -213,8 +215,8 @@ final class TimeTemplates {
return a.compareTo(b) > 0;
}
@AlsoNegation
@AfterTemplate
@AlsoNegation
boolean after(ChronoLocalDateTime<?> a, ChronoLocalDateTime<?> b) {
return a.isAfter(b);
}
@@ -230,8 +232,8 @@ final class TimeTemplates {
return a.compareTo(b) < 0;
}
@AlsoNegation
@AfterTemplate
@AlsoNegation
boolean after(ChronoZonedDateTime<?> a, ChronoZonedDateTime<?> b) {
return a.isBefore(b);
}
@@ -247,8 +249,8 @@ final class TimeTemplates {
return a.compareTo(b) > 0;
}
@AlsoNegation
@AfterTemplate
@AlsoNegation
boolean after(ChronoZonedDateTime<?> a, ChronoZonedDateTime<?> b) {
return a.isAfter(b);
}
@@ -264,8 +266,8 @@ final class TimeTemplates {
return a.compareTo(b) < 0;
}
@AlsoNegation
@AfterTemplate
@AlsoNegation
boolean after(OffsetDateTime a, OffsetDateTime b) {
return a.isBefore(b);
}
@@ -281,8 +283,8 @@ final class TimeTemplates {
return a.compareTo(b) > 0;
}
@AlsoNegation
@AfterTemplate
@AlsoNegation
boolean after(OffsetDateTime a, OffsetDateTime b) {
return a.isAfter(b);
}

View File

@@ -1,7 +1,4 @@
/** Picnic Refaster templates. */
@CheckReturnValue
@ParametersAreNonnullByDefault
@com.google.errorprone.annotations.CheckReturnValue
@javax.annotation.ParametersAreNonnullByDefault
package tech.picnic.errorprone.refastertemplates;
import com.google.errorprone.annotations.CheckReturnValue;
import javax.annotation.ParametersAreNonnullByDefault;

View File

@@ -0,0 +1,149 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.base.Predicates.containsPattern;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class AmbiguousJsonCreatorCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(AmbiguousJsonCreatorCheck.class, getClass())
.expectErrorMessage(
"X",
containsPattern("`JsonCreator.Mode` should be set for single-argument creators"));
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(AmbiguousJsonCreatorCheck.class, getClass());
@Test
void identification() {
compilationTestHelper
.addSourceLines(
"Container.java",
"import com.fasterxml.jackson.annotation.JsonCreator;",
"import com.fasterxml.jackson.annotation.JsonValue;",
"",
"interface Container {",
" enum A {",
" FOO(1);",
"",
" private final int i;",
"",
" A(int i) {",
" this.i = i;",
" }",
"",
" // BUG: Diagnostic matches: X",
" @JsonCreator",
" public static A of(int i) {",
" return FOO;",
" }",
" }",
"",
" enum B {",
" FOO(1);",
"",
" private final int i;",
"",
" B(int i) {",
" this.i = i;",
" }",
"",
" @JsonCreator(mode = JsonCreator.Mode.DELEGATING)",
" public static B of(int i) {",
" return FOO;",
" }",
" }",
"",
" enum C {",
" FOO(1, \"s\");",
"",
" @JsonValue private final int i;",
" private final String s;",
"",
" C(int i, String s) {",
" this.i = i;",
" this.s = s;",
" }",
"",
" // BUG: Diagnostic matches: X",
" @JsonCreator",
" public static C of(int i) {",
" return FOO;",
" }",
" }",
"",
" enum D {",
" FOO(1, \"s\");",
"",
" private final int i;",
" private final String s;",
"",
" D(int i, String s) {",
" this.i = i;",
" this.s = s;",
" }",
"",
" @JsonCreator",
" public static D of(int i, String s) {",
" return FOO;",
" }",
" }",
"",
" enum E {",
" FOO;",
"",
" // BUG: Diagnostic matches: X",
" @JsonCreator",
" public static E of(String s) {",
" return FOO;",
" }",
" }",
"",
" class F {",
" private final String s;",
"",
" F(String s) {",
" this.s = s;",
" }",
"",
" @JsonCreator",
" public static F of(String s) {",
" return new F(s);",
" }",
" }",
"",
"}")
.doTest();
}
@Test
void replacement() {
refactoringTestHelper
.addInputLines(
"in/A.java",
"import com.fasterxml.jackson.annotation.JsonCreator;",
"",
"enum A {",
" FOO;",
"",
" @JsonCreator",
" public static A of(String s) {",
" return FOO;",
" }",
"}")
.addOutputLines(
"out/A.java",
"import com.fasterxml.jackson.annotation.JsonCreator;",
"",
"enum A {",
" FOO;",
"",
" @JsonCreator(mode = JsonCreator.Mode.DELEGATING)",
" public static A of(String s) {",
" return FOO;",
" }",
"}")
.doTest(BugCheckerRefactoringTestHelper.TestMode.TEXT_MATCH);
}
}

View File

@@ -8,14 +8,14 @@ import org.junit.jupiter.api.Test;
public final class AnnotationAttributeMatcherTest {
@Test
public void testWithoutListings() {
void withoutListings() {
AnnotationAttributeMatcher matcher =
AnnotationAttributeMatcher.create(Optional.empty(), ImmutableList.of());
assertThat(matcher.matches("foo", "bar")).isTrue();
}
@Test
public void testWithSingleFullAnnotationWhitelist() {
void withSingleFullAnnotationWhitelist() {
AnnotationAttributeMatcher matcher =
AnnotationAttributeMatcher.create(Optional.of(ImmutableList.of("foo")), ImmutableList.of());
assertThat(matcher.matches("foo", "bar")).isTrue();
@@ -24,7 +24,7 @@ public final class AnnotationAttributeMatcherTest {
}
@Test
public void testWithSingleAnnotationAttributeWhitelist() {
void withSingleAnnotationAttributeWhitelist() {
AnnotationAttributeMatcher matcher =
AnnotationAttributeMatcher.create(
Optional.of(ImmutableList.of("foo#bar")), ImmutableList.of());
@@ -34,7 +34,7 @@ public final class AnnotationAttributeMatcherTest {
}
@Test
public void testWithSingleFullAnnotationBlacklist() {
void withSingleFullAnnotationBlacklist() {
AnnotationAttributeMatcher matcher =
AnnotationAttributeMatcher.create(Optional.empty(), ImmutableList.of("foo"));
assertThat(matcher.matches("foo", "bar")).isFalse();
@@ -43,7 +43,7 @@ public final class AnnotationAttributeMatcherTest {
}
@Test
public void testWithSingleAnnotationAttributeBlacklist() {
void withSingleAnnotationAttributeBlacklist() {
AnnotationAttributeMatcher matcher =
AnnotationAttributeMatcher.create(Optional.empty(), ImmutableList.of("foo#bar"));
assertThat(matcher.matches("foo", "bar")).isFalse();
@@ -52,7 +52,7 @@ public final class AnnotationAttributeMatcherTest {
}
@Test
public void testWithComplicatedConfiguration() {
void withComplicatedConfiguration() {
AnnotationAttributeMatcher matcher =
AnnotationAttributeMatcher.create(
Optional.of(ImmutableList.of("foo", "bar", "baz", "baz#1", "baz#2", "quux#1")),

View File

@@ -9,10 +9,10 @@ public final class AutowiredConstructorCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(AutowiredConstructorCheck.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(new AutowiredConstructorCheck(), getClass());
BugCheckerRefactoringTestHelper.newInstance(AutowiredConstructorCheck.class, getClass());
@Test
public void testIdentification() {
void identification() {
compilationTestHelper
.addSourceLines(
"Container.java",
@@ -62,7 +62,7 @@ public final class AutowiredConstructorCheckTest {
}
@Test
public void testReplacement() {
void replacement() {
refactoringTestHelper
.addInputLines(
"in/Container.java",

View File

@@ -9,10 +9,10 @@ public final class CanonicalAnnotationSyntaxCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(CanonicalAnnotationSyntaxCheck.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(new CanonicalAnnotationSyntaxCheck(), getClass());
BugCheckerRefactoringTestHelper.newInstance(CanonicalAnnotationSyntaxCheck.class, getClass());
@Test
public void testIdentification() {
void identification() {
compilationTestHelper
.addSourceLines(
"pkg/A.java",
@@ -85,7 +85,7 @@ public final class CanonicalAnnotationSyntaxCheckTest {
}
@Test
public void testReplacement() {
void replacement() {
refactoringTestHelper
.addInputLines(
"in/pkg/A.java",

View File

@@ -9,10 +9,10 @@ public final class EmptyMethodCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(EmptyMethodCheck.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(new EmptyMethodCheck(), getClass());
BugCheckerRefactoringTestHelper.newInstance(EmptyMethodCheck.class, getClass());
@Test
public void testIdentification() {
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -64,7 +64,7 @@ public final class EmptyMethodCheckTest {
}
@Test
public void testReplacement() {
void replacement() {
refactoringTestHelper
.addInputLines(
"in/A.java",

View File

@@ -0,0 +1,85 @@
package tech.picnic.errorprone.bugpatterns;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class ExplicitEnumOrderingCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(ExplicitEnumOrderingCheck.class, getClass());
@Test
void Identification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import static java.lang.annotation.RetentionPolicy.SOURCE;",
"import static java.lang.annotation.RetentionPolicy.CLASS;",
"import static java.lang.annotation.RetentionPolicy.RUNTIME;",
"import static java.time.chrono.IsoEra.BCE;",
"import static java.time.chrono.IsoEra.CE;",
"",
"import com.google.common.collect.Ordering;",
"import com.google.common.collect.ImmutableList;",
"import java.lang.annotation.RetentionPolicy;",
"import java.time.chrono.IsoEra;",
"",
"class A {",
" {",
" // The `List`-accepting overload is currently ignored.",
" Ordering.explicit(ImmutableList.of(RetentionPolicy.SOURCE, RetentionPolicy.CLASS));",
"",
" Ordering.explicit(IsoEra.BCE, IsoEra.CE);",
" // BUG: Diagnostic contains: IsoEra.CE",
" Ordering.explicit(IsoEra.BCE);",
" // BUG: Diagnostic contains: IsoEra.BCE",
" Ordering.explicit(IsoEra.CE);",
"",
" Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.CLASS, RetentionPolicy.RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.CLASS, RetentionPolicy.RUNTIME",
" Ordering.explicit(RetentionPolicy.SOURCE);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME",
" Ordering.explicit(RetentionPolicy.CLASS);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.CLASS",
" Ordering.explicit(RetentionPolicy.RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.RUNTIME",
" Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.CLASS);",
" // BUG: Diagnostic contains: RetentionPolicy.CLASS",
" Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE",
" Ordering.explicit(RetentionPolicy.CLASS, RetentionPolicy.RUNTIME);",
"",
" Ordering.explicit(BCE, CE);",
" // BUG: Diagnostic contains: IsoEra.CE",
" Ordering.explicit(BCE);",
" // BUG: Diagnostic contains: IsoEra.BCE",
" Ordering.explicit(CE);",
"",
" Ordering.explicit(SOURCE, CLASS, RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.CLASS, RetentionPolicy.RUNTIME",
" Ordering.explicit(SOURCE);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME",
" Ordering.explicit(CLASS);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.CLASS",
" Ordering.explicit(RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.RUNTIME",
" Ordering.explicit(SOURCE, CLASS);",
" // BUG: Diagnostic contains: RetentionPolicy.CLASS",
" Ordering.explicit(SOURCE, RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE",
" Ordering.explicit(CLASS, RUNTIME);",
"",
" Ordering.explicit(RetentionPolicy.SOURCE, BCE, RetentionPolicy.CLASS, CE, RUNTIME);",
" Ordering.explicit(SOURCE, IsoEra.BCE, CLASS, IsoEra.CE, RetentionPolicy.RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.CLASS",
" Ordering.explicit(RetentionPolicy.SOURCE, BCE, CE, RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.CLASS",
" Ordering.explicit(IsoEra.BCE, SOURCE, IsoEra.CE, RetentionPolicy.RUNTIME);",
" // BUG: Diagnostic contains: IsoEra.CE, RetentionPolicy.RUNTIME",
" Ordering.explicit(IsoEra.BCE, SOURCE, RetentionPolicy.CLASS);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, IsoEra.BCE",
" Ordering.explicit(CLASS, RUNTIME, CE);",
" }",
"}")
.doTest();
}
}

View File

@@ -9,10 +9,10 @@ public final class JUnitMethodDeclarationCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(JUnitMethodDeclarationCheck.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(new JUnitMethodDeclarationCheck(), getClass());
BugCheckerRefactoringTestHelper.newInstance(JUnitMethodDeclarationCheck.class, getClass());
@Test
public void testIdentification() {
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -91,7 +91,7 @@ public final class JUnitMethodDeclarationCheckTest {
"import org.junit.jupiter.api.Test;",
"import org.junit.jupiter.params.ParameterizedTest;",
"",
"final class B extends A {",
"class B extends A {",
" @Override @BeforeAll void setUp1() {}",
" @Override @BeforeAll public void setUp2() {}",
" @Override @BeforeAll protected void setUp3() {}",
@@ -127,7 +127,7 @@ public final class JUnitMethodDeclarationCheckTest {
}
@Test
public void testReplacement() {
void replacement() {
refactoringTestHelper
.addInputLines(
"in/A.java",

View File

@@ -19,10 +19,10 @@ public final class LexicographicalAnnotationAttributeListingCheckTest {
"-XepOpt:LexicographicalAnnotationAttributeListing:Excludes=pkg.A.Bar#value"));
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(
new LexicographicalAnnotationAttributeListingCheck(), getClass());
LexicographicalAnnotationAttributeListingCheck.class, getClass());
@Test
public void testIdentification() {
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -105,7 +105,7 @@ public final class LexicographicalAnnotationAttributeListingCheckTest {
// introduced. Avoiding that might make the code too complex. Instead, users can have the
// `CanonicalAnnotationSyntaxCheck` correct the situation in a subsequent run.
@Test
public void testReplacement() {
void replacement() {
refactoringTestHelper
.addInputLines(
"in/A.java",
@@ -161,7 +161,7 @@ public final class LexicographicalAnnotationAttributeListingCheckTest {
}
@Test
public void testFiltering() {
void filtering() {
/* Some violations are not flagged because they are not in- or excluded. */
restrictedCompilationTestHelper
.addSourceLines(

View File

@@ -0,0 +1,148 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.base.Predicates.containsPattern;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
public final class LexicographicalAnnotationListingCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(LexicographicalAnnotationListingCheck.class, getClass())
.expectErrorMessage(
"X", containsPattern("Sort annotations lexicographically where possible"));
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(
LexicographicalAnnotationListingCheck.class, getClass());
@Test
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import java.lang.annotation.Repeatable;",
"",
"interface A {",
" @Repeatable(Foos.class)",
" @interface Foo {",
" String[] value() default {};",
" int[] ints() default {};",
" Bar[] anns() default {};",
" }",
"",
" @interface Bar {",
" String[] value() default {};",
" }",
"",
" @interface Baz {",
" String[] str() default {};",
" }",
"",
" @interface Foos {",
" Foo[] value();",
" }",
"",
" // BUG: Diagnostic matches: X",
" @Foo @Bar A unsortedSimpleCase();",
" // BUG: Diagnostic matches: X",
" @Foo() @Bar() A unsortedWithParens();",
" @Foo() A onlyOneAnnotation();",
" @Bar @Foo() A sortedAnnotationsOneWithParens();",
"",
" // BUG: Diagnostic matches: X",
" @Foo @Baz @Bar A threeUnsortedAnnotationsSameInitialLetter();",
" // BUG: Diagnostic matches: X",
" @Bar @Foo() @Baz A firstOrderedWithTwoUnsortedAnnotations();",
" @Bar @Baz @Foo() A threeSortedAnnotations();",
"",
" // BUG: Diagnostic matches: X",
" @Foo({\"b\"}) @Bar({\"a\"}) A unsortedWithStringAttributes();",
" // BUG: Diagnostic matches: X",
" @Baz(str = {\"a\", \"b\"}) @Foo(ints = {1, 0}) @Bar A unsortedWithAttributes();",
" // BUG: Diagnostic matches: X",
" @Bar @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")}) @Baz A unsortedWithNestedBar();",
" @Bar @Baz @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")}) A sortedWithNestedBar();",
"",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")}) @Foo(ints = {1, 2}) @Foo({\"b\"}) A sortedRepeatableAnnotation();",
" // BUG: Diagnostic matches: X",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")}) @Bar @Foo(ints = {1, 2}) A unsortedRepeatableAnnotation();",
"}")
.doTest();
}
@Test
void replacement() {
refactoringTestHelper
.addInputLines(
"in/A.java",
"import java.lang.annotation.Repeatable;",
"interface A {",
" @Repeatable(Foos.class)",
" @interface Foo {",
" String[] value() default {};",
" int[] ints() default {};",
" Bar[] anns() default {};",
" }",
"",
" @interface Bar {",
" String[] value() default {};",
" }",
"",
" @interface Baz {",
" String[] str() default {};",
" }",
"",
" @interface Foos {",
" Foo[] value();",
" }",
"",
" @Bar A singleAnnotation();",
" @Bar @Foo A sortedAnnotations();",
" @Foo @Bar A unsortedAnnotations();",
" @Foo() @Baz() @Bar A unsortedAnnotationsWithSomeParens();",
"",
" @Bar @Baz(str = {\"a\", \"b\"}) @Foo() A unsortedAnnotationsOneContainingAttributes();",
" @Baz(str = {\"a\", \"b\"}) @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")}) @Bar({\"b\"}) A unsortedAnnotationsWithAttributes();",
"",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")}) @Foo(ints = {1, 2}) @Foo({\"b\"}) A sortedRepeatableAnnotation();",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")}) @Bar @Foo(ints = {1, 2}) A unsortedRepeatableAnnotation();",
"",
"}")
.addOutputLines(
"out/A.java",
"import java.lang.annotation.Repeatable;",
"interface A {",
" @Repeatable(Foos.class)",
" @interface Foo {",
" String[] value() default {};",
" int[] ints() default {};",
" Bar[] anns() default {};",
" }",
"",
" @interface Bar {",
" String[] value() default {};",
" }",
"",
" @interface Baz {",
" String[] str() default {};",
" }",
"",
" @interface Foos {",
" Foo[] value();",
" }",
" @Bar A singleAnnotation();",
" @Bar @Foo A sortedAnnotations();",
" @Bar @Foo A unsortedAnnotations();",
" @Bar @Baz() @Foo() A unsortedAnnotationsWithSomeParens();",
"",
" @Bar @Baz(str = {\"a\", \"b\"}) @Foo() A unsortedAnnotationsOneContainingAttributes();",
" @Bar({\"b\"}) @Baz(str = {\"a\", \"b\"}) @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")}) A unsortedAnnotationsWithAttributes();",
"",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")}) @Foo(ints = {1, 2}) @Foo({\"b\"}) A sortedRepeatableAnnotation();",
" @Bar @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")}) @Foo(ints = {1, 2}) A unsortedRepeatableAnnotation();",
"",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -47,7 +47,7 @@ public final class MethodMatcherFactoryTest {
CompilationTestHelper.newInstance(MatchedMethodsFlagger.class, getClass());
@Test
public void testCreateWithMalformedSignatures() {
void createWithMalformedSignatures() {
MethodMatcherFactory factory = new MethodMatcherFactory();
assertThatThrownBy(() -> factory.create(ImmutableList.of("foo.bar")))
.isInstanceOf(IllegalArgumentException.class);
@@ -60,7 +60,7 @@ public final class MethodMatcherFactoryTest {
}
@Test
public void testMatcher() {
void matcher() {
compilationTestHelper
.addSourceLines(
"com/example/A.java",

View File

@@ -9,10 +9,10 @@ public final class MethodReferenceUsageCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(MethodReferenceUsageCheck.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(new MethodReferenceUsageCheck(), getClass());
BugCheckerRefactoringTestHelper.newInstance(MethodReferenceUsageCheck.class, getClass());
@Test
public void testIdentification() {
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -201,7 +201,7 @@ public final class MethodReferenceUsageCheckTest {
}
@Test
public void testReplacement() {
void replacement() {
refactoringTestHelper
.addInputLines(
"in/A.java",

View File

@@ -0,0 +1,93 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.base.Predicates.containsPattern;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
public final class MissingRefasterAnnotationCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(MissingRefasterAnnotationCheck.class, getClass())
.expectErrorMessage(
"X",
containsPattern(
"The Refaster template contains a method without any Refaster annotations"));
@Test
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import com.google.errorprone.refaster.annotation.AfterTemplate;",
"import com.google.errorprone.refaster.annotation.AlsoNegation;",
"import com.google.errorprone.refaster.annotation.BeforeTemplate;",
"import java.util.Map;",
"",
"class A {",
" // BUG: Diagnostic matches: X",
" static final class MethodLacksBeforeTemplateAnnotation {",
" @BeforeTemplate",
" boolean before1(String string) {",
" return string.equals(\"\");",
" }",
"",
" // @BeforeTemplate is missing",
" boolean before2(String string) {",
" return string.length() == 0;",
" }",
"",
" @AfterTemplate",
" @AlsoNegation",
" boolean after(String string) {",
" return string.isEmpty();",
" }",
" }",
"",
" // BUG: Diagnostic matches: X",
" static final class MethodLacksAfterTemplateAnnotation {",
" @BeforeTemplate",
" boolean before(String string) {",
" return string.equals(\"\");",
" }",
"",
" // @AfterTemplate is missing",
" boolean after(String string) {",
" return string.isEmpty();",
" }",
" }",
"",
" // BUG: Diagnostic matches: X",
" abstract class MethodLacksPlaceholderAnnotation<K, V> {",
" // @Placeholder is missing",
" abstract V function(K key);",
"",
" @BeforeTemplate",
" void before(Map<K, V> map, K key) {",
" if (!map.containsKey(key)) {",
" map.put(key, function(key));",
" }",
" }",
"",
" @AfterTemplate",
" void after(Map<K, V> map, K key) {",
" map.computeIfAbsent(key, k -> function(k));",
" }",
" }",
"",
" static final class ValidRefasterTemplate {",
" @BeforeTemplate",
" void unusedPureFunctionCall(Object o) {",
" o.toString();",
" }",
" }",
"",
" static final class NotARefasterTemplate {",
" @Override",
" public String toString() {",
" return \"This is not a Refaster template\";",
" }",
" }",
"}")
.doTest();
}
}

View File

@@ -9,7 +9,7 @@ public final class PrimitiveComparisonCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(PrimitiveComparisonCheck.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(new PrimitiveComparisonCheck(), getClass());
BugCheckerRefactoringTestHelper.newInstance(PrimitiveComparisonCheck.class, getClass());
// XXX: There are no tests for multiple replacements within the same expression:
// - Error Prone doesn't currently support this, it seems.
@@ -19,7 +19,7 @@ public final class PrimitiveComparisonCheckTest {
// The logic for `char` and `short` is exactly analogous to the `byte` case.
@Test
public void testByteComparison() {
void byteComparison() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -108,7 +108,7 @@ public final class PrimitiveComparisonCheckTest {
}
@Test
public void testIntComparison() {
void intComparison() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -201,7 +201,7 @@ public final class PrimitiveComparisonCheckTest {
}
@Test
public void testLongComparison() {
void longComparison() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -278,7 +278,7 @@ public final class PrimitiveComparisonCheckTest {
}
@Test
public void testFloatComparison() {
void floatComparison() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -335,7 +335,7 @@ public final class PrimitiveComparisonCheckTest {
}
@Test
public void testDoubleComparison() {
void doubleComparison() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -396,7 +396,7 @@ public final class PrimitiveComparisonCheckTest {
}
@Test
public void testStringComparison() {
void stringComparison() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -429,7 +429,7 @@ public final class PrimitiveComparisonCheckTest {
// XXX: If the explicit `<A, BoxedPrimitive>` generic type information was necessary, then this
// replacement drops too much information.
@Test
public void testReplacementWithPrimitiveVariants() {
void replacementWithPrimitiveVariants() {
refactoringTestHelper
.addInputLines(
"in/A.java",
@@ -483,7 +483,7 @@ public final class PrimitiveComparisonCheckTest {
// XXX: If the explicit `<A>` generic type information was necessary, then this replacement drops
// too much information.
@Test
public void testReplacementWithBoxedVariants() {
void replacementWithBoxedVariants() {
refactoringTestHelper
.addInputLines(
"in/A.java",
@@ -535,7 +535,7 @@ public final class PrimitiveComparisonCheckTest {
}
@Test
public void testReplacementWithPrimitiveVariantsUsingStaticImports() {
void replacementWithPrimitiveVariantsUsingStaticImports() {
refactoringTestHelper
.addInputLines(
"in/A.java",
@@ -574,7 +574,7 @@ public final class PrimitiveComparisonCheckTest {
}
@Test
public void testReplacementWithBoxedVariantsUsingStaticImports() {
void replacementWithBoxedVariantsUsingStaticImports() {
refactoringTestHelper
.addInputLines(
"in/A.java",
@@ -615,7 +615,7 @@ public final class PrimitiveComparisonCheckTest {
}
@Test
public void testReplacementWithPrimitiveVariantsInComplexSyntacticalContext() {
void replacementWithPrimitiveVariantsInComplexSyntacticalContext() {
refactoringTestHelper
.addInputLines(
"in/A.java",
@@ -647,7 +647,7 @@ public final class PrimitiveComparisonCheckTest {
}
@Test
public void testReplacementWithBoxedVariantsInComplexSyntacticalContext() {
void replacementWithBoxedVariantsInComplexSyntacticalContext() {
refactoringTestHelper
.addInputLines(
"in/A.java",

View File

@@ -18,10 +18,10 @@ public final class RedundantStringConversionCheckTest {
ImmutableList.of(
"-XepOpt:RedundantStringConversion:ExtraConversionMethods=java.lang.Enum#name(),A#name(),A.B#toString(int)"));
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(new RedundantStringConversionCheck(), getClass());
BugCheckerRefactoringTestHelper.newInstance(RedundantStringConversionCheck.class, getClass());
@Test
public void testIdentificationOfIdentityTransformation() {
void identificationOfIdentityTransformation() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -44,7 +44,7 @@ public final class RedundantStringConversionCheckTest {
}
@Test
public void testIdentificationWithinMutatingAssignment() {
void identificationWithinMutatingAssignment() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -100,7 +100,7 @@ public final class RedundantStringConversionCheckTest {
}
@Test
public void testIdentificationWithinBinaryOperation() {
void identificationWithinBinaryOperation() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -186,7 +186,7 @@ public final class RedundantStringConversionCheckTest {
}
@Test
public void testIdentificationWithinStringBuilderMethod() {
void identificationWithinStringBuilderMethod() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -235,7 +235,7 @@ public final class RedundantStringConversionCheckTest {
// XXX: Also test the other formatter methods.
@Test
public void testIdentificationWithinFormatterMethod() {
void identificationWithinFormatterMethod() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -280,7 +280,7 @@ public final class RedundantStringConversionCheckTest {
}
@Test
public void testIdentificationWithinGuavaGuardMethod() {
void identificationWithinGuavaGuardMethod() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -340,7 +340,7 @@ public final class RedundantStringConversionCheckTest {
}
@Test
public void testIdentificationWithinSlf4jLoggerMethod() {
void identificationWithinSlf4jLoggerMethod() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -395,7 +395,7 @@ public final class RedundantStringConversionCheckTest {
}
@Test
public void testIdentificationOfCustomConversionMethod() {
void identificationOfCustomConversionMethod() {
customizedCompilationTestHelper
.addSourceLines(
"A.java",
@@ -486,7 +486,7 @@ public final class RedundantStringConversionCheckTest {
}
@Test
public void testReplacement() {
void replacement() {
refactoringTestHelper
.addInputLines(
"in/A.java",

View File

@@ -0,0 +1,68 @@
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;
public final class RefasterAnyOfUsageCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(RefasterAnyOfUsageCheck.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(RefasterAnyOfUsageCheck.class, getClass());
@Test
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import com.google.errorprone.refaster.Refaster;",
"import com.google.errorprone.refaster.annotation.BeforeTemplate;",
"",
"class A {",
" @BeforeTemplate",
" String before(String str) {",
" // BUG: Diagnostic contains:",
" Refaster.anyOf();",
" // BUG: Diagnostic contains:",
" return Refaster.anyOf(str);",
" }",
"",
" @BeforeTemplate",
" Object before2(String str, Object obj) {",
" return Refaster.anyOf(str, obj);",
" }",
"}")
.doTest();
}
@Test
void replacement() {
refactoringTestHelper
.addInputLines(
"in/A.java",
"import com.google.errorprone.refaster.Refaster;",
"import com.google.errorprone.refaster.annotation.BeforeTemplate;",
"",
"class A {",
" @BeforeTemplate",
" String before(String str) {",
" Refaster.anyOf();",
" return Refaster.anyOf(str);",
" }",
"}")
.addOutputLines(
"out/A.java",
"import com.google.errorprone.refaster.Refaster;",
"import com.google.errorprone.refaster.annotation.BeforeTemplate;",
"",
"class A {",
" @BeforeTemplate",
" String before(String str) {",
" Refaster.anyOf();",
" return str;",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -5,15 +5,12 @@ 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.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CodeTransformer;
import com.google.errorprone.ErrorProneFlags;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
@@ -77,9 +74,6 @@ public final class RefasterCheckTest {
*/
private static final Pattern TEMPLATE_FQCN_TRIM_FOR_GROUP_NAME =
Pattern.compile(".*\\.|Templates\\$.*");
/** All Refaster templates on the classpath, indexed by their name. */
private static final ImmutableListMultimap<String, CodeTransformer> ALL_CODE_TRANSFORMERS =
RefasterCheck.loadAllCodeTransformers();
/**
* A mapping from template group names to associated template names.
*
@@ -87,7 +81,7 @@ public final class RefasterCheckTest {
* templates, while the keys correspond to the associated top-level "aggregator" classes.
*/
private static final ImmutableSetMultimap<String, String> TEMPLATES_BY_GROUP =
indexTemplateNamesByGroup(ALL_CODE_TRANSFORMERS.keySet());
indexTemplateNamesByGroup(RefasterCheck.ALL_CODE_TRANSFORMERS.get().keySet());
/** Returns every known template group name as a parameterized test argument. */
@SuppressWarnings("UnusedMethod" /* Used as a `@MethodSource`. */)
@@ -104,7 +98,7 @@ public final class RefasterCheckTest {
// 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.of(e.getKey(), e.getValue()));
.map(e -> arguments(e.getKey(), e.getValue()));
}
/**
@@ -112,10 +106,10 @@ public final class RefasterCheckTest {
* 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 #testReplacement}'s coverage is exhaustive.
* that in turn {@link #replacement}'s coverage is exhaustive.
*/
@Test
public void testLoadAllCodeTransformers() {
void loadAllCodeTransformers() {
assertThat(TEMPLATES_BY_GROUP.keySet()).hasSameElementsAs(TEMPLATE_GROUPS);
}
@@ -123,9 +117,9 @@ public final class RefasterCheckTest {
* Verifies for each of the {@link #TEMPLATE_GROUPS} that the associated code transformers have
* the desired effect.
*/
@ParameterizedTest
@MethodSource("templateGroupsUnderTest")
public void testReplacement(String group) {
@ParameterizedTest
void replacement(String group) {
verifyRefactoring(group, namePattern(group));
}
@@ -136,9 +130,9 @@ public final class RefasterCheckTest {
* com.google.errorprone.refaster.Refaster#anyOf} branches are tested. Idem for {@link
* com.google.errorprone.refaster.annotation.BeforeTemplate} methods in case there are multiple .
*/
@ParameterizedTest
@MethodSource("templatesUnderTest")
public void testCoverage(String group, String template) {
@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)
@@ -171,10 +165,7 @@ public final class RefasterCheckTest {
private BugCheckerRefactoringTestHelper createRestrictedRefactoringTestHelper(
String namePattern) {
return BugCheckerRefactoringTestHelper.newInstance(
new RefasterCheck(
ErrorProneFlags.fromMap(ImmutableMap.of("Refaster:NamePattern", namePattern)),
ALL_CODE_TRANSFORMERS),
getClass());
return BugCheckerRefactoringTestHelper.newInstance(RefasterCheck.class, getClass())
.setArgs("-XepOpt:Refaster:NamePattern=" + namePattern);
}
}

View File

@@ -0,0 +1,72 @@
package tech.picnic.errorprone.bugpatterns;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
public final class RequestMappingAnnotationCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(RequestMappingAnnotationCheck.class, getClass());
@Test
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import java.io.InputStream;",
"import javax.servlet.http.HttpServletRequest;",
"import javax.servlet.http.HttpServletResponse;",
"import org.springframework.http.HttpMethod;",
"import org.springframework.web.bind.annotation.DeleteMapping;",
"import org.springframework.web.bind.annotation.GetMapping;",
"import org.springframework.web.bind.annotation.PatchMapping;",
"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.RequestBody;",
"import org.springframework.web.bind.annotation.RequestHeader;",
"import org.springframework.web.bind.annotation.RequestMapping;",
"import org.springframework.web.bind.annotation.RequestMethod;",
"import org.springframework.web.bind.annotation.RequestParam;",
"import org.springframework.web.context.request.WebRequest;",
"",
"interface A {",
" A noMapping();",
" A noMapping(String param);",
" @DeleteMapping A properNoParameters();",
" @GetMapping A properPathVariable(@PathVariable String param);",
" @PatchMapping A properRequestBody(@RequestBody String body);",
" @PostMapping A properRequestHeader(@RequestHeader String header);",
" @PutMapping A properRequestParam(@RequestParam String param);",
" @RequestMapping A properInputStream(InputStream input);",
" @RequestMapping A properHttpServletRequest(HttpServletRequest request);",
" @RequestMapping A properHttpServletResponse(HttpServletResponse response);",
" @RequestMapping A properHttpMethod(HttpMethod method);",
" @RequestMapping A properWebRequest(WebRequest request);",
"",
" // BUG: Diagnostic contains:",
" @DeleteMapping A delete(String param);",
"",
" // BUG: Diagnostic contains:",
" @GetMapping A get(String param);",
"",
" // BUG: Diagnostic contains:",
" @PatchMapping A patch(String param);",
"",
" // BUG: Diagnostic contains:",
" @PostMapping A post(String param);",
"",
" // BUG: Diagnostic contains:",
" @PutMapping A put(String param);",
"",
" // BUG: Diagnostic contains:",
" @RequestMapping A requestMultiple(String param, String param2);",
"",
" // BUG: Diagnostic contains:",
" @RequestMapping A requestFirstParamViolation(String param, @PathVariable String param2);",
"",
" // BUG: Diagnostic contains:",
" @RequestMapping A requestSecondParamViolation(@RequestBody String param, String param2);",
"}")
.doTest();
}
}

View File

@@ -9,10 +9,10 @@ public final class Slf4jLogStatementCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(Slf4jLogStatementCheck.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(new Slf4jLogStatementCheck(), getClass());
BugCheckerRefactoringTestHelper.newInstance(Slf4jLogStatementCheck.class, getClass());
@Test
public void testIdentification() {
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -92,7 +92,7 @@ public final class Slf4jLogStatementCheckTest {
// XXX: Drop what's unused.
@Test
public void testReplacement() {
void replacement() {
refactoringTestHelper
.addInputLines(
"in/A.java",

View File

@@ -9,10 +9,10 @@ public final class SpringMvcAnnotationCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(SpringMvcAnnotationCheck.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(new SpringMvcAnnotationCheck(), getClass());
BugCheckerRefactoringTestHelper.newInstance(SpringMvcAnnotationCheck.class, getClass());
@Test
public void testIdentification() {
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -59,7 +59,7 @@ public final class SpringMvcAnnotationCheckTest {
}
@Test
public void testReplacement() {
void replacement() {
refactoringTestHelper
.addInputLines(
"in/A.java",

View File

@@ -10,16 +10,16 @@ public final class StaticImportCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(StaticImportCheck.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(new StaticImportCheck(), getClass());
BugCheckerRefactoringTestHelper.newInstance(StaticImportCheck.class, getClass());
@Test
public void testCandidateMethodsAreNotRedundant() {
void candidateMethodsAreNotRedundant() {
assertThat(StaticImportCheck.STATIC_IMPORT_CANDIDATE_METHODS.keySet())
.doesNotContainAnyElementsOf(StaticImportCheck.STATIC_IMPORT_CANDIDATE_CLASSES);
}
@Test
public void testIdentification() {
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
@@ -77,7 +77,7 @@ public final class StaticImportCheckTest {
}
@Test
public void testReplacement() {
void replacement() {
refactoringTestHelper
.addInputLines(
"in/A.java",

View File

@@ -0,0 +1,84 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.base.Predicates.containsPattern;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
public final class TimeZoneUsageCheckTest {
private final CompilationTestHelper compilationHelper =
CompilationTestHelper.newInstance(TimeZoneUsageCheck.class, getClass())
.expectErrorMessage(
"X",
containsPattern(
"Derive the current time from an existing `Clock` Spring bean, and don't rely on a `Clock`'s time zone"));
@Test
void identification() {
compilationHelper
.addSourceLines(
"A.java",
"import static java.time.ZoneOffset.UTC;",
"",
"import java.time.Clock;",
"import java.time.Duration;",
"import java.time.Instant;",
"import java.time.LocalDate;",
"import java.time.LocalDateTime;",
"import java.time.LocalTime;",
"",
"class A {",
" void m() {",
" Clock clock = Clock.fixed(Instant.EPOCH, UTC);",
" clock.instant();",
" clock.millis();",
" Clock.offset(clock, Duration.ZERO);",
" Clock.tick(clock, Duration.ZERO);",
"",
" // BUG: Diagnostic matches: X",
" Clock.systemUTC();",
" // BUG: Diagnostic matches: X",
" Clock.systemDefaultZone();",
" // BUG: Diagnostic matches: X",
" Clock.system(UTC);",
" // BUG: Diagnostic matches: X",
" Clock.tickMillis(UTC);",
" // BUG: Diagnostic matches: X",
" Clock.tickMinutes(UTC);",
" // BUG: Diagnostic matches: X",
" Clock.tickSeconds(UTC);",
" // BUG: Diagnostic matches: X",
" clock.getZone();",
" // BUG: Diagnostic matches: X",
" clock.withZone(UTC);",
"",
" // BUG: Diagnostic matches: X",
" Instant.now();",
" // This is equivalent to `clock.instant()`, which is fine.",
" Instant.now(clock);",
"",
" // BUG: Diagnostic matches: X",
" LocalDate.now();",
" // BUG: Diagnostic matches: X",
" LocalDate.now(clock);",
" // BUG: Diagnostic matches: X",
" LocalDate.now(UTC);",
"",
" // BUG: Diagnostic matches: X",
" LocalDateTime.now();",
" // BUG: Diagnostic matches: X",
" LocalDateTime.now(clock);",
" // BUG: Diagnostic matches: X",
" LocalDateTime.now(UTC);",
"",
" // BUG: Diagnostic matches: X",
" LocalTime.now();",
" // BUG: Diagnostic matches: X",
" LocalTime.now(clock);",
" // BUG: Diagnostic matches: X",
" LocalTime.now(UTC);",
" }",
"}")
.doTest();
}
}

View File

@@ -6,6 +6,7 @@ import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Optional;
import java.util.TreeSet;
@@ -25,11 +26,12 @@ final class CollectionTemplatesTest implements RefasterTemplateTestCase {
ImmutableSet.of(4).size() != 0,
ImmutableSet.of(5).size() > 0,
ImmutableSet.of(6).size() >= 1,
Iterables.isEmpty(ImmutableSet.of(7)));
Iterables.isEmpty(ImmutableSet.of(7)),
ImmutableSet.of(8).asList().isEmpty());
}
int testCollectionSize() {
return Iterables.size(ImmutableSet.of());
ImmutableSet<Integer> testCollectionSize() {
return ImmutableSet.of(Iterables.size(ImmutableSet.of(1)), ImmutableSet.of(2).asList().size());
}
boolean testCollectionAddAllToCollectionExpression() {
@@ -64,7 +66,7 @@ final class CollectionTemplatesTest implements RefasterTemplateTestCase {
return Lists.newArrayList(ImmutableList.of("foo"));
}
Stream<Integer> testImmutableCollectionAsListToStream() {
Stream<Integer> testImmutableCollectionStream() {
return ImmutableSet.of(1).asList().stream();
}
@@ -72,6 +74,37 @@ final class CollectionTemplatesTest implements RefasterTemplateTestCase {
return ImmutableList.copyOf(ImmutableSet.of(1));
}
boolean testImmutableCollectionContains() {
return ImmutableSet.of(1).asList().contains("foo");
}
Stream<Integer> testImmutableCollectionParallelStream() {
return ImmutableSet.of(1).asList().parallelStream();
}
String testImmutableCollectionToString() {
return ImmutableSet.of(1).asList().toString();
}
ImmutableSet<Object[]> testCollectionToArray() {
return ImmutableSet.of(
ImmutableSet.of(1).toArray(new Object[1]),
ImmutableSet.of(2).toArray(Object[]::new),
ImmutableSet.of(3).asList().toArray());
}
Integer[] testImmutableCollectionToArrayWithArray() {
return ImmutableSet.of(1).asList().toArray(new Integer[0]);
}
Integer[] testImmutableCollectionToArrayWithGenerator() {
return ImmutableSet.of(1).asList().toArray(Integer[]::new);
}
Iterator<Integer> testImmutableCollectionIterator() {
return ImmutableSet.of(1).asList().iterator();
}
ImmutableSet<Optional<Integer>> testOptionalFirstCollectionElement() {
return ImmutableSet.of(
ImmutableSet.of(0).stream().findAny(),

View File

@@ -6,6 +6,7 @@ import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Optional;
import java.util.TreeSet;
@@ -25,11 +26,12 @@ final class CollectionTemplatesTest implements RefasterTemplateTestCase {
!ImmutableSet.of(4).isEmpty(),
!ImmutableSet.of(5).isEmpty(),
!ImmutableSet.of(6).isEmpty(),
ImmutableSet.of(7).isEmpty());
ImmutableSet.of(7).isEmpty(),
ImmutableSet.of(8).isEmpty());
}
int testCollectionSize() {
return ImmutableSet.of().size();
ImmutableSet<Integer> testCollectionSize() {
return ImmutableSet.of(ImmutableSet.of(1).size(), ImmutableSet.of(2).size());
}
boolean testCollectionAddAllToCollectionExpression() {
@@ -56,7 +58,7 @@ final class CollectionTemplatesTest implements RefasterTemplateTestCase {
return new ArrayList<>(ImmutableList.of("foo"));
}
Stream<Integer> testImmutableCollectionAsListToStream() {
Stream<Integer> testImmutableCollectionStream() {
return ImmutableSet.of(1).stream();
}
@@ -64,6 +66,35 @@ final class CollectionTemplatesTest implements RefasterTemplateTestCase {
return ImmutableSet.of(1).asList();
}
boolean testImmutableCollectionContains() {
return ImmutableSet.of(1).contains("foo");
}
Stream<Integer> testImmutableCollectionParallelStream() {
return ImmutableSet.of(1).parallelStream();
}
String testImmutableCollectionToString() {
return ImmutableSet.of(1).toString();
}
ImmutableSet<Object[]> testCollectionToArray() {
return ImmutableSet.of(
ImmutableSet.of(1).toArray(), ImmutableSet.of(2).toArray(), ImmutableSet.of(3).toArray());
}
Integer[] testImmutableCollectionToArrayWithArray() {
return ImmutableSet.of(1).toArray(new Integer[0]);
}
Integer[] testImmutableCollectionToArrayWithGenerator() {
return ImmutableSet.of(1).toArray(Integer[]::new);
}
Iterator<Integer> testImmutableCollectionIterator() {
return ImmutableSet.of(1).iterator();
}
ImmutableSet<Optional<Integer>> testOptionalFirstCollectionElement() {
return ImmutableSet.of(
ImmutableSet.of(0).stream().findFirst(),

View File

@@ -83,18 +83,12 @@ final class DoubleStreamTemplatesTest implements RefasterTemplateTestCase {
DoubleStream.of(2).filter(n -> n > 2).findAny().isPresent());
}
ImmutableSet<Boolean> testDoubleStreamAllMatch() {
boolean testDoubleStreamAllMatch() {
DoublePredicate pred = i -> i > 0;
return ImmutableSet.of(
DoubleStream.of(1).noneMatch(pred.negate()),
!DoubleStream.of(2).anyMatch(pred.negate()),
DoubleStream.of(3).filter(pred.negate()).findAny().isEmpty());
return DoubleStream.of(1).noneMatch(pred.negate());
}
ImmutableSet<Boolean> testDoubleStreamAllMatch2() {
return ImmutableSet.of(
DoubleStream.of(1).noneMatch(n -> !(n > 1)),
!DoubleStream.of(2).anyMatch(n -> !(n > 2)),
DoubleStream.of(3).filter(n -> !(n > 3)).findAny().isEmpty());
boolean testDoubleStreamAllMatch2() {
return DoubleStream.of(1).noneMatch(n -> !(n > 1));
}
}

View File

@@ -82,18 +82,12 @@ final class DoubleStreamTemplatesTest implements RefasterTemplateTestCase {
DoubleStream.of(1).anyMatch(n -> n > 1), DoubleStream.of(2).anyMatch(n -> n > 2));
}
ImmutableSet<Boolean> testDoubleStreamAllMatch() {
boolean testDoubleStreamAllMatch() {
DoublePredicate pred = i -> i > 0;
return ImmutableSet.of(
DoubleStream.of(1).allMatch(pred),
DoubleStream.of(2).allMatch(pred),
DoubleStream.of(3).allMatch(pred));
return DoubleStream.of(1).allMatch(pred);
}
ImmutableSet<Boolean> testDoubleStreamAllMatch2() {
return ImmutableSet.of(
DoubleStream.of(1).allMatch(n -> n > 1),
DoubleStream.of(2).allMatch(n -> n > 2),
DoubleStream.of(3).allMatch(n -> n > 3));
boolean testDoubleStreamAllMatch2() {
return DoubleStream.of(1).allMatch(n -> n > 1);
}
}

View File

@@ -7,38 +7,15 @@ import java.util.Objects;
import java.util.stream.Stream;
final class EqualityTemplatesTest implements RefasterTemplateTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
return ImmutableSet.of(Objects.class);
}
ImmutableSet<Boolean> testPrimitiveOrReferenceEquality() {
return ImmutableSet.of(
Objects.equals(true, false),
Objects.equals((byte) 0, (byte) 1),
Objects.equals((short) 0, (short) 1),
Objects.equals(0, 1),
Objects.equals(0L, 1L),
Objects.equals(0F, 1F),
Objects.equals(0.0, 1.0),
Objects.equals(Boolean.TRUE, Boolean.FALSE),
Objects.equals(Byte.valueOf((byte) 0), Byte.valueOf((byte) 1)),
Objects.equals(Short.valueOf((short) 0), Short.valueOf((short) 1)),
Objects.equals(Integer.valueOf(0), Integer.valueOf(1)),
Objects.equals(Long.valueOf(0L), Long.valueOf(1L)),
Objects.equals(Float.valueOf(0F), Float.valueOf(1F)),
Objects.equals(Double.valueOf(0.0), Double.valueOf(1.0)),
RoundingMode.UP.equals(RoundingMode.DOWN),
Objects.equals(RoundingMode.UP, RoundingMode.DOWN),
!Objects.equals(true, false),
!Objects.equals((byte) 0, (byte) 1),
!Objects.equals((short) 0, (short) 1),
!Objects.equals(0, 1),
!Objects.equals(0L, 1L),
!Objects.equals(0F, 1F),
!Objects.equals(0.0, 1.0),
!Objects.equals(Boolean.TRUE, Boolean.FALSE),
!Objects.equals(Byte.valueOf((byte) 0), Byte.valueOf((byte) 1)),
!Objects.equals(Short.valueOf((short) 0), Short.valueOf((short) 1)),
!Objects.equals(Integer.valueOf(0), Integer.valueOf(1)),
!Objects.equals(Long.valueOf(0L), Long.valueOf(1L)),
!Objects.equals(Float.valueOf(0F), Float.valueOf(1F)),
!Objects.equals(Double.valueOf(0.0), Double.valueOf(1.0)),
!RoundingMode.UP.equals(RoundingMode.DOWN),
!Objects.equals(RoundingMode.UP, RoundingMode.DOWN));
}

View File

@@ -7,38 +7,15 @@ import java.util.Objects;
import java.util.stream.Stream;
final class EqualityTemplatesTest implements RefasterTemplateTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
return ImmutableSet.of(Objects.class);
}
ImmutableSet<Boolean> testPrimitiveOrReferenceEquality() {
return ImmutableSet.of(
true == false,
(byte) 0 == (byte) 1,
(short) 0 == (short) 1,
0 == 1,
0L == 1L,
0F == 1F,
0.0 == 1.0,
Objects.equals(Boolean.TRUE, Boolean.FALSE),
Objects.equals(Byte.valueOf((byte) 0), Byte.valueOf((byte) 1)),
Objects.equals(Short.valueOf((short) 0), Short.valueOf((short) 1)),
Objects.equals(Integer.valueOf(0), Integer.valueOf(1)),
Objects.equals(Long.valueOf(0L), Long.valueOf(1L)),
Objects.equals(Float.valueOf(0F), Float.valueOf(1F)),
Objects.equals(Double.valueOf(0.0), Double.valueOf(1.0)),
RoundingMode.UP == RoundingMode.DOWN,
RoundingMode.UP == RoundingMode.DOWN,
true != false,
(byte) 0 != (byte) 1,
(short) 0 != (short) 1,
0 != 1,
0L != 1L,
0F != 1F,
0.0 != 1.0,
!Objects.equals(Boolean.TRUE, Boolean.FALSE),
!Objects.equals(Byte.valueOf((byte) 0), Byte.valueOf((byte) 1)),
!Objects.equals(Short.valueOf((short) 0), Short.valueOf((short) 1)),
!Objects.equals(Integer.valueOf(0), Integer.valueOf(1)),
!Objects.equals(Long.valueOf(0L), Long.valueOf(1L)),
!Objects.equals(Float.valueOf(0F), Float.valueOf(1F)),
!Objects.equals(Double.valueOf(0.0), Double.valueOf(1.0)),
RoundingMode.UP != RoundingMode.DOWN,
RoundingMode.UP != RoundingMode.DOWN);
}

View File

@@ -33,25 +33,20 @@ final class ImmutableListMultimapTemplatesTest implements RefasterTemplateTestCa
ImmutableSet<ImmutableMultimap<String, Integer>> testEmptyImmutableListMultimap() {
return ImmutableSet.of(
ImmutableListMultimap.<String, Integer>builder().build(),
ImmutableMultimap.<String, Integer>builder().build(),
ImmutableMultimap.of());
ImmutableListMultimap.<String, Integer>builder().build(), ImmutableMultimap.of());
}
ImmutableSet<ImmutableMultimap<String, Integer>> testPairToImmutableListMultimap() {
return ImmutableSet.of(
ImmutableListMultimap.<String, Integer>builder().put("foo", 1).build(),
ImmutableMultimap.<String, Integer>builder().put("bar", 2).build(),
ImmutableMultimap.of("baz", 3));
ImmutableMultimap.of("bar", 2));
}
ImmutableList<ImmutableMultimap<String, Integer>> testEntryToImmutableListMultimap() {
return ImmutableList.of(
ImmutableListMultimap.<String, Integer>builder().put(Map.entry("foo", 1)).build(),
Stream.of(Map.entry("foo", 1))
.collect(toImmutableListMultimap(Map.Entry::getKey, Map.Entry::getValue)),
ImmutableMultimap.<String, Integer>builder().put(Map.entry("foo", 1)).build(),
ImmutableMultimap.of(Map.entry("foo", 1).getKey(), Map.entry("foo", 1).getValue()));
.collect(toImmutableListMultimap(Map.Entry::getKey, Map.Entry::getValue)));
}
ImmutableList<ImmutableMultimap<String, Integer>> testIterableToImmutableListMultimap() {
@@ -69,12 +64,6 @@ final class ImmutableListMultimapTemplatesTest implements RefasterTemplateTestCa
.collect(toImmutableListMultimap(Map.Entry::getKey, Map.Entry::getValue)),
ImmutableMultimap.copyOf(ImmutableListMultimap.of("foo", 1)),
ImmutableMultimap.copyOf(ImmutableListMultimap.of("foo", 1).entries()),
ImmutableMultimap.<String, Integer>builder()
.putAll(ImmutableListMultimap.of("foo", 1))
.build(),
ImmutableMultimap.<String, Integer>builder()
.putAll(ImmutableListMultimap.of("foo", 1).entries())
.build(),
ImmutableMultimap.copyOf(Iterables.cycle(Map.entry("foo", 1))));
}

View File

@@ -32,21 +32,15 @@ final class ImmutableListMultimapTemplatesTest implements RefasterTemplateTestCa
}
ImmutableSet<ImmutableMultimap<String, Integer>> testEmptyImmutableListMultimap() {
return ImmutableSet.of(
ImmutableListMultimap.of(), ImmutableListMultimap.of(), ImmutableListMultimap.of());
return ImmutableSet.of(ImmutableListMultimap.of(), ImmutableListMultimap.of());
}
ImmutableSet<ImmutableMultimap<String, Integer>> testPairToImmutableListMultimap() {
return ImmutableSet.of(
ImmutableListMultimap.of("foo", 1),
ImmutableListMultimap.of("bar", 2),
ImmutableListMultimap.of("baz", 3));
return ImmutableSet.of(ImmutableListMultimap.of("foo", 1), ImmutableListMultimap.of("bar", 2));
}
ImmutableList<ImmutableMultimap<String, Integer>> testEntryToImmutableListMultimap() {
return ImmutableList.of(
ImmutableListMultimap.of(Map.entry("foo", 1).getKey(), Map.entry("foo", 1).getValue()),
ImmutableListMultimap.of(Map.entry("foo", 1).getKey(), Map.entry("foo", 1).getValue()),
ImmutableListMultimap.of(Map.entry("foo", 1).getKey(), Map.entry("foo", 1).getValue()),
ImmutableListMultimap.of(Map.entry("foo", 1).getKey(), Map.entry("foo", 1).getValue()));
}
@@ -60,8 +54,6 @@ final class ImmutableListMultimapTemplatesTest implements RefasterTemplateTestCa
ImmutableListMultimap.copyOf(Iterables.cycle(Map.entry("foo", 1))),
ImmutableListMultimap.copyOf(ImmutableListMultimap.of("foo", 1)),
ImmutableListMultimap.copyOf(ImmutableListMultimap.of("foo", 1)),
ImmutableListMultimap.copyOf(ImmutableListMultimap.of("foo", 1)),
ImmutableListMultimap.copyOf(ImmutableListMultimap.of("foo", 1).entries()),
ImmutableListMultimap.copyOf(Iterables.cycle(Map.entry("foo", 1))));
}

View File

@@ -50,15 +50,13 @@ final class ImmutableListTemplatesTest implements RefasterTemplateTestCase {
ImmutableList.<Integer>builder().addAll(ImmutableList.of(5)::iterator).build(),
ImmutableList.<Integer>builder().addAll(ImmutableList.of(6).iterator()).build(),
ImmutableList.<Integer>builder().add(new Integer[] {7}).build(),
Stream.of(new Integer[] {8}).collect(toImmutableList()),
Arrays.stream(new Integer[] {9}).collect(toImmutableList()));
Arrays.stream(new Integer[] {8}).collect(toImmutableList()));
}
ImmutableSet<ImmutableList<Integer>> testStreamToImmutableList() {
return ImmutableSet.of(
ImmutableList.copyOf(Stream.of(1).iterator()),
ImmutableList.copyOf(Stream.of(2).iterator()),
Stream.of(3).collect(collectingAndThen(toList(), ImmutableList::copyOf)));
Stream.of(2).collect(collectingAndThen(toList(), ImmutableList::copyOf)));
}
ImmutableList<Integer> testImmutableListAsList() {

View File

@@ -49,15 +49,12 @@ final class ImmutableListTemplatesTest implements RefasterTemplateTestCase {
ImmutableList.copyOf(ImmutableList.of(5)::iterator),
ImmutableList.copyOf(ImmutableList.of(6).iterator()),
ImmutableList.copyOf(new Integer[] {7}),
ImmutableList.copyOf(new Integer[] {8}),
ImmutableList.copyOf(new Integer[] {9}));
ImmutableList.copyOf(new Integer[] {8}));
}
ImmutableSet<ImmutableList<Integer>> testStreamToImmutableList() {
return ImmutableSet.of(
Stream.of(1).collect(toImmutableList()),
Stream.of(2).collect(toImmutableList()),
Stream.of(3).collect(toImmutableList()));
Stream.of(1).collect(toImmutableList()), Stream.of(2).collect(toImmutableList()));
}
ImmutableList<Integer> testImmutableListAsList() {

View File

@@ -36,15 +36,13 @@ final class ImmutableMultisetTemplatesTest implements RefasterTemplateTestCase {
ImmutableMultiset.<Integer>builder().addAll(ImmutableMultiset.of(5)::iterator).build(),
ImmutableMultiset.<Integer>builder().addAll(ImmutableMultiset.of(6).iterator()).build(),
ImmutableMultiset.<Integer>builder().add(new Integer[] {7}).build(),
Stream.of(new Integer[] {8}).collect(toImmutableMultiset()),
Arrays.stream(new Integer[] {9}).collect(toImmutableMultiset()));
Arrays.stream(new Integer[] {8}).collect(toImmutableMultiset()));
}
ImmutableSet<ImmutableMultiset<Integer>> testStreamToImmutableMultiset() {
return ImmutableSet.of(
ImmutableMultiset.copyOf(Stream.of(1).iterator()),
ImmutableMultiset.copyOf(Stream.of(2)::iterator),
Stream.of(3).collect(collectingAndThen(toList(), ImmutableMultiset::copyOf)));
Stream.of(2).collect(collectingAndThen(toList(), ImmutableMultiset::copyOf)));
}
ImmutableMultiset<Integer> testImmutableMultisetCopyOfImmutableMultiset() {

View File

@@ -34,15 +34,12 @@ final class ImmutableMultisetTemplatesTest implements RefasterTemplateTestCase {
ImmutableMultiset.copyOf(ImmutableMultiset.of(5)::iterator),
ImmutableMultiset.copyOf(ImmutableMultiset.of(6).iterator()),
ImmutableMultiset.copyOf(new Integer[] {7}),
ImmutableMultiset.copyOf(new Integer[] {8}),
ImmutableMultiset.copyOf(new Integer[] {9}));
ImmutableMultiset.copyOf(new Integer[] {8}));
}
ImmutableSet<ImmutableMultiset<Integer>> testStreamToImmutableMultiset() {
return ImmutableSet.of(
Stream.of(1).collect(toImmutableMultiset()),
Stream.of(2).collect(toImmutableMultiset()),
Stream.of(3).collect(toImmutableMultiset()));
Stream.of(1).collect(toImmutableMultiset()), Stream.of(2).collect(toImmutableMultiset()));
}
ImmutableMultiset<Integer> testImmutableMultisetCopyOfImmutableMultiset() {

View File

@@ -48,17 +48,15 @@ final class ImmutableSetTemplatesTest implements RefasterTemplateTestCase {
ImmutableSet.<Integer>builder().addAll(ImmutableSet.of(5)::iterator).build(),
ImmutableSet.<Integer>builder().addAll(ImmutableSet.of(6).iterator()).build(),
ImmutableSet.<Integer>builder().add(new Integer[] {7}).build(),
Stream.of(new Integer[] {8}).collect(toImmutableSet()),
Arrays.stream(new Integer[] {9}).collect(toImmutableSet()));
Arrays.stream(new Integer[] {8}).collect(toImmutableSet()));
}
ImmutableSet<ImmutableSet<Integer>> testStreamToImmutableSet() {
return ImmutableSet.of(
ImmutableSet.copyOf(Stream.of(1).iterator()),
ImmutableSet.copyOf(Stream.of(2)::iterator),
Stream.of(3).distinct().collect(toImmutableSet()),
Stream.of(4).collect(collectingAndThen(toList(), ImmutableSet::copyOf)),
Stream.of(5).collect(collectingAndThen(toSet(), ImmutableSet::copyOf)));
Stream.of(2).distinct().collect(toImmutableSet()),
Stream.of(3).collect(collectingAndThen(toList(), ImmutableSet::copyOf)),
Stream.of(4).collect(collectingAndThen(toSet(), ImmutableSet::copyOf)));
}
ImmutableSet<Integer> testImmutableSetCopyOfImmutableSet() {

View File

@@ -47,8 +47,7 @@ final class ImmutableSetTemplatesTest implements RefasterTemplateTestCase {
ImmutableSet.copyOf(ImmutableSet.of(5)::iterator),
ImmutableSet.copyOf(ImmutableSet.of(6).iterator()),
ImmutableSet.copyOf(new Integer[] {7}),
ImmutableSet.copyOf(new Integer[] {8}),
ImmutableSet.copyOf(new Integer[] {9}));
ImmutableSet.copyOf(new Integer[] {8}));
}
ImmutableSet<ImmutableSet<Integer>> testStreamToImmutableSet() {
@@ -56,8 +55,7 @@ final class ImmutableSetTemplatesTest implements RefasterTemplateTestCase {
Stream.of(1).collect(toImmutableSet()),
Stream.of(2).collect(toImmutableSet()),
Stream.of(3).collect(toImmutableSet()),
Stream.of(4).collect(toImmutableSet()),
Stream.of(5).collect(toImmutableSet()));
Stream.of(4).collect(toImmutableSet()));
}
ImmutableSet<Integer> testImmutableSetCopyOfImmutableSet() {

View File

@@ -55,14 +55,12 @@ final class ImmutableSortedMultisetTemplatesTest implements RefasterTemplateTest
.addAll(ImmutableMultiset.of(8).iterator())
.build(),
ImmutableSortedMultiset.<Integer>naturalOrder().add(new Integer[] {9}).build(),
Stream.of(new Integer[] {10}).collect(toImmutableSortedMultiset(naturalOrder())),
Arrays.stream(new Integer[] {11}).collect(toImmutableSortedMultiset(naturalOrder())));
Arrays.stream(new Integer[] {10}).collect(toImmutableSortedMultiset(naturalOrder())));
}
ImmutableSet<ImmutableSortedMultiset<Integer>> testStreamToImmutableSortedMultiset() {
return ImmutableSet.of(
ImmutableSortedMultiset.copyOf(Stream.of(1).iterator()),
ImmutableSortedMultiset.copyOf(Stream.of(2)::iterator),
Stream.of(3).collect(collectingAndThen(toList(), ImmutableSortedMultiset::copyOf)));
Stream.of(2).collect(collectingAndThen(toList(), ImmutableSortedMultiset::copyOf)));
}
}

View File

@@ -47,14 +47,12 @@ final class ImmutableSortedMultisetTemplatesTest implements RefasterTemplateTest
ImmutableSortedMultiset.copyOf(ImmutableMultiset.of(7)::iterator),
ImmutableSortedMultiset.copyOf(ImmutableMultiset.of(8).iterator()),
ImmutableSortedMultiset.copyOf(new Integer[] {9}),
ImmutableSortedMultiset.copyOf(new Integer[] {10}),
ImmutableSortedMultiset.copyOf(new Integer[] {11}));
ImmutableSortedMultiset.copyOf(new Integer[] {10}));
}
ImmutableSet<ImmutableSortedMultiset<Integer>> testStreamToImmutableSortedMultiset() {
return ImmutableSet.of(
Stream.of(1).collect(toImmutableSortedMultiset(naturalOrder())),
Stream.of(2).collect(toImmutableSortedMultiset(naturalOrder())),
Stream.of(3).collect(toImmutableSortedMultiset(naturalOrder())));
Stream.of(2).collect(toImmutableSortedMultiset(naturalOrder())));
}
}

View File

@@ -50,14 +50,12 @@ final class ImmutableSortedSetTemplatesTest implements RefasterTemplateTestCase
ImmutableSortedSet.<Integer>naturalOrder().addAll(ImmutableSet.of(7)::iterator).build(),
ImmutableSortedSet.<Integer>naturalOrder().addAll(ImmutableSet.of(8).iterator()).build(),
ImmutableSortedSet.<Integer>naturalOrder().add(new Integer[] {9}).build(),
Stream.of(new Integer[] {10}).collect(toImmutableSortedSet(naturalOrder())),
Arrays.stream(new Integer[] {11}).collect(toImmutableSortedSet(naturalOrder())));
Arrays.stream(new Integer[] {10}).collect(toImmutableSortedSet(naturalOrder())));
}
ImmutableSet<ImmutableSortedSet<Integer>> testStreamToImmutableSortedSet() {
return ImmutableSet.of(
ImmutableSortedSet.copyOf(Stream.of(1).iterator()),
ImmutableSortedSet.copyOf(Stream.of(2)::iterator),
Stream.of(3).collect(collectingAndThen(toList(), ImmutableSortedSet::copyOf)));
Stream.of(2).collect(collectingAndThen(toList(), ImmutableSortedSet::copyOf)));
}
}

View File

@@ -47,14 +47,12 @@ final class ImmutableSortedSetTemplatesTest implements RefasterTemplateTestCase
ImmutableSortedSet.copyOf(ImmutableSet.of(7)::iterator),
ImmutableSortedSet.copyOf(ImmutableSet.of(8).iterator()),
ImmutableSortedSet.copyOf(new Integer[] {9}),
ImmutableSortedSet.copyOf(new Integer[] {10}),
ImmutableSortedSet.copyOf(new Integer[] {11}));
ImmutableSortedSet.copyOf(new Integer[] {10}));
}
ImmutableSet<ImmutableSortedSet<Integer>> testStreamToImmutableSortedSet() {
return ImmutableSet.of(
Stream.of(1).collect(toImmutableSortedSet(naturalOrder())),
Stream.of(2).collect(toImmutableSortedSet(naturalOrder())),
Stream.of(3).collect(toImmutableSortedSet(naturalOrder())));
Stream.of(2).collect(toImmutableSortedSet(naturalOrder())));
}
}

View File

@@ -87,18 +87,12 @@ final class IntStreamTemplatesTest implements RefasterTemplateTestCase {
IntStream.of(2).filter(n -> n > 2).findAny().isPresent());
}
ImmutableSet<Boolean> testIntStreamAllMatch() {
boolean testIntStreamAllMatch() {
IntPredicate pred = i -> i > 0;
return ImmutableSet.of(
IntStream.of(1).noneMatch(pred.negate()),
!IntStream.of(2).anyMatch(pred.negate()),
IntStream.of(3).filter(pred.negate()).findAny().isEmpty());
return IntStream.of(1).noneMatch(pred.negate());
}
ImmutableSet<Boolean> testIntStreamAllMatch2() {
return ImmutableSet.of(
IntStream.of(1).noneMatch(n -> !(n > 1)),
!IntStream.of(2).anyMatch(n -> !(n > 2)),
IntStream.of(3).filter(n -> !(n > 3)).findAny().isEmpty());
boolean testIntStreamAllMatch2() {
return IntStream.of(1).noneMatch(n -> !(n > 1));
}
}

View File

@@ -86,18 +86,12 @@ final class IntStreamTemplatesTest implements RefasterTemplateTestCase {
IntStream.of(1).anyMatch(n -> n > 1), IntStream.of(2).anyMatch(n -> n > 2));
}
ImmutableSet<Boolean> testIntStreamAllMatch() {
boolean testIntStreamAllMatch() {
IntPredicate pred = i -> i > 0;
return ImmutableSet.of(
IntStream.of(1).allMatch(pred),
IntStream.of(2).allMatch(pred),
IntStream.of(3).allMatch(pred));
return IntStream.of(1).allMatch(pred);
}
ImmutableSet<Boolean> testIntStreamAllMatch2() {
return ImmutableSet.of(
IntStream.of(1).allMatch(n -> n > 1),
IntStream.of(2).allMatch(n -> n > 2),
IntStream.of(3).allMatch(n -> n > 3));
boolean testIntStreamAllMatch2() {
return IntStream.of(1).allMatch(n -> n > 1);
}
}

View File

@@ -87,18 +87,12 @@ final class LongStreamTemplatesTest implements RefasterTemplateTestCase {
LongStream.of(2).filter(n -> n > 2).findAny().isPresent());
}
ImmutableSet<Boolean> testLongStreamAllMatch() {
boolean testLongStreamAllMatch() {
LongPredicate pred = i -> i > 0;
return ImmutableSet.of(
LongStream.of(1).noneMatch(pred.negate()),
!LongStream.of(2).anyMatch(pred.negate()),
LongStream.of(3).filter(pred.negate()).findAny().isEmpty());
return LongStream.of(1).noneMatch(pred.negate());
}
ImmutableSet<Boolean> testLongStreamAllMatch2() {
return ImmutableSet.of(
LongStream.of(1).noneMatch(n -> !(n > 1)),
!LongStream.of(2).anyMatch(n -> !(n > 2)),
LongStream.of(3).filter(n -> !(n > 3)).findAny().isEmpty());
boolean testLongStreamAllMatch2() {
return LongStream.of(1).noneMatch(n -> !(n > 1));
}
}

View File

@@ -86,18 +86,12 @@ final class LongStreamTemplatesTest implements RefasterTemplateTestCase {
LongStream.of(1).anyMatch(n -> n > 1), LongStream.of(2).anyMatch(n -> n > 2));
}
ImmutableSet<Boolean> testLongStreamAllMatch() {
boolean testLongStreamAllMatch() {
LongPredicate pred = i -> i > 0;
return ImmutableSet.of(
LongStream.of(1).allMatch(pred),
LongStream.of(2).allMatch(pred),
LongStream.of(3).allMatch(pred));
return LongStream.of(1).allMatch(pred);
}
ImmutableSet<Boolean> testLongStreamAllMatch2() {
return ImmutableSet.of(
LongStream.of(1).allMatch(n -> n > 1),
LongStream.of(2).allMatch(n -> n > 2),
LongStream.of(3).allMatch(n -> n > 3));
boolean testLongStreamAllMatch2() {
return LongStream.of(1).allMatch(n -> n > 1);
}
}

View File

@@ -24,16 +24,12 @@ final class ReactorTemplatesTest implements RefasterTemplateTestCase {
return Flux.defer(() -> Flux.error(new IllegalStateException()));
}
ImmutableSet<Mono<Void>> testMonoErrorSupplier() {
return ImmutableSet.of(
Mono.error(((Supplier<RuntimeException>) null)::get),
Mono.error(() -> ((Supplier<RuntimeException>) null).get()));
Mono<Void> testMonoErrorSupplier() {
return Mono.error(() -> ((Supplier<RuntimeException>) null).get());
}
ImmutableSet<Flux<Void>> testFluxErrorSupplier() {
return ImmutableSet.of(
Flux.error(((Supplier<RuntimeException>) null)::get),
Flux.error(() -> ((Supplier<RuntimeException>) null).get()));
Flux<Void> testFluxErrorSupplier() {
return Flux.error(() -> ((Supplier<RuntimeException>) null).get());
}
Mono<String> testMonoThenReturn() {

View File

@@ -26,16 +26,12 @@ final class ReactorTemplatesTest implements RefasterTemplateTestCase {
return Flux.error(() -> new IllegalStateException());
}
ImmutableSet<Mono<Void>> testMonoErrorSupplier() {
return ImmutableSet.of(
Mono.error(((Supplier<RuntimeException>) null)),
Mono.error(((Supplier<RuntimeException>) null)));
Mono<Void> testMonoErrorSupplier() {
return Mono.error(((Supplier<RuntimeException>) null));
}
ImmutableSet<Flux<Void>> testFluxErrorSupplier() {
return ImmutableSet.of(
Flux.error(((Supplier<RuntimeException>) null)),
Flux.error(((Supplier<RuntimeException>) null)));
Flux<Void> testFluxErrorSupplier() {
return Flux.error(((Supplier<RuntimeException>) null));
}
Mono<String> testMonoThenReturn() {

View File

@@ -17,15 +17,15 @@ final class StreamTemplatesTest implements RefasterTemplateTestCase {
return ImmutableSet.of(Objects.class, Streams.class, not(null), reverseOrder());
}
Stream<String> testEmptyStream() {
return Stream.of();
}
ImmutableSet<Stream<String>> testStreamOfNullable() {
return ImmutableSet.of(
Stream.of("a").filter(Objects::nonNull), Optional.ofNullable("b").stream());
}
Stream<String> testStreamOfArray() {
return Stream.of(new String[] {"foo", "bar"});
}
Stream<Integer> testConcatOneStream() {
return Streams.concat(Stream.of(1));
}
@@ -114,20 +114,10 @@ final class StreamTemplatesTest implements RefasterTemplateTestCase {
Predicate<String> pred = String::isBlank;
return ImmutableSet.of(
Stream.of("foo").noneMatch(not(String::isBlank)),
Stream.of("bar").noneMatch(pred.negate()),
!Stream.of("baz").anyMatch(not(s -> s.length() > 1)),
!Stream.of("qux").anyMatch(pred.negate()),
Stream.of("quux").filter(not(String::isEmpty)).findAny().isEmpty(),
Stream.of("quuz").filter(pred.negate()).findAny().isEmpty(),
Stream.of(Boolean.TRUE).noneMatch(b -> !b),
!Stream.of(Boolean.TRUE).anyMatch(b -> !b),
Stream.of(Boolean.TRUE).filter(b -> !b).findAny().isEmpty());
Stream.of("bar").noneMatch(pred.negate()));
}
ImmutableSet<Boolean> testStreamAllMatch2() {
return ImmutableSet.of(
Stream.of("foo").noneMatch(s -> !s.isBlank()),
!Stream.of("bar").anyMatch(s -> !s.isEmpty()),
Stream.of("baz").filter(s -> !s.isBlank()).findAny().isEmpty());
boolean testStreamAllMatch2() {
return Stream.of("foo").noneMatch(s -> !s.isBlank());
}
}

View File

@@ -7,6 +7,7 @@ import static java.util.function.Predicate.not;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Streams;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
@@ -18,14 +19,14 @@ final class StreamTemplatesTest implements RefasterTemplateTestCase {
return ImmutableSet.of(Objects.class, Streams.class, not(null), reverseOrder());
}
Stream<String> testEmptyStream() {
return Stream.empty();
}
ImmutableSet<Stream<String>> testStreamOfNullable() {
return ImmutableSet.of(Stream.ofNullable("a"), Stream.ofNullable("b"));
}
Stream<String> testStreamOfArray() {
return Arrays.stream(new String[] {"foo", "bar"});
}
Stream<Integer> testConcatOneStream() {
return Stream.of(1);
}
@@ -112,21 +113,10 @@ final class StreamTemplatesTest implements RefasterTemplateTestCase {
ImmutableSet<Boolean> testStreamAllMatch() {
Predicate<String> pred = String::isBlank;
return ImmutableSet.of(
Stream.of("foo").allMatch(String::isBlank),
Stream.of("bar").allMatch(pred),
Stream.of("baz").allMatch(s -> s.length() > 1),
Stream.of("qux").allMatch(pred),
Stream.of("quux").allMatch(String::isEmpty),
Stream.of("quuz").allMatch(pred),
Stream.of(Boolean.TRUE).allMatch(b -> b),
Stream.of(Boolean.TRUE).allMatch(b -> b),
Stream.of(Boolean.TRUE).allMatch(b -> b));
Stream.of("foo").allMatch(String::isBlank), Stream.of("bar").allMatch(pred));
}
ImmutableSet<Boolean> testStreamAllMatch2() {
return ImmutableSet.of(
Stream.of("foo").allMatch(s -> s.isBlank()),
Stream.of("bar").allMatch(s -> s.isEmpty()),
Stream.of("baz").allMatch(s -> s.isBlank()));
boolean testStreamAllMatch2() {
return Stream.of("foo").allMatch(s -> s.isBlank());
}
}

View File

@@ -1,5 +1,6 @@
package tech.picnic.errorprone.bugpatterns;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.joining;
import com.google.common.base.Joiner;
@@ -8,7 +9,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;
@@ -17,7 +17,7 @@ final class StringTemplatesTest implements RefasterTemplateTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
return ImmutableSet.of(
Arrays.class, Joiner.class, StandardCharsets.class, Stream.class, Streams.class, joining());
Arrays.class, Joiner.class, Stream.class, Streams.class, joining(), UTF_8);
}
ImmutableSet<Boolean> testStringIsEmpty() {
@@ -51,12 +51,11 @@ final class StringTemplatesTest implements RefasterTemplateTestCase {
ImmutableSet<String> testJoinStrings() {
return ImmutableSet.of(
Joiner.on("a").join(new String[] {"foo", "bar"}),
Joiner.on("b").join(new CharSequence[] {"baz", "qux"}),
Stream.of(new String[] {"foo", "bar"}).collect(joining("c")),
Arrays.stream(new CharSequence[] {"baz", "qux"}).collect(joining("d")),
Joiner.on("e").join(ImmutableList.of("foo", "bar")),
Streams.stream(Iterables.cycle(ImmutableList.of("foo", "bar"))).collect(joining("f")),
ImmutableList.of("baz", "qux").stream().collect(joining("g")));
Joiner.on("b").join(new CharSequence[] {"foo", "bar"}),
Arrays.stream(new String[] {"foo", "bar"}).collect(joining("c")),
Joiner.on("d").join(ImmutableList.of("foo", "bar")),
Streams.stream(Iterables.cycle(ImmutableList.of("foo", "bar"))).collect(joining("e")),
ImmutableList.of("foo", "bar").stream().collect(joining("f")));
}
String testSubstringRemainder() {
@@ -64,6 +63,6 @@ final class StringTemplatesTest implements RefasterTemplateTestCase {
}
int testUtf8EncodedLength() {
return "foo".getBytes(StandardCharsets.UTF_8).length;
return "foo".getBytes(UTF_8).length;
}
}

View File

@@ -1,5 +1,6 @@
package tech.picnic.errorprone.bugpatterns;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.joining;
import com.google.common.base.Joiner;
@@ -9,7 +10,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;
@@ -18,7 +18,7 @@ final class StringTemplatesTest implements RefasterTemplateTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
return ImmutableSet.of(
Arrays.class, Joiner.class, StandardCharsets.class, Stream.class, Streams.class, joining());
Arrays.class, Joiner.class, Stream.class, Streams.class, joining(), UTF_8);
}
ImmutableSet<Boolean> testStringIsEmpty() {
@@ -51,12 +51,11 @@ final class StringTemplatesTest implements RefasterTemplateTestCase {
ImmutableSet<String> testJoinStrings() {
return ImmutableSet.of(
String.join("a", new String[] {"foo", "bar"}),
String.join("b", new CharSequence[] {"baz", "qux"}),
String.join("b", new CharSequence[] {"foo", "bar"}),
String.join("c", new String[] {"foo", "bar"}),
String.join("d", new CharSequence[] {"baz", "qux"}),
String.join("e", ImmutableList.of("foo", "bar")),
String.join("f", Iterables.cycle(ImmutableList.of("foo", "bar"))),
String.join("g", ImmutableList.of("baz", "qux")));
String.join("d", ImmutableList.of("foo", "bar")),
String.join("e", Iterables.cycle(ImmutableList.of("foo", "bar"))),
String.join("f", ImmutableList.of("foo", "bar")));
}
String testSubstringRemainder() {

View File

@@ -28,7 +28,6 @@ final class TimeTemplatesTest implements RefasterTemplateTestCase {
return ImmutableSet.of(
ZoneId.of("GMT"),
ZoneId.of("UTC"),
ZoneId.of("Z"),
ZoneId.of("+0"),
ZoneId.of("-0"),
ZoneOffset.UTC,

View File

@@ -31,7 +31,6 @@ final class TimeTemplatesTest implements RefasterTemplateTestCase {
ZoneOffset.UTC,
ZoneOffset.UTC,
ZoneOffset.UTC,
ZoneOffset.UTC,
ZoneOffset.UTC);
}

324
pom.xml
View File

@@ -17,7 +17,7 @@
</organization>
<licenses>
<license>
<name>MIT License</name>
<name>MIT</name>
<url>https://opensource.org/licenses/mit-license.php</url>
<distribution>repo</distribution>
</license>
@@ -35,6 +35,7 @@
<modules>
<module>error-prone-contrib</module>
<module>refaster-resource-compiler</module>
<module>refaster-support</module>
</modules>
<scm>
@@ -73,10 +74,7 @@
-XX:TieredStopAtLevel=1
<!-- We cap memory usage. This is especially relevant on Travis CI,
but locally this should also be more than enough. -->
<!-- XXX: RefasterCheckTest` requires more memory, so here we use
more than in other projects. Review how to reconcile this. (Extra
property?) -->
-Xmx1024m
-Xmx512m
<!-- This argument cannot be set through Surefire's
'systemPropertyVariables' configuration setting. Setting the file
encoding is necessary because forked unit test invocations
@@ -99,9 +97,10 @@
build number. When building locally, this number is obviously absent.
So we provide a default value. -->
<build.number>LOCAL</build.number>
<!-- Property using which additional Error Prone flags can be
specified. Used by the `patch` profile to enable patching. -->
<error-prone.args />
<!-- Properties using which additional Error Prone flags can be
specified. Used by the `patch` and `self-check` profiles. -->
<error-prone.patch-args />
<error-prone.self-check-args />
<!-- The Maven `groupId` under which Error Prone dependencies are
published. By default we use an official Error Prone release. This
property allows the `error-prone-fork` profile below to build the
@@ -111,15 +110,27 @@
<!-- Dependency and plugin versions that are referenced in more than
one place. We use these to keep dependencies in sync. Version numbers
that need to be referenced only once should *not* be listed here. -->
<version.auto-service>1.0-rc7</version.auto-service>
<version.error-prone>2.4.0</version.error-prone>
<version.auto-service>1.0</version.auto-service>
<version.error-prone>${version.error-prone-orig}</version.error-prone>
<version.error-prone-fork>v${version.error-prone-orig}-picnic-1</version.error-prone-fork>
<version.error-prone-orig>2.8.0</version.error-prone-orig>
<version.error-prone-slf4j>0.1.4</version.error-prone-slf4j>
<version.findbugs-format-string>3.0.0</version.findbugs-format-string>
<version.guava-beta-checker>1.0</version.guava-beta-checker>
<version.jdk>11</version.jdk>
<version.maven>3.6.3</version.maven>
<version.mockito>3.7.0</version.mockito>
<version.mockito>3.11.2</version.mockito>
<version.nopen-checker>1.0.1</version.nopen-checker>
<version.nullaway>0.8.0</version.nullaway>
<version.nullaway>0.9.1</version.nullaway>
<!-- XXX: Two other dependencies are potentially of interest:
`com.palantir.assertj-automation:assertj-refaster-rules` and
`com.palantir.baseline:baseline-refaster-rules` contain Refaster rules
which aren't currently applied. We should use
`RefasterRuleBuilderScanner` to convert those to `.refaster` files so
that we can pick them up. (But in case of `baseline-refaster-rules`
perhaps we can simply incorporate all of them.) -->
<version.palantir-assertj-automation>0.2.1</version.palantir-assertj-automation>
<version.palantir-baseline>4.7.0</version.palantir-baseline>
<version.surefire>2.22.2</version.surefire>
</properties>
@@ -155,17 +166,22 @@
<artifactId>refaster-resource-compiler</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>refaster-support</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>2.12.1</version>
<version>2.12.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.google.auto</groupId>
<artifactId>auto-common</artifactId>
<version>0.11</version>
<version>1.1</version>
</dependency>
<dependency>
<groupId>com.google.auto.service</groupId>
@@ -175,7 +191,14 @@
<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value-annotations</artifactId>
<version>1.7.4</version>
<version>1.8.2</version>
</dependency>
<!-- Specified as a workaround for
https://github.com/mojohaus/versions-maven-plugin/issues/244. -->
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jFormatString</artifactId>
<version>${version.findbugs-format-string}</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
@@ -197,7 +220,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-bom</artifactId>
<version>30.1-jre</version>
<version>30.1.1-jre</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -215,6 +238,20 @@
</dependency>
<!-- Specified as a workaround for
https://github.com/mojohaus/versions-maven-plugin/issues/244. -->
<dependency>
<groupId>com.palantir.assertj-automation</groupId>
<artifactId>assertj-error-prone</artifactId>
<version>${version.palantir-assertj-automation}</version>
</dependency>
<!-- Specified as a workaround for
https://github.com/mojohaus/versions-maven-plugin/issues/244. -->
<dependency>
<groupId>com.palantir.baseline</groupId>
<artifactId>baseline-error-prone</artifactId>
<version>${version.palantir-baseline}</version>
</dependency>
<!-- Specified as a workaround for
https://github.com/mojohaus/versions-maven-plugin/issues/244. -->
<dependency>
<groupId>com.uber.nullaway</groupId>
<artifactId>nullaway</artifactId>
@@ -223,14 +260,14 @@
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-bom</artifactId>
<version>2020.0.3</version>
<version>2020.0.9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxjava</artifactId>
<version>2.2.20</version>
<version>2.2.21</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
@@ -240,7 +277,12 @@
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.1.6</version>
<version>2.1.10</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>4.0.4</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
@@ -257,22 +299,22 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<version>4.13.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
<version>1.9.7</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.18.1</version>
<version>3.20.2</version>
</dependency>
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
<version>3.9.1</version>
<version>3.16.0</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
@@ -282,7 +324,7 @@
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.7.0</version>
<version>5.7.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -299,19 +341,19 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>5.3.3</version>
<version>5.3.9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.3.0</version>
<version>7.4.0</version>
</dependency>
</dependencies>
</dependencyManagement>
@@ -327,7 +369,7 @@
<plugin>
<groupId>com.github.ekryd.sortpom</groupId>
<artifactId>sortpom-maven-plugin</artifactId>
<version>2.12.0</version>
<version>3.0.0</version>
<configuration>
<createBackupFile>false</createBackupFile>
<encoding>${project.build.sourceEncoding}</encoding>
@@ -335,6 +377,7 @@
<nrOfIndentSpace>4</nrOfIndentSpace>
<predefinedSortOrder>recommended_2008_06</predefinedSortOrder>
<sortDependencies>groupId,artifactId</sortDependencies>
<sortDependencyExclusions>groupId,artifactId</sortDependencyExclusions>
<sortModules>true</sortModules>
<sortPlugins>groupId,artifactId</sortPlugins>
<sortProperties>true</sortProperties>
@@ -424,7 +467,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.1.1</version>
<version>3.1.2</version>
<configuration>
<checkstyleRules>
<!-- We only enable rules that are not enforced by
@@ -495,19 +538,12 @@
<property name="ignoreSetter" value="true" />
<property name="setterCanReturnItsClass" value="true" />
</module>
<module name="IllegalIdentifierName" />
<module name="IllegalImport">
<property name="illegalClasses" value="com.google.api.client.util.Preconditions">
<!-- Instead, please use
`com.google.common.base.Preconditions`. -->
</property>
<property name="illegalClasses" value="com.mongodb.lang.Nullable">
<!-- Instead, please use
`javax.annotation.Nullable`. -->
</property>
<property name="illegalClasses" value="com.nimbusds.jose.util.StandardCharset">
<!-- Instead, please use
`java.nio.charset.StandardCharsets`. -->
</property>
<property name="illegalClasses" value="io.micrometer.core.lang.Nullable">
<!-- Instead, please use
`javax.annotation.Nullable`. -->
@@ -516,11 +552,6 @@
<!-- Instead, please use
`com.google.errorprone.annotations.Immutable`. -->
</property>
<property name="illegalClasses" value="javax.xml.bind.DatatypeConverter" />
<property name="illegalClasses" value="org.assertj.core.util.Preconditions">
<!-- Instead, please use
`com.google.common.base.Preconditions`. -->
</property>
<property name="illegalClasses" value="org.jetbrains.annotations.VisibleForTesting">
<!-- Instead, please use
`com.google.common.annotations.VisibleForTesting`. -->
@@ -561,7 +592,23 @@
this config can be merged into the one
above. See
https://github.com/checkstyle/checkstyle/issues/4954. -->
<property name="illegalClasses" value="org\.testng\.AssertJUnit(\..*?)?" />
<property name="illegalClasses" value="com\.google\.api\.client\.util\.Preconditions(\..*?)?">
<!-- Instead, please use
`com.google.common.base.Preconditions`. -->
</property>
<property name="illegalClasses" value="com\.nimbusds\.jose\.util\.StandardCharset(\..*?)?">
<!-- Instead, please use
`java.nio.charset.StandardCharsets`. -->
</property>
<property name="illegalClasses" value="javax\.xml\.bind\.DatatypeConverter(\..*?)?" />
<property name="illegalClasses" value="org\.assertj\.core\.util\.Preconditions(\..*?)?">
<!-- Instead, please use
`com.google.common.base.Preconditions`. -->
</property>
<property name="illegalClasses" value="org\.junit\.jupiter\.api\.Assertions(\..*?)?">
<!-- Instead, please use
`org.assertj.core.api.Assertions`. -->
</property>
<property name="illegalClasses" value="org\.springframework\.stereotype\.(Component|Controller|Service)">
<!-- We don't use Spring's
component scanning, so `@Component`
@@ -569,6 +616,14 @@
Instead of `@Controller` use
`@RestController`. -->
</property>
<property name="illegalClasses" value="org\.springframework\.util\.Assert(\..*?)?">
<!-- Instead, please use
`com.google.common.base.Preconditions`. -->
</property>
<property name="illegalClasses" value="org\.testng\.AssertJUnit(\..*?)?">
<!-- Instead, please use
`com.google.common.base.Preconditions`. -->
</property>
<property name="regexp" value="true" />
</module>
<module name="IllegalCatch" />
@@ -620,7 +675,7 @@
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>8.39</version>
<version>8.41.1</version>
</dependency>
</dependencies>
<executions>
@@ -704,7 +759,18 @@
</requireMavenVersion>
<requirePluginVersions />
<requireSameVersionsReactor />
<requireUpperBoundDeps />
<requireUpperBoundDeps>
<excludes>
<!-- XXX:
`com.google.errorprone:error_prone_test_helpers`
pulls in a more recent version of Truth
than
`com.google.testing.compile:compile-testing`,
but the latter is incompatible with said
never version. -->
<exclude>com.google.truth:truth</exclude>
</excludes>
</requireUpperBoundDeps>
</rules>
</configuration>
<dependencies>
@@ -726,7 +792,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<version>3.0.1</version>
<executions>
<execution>
<id>sign-artifacts</id>
@@ -770,7 +836,14 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
<configuration>
<!-- All relevant doclint checks are performed during
the compilation phase; no need to recheck during
Javadoc generation. -->
<doclint>none</doclint>
<source>${version.jdk}</source>
</configuration>
<executions>
<execution>
<id>generate-javadoc-jar</id>
@@ -910,6 +983,7 @@
BSD-3-Clause
| 3-Clause BSD License
| BSD 3-clause
| Eclipse Distribution License (New BSD License)
| New BSD License
</licenseMerge>
<licenseMerge>
@@ -932,6 +1006,7 @@
<licenseMerge>
<!-- -->
EPL-2.0
| Eclipse Public License - v 2.0
| Eclipse Public License v2.0
</licenseMerge>
<licenseMerge>
@@ -975,7 +1050,7 @@
<plugin>
<groupId>org.gaul</groupId>
<artifactId>modernizer-maven-plugin</artifactId>
<version>2.1.0</version>
<version>2.2.0</version>
<configuration>
<exclusionPatterns>
<!-- The plugin suggests replacing Guava's
@@ -1007,14 +1082,14 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.6</version>
<version>0.8.7</version>
</plugin>
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>1.6.2</version>
<version>1.6.7</version>
<configuration>
<!-- Use multple threads to speed things up. Extend
<!-- Use multiple threads to speed things up. Extend
timeouts to prevent false positives as a result of
contention. -->
<threads>4</threads>
@@ -1025,7 +1100,7 @@
<dependency>
<groupId>org.pitest</groupId>
<artifactId>pitest-junit5-plugin</artifactId>
<version>0.12</version>
<version>0.14</version>
</dependency>
</dependencies>
<executions>
@@ -1040,7 +1115,7 @@
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.8.0.2131</version>
<version>3.9.0.2155</version>
</plugin>
</plugins>
</pluginManagement>
@@ -1061,7 +1136,7 @@
<id>error-prone-fork</id>
<properties>
<groupId.error-prone>com.github.PicnicSupermarket.error-prone</groupId.error-prone>
<version.error-prone>v2.4.0-picnic-3</version.error-prone>
<version.error-prone>${version.error-prone-fork}</version.error-prone>
</properties>
<dependencyManagement>
<!-- Even when we directly depend on the Picnic Error Prone
@@ -1072,7 +1147,7 @@
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<version>2.4.0</version>
<version>${version.error-prone-orig}</version>
</dependency>
</dependencies>
</dependencyManagement>
@@ -1081,21 +1156,11 @@
<!-- Error Prone checks which are not availabe from Maven Central;
these are therefore not enabled by default. -->
<id>non-maven-central</id>
<!-- XXX: Two other dependencies are potentially of interest:
`com.palantir.assertj-automation:assertj-refaster-rules` and
`com.palantir.baseline:baseline-refaster-rules` contain Refaster
rules which aren't currently applied. We should use
`RefasterRuleBuilderScanner` to convert those to `.refaster` files
so that we can pick them up. (But in case of
`baseline-refaster-rules` perhaps we can simply incorporate all of
them.) -->
<properties>
<version.palantir-assertj-automation>0.2.1</version.palantir-assertj-automation>
<version.palantir-baseline>3.63.3</version.palantir-baseline>
<version.reactor-error-prone>0.1.4</version.reactor-error-prone>
</properties>
<dependencyManagement>
<!-- All these dependencies are specified as a workaround for
<!-- Specified as a workaround for
https://github.com/mojohaus/versions-maven-plugin/issues/244. -->
<dependencies>
<dependency>
@@ -1103,16 +1168,6 @@
<artifactId>reactor-error-prone</artifactId>
<version>${version.reactor-error-prone}</version>
</dependency>
<dependency>
<groupId>com.palantir.assertj-automation</groupId>
<artifactId>assertj-error-prone</artifactId>
<version>${version.palantir-assertj-automation}</version>
</dependency>
<dependency>
<groupId>com.palantir.baseline</groupId>
<artifactId>baseline-error-prone</artifactId>
<version>${version.palantir-baseline}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
@@ -1127,22 +1182,39 @@
<artifactId>reactor-error-prone</artifactId>
<version>${version.reactor-error-prone}</version>
</path>
<!-- XXX: Before enabling these checks we'll
need to resolve some violations. Some of the
checks will need to be disabled; check how to
best do this, given that this configuration is
defined in an optional profile.
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<!-- Applies the Error Prone checks defined by this project to the
code base itself. Assumes that a prior build has already installed
the project in the local Maven repository. -->
<id>self-check</id>
<properties>
<!-- XXX: `MethodReferenceUsage` is an extremely expensive
check due to its use of `SuggestedFixes.compilesWithFix`. Maybe
we should drop it altogether? -->
<!-- XXX: Find a way to assert that test code (both inline
`BugChecker` test code and the Refaster test files) does not
exhibit anti-patterns other than those associated with the
check/template under test. Ideally all test cases are realistic. -->
<error-prone.self-check-args>-Xep:MethodReferenceUsage:OFF</error-prone.self-check-args>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths combine.children="append">
<path>
<groupId>com.palantir.assertj-automation</groupId>
<artifactId>assertj-error-prone</artifactId>
<version>${version.palantir-assertj-automation}</version>
<groupId>${project.groupId}</groupId>
<artifactId>error-prone-contrib</artifactId>
<version>${project.version}</version>
</path>
<path>
<groupId>com.palantir.baseline</groupId>
<artifactId>baseline-error-prone</artifactId>
<version>${version.palantir-baseline}</version>
</path>
-->
</annotationProcessorPaths>
</configuration>
</plugin>
@@ -1284,11 +1356,24 @@
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths combine.children="append">
<path>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotations</artifactId>
<version>${version.error-prone}</version>
</path>
<path>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_core</artifactId>
<version>${version.error-prone}</version>
</path>
<!-- This is a dependency of some Error Prone
plugins, but for licensing reasons it is not
packaged with the artifact. -->
<path>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jFormatString</artifactId>
<version>${version.findbugs-format-string}</version>
</path>
<path>
<groupId>com.google.guava</groupId>
<artifactId>guava-beta-checker</artifactId>
@@ -1299,6 +1384,20 @@
<artifactId>nopen-checker</artifactId>
<version>${version.nopen-checker}</version>
</path>
<!-- XXX: Before enabling these plugins we'll
need to resolve some violations. Some of the
checks will need to be disabled.
<path>
<groupId>com.palantir.assertj-automation</groupId>
<artifactId>assertj-error-prone</artifactId>
<version>${version.palantir-assertj-automation}</version>
</path>
-->
<path>
<groupId>com.palantir.baseline</groupId>
<artifactId>baseline-error-prone</artifactId>
<version>${version.palantir-baseline}</version>
</path>
<path>
<groupId>com.uber.nullaway</groupId>
<artifactId>nullaway</artifactId>
@@ -1336,16 +1435,47 @@
-Xep:BetaApi:OFF
<!-- We don't target JDK 7. -->
-Xep:Java7ApiChecker:OFF
<!-- Too many false positives for now. See
https://github.com/google/error-prone/issues/1610 and
https://github.com/google/error-prone/issues/1646. -->
-Xep:JdkObsolete:OFF
<!-- We don't target Android. -->
-Xep:StaticOrDefaultInterfaceMethod:OFF
<!--
Flags for `baseline-error-prone`.
-->
<!-- We prefer to name loggers name `LOG`,
rather than `log`. -->
-Xep:ConsistentLoggerName:OFF
<!-- XXX: This check discourages use of
parallel streams, which is good, but also
suggests a Palantir alternative. Consider
introducing a similar but less opinionated
check. -->
-Xep:DangerousParallelStreamUsage:OFF
<!-- Nice idea, but too expensive due to
(recursive) invocation of
`SuggestedFixes.compilesWithFix`. -->
-Xep:LambdaMethodReference:OFF
<!-- We don't use Palantir's `safe-logging`
library. -->
-Xep:PreferSafeLoggingPreconditions:OFF
<!-- We don't use Palantir's `safe-logging`
library. -->
-Xep:Slf4jLogsafeArgs:OFF
<!-- XXX: This check suggests prefixing
unused parameters with an underscore.
Discuss this idea within the team. -->
-Xep:StrictUnusedVariable:OFF
<!-- Ideally `@VisibleForTesting` members
are package-private, but there are
reasonable exceptions. -->
-Xep:VisibleForTestingPackagePrivate:OFF
<!--
Flags for `nullaway`.
-->
-XepOpt:NullAway:AnnotatedPackages=tech.picnic
-XepOpt:NullAway:AssertsEnabled=true
-XepOpt:NullAway:CheckOptionalEmptiness=true
<!-- Append additional custom arguments. -->
${error-prone.args}
${error-prone.patch-args}
${error-prone.self-check-args}
</arg>
<!-- The Error Prone plugin makes certain
assumptions about the state of the AST at the
@@ -1371,7 +1501,7 @@
</property>
</activation>
<properties>
<error-prone.args>-XepPatchChecks:${error-prone.patch-checks} -XepPatchLocation:IN_PLACE</error-prone.args>
<error-prone.patch-args>-XepPatchChecks:${error-prone.patch-checks} -XepPatchLocation:IN_PLACE</error-prone.patch-args>
</properties>
</profile>
<profile>
@@ -1494,7 +1624,7 @@
compiler. The following `add-exports` arguments are not necessary
for the code to compile because `com.google.errorprone:javac` is on
the classpath. In fact, enabling this profile when building with
Maven on the command line with cause a build failure, because these
Maven on the command line will cause a build failure, because these
flags are incompatible with the `release` flag. This profile exists
solely to be enabled within an IDE: without them IntelliJ IDEA
reports compilation errors. -->

View File

@@ -14,6 +14,11 @@
<description>Java Compiler Plugin which identifies and compiles Refaster templates, storing them as resource files on the classpath.</description>
<dependencies>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_check_api</artifactId>
@@ -27,6 +32,11 @@
<artifactId>auto-service-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>javac</artifactId>

View File

@@ -0,0 +1,4 @@
/** A {@code javac} plugin which compiles Refaster templates once their Java code is compiled. */
@com.google.errorprone.annotations.CheckReturnValue
@javax.annotation.ParametersAreNonnullByDefault
package tech.picnic.errorprone.refaster.plugin;

70
refaster-support/pom.xml Normal file
View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>refaster-support</artifactId>
<name>Picnic :: Error Prone Support :: Refaster Support</name>
<description>Helper utilities for use with Refaster templates.</description>
<dependencies>
<!-- This dependency is listed out-of-order so as not to confuse the
`maven-dependency-plugin` when the `error-prone-fork` profile is
enabled: the `error_prone_annotation` dependency pulls in the
non-forked `error_prone_annotations` artifact through a dependency on
Guava. -->
<?SORTPOM IGNORE?>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<?SORTPOM RESUME?>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>javac</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

Some files were not shown because too many files have changed in this diff Show More