Compare commits

..

20 Commits

Author SHA1 Message Date
Pieter Dirk Soels
a71e90f856 Upgrade dependencies to the latest versions 2022-10-12 15:44:00 +02:00
Pieter Dirk Soels
af794e5fc6 Generate Markdown files from existing content for the website 2022-10-12 15:43:57 +02:00
Pieter Dirk Soels
6d25ff68b0 Improve website styling
Co-authored-by: japborst <japborst@gmail.com>
Co-authored-by: Gijs de Jong <berichtaangijs@gmail.com>
2022-10-12 15:00:02 +02:00
Rick Ossendrijver
bd048d2a0e Introduce Docgen module to extract website data from source code
By adding a compilation `TaskListener` that extracts data from the Bug pattern
and Refaster rule collection (test) classes and writing to JSON output files
in the target directory. This extraction happens as part of the Maven build
using the `docgen` profile.
2022-10-12 14:53:53 +02:00
Stephan Schroevers
d5a78186db Augment Descriptions of Refaster rule matches (#255)
By emitting a website link, if available, and reporting the matching Refaster
rule in the description's message rather than the check name. Additionally, it
is now possible to provide a custom explanatory text, to assign a custom
severity to Refaster rules, and to override the severity of matches for all
Refaster rules by passing `-Xep:Refaster:[SEVERITY]`.

Violations of Refaster rules defined in this repository now include a link to
the rule's documentation, hosted on https://error-prone.picnic.tech.
2022-10-12 11:41:14 +02:00
Rick Ossendrijver
128e178d37 Consistently prefer "Refaster rule" over "Refaster template" (#286)
As the former term references a class containing one or more `@BeforeTemplate`
methods, one or more `@Placeholder` methods and an optional `@AfterTemplate`, 
while the latter term more narrowly references a single `@BeforeTemplate` or 
`@AfterTemplate` method.
2022-10-11 17:23:54 +02:00
Picnic-Bot
7aef2cfe51 Upgrade pitest-maven-plugin 1.9.7 -> 1.9.8 (#290)
See https://github.com/hcoles/pitest/compare/1.9.7...1.9.8
2022-10-11 15:43:05 +02:00
Pieter Dirk Soels
5cec0dd508 Rename Slf4JLogStatementTest to Slf4jLogStatementTest (#289) 2022-10-11 14:57:19 +02:00
Rick Ossendrijver
3f1399c139 Accommodate rapid website development on the website branch (#287)
By (a) deploying from that branch and (b) temporarily disabling external link
checking.
2022-10-11 14:43:34 +02:00
Jelmer Borst
757d5b1d70 Unify local and GitHub Actions website generation flow (#274) 2022-10-09 19:43:01 +02:00
Jelmer Borst
45cac6105e Have website use theme variables instead of custom SASS overrides (#285) 2022-10-09 19:41:32 +02:00
Picnic-Bot
8f8f57fc5b Upgrade AutoValue 1.9 -> 1.10 (#283)
See:
- https://github.com/google/auto/releases/tag/auto-value-1.10
- https://github.com/google/auto/compare/auto-value-1.9...auto-value-1.10
2022-10-09 10:03:55 +02:00
Bastien Diederichs
902d4f7736 Suggest Flux#concatMap{,Iterable} usage in more contexts (#279) 2022-10-08 11:12:41 +02:00
Sander Mak
4ec349582c Reference blog post in README (#282) 2022-10-07 21:28:08 +02:00
Bastien Diederichs
57836103ea Fix LexicographicalAnnotationAttributeListing string sorting (#281)
In particular, the empty string is now ordered first.
2022-10-07 14:34:14 +02:00
chamil-prabodha
bd73243c34 Introduce {Mono,Flux}OnErrorComplete Refaster rules (#273) 2022-10-07 11:54:50 +02:00
Stephan Schroevers
9af50d7e0b Introduce StringJoin check (#194)
This new `BugChecker` flags `String#format` invocations which can be
replaced with a `String#join` or even `String#valueOf` invocation.
2022-10-06 11:27:29 +02:00
Picnic-Bot
f5ae47fbac Upgrade pitest-maven-plugin 1.9.6 -> 1.9.7 (#280)
See https://github.com/hcoles/pitest/compare/1.9.6...1.9.7
2022-10-06 10:40:32 +02:00
Picnic-Bot
9ad8c275d3 Upgrade actions/checkout v3.0.2 -> v3.1.0 (#277)
See:
- https://github.com/actions/checkout/releases/tag/v3.1.0
- https://github.com/actions/checkout/compare/v3.0.2...v3.1.0
2022-10-05 15:57:16 +02:00
Jelmer Borst
f4e191e33b Fix default branch reference in GitHub Actions definition (#278) 2022-10-05 12:48:07 +02:00
272 changed files with 3453 additions and 1367 deletions

2
.github/release.yml vendored
View File

@@ -3,7 +3,7 @@ changelog:
labels:
- "ignore-changelog"
categories:
- title: ":rocket: New Error Prone checks and Refaster templates"
- title: ":rocket: New Error Prone checks and Refaster rules"
labels:
- "new feature"
- title: ":sparkles: Improvements"

View File

@@ -2,7 +2,7 @@ name: Build and verify
on:
pull_request:
push:
branches: [$default-branch]
branches: [ master ]
permissions:
contents: read
jobs:
@@ -18,7 +18,7 @@ jobs:
# additionally enabling all checks defined in this project and any
# Error Prone checks available only from other artifact repositories.
- name: Check out code
uses: actions/checkout@v3.0.2
uses: actions/checkout@v3.1.0
- name: Set up JDK
uses: actions/setup-java@v3.5.1
with:

View File

@@ -2,7 +2,7 @@ name: Update `error-prone.picnic.tech` website content
on:
pull_request:
push:
branches: [$default-branch]
branches: [ master, website ]
permissions:
contents: read
id-token: write
@@ -15,25 +15,28 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v3.0.2
uses: actions/checkout@v3.1.0
- uses: ruby/setup-ruby@v1.117.0
with:
working-directory: ./website
bundler-cache: true
- name: Configure Github Pages
uses: actions/configure-pages@v2.1.1
# XXX: Run website/generate-docs.rb instead.
- name: Generate documentation
run: ./generate-docs.sh
- name: Build website with Jekyll
uses: actions/jekyll-build-pages@v1.0.5
with:
source: website/
destination: ./_site
working-directory: ./website
run: bundle exec ruby generate-docs.rb
- name: Validate HTML output
uses: anishathalye/proof-html@v1.4.1
with:
directory: ./_site
check_external_hash: false
working-directory: ./website
# XXX: Drop `--disable_external true` once we fully adopted the
# "Refaster rules" terminology on our website and in the code.
run: bundle exec htmlproofer --disable_external true --check-external-hash false ./_site
- name: Upload website as artifact
uses: actions/upload-pages-artifact@v1.0.4
with:
path: ./website/_site
deploy:
if: github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
if: github.ref == 'refs/heads/website'
needs: build
runs-on: ubuntu-22.04
environment:

View File

@@ -15,6 +15,10 @@ focussing on maintainability, consistency and avoidance of common pitfalls.
> Error Prone is a static analysis tool for Java that catches common
> programming mistakes at compile-time.
Read more on how Picnic uses Error Prone (Support) in the blog post [_Picnic
loves Error Prone: producing high-quality and consistent Java
code_][picnic-blog-ep-post].
[![Maven Central][maven-central-badge]][maven-central-search]
[![GitHub Actions][github-actions-build-badge]][github-actions-build-master]
[![License][license-badge]][license]
@@ -59,7 +63,7 @@ it:
<artifactId>error-prone-contrib</artifactId>
<version>${error-prone-support.version}</version>
</path>
<!-- Error Prone Support's Refaster templates. -->
<!-- Error Prone Support's Refaster rules. -->
<path>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>refaster-runner</artifactId>
@@ -118,7 +122,7 @@ $ mvn clean install
[INFO] -------------------------------------------------------------
[WARNING] COMPILATION WARNING :
[INFO] -------------------------------------------------------------
[WARNING] Example.java:[9,34] [tech.picnic.errorprone.refastertemplates.BigDecimalTemplates.BigDecimalZero]
[WARNING] Example.java:[9,34] [tech.picnic.errorprone.refasterrules.BigDecimalRules.BigDecimalZero]
Did you mean 'return BigDecimal.ZERO;'?
[WARNING] Example.java:[13,35] [IdentityConversion] This method invocation appears redundant; remove it or suppress this warning and add a comment explaining its purpose
(see https://error-prone.picnic.tech/bugpatterns/IdentityConversion)
@@ -132,12 +136,12 @@ Two things are kicking in here:
1. An Error Prone [`BugChecker`][error-prone-bugchecker] that flags unnecessary
[identity conversions][bug-checks-identity-conversion].
2. A [Refaster][refaster] template capable of
[rewriting][refaster-templates-bigdecimal] expressions of the form
2. A [Refaster][refaster] rule capable of
[rewriting][refaster-rules-bigdecimal] expressions of the form
`BigDecimal.valueOf(0)` and `new BigDecimal(0)` to `BigDecimal.ZERO`.
Be sure to check out all [bug checks][bug-checks] and [refaster
templates][refaster-templates].
rules][refaster-rules].
## 👷 Developing Error Prone Support
@@ -218,9 +222,10 @@ guidelines][contributing].
[maven-central-search]: https://search.maven.org/artifact/tech.picnic.error-prone-support/error-prone-support
[maven]: https://maven.apache.org
[picnic-blog]: https://blog.picnic.nl
[picnic-blog-ep-post]: https://blog.picnic.nl/picnic-loves-error-prone-producing-high-quality-and-consistent-java-code-b8a566be6886
[pitest]: https://pitest.org
[pitest-maven]: https://pitest.org/quickstart/maven
[pr-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg
[refaster]: https://errorprone.info/docs/refaster
[refaster-templates-bigdecimal]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/error-prone-contrib/src/main/java/tech/picnic/errorprone/refastertemplates/BigDecimalTemplates.java
[refaster-templates]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/error-prone-contrib/src/main/java/tech/picnic/errorprone/refastertemplates/
[refaster-rules-bigdecimal]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/BigDecimalRules.java
[refaster-rules]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/

View File

@@ -1,15 +1,26 @@
package tech.picnic.errorprone.plugin;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.sun.source.tree.ClassTree;
import com.sun.source.util.TaskEvent;
import tech.picnic.errorprone.plugin.objects.BugPatternData;
import tech.picnic.errorprone.plugin.models.BugPatternData;
public final class BugPatternExtractor implements DocExtractor<BugPatternData> {
@Override
public BugPatternData extractData(ClassTree tree, TaskEvent taskEvent, VisitorState state) {
BugPattern annotation = taskEvent.getTypeElement().getAnnotation(BugPattern.class);
return BugPatternData.create(annotation, taskEvent.getTypeElement().getSimpleName().toString());
return BugPatternData.create(
taskEvent.getTypeElement().getQualifiedName().toString(),
taskEvent.getTypeElement().getSimpleName().toString(),
ImmutableList.copyOf(annotation.altNames()),
annotation.linkType(),
annotation.link(),
ImmutableList.copyOf(annotation.tags()),
annotation.summary(),
annotation.explanation(),
annotation.severity(),
annotation.disableable());
}
}

View File

@@ -1,12 +1,11 @@
package tech.picnic.errorprone.plugin;
import static com.google.errorprone.matchers.Matchers.allOf;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.hasAnnotation;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.Matchers.methodIsNamed;
import com.google.errorprone.VisitorState;
import com.google.errorprone.annotations.Var;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ClassTree;
@@ -15,15 +14,17 @@ import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TreeScanner;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import tech.picnic.errorprone.plugin.objects.BugPatternTestData;
import tech.picnic.errorprone.plugin.models.BugPatternReplacementTestData;
import tech.picnic.errorprone.plugin.models.BugPatternTestData;
/** XXX: Write this. */
// XXX: Take into account `expectUnchanged()`.
public final class BugPatternTestsExtractor implements DocExtractor<BugPatternTestData> {
private static final Matcher<MethodTree> BUG_PATTERN_TEST =
allOf(
hasAnnotation("org.junit.jupiter.api.Test"),
anyOf(methodIsNamed("replacement"), methodIsNamed("identification")));
private static final Matcher<MethodTree> JUNIT_TEST_METHOD =
allOf(hasAnnotation("org.junit.jupiter.api.Test"));
private static final Matcher<ExpressionTree> IDENTIFICATION_SOURCE_LINES =
instanceMethod()
.onDescendantOf("com.google.errorprone.CompilationTestHelper")
@@ -45,57 +46,48 @@ public final class BugPatternTestsExtractor implements DocExtractor<BugPatternTe
tree.getMembers().stream()
.filter(MethodTree.class::isInstance)
.map(MethodTree.class::cast)
.filter(m -> BUG_PATTERN_TEST.matches(m, state))
.filter(m -> JUNIT_TEST_METHOD.matches(m, state))
.forEach(m -> scanner.scan(m, null));
return BugPatternTestData.create(
name, scanner.getIdentification(), scanner.getInput(), scanner.getOutput());
name, scanner.getIdentificationTests(), scanner.getReplacementTests());
}
private static final class ScanBugCheckerTestData extends TreeScanner<Void, Void> {
private final VisitorState state;
private final List<String> identificationTests = new ArrayList<>();
private final List<BugPatternReplacementTestData> replacementTests = new ArrayList<>();
private String identification;
private String input;
private String output;
// XXX: Using this output field is a bit hacky. Come up with a better solution.
@Var private String output;
ScanBugCheckerTestData(VisitorState state) {
this.state = state;
}
public String getIdentification() {
return identification;
public List<String> getIdentificationTests() {
return identificationTests;
}
public String getInput() {
return input;
public List<BugPatternReplacementTestData> getReplacementTests() {
return replacementTests;
}
public String getOutput() {
return output;
}
@Nullable
@Override
public Void visitMethodInvocation(MethodInvocationTree node, Void unused) {
if (IDENTIFICATION_SOURCE_LINES.matches(node, state)) {
identification = getSourceLines(node);
identificationTests.add(getSourceLines(node));
} else if (REPLACEMENT_INPUT.matches(node, state)) {
input = getSourceLines(node);
replacementTests.add(BugPatternReplacementTestData.create(getSourceLines(node), output));
} else if (REPLACEMENT_OUTPUT.matches(node, state)) {
output = getSourceLines(node);
}
return super.visitMethodInvocation(node, unused);
}
private String getSourceLines(MethodInvocationTree tree) {
private static String getSourceLines(MethodInvocationTree tree) {
List<? extends ExpressionTree> sourceLines =
tree.getArguments().subList(1, tree.getArguments().size());
return getConstantSourceCode(sourceLines);
}
private String getConstantSourceCode(List<? extends ExpressionTree> sourceLines) {
StringBuilder source = new StringBuilder();
for (ExpressionTree sourceLine : sourceLines) {
@@ -103,7 +95,6 @@ public final class BugPatternTestsExtractor implements DocExtractor<BugPatternTe
if (value == null) {
return "";
}
source.append(value).append('\n');
}

View File

@@ -0,0 +1,25 @@
package tech.picnic.errorprone.plugin;
public enum DocType {
BUG_PATTERN("bug-pattern", new BugPatternExtractor()),
BUG_PATTERN_TEST("bug-pattern-test", new BugPatternTestsExtractor()),
// REFASTER("refaster", new RefasterExtractor()),
REFASTER_TEMPLATE_TEST_INPUT("refaster-test-input", new RefasterTestExtractor()),
REFASTER_TEMPLATE_TEST_OUTPUT("refaster-test-output", new RefasterTestExtractor());
private final String outputFileNamePrefix;
private final DocExtractor<?> docExtractor;
DocType(String outputFileNamePrefix, DocExtractor<?> docExtractor) {
this.outputFileNamePrefix = outputFileNamePrefix;
this.docExtractor = docExtractor;
}
public String getOutputFileNamePrefix() {
return outputFileNamePrefix;
}
public DocExtractor<?> getDocExtractor() {
return docExtractor;
}
}

View File

@@ -5,11 +5,7 @@ import com.sun.source.util.JavacTask;
import com.sun.source.util.Plugin;
import com.sun.tools.javac.api.BasicJavacTask;
/**
* A variant of {@code com.google.errorprone.refaster.RefasterRuleCompiler} that outputs a {@code
* fully/qualified/Class.refaster} file for each compiled {@code fully.qualified.Class} that
* contains a Refaster template.
*/
/** XXX: Write. */
@AutoService(Plugin.class)
public final class Docgen implements Plugin {
@Override

View File

@@ -1,24 +0,0 @@
package tech.picnic.errorprone.plugin;
public enum DocgenPart {
BUGPATTERN("bug-pattern-test-data.jsonl", new BugPatternExtractor()),
BUGPATTERN_TEST("bug-pattern-data.jsonl", new BugPatternTestsExtractor()),
REFASTER_TEMPLATE_TEST_INPUT("refaster-test-input-data.jsonl", new RefasterTestExtractor()),
REFASTER_TEMPLATE_TEST_OUTPUT("refaster-test-output-data.jsonl", new RefasterTestExtractor());
private final String dataFileName;
private final DocExtractor<?> extractor;
DocgenPart(String dataFileName, DocExtractor<?> extractor) {
this.dataFileName = dataFileName;
this.extractor = extractor;
}
public DocExtractor<?> getExtractor() {
return extractor;
}
public String getDataFileName() {
return dataFileName;
}
}

View File

@@ -1,5 +1,12 @@
package tech.picnic.errorprone.plugin;
import static tech.picnic.errorprone.plugin.DocType.BUG_PATTERN;
import static tech.picnic.errorprone.plugin.DocType.BUG_PATTERN_TEST;
import static tech.picnic.errorprone.plugin.DocType.REFASTER_TEMPLATE_TEST_INPUT;
import static tech.picnic.errorprone.plugin.DocType.REFASTER_TEMPLATE_TEST_OUTPUT;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
@@ -15,6 +22,8 @@ import com.sun.tools.javac.util.Context;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Optional;
import javax.tools.JavaFileObject;
@@ -28,49 +37,57 @@ final class DocgenTaskListener implements TaskListener {
private final ObjectMapper mapper =
new ObjectMapper()
.setVisibility(PropertyAccessor.FIELD, Visibility.ANY)
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
DocgenTaskListener(Context context, String path) {
this.context = context;
this.basePath = path.substring(path.indexOf('=') + 1);
this.basePath = path.substring(path.indexOf('=') + 1) + "/docs";
this.state = VisitorState.createForUtilityPurposes(context);
// XXX: Move this somewhere else?
try {
Files.createDirectories(Paths.get(basePath));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
@SuppressWarnings("SystemOut")
public void finished(TaskEvent taskEvent) {
ClassTree tree = JavacTrees.instance(context).getTree(taskEvent.getTypeElement());
if (tree == null || taskEvent.getSourceFile() == null) {
JavaFileObject sourceFile = taskEvent.getSourceFile();
if (tree == null || sourceFile == null || taskEvent.getKind() != TaskEvent.Kind.ANALYZE) {
return;
}
getDocgenPart(tree, taskEvent)
getDocType(tree, sourceFile)
.ifPresent(
docgenPart ->
docType ->
writeToFile(
docgenPart.getExtractor().extractData(tree, taskEvent, state),
docgenPart.getDataFileName()));
docType.getDocExtractor().extractData(tree, taskEvent, state),
docType.getOutputFileNamePrefix(),
getSimpleClassName(sourceFile.getName())));
}
private static Optional<DocgenPart> getDocgenPart(ClassTree tree, TaskEvent taskEvent) {
JavaFileObject sourceFile = taskEvent.getSourceFile();
if (isBugPatternTest(tree)) {
return Optional.of(DocgenPart.BUGPATTERN_TEST);
} else if (isBugPattern(tree)) {
return Optional.of(DocgenPart.BUGPATTERN);
private static Optional<DocType> getDocType(ClassTree tree, JavaFileObject sourceFile) {
if (isBugPattern(tree)) {
return Optional.of(BUG_PATTERN);
} else if (isBugPatternTest(tree)) {
return Optional.of(BUG_PATTERN_TEST);
} else if (sourceFile.getName().contains("TestInput")) {
return Optional.of(DocgenPart.REFASTER_TEMPLATE_TEST_INPUT);
return Optional.of(REFASTER_TEMPLATE_TEST_INPUT);
} else if (sourceFile.getName().contains("TestOutput")) {
return Optional.of(DocgenPart.REFASTER_TEMPLATE_TEST_OUTPUT);
} else {
return Optional.empty();
return Optional.of(REFASTER_TEMPLATE_TEST_OUTPUT);
}
return Optional.empty();
}
private <T> void writeToFile(T data, String fileName) {
File file = new File(basePath + "/" + fileName);
private <T> void writeToFile(T data, String fileName, String name) {
File file = new File(basePath + "/" + fileName + "-" + name + ".json");
// XXX: Use Path instead of File.
try (FileWriter fileWriter = new FileWriter(file, true)) {
mapper.writeValue(fileWriter, data);
@@ -86,10 +103,21 @@ final class DocgenTaskListener implements TaskListener {
private static boolean isBugPatternTest(ClassTree tree) {
return tree.getSimpleName().toString().endsWith("Test")
// XXX: Instead, omit files from the util directory
&& !tree.getSimpleName().toString().equals("MethodMatcherFactoryTest")
&& tree.getMembers().stream()
.filter(VariableTree.class::isInstance)
.map(VariableTree.class::cast)
.map(vt -> vt.getType().toString())
.anyMatch(
member -> member.getType().toString().equals("BugCheckerRefactoringTestHelper"));
vt ->
vt.equals("BugCheckerRefactoringTestHelper")
|| vt.equals("CompilationTestHelper"));
}
private static String getSimpleClassName(String path) {
int index = path.lastIndexOf('/');
String fileName = path.substring(index + 1);
return fileName.replace(".java", "");
}
}

View File

@@ -7,26 +7,29 @@ import com.google.errorprone.VisitorState;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.util.TaskEvent;
import tech.picnic.errorprone.plugin.objects.RefasterTemplateTestData;
import tech.picnic.errorprone.plugin.models.RefasterTemplateCollectionTestData;
import tech.picnic.errorprone.plugin.models.RefasterTemplateTestData;
public class RefasterTestExtractor
implements DocExtractor<ImmutableList<RefasterTemplateTestData>> {
public final class RefasterTestExtractor
implements DocExtractor<RefasterTemplateCollectionTestData> {
@Override
public ImmutableList<RefasterTemplateTestData> extractData(
public RefasterTemplateCollectionTestData extractData(
ClassTree tree, TaskEvent taskEvent, VisitorState state) {
String templateCollectionName = tree.getSimpleName().toString().replace("Test", "");
boolean isInput = taskEvent.getSourceFile().getName().contains("Input");
return tree.getMembers().stream()
.filter(MethodTree.class::isInstance)
.map(MethodTree.class::cast)
.filter(m -> m.getName().toString().startsWith("test"))
.map(
m ->
RefasterTemplateTestData.create(
templateCollectionName,
m.getName().toString().replace("test", ""),
m.toString()))
.collect(toImmutableList());
ImmutableList<RefasterTemplateTestData> templateTests =
tree.getMembers().stream()
.filter(MethodTree.class::isInstance)
.map(MethodTree.class::cast)
.filter(m -> m.getName().toString().startsWith("test"))
.map(
m ->
RefasterTemplateTestData.create(
m.getName().toString().replace("test", ""), m.toString()))
.collect(toImmutableList());
return RefasterTemplateCollectionTestData.create(
templateCollectionName, isInput, templateTests);
}
}

View File

@@ -0,0 +1,55 @@
package tech.picnic.errorprone.plugin.models;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
/** XXX: Write. */
// XXX: What about `SuppressionAnnotations` and `DocumentSuppression`?
@AutoValue
public abstract class BugPatternData {
public static BugPatternData create(
String fullyQualifiedName,
String name,
ImmutableList<String> altNames,
LinkType linkType,
String link,
ImmutableList<String> tags,
String summary,
String explanation,
SeverityLevel severityLevel,
boolean disableable) {
return new AutoValue_BugPatternData(
fullyQualifiedName,
name,
altNames,
linkType,
link,
tags,
summary,
explanation,
severityLevel,
disableable);
}
abstract String fullyQualifiedName();
abstract String name();
abstract ImmutableList<String> altNames();
abstract LinkType linkType();
abstract String link();
abstract ImmutableList<String> tags();
abstract String summary();
abstract String explanation();
abstract SeverityLevel severityLevel();
abstract boolean disableable();
}

View File

@@ -0,0 +1,17 @@
package tech.picnic.errorprone.plugin.models;
import com.google.auto.value.AutoValue;
import javax.annotation.Nullable;
@AutoValue
public abstract class BugPatternReplacementTestData {
public static BugPatternReplacementTestData create(String inputLines, String outputLines) {
return new AutoValue_BugPatternReplacementTestData(inputLines, outputLines);
}
@Nullable
abstract String inputLines();
@Nullable
abstract String outputLines();
}

View File

@@ -0,0 +1,23 @@
package tech.picnic.errorprone.plugin.models;
import com.google.auto.value.AutoValue;
import java.util.List;
import javax.annotation.Nullable;
@AutoValue
public abstract class BugPatternTestData {
public static BugPatternTestData create(
String name,
List<String> identificationTests,
List<BugPatternReplacementTestData> replacementTests) {
return new AutoValue_BugPatternTestData(name, identificationTests, replacementTests);
}
abstract String name();
@Nullable
abstract List<String> identificationTests();
@Nullable
abstract List<BugPatternReplacementTestData> replacementTests();
}

View File

@@ -0,0 +1,24 @@
package tech.picnic.errorprone.plugin.models;
import com.google.auto.value.AutoValue;
import java.util.List;
/**
* Object containing all data related to a Refaster template collection. This is solely used for
* serialization.
*/
@AutoValue
public abstract class RefasterTemplateCollectionData {
public static RefasterTemplateCollectionData create(
String name, String description, String link, List<RefasterTemplateData> templates) {
return new AutoValue_RefasterTemplateCollectionData(name, description, link, templates);
}
abstract String name();
abstract String description();
abstract String link();
abstract List<RefasterTemplateData> templates();
}

View File

@@ -0,0 +1,19 @@
package tech.picnic.errorprone.plugin.models;
import com.google.auto.value.AutoValue;
import java.util.List;
@AutoValue
public abstract class RefasterTemplateCollectionTestData {
public static RefasterTemplateCollectionTestData create(
String templateCollection, boolean isInput, List<RefasterTemplateTestData> templatesTests) {
return new AutoValue_RefasterTemplateCollectionTestData(
templateCollection, isInput, templatesTests);
}
abstract String templateCollection();
abstract boolean isInput();
abstract List<RefasterTemplateTestData> templateTests();
}

View File

@@ -1,6 +1,5 @@
package tech.picnic.errorprone.plugin.objects;
package tech.picnic.errorprone.plugin.models;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.auto.value.AutoValue;
import com.google.errorprone.BugPattern.SeverityLevel;
@@ -11,15 +10,11 @@ public abstract class RefasterTemplateData {
return new AutoValue_RefasterTemplateData(name, description, link, severityLevel);
}
@JsonProperty
abstract String name();
@JsonProperty
abstract String description();
@JsonProperty
abstract String link();
@JsonProperty
abstract SeverityLevel severityLevel();
}

View File

@@ -0,0 +1,14 @@
package tech.picnic.errorprone.plugin.models;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class RefasterTemplateTestData {
public static RefasterTemplateTestData create(String templateName, String templateTestContent) {
return new AutoValue_RefasterTemplateTestData(templateName, templateTestContent);
}
abstract String templateName();
abstract String templateTestContent();
}

View File

@@ -1,56 +0,0 @@
package tech.picnic.errorprone.plugin.objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.auto.value.AutoValue;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import java.util.Arrays;
@AutoValue
public abstract class BugPatternData {
public static BugPatternData create(BugPattern annotation, String name) {
return new AutoValue_BugPatternData(
name,
Arrays.toString(annotation.altNames()),
annotation.linkType(),
annotation.link(),
Arrays.toString(annotation.tags()),
annotation.summary(),
annotation.explanation(),
annotation.severity(),
annotation.disableable());
}
@JsonProperty
abstract String name();
// Should be String[]
@JsonProperty
abstract String altNames();
@JsonProperty
abstract LinkType linkType();
@JsonProperty
abstract String link();
@JsonProperty
// Should be String[]
abstract String tags();
@JsonProperty
abstract String summary();
@JsonProperty
abstract String explanation();
@JsonProperty
abstract SeverityLevel severityLevel();
@JsonProperty
abstract boolean disableable();
// SuppressionAnnotations?
// DocumentSuppression?
}

View File

@@ -1,28 +0,0 @@
package tech.picnic.errorprone.plugin.objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.auto.value.AutoValue;
import javax.annotation.Nullable;
@AutoValue
public abstract class BugPatternTestData {
public static BugPatternTestData create(
String name, String identificationLines, String inputLines, String outputLines) {
return new AutoValue_BugPatternTestData(name, identificationLines, inputLines, outputLines);
}
@JsonProperty
abstract String name();
@Nullable
@JsonProperty
abstract String identificationLines();
@Nullable
@JsonProperty
abstract String inputLines();
@Nullable
@JsonProperty
abstract String outputLines();
}

View File

@@ -1,22 +0,0 @@
package tech.picnic.errorprone.plugin.objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class RefasterTemplateTestData {
public static RefasterTemplateTestData create(
String templateCollection, String templateName, String templateTestContent) {
return new AutoValue_RefasterTemplateTestData(
templateCollection, templateName, templateTestContent);
}
@JsonProperty
abstract String templateCollection();
@JsonProperty
abstract String templateName();
@JsonProperty
abstract String templateTestContent();
}

View File

@@ -267,7 +267,7 @@ Refaster's expressiveness:
motivating example, see the two subtly different loop definitions in
`CollectionRemoveAllFromCollectionExpression`.
- Figure out why Refaster sometimes doesn't match the correct generic overload.
See the `AssertThatIterableHasOneComparableElementEqualTo` template for an
See the `AssertThatIterableHasOneComparableElementEqualTo` rule for an
example.
[autorefactor]: https://autorefactor.org

View File

@@ -24,7 +24,7 @@ import com.sun.source.tree.MethodInvocationTree;
/**
* A {@link BugChecker} that flags AssertJ {@code isEqualTo(null)} checks for simplification.
*
* <p>This bug checker cannot be replaced with a simple Refaster template, as the Refaster approach
* <p>This bug checker cannot be replaced with a simple Refaster rule, as the Refaster approach
* would require that all overloads of {@link org.assertj.core.api.Assert#isEqualTo(Object)} (such
* as {@link org.assertj.core.api.AbstractStringAssert#isEqualTo(String)}) are explicitly
* enumerated. This bug checker generically matches all such current and future overloads.

View File

@@ -86,6 +86,6 @@ public final class ExplicitEnumOrdering extends BugChecker implements MethodInvo
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));
.map(v -> String.join(".", typeSymbol.getSimpleName(), v));
}
}

View File

@@ -48,7 +48,7 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
// `Formattable#toString` invocation with a `Formattable#formatTo` invocation. But likely that
// should be considered a bug fix, too.
// XXX: Introduce a separate check that adds/removes the `Locale` parameter to `String.format`
// invocations, as necessary.
// invocations, as necessary. See also a comment in the `StringJoin` check.
@AutoService(BugChecker.class)
@BugPattern(
summary = "Defer string concatenation to the invoked method",

View File

@@ -1,5 +1,6 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.STYLE;
@@ -9,6 +10,7 @@ import static java.util.stream.Collectors.joining;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.base.Splitter;
import com.google.common.collect.Comparators;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -71,6 +73,12 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
private static final String FLAG_PREFIX = "LexicographicalAnnotationAttributeListing:";
private static final String INCLUDED_ANNOTATIONS_FLAG = FLAG_PREFIX + "Includes";
private static final String EXCLUDED_ANNOTATIONS_FLAG = FLAG_PREFIX + "Excludes";
/**
* The splitter applied to string-typed annotation arguments prior to lexicographical sorting. By
* splitting on {@code =}, strings that represent e.g. inline Spring property declarations are
* properly sorted by key, then value.
*/
private static final Splitter STRING_ARGUMENT_SPLITTER = Splitter.on('=');
private final AnnotationAttributeMatcher matcher;
@@ -126,7 +134,7 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
}
List<? extends ExpressionTree> actualOrdering = array.getInitializers();
ImmutableList<? extends ExpressionTree> desiredOrdering = doSort(actualOrdering, state);
ImmutableList<? extends ExpressionTree> desiredOrdering = doSort(actualOrdering);
if (actualOrdering.equals(desiredOrdering)) {
/* In the (presumably) common case the elements are already sorted. */
return Optional.empty();
@@ -156,12 +164,12 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
}
private static ImmutableList<? extends ExpressionTree> doSort(
Iterable<? extends ExpressionTree> elements, VisitorState state) {
Iterable<? extends ExpressionTree> elements) {
// 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(
comparing(
e -> getStructure(e, state),
LexicographicalAnnotationAttributeListing::getStructure,
Comparators.lexicographical(
Comparators.lexicographical(
String.CASE_INSENSITIVE_ORDER.thenComparing(naturalOrder())))),
@@ -173,38 +181,34 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
* performed. This approach disregards e.g. irrelevant whitespace. It also allows special
* structure within string literals to be respected.
*/
private static ImmutableList<ImmutableList<String>> getStructure(
ExpressionTree array, VisitorState state) {
private static ImmutableList<ImmutableList<String>> getStructure(ExpressionTree array) {
ImmutableList.Builder<ImmutableList<String>> nodes = ImmutableList.builder();
new TreeScanner<Void, Void>() {
@Nullable
@Override
public Void visitIdentifier(IdentifierTree node, @Nullable Void ctx) {
nodes.add(tokenize(node));
return super.visitIdentifier(node, ctx);
public Void visitIdentifier(IdentifierTree node, @Nullable Void unused) {
nodes.add(ImmutableList.of(node.getName().toString()));
return super.visitIdentifier(node, unused);
}
@Nullable
@Override
public Void visitLiteral(LiteralTree node, @Nullable Void ctx) {
nodes.add(tokenize(node));
return super.visitLiteral(node, ctx);
public Void visitLiteral(LiteralTree node, @Nullable Void unused) {
Object value = ASTHelpers.constValue(node);
nodes.add(
value instanceof String
? STRING_ARGUMENT_SPLITTER.splitToStream((String) value).collect(toImmutableList())
: ImmutableList.of(String.valueOf(value)));
return super.visitLiteral(node, unused);
}
@Nullable
@Override
public Void visitPrimitiveType(PrimitiveTypeTree node, @Nullable Void ctx) {
nodes.add(tokenize(node));
return super.visitPrimitiveType(node, ctx);
}
private ImmutableList<String> tokenize(Tree node) {
/*
* Tokens are split on `=` so that e.g. inline Spring property declarations are properly
* sorted by key, then value.
*/
return ImmutableList.copyOf(SourceCode.treeToString(node, state).split("=", -1));
public Void visitPrimitiveType(PrimitiveTypeTree node, @Nullable Void unused) {
nodes.add(ImmutableList.of(node.getPrimitiveTypeKind().toString()));
return super.visitPrimitiveType(node, unused);
}
}.scan(array, null);

View File

@@ -25,7 +25,7 @@ import com.sun.source.tree.Tree;
/** A {@link BugChecker} that flags likely missing Refaster annotations. */
@AutoService(BugChecker.class)
@BugPattern(
summary = "The Refaster template contains a method without any Refaster annotations",
summary = "The Refaster rule contains a method without any Refaster annotations",
link = BUG_PATTERNS_BASE_URL + "MissingRefasterAnnotation",
linkType = CUSTOM,
severity = WARNING,

View File

@@ -22,8 +22,8 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
/**
* A {@link BugChecker} that 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.
* <p>Note that this logic can't be implemented as a Refaster rule, as the {@link Refaster} class is
* treated specially.
*/
@AutoService(BugChecker.class)
@BugPattern(

View File

@@ -35,11 +35,11 @@ import javax.lang.model.element.Modifier;
@AutoService(BugChecker.class)
@BugPattern(
summary = "Refaster class and method definitions should specify a canonical set of modifiers",
link = BUG_PATTERNS_BASE_URL + "RefasterTemplateModifiers",
link = BUG_PATTERNS_BASE_URL + "RefasterRuleModifiers",
linkType = CUSTOM,
severity = SUGGESTION,
tags = STYLE)
public final class RefasterTemplateModifiers extends BugChecker
public final class RefasterRuleModifiers extends BugChecker
implements ClassTreeMatcher, MethodTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<Tree> BEFORE_TEMPLATE_METHOD = hasAnnotation(BeforeTemplate.class);
@@ -85,8 +85,8 @@ public final class RefasterTemplateModifiers extends BugChecker
if (!hasMatchingMember(tree, PLACEHOLDER_METHOD, state)) {
/*
* Templates without a `@Placeholder` method should be `final`. Note that Refaster enforces
* that `@Placeholder` methods are `abstract`, so templates _with_ such a method will
* Rules without a `@Placeholder` method should be `final`. Note that Refaster enforces
* that `@Placeholder` methods are `abstract`, so rules _with_ such a method will
* naturally be `abstract` and non-`final`.
*/
modifiersToAdd.add(Modifier.FINAL);

View File

@@ -29,6 +29,7 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
// XXX: The special-casing of Throwable applies only to SLF4J 1.6.0+; see
// https://www.slf4j.org/faq.html#paramException. That should be documented.
// XXX: Also simplify `LOG.error(String.format("Something %s", arg), throwable)`.
// XXX: Also simplify `LOG.error(String.join("sep", arg1, arg2), throwable)`? Perhaps too obscure.
// XXX: Write a similar checker for Spring RestTemplates, String.format and friends, Guava
// preconditions, ...
@AutoService(BugChecker.class)

View File

@@ -0,0 +1,182 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import com.google.auto.service.AutoService;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Supplier;
import com.google.errorprone.suppliers.Suppliers;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.util.Convert;
import java.util.Formattable;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nullable;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
/**
* A {@link BugChecker} which flags {@link String#format(String, Object...)} invocations which can
* be replaced with a {@link String#join(CharSequence, CharSequence...)} or even a {@link
* String#valueOf} invocation.
*/
// XXX: What about `v1 + "sep" + v2` and similar expressions? Do we want to rewrite those to
// `String.join`, or should some `String.join` invocations be rewritten to use the `+` operator?
// (The latter suggestion would conflict with the `FormatStringConcatenation` check.)
@AutoService(BugChecker.class)
@BugPattern(
summary = "Prefer `String#join` over `String#format`",
linkType = NONE,
severity = SUGGESTION,
tags = SIMPLIFICATION)
public final class StringJoin extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Splitter FORMAT_SPECIFIER_SPLITTER = Splitter.on("%s");
private static final Matcher<ExpressionTree> STRING_FORMAT_INVOCATION =
staticMethod().onClass(String.class.getName()).named("format");
private static final Supplier<Type> CHAR_SEQUENCE_TYPE =
Suppliers.typeFromClass(CharSequence.class);
private static final Supplier<Type> FORMATTABLE_TYPE = Suppliers.typeFromClass(Formattable.class);
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (!STRING_FORMAT_INVOCATION.matches(tree, state)) {
return Description.NO_MATCH;
}
// XXX: This check assumes that if the first argument to `String#format` is a `Locale`, that
// this argument is not vacuous, and that as a result the expression cannot be simplified using
// `#valueOf` or `#join`. Implement a separate check that identifies and drops redundant
// `Locale` arguments. See also a related comment in `FormatStringConcatenation`.
String formatString = ASTHelpers.constValue(tree.getArguments().get(0), String.class);
if (formatString == null) {
return Description.NO_MATCH;
}
List<String> separators = FORMAT_SPECIFIER_SPLITTER.splitToList(formatString);
if (separators.size() < 2) {
/* The format string does not contain `%s` format specifiers. */
return Description.NO_MATCH;
}
if (separators.size() != tree.getArguments().size()) {
/* The number of arguments does not match the number of `%s` format specifiers. */
return Description.NO_MATCH;
}
int lastIndex = separators.size() - 1;
if (!separators.get(0).isEmpty() || !separators.get(lastIndex).isEmpty()) {
/* The format string contains leading or trailing characters. */
return Description.NO_MATCH;
}
ImmutableSet<String> innerSeparators = ImmutableSet.copyOf(separators.subList(1, lastIndex));
if (innerSeparators.size() > 1) {
/* The `%s` format specifiers are not uniformly separated. */
return Description.NO_MATCH;
}
if (innerSeparators.isEmpty()) {
/*
* This `String#format` invocation performs a straightforward string conversion; use
* `String#valueOf` instead.
*/
return trySuggestExplicitStringConversion(tree, state);
}
String separator = Iterables.getOnlyElement(innerSeparators);
if (separator.indexOf('%') >= 0) {
/* The `%s` format specifiers are separated by another format specifier. */
// XXX: Strictly speaking we could support `%%` by mapping it to a literal `%`, but that
// doesn't seem worth the trouble.
return Description.NO_MATCH;
}
return trySuggestExplicitJoin(tree, separator, state);
}
/**
* If guaranteed to be behavior preserving, suggests replacing {@code String.format("%s", arg)}
* with {@code String.valueOf(arg)}.
*
* <p>If {@code arg} is already a string then the resultant conversion is vacuous. The {@link
* IdentityConversion} check will subsequently drop it.
*/
private Description trySuggestExplicitStringConversion(
MethodInvocationTree tree, VisitorState state) {
ExpressionTree argument = tree.getArguments().get(1);
if (isSubtype(ASTHelpers.getType(argument), FORMATTABLE_TYPE, state)) {
/*
* `Formattable` arguments are handled specially; `String#valueOf` is not a suitable
* alternative.
*/
return Description.NO_MATCH;
}
return buildDescription(tree)
.setMessage("Prefer `String#valueOf` over `String#format`")
.addFix(SuggestedFix.replace(tree, withStringConversionExpression(argument, state)))
.build();
}
/**
* Unless the given {@code String.format} expression includes {@link Formattable} arguments,
* suggests replacing it with a {@code String.join} expression using the specified argument
* separator.
*/
private Description trySuggestExplicitJoin(
MethodInvocationTree tree, String separator, VisitorState state) {
Iterator<? extends ExpressionTree> arguments = tree.getArguments().iterator();
SuggestedFix.Builder fix =
SuggestedFix.builder()
.replace(tree.getMethodSelect(), "String.join")
.replace(arguments.next(), String.format("\"%s\"", Convert.quote(separator)));
while (arguments.hasNext()) {
ExpressionTree argument = arguments.next();
Type argumentType = ASTHelpers.getType(argument);
if (isSubtype(argumentType, FORMATTABLE_TYPE, state)) {
/*
* `Formattable` arguments are handled specially; `String#join` is not a suitable
* alternative.
*/
return Description.NO_MATCH;
}
if (!isSubtype(argumentType, CHAR_SEQUENCE_TYPE, state)) {
/*
* The argument was previously implicitly converted to a string; now this must happen
* explicitly.
*/
fix.replace(argument, withStringConversionExpression(argument, state));
}
}
return describeMatch(tree, fix.build());
}
private static boolean isSubtype(
@Nullable Type subType, Supplier<Type> superType, VisitorState state) {
return ASTHelpers.isSubtype(subType, superType.get(state), state);
}
private static String withStringConversionExpression(
ExpressionTree argument, VisitorState state) {
return String.format("String.valueOf(%s)", SourceCode.treeToString(argument, state));
}
}

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static org.assertj.core.data.Offset.offset;
import static org.assertj.core.data.Percentage.withPercentage;
@@ -9,19 +9,21 @@ import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.math.BigDecimal;
import org.assertj.core.api.AbstractBigDecimalAssert;
import org.assertj.core.api.BigDecimalAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/**
* Refaster templates related to AssertJ assertions over {@link BigDecimal}s.
* Refaster rules related to AssertJ assertions over {@link BigDecimal}s.
*
* <p>Note that, contrary to collections of Refaster templates for other {@link
* org.assertj.core.api.NumberAssert} subtypes, these templates do not rewrite to/from {@link
* <p>Note that, contrary to collections of Refaster rules for other {@link
* org.assertj.core.api.NumberAssert} subtypes, these rules do not rewrite to/from {@link
* BigDecimalAssert#isEqualTo(Object)} and {@link BigDecimalAssert#isNotEqualTo(Object)}. This is
* because {@link BigDecimal#equals(Object)} considers not only the numeric value of compared
* instances, but also their scale. As a result various seemingly straightforward transformations
* would actually subtly change the assertion's semantics.
*/
final class AssertJBigDecimalTemplates {
private AssertJBigDecimalTemplates() {}
@OnlineDocumentation
final class AssertJBigDecimalRules {
private AssertJBigDecimalRules() {}
static final class AbstractBigDecimalAssertIsEqualByComparingTo {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static org.assertj.core.data.Offset.offset;
import static org.assertj.core.data.Percentage.withPercentage;
@@ -8,11 +8,13 @@ import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.math.BigInteger;
import org.assertj.core.api.AbstractBigIntegerAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
// XXX: If we add a rule that drops unnecessary `L` suffixes from literal longs, then the `0L`/`1L`
// cases below can go.
final class AssertJBigIntegerTemplates {
private AssertJBigIntegerTemplates() {}
@OnlineDocumentation
final class AssertJBigIntegerRules {
private AssertJBigIntegerRules() {}
static final class AbstractBigIntegerAssertIsEqualTo {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
@@ -8,9 +8,11 @@ import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import org.assertj.core.api.AbstractBooleanAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJBooleanTemplates {
private AssertJBooleanTemplates() {}
@OnlineDocumentation
final class AssertJBooleanRules {
private AssertJBooleanRules() {}
static final class AbstractBooleanAssertIsEqualTo {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static org.assertj.core.data.Offset.offset;
import static org.assertj.core.data.Percentage.withPercentage;
@@ -7,9 +7,11 @@ import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import org.assertj.core.api.AbstractByteAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJByteTemplates {
private AssertJByteTemplates() {}
@OnlineDocumentation
final class AssertJByteRules {
private AssertJByteRules() {}
static final class AbstractByteAssertIsEqualTo {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
@@ -8,9 +8,11 @@ import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import org.assertj.core.api.AbstractAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJCharSequenceTemplates {
private AssertJCharSequenceTemplates() {}
@OnlineDocumentation
final class AssertJCharSequenceRules {
private AssertJCharSequenceRules() {}
static final class AssertThatCharSequenceIsEmpty {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
@@ -8,9 +8,11 @@ import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import org.assertj.core.api.AbstractComparableAssert;
import org.assertj.core.api.AbstractIntegerAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJComparableTemplates {
private AssertJComparableTemplates() {}
@OnlineDocumentation
final class AssertJComparableRules {
private AssertJComparableRules() {}
static final class AssertThatIsEqualByComparingTo<T extends Comparable<? super T>> {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static org.assertj.core.data.Offset.offset;
import static org.assertj.core.data.Percentage.withPercentage;
@@ -8,9 +8,11 @@ import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import org.assertj.core.api.AbstractDoubleAssert;
import org.assertj.core.data.Offset;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJDoubleTemplates {
private AssertJDoubleTemplates() {}
@OnlineDocumentation
final class AssertJDoubleRules {
private AssertJDoubleRules() {}
static final class AbstractDoubleAssertIsCloseToWithOffset {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.Iterables;
import com.google.errorprone.refaster.Refaster;
@@ -6,9 +6,11 @@ import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.Collection;
import org.assertj.core.api.EnumerableAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJEnumerableTemplates {
private AssertJEnumerableTemplates() {}
@OnlineDocumentation
final class AssertJEnumerableRules {
private AssertJEnumerableRules() {}
static final class EnumerableAssertIsEmpty<E> {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static org.assertj.core.data.Offset.offset;
import static org.assertj.core.data.Percentage.withPercentage;
@@ -8,9 +8,11 @@ import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import org.assertj.core.api.AbstractFloatAssert;
import org.assertj.core.data.Offset;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJFloatTemplates {
private AssertJFloatTemplates() {}
@OnlineDocumentation
final class AssertJFloatRules {
private AssertJFloatRules() {}
static final class AbstractFloatAssertIsCloseToWithOffset {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static org.assertj.core.data.Offset.offset;
import static org.assertj.core.data.Percentage.withPercentage;
@@ -7,9 +7,11 @@ import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import org.assertj.core.api.AbstractIntegerAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJIntegerTemplates {
private AssertJIntegerTemplates() {}
@OnlineDocumentation
final class AssertJIntegerRules {
private AssertJIntegerRules() {}
static final class AbstractIntegerAssertIsEqualTo {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static org.assertj.core.data.Offset.offset;
import static org.assertj.core.data.Percentage.withPercentage;
@@ -7,9 +7,11 @@ import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import org.assertj.core.api.AbstractLongAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJLongTemplates {
private AssertJLongTemplates() {}
@OnlineDocumentation
final class AssertJLongRules {
private AssertJLongRules() {}
static final class AbstractLongAssertIsEqualTo {
@BeforeTemplate

View File

@@ -1,13 +1,15 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.ImmutableMap;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.Map;
import org.assertj.core.api.AbstractMapAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJMapTemplates {
private AssertJMapTemplates() {}
@OnlineDocumentation
final class AssertJMapRules {
private AssertJMapRules() {}
static final class AbstractMapAssertContainsExactlyInAnyOrderEntriesOf<K, V> {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
@@ -19,10 +19,12 @@ import org.assertj.core.api.AbstractIntegerAssert;
import org.assertj.core.api.AbstractLongAssert;
import org.assertj.core.api.AbstractShortAssert;
import org.assertj.core.api.NumberAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.matchers.IsCharacter;
final class AssertJNumberTemplates {
private AssertJNumberTemplates() {}
@OnlineDocumentation
final class AssertJNumberRules {
private AssertJNumberRules() {}
static final class NumberAssertIsPositive {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
@@ -10,9 +10,11 @@ import com.google.errorprone.refaster.annotation.UseImportPolicy;
import org.assertj.core.api.AbstractBooleanAssert;
import org.assertj.core.api.AbstractStringAssert;
import org.assertj.core.api.ObjectAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJObjectTemplates {
private AssertJObjectTemplates() {}
@OnlineDocumentation
final class AssertJObjectRules {
private AssertJObjectRules() {}
static final class AssertThatIsInstanceOf<S, T> {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
@@ -14,9 +14,11 @@ import org.assertj.core.api.AbstractObjectAssert;
import org.assertj.core.api.AbstractOptionalAssert;
import org.assertj.core.api.ObjectAssert;
import org.assertj.core.api.OptionalAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJOptionalTemplates {
private AssertJOptionalTemplates() {}
@OnlineDocumentation
final class AssertJOptionalRules {
private AssertJOptionalRules() {}
static final class AssertThatOptional<T> {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
@@ -9,9 +9,11 @@ import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import org.assertj.core.api.AbstractBooleanAssert;
import org.assertj.core.api.AbstractDoubleAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJPrimitiveTemplates {
private AssertJPrimitiveTemplates() {}
@OnlineDocumentation
final class AssertJPrimitiveRules {
private AssertJPrimitiveRules() {}
static final class AssertThatIsEqualTo {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
@@ -53,9 +53,10 @@ 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.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.matchers.IsArray;
/** Refaster templates related to AssertJ expressions and statements. */
/** Refaster rules related to AssertJ expressions and statements. */
// XXX: Most `AbstractIntegerAssert` rules can also be applied for other primitive types. Generate
// these in separate files.
// XXX: Also do for BigInteger/BigDecimal?
@@ -63,7 +64,7 @@ import tech.picnic.errorprone.refaster.matchers.IsArray;
// ^ And variants.
// XXX: Consider splitting this class into multiple classes.
// XXX: Some of these rules may not apply given the updated TestNG rewrite rules. Review.
// XXX: For the templates that "unwrap" explicitly enumerated collections, also introduce variants
// XXX: For the rules that "unwrap" explicitly enumerated collections, also introduce variants
// with explicitly enumerated sorted collections. (Requires that the type bound is Comparable.)
// XXX: Handle `.isEqualTo(explicitlyEnumeratedCollection)`. Can be considered equivalent to
// `.containsOnly(elements)`. (This does mean the auto-generated code needs to be more advanced.
@@ -101,7 +102,7 @@ import tech.picnic.errorprone.refaster.matchers.IsArray;
// (etc.)
// XXX: Look into using Assertions#contentOf(URL url, Charset charset) instead of our own test
// method.
// XXX: Write Optional templates also for `OptionalInt` and variants.
// XXX: Write `Optional` rules also for `OptionalInt` and variants.
// XXX: Write plugin to flag `assertThat(compileTimeConstant)` occurrences. Also other likely
// candidates, such as `assertThat(ImmutableSet(foo, bar)).XXX`
// XXX: Write generic plugin to replace explicit array parameters with varargs (`new int[] {1, 2}`
@@ -118,10 +119,11 @@ import tech.picnic.errorprone.refaster.matchers.IsArray;
// XXX: `assertThat(ImmutableList.sortedCopyOf(cmp, values)).somethingExactOrder` -> just compare
// "in any order".
// XXX: Turns out a lot of this is also covered by https://github.com/palantir/assertj-automation.
// See how we can combine these things. Do note that (at present) their Refaster templates don't
// See how we can combine these things. Do note that (at present) their Refaster rules don't
// show up as Error Prone checks. So we'd have to build an integration for that.
final class AssertJTemplates {
private AssertJTemplates() {}
@OnlineDocumentation
final class AssertJRules {
private AssertJRules() {}
//
// OptionalDouble
@@ -491,7 +493,7 @@ final class AssertJTemplates {
}
// XXX: This overload is here because `assertThat` has an overload for `Comparable` types.
// Unfortunately this still doesn't convince Refaster to match this template in the context of
// Unfortunately this still doesn't convince Refaster to match this rule in the context of
// Comparable types. Figure out why! Note that this also affects the `AssertThatOptional` rule.
static final class AssertThatIterableHasOneComparableElementEqualTo<
S extends Comparable<? super S>, T extends S> {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static org.assertj.core.data.Offset.offset;
import static org.assertj.core.data.Percentage.withPercentage;
@@ -7,9 +7,11 @@ import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import org.assertj.core.api.AbstractShortAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJShortTemplates {
private AssertJShortTemplates() {}
@OnlineDocumentation
final class AssertJShortRules {
private AssertJShortRules() {}
static final class AbstractShortAssertIsEqualTo {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
@@ -8,9 +8,11 @@ import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractStringAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJStringTemplates {
private AssertJStringTemplates() {}
@OnlineDocumentation
final class AssertJStringRules {
private AssertJStringRules() {}
static final class AbstractStringAssertStringIsEmpty {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -16,18 +16,20 @@ import java.io.IOException;
import org.assertj.core.api.AbstractObjectAssert;
import org.assertj.core.api.AbstractThrowableAssert;
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/**
* Refaster templates related to AssertJ assertions over expressions that may throw a {@link
* Throwable} subtype.
* Refaster rules related to AssertJ assertions over expressions that may throw a {@link Throwable}
* subtype.
*
* <p>For reasons of consistency we prefer {@link
* org.assertj.core.api.Assertions#assertThatThrownBy} over static methods for specific exception
* types. Note that only the most common assertion expressions are rewritten here; covering all
* cases would require the implementation of an Error Prone check instead.
*/
final class AssertJThrowingCallableTemplates {
private AssertJThrowingCallableTemplates() {}
@OnlineDocumentation
final class AssertJThrowingCallableRules {
private AssertJThrowingCallableRules() {}
static final class AssertThatThrownByIllegalArgumentException {
@BeforeTemplate
@@ -429,8 +431,8 @@ final class AssertJThrowingCallableTemplates {
}
}
// XXX: Drop this template in favour of a generic Error Prone check that flags
// `String.format(...)` arguments to a wide range of format methods.
// XXX: Drop this rule in favour of a generic Error Prone check that flags `String.format(...)`
// arguments to a wide range of format methods.
static final class AbstractThrowableAssertHasMessage {
@BeforeTemplate
AbstractThrowableAssert<?, ? extends Throwable> before(
@@ -449,8 +451,8 @@ final class AssertJThrowingCallableTemplates {
}
}
// XXX: Drop this template in favour of a generic Error Prone check that flags
// `String.format(...)` arguments to a wide range of format methods.
// XXX: Drop this rule in favour of a generic Error Prone check that flags `String.format(...)`
// arguments to a wide range of format methods.
static final class AbstractThrowableAssertWithFailMessage {
@BeforeTemplate
AbstractThrowableAssert<?, ? extends Throwable> before(

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.common.base.Preconditions.checkElementIndex;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
@@ -28,13 +28,15 @@ import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/**
* Assorted Refaster templates that do not (yet) belong in one of the other classes with more
* topical Refaster templates.
* Assorted Refaster rules that do not (yet) belong in one of the other classes with more topical
* Refaster rules.
*/
final class AssortedTemplates {
private AssortedTemplates() {}
@OnlineDocumentation
final class AssortedRules {
private AssortedRules() {}
/** Prefer {@link Objects#checkIndex(int, int)} over the Guava alternative. */
static final class CheckIndex {
@@ -117,7 +119,7 @@ final class AssortedTemplates {
}
/** Don't unnecessarily repeat boolean expressions. */
// XXX: This template captures only the simplest case. `@AlsoNegation` doesn't help. Consider
// XXX: This rule captures only the simplest case. `@AlsoNegation` doesn't help. Consider
// contributing a Refaster patch, which handles the negation in the `@BeforeTemplate` more
// intelligently.
static final class LogicalImplication {
@@ -172,8 +174,8 @@ final class AssortedTemplates {
* Collections#disjoint(Collection, Collection)}.
*/
// XXX: Other copy operations could be elided too, but these are most common after application of
// the `DisjointSets` template defined above. If we ever introduce a generic "makes a copy"
// stand-in, use it here.
// the `DisjointSets` rule defined above. If we ever introduce a generic "makes a copy" stand-in,
// use it here.
static final class DisjointCollections<T> {
@BeforeTemplate
boolean before(Collection<T> collection1, Collection<T> collection2) {

View File

@@ -1,13 +1,15 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.math.BigDecimal;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link BigDecimal}s. */
final class BigDecimalTemplates {
private BigDecimalTemplates() {}
/** Refaster rules related to expressions dealing with {@link BigDecimal}s. */
@OnlineDocumentation
final class BigDecimalRules {
private BigDecimalRules() {}
/** Prefer using the constant {@link BigDecimal#ZERO} when possible. */
static final class BigDecimalZero {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
@@ -19,12 +19,14 @@ import java.util.Set;
import java.util.SortedSet;
import java.util.function.IntFunction;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with (arbitrary) collections. */
/** Refaster rules related to expressions dealing with (arbitrary) collections. */
// XXX: There are other Guava `Iterables` methods that should not be called if the input is known to
// be a `Collection`. Add those here.
final class CollectionTemplates {
private CollectionTemplates() {}
@OnlineDocumentation
final class CollectionRules {
private CollectionRules() {}
/**
* Prefer {@link Collection#isEmpty()} over alternatives that consult the collection's size or are

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Comparator.comparing;
@@ -24,10 +24,12 @@ import java.util.function.Function;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link Comparator}s. */
final class ComparatorTemplates {
private ComparatorTemplates() {}
/** Refaster rules related to expressions dealing with {@link Comparator}s. */
@OnlineDocumentation
final class ComparatorRules {
private ComparatorRules() {}
/** Prefer {@link Comparator#naturalOrder()} over more complicated constructs. */
static final class NaturalOrder<T extends Comparable<? super T>> {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.Refaster;
@@ -12,10 +12,12 @@ import java.util.function.DoublePredicate;
import java.util.function.DoubleUnaryOperator;
import java.util.stream.DoubleStream;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link DoubleStream}s. */
final class DoubleStreamTemplates {
private DoubleStreamTemplates() {}
/** Refaster rules related to expressions dealing with {@link DoubleStream}s. */
@OnlineDocumentation
final class DoubleStreamRules {
private DoubleStreamRules() {}
/** Don't unnecessarily call {@link Streams#concat(DoubleStream...)}. */
static final class ConcatOneDoubleStream {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
@@ -6,10 +6,12 @@ import com.google.errorprone.refaster.annotation.AlsoNegation;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.Objects;
import java.util.function.Predicate;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with (in)equalities. */
final class EqualityTemplates {
private EqualityTemplates() {}
/** Refaster rules related to expressions dealing with (in)equalities. */
@OnlineDocumentation
final class EqualityRules {
private EqualityRules() {}
/** Prefer reference-based quality for enums. */
// Primitive value comparisons are not listed, because Error Prone flags those out of the box.

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableListMultimap.flatteningToImmutableListMultimap;
import static com.google.common.collect.ImmutableListMultimap.toImmutableListMultimap;
@@ -24,10 +24,12 @@ import java.util.Iterator;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link ImmutableListMultimap}s. */
final class ImmutableListMultimapTemplates {
private ImmutableListMultimapTemplates() {}
/** Refaster rules related to expressions dealing with {@link ImmutableListMultimap}s. */
@OnlineDocumentation
final class ImmutableListMultimapRules {
private ImmutableListMultimapRules() {}
/**
* Prefer {@link ImmutableListMultimap#builder()} over the associated constructor on constructions
@@ -70,7 +72,7 @@ final class ImmutableListMultimapTemplates {
* alternatives.
*/
// XXX: One can define variants for more than one key-value pair, but at some point the builder
// actually produces nicer code. So it's not clear we should add Refaster templates for those
// actually produces nicer code. So it's not clear we should add Refaster rules for those
// variants.
static final class PairToImmutableListMultimap<K, V> {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
@@ -20,10 +20,12 @@ import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link ImmutableList}s. */
final class ImmutableListTemplates {
private ImmutableListTemplates() {}
/** Refaster rules related to expressions dealing with {@link ImmutableList}s. */
@OnlineDocumentation
final class ImmutableListRules {
private ImmutableListRules() {}
/** Prefer {@link ImmutableList#builder()} over the associated constructor. */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
@@ -154,7 +156,7 @@ final class ImmutableListTemplates {
* communicate the immutability of the resulting list at the type level.
*/
// XXX: The `Stream` variant may be too contrived to warrant inclusion. Review its usage if/when
// this and similar Refaster templates are replaced with an Error Prone check.
// this and similar Refaster rules are replaced with an Error Prone check.
static final class ImmutableListOf<T> {
@BeforeTemplate
List<T> before() {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
@@ -21,10 +21,12 @@ import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link ImmutableMap}s. */
final class ImmutableMapTemplates {
private ImmutableMapTemplates() {}
/** Refaster rules related to expressions dealing with {@link ImmutableMap}s. */
@OnlineDocumentation
final class ImmutableMapRules {
private ImmutableMapRules() {}
/** Prefer {@link ImmutableMap#builder()} over the associated constructor. */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
@@ -313,7 +315,7 @@ final class ImmutableMapTemplates {
}
}
// XXX: Add a template for this:
// XXX: Add a rule for this:
// Maps.transformValues(streamOfEntries.collect(groupBy(fun)), ImmutableMap::copyOf)
// ->
// streamOfEntries.collect(groupBy(fun, toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)))

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableMultiset.toImmutableMultiset;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
@@ -13,10 +13,12 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link ImmutableMultiset}s. */
final class ImmutableMultisetTemplates {
private ImmutableMultisetTemplates() {}
/** Refaster rules related to expressions dealing with {@link ImmutableMultiset}s. */
@OnlineDocumentation
final class ImmutableMultisetRules {
private ImmutableMultisetRules() {}
/** Prefer {@link ImmutableMultiset#builder()} over the associated constructor. */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableSetMultimap.flatteningToImmutableSetMultimap;
import static com.google.common.collect.ImmutableSetMultimap.toImmutableSetMultimap;
@@ -21,10 +21,12 @@ import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link ImmutableSetMultimap}s. */
final class ImmutableSetMultimapTemplates {
private ImmutableSetMultimapTemplates() {}
/** Refaster rules related to expressions dealing with {@link ImmutableSetMultimap}s. */
@OnlineDocumentation
final class ImmutableSetMultimapRules {
private ImmutableSetMultimapRules() {}
/** Prefer {@link ImmutableSetMultimap#builder()} over the associated constructor. */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
@@ -56,7 +58,7 @@ final class ImmutableSetMultimapTemplates {
/** Prefer {@link ImmutableSetMultimap#of(Object, Object)} over more contrived alternatives. */
// XXX: One can define variants for more than one key-value pair, but at some point the builder
// actually produces nicer code. So it's not clear we should add Refaster templates for those
// actually produces nicer code. So it's not clear we should add Refaster rules for those
// variants.
static final class PairToImmutableSetMultimap<K, V> {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
@@ -17,10 +17,12 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link ImmutableSet}s. */
final class ImmutableSetTemplates {
private ImmutableSetTemplates() {}
/** Refaster rules related to expressions dealing with {@link ImmutableSet}s. */
@OnlineDocumentation
final class ImmutableSetRules {
private ImmutableSetRules() {}
/** Prefer {@link ImmutableSet#builder()} over the associated constructor. */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
@@ -104,7 +106,7 @@ final class ImmutableSetTemplates {
* communicate the immutability of the resulting set at the type level.
*/
// XXX: The `Stream` variant may be too contrived to warrant inclusion. Review its usage if/when
// this and similar Refaster templates are replaced with an Error Prone check.
// this and similar Refaster rules are replaced with an Error Prone check.
static final class ImmutableSetOf<T> {
@BeforeTemplate
Set<T> before() {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableSortedMap.toImmutableSortedMap;
import static java.util.Comparator.naturalOrder;
@@ -13,10 +13,12 @@ import java.util.Collection;
import java.util.Comparator;
import java.util.Map;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link ImmutableSortedMap}s. */
final class ImmutableSortedMapTemplates {
private ImmutableSortedMapTemplates() {}
/** Refaster rules related to expressions dealing with {@link ImmutableSortedMap}s. */
@OnlineDocumentation
final class ImmutableSortedMapRules {
private ImmutableSortedMapRules() {}
/** Prefer {@link ImmutableSortedMap#orderedBy(Comparator)} over the associated constructor. */
static final class ImmutableSortedMapBuilder<K, V> {
@@ -82,7 +84,7 @@ final class ImmutableSortedMapTemplates {
/** Prefer {@link ImmutableSortedMap#of(Object, Object)} over more contrived alternatives. */
// XXX: One can define variants for more than one key-value pair, but at some point the builder
// actually produces nicer code. So it's not clear we should add Refaster templates for those
// actually produces nicer code. So it's not clear we should add Refaster rules for those
// variants.
// XXX: We could also rewrite builders with non-natural orders, but that would affect
// `ImmutableSortedMap#comparator()`.

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableSortedMultiset.toImmutableSortedMultiset;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
@@ -15,10 +15,12 @@ import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link ImmutableSortedMultiset}s. */
final class ImmutableSortedMultisetTemplates {
private ImmutableSortedMultisetTemplates() {}
/** Refaster rules related to expressions dealing with {@link ImmutableSortedMultiset}s. */
@OnlineDocumentation
final class ImmutableSortedMultisetRules {
private ImmutableSortedMultisetRules() {}
/**
* Prefer {@link ImmutableSortedMultiset#orderedBy(Comparator)} over the associated constructor.

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
@@ -15,10 +15,12 @@ import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link ImmutableSortedSet}s. */
final class ImmutableSortedSetTemplates {
private ImmutableSortedSetTemplates() {}
/** Refaster rules related to expressions dealing with {@link ImmutableSortedSet}s. */
@OnlineDocumentation
final class ImmutableSortedSetRules {
private ImmutableSortedSetRules() {}
/** Prefer {@link ImmutableSortedSet#orderedBy(Comparator)} over the associated constructor. */
static final class ImmutableSortedSetBuilder<T> {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.Refaster;
@@ -12,10 +12,12 @@ import java.util.function.IntPredicate;
import java.util.function.IntUnaryOperator;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link IntStream}s. */
final class IntStreamTemplates {
private IntStreamTemplates() {}
/** Refaster rules related to expressions dealing with {@link IntStream}s. */
@OnlineDocumentation
final class IntStreamRules {
private IntStreamRules() {}
/** Prefer {@link IntStream#range(int, int)} over the more contrived alternative. */
static final class IntStreamClosedOpenRange {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.junit.jupiter.params.provider.Arguments.arguments;
@@ -8,10 +8,12 @@ import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Repeated;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import org.junit.jupiter.params.provider.Arguments;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to JUnit expressions and statements. */
final class JUnitTemplates {
private JUnitTemplates() {}
/** Refaster rules related to JUnit expressions and statements. */
@OnlineDocumentation
final class JUnitRules {
private JUnitRules() {}
/** Prefer statically imported {@link Arguments#arguments} over {@link Arguments#of} calls. */
static final class ArgumentsEnumeration<T> {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.Refaster;
@@ -12,10 +12,12 @@ import java.util.function.LongPredicate;
import java.util.function.LongUnaryOperator;
import java.util.stream.LongStream;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link LongStream}s. */
final class LongStreamTemplates {
private LongStreamTemplates() {}
/** Refaster rules related to expressions dealing with {@link LongStream}s. */
@OnlineDocumentation
final class LongStreamRules {
private LongStreamRules() {}
/** Prefer {@link LongStream#range(long, long)} over the more contrived alternative. */
static final class LongStreamClosedOpenRange {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Comparator.comparing;
@@ -14,10 +14,12 @@ import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.AbstractMap;
import java.util.Comparator;
import java.util.Map;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link Map.Entry} instances. */
final class MapEntryTemplates {
private MapEntryTemplates() {}
/** Refaster rules related to expressions dealing with {@link Map.Entry} instances. */
@OnlineDocumentation
final class MapEntryRules {
private MapEntryRules() {}
/**
* Prefer {@link Map#entry(Object, Object)} over alternative ways to create an immutable map

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.mockito.Mockito.never;
@@ -10,10 +10,12 @@ import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import org.mockito.Mockito;
import org.mockito.verification.VerificationMode;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to Mockito expressions and statements. */
final class MockitoTemplates {
private MockitoTemplates() {}
/** Refaster rules related to Mockito expressions and statements. */
@OnlineDocumentation
final class MockitoRules {
private MockitoRules() {}
/**
* Prefer {@link Mockito#never()}} over explicitly specifying that the associated invocation must

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
@@ -8,10 +8,12 @@ import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.Collection;
import java.util.Set;
import javax.annotation.Nullable;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link Multimap}s. */
final class MultimapTemplates {
private MultimapTemplates() {}
/** Refaster rules related to expressions dealing with {@link Multimap}s. */
@OnlineDocumentation
final class MultimapRules {
private MultimapRules() {}
/** Prefer {@link Multimap#keySet()} over more contrived alternatives. */
static final class MultimapKeySet<K, V> {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Objects.requireNonNullElse;
@@ -10,10 +10,12 @@ import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Objects;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with (possibly) null values. */
final class NullTemplates {
private NullTemplates() {}
/** Refaster rules related to expressions dealing with (possibly) null values. */
@OnlineDocumentation
final class NullRules {
private NullRules() {}
/** Prefer the {@code ==} operator over {@link Objects#isNull(Object)}. */
static final class IsNull {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
@@ -17,10 +17,12 @@ import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link Optional}s. */
final class OptionalTemplates {
private OptionalTemplates() {}
/** Refaster rules related to expressions dealing with {@link Optional}s. */
@OnlineDocumentation
final class OptionalRules {
private OptionalRules() {}
static final class OptionalOfNullable<T> {
// XXX: Refaster should be smart enough to also rewrite occurrences in which there are
@@ -78,8 +80,8 @@ final class OptionalTemplates {
}
/** Prefer {@link Optional#orElseThrow()} over the less explicit {@link Optional#get()}. */
// XXX: This template is analogous to `OptionalOrElseThrow` above. Arguably this is its
// generalization. If/when Refaster is extended to understand this, delete the template above.
// XXX: This rule is analogous to `OptionalOrElseThrow` above. Arguably this is its
// generalization. If/when Refaster is extended to understand this, delete the rule above.
static final class OptionalOrElseThrowMethodReference<T> {
@BeforeTemplate
Function<Optional<T>, T> before() {

View File

@@ -1,12 +1,14 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import com.google.common.primitives.Ints;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with primitives. */
final class PrimitiveTemplates {
private PrimitiveTemplates() {}
/** Refaster rules related to expressions dealing with primitives. */
@OnlineDocumentation
final class PrimitiveRules {
private PrimitiveRules() {}
/** Avoid contrived ways of expressing the "less than" relationship. */
static final class LessThan {

View File

@@ -1,7 +1,8 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.MoreCollectors.toOptional;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.function.Function.identity;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.MoreCollectors;
@@ -24,11 +25,13 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import reactor.test.publisher.PublisherProbe;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.matchers.ThrowsCheckedException;
/** Refaster templates related to Reactor expressions and statements. */
final class ReactorTemplates {
private ReactorTemplates() {}
/** Refaster rules related to Reactor expressions and statements. */
@OnlineDocumentation
final class ReactorRules {
private ReactorRules() {}
/**
* Prefer {@link Mono#fromSupplier(Supplier)} over {@link Mono#fromCallable(Callable)} where
@@ -94,7 +97,7 @@ final class ReactorTemplates {
/**
* Don't unnecessarily pass {@link Mono#error(Supplier)} a method reference or lambda expression.
*/
// XXX: Drop this rule once the more general rule `AssortedTemplates#SupplierAsSupplier` works
// XXX: Drop this rule once the more general rule `AssortedRules#SupplierAsSupplier` works
// reliably.
static final class MonoErrorSupplier<T, E extends Throwable> {
@BeforeTemplate
@@ -111,7 +114,7 @@ final class ReactorTemplates {
/**
* Don't unnecessarily pass {@link Flux#error(Supplier)} a method reference or lambda expression.
*/
// XXX: Drop this rule once the more general rule `AssortedTemplates#SupplierAsSupplier` works
// XXX: Drop this rule once the more general rule `AssortedRules#SupplierAsSupplier` works
// reliably.
static final class FluxErrorSupplier<T, E extends Throwable> {
@BeforeTemplate
@@ -177,6 +180,26 @@ final class ReactorTemplates {
}
}
/** Prefer {@link Flux#concatMap(Function, int)} over more contrived alternatives. */
static final class FluxConcatMapWithPrefetch<T, S> {
@BeforeTemplate
Flux<S> before(
Flux<T> flux,
Function<? super T, ? extends Publisher<? extends S>> function,
int prefetch) {
return Refaster.anyOf(
flux.flatMap(function, 1, prefetch), flux.flatMapSequential(function, 1, prefetch));
}
@AfterTemplate
Flux<S> after(
Flux<T> flux,
Function<? super T, ? extends Publisher<? extends S>> function,
int prefetch) {
return flux.concatMap(function, prefetch);
}
}
/**
* Prefer {@link Flux#concatMapIterable(Function)} over {@link Flux#flatMapIterable(Function)}, as
* the former has equivalent semantics but a clearer name.
@@ -193,6 +216,24 @@ final class ReactorTemplates {
}
}
/**
* Prefer {@link Flux#concatMapIterable(Function, int)} over {@link Flux#flatMapIterable(Function,
* int)}, as the former has equivalent semantics but a clearer name.
*/
static final class FluxConcatMapIterableWithPrefetch<T, S> {
@BeforeTemplate
Flux<S> before(
Flux<T> flux, Function<? super T, ? extends Iterable<? extends S>> function, int prefetch) {
return flux.flatMapIterable(function, prefetch);
}
@AfterTemplate
Flux<S> after(
Flux<T> flux, Function<? super T, ? extends Iterable<? extends S>> function, int prefetch) {
return flux.concatMapIterable(function, prefetch);
}
}
/**
* Don't use {@link Mono#flatMapMany(Function)} to implicitly convert a {@link Mono} to a {@link
* Flux}.
@@ -271,11 +312,74 @@ final class ReactorTemplates {
}
}
/**
* Prefer {@link Flux#concatMapIterable(Function)} over alternatives that require an additional
* subscription.
*/
static final class ConcatMapIterableIdentity<T> {
@BeforeTemplate
Flux<T> before(Flux<? extends Iterable<T>> flux) {
return Refaster.anyOf(
flux.concatMap(list -> Flux.fromIterable(list)), flux.concatMap(Flux::fromIterable));
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Flux<T> after(Flux<? extends Iterable<T>> flux) {
return flux.concatMapIterable(identity());
}
}
/**
* Prefer {@link Flux#concatMapIterable(Function, int)} over alternatives that require an
* additional subscription.
*/
static final class ConcatMapIterableIdentityWithPrefetch<T> {
@BeforeTemplate
Flux<T> before(Flux<? extends Iterable<T>> flux, int prefetch) {
return Refaster.anyOf(
flux.concatMap(list -> Flux.fromIterable(list), prefetch),
flux.concatMap(Flux::fromIterable, prefetch));
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Flux<T> after(Flux<? extends Iterable<T>> flux, int prefetch) {
return flux.concatMapIterable(identity(), prefetch);
}
}
/** Prefer {@link Mono#onErrorComplete()} over more contrived alternatives. */
static final class MonoOnErrorComplete<T> {
@BeforeTemplate
Mono<T> before(Mono<T> mono) {
return mono.onErrorResume(e -> Mono.empty());
}
@AfterTemplate
Mono<T> after(Mono<T> mono) {
return mono.onErrorComplete();
}
}
/** Prefer {@link Flux#onErrorComplete()} over more contrived alternatives. */
static final class FluxOnErrorComplete<T> {
@BeforeTemplate
Flux<T> before(Flux<T> flux) {
return flux.onErrorResume(e -> Refaster.anyOf(Mono.empty(), Flux.empty()));
}
@AfterTemplate
Flux<T> after(Flux<T> flux) {
return flux.onErrorComplete();
}
}
/** Prefer {@link PublisherProbe#empty()}} over more verbose alternatives. */
static final class PublisherProbeEmpty<T> {
@BeforeTemplate
PublisherProbe<T> before() {
return Refaster.anyOf(PublisherProbe.of(Mono.empty()), PublisherProbe.of(Flux.empty()));
return PublisherProbe.of(Refaster.anyOf(Mono.empty(), Flux.empty()));
}
@AfterTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
@@ -13,10 +13,12 @@ import org.jspecify.nullness.Nullable;
import reactor.adapter.rxjava.RxJava2Adapter;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link RxJava2Adapter}. */
final class RxJava2AdapterTemplates {
private RxJava2AdapterTemplates() {}
/** Refaster rules related to expressions dealing with {@link RxJava2Adapter}. */
@OnlineDocumentation
final class RxJava2AdapterRules {
private RxJava2AdapterRules() {}
/** Use the fluent API style when using {@link RxJava2Adapter#completableToMono}. */
static final class CompletableToMono {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Comparator.naturalOrder;
@@ -22,10 +22,12 @@ import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link Stream}s. */
final class StreamTemplates {
private StreamTemplates() {}
/** Refaster rules related to expressions dealing with {@link Stream}s. */
@OnlineDocumentation
final class StreamRules {
private StreamRules() {}
/**
* Prefer {@link Collectors#joining()} over {@link Collectors#joining(CharSequence)} with an empty

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.joining;
@@ -17,11 +17,13 @@ import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import javax.annotation.Nullable;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with {@link String}s. */
/** Refaster rules related to expressions dealing with {@link String}s. */
// XXX: Should we prefer `s -> !s.isEmpty()` or `not(String::isEmpty)`?
final class StringTemplates {
private StringTemplates() {}
@OnlineDocumentation
final class StringRules {
private StringRules() {}
/** Prefer {@link String#isEmpty()} over alternatives that consult the string's length. */
static final class StringIsEmpty {
@@ -128,8 +130,8 @@ final class StringTemplates {
* Prefer direct delegation to {@link String#valueOf(Object)} over the indirection introduced by
* {@link Objects#toString(Object)}.
*/
// XXX: This template is analogous to `StringValueOf` above. Arguably this is its generalization.
// If/when Refaster is extended to understand this, delete the template above.
// XXX: This rule is analogous to `StringValueOf` above. Arguably this is its generalization.
// If/when Refaster is extended to understand this, delete the rule above.
static final class StringValueOfMethodReference {
@BeforeTemplate
Function<Object, String> before() {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
@@ -30,7 +30,7 @@ import org.testng.Assert;
import org.testng.Assert.ThrowingRunnable;
/**
* Refaster templates that replace TestNG assertions with equivalent AssertJ assertions.
* Refaster rules that replace TestNG assertions with equivalent AssertJ assertions.
*
* <p>Some of the classes below have TestNG {@code @BeforeTemplate}s that reference wildcard type
* bounds ({@code <?>}), while the associated AssertJ {@code @AfterTemplate}s reference stricter
@@ -69,11 +69,11 @@ import org.testng.Assert.ThrowingRunnable;
* </ul>
* </ul>
*/
// XXX: As-is these templates do not result in a complete migration:
// XXX: As-is these rules do not result in a complete migration:
// - Expressions containing comments are skipped due to a limitation of Refaster.
// - Assertions inside lambda expressions are also skipped. Unclear why.
final class TestNGToAssertJTemplates {
private TestNGToAssertJTemplates() {}
final class TestNGToAssertJRules {
private TestNGToAssertJRules() {}
static final class Fail {
@BeforeTemplate

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static java.time.ZoneOffset.UTC;
@@ -21,10 +21,12 @@ import java.time.chrono.ChronoLocalDateTime;
import java.time.chrono.ChronoZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster templates related to expressions dealing with time. */
final class TimeTemplates {
private TimeTemplates() {}
/** Refaster rules related to expressions dealing with time. */
@OnlineDocumentation
final class TimeRules {
private TimeRules() {}
/**
* Prefer {@link Clock#instant()} over {@link Instant#now(Clock)}, as it is more concise and more

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates;
package tech.picnic.errorprone.refasterrules;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.HEAD;
@@ -20,13 +20,15 @@ import org.springframework.web.reactive.function.client.WebClient.RequestBodySpe
import org.springframework.web.reactive.function.client.WebClient.RequestBodyUriSpec;
import org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec;
import org.springframework.web.reactive.function.client.WebClient.RequestHeadersUriSpec;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/**
* Refaster templates related to expressions dealing with {@link
* Refaster rules related to expressions dealing with {@link
* org.springframework.web.reactive.function.client.WebClient} and related types.
*/
final class WebClientTemplates {
private WebClientTemplates() {}
@OnlineDocumentation
final class WebClientRules {
private WebClientRules() {}
/** Prefer {@link RequestBodySpec#bodyValue(Object)} over more contrived alternatives. */
static final class BodyValue<T> {

View File

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

View File

@@ -188,7 +188,7 @@ final class LexicographicalAnnotationAttributeListingTest {
" String[] value() default {};",
" }",
"",
" @Foo({\"b\", \"a\"})",
" @Foo({\" \", \"\", \"b\", \"a\"})",
" A unsortedString();",
"",
" @Foo(cls = {long.class, int.class})",
@@ -225,7 +225,7 @@ final class LexicographicalAnnotationAttributeListingTest {
" String[] value() default {};",
" }",
"",
" @Foo({\"a\", \"b\"})",
" @Foo({\"\", \" \", \"a\", \"b\"})",
" A unsortedString();",
"",
" @Foo(cls = {int.class, long.class})",

View File

@@ -11,7 +11,7 @@ final class MissingRefasterAnnotationTest {
.expectErrorMessage(
"X",
containsPattern(
"The Refaster template contains a method without any Refaster annotations"));
"The Refaster rule contains a method without any Refaster annotations"));
@Test
void identification() {
@@ -74,17 +74,17 @@ final class MissingRefasterAnnotationTest {
" }",
" }",
"",
" static final class ValidRefasterTemplate {",
" static final class ValidRefasterRule {",
" @BeforeTemplate",
" void unusedPureFunctionCall(Object o) {",
" o.toString();",
" }",
" }",
"",
" static final class NotARefasterTemplate {",
" static final class NotARefasterRule {",
" @Override",
" public String toString() {",
" return \"This is not a Refaster template\";",
" return \"This is not a Refaster rule\";",
" }",
" }",
"}")

View File

@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class RefasterTemplateModifiersTest {
final class RefasterRuleModifiersTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(RefasterTemplateModifiers.class, getClass());
CompilationTestHelper.newInstance(RefasterRuleModifiers.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(RefasterTemplateModifiers.class, getClass());
BugCheckerRefactoringTestHelper.newInstance(RefasterRuleModifiers.class, getClass());
@Test
void identification() {

View File

@@ -5,7 +5,7 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class Slf4JLogStatementTest {
final class Slf4jLogStatementTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(Slf4jLogStatement.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =

View File

@@ -0,0 +1,97 @@
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;
final class StringJoinTest {
private final CompilationTestHelper compilationHelper =
CompilationTestHelper.newInstance(StringJoin.class, getClass())
.expectErrorMessage(
"valueOf", containsPattern("Prefer `String#valueOf` over `String#format`"))
.expectErrorMessage("join", containsPattern("Prefer `String#join` over `String#format`"));
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(StringJoin.class, getClass());
@Test
void identification() {
compilationHelper
.addSourceLines(
"A.java",
"import java.util.Formattable;",
"import java.util.Locale;",
"",
"class A {",
" void m() {",
" String.join(\"-\", getClass().getName());",
" String.format(getClass().getName(), getClass().getName());",
" String.format(Locale.ROOT, \"%s\", getClass().getName());",
" String.format(\"%20s\", getClass().getName());",
" // BUG: Diagnostic matches: valueOf",
" String.format(\"%s\", getClass().getName());",
" // BUG: Diagnostic matches: valueOf",
" String.format(\"%s\", hashCode());",
" String.format(\"%s\", (Formattable) null);",
" String.format(\"-%s\", getClass().getName());",
" String.format(\"%s-\", getClass().getName());",
" String.format(\"-%s-\", getClass().getName());",
" // BUG: Diagnostic matches: join",
" String.format(\"%s%s\", getClass().getName(), getClass().getName());",
" // BUG: Diagnostic matches: join",
" String.format(\"%s%s\", getClass().getName(), hashCode());",
" // BUG: Diagnostic matches: join",
" String.format(\"%s%s\", hashCode(), getClass().getName());",
" String.format(\"%s%s\", getClass().getName(), (Formattable) null);",
" String.format(\"%s%s\", (Formattable) null, getClass().getName());",
" String.format(\"%s%s\", getClass().getName());",
" // BUG: Diagnostic matches: join",
" String.format(\"%s-%s\", getClass().getName(), getClass().getName());",
" // BUG: Diagnostic matches: join",
" String.format(\"%saa%s\", getClass().getName(), getClass().getName());",
" String.format(\"%s%%%s\", getClass().getName(), getClass().getName());",
" // BUG: Diagnostic matches: join",
" String.format(\"%s_%s_%s\", getClass().getName(), getClass().getName(), getClass().getName());",
" String.format(\"%s_%s_%s\", getClass().getName(), getClass().getName());",
" String.format(\"%s_%s-%s\", getClass().getName(), getClass().getName(), getClass().getName());",
" }",
"}")
.doTest();
}
@Test
void replacement() {
refactoringTestHelper
.addInputLines(
"A.java",
"class A {",
" void m() {",
" String.format(\"%s\", getClass().getName());",
" String.format(\"%s%s\", getClass().getName(), getClass().getName());",
" String.format(\"%s%s\", getClass().getName(), hashCode());",
" String.format(\"%s%s\", hashCode(), getClass().getName());",
" String.format(\"%s-%s\", getClass().getName(), getClass().getName());",
" String.format(\"%saa%s\", getClass().getName(), getClass().getName());",
" String.format(\"%s\\\"%s\", getClass().getName(), getClass().getName());",
" String.format(\"%s_%s_%s\", getClass().getName(), getClass().getName(), getClass().getName());",
" }",
"}")
.addOutputLines(
"A.java",
"class A {",
" void m() {",
" String.valueOf(getClass().getName());",
" String.join(\"\", getClass().getName(), getClass().getName());",
" String.join(\"\", getClass().getName(), String.valueOf(hashCode()));",
" String.join(\"\", String.valueOf(hashCode()), getClass().getName());",
" String.join(\"-\", getClass().getName(), getClass().getName());",
" String.join(\"aa\", getClass().getName(), getClass().getName());",
" String.join(\"\\\"\", getClass().getName(), getClass().getName());",
" String.join(\"_\", getClass().getName(), getClass().getName(), getClass().getName());",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -0,0 +1,83 @@
package tech.picnic.errorprone.refasterrules;
import static java.util.function.Predicate.not;
import com.google.common.collect.ImmutableSet;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollection;
final class RefasterRulesTest {
/** The names of all Refaster rule groups defined in this module. */
private static final ImmutableSet<Class<?>> RULE_COLLECTIONS =
ImmutableSet.of(
AssertJRules.class,
AssertJBigDecimalRules.class,
AssertJBigIntegerRules.class,
AssertJBooleanRules.class,
AssertJByteRules.class,
AssertJCharSequenceRules.class,
AssertJComparableRules.class,
AssertJDoubleRules.class,
AssertJEnumerableRules.class,
AssertJFloatRules.class,
AssertJIntegerRules.class,
AssertJLongRules.class,
AssertJNumberRules.class,
AssertJMapRules.class,
AssertJObjectRules.class,
AssertJOptionalRules.class,
AssertJPrimitiveRules.class,
AssertJShortRules.class,
AssertJStringRules.class,
AssertJThrowingCallableRules.class,
AssortedRules.class,
BigDecimalRules.class,
CollectionRules.class,
ComparatorRules.class,
DoubleStreamRules.class,
EqualityRules.class,
ImmutableListRules.class,
ImmutableListMultimapRules.class,
ImmutableMapRules.class,
ImmutableMultisetRules.class,
ImmutableSetRules.class,
ImmutableSetMultimapRules.class,
ImmutableSortedMapRules.class,
ImmutableSortedMultisetRules.class,
ImmutableSortedSetRules.class,
IntStreamRules.class,
JUnitRules.class,
LongStreamRules.class,
MapEntryRules.class,
MockitoRules.class,
MultimapRules.class,
NullRules.class,
OptionalRules.class,
PrimitiveRules.class,
ReactorRules.class,
RxJava2AdapterRules.class,
StreamRules.class,
StringRules.class,
TestNGToAssertJRules.class,
TimeRules.class,
WebClientRules.class);
// XXX: Create a JUnit extension to automatically discover the rule collections in a given context
// to make sure the list is exhaustive.
private static Stream<Arguments> validateRuleCollectionTestCases() {
// XXX: Drop the filter once we have added tests for AssertJ! We can then also replace this
// method with `@ValueSource(classes = {...})`.
return RULE_COLLECTIONS.stream()
.filter(not(AssertJRules.class::equals))
.map(Arguments::arguments);
}
@MethodSource("validateRuleCollectionTestCases")
@ParameterizedTest
void validateRuleCollection(Class<?> clazz) {
RefasterRuleCollection.validate(clazz);
}
}

View File

@@ -1,83 +0,0 @@
package tech.picnic.errorprone.refastertemplates;
import static java.util.function.Predicate.not;
import com.google.common.collect.ImmutableSet;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import tech.picnic.errorprone.refaster.test.RefasterTemplateCollection;
final class RefasterTemplatesTest {
/** The names of all Refaster template groups defined in this module. */
private static final ImmutableSet<Class<?>> TEMPLATE_COLLECTIONS =
ImmutableSet.of(
AssertJTemplates.class,
AssertJBigDecimalTemplates.class,
AssertJBigIntegerTemplates.class,
AssertJBooleanTemplates.class,
AssertJByteTemplates.class,
AssertJCharSequenceTemplates.class,
AssertJComparableTemplates.class,
AssertJDoubleTemplates.class,
AssertJEnumerableTemplates.class,
AssertJFloatTemplates.class,
AssertJIntegerTemplates.class,
AssertJLongTemplates.class,
AssertJNumberTemplates.class,
AssertJMapTemplates.class,
AssertJObjectTemplates.class,
AssertJOptionalTemplates.class,
AssertJPrimitiveTemplates.class,
AssertJShortTemplates.class,
AssertJStringTemplates.class,
AssertJThrowingCallableTemplates.class,
AssortedTemplates.class,
BigDecimalTemplates.class,
CollectionTemplates.class,
ComparatorTemplates.class,
DoubleStreamTemplates.class,
EqualityTemplates.class,
ImmutableListTemplates.class,
ImmutableListMultimapTemplates.class,
ImmutableMapTemplates.class,
ImmutableMultisetTemplates.class,
ImmutableSetTemplates.class,
ImmutableSetMultimapTemplates.class,
ImmutableSortedMapTemplates.class,
ImmutableSortedMultisetTemplates.class,
ImmutableSortedSetTemplates.class,
IntStreamTemplates.class,
JUnitTemplates.class,
LongStreamTemplates.class,
MapEntryTemplates.class,
MockitoTemplates.class,
MultimapTemplates.class,
NullTemplates.class,
OptionalTemplates.class,
PrimitiveTemplates.class,
ReactorTemplates.class,
RxJava2AdapterTemplates.class,
StreamTemplates.class,
StringTemplates.class,
TestNGToAssertJTemplates.class,
TimeTemplates.class,
WebClientTemplates.class);
// XXX: Create a JUnit extension to automatically discover the template collections in a given
// context to make sure the list is exhaustive.
private static Stream<Arguments> validateTemplateCollectionTestCases() {
// XXX: Drop the filter once we have added tests for AssertJ! We can then also replace this
// method with `@ValueSource(classes = {...})`.
return TEMPLATE_COLLECTIONS.stream()
.filter(not(AssertJTemplates.class::equals))
.map(Arguments::arguments);
}
@MethodSource("validateTemplateCollectionTestCases")
@ParameterizedTest
void validateTemplateCollection(Class<?> clazz) {
RefasterTemplateCollection.validate(clazz);
}
}

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates.input;
package tech.picnic.errorprone.refasterrules.input;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.Offset.offset;
@@ -7,9 +7,9 @@ import static org.assertj.core.data.Percentage.withPercentage;
import com.google.common.collect.ImmutableSet;
import java.math.BigDecimal;
import org.assertj.core.api.AbstractBigDecimalAssert;
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJBigDecimalTemplatesTest implements RefasterTemplateTestCase {
final class AssertJBigDecimalRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
return ImmutableSet.of(offset(0), withPercentage(0));

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates.input;
package tech.picnic.errorprone.refasterrules.input;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.Offset.offset;
@@ -7,9 +7,9 @@ import static org.assertj.core.data.Percentage.withPercentage;
import com.google.common.collect.ImmutableSet;
import java.math.BigInteger;
import org.assertj.core.api.AbstractBigIntegerAssert;
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJBigIntegerTemplatesTest implements RefasterTemplateTestCase {
final class AssertJBigIntegerRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
return ImmutableSet.of(offset(0), withPercentage(0));

View File

@@ -1,12 +1,12 @@
package tech.picnic.errorprone.refastertemplates.input;
package tech.picnic.errorprone.refasterrules.input;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableSet;
import org.assertj.core.api.AbstractBooleanAssert;
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJBooleanTemplatesTest implements RefasterTemplateTestCase {
final class AssertJBooleanRulesTest implements RefasterRuleCollectionTestCase {
AbstractBooleanAssert<?> testAbstractBooleanAssertIsEqualTo() {
return assertThat(true).isNotEqualTo(!Boolean.FALSE);
}

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates.input;
package tech.picnic.errorprone.refasterrules.input;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.Offset.offset;
@@ -6,9 +6,9 @@ import static org.assertj.core.data.Percentage.withPercentage;
import com.google.common.collect.ImmutableSet;
import org.assertj.core.api.AbstractByteAssert;
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJByteTemplatesTest implements RefasterTemplateTestCase {
final class AssertJByteRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
return ImmutableSet.of(offset(0), withPercentage(0));

View File

@@ -1,12 +1,12 @@
package tech.picnic.errorprone.refastertemplates.input;
package tech.picnic.errorprone.refasterrules.input;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableSet;
import org.assertj.core.api.AbstractAssert;
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJCharSequenceTemplatesTest implements RefasterTemplateTestCase {
final class AssertJCharSequenceRulesTest implements RefasterRuleCollectionTestCase {
void testAssertThatCharSequenceIsEmpty() {
assertThat("foo".length()).isEqualTo(0L);
assertThat("foo".length()).isNotPositive();

View File

@@ -1,12 +1,12 @@
package tech.picnic.errorprone.refastertemplates.input;
package tech.picnic.errorprone.refasterrules.input;
import static org.assertj.core.api.Assertions.assertThat;
import java.math.BigDecimal;
import org.assertj.core.api.AbstractComparableAssert;
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJComparableTemplatesTest implements RefasterTemplateTestCase {
final class AssertJComparableRulesTest implements RefasterRuleCollectionTestCase {
AbstractComparableAssert<?, ?> testAssertThatIsEqualByComparingTo() {
return assertThat(BigDecimal.ZERO.compareTo(BigDecimal.ONE)).isEqualTo(0);
}

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates.input;
package tech.picnic.errorprone.refasterrules.input;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.Offset.offset;
@@ -6,9 +6,9 @@ import static org.assertj.core.data.Percentage.withPercentage;
import com.google.common.collect.ImmutableSet;
import org.assertj.core.api.AbstractDoubleAssert;
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJDoubleTemplatesTest implements RefasterTemplateTestCase {
final class AssertJDoubleRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
return ImmutableSet.of(withPercentage(0));

View File

@@ -1,13 +1,13 @@
package tech.picnic.errorprone.refastertemplates.input;
package tech.picnic.errorprone.refasterrules.input;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import org.assertj.core.api.EnumerableAssert;
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJEnumerableTemplatesTest implements RefasterTemplateTestCase {
final class AssertJEnumerableRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
return ImmutableSet.of(Iterables.class);

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates.input;
package tech.picnic.errorprone.refasterrules.input;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.Offset.offset;
@@ -6,9 +6,9 @@ import static org.assertj.core.data.Percentage.withPercentage;
import com.google.common.collect.ImmutableSet;
import org.assertj.core.api.AbstractFloatAssert;
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJFloatTemplatesTest implements RefasterTemplateTestCase {
final class AssertJFloatRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
return ImmutableSet.of(withPercentage(0));

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.refastertemplates.input;
package tech.picnic.errorprone.refasterrules.input;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.Offset.offset;
@@ -6,9 +6,9 @@ import static org.assertj.core.data.Percentage.withPercentage;
import com.google.common.collect.ImmutableSet;
import org.assertj.core.api.AbstractIntegerAssert;
import tech.picnic.errorprone.refaster.test.RefasterTemplateTestCase;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJIntegerTemplatesTest implements RefasterTemplateTestCase {
final class AssertJIntegerRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
return ImmutableSet.of(offset(0), withPercentage(0));

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