mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
Compare commits
70 Commits
sschroever
...
gdejong/ju
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a9ce49075 | ||
|
|
80a312a829 | ||
|
|
f0ff5c3fd6 | ||
|
|
738a6706fd | ||
|
|
fd97ac3676 | ||
|
|
5b011312e1 | ||
|
|
ff3f963820 | ||
|
|
94edab3b4f | ||
|
|
276529fd34 | ||
|
|
f5022efe68 | ||
|
|
49e7313e1c | ||
|
|
b3462b0a1e | ||
|
|
a5b71410ae | ||
|
|
6b73f03b22 | ||
|
|
5d120252ac | ||
|
|
351b886e6c | ||
|
|
ad5dd92b9a | ||
|
|
e9a5295e80 | ||
|
|
7ae9356c9e | ||
|
|
5618de49f4 | ||
|
|
17c7b396d2 | ||
|
|
eafb73814a | ||
|
|
7793006b5e | ||
|
|
7733ceaaec | ||
|
|
53e0a0cb41 | ||
|
|
1d25b78c4c | ||
|
|
b70da48d70 | ||
|
|
01fd608aac | ||
|
|
dd0369a645 | ||
|
|
74b1104890 | ||
|
|
a230bbff12 | ||
|
|
100305ed1f | ||
|
|
96c836e6a9 | ||
|
|
97acfbc3bc | ||
|
|
9ce7c6b40b | ||
|
|
57a43a1c85 | ||
|
|
89c4969a31 | ||
|
|
dbd4853e3e | ||
|
|
62a7dacf4d | ||
|
|
d23684ee6d | ||
|
|
fd150af6c6 | ||
|
|
a1a865b87a | ||
|
|
64000ebb07 | ||
|
|
6122d7a39f | ||
|
|
ca01bbb74a | ||
|
|
4ce9f92489 | ||
|
|
e8d14993a1 | ||
|
|
88860800b1 | ||
|
|
e76dd5c31b | ||
|
|
701db7d61e | ||
|
|
8781a9ede5 | ||
|
|
dc14c4e970 | ||
|
|
a435b657ae | ||
|
|
00edc5ea1f | ||
|
|
7383a11da7 | ||
|
|
e4e17664d0 | ||
|
|
5972a8e225 | ||
|
|
01b30d767b | ||
|
|
c2426d3a8d | ||
|
|
8130ddf59c | ||
|
|
c3b950f114 | ||
|
|
fa026de336 | ||
|
|
2ff3095fca | ||
|
|
2b2d9f498e | ||
|
|
2a5dd7d56d | ||
|
|
dd021b3757 | ||
|
|
c77cc9a35d | ||
|
|
7a7a09d208 | ||
|
|
62077dacbb | ||
|
|
3a76f91d18 |
@@ -31,11 +31,11 @@ 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@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
|
||||
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
|
||||
with:
|
||||
java-version: ${{ matrix.jdk }}
|
||||
distribution: ${{ matrix.distribution }}
|
||||
10
.github/workflows/codeql.yml
vendored
10
.github/workflows/codeql.yml
vendored
@@ -22,23 +22,23 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
|
||||
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
|
||||
with:
|
||||
java-version: 17.0.8
|
||||
distribution: temurin
|
||||
cache: maven
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@2cb752a87e96af96708ab57187ab6372ee1973ab # v2.22.0
|
||||
uses: github/codeql-action/init@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Perform minimal build
|
||||
if: matrix.language == 'java'
|
||||
run: mvn -T1C clean install -DskipTests -Dverification.skip
|
||||
run: mvn -T1C clean package -DskipTests -Dverification.skip
|
||||
- name: Perform CodeQL analysis
|
||||
uses: github/codeql-action/analyze@2cb752a87e96af96708ab57187ab6372ee1973ab # v2.22.0
|
||||
uses: github/codeql-action/analyze@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8
|
||||
with:
|
||||
category: /language:${{ matrix.language }}
|
||||
|
||||
@@ -12,15 +12,15 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ruby/setup-ruby@d37167af451eb51448db3354e1057b75c4b268f7 # v1.155.0
|
||||
- uses: ruby/setup-ruby@8575951200e472d5f2d95c625da0c7bec8217c42 # v1.161.0
|
||||
with:
|
||||
working-directory: ./website
|
||||
bundler-cache: true
|
||||
- name: Configure Github Pages
|
||||
uses: actions/configure-pages@f156874f8191504dae5b037505266ed5dda6c382 # v3.0.6
|
||||
uses: actions/configure-pages@1f0c5cde4bc74cd7e1254d0cb4de8d49e9068c7d # v4.0.0
|
||||
- name: Generate documentation
|
||||
run: ./generate-docs.sh
|
||||
- name: Build website with Jekyll
|
||||
@@ -48,4 +48,4 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@9dbe3824824f8a1377b8e298bafde1a50ede43e5 # v2.0.4
|
||||
uses: actions/deploy-pages@13b55b33dd8996121833dbc1db458c793a334630 # v3.0.1
|
||||
6
.github/workflows/openssf-scorecard.yml
vendored
6
.github/workflows/openssf-scorecard.yml
vendored
@@ -21,16 +21,16 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run OpenSSF Scorecard analysis
|
||||
uses: ossf/scorecard-action@483ef80eb98fb506c348f7d62e28055e49fe2398 # v2.3.0
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
publish_results: ${{ github.ref == 'refs/heads/master' }}
|
||||
- name: Update GitHub's code scanning dashboard
|
||||
uses: github/codeql-action/upload-sarif@2cb752a87e96af96708ab57187ab6372ee1973ab # v2.22.0
|
||||
uses: github/codeql-action/upload-sarif@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
4
.github/workflows/pitest-analyze-pr.yml
vendored
4
.github/workflows/pitest-analyze-pr.yml
vendored
@@ -12,12 +12,12 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
fetch-depth: 2
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
|
||||
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
|
||||
with:
|
||||
java-version: 17.0.8
|
||||
distribution: temurin
|
||||
|
||||
6
.github/workflows/pitest-update-pr.yml
vendored
6
.github/workflows/pitest-update-pr.yml
vendored
@@ -20,17 +20,17 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
|
||||
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
|
||||
with:
|
||||
java-version: 17.0.8
|
||||
distribution: temurin
|
||||
cache: maven
|
||||
- name: Download Pitest analysis artifact
|
||||
uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e # v2.28.0
|
||||
uses: dawidd6/action-download-artifact@f29d1b6a8930683e80acedfbe6baa2930cd646b4 # v2.28.1
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
name: pitest-reports
|
||||
|
||||
43
.github/workflows/run-integration-tests.yml
vendored
Normal file
43
.github/workflows/run-integration-tests.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# If requested by means of a pull request comment, runs integration tests
|
||||
# against the project, using the code found on the pull request branch.
|
||||
# XXX: Generalize this to a matrix build of multiple integration tests,
|
||||
# possibly using multiple JDK or OS versions.
|
||||
# XXX: Investigate whether the comment can specify which integration tests run
|
||||
# run. See this example of a dynamic build matrix:
|
||||
# https://docs.github.com/en/actions/learn-github-actions/expressions#example-returning-a-json-object
|
||||
name: "Integration tests"
|
||||
on:
|
||||
issue_comment:
|
||||
types: [ created ]
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
run-integration-tests:
|
||||
name: On-demand integration test
|
||||
if: |
|
||||
github.event.issue.pull_request && contains(github.event.comment.body, '/integration-test')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: refs/pull/${{ github.event.issue.number }}/head
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
|
||||
with:
|
||||
java-version: 17.0.8
|
||||
distribution: temurin
|
||||
cache: maven
|
||||
- name: Install project to local Maven repository
|
||||
run: mvn -T1C install -DskipTests -Dverification.skip
|
||||
- name: Run integration test
|
||||
run: xvfb-run ./integration-tests/checkstyle-10.12.4.sh "${{ runner.temp }}/artifacts"
|
||||
- name: Upload artifacts on failure
|
||||
if: ${{ failure() }}
|
||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
||||
with:
|
||||
name: integration-test-checkstyle-10.12.4
|
||||
path: "${{ runner.temp }}/artifacts"
|
||||
- name: Remove installed project artifacts
|
||||
run: mvn build-helper:remove-project-artifact
|
||||
4
.github/workflows/sonarcloud.yml
vendored
4
.github/workflows/sonarcloud.yml
vendored
@@ -16,12 +16,12 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
|
||||
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
|
||||
with:
|
||||
java-version: 17.0.8
|
||||
distribution: temurin
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -9,3 +9,6 @@
|
||||
target
|
||||
*.iml
|
||||
*.swp
|
||||
|
||||
# The Git repositories checked out by the integration test framework.
|
||||
integration-tests/.repos
|
||||
|
||||
13
README.md
13
README.md
@@ -15,9 +15,11 @@ 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].
|
||||
To learn more about Error Prone (Support), how you can start using Error Prone
|
||||
in practice, and how we use it at Picnic, watch the conference talk
|
||||
[_Automating away bugs with Error Prone in practice_][conference-talk]. Also
|
||||
consider checking out 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]
|
||||
[![Reproducible Builds][reproducible-builds-badge]][reproducible-builds-report]
|
||||
@@ -265,6 +267,7 @@ channel; please see our [security policy][security] for details.
|
||||
[bug-checks-identity-conversion]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/IdentityConversion.java
|
||||
[codeql-badge]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/codeql.yml/badge.svg?branch=master&event=push
|
||||
[codeql-master]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/codeql.yml?query=branch:master+event:push
|
||||
[conference-talk]: https://www.youtube.com/watch?v=-47WD-3wKBs
|
||||
[contributing]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/CONTRIBUTING.md
|
||||
[contributing-pull-request]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/CONTRIBUTING.md#-opening-a-pull-request
|
||||
[error-prone-bugchecker]: https://github.com/google/error-prone/blob/master/check_api/src/main/java/com/google/errorprone/bugpatterns/BugChecker.java
|
||||
@@ -274,8 +277,8 @@ channel; please see our [security policy][security] for details.
|
||||
[error-prone-installation-guide]: https://errorprone.info/docs/installation#maven
|
||||
[error-prone-orig-repo]: https://github.com/google/error-prone
|
||||
[error-prone-pull-3301]: https://github.com/google/error-prone/pull/3301
|
||||
[github-actions-build-badge]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yaml/badge.svg
|
||||
[github-actions-build-master]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yaml?query=branch:master&event=push
|
||||
[github-actions-build-badge]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yml/badge.svg
|
||||
[github-actions-build-master]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yml?query=branch:master&event=push
|
||||
[google-java-format]: https://github.com/google/google-java-format
|
||||
[idea-288052]: https://youtrack.jetbrains.com/issue/IDEA-288052
|
||||
[license-badge]: https://img.shields.io/github/license/PicnicSupermarket/error-prone-support
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Arcmutate license for Error Prone Support, requested by sending an email to
|
||||
# support@arcmutate.com.
|
||||
expires=07/11/2023
|
||||
expires=27/10/2025
|
||||
keyVersion=1
|
||||
signature=MhZxMbnO6UovNfllM0JuVWkZyvRT3/G5o/uT0Mm36c7200VpZNVu03gTAGivnl9W5RzvZhfpIHccuQ5ctjQkrqhsFSrl4fyqPqu3y5V2fsHIdFXP/G72EGj6Kay9ndLpaEHalqE0bEwxdnHMzEYq5y3O9vUPv8MhUl57xk+rvBo\=
|
||||
signature=aQLVt0J//7nXDAlJuBe9ru7Dq6oApcLh17rxsgHoJqBkUCd2zvrtRxkcPm5PmF1I8gBDT9PHb+kTf6Kcfz+D1fT0wRrZv38ip56521AQPD6zjRSqak9O2Gisjo+QTPMD7oS009aSWKzQ1SMdtuZ+KIRvw4Gl+frtYzexqnGWEUQ\=
|
||||
packages=tech.picnic.errorprone.*
|
||||
type=OSSS
|
||||
|
||||
@@ -5,17 +5,19 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import com.google.auto.common.AnnotationMirrors;
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.BugPattern.SeverityLevel;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.tools.javac.code.Attribute;
|
||||
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import java.util.Optional;
|
||||
import javax.lang.model.element.AnnotationValue;
|
||||
import tech.picnic.errorprone.documentation.BugPatternExtractor.BugPatternDocumentation;
|
||||
|
||||
@@ -23,29 +25,39 @@ import tech.picnic.errorprone.documentation.BugPatternExtractor.BugPatternDocume
|
||||
* An {@link Extractor} that describes how to extract data from a {@code @BugPattern} annotation.
|
||||
*/
|
||||
@Immutable
|
||||
final class BugPatternExtractor implements Extractor<BugPatternDocumentation> {
|
||||
@Override
|
||||
public BugPatternDocumentation extract(ClassTree tree, Context context) {
|
||||
ClassSymbol symbol = ASTHelpers.getSymbol(tree);
|
||||
BugPattern annotation = symbol.getAnnotation(BugPattern.class);
|
||||
requireNonNull(annotation, "BugPattern annotation must be present");
|
||||
@AutoService(Extractor.class)
|
||||
@SuppressWarnings("rawtypes" /* See https://github.com/google/auto/issues/870. */)
|
||||
public final class BugPatternExtractor implements Extractor<BugPatternDocumentation> {
|
||||
/** Instantiates a new {@link BugPatternExtractor} instance. */
|
||||
public BugPatternExtractor() {}
|
||||
|
||||
return new AutoValue_BugPatternExtractor_BugPatternDocumentation(
|
||||
symbol.getQualifiedName().toString(),
|
||||
annotation.name().isEmpty() ? tree.getSimpleName().toString() : annotation.name(),
|
||||
ImmutableList.copyOf(annotation.altNames()),
|
||||
annotation.link(),
|
||||
ImmutableList.copyOf(annotation.tags()),
|
||||
annotation.summary(),
|
||||
annotation.explanation(),
|
||||
annotation.severity(),
|
||||
annotation.disableable(),
|
||||
annotation.documentSuppression() ? getSuppressionAnnotations(tree) : ImmutableList.of());
|
||||
@Override
|
||||
public String identifier() {
|
||||
return "bugpattern";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExtract(ClassTree tree) {
|
||||
return ASTHelpers.hasDirectAnnotationWithSimpleName(tree, BugPattern.class.getSimpleName());
|
||||
public Optional<BugPatternDocumentation> tryExtract(ClassTree tree, VisitorState state) {
|
||||
ClassSymbol symbol = ASTHelpers.getSymbol(tree);
|
||||
BugPattern annotation = symbol.getAnnotation(BugPattern.class);
|
||||
if (annotation == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(
|
||||
new AutoValue_BugPatternExtractor_BugPatternDocumentation(
|
||||
symbol.getQualifiedName().toString(),
|
||||
annotation.name().isEmpty() ? tree.getSimpleName().toString() : annotation.name(),
|
||||
ImmutableList.copyOf(annotation.altNames()),
|
||||
annotation.link(),
|
||||
ImmutableList.copyOf(annotation.tags()),
|
||||
annotation.summary(),
|
||||
annotation.explanation(),
|
||||
annotation.severity(),
|
||||
annotation.disableable(),
|
||||
annotation.documentSuppression()
|
||||
? getSuppressionAnnotations(tree)
|
||||
: ImmutableList.of()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
package tech.picnic.errorprone.documentation;
|
||||
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.TestCases;
|
||||
|
||||
/**
|
||||
* An {@link Extractor} that describes how to extract data from classes that test a {@code
|
||||
* BugChecker}.
|
||||
*/
|
||||
// XXX: Handle other methods from `{BugCheckerRefactoring,Compilation}TestHelper`:
|
||||
// - Indicate which custom arguments are specified, if any.
|
||||
// - For replacement tests, indicate which `FixChooser` is used.
|
||||
// - ... (We don't use all optional features; TBD what else to support.)
|
||||
@Immutable
|
||||
@AutoService(Extractor.class)
|
||||
@SuppressWarnings("rawtypes" /* See https://github.com/google/auto/issues/870. */)
|
||||
public final class BugPatternTestExtractor implements Extractor<TestCases> {
|
||||
/** Instantiates a new {@link BugPatternTestExtractor} instance. */
|
||||
public BugPatternTestExtractor() {}
|
||||
|
||||
@Override
|
||||
public String identifier() {
|
||||
return "bugpattern-test";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TestCases> tryExtract(ClassTree tree, VisitorState state) {
|
||||
BugPatternTestCollector collector = new BugPatternTestCollector();
|
||||
|
||||
collector.scan(tree, state);
|
||||
|
||||
return Optional.of(collector.getCollectedTests())
|
||||
.filter(not(ImmutableList::isEmpty))
|
||||
.map(
|
||||
tests ->
|
||||
new AutoValue_BugPatternTestExtractor_TestCases(
|
||||
ASTHelpers.getSymbol(tree).className(), tests));
|
||||
}
|
||||
|
||||
private static final class BugPatternTestCollector
|
||||
extends TreeScanner<@Nullable Void, VisitorState> {
|
||||
private static final Matcher<ExpressionTree> COMPILATION_HELPER_DO_TEST =
|
||||
instanceMethod()
|
||||
.onDescendantOf("com.google.errorprone.CompilationTestHelper")
|
||||
.named("doTest");
|
||||
private static final Matcher<ExpressionTree> TEST_HELPER_NEW_INSTANCE =
|
||||
staticMethod()
|
||||
.onDescendantOfAny(
|
||||
"com.google.errorprone.CompilationTestHelper",
|
||||
"com.google.errorprone.BugCheckerRefactoringTestHelper")
|
||||
.named("newInstance")
|
||||
.withParameters("java.lang.Class", "java.lang.Class");
|
||||
private static final Matcher<ExpressionTree> IDENTIFICATION_SOURCE_LINES =
|
||||
instanceMethod()
|
||||
.onDescendantOf("com.google.errorprone.CompilationTestHelper")
|
||||
.named("addSourceLines");
|
||||
private static final Matcher<ExpressionTree> REPLACEMENT_DO_TEST =
|
||||
instanceMethod()
|
||||
.onDescendantOf("com.google.errorprone.BugCheckerRefactoringTestHelper")
|
||||
.named("doTest");
|
||||
private static final Matcher<ExpressionTree> REPLACEMENT_EXPECT_UNCHANGED =
|
||||
instanceMethod()
|
||||
.onDescendantOf("com.google.errorprone.BugCheckerRefactoringTestHelper.ExpectOutput")
|
||||
.named("expectUnchanged");
|
||||
private static final Matcher<ExpressionTree> REPLACEMENT_OUTPUT_SOURCE_LINES =
|
||||
instanceMethod()
|
||||
.onDescendantOf("com.google.errorprone.BugCheckerRefactoringTestHelper.ExpectOutput")
|
||||
.namedAnyOf("addOutputLines", "expectUnchanged");
|
||||
|
||||
private final List<TestCase> collectedTestCases = new ArrayList<>();
|
||||
|
||||
private ImmutableList<TestCase> getCollectedTests() {
|
||||
return ImmutableList.copyOf(collectedTestCases);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitMethodInvocation(MethodInvocationTree node, VisitorState state) {
|
||||
boolean isReplacementTest = REPLACEMENT_DO_TEST.matches(node, state);
|
||||
if (isReplacementTest || COMPILATION_HELPER_DO_TEST.matches(node, state)) {
|
||||
getClassUnderTest(node, state)
|
||||
.ifPresent(
|
||||
classUnderTest -> {
|
||||
List<TestEntry> entries = new ArrayList<>();
|
||||
if (isReplacementTest) {
|
||||
extractReplacementTestCases(node, entries, state);
|
||||
} else {
|
||||
extractIdentificationTestCases(node, entries, state);
|
||||
}
|
||||
|
||||
if (!entries.isEmpty()) {
|
||||
collectedTestCases.add(
|
||||
new AutoValue_BugPatternTestExtractor_TestCase(
|
||||
classUnderTest, ImmutableList.copyOf(entries).reverse()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return super.visitMethodInvocation(node, state);
|
||||
}
|
||||
|
||||
private static Optional<String> getClassUnderTest(
|
||||
MethodInvocationTree tree, VisitorState state) {
|
||||
if (TEST_HELPER_NEW_INSTANCE.matches(tree, state)) {
|
||||
return Optional.ofNullable(ASTHelpers.getSymbol(tree.getArguments().get(0)))
|
||||
.filter(s -> !s.type.allparams().isEmpty())
|
||||
.map(s -> s.type.allparams().get(0).tsym.getQualifiedName().toString());
|
||||
}
|
||||
|
||||
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
|
||||
return receiver instanceof MethodInvocationTree
|
||||
? getClassUnderTest((MethodInvocationTree) receiver, state)
|
||||
: Optional.empty();
|
||||
}
|
||||
|
||||
private static void extractIdentificationTestCases(
|
||||
MethodInvocationTree tree, List<TestEntry> sink, VisitorState state) {
|
||||
if (IDENTIFICATION_SOURCE_LINES.matches(tree, state)) {
|
||||
String path = ASTHelpers.constValue(tree.getArguments().get(0), String.class);
|
||||
Optional<String> sourceCode =
|
||||
getSourceCode(tree).filter(s -> s.contains("// BUG: Diagnostic"));
|
||||
if (path != null && sourceCode.isPresent()) {
|
||||
sink.add(
|
||||
new AutoValue_BugPatternTestExtractor_IdentificationTestEntry(
|
||||
path, sourceCode.orElseThrow()));
|
||||
}
|
||||
}
|
||||
|
||||
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
|
||||
if (receiver instanceof MethodInvocationTree) {
|
||||
extractIdentificationTestCases((MethodInvocationTree) receiver, sink, state);
|
||||
}
|
||||
}
|
||||
|
||||
private static void extractReplacementTestCases(
|
||||
MethodInvocationTree tree, List<TestEntry> sink, VisitorState state) {
|
||||
if (REPLACEMENT_OUTPUT_SOURCE_LINES.matches(tree, state)) {
|
||||
/*
|
||||
* Retrieve the method invocation that contains the input source code. Note that this cast
|
||||
* is safe, because this code is guarded by an earlier call to `#getClassUnderTest(..)`,
|
||||
* which ensures that `tree` is part of a longer method invocation chain.
|
||||
*/
|
||||
MethodInvocationTree inputTree = (MethodInvocationTree) ASTHelpers.getReceiver(tree);
|
||||
|
||||
String path = ASTHelpers.constValue(inputTree.getArguments().get(0), String.class);
|
||||
Optional<String> inputCode = getSourceCode(inputTree);
|
||||
if (path != null && inputCode.isPresent()) {
|
||||
Optional<String> outputCode =
|
||||
REPLACEMENT_EXPECT_UNCHANGED.matches(tree, state) ? inputCode : getSourceCode(tree);
|
||||
|
||||
if (outputCode.isPresent() && !inputCode.equals(outputCode)) {
|
||||
sink.add(
|
||||
new AutoValue_BugPatternTestExtractor_ReplacementTestEntry(
|
||||
path, inputCode.orElseThrow(), outputCode.orElseThrow()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
|
||||
if (receiver instanceof MethodInvocationTree) {
|
||||
extractReplacementTestCases((MethodInvocationTree) receiver, sink, state);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: This logic is duplicated in `ErrorProneTestSourceFormat`. Can we do better?
|
||||
private static Optional<String> getSourceCode(MethodInvocationTree tree) {
|
||||
List<? extends ExpressionTree> sourceLines =
|
||||
tree.getArguments().subList(1, tree.getArguments().size());
|
||||
StringBuilder source = new StringBuilder();
|
||||
|
||||
for (ExpressionTree sourceLine : sourceLines) {
|
||||
String value = ASTHelpers.constValue(sourceLine, String.class);
|
||||
if (value == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
source.append(value).append('\n');
|
||||
}
|
||||
|
||||
return Optional.of(source.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class TestCases {
|
||||
abstract String testClass();
|
||||
|
||||
abstract ImmutableList<TestCase> testCases();
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class TestCase {
|
||||
abstract String classUnderTest();
|
||||
|
||||
abstract ImmutableList<TestEntry> entries();
|
||||
}
|
||||
|
||||
interface TestEntry {
|
||||
String path();
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class ReplacementTestEntry implements TestEntry {
|
||||
abstract String input();
|
||||
|
||||
abstract String output();
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class IdentificationTestEntry implements TestEntry {
|
||||
abstract String code();
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,14 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.util.TaskEvent;
|
||||
import com.sun.source.util.TaskEvent.Kind;
|
||||
import com.sun.source.util.TaskListener;
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.tools.javac.api.JavacTrees;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import java.io.File;
|
||||
@@ -19,6 +23,7 @@ import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ServiceLoader;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
/**
|
||||
@@ -27,6 +32,13 @@ import javax.tools.JavaFileObject;
|
||||
*/
|
||||
// XXX: Find a better name for this class; it doesn't generate documentation per se.
|
||||
final class DocumentationGeneratorTaskListener implements TaskListener {
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private static final ImmutableList<Extractor<?>> EXTRACTORS =
|
||||
(ImmutableList)
|
||||
ImmutableList.copyOf(
|
||||
ServiceLoader.load(
|
||||
Extractor.class, DocumentationGeneratorTaskListener.class.getClassLoader()));
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER =
|
||||
new ObjectMapper().setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
|
||||
|
||||
@@ -51,19 +63,25 @@ final class DocumentationGeneratorTaskListener implements TaskListener {
|
||||
return;
|
||||
}
|
||||
|
||||
ClassTree classTree = JavacTrees.instance(context).getTree(taskEvent.getTypeElement());
|
||||
JavaFileObject sourceFile = taskEvent.getSourceFile();
|
||||
if (classTree == null || sourceFile == null) {
|
||||
CompilationUnitTree compilationUnit = taskEvent.getCompilationUnit();
|
||||
ClassTree classTree = JavacTrees.instance(context).getTree(taskEvent.getTypeElement());
|
||||
if (sourceFile == null || compilationUnit == null || classTree == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ExtractorType.findMatchingType(classTree)
|
||||
.ifPresent(
|
||||
extractorType ->
|
||||
writeToFile(
|
||||
extractorType.getIdentifier(),
|
||||
getSimpleClassName(sourceFile.toUri()),
|
||||
extractorType.getExtractor().extract(classTree, context)));
|
||||
VisitorState state =
|
||||
VisitorState.createForUtilityPurposes(context)
|
||||
.withPath(new TreePath(new TreePath(compilationUnit), classTree));
|
||||
|
||||
for (Extractor<?> extractor : EXTRACTORS) {
|
||||
extractor
|
||||
.tryExtract(classTree, state)
|
||||
.ifPresent(
|
||||
data ->
|
||||
writeToFile(
|
||||
extractor.identifier(), getSimpleClassName(sourceFile.toUri()), data));
|
||||
}
|
||||
}
|
||||
|
||||
private void createDocsDirectory() {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package tech.picnic.errorprone.documentation;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Interface implemented by classes that define how to extract data of some type {@link T} from a
|
||||
@@ -13,21 +14,20 @@ import com.sun.tools.javac.util.Context;
|
||||
@Immutable
|
||||
interface Extractor<T> {
|
||||
/**
|
||||
* Extracts and returns an instance of {@link T} using the provided arguments.
|
||||
* Returns the unique identifier of this extractor.
|
||||
*
|
||||
* @param tree The {@link ClassTree} to analyze and from which to extract instances of {@link T}.
|
||||
* @param context The {@link Context} in which the current compilation takes place.
|
||||
* @return A non-null instance of {@link T}.
|
||||
* @return A non-{@code null} string.
|
||||
*/
|
||||
// XXX: Drop `Context` parameter unless used.
|
||||
T extract(ClassTree tree, Context context);
|
||||
String identifier();
|
||||
|
||||
/**
|
||||
* Tells whether this {@link Extractor} can extract documentation content from the given {@link
|
||||
* ClassTree}.
|
||||
* Attempts to extract an instance of type {@link T} using the provided arguments.
|
||||
*
|
||||
* @param tree The {@link ClassTree} of interest.
|
||||
* @return {@code true} iff data extraction is supported.
|
||||
* @param tree The {@link ClassTree} to analyze and from which to extract an instance of type
|
||||
* {@link T}.
|
||||
* @param state A {@link VisitorState} describing the context in which the given {@link ClassTree}
|
||||
* is found.
|
||||
* @return An instance of type {@link T}, if possible.
|
||||
*/
|
||||
boolean canExtract(ClassTree tree);
|
||||
Optional<T> tryExtract(ClassTree tree, VisitorState state);
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package tech.picnic.errorprone.documentation;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Optional;
|
||||
|
||||
/** An enumeration of {@link Extractor} types. */
|
||||
enum ExtractorType {
|
||||
BUG_PATTERN("bugpattern", new BugPatternExtractor());
|
||||
|
||||
private static final ImmutableSet<ExtractorType> TYPES =
|
||||
Sets.immutableEnumSet(EnumSet.allOf(ExtractorType.class));
|
||||
|
||||
private final String identifier;
|
||||
private final Extractor<?> extractor;
|
||||
|
||||
ExtractorType(String identifier, Extractor<?> extractor) {
|
||||
this.identifier = identifier;
|
||||
this.extractor = extractor;
|
||||
}
|
||||
|
||||
String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
@SuppressWarnings("java:S1452" /* The extractor returns data of an unspecified type. */)
|
||||
Extractor<?> getExtractor() {
|
||||
return extractor;
|
||||
}
|
||||
|
||||
static Optional<ExtractorType> findMatchingType(ClassTree tree) {
|
||||
return TYPES.stream().filter(type -> type.getExtractor().canExtract(tree)).findFirst();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,9 @@
|
||||
package tech.picnic.errorprone.documentation;
|
||||
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import com.google.common.io.Resources;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -45,10 +36,7 @@ final class BugPatternExtractorTest {
|
||||
"@BugPattern(summary = \"MinimalBugChecker summary\", severity = SeverityLevel.ERROR)",
|
||||
"public final class MinimalBugChecker extends BugChecker {}");
|
||||
|
||||
verifyFileMatchesResource(
|
||||
outputDirectory,
|
||||
"bugpattern-MinimalBugChecker.json",
|
||||
"bugpattern-documentation-minimal.json");
|
||||
verifyGeneratedFileContent(outputDirectory, "MinimalBugChecker");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -76,10 +64,7 @@ final class BugPatternExtractorTest {
|
||||
" suppressionAnnotations = {BugPattern.class, Test.class})",
|
||||
"public final class CompleteBugChecker extends BugChecker {}");
|
||||
|
||||
verifyFileMatchesResource(
|
||||
outputDirectory,
|
||||
"bugpattern-CompleteBugChecker.json",
|
||||
"bugpattern-documentation-complete.json");
|
||||
verifyGeneratedFileContent(outputDirectory, "CompleteBugChecker");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -99,55 +84,23 @@ final class BugPatternExtractorTest {
|
||||
" documentSuppression = false)",
|
||||
"public final class UndocumentedSuppressionBugPattern extends BugChecker {}");
|
||||
|
||||
verifyFileMatchesResource(
|
||||
outputDirectory,
|
||||
"bugpattern-UndocumentedSuppressionBugPattern.json",
|
||||
"bugpattern-documentation-undocumented-suppression.json");
|
||||
verifyGeneratedFileContent(outputDirectory, "UndocumentedSuppressionBugPattern");
|
||||
}
|
||||
|
||||
@Test
|
||||
void bugPatternAnnotationIsAbsent() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"TestChecker.java",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"// BUG: Diagnostic contains: Can extract: false",
|
||||
"public final class TestChecker extends BugChecker {}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
private static void verifyFileMatchesResource(
|
||||
Path outputDirectory, String fileName, String resourceName) throws IOException {
|
||||
assertThat(outputDirectory.resolve(fileName))
|
||||
private static void verifyGeneratedFileContent(Path outputDirectory, String testClass)
|
||||
throws IOException {
|
||||
String resourceName = String.format("bugpattern-%s.json", testClass);
|
||||
assertThat(outputDirectory.resolve(resourceName))
|
||||
.content(UTF_8)
|
||||
.isEqualToIgnoringWhitespace(getResource(resourceName));
|
||||
.isEqualToIgnoringWhitespace(
|
||||
getResource(
|
||||
String.join("-", BugPatternExtractorTest.class.getSimpleName(), resourceName)));
|
||||
}
|
||||
|
||||
// XXX: Once we support only JDK 15+, drop this method in favour of including the resources as
|
||||
// text blocks in this class. (This also requires renaming the `verifyFileMatchesResource`
|
||||
// method.)
|
||||
// text blocks in this class.
|
||||
private static String getResource(String resourceName) throws IOException {
|
||||
return Resources.toString(
|
||||
Resources.getResource(BugPatternExtractorTest.class, resourceName), UTF_8);
|
||||
}
|
||||
|
||||
/** A {@link BugChecker} that validates the {@link BugPatternExtractor}. */
|
||||
@BugPattern(summary = "Validates `BugPatternExtractor` extraction", severity = ERROR)
|
||||
public static final class TestChecker extends BugChecker implements ClassTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Description matchClass(ClassTree tree, VisitorState state) {
|
||||
BugPatternExtractor extractor = new BugPatternExtractor();
|
||||
|
||||
assertThatThrownBy(() -> extractor.extract(tree, state.context))
|
||||
.isInstanceOf(NullPointerException.class)
|
||||
.hasMessage("BugPattern annotation must be present");
|
||||
|
||||
return buildDescription(tree)
|
||||
.setMessage(String.format("Can extract: %s", extractor.canExtract(tree)))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,468 @@
|
||||
package tech.picnic.errorprone.documentation;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.io.Resources;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
final class BugPatternTestExtractorTest {
|
||||
@Test
|
||||
void noTestClass(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerWithoutAnnotation.java",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"public final class TestCheckerWithoutAnnotation extends BugChecker {}");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void noDoTestInvocation(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\");",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\");",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullBugCheckerInstance(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance((Class<BugChecker>) null, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance((Class<BugChecker>) null, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void rawBugCheckerInstance(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" @SuppressWarnings(\"unchecked\")",
|
||||
" void m() {",
|
||||
" @SuppressWarnings(\"rawtypes\")",
|
||||
" Class bugChecker = TestChecker.class;",
|
||||
"",
|
||||
" CompilationTestHelper.newInstance(bugChecker, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(bugChecker, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void scannerSupplierInstance(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"import com.google.errorprone.scanner.ScannerSupplier;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(",
|
||||
" ScannerSupplier.fromBugCheckerClasses(TestChecker.class), getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(",
|
||||
" ScannerSupplier.fromBugCheckerClasses(TestChecker.class), getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void nonCompileTimeConstantStrings(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addSourceLines(toString() + \"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .addSourceLines(\"B.java\", \"// BUG: Diagnostic contains:\", \"class B {}\", toString())",
|
||||
" .doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addInputLines(toString() + \"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .addInputLines(\"B.java\", \"class B {}\", toString())",
|
||||
" .addOutputLines(\"B.java\", \"class B { /* This is a change. */ }\")",
|
||||
" .addInputLines(\"C.java\", \"class C {}\")",
|
||||
" .addOutputLines(\"C.java\", \"class C { /* This is a change. */ }\", toString())",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void nonFluentTestHelperExpressions(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper testHelper =",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"class A {}\");",
|
||||
" testHelper.doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.ExpectOutput expectedOutput =",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\");",
|
||||
" expectedOutput.addOutputLines(\"A.java\", \"class A {}\").doTest();",
|
||||
" expectedOutput.expectUnchanged().doTest();",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void noSource(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass()).doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass()).doTest();",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void noDiagnostics(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A {}\")",
|
||||
" .addInputLines(\"B.java\", \"class B {}\")",
|
||||
" .expectUnchanged()",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleFileCompilationTestHelper(@TempDir Path outputDirectory) throws IOException {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"SingleFileCompilationTestHelperTest.java",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class SingleFileCompilationTestHelperTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
verifyGeneratedFileContent(outputDirectory, "SingleFileCompilationTestHelperTest");
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleFileCompilationTestHelperWithSetArgs(@TempDir Path outputDirectory)
|
||||
throws IOException {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"SingleFileCompilationTestHelperWithSetArgsTest.java",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class SingleFileCompilationTestHelperWithSetArgsTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .setArgs(\"-XepAllSuggestionsAsWarnings\")",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
verifyGeneratedFileContent(outputDirectory, "SingleFileCompilationTestHelperWithSetArgsTest");
|
||||
}
|
||||
|
||||
@Test
|
||||
void multiFileCompilationTestHelper(@TempDir Path outputDirectory) throws IOException {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"MultiFileCompilationTestHelperTest.java",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class MultiFileCompilationTestHelperTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .addSourceLines(\"B.java\", \"// BUG: Diagnostic contains:\", \"class B {}\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
verifyGeneratedFileContent(outputDirectory, "MultiFileCompilationTestHelperTest");
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleFileBugCheckerRefactoringTestHelper(@TempDir Path outputDirectory) throws IOException {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"SingleFileBugCheckerRefactoringTestHelperTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class SingleFileBugCheckerRefactoringTestHelperTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
verifyGeneratedFileContent(outputDirectory, "SingleFileBugCheckerRefactoringTestHelperTest");
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestMode(
|
||||
@TempDir Path outputDirectory) throws IOException {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .setArgs(\"-XepAllSuggestionsAsWarnings\")",
|
||||
" .setFixChooser(FixChoosers.SECOND)",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .doTest(TestMode.TEXT_MATCH);",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest");
|
||||
}
|
||||
|
||||
@Test
|
||||
void multiFileBugCheckerRefactoringTestHelper(@TempDir Path outputDirectory) throws IOException {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"MultiFileBugCheckerRefactoringTestHelperTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class MultiFileBugCheckerRefactoringTestHelperTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .addInputLines(\"B.java\", \"class B {}\")",
|
||||
" .addOutputLines(\"B.java\", \"class B { /* This is a change. */ }\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
verifyGeneratedFileContent(outputDirectory, "MultiFileBugCheckerRefactoringTestHelperTest");
|
||||
}
|
||||
|
||||
@Test
|
||||
void compilationAndBugCheckerRefactoringTestHelpers(@TempDir Path outputDirectory)
|
||||
throws IOException {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"CompilationAndBugCheckerRefactoringTestHelpersTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class CompilationAndBugCheckerRefactoringTestHelpersTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory, "CompilationAndBugCheckerRefactoringTestHelpersTest");
|
||||
}
|
||||
|
||||
@Test
|
||||
void compilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNames(
|
||||
@TempDir Path outputDirectory) throws IOException {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.java",
|
||||
"package pkg;",
|
||||
"",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest {",
|
||||
" private static class CustomTestChecker extends BugChecker {}",
|
||||
"",
|
||||
" private static class CustomTestChecker2 extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(CustomTestChecker.class, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(CustomTestChecker2.class, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
"CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest");
|
||||
}
|
||||
|
||||
private static void verifyGeneratedFileContent(Path outputDirectory, String testClass)
|
||||
throws IOException {
|
||||
String resourceName = String.format("bugpattern-test-%s.json", testClass);
|
||||
assertThat(outputDirectory.resolve(resourceName))
|
||||
.content(UTF_8)
|
||||
.isEqualToIgnoringWhitespace(
|
||||
getResource(
|
||||
String.join("-", BugPatternTestExtractorTest.class.getSimpleName(), resourceName)));
|
||||
}
|
||||
|
||||
// XXX: Once we support only JDK 15+, drop this method in favour of including the resources as
|
||||
// text blocks in this class.
|
||||
private static String getResource(String resourceName) throws IOException {
|
||||
return Resources.toString(
|
||||
Resources.getResource(BugPatternTestExtractorTest.class, resourceName), UTF_8);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package tech.picnic.errorprone.documentation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.FileManagers;
|
||||
import com.google.errorprone.FileObjects;
|
||||
@@ -7,39 +9,66 @@ import com.sun.tools.javac.api.JavacTaskImpl;
|
||||
import com.sun.tools.javac.api.JavacTool;
|
||||
import com.sun.tools.javac.file.JavacFileManager;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
// XXX: Generalize and move this class so that it can also be used by `refaster-compiler`.
|
||||
// XXX: Add support for this class to the `ErrorProneTestHelperSourceFormat` check.
|
||||
// XXX: This class is supported by the `ErrorProneTestHelperSourceFormat` check, but until that
|
||||
// support is covered by unit tests, make sure to update that logic if this class or its methods are
|
||||
// moved/renamed.
|
||||
public final class Compilation {
|
||||
private Compilation() {}
|
||||
|
||||
public static void compileWithDocumentationGenerator(
|
||||
Path outputDirectory, String fileName, String... lines) {
|
||||
compileWithDocumentationGenerator(outputDirectory.toAbsolutePath().toString(), fileName, lines);
|
||||
Path outputDirectory, String path, String... lines) {
|
||||
compileWithDocumentationGenerator(outputDirectory.toAbsolutePath().toString(), path, lines);
|
||||
}
|
||||
|
||||
public static void compileWithDocumentationGenerator(
|
||||
String outputDirectory, String fileName, String... lines) {
|
||||
String outputDirectory, String path, String... lines) {
|
||||
/*
|
||||
* The compiler options specified here largely match those used by Error Prone's
|
||||
* `CompilationTestHelper`. A key difference is the stricter linting configuration. When
|
||||
* compiling using JDK 21+, these lint options also require that certain JDK modules are
|
||||
* explicitly exported.
|
||||
*/
|
||||
compile(
|
||||
ImmutableList.of("-Xplugin:DocumentationGenerator -XoutputDirectory=" + outputDirectory),
|
||||
FileObjects.forSourceLines(fileName, lines));
|
||||
ImmutableList.of(
|
||||
"--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
|
||||
"--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
|
||||
"--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
|
||||
"-encoding",
|
||||
"UTF-8",
|
||||
"-parameters",
|
||||
"-proc:none",
|
||||
"-Werror",
|
||||
"-Xlint:all,-serial",
|
||||
"-Xplugin:DocumentationGenerator -XoutputDirectory=" + outputDirectory,
|
||||
"-XDdev",
|
||||
"-XDcompilePolicy=simple"),
|
||||
FileObjects.forSourceLines(path, lines));
|
||||
}
|
||||
|
||||
private static void compile(ImmutableList<String> options, JavaFileObject javaFileObject) {
|
||||
JavacFileManager javacFileManager = FileManagers.testFileManager();
|
||||
JavaCompiler compiler = JavacTool.create();
|
||||
|
||||
List<Diagnostic<?>> diagnostics = new ArrayList<>();
|
||||
JavacTaskImpl task =
|
||||
(JavacTaskImpl)
|
||||
compiler.getTask(
|
||||
null,
|
||||
javacFileManager,
|
||||
null,
|
||||
diagnostics::add,
|
||||
options,
|
||||
ImmutableList.of(),
|
||||
ImmutableList.of(javaFileObject));
|
||||
|
||||
task.call();
|
||||
Boolean result = task.call();
|
||||
assertThat(diagnostics).isEmpty();
|
||||
assertThat(result).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,29 @@
|
||||
package tech.picnic.errorprone.documentation;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.nio.file.attribute.AclEntryPermission.ADD_SUBDIRECTORY;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.jupiter.api.condition.OS.WINDOWS;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystemException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.AclEntry;
|
||||
import java.nio.file.attribute.AclFileAttributeView;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledOnOs;
|
||||
import org.junit.jupiter.api.condition.EnabledOnOs;
|
||||
@@ -75,4 +85,56 @@ final class DocumentationGeneratorTaskListenerTest {
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("Precisely one path must be provided");
|
||||
}
|
||||
|
||||
@Test
|
||||
void extraction(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"DocumentationGeneratorTaskListenerTestClass.java",
|
||||
"class DocumentationGeneratorTaskListenerTestClass {}");
|
||||
|
||||
// XXX: Once we support only JDK 15+, use a text block for the `expected` string.
|
||||
assertThat(
|
||||
outputDirectory.resolve(
|
||||
"documentation-generator-task-listener-test-DocumentationGeneratorTaskListenerTestClass.json"))
|
||||
.content(UTF_8)
|
||||
.isEqualToIgnoringWhitespace(
|
||||
"{\"className\":\"DocumentationGeneratorTaskListenerTestClass\",\"path\":[\"CLASS: DocumentationGeneratorTaskListenerTestClass\",\"COMPILATION_UNIT\"]}");
|
||||
}
|
||||
|
||||
@Immutable
|
||||
@AutoService(Extractor.class)
|
||||
@SuppressWarnings("rawtypes" /* See https://github.com/google/auto/issues/870. */)
|
||||
public static final class TestExtractor implements Extractor<ExtractionParameters> {
|
||||
@Override
|
||||
public String identifier() {
|
||||
return "documentation-generator-task-listener-test";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ExtractionParameters> tryExtract(ClassTree tree, VisitorState state) {
|
||||
return Optional.of(tree.getSimpleName().toString())
|
||||
.filter(n -> n.contains(DocumentationGeneratorTaskListenerTest.class.getSimpleName()))
|
||||
.map(
|
||||
className ->
|
||||
new AutoValue_DocumentationGeneratorTaskListenerTest_ExtractionParameters(
|
||||
className,
|
||||
Streams.stream(state.getPath())
|
||||
.map(TestExtractor::describeTree)
|
||||
.collect(toImmutableList())));
|
||||
}
|
||||
|
||||
private static String describeTree(Tree tree) {
|
||||
return (tree instanceof ClassTree)
|
||||
? String.join(": ", String.valueOf(tree.getKind()), ((ClassTree) tree).getSimpleName())
|
||||
: tree.getKind().toString();
|
||||
}
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class ExtractionParameters {
|
||||
abstract String className();
|
||||
|
||||
abstract ImmutableList<String> path();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"testClass": "CompilationAndBugCheckerRefactoringTestHelpersTest",
|
||||
"testCases": [
|
||||
{
|
||||
"classUnderTest": "CompilationAndBugCheckerRefactoringTestHelpersTest.TestChecker",
|
||||
"entries": [
|
||||
{
|
||||
"path": "A.java",
|
||||
"code": "// BUG: Diagnostic contains:\nclass A {}\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"classUnderTest": "CompilationAndBugCheckerRefactoringTestHelpersTest.TestChecker",
|
||||
"entries": [
|
||||
{
|
||||
"path": "A.java",
|
||||
"input": "class A {}\n",
|
||||
"output": "class A { /* This is a change. */ }\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"testClass": "pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest",
|
||||
"testCases": [
|
||||
{
|
||||
"classUnderTest": "pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.CustomTestChecker",
|
||||
"entries": [
|
||||
{
|
||||
"path": "A.java",
|
||||
"code": "// BUG: Diagnostic contains:\nclass A {}\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"classUnderTest": "pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.CustomTestChecker2",
|
||||
"entries": [
|
||||
{
|
||||
"path": "A.java",
|
||||
"input": "class A {}\n",
|
||||
"output": "class A { /* This is a change. */ }\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"testClass": "MultiFileBugCheckerRefactoringTestHelperTest",
|
||||
"testCases": [
|
||||
{
|
||||
"classUnderTest": "MultiFileBugCheckerRefactoringTestHelperTest.TestChecker",
|
||||
"entries": [
|
||||
{
|
||||
"path": "A.java",
|
||||
"input": "class A {}\n",
|
||||
"output": "class A { /* This is a change. */ }\n"
|
||||
},
|
||||
{
|
||||
"path": "B.java",
|
||||
"input": "class B {}\n",
|
||||
"output": "class B { /* This is a change. */ }\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"testClass": "MultiFileCompilationTestHelperTest",
|
||||
"testCases": [
|
||||
{
|
||||
"classUnderTest": "MultiFileCompilationTestHelperTest.TestChecker",
|
||||
"entries": [
|
||||
{
|
||||
"path": "A.java",
|
||||
"code": "// BUG: Diagnostic contains:\nclass A {}\n"
|
||||
},
|
||||
{
|
||||
"path": "B.java",
|
||||
"code": "// BUG: Diagnostic contains:\nclass B {}\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"testClass": "SingleFileBugCheckerRefactoringTestHelperTest",
|
||||
"testCases": [
|
||||
{
|
||||
"classUnderTest": "SingleFileBugCheckerRefactoringTestHelperTest.TestChecker",
|
||||
"entries": [
|
||||
{
|
||||
"path": "A.java",
|
||||
"input": "class A {}\n",
|
||||
"output": "class A { /* This is a change. */ }\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"testClass": "SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest",
|
||||
"testCases": [
|
||||
{
|
||||
"classUnderTest": "SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest.TestChecker",
|
||||
"entries": [
|
||||
{
|
||||
"path": "A.java",
|
||||
"input": "class A {}\n",
|
||||
"output": "class A { /* This is a change. */ }\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"testClass": "SingleFileCompilationTestHelperTest",
|
||||
"testCases": [
|
||||
{
|
||||
"classUnderTest": "SingleFileCompilationTestHelperTest.TestChecker",
|
||||
"entries": [
|
||||
{
|
||||
"path": "A.java",
|
||||
"code": "// BUG: Diagnostic contains:\nclass A {}\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"testClass": "SingleFileCompilationTestHelperWithSetArgsTest",
|
||||
"testCases": [
|
||||
{
|
||||
"classUnderTest": "SingleFileCompilationTestHelperWithSetArgsTest.TestChecker",
|
||||
"entries": [
|
||||
{
|
||||
"path": "A.java",
|
||||
"code": "// BUG: Diagnostic contains:\nclass A {}\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -72,6 +72,11 @@
|
||||
<artifactId>auto-service-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.value</groupId>
|
||||
<artifactId>auto-value-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.googlejavaformat</groupId>
|
||||
<artifactId>google-java-format</artifactId>
|
||||
@@ -248,17 +253,6 @@
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<configuration>
|
||||
<ignoredUnusedDeclaredDependencies>
|
||||
<!-- XXX: Figure out why the plugin thinks this
|
||||
dependency is unused. -->
|
||||
<ignoredUnusedDeclaredDependency>${project.groupId}:refaster-support</ignoredUnusedDeclaredDependency>
|
||||
</ignoredUnusedDeclaredDependencies>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
@@ -9,7 +9,6 @@ import static com.google.errorprone.matchers.Matchers.isType;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
@@ -17,6 +16,7 @@ import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.MultiMatcher;
|
||||
import com.google.errorprone.matchers.MultiMatcher.MultiMatchResult;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
@@ -48,11 +48,9 @@ public final class AutowiredConstructor extends BugChecker implements ClassTreeM
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
ImmutableList<AnnotationTree> annotations =
|
||||
AUTOWIRED_ANNOTATION
|
||||
.multiMatchResult(Iterables.getOnlyElement(constructors), state)
|
||||
.matchingNodes();
|
||||
if (annotations.size() != 1) {
|
||||
MultiMatchResult<AnnotationTree> hasAutowiredAnnotation =
|
||||
AUTOWIRED_ANNOTATION.multiMatchResult(Iterables.getOnlyElement(constructors), state);
|
||||
if (!hasAutowiredAnnotation.matches()) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
@@ -61,7 +59,7 @@ public final class AutowiredConstructor extends BugChecker implements ClassTreeM
|
||||
* means that the associated import can be removed as well. Rather than adding code for this
|
||||
* case we leave flagging the unused import to Error Prone's `RemoveUnusedImports` check.
|
||||
*/
|
||||
AnnotationTree annotation = Iterables.getOnlyElement(annotations);
|
||||
AnnotationTree annotation = hasAutowiredAnnotation.onlyMatchingNode();
|
||||
return describeMatch(annotation, SourceCode.deleteWithTrailingWhitespace(annotation, state));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.STYLE;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
@@ -66,7 +67,12 @@ public final class ErrorProneTestHelperSourceFormat extends BugChecker
|
||||
.named("addSourceLines"),
|
||||
instanceMethod()
|
||||
.onDescendantOf("com.google.errorprone.BugCheckerRefactoringTestHelper")
|
||||
.named("addInputLines"));
|
||||
.named("addInputLines"),
|
||||
// XXX: Add tests for `Compilation.compileWithDocumentationGenerator`. Until done, make
|
||||
// sure to update this matcher if that method's class or name is changed/moved.
|
||||
staticMethod()
|
||||
.onClass("tech.picnic.errorprone.documentation.Compilation")
|
||||
.named("compileWithDocumentationGenerator"));
|
||||
private static final Matcher<ExpressionTree> OUTPUT_SOURCE_ACCEPTING_METHOD =
|
||||
instanceMethod()
|
||||
.onDescendantOf("com.google.errorprone.BugCheckerRefactoringTestHelper.ExpectOutput")
|
||||
@@ -83,7 +89,8 @@ public final class ErrorProneTestHelperSourceFormat extends BugChecker
|
||||
}
|
||||
|
||||
List<? extends ExpressionTree> sourceLines =
|
||||
tree.getArguments().subList(1, tree.getArguments().size());
|
||||
tree.getArguments()
|
||||
.subList(ASTHelpers.getSymbol(tree).params().size() - 1, tree.getArguments().size());
|
||||
if (sourceLines.isEmpty()) {
|
||||
return buildDescription(tree).setMessage("No source code provided").build();
|
||||
}
|
||||
@@ -149,12 +156,13 @@ public final class ErrorProneTestHelperSourceFormat extends BugChecker
|
||||
return FORMATTER.formatSource(withOptionallyRemovedImports);
|
||||
}
|
||||
|
||||
// XXX: This logic is duplicated in `BugPatternTestExtractor`. Can we do better?
|
||||
private static Optional<String> getConstantSourceCode(
|
||||
List<? extends ExpressionTree> sourceLines) {
|
||||
StringBuilder source = new StringBuilder();
|
||||
|
||||
for (ExpressionTree sourceLine : sourceLines) {
|
||||
Object value = ASTHelpers.constValue(sourceLine);
|
||||
String value = ASTHelpers.constValue(sourceLine, String.class);
|
||||
if (value == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
// the target method such a modification may change the code's semantics or performance.
|
||||
// XXX: Also flag `Stream#map`, `Mono#map` and `Flux#map` invocations where the given transformation
|
||||
// is effectively the identity operation.
|
||||
// XXX: Also flag nullary instance method invocations that represent an identity conversion, such as
|
||||
// `Boolean#booleanValue()`, `Byte#byteValue()` and friends.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Avoid or clarify identity conversions",
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
|
||||
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE;
|
||||
import static com.google.errorprone.matchers.Matchers.annotations;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.isType;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreMatchers.hasMetaAnnotation;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.fixes.SuggestedFixes;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.matchers.MultiMatcher;
|
||||
import com.google.errorprone.matchers.MultiMatcher.MultiMatchResult;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags nullary {@link
|
||||
* org.junit.jupiter.params.ParameterizedTest @ParameterizedTest} test methods.
|
||||
*
|
||||
* <p>Such tests are unnecessarily executed more than necessary. This checker suggests annotating
|
||||
* the method with {@link org.junit.jupiter.api.Test @Test}, and to drop all declared {@link
|
||||
* org.junit.jupiter.params.provider.ArgumentsSource argument sources}.
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Nullary JUnit test methods should not be parameterized",
|
||||
link = BUG_PATTERNS_BASE_URL + "JUnitNullaryParameterizedTestDeclaration",
|
||||
linkType = CUSTOM,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class JUnitNullaryParameterizedTestDeclaration extends BugChecker
|
||||
implements MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final MultiMatcher<MethodTree, AnnotationTree> IS_PARAMETERIZED_TEST =
|
||||
annotations(AT_LEAST_ONE, isType("org.junit.jupiter.params.ParameterizedTest"));
|
||||
private static final Matcher<AnnotationTree> IS_ARGUMENT_SOURCE =
|
||||
anyOf(
|
||||
isType("org.junit.jupiter.params.provider.ArgumentsSource"),
|
||||
isType("org.junit.jupiter.params.provider.ArgumentsSources"),
|
||||
hasMetaAnnotation("org.junit.jupiter.params.provider.ArgumentsSource"));
|
||||
|
||||
/** Instantiates a new {@link JUnitNullaryParameterizedTestDeclaration} instance. */
|
||||
public JUnitNullaryParameterizedTestDeclaration() {}
|
||||
|
||||
@Override
|
||||
public Description matchMethod(MethodTree tree, VisitorState state) {
|
||||
if (!tree.getParameters().isEmpty()) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
MultiMatchResult<AnnotationTree> isParameterizedTest =
|
||||
IS_PARAMETERIZED_TEST.multiMatchResult(tree, state);
|
||||
if (!isParameterizedTest.matches()) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is vacuously parameterized. Suggest replacing `@ParameterizedTest` with `@Test`.
|
||||
* (As each method is checked independently, we cannot in general determine whether this
|
||||
* suggestion makes a `ParameterizedTest` type import obsolete; that task is left to Error
|
||||
* Prone's `RemoveUnusedImports` check.)
|
||||
*/
|
||||
SuggestedFix.Builder fix = SuggestedFix.builder();
|
||||
fix.merge(
|
||||
SuggestedFix.replace(
|
||||
isParameterizedTest.onlyMatchingNode(),
|
||||
'@' + SuggestedFixes.qualifyType(state, fix, "org.junit.jupiter.api.Test")));
|
||||
|
||||
/*
|
||||
* Also suggest dropping all (explicit and implicit) `@ArgumentsSource`s. No attempt is made to
|
||||
* assess whether a dropped `@MethodSource` also makes the referenced factory method(s) unused.
|
||||
*/
|
||||
tree.getModifiers().getAnnotations().stream()
|
||||
.filter(a -> IS_ARGUMENT_SOURCE.matches(a, state))
|
||||
.forEach(a -> fix.merge(SourceCode.deleteWithTrailingWhitespace(a, state)));
|
||||
|
||||
return describeMatch(tree, fix.build());
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public final class MockitoMockClassReference extends BugChecker
|
||||
Tree parent = state.getPath().getParentPath().getLeaf();
|
||||
switch (parent.getKind()) {
|
||||
case VARIABLE:
|
||||
return !ASTHelpers.hasNoExplicitType((VariableTree) parent, state)
|
||||
return !ASTHelpers.hasImplicitType((VariableTree) parent, state)
|
||||
&& MoreASTHelpers.areSameType(tree, parent, state);
|
||||
case ASSIGNMENT:
|
||||
return MoreASTHelpers.areSameType(tree, parent, state);
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.STYLE;
|
||||
import static tech.picnic.errorprone.bugpatterns.StaticImport.STATIC_IMPORT_CANDIDATE_MEMBERS;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSetMultimap;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.CompilationUnitTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.fixes.SuggestedFixes;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.tree.IdentifierTree;
|
||||
import com.sun.source.tree.ImportTree;
|
||||
import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags static imports of type members that should *not* be statically
|
||||
* imported.
|
||||
*/
|
||||
// XXX: This check is closely linked to `StaticImport`. Consider merging the two.
|
||||
// XXX: Add suppression support. If qualification of one more more identifiers is suppressed, then
|
||||
// the associated static import should *not* be removed.
|
||||
// XXX: Also introduce logic that disallows statically importing `ZoneOffset.ofHours` and other
|
||||
// `ofXXX`-style methods.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Member should not be statically imported",
|
||||
link = BUG_PATTERNS_BASE_URL + "NonStaticImport",
|
||||
linkType = CUSTOM,
|
||||
severity = SUGGESTION,
|
||||
tags = STYLE)
|
||||
public final class NonStaticImport extends BugChecker implements CompilationUnitTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Types whose members should not be statically imported, unless exempted by {@link
|
||||
* StaticImport#STATIC_IMPORT_CANDIDATE_MEMBERS}.
|
||||
*
|
||||
* <p>Types listed here should be mutually exclusive with {@link
|
||||
* StaticImport#STATIC_IMPORT_CANDIDATE_TYPES}.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static final ImmutableSet<String> NON_STATIC_IMPORT_CANDIDATE_TYPES =
|
||||
ImmutableSet.of(
|
||||
"com.google.common.base.Strings",
|
||||
"com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode",
|
||||
"java.time.Clock",
|
||||
"java.time.ZoneOffset");
|
||||
|
||||
/**
|
||||
* Type members that should never be statically imported.
|
||||
*
|
||||
* <p>Please note that:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Types listed by {@link #NON_STATIC_IMPORT_CANDIDATE_TYPES} and members listed by {@link
|
||||
* #NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS} should be omitted from this collection.
|
||||
* <li>This collection should be mutually exclusive with {@link
|
||||
* StaticImport#STATIC_IMPORT_CANDIDATE_MEMBERS}.
|
||||
* </ul>
|
||||
*/
|
||||
// XXX: Perhaps the set of exempted `java.util.Collections` methods is too strict. For now any
|
||||
// method name that could be considered "too vague" or could conceivably mean something else in a
|
||||
// specific context is left out.
|
||||
static final ImmutableSetMultimap<String, String> NON_STATIC_IMPORT_CANDIDATE_MEMBERS =
|
||||
ImmutableSetMultimap.<String, String>builder()
|
||||
.put("com.google.common.base.Predicates", "contains")
|
||||
.putAll(
|
||||
"java.util.Collections",
|
||||
"addAll",
|
||||
"copy",
|
||||
"fill",
|
||||
"list",
|
||||
"max",
|
||||
"min",
|
||||
"nCopies",
|
||||
"rotate",
|
||||
"sort",
|
||||
"swap")
|
||||
.put("java.util.Locale", "ROOT")
|
||||
.putAll("java.util.regex.Pattern", "compile", "matches", "quote")
|
||||
.put("org.springframework.http.MediaType", "ALL")
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Identifiers that should never be statically imported.
|
||||
*
|
||||
* <p>Please note that:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Identifiers listed by {@link StaticImport#STATIC_IMPORT_CANDIDATE_MEMBERS} should be
|
||||
* mutually exclusive with identifiers listed here.
|
||||
* <li>This list should contain a superset of the identifiers flagged by {@link
|
||||
* com.google.errorprone.bugpatterns.BadImport}.
|
||||
* </ul>
|
||||
*/
|
||||
static final ImmutableSet<String> NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS =
|
||||
ImmutableSet.of(
|
||||
"builder",
|
||||
"copyOf",
|
||||
"create",
|
||||
"empty",
|
||||
"from",
|
||||
"getDefaultInstance",
|
||||
"INSTANCE",
|
||||
"MAX",
|
||||
"MAX_VALUE",
|
||||
"MIN",
|
||||
"MIN_VALUE",
|
||||
"newBuilder",
|
||||
"newInstance",
|
||||
"of",
|
||||
"ONE",
|
||||
"parse",
|
||||
"valueOf",
|
||||
"ZERO");
|
||||
|
||||
/** Instantiates a new {@link NonStaticImport} instance. */
|
||||
public NonStaticImport() {}
|
||||
|
||||
@Override
|
||||
public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) {
|
||||
ImmutableTable<String, String, UndesiredStaticImport> undesiredStaticImports =
|
||||
getUndesiredStaticImports(tree, state);
|
||||
|
||||
if (!undesiredStaticImports.isEmpty()) {
|
||||
replaceUndesiredStaticImportUsages(tree, undesiredStaticImports, state);
|
||||
|
||||
for (UndesiredStaticImport staticImport : undesiredStaticImports.values()) {
|
||||
state.reportMatch(
|
||||
describeMatch(staticImport.importTree(), staticImport.fixBuilder().build()));
|
||||
}
|
||||
}
|
||||
|
||||
/* Any violations have been flagged against the offending static import statement. */
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
private static ImmutableTable<String, String, UndesiredStaticImport> getUndesiredStaticImports(
|
||||
CompilationUnitTree tree, VisitorState state) {
|
||||
ImmutableTable.Builder<String, String, UndesiredStaticImport> imports =
|
||||
ImmutableTable.builder();
|
||||
for (ImportTree importTree : tree.getImports()) {
|
||||
Tree qualifiedIdentifier = importTree.getQualifiedIdentifier();
|
||||
if (importTree.isStatic() && qualifiedIdentifier instanceof MemberSelectTree) {
|
||||
MemberSelectTree memberSelectTree = (MemberSelectTree) qualifiedIdentifier;
|
||||
String type = SourceCode.treeToString(memberSelectTree.getExpression(), state);
|
||||
String member = memberSelectTree.getIdentifier().toString();
|
||||
if (shouldNotBeStaticallyImported(type, member)) {
|
||||
imports.put(
|
||||
type,
|
||||
member,
|
||||
new AutoValue_NonStaticImport_UndesiredStaticImport(
|
||||
importTree, SuggestedFix.builder().removeStaticImport(type + '.' + member)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return imports.build();
|
||||
}
|
||||
|
||||
private static boolean shouldNotBeStaticallyImported(String type, String member) {
|
||||
return (NON_STATIC_IMPORT_CANDIDATE_TYPES.contains(type)
|
||||
&& !STATIC_IMPORT_CANDIDATE_MEMBERS.containsEntry(type, member))
|
||||
|| NON_STATIC_IMPORT_CANDIDATE_MEMBERS.containsEntry(type, member)
|
||||
|| NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS.contains(member);
|
||||
}
|
||||
|
||||
private static void replaceUndesiredStaticImportUsages(
|
||||
CompilationUnitTree tree,
|
||||
ImmutableTable<String, String, UndesiredStaticImport> undesiredStaticImports,
|
||||
VisitorState state) {
|
||||
new TreeScanner<@Nullable Void, @Nullable Void>() {
|
||||
@Override
|
||||
public @Nullable Void visitIdentifier(IdentifierTree node, @Nullable Void unused) {
|
||||
Symbol symbol = ASTHelpers.getSymbol(node);
|
||||
if (symbol != null) {
|
||||
UndesiredStaticImport staticImport =
|
||||
undesiredStaticImports.get(
|
||||
symbol.owner.getQualifiedName().toString(), symbol.name.toString());
|
||||
if (staticImport != null) {
|
||||
SuggestedFix.Builder fix = staticImport.fixBuilder();
|
||||
fix.prefixWith(node, SuggestedFixes.qualifyType(state, fix, symbol.owner) + '.');
|
||||
}
|
||||
}
|
||||
|
||||
return super.visitIdentifier(node, unused);
|
||||
}
|
||||
}.scan(tree, null);
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
abstract static class UndesiredStaticImport {
|
||||
abstract ImportTree importTree();
|
||||
|
||||
abstract SuggestedFix.Builder fixBuilder();
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,10 @@ package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.STYLE;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static tech.picnic.errorprone.bugpatterns.NonStaticImport.NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS;
|
||||
import static tech.picnic.errorprone.bugpatterns.NonStaticImport.NON_STATIC_IMPORT_CANDIDATE_MEMBERS;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
@@ -27,35 +29,30 @@ import com.sun.source.tree.Tree;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags methods and constants that can and should be statically imported.
|
||||
*/
|
||||
/** A {@link BugChecker} that flags type members that can and should be statically imported. */
|
||||
// XXX: This check is closely linked to `NonStaticImport`. Consider merging the two.
|
||||
// XXX: Tricky cases:
|
||||
// - `org.springframework.http.HttpStatus` (not always an improvement, and `valueOf` must
|
||||
// certainly be excluded)
|
||||
// - `com.google.common.collect.Tables`
|
||||
// - `ch.qos.logback.classic.Level.{DEBUG, ERROR, INFO, TRACE, WARN"}`
|
||||
// XXX: Also introduce a check that disallows static imports of certain methods. Candidates:
|
||||
// - `com.google.common.base.Strings`
|
||||
// - `java.util.Optional.empty`
|
||||
// - `java.util.Locale.ROOT`
|
||||
// - `ZoneOffset.ofHours` and other `ofXXX`-style methods.
|
||||
// - `java.time.Clock`.
|
||||
// - Several other `java.time` classes.
|
||||
// - Likely any of `*.{ZERO, ONE, MIX, MAX, MIN_VALUE, MAX_VALUE}`.
|
||||
// - `ch.qos.logback.classic.Level.{DEBUG, ERROR, INFO, TRACE, WARN}`
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Identifier should be statically imported",
|
||||
link = BUG_PATTERNS_BASE_URL + "StaticImport",
|
||||
linkType = CUSTOM,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
tags = STYLE)
|
||||
public final class StaticImport extends BugChecker implements MemberSelectTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Types whose members should be statically imported, unless exempted by {@link
|
||||
* #STATIC_IMPORT_EXEMPTED_MEMBERS} or {@link #STATIC_IMPORT_EXEMPTED_IDENTIFIERS}.
|
||||
* NonStaticImport#NON_STATIC_IMPORT_CANDIDATE_MEMBERS} or {@link
|
||||
* NonStaticImport#NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS}.
|
||||
*
|
||||
* <p>Types listed here should be mutually exclusive with {@link
|
||||
* NonStaticImport#NON_STATIC_IMPORT_CANDIDATE_TYPES}.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static final ImmutableSet<String> STATIC_IMPORT_CANDIDATE_TYPES =
|
||||
@@ -104,8 +101,20 @@ public final class StaticImport extends BugChecker implements MemberSelectTreeMa
|
||||
"reactor.function.TupleUtils",
|
||||
"tech.picnic.errorprone.bugpatterns.util.MoreTypes");
|
||||
|
||||
/** Type members that should be statically imported. */
|
||||
@VisibleForTesting
|
||||
/**
|
||||
* Type members that should be statically imported.
|
||||
*
|
||||
* <p>Please note that:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Types listed by {@link #STATIC_IMPORT_CANDIDATE_TYPES} should be omitted from this
|
||||
* collection.
|
||||
* <li>This collection should be mutually exclusive with {@link
|
||||
* NonStaticImport#NON_STATIC_IMPORT_CANDIDATE_MEMBERS}.
|
||||
* <li>This collection should not list members contained in {@link
|
||||
* NonStaticImport#NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS}.
|
||||
* </ul>
|
||||
*/
|
||||
static final ImmutableSetMultimap<String, String> STATIC_IMPORT_CANDIDATE_MEMBERS =
|
||||
ImmutableSetMultimap.<String, String>builder()
|
||||
.putAll(
|
||||
@@ -143,55 +152,6 @@ public final class StaticImport extends BugChecker implements MemberSelectTreeMa
|
||||
.putAll("com.google.common.collect.Comparators", "emptiesFirst", "emptiesLast")
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Type members that should never be statically imported.
|
||||
*
|
||||
* <p>Identifiers listed by {@link #STATIC_IMPORT_EXEMPTED_IDENTIFIERS} should be omitted from
|
||||
* this collection.
|
||||
*/
|
||||
// XXX: Perhaps the set of exempted `java.util.Collections` methods is too strict. For now any
|
||||
// method name that could be considered "too vague" or could conceivably mean something else in a
|
||||
// specific context is left out.
|
||||
@VisibleForTesting
|
||||
static final ImmutableSetMultimap<String, String> STATIC_IMPORT_EXEMPTED_MEMBERS =
|
||||
ImmutableSetMultimap.<String, String>builder()
|
||||
.put("com.google.common.base.Predicates", "contains")
|
||||
.put("com.mongodb.client.model.Filters", "empty")
|
||||
.putAll(
|
||||
"java.util.Collections",
|
||||
"addAll",
|
||||
"copy",
|
||||
"fill",
|
||||
"list",
|
||||
"max",
|
||||
"min",
|
||||
"nCopies",
|
||||
"rotate",
|
||||
"sort",
|
||||
"swap")
|
||||
.putAll("java.util.regex.Pattern", "compile", "matches", "quote")
|
||||
.put("org.springframework.http.MediaType", "ALL")
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Identifiers that should never be statically imported.
|
||||
*
|
||||
* <p>This should be a superset of the identifiers flagged by {@link
|
||||
* com.google.errorprone.bugpatterns.BadImport}.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static final ImmutableSet<String> STATIC_IMPORT_EXEMPTED_IDENTIFIERS =
|
||||
ImmutableSet.of(
|
||||
"builder",
|
||||
"create",
|
||||
"copyOf",
|
||||
"from",
|
||||
"getDefaultInstance",
|
||||
"INSTANCE",
|
||||
"newBuilder",
|
||||
"of",
|
||||
"valueOf");
|
||||
|
||||
/** Instantiates a new {@link StaticImport} instance. */
|
||||
public StaticImport() {}
|
||||
|
||||
@@ -229,13 +189,13 @@ public final class StaticImport extends BugChecker implements MemberSelectTreeMa
|
||||
|
||||
private static boolean isCandidate(MemberSelectTree tree) {
|
||||
String identifier = tree.getIdentifier().toString();
|
||||
if (STATIC_IMPORT_EXEMPTED_IDENTIFIERS.contains(identifier)) {
|
||||
if (NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS.contains(identifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type type = ASTHelpers.getType(tree.getExpression());
|
||||
return type != null
|
||||
&& !STATIC_IMPORT_EXEMPTED_MEMBERS.containsEntry(type.toString(), identifier);
|
||||
&& !NON_STATIC_IMPORT_CANDIDATE_MEMBERS.containsEntry(type.toString(), identifier);
|
||||
}
|
||||
|
||||
private static Optional<String> getCandidateSimpleName(StaticImportInfo importInfo) {
|
||||
|
||||
@@ -23,7 +23,7 @@ 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 com.sun.tools.javac.util.Constants;
|
||||
import java.util.Formattable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -150,7 +150,7 @@ public final class StringJoin extends BugChecker implements MethodInvocationTree
|
||||
SuggestedFix.Builder fix =
|
||||
SuggestedFix.builder()
|
||||
.replace(tree.getMethodSelect(), "String.join")
|
||||
.replace(arguments.next(), String.format("\"%s\"", Convert.quote(separator)));
|
||||
.replace(arguments.next(), Constants.format(separator));
|
||||
|
||||
while (arguments.hasNext()) {
|
||||
ExpressionTree argument = arguments.next();
|
||||
|
||||
@@ -3,80 +3,40 @@ package tech.picnic.errorprone.refasterrules;
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultiset;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.ImmutableSortedMultiset;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Matches;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.AbstractBooleanAssert;
|
||||
import org.assertj.core.api.AbstractCollectionAssert;
|
||||
import org.assertj.core.api.AbstractMapAssert;
|
||||
import org.assertj.core.api.MapAssert;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsEmpty;
|
||||
|
||||
@OnlineDocumentation
|
||||
final class AssertJMapRules {
|
||||
private AssertJMapRules() {}
|
||||
|
||||
// XXX: Reduce boilerplate using a `Matcher` that identifies "empty" instances.
|
||||
static final class AbstractMapAssertIsEmpty<K, V> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
void before(AbstractMapAssert<?, ?, K, V> mapAssert) {
|
||||
void before(
|
||||
AbstractMapAssert<?, ?, K, V> mapAssert,
|
||||
@Matches(IsEmpty.class) Map<? extends K, ? extends V> wellTypedMap,
|
||||
@Matches(IsEmpty.class) Map<?, ?> arbitrarilyTypedMap,
|
||||
@Matches(IsEmpty.class) Iterable<? extends K> keys) {
|
||||
Refaster.anyOf(
|
||||
mapAssert.containsExactlyEntriesOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableMap.of(),
|
||||
ImmutableBiMap.of(),
|
||||
ImmutableSortedMap.of(),
|
||||
new HashMap<>(),
|
||||
new LinkedHashMap<>(),
|
||||
new TreeMap<>())),
|
||||
mapAssert.hasSameSizeAs(
|
||||
Refaster.anyOf(
|
||||
ImmutableMap.of(),
|
||||
ImmutableBiMap.of(),
|
||||
ImmutableSortedMap.of(),
|
||||
new HashMap<>(),
|
||||
new LinkedHashMap<>(),
|
||||
new TreeMap<>())),
|
||||
mapAssert.isEqualTo(
|
||||
Refaster.anyOf(
|
||||
ImmutableMap.of(),
|
||||
ImmutableBiMap.of(),
|
||||
ImmutableSortedMap.of(),
|
||||
new HashMap<>(),
|
||||
new LinkedHashMap<>(),
|
||||
new TreeMap<>())),
|
||||
mapAssert.containsOnlyKeys(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(),
|
||||
new ArrayList<>(),
|
||||
ImmutableSet.of(),
|
||||
new HashSet<>(),
|
||||
new LinkedHashSet<>(),
|
||||
ImmutableSortedSet.of(),
|
||||
new TreeSet<>(),
|
||||
ImmutableMultiset.of(),
|
||||
ImmutableSortedMultiset.of())),
|
||||
mapAssert.containsExactlyEntriesOf(wellTypedMap),
|
||||
mapAssert.containsExactlyInAnyOrderEntriesOf(wellTypedMap),
|
||||
mapAssert.hasSameSizeAs(arbitrarilyTypedMap),
|
||||
mapAssert.isEqualTo(arbitrarilyTypedMap),
|
||||
mapAssert.containsOnlyKeys(keys),
|
||||
mapAssert.containsExactly(),
|
||||
mapAssert.containsOnly(),
|
||||
mapAssert.containsOnlyKeys());
|
||||
@@ -112,15 +72,9 @@ final class AssertJMapRules {
|
||||
|
||||
static final class AbstractMapAssertIsNotEmpty<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractMapAssert<?, ?, K, V> before(AbstractMapAssert<?, ?, K, V> mapAssert) {
|
||||
return mapAssert.isNotEqualTo(
|
||||
Refaster.anyOf(
|
||||
ImmutableMap.of(),
|
||||
ImmutableBiMap.of(),
|
||||
ImmutableSortedMap.of(),
|
||||
new HashMap<>(),
|
||||
new LinkedHashMap<>(),
|
||||
new TreeMap<>()));
|
||||
AbstractMapAssert<?, ?, K, V> before(
|
||||
AbstractMapAssert<?, ?, K, V> mapAssert, @Matches(IsEmpty.class) Map<?, ?> map) {
|
||||
return mapAssert.isNotEqualTo(map);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -148,12 +102,14 @@ final class AssertJMapRules {
|
||||
|
||||
static final class AbstractMapAssertContainsExactlyInAnyOrderEntriesOf<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractMapAssert<?, ?, K, V> before(AbstractMapAssert<?, ?, K, V> mapAssert, Map<K, V> map) {
|
||||
AbstractMapAssert<?, ?, K, V> before(
|
||||
AbstractMapAssert<?, ?, K, V> mapAssert, Map<? extends K, ? extends V> map) {
|
||||
return mapAssert.isEqualTo(map);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
AbstractMapAssert<?, ?, K, V> after(AbstractMapAssert<?, ?, K, V> mapAssert, Map<K, V> map) {
|
||||
AbstractMapAssert<?, ?, K, V> after(
|
||||
AbstractMapAssert<?, ?, K, V> mapAssert, Map<? extends K, ? extends V> map) {
|
||||
return mapAssert.containsExactlyInAnyOrderEntriesOf(map);
|
||||
}
|
||||
}
|
||||
@@ -187,12 +143,12 @@ final class AssertJMapRules {
|
||||
|
||||
static final class AbstractMapAssertHasSameSizeAs<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractMapAssert<?, ?, K, V> before(AbstractMapAssert<?, ?, K, V> mapAssert, Map<K, V> map) {
|
||||
AbstractMapAssert<?, ?, K, V> before(AbstractMapAssert<?, ?, K, V> mapAssert, Map<?, ?> map) {
|
||||
return mapAssert.hasSize(map.size());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
AbstractMapAssert<?, ?, K, V> after(AbstractMapAssert<?, ?, K, V> mapAssert, Map<K, V> map) {
|
||||
AbstractMapAssert<?, ?, K, V> after(AbstractMapAssert<?, ?, K, V> mapAssert, Map<?, ?> map) {
|
||||
return mapAssert.hasSameSizeAs(map);
|
||||
}
|
||||
}
|
||||
@@ -225,13 +181,14 @@ final class AssertJMapRules {
|
||||
|
||||
static final class AssertThatMapContainsOnlyKeys<K, V> {
|
||||
@BeforeTemplate
|
||||
AbstractCollectionAssert<?, Collection<? extends K>, K, ?> before(Map<K, V> map, Set<K> keys) {
|
||||
AbstractCollectionAssert<?, Collection<? extends K>, K, ?> before(
|
||||
Map<K, V> map, Set<? extends K> keys) {
|
||||
return assertThat(map.keySet()).hasSameElementsAs(keys);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
MapAssert<K, V> after(Map<K, V> map, Set<K> keys) {
|
||||
MapAssert<K, V> after(Map<K, V> map, Set<? extends K> keys) {
|
||||
return assertThat(map).containsOnlyKeys(keys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,28 +6,23 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultiset;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMultiset;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Multiset;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Matches;
|
||||
import com.google.errorprone.refaster.annotation.NotMatches;
|
||||
import com.google.errorprone.refaster.annotation.Repeated;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.OptionalLong;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.Stream;
|
||||
@@ -47,6 +42,7 @@ 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;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsEmpty;
|
||||
|
||||
/** Refaster rules related to AssertJ expressions and statements. */
|
||||
// XXX: Most `AbstractIntegerAssert` rules can also be applied for other primitive types. Generate
|
||||
@@ -181,63 +177,16 @@ final class AssertJRules {
|
||||
static final class AssertThatObjectEnumerableIsEmpty<E> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
void before(ObjectEnumerableAssert<?, E> enumAssert) {
|
||||
void before(
|
||||
ObjectEnumerableAssert<?, E> enumAssert,
|
||||
@Matches(IsEmpty.class) Iterable<? extends E> wellTypedIterable,
|
||||
@Matches(IsEmpty.class) Iterable<?> arbitrarilyTypedIterable) {
|
||||
Refaster.anyOf(
|
||||
enumAssert.containsExactlyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(),
|
||||
new ArrayList<>(),
|
||||
ImmutableSet.of(),
|
||||
new HashSet<>(),
|
||||
new LinkedHashSet<>(),
|
||||
ImmutableSortedSet.of(),
|
||||
new TreeSet<>(),
|
||||
ImmutableMultiset.of(),
|
||||
ImmutableSortedMultiset.of())),
|
||||
enumAssert.containsExactlyInAnyOrderElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(),
|
||||
new ArrayList<>(),
|
||||
ImmutableSet.of(),
|
||||
new HashSet<>(),
|
||||
new LinkedHashSet<>(),
|
||||
ImmutableSortedSet.of(),
|
||||
new TreeSet<>(),
|
||||
ImmutableMultiset.of(),
|
||||
ImmutableSortedMultiset.of())),
|
||||
enumAssert.hasSameElementsAs(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(),
|
||||
new ArrayList<>(),
|
||||
ImmutableSet.of(),
|
||||
new HashSet<>(),
|
||||
new LinkedHashSet<>(),
|
||||
ImmutableSortedSet.of(),
|
||||
new TreeSet<>(),
|
||||
ImmutableMultiset.of(),
|
||||
ImmutableSortedMultiset.of())),
|
||||
enumAssert.hasSameSizeAs(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(),
|
||||
new ArrayList<>(),
|
||||
ImmutableSet.of(),
|
||||
new HashSet<>(),
|
||||
new LinkedHashSet<>(),
|
||||
ImmutableSortedSet.of(),
|
||||
new TreeSet<>(),
|
||||
ImmutableMultiset.of(),
|
||||
ImmutableSortedMultiset.of())),
|
||||
enumAssert.isSubsetOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(),
|
||||
new ArrayList<>(),
|
||||
ImmutableSet.of(),
|
||||
new HashSet<>(),
|
||||
new LinkedHashSet<>(),
|
||||
ImmutableSortedSet.of(),
|
||||
new TreeSet<>(),
|
||||
ImmutableMultiset.of(),
|
||||
ImmutableSortedMultiset.of())),
|
||||
enumAssert.containsExactlyElementsOf(wellTypedIterable),
|
||||
enumAssert.containsExactlyInAnyOrderElementsOf(wellTypedIterable),
|
||||
enumAssert.hasSameElementsAs(wellTypedIterable),
|
||||
enumAssert.hasSameSizeAs(arbitrarilyTypedIterable),
|
||||
enumAssert.isSubsetOf(wellTypedIterable),
|
||||
enumAssert.containsExactly(),
|
||||
enumAssert.containsExactlyInAnyOrder(),
|
||||
enumAssert.containsOnly(),
|
||||
|
||||
@@ -2,6 +2,7 @@ package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.AlsoNegation;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import java.math.BigDecimal;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
@@ -66,4 +67,61 @@ final class BigDecimalRules {
|
||||
return BigDecimal.valueOf(value);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer using {@link BigDecimal#signum()} over more contrived alternatives. */
|
||||
static final class BigDecimalSignumIsZero {
|
||||
@BeforeTemplate
|
||||
boolean before(BigDecimal value) {
|
||||
return Refaster.anyOf(
|
||||
value.compareTo(BigDecimal.ZERO) == 0, BigDecimal.ZERO.compareTo(value) == 0);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(BigDecimal value) {
|
||||
return value.signum() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer a {@link BigDecimal#signum()} comparison to 1 over more contrived or less clear
|
||||
* alternatives.
|
||||
*/
|
||||
static final class BigDecimalSignumIsPositive {
|
||||
@BeforeTemplate
|
||||
boolean before(BigDecimal value) {
|
||||
return Refaster.anyOf(
|
||||
value.compareTo(BigDecimal.ZERO) > 0,
|
||||
BigDecimal.ZERO.compareTo(value) < 0,
|
||||
value.signum() > 0,
|
||||
value.signum() >= 1);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(BigDecimal value) {
|
||||
return value.signum() == 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer a {@link BigDecimal#signum()} comparison to -1 over more contrived or less clear
|
||||
* alternatives.
|
||||
*/
|
||||
static final class BigDecimalSignumIsNegative {
|
||||
@BeforeTemplate
|
||||
boolean before(BigDecimal value) {
|
||||
return Refaster.anyOf(
|
||||
value.compareTo(BigDecimal.ZERO) < 0,
|
||||
BigDecimal.ZERO.compareTo(value) > 0,
|
||||
value.signum() < 0,
|
||||
value.signum() <= -1);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(BigDecimal value) {
|
||||
return value.signum() == -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.sun.tools.javac.util.Constants;
|
||||
import com.sun.tools.javac.util.Convert;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/** Refaster rules related to {@link com.google.errorprone.bugpatterns.BugChecker} classes. */
|
||||
@@ -52,4 +54,17 @@ final class BugCheckerRules {
|
||||
return helper.addInputLines(path, source).expectUnchanged();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer using the {@link Constants} API over more verbose alternatives. */
|
||||
static final class ConstantsFormat {
|
||||
@BeforeTemplate
|
||||
String before(String value) {
|
||||
return String.format("\"%s\"", Convert.quote(value));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(String value) {
|
||||
return Constants.format(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import static java.util.Comparator.comparingInt;
|
||||
import static java.util.Comparator.comparingLong;
|
||||
import static java.util.Comparator.naturalOrder;
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
import static java.util.function.Function.identity;
|
||||
|
||||
import com.google.common.collect.Comparators;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -16,6 +15,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Matches;
|
||||
import com.google.errorprone.refaster.annotation.Repeated;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.Arrays;
|
||||
@@ -28,6 +28,7 @@ import java.util.function.ToIntFunction;
|
||||
import java.util.function.ToLongFunction;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsIdentityOperation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with {@link Comparator}s. */
|
||||
@OnlineDocumentation
|
||||
@@ -36,12 +37,12 @@ final class ComparatorRules {
|
||||
|
||||
/** Prefer {@link Comparator#naturalOrder()} over more complicated constructs. */
|
||||
static final class NaturalOrder<T extends Comparable<? super T>> {
|
||||
// XXX: Drop the `Refaster.anyOf` if/when we decide to rewrite one to the other.
|
||||
@BeforeTemplate
|
||||
Comparator<T> before() {
|
||||
Comparator<T> before(
|
||||
@Matches(IsIdentityOperation.class) Function<? super T, ? extends T> keyExtractor) {
|
||||
return Refaster.anyOf(
|
||||
T::compareTo,
|
||||
comparing(Refaster.anyOf(identity(), v -> v)),
|
||||
comparing(keyExtractor),
|
||||
Collections.<T>reverseOrder(reverseOrder()),
|
||||
Comparator.<T>reverseOrder().reversed());
|
||||
}
|
||||
@@ -72,10 +73,11 @@ final class ComparatorRules {
|
||||
}
|
||||
|
||||
static final class CustomComparator<T> {
|
||||
// XXX: Drop the `Refaster.anyOf` if/when we decide to rewrite one to the other.
|
||||
@BeforeTemplate
|
||||
Comparator<T> before(Comparator<T> cmp) {
|
||||
return comparing(Refaster.anyOf(identity(), v -> v), cmp);
|
||||
Comparator<T> before(
|
||||
Comparator<T> cmp,
|
||||
@Matches(IsIdentityOperation.class) Function<? super T, ? extends T> keyExtractor) {
|
||||
return comparing(keyExtractor, cmp);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -183,14 +185,15 @@ final class ComparatorRules {
|
||||
}
|
||||
|
||||
/**
|
||||
* Where applicable, prefer {@link Comparator#naturalOrder()} over {@link Function#identity()}, as
|
||||
* it more clearly states intent.
|
||||
* Where applicable, prefer {@link Comparator#naturalOrder()} over identity function-based
|
||||
* comparisons, as the former more clearly states intent.
|
||||
*/
|
||||
static final class ThenComparingNaturalOrder<T extends Comparable<? super T>> {
|
||||
// XXX: Drop the `Refaster.anyOf` if/when we decide to rewrite one to the other.
|
||||
@BeforeTemplate
|
||||
Comparator<T> before(Comparator<T> cmp) {
|
||||
return cmp.thenComparing(Refaster.anyOf(identity(), v -> v));
|
||||
Comparator<T> before(
|
||||
Comparator<T> cmp,
|
||||
@Matches(IsIdentityOperation.class) Function<? super T, ? extends T> keyExtractor) {
|
||||
return cmp.thenComparing(keyExtractor);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
|
||||
@@ -3,7 +3,6 @@ package tech.picnic.errorprone.refasterrules;
|
||||
import static com.google.common.collect.ImmutableListMultimap.flatteningToImmutableListMultimap;
|
||||
import static com.google.common.collect.ImmutableListMultimap.toImmutableListMultimap;
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static java.util.function.Function.identity;
|
||||
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
@@ -16,6 +15,7 @@ import com.google.common.collect.Streams;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Matches;
|
||||
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
|
||||
import com.google.errorprone.refaster.annotation.Placeholder;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
@@ -25,6 +25,7 @@ import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsIdentityOperation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with {@link ImmutableListMultimap}s. */
|
||||
@OnlineDocumentation
|
||||
@@ -173,27 +174,29 @@ final class ImmutableListMultimapRules {
|
||||
* Prefer {@link Multimaps#index(Iterable, com.google.common.base.Function)} over the stream-based
|
||||
* alternative.
|
||||
*/
|
||||
// XXX: Drop the `Refaster.anyOf` if/when we decide to rewrite one to the other.
|
||||
static final class IndexIterableToImmutableListMultimap<K, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableListMultimap<K, V> before(
|
||||
Iterator<V> iterable, Function<? super V, ? extends K> keyFunction) {
|
||||
return Streams.stream(iterable)
|
||||
.collect(toImmutableListMultimap(keyFunction, Refaster.anyOf(identity(), v -> v)));
|
||||
Iterator<V> iterable,
|
||||
Function<? super V, ? extends K> keyFunction,
|
||||
@Matches(IsIdentityOperation.class) Function<? super V, ? extends V> valueFunction) {
|
||||
return Streams.stream(iterable).collect(toImmutableListMultimap(keyFunction, valueFunction));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
ImmutableListMultimap<K, V> before(
|
||||
Iterable<V> iterable, Function<? super V, ? extends K> keyFunction) {
|
||||
return Streams.stream(iterable)
|
||||
.collect(toImmutableListMultimap(keyFunction, Refaster.anyOf(identity(), v -> v)));
|
||||
Iterable<V> iterable,
|
||||
Function<? super V, ? extends K> keyFunction,
|
||||
@Matches(IsIdentityOperation.class) Function<? super V, ? extends V> valueFunction) {
|
||||
return Streams.stream(iterable).collect(toImmutableListMultimap(keyFunction, valueFunction));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
ImmutableListMultimap<K, V> before(
|
||||
Collection<V> iterable, Function<? super V, ? extends K> keyFunction) {
|
||||
return iterable.stream()
|
||||
.collect(toImmutableListMultimap(keyFunction, Refaster.anyOf(identity(), v -> v)));
|
||||
Collection<V> iterable,
|
||||
Function<? super V, ? extends K> keyFunction,
|
||||
@Matches(IsIdentityOperation.class) Function<? super V, ? extends V> valueFunction) {
|
||||
return iterable.stream().collect(toImmutableListMultimap(keyFunction, valueFunction));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
|
||||
@@ -4,7 +4,6 @@ import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static java.util.function.Function.identity;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@@ -13,6 +12,7 @@ import com.google.common.collect.Streams;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Matches;
|
||||
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
|
||||
import com.google.errorprone.refaster.annotation.Placeholder;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
@@ -23,6 +23,7 @@ import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsIdentityOperation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with {@link ImmutableMap}s. */
|
||||
@OnlineDocumentation
|
||||
@@ -63,27 +64,29 @@ final class ImmutableMapRules {
|
||||
* Prefer {@link Maps#toMap(Iterable, com.google.common.base.Function)} over more contrived
|
||||
* alternatives.
|
||||
*/
|
||||
// XXX: Drop the `Refaster.anyOf` if/when we decide to rewrite one to the other.
|
||||
static final class IterableToImmutableMap<K, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableMap<K, V> before(
|
||||
Iterator<K> iterable, Function<? super K, ? extends V> valueFunction) {
|
||||
return Streams.stream(iterable)
|
||||
.collect(toImmutableMap(Refaster.anyOf(identity(), k -> k), valueFunction));
|
||||
Iterator<K> iterable,
|
||||
Function<? super K, ? extends V> valueFunction,
|
||||
@Matches(IsIdentityOperation.class) Function<? super K, ? extends K> keyFunction) {
|
||||
return Streams.stream(iterable).collect(toImmutableMap(keyFunction, valueFunction));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
ImmutableMap<K, V> before(
|
||||
Iterable<K> iterable, Function<? super K, ? extends V> valueFunction) {
|
||||
return Streams.stream(iterable)
|
||||
.collect(toImmutableMap(Refaster.anyOf(identity(), k -> k), valueFunction));
|
||||
Iterable<K> iterable,
|
||||
Function<? super K, ? extends V> valueFunction,
|
||||
@Matches(IsIdentityOperation.class) Function<? super K, ? extends K> keyFunction) {
|
||||
return Streams.stream(iterable).collect(toImmutableMap(keyFunction, valueFunction));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
ImmutableMap<K, V> before(
|
||||
Collection<K> iterable, Function<? super K, ? extends V> valueFunction) {
|
||||
return iterable.stream()
|
||||
.collect(toImmutableMap(Refaster.anyOf(identity(), k -> k), valueFunction));
|
||||
Collection<K> iterable,
|
||||
Function<? super K, ? extends V> valueFunction,
|
||||
@Matches(IsIdentityOperation.class) Function<? super K, ? extends K> keyFunction) {
|
||||
return iterable.stream().collect(toImmutableMap(keyFunction, valueFunction));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
@@ -157,25 +160,29 @@ final class ImmutableMapRules {
|
||||
* Prefer {@link Maps#uniqueIndex(Iterable, com.google.common.base.Function)} over the
|
||||
* stream-based alternative.
|
||||
*/
|
||||
// XXX: Drop the `Refaster.anyOf` if/when we decide to rewrite one to the other.
|
||||
static final class IndexIterableToImmutableMap<K, V> {
|
||||
@BeforeTemplate
|
||||
ImmutableMap<K, V> before(Iterator<V> iterable, Function<? super V, ? extends K> keyFunction) {
|
||||
return Streams.stream(iterable)
|
||||
.collect(toImmutableMap(keyFunction, Refaster.anyOf(identity(), v -> v)));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
ImmutableMap<K, V> before(Iterable<V> iterable, Function<? super V, ? extends K> keyFunction) {
|
||||
return Streams.stream(iterable)
|
||||
.collect(toImmutableMap(keyFunction, Refaster.anyOf(identity(), v -> v)));
|
||||
ImmutableMap<K, V> before(
|
||||
Iterator<V> iterable,
|
||||
Function<? super V, ? extends K> keyFunction,
|
||||
@Matches(IsIdentityOperation.class) Function<? super V, ? extends V> valueFunction) {
|
||||
return Streams.stream(iterable).collect(toImmutableMap(keyFunction, valueFunction));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
ImmutableMap<K, V> before(
|
||||
Collection<V> iterable, Function<? super V, ? extends K> keyFunction) {
|
||||
return iterable.stream()
|
||||
.collect(toImmutableMap(keyFunction, Refaster.anyOf(identity(), v -> v)));
|
||||
Iterable<V> iterable,
|
||||
Function<? super V, ? extends K> keyFunction,
|
||||
@Matches(IsIdentityOperation.class) Function<? super V, ? extends V> valueFunction) {
|
||||
return Streams.stream(iterable).collect(toImmutableMap(keyFunction, valueFunction));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
ImmutableMap<K, V> before(
|
||||
Collection<V> iterable,
|
||||
Function<? super V, ? extends K> keyFunction,
|
||||
@Matches(IsIdentityOperation.class) Function<? super V, ? extends V> valueFunction) {
|
||||
return iterable.stream().collect(toImmutableMap(keyFunction, valueFunction));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
|
||||
@@ -6,6 +6,7 @@ import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
@@ -517,4 +518,82 @@ final class JUnitToAssertJRules {
|
||||
assertThat(actual).withFailMessage(supplier).isInstanceOf(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatByteIsEqualTo {
|
||||
@BeforeTemplate
|
||||
void before(byte actual, byte expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(byte actual, byte expected) {
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatByteWithFailMessageStringIsEqualTo {
|
||||
@BeforeTemplate
|
||||
void before(byte actual, byte expected, String message) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(byte actual, byte expected, String message) {
|
||||
assertThat(actual).withFailMessage(message).isEqualTo(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatByteWithFailMessageSupplierIsEqualTo {
|
||||
@BeforeTemplate
|
||||
void before(byte actual, byte expected, Supplier<String> message) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(byte actual, byte expected, Supplier<String> message) {
|
||||
assertThat(actual).withFailMessage(message).isEqualTo(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatCharIsEqualTo {
|
||||
@BeforeTemplate
|
||||
void before(char actual, char expected) {
|
||||
assertEquals(actual, expected);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(char actual, char expected) {
|
||||
assertThat(actual).isEqualTo(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatCharWithFailMessageStringIsEqualTo {
|
||||
@BeforeTemplate
|
||||
void before(char actual, char expected, String message) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(char actual, char expected, String message) {
|
||||
assertThat(actual).withFailMessage(message).isEqualTo(expected);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatCharWithFailMessageSupplierIsEqualTo {
|
||||
@BeforeTemplate
|
||||
void before(char actual, char expected, Supplier<String> message) {
|
||||
assertEquals(actual, expected, message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(char actual, char expected, Supplier<String> message) {
|
||||
assertThat(actual).withFailMessage(message).isEqualTo(expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ import com.google.common.primitives.Floats;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
import com.google.common.primitives.Shorts;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.AlsoNegation;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
@@ -384,4 +386,60 @@ final class PrimitiveRules {
|
||||
return Double.isFinite(d);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer an {@link Integer#signum(int)} comparison to 1 over less clear alternatives. */
|
||||
static final class IntegerSignumIsPositive {
|
||||
@BeforeTemplate
|
||||
boolean before(int i) {
|
||||
return Refaster.anyOf(Integer.signum(i) > 0, Integer.signum(i) >= 1);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(int i) {
|
||||
return Integer.signum(i) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer an {@link Integer#signum(int)} comparison to -1 over less clear alternatives. */
|
||||
static final class IntegerSignumIsNegative {
|
||||
@BeforeTemplate
|
||||
boolean before(int i) {
|
||||
return Refaster.anyOf(Integer.signum(i) < 0, Integer.signum(i) <= -1);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(int i) {
|
||||
return Integer.signum(i) == -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer an {@link Long#signum(long)} comparison to 1 over less clear alternatives. */
|
||||
static final class LongSignumIsPositive {
|
||||
@BeforeTemplate
|
||||
boolean before(long l) {
|
||||
return Refaster.anyOf(Long.signum(l) > 0, Long.signum(l) >= 1);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(long l) {
|
||||
return Long.signum(l) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer an {@link Long#signum(long)} comparison to -1 over less clear alternatives. */
|
||||
static final class LongSignumIsNegative {
|
||||
@BeforeTemplate
|
||||
boolean before(long l) {
|
||||
return Refaster.anyOf(Long.signum(l) < 0, Long.signum(l) <= -1);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(long l) {
|
||||
return Long.signum(l) == -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@ import static reactor.function.TupleUtils.function;
|
||||
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Matches;
|
||||
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
|
||||
import com.google.errorprone.refaster.annotation.NotMatches;
|
||||
import com.google.errorprone.refaster.annotation.Placeholder;
|
||||
@@ -26,8 +26,8 @@ import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.BiConsumer;
|
||||
@@ -48,6 +48,8 @@ import reactor.util.function.Tuple2;
|
||||
import tech.picnic.errorprone.refaster.annotation.Description;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.annotation.Severity;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsEmpty;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsIdentityOperation;
|
||||
import tech.picnic.errorprone.refaster.matchers.ThrowsCheckedException;
|
||||
|
||||
/** Refaster rules related to Reactor expressions and statements. */
|
||||
@@ -508,7 +510,8 @@ final class ReactorRules {
|
||||
}
|
||||
|
||||
// XXX: Replace this rule with an extension of the `IdentityConversion` rule, supporting
|
||||
// `Stream#map`, `Mono#map` and `Flux#map`.
|
||||
// `Stream#map`, `Mono#map` and `Flux#map`. Alternatively, extend the `IsIdentityOperation`
|
||||
// matcher and use it to constrain the matched `map` argument.
|
||||
@BeforeTemplate
|
||||
Mono<ImmutableList<T>> before3(Mono<ImmutableList<T>> mono) {
|
||||
return mono.map(ImmutableList::copyOf);
|
||||
@@ -549,51 +552,59 @@ final class ReactorRules {
|
||||
}
|
||||
|
||||
/** Prefer {@link Flux#concatMap(Function)} over more contrived alternatives. */
|
||||
static final class FluxConcatMap<T, S> {
|
||||
static final class FluxConcatMap<T, S, P extends Publisher<? extends S>> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedPublishers")
|
||||
Flux<S> before(Flux<T> flux, Function<? super T, ? extends Publisher<? extends S>> function) {
|
||||
Flux<S> before(
|
||||
Flux<T> flux,
|
||||
Function<? super T, ? extends P> function,
|
||||
@Matches(IsIdentityOperation.class)
|
||||
Function<? super P, ? extends Publisher<? extends S>> identityOperation) {
|
||||
return Refaster.anyOf(
|
||||
flux.flatMap(function, 1),
|
||||
flux.flatMapSequential(function, 1),
|
||||
flux.map(function).concatMap(identity()));
|
||||
flux.map(function).concatMap(identityOperation));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<S> after(Flux<T> flux, Function<? super T, ? extends Publisher<? extends S>> function) {
|
||||
Flux<S> after(Flux<T> flux, Function<? super T, ? extends P> function) {
|
||||
return flux.concatMap(function);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Flux#concatMap(Function, int)} over more contrived alternatives. */
|
||||
static final class FluxConcatMapWithPrefetch<T, S> {
|
||||
static final class FluxConcatMapWithPrefetch<T, S, P extends Publisher<? extends S>> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedPublishers")
|
||||
Flux<S> before(
|
||||
Flux<T> flux,
|
||||
Function<? super T, ? extends Publisher<? extends S>> function,
|
||||
int prefetch) {
|
||||
Function<? super T, ? extends P> function,
|
||||
int prefetch,
|
||||
@Matches(IsIdentityOperation.class)
|
||||
Function<? super P, ? extends Publisher<? extends S>> identityOperation) {
|
||||
return Refaster.anyOf(
|
||||
flux.flatMap(function, 1, prefetch),
|
||||
flux.flatMapSequential(function, 1, prefetch),
|
||||
flux.map(function).concatMap(identity(), prefetch));
|
||||
flux.map(function).concatMap(identityOperation, prefetch));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<S> after(
|
||||
Flux<T> flux,
|
||||
Function<? super T, ? extends Publisher<? extends S>> function,
|
||||
int prefetch) {
|
||||
Flux<S> after(Flux<T> flux, Function<? super T, ? extends P> function, int prefetch) {
|
||||
return flux.concatMap(function, prefetch);
|
||||
}
|
||||
}
|
||||
|
||||
/** Avoid contrived alternatives to {@link Mono#flatMapIterable(Function)}. */
|
||||
static final class MonoFlatMapIterable<T, S> {
|
||||
static final class MonoFlatMapIterable<T, S, I extends Iterable<? extends S>> {
|
||||
@BeforeTemplate
|
||||
Flux<S> before(Mono<T> mono, Function<? super T, ? extends Iterable<? extends S>> function) {
|
||||
Flux<S> before(
|
||||
Mono<T> mono,
|
||||
Function<? super T, I> function,
|
||||
@Matches(IsIdentityOperation.class)
|
||||
Function<? super I, ? extends Iterable<? extends S>> identityOperation) {
|
||||
return Refaster.anyOf(
|
||||
mono.map(function).flatMapIterable(identity()), mono.flux().concatMapIterable(function));
|
||||
mono.map(function).flatMapIterable(identityOperation),
|
||||
mono.flux().concatMapIterable(function));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -623,11 +634,15 @@ final class ReactorRules {
|
||||
* Prefer {@link Flux#concatMapIterable(Function)} over alternatives with less clear syntax or
|
||||
* semantics.
|
||||
*/
|
||||
static final class FluxConcatMapIterable<T, S> {
|
||||
static final class FluxConcatMapIterable<T, S, I extends Iterable<? extends S>> {
|
||||
@BeforeTemplate
|
||||
Flux<S> before(Flux<T> flux, Function<? super T, ? extends Iterable<? extends S>> function) {
|
||||
Flux<S> before(
|
||||
Flux<T> flux,
|
||||
Function<? super T, I> function,
|
||||
@Matches(IsIdentityOperation.class)
|
||||
Function<? super I, ? extends Iterable<? extends S>> identityOperation) {
|
||||
return Refaster.anyOf(
|
||||
flux.flatMapIterable(function), flux.map(function).concatMapIterable(identity()));
|
||||
flux.flatMapIterable(function), flux.map(function).concatMapIterable(identityOperation));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -640,13 +655,17 @@ final class ReactorRules {
|
||||
* Prefer {@link Flux#concatMapIterable(Function, int)} over alternatives with less clear syntax
|
||||
* or semantics.
|
||||
*/
|
||||
static final class FluxConcatMapIterableWithPrefetch<T, S> {
|
||||
static final class FluxConcatMapIterableWithPrefetch<T, S, I extends Iterable<? extends S>> {
|
||||
@BeforeTemplate
|
||||
Flux<S> before(
|
||||
Flux<T> flux, Function<? super T, ? extends Iterable<? extends S>> function, int prefetch) {
|
||||
Flux<T> flux,
|
||||
Function<? super T, I> function,
|
||||
int prefetch,
|
||||
@Matches(IsIdentityOperation.class)
|
||||
Function<? super I, ? extends Iterable<? extends S>> identityOperation) {
|
||||
return Refaster.anyOf(
|
||||
flux.flatMapIterable(function, prefetch),
|
||||
flux.map(function).concatMapIterable(identity(), prefetch));
|
||||
flux.map(function).concatMapIterable(identityOperation, prefetch));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -1080,31 +1099,37 @@ final class ReactorRules {
|
||||
}
|
||||
|
||||
/** Prefer {@link Mono#flatMap(Function)} over more contrived alternatives. */
|
||||
static final class MonoFlatMap<S, T> {
|
||||
static final class MonoFlatMap<S, T, P extends Mono<? extends T>> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedPublishers")
|
||||
Mono<T> before(Mono<S> mono, Function<? super S, ? extends Mono<? extends T>> function) {
|
||||
return mono.map(function).flatMap(identity());
|
||||
Mono<T> before(
|
||||
Mono<S> mono,
|
||||
Function<? super S, ? extends P> function,
|
||||
@Matches(IsIdentityOperation.class)
|
||||
Function<? super P, ? extends Mono<? extends T>> identityOperation) {
|
||||
return mono.map(function).flatMap(identityOperation);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(Mono<S> mono, Function<? super S, ? extends Mono<? extends T>> function) {
|
||||
Mono<T> after(Mono<S> mono, Function<? super S, ? extends P> function) {
|
||||
return mono.flatMap(function);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Mono#flatMapMany(Function)} over more contrived alternatives. */
|
||||
static final class MonoFlatMapMany<S, T> {
|
||||
static final class MonoFlatMapMany<S, T, P extends Publisher<? extends T>> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedPublishers")
|
||||
Flux<T> before(
|
||||
Mono<S> mono,
|
||||
Function<? super S, ? extends Publisher<? extends T>> function,
|
||||
Function<? super S, P> function,
|
||||
@Matches(IsIdentityOperation.class)
|
||||
Function<? super P, ? extends Publisher<? extends T>> identityOperation,
|
||||
boolean delayUntilEnd,
|
||||
int maxConcurrency,
|
||||
int prefetch) {
|
||||
return Refaster.anyOf(
|
||||
mono.map(function).flatMapMany(identity()),
|
||||
mono.map(function).flatMapMany(identityOperation),
|
||||
mono.flux().concatMap(function),
|
||||
mono.flux().concatMap(function, prefetch),
|
||||
mono.flux().concatMapDelayError(function),
|
||||
@@ -1124,7 +1149,7 @@ final class ReactorRules {
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<T> after(Mono<S> mono, Function<? super S, ? extends Publisher<? extends T>> function) {
|
||||
Flux<T> after(Mono<S> mono, Function<? super S, ? extends P> function) {
|
||||
return mono.flatMapMany(function);
|
||||
}
|
||||
}
|
||||
@@ -1555,12 +1580,12 @@ final class ReactorRules {
|
||||
}
|
||||
|
||||
/** Prefer {@link reactor.util.context.Context#empty()}} over more verbose alternatives. */
|
||||
// XXX: Consider introducing an `IsEmpty` matcher that identifies a wide range of guaranteed-empty
|
||||
// `Collection` and `Map` expressions.
|
||||
// XXX: Introduce Refaster rules or a `BugChecker` that maps `(Immutable)Map.of(k, v)` to
|
||||
// `Context.of(k, v)` and likewise for multi-pair overloads.
|
||||
static final class ContextEmpty {
|
||||
@BeforeTemplate
|
||||
Context before() {
|
||||
return Context.of(Refaster.anyOf(new HashMap<>(), ImmutableMap.of()));
|
||||
Context before(@Matches(IsEmpty.class) Map<?, ?> map) {
|
||||
return Context.of(map);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -1609,13 +1634,13 @@ final class ReactorRules {
|
||||
}
|
||||
|
||||
/** Don't unnecessarily have {@link StepVerifier.Step} expect no elements. */
|
||||
// XXX: Given an `IsEmpty` matcher that identifies a wide range of guaranteed-empty `Iterable`
|
||||
// expressions, consider also simplifying `step.expectNextSequence(someEmptyIterable)`.
|
||||
static final class StepVerifierStepIdentity<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
StepVerifier.Step<T> before(StepVerifier.Step<T> step) {
|
||||
return Refaster.anyOf(step.expectNext(), step.expectNextCount(0));
|
||||
StepVerifier.Step<T> before(
|
||||
StepVerifier.Step<T> step, @Matches(IsEmpty.class) Iterable<? extends T> iterable) {
|
||||
return Refaster.anyOf(
|
||||
step.expectNext(), step.expectNextCount(0), step.expectNextSequence(iterable));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
|
||||
@@ -3,7 +3,6 @@ package tech.picnic.errorprone.refasterrules;
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static java.util.Comparator.naturalOrder;
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
import static java.util.function.Function.identity;
|
||||
import static java.util.function.Predicate.not;
|
||||
import static java.util.stream.Collectors.counting;
|
||||
import static java.util.stream.Collectors.filtering;
|
||||
@@ -51,6 +50,7 @@ import java.util.stream.Collector;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsIdentityOperation;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsLambdaExpressionOrMethodReference;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsRefasterAsVarargs;
|
||||
|
||||
@@ -357,6 +357,8 @@ final class StreamRules {
|
||||
stream.filter(predicate).findAny().isEmpty());
|
||||
}
|
||||
|
||||
// XXX: Consider extending `@Matches(IsIdentityOperation.class)` such that it can replace this
|
||||
// template's `Refaster.anyOf` usage.
|
||||
@BeforeTemplate
|
||||
boolean before2(
|
||||
Stream<T> stream,
|
||||
@@ -395,6 +397,8 @@ final class StreamRules {
|
||||
!stream.noneMatch(predicate), stream.filter(predicate).findAny().isPresent());
|
||||
}
|
||||
|
||||
// XXX: Consider extending `@Matches(IsIdentityOperation.class)` such that it can replace this
|
||||
// template's `Refaster.anyOf` usage.
|
||||
@BeforeTemplate
|
||||
boolean before2(
|
||||
Stream<T> stream,
|
||||
@@ -415,6 +419,8 @@ final class StreamRules {
|
||||
return stream.noneMatch(Refaster.anyOf(not(predicate), predicate.negate()));
|
||||
}
|
||||
|
||||
// XXX: Consider extending `@Matches(IsIdentityOperation.class)` such that it can replace this
|
||||
// template's `Refaster.anyOf` usage.
|
||||
@BeforeTemplate
|
||||
boolean before2(
|
||||
Stream<T> stream,
|
||||
@@ -632,8 +638,11 @@ final class StreamRules {
|
||||
|
||||
static final class StreamsConcat<T> {
|
||||
@BeforeTemplate
|
||||
Stream<T> before(@Repeated Stream<T> stream) {
|
||||
return Stream.of(Refaster.asVarargs(stream)).flatMap(Refaster.anyOf(identity(), s -> s));
|
||||
Stream<T> before(
|
||||
@Repeated Stream<T> stream,
|
||||
@Matches(IsIdentityOperation.class)
|
||||
Function<? super Stream<T>, ? extends Stream<? extends T>> mapper) {
|
||||
return Stream.of(Refaster.asVarargs(stream)).flatMap(mapper);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class JUnitNullaryParameterizedTestDeclarationTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(JUnitNullaryParameterizedTestDeclaration.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"import org.junit.jupiter.params.provider.ValueSource;",
|
||||
"",
|
||||
"class A {",
|
||||
" void nonTest() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void nonParameterizedTest() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(ints = {0, 1})",
|
||||
" void goodParameterizedTest(int someInt) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(ints = {0, 1})",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" void nullaryParameterizedTest() {}",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(
|
||||
JUnitNullaryParameterizedTestDeclaration.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"import org.junit.jupiter.params.provider.ArgumentsProvider;",
|
||||
"import org.junit.jupiter.params.provider.ArgumentsSource;",
|
||||
"import org.junit.jupiter.params.provider.ArgumentsSources;",
|
||||
"import org.junit.jupiter.params.provider.MethodSource;",
|
||||
"import org.junit.jupiter.params.provider.ValueSource;",
|
||||
"",
|
||||
"class A {",
|
||||
" @ParameterizedTest",
|
||||
" void withoutArgumentSource() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ArgumentsSource(ArgumentsProvider.class)",
|
||||
" void withCustomArgumentSource() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ArgumentsSources({",
|
||||
" @ArgumentsSource(ArgumentsProvider.class),",
|
||||
" @ArgumentsSource(ArgumentsProvider.class)",
|
||||
" })",
|
||||
" void withCustomerArgumentSources() {}",
|
||||
"",
|
||||
" /** Foo. */",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(ints = {0, 1})",
|
||||
" void withValueSourceAndJavadoc() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"nonexistentMethod\")",
|
||||
" @SuppressWarnings(\"foo\")",
|
||||
" void withMethodSourceAndUnrelatedAnnotation() {}",
|
||||
"",
|
||||
" @org.junit.jupiter.params.ParameterizedTest",
|
||||
" @ArgumentsSource(ArgumentsProvider.class)",
|
||||
" @ValueSource(ints = {0, 1})",
|
||||
" @MethodSource(\"nonexistentMethod\")",
|
||||
" void withMultipleArgumentSourcesAndFullyQualifiedImport() {}",
|
||||
"",
|
||||
" class NestedWithTestAnnotationFirst {",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(ints = {0, 1})",
|
||||
" void withValueSource() {}",
|
||||
" }",
|
||||
"",
|
||||
" class NestedWithTestAnnotationSecond {",
|
||||
" @ValueSource(ints = {0, 1})",
|
||||
" @ParameterizedTest",
|
||||
" void withValueSource() {}",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"import org.junit.jupiter.params.provider.ArgumentsProvider;",
|
||||
"import org.junit.jupiter.params.provider.ArgumentsSource;",
|
||||
"import org.junit.jupiter.params.provider.ArgumentsSources;",
|
||||
"import org.junit.jupiter.params.provider.MethodSource;",
|
||||
"import org.junit.jupiter.params.provider.ValueSource;",
|
||||
"",
|
||||
"class A {",
|
||||
" @Test",
|
||||
" void withoutArgumentSource() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void withCustomArgumentSource() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void withCustomerArgumentSources() {}",
|
||||
"",
|
||||
" /** Foo. */",
|
||||
" @Test",
|
||||
" void withValueSourceAndJavadoc() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" @SuppressWarnings(\"foo\")",
|
||||
" void withMethodSourceAndUnrelatedAnnotation() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void withMultipleArgumentSourcesAndFullyQualifiedImport() {}",
|
||||
"",
|
||||
" class NestedWithTestAnnotationFirst {",
|
||||
" @Test",
|
||||
" void withValueSource() {}",
|
||||
" }",
|
||||
"",
|
||||
" class NestedWithTestAnnotationSecond {",
|
||||
" @Test",
|
||||
" void withValueSource() {}",
|
||||
" }",
|
||||
"}")
|
||||
.addInputLines(
|
||||
"B.java",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"",
|
||||
"class B {",
|
||||
" @ParameterizedTest",
|
||||
" void scopeInWhichIdentifierTestIsAlreadyDeclared() {}",
|
||||
"",
|
||||
" class Test {}",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"B.java",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"",
|
||||
"class B {",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" void scopeInWhichIdentifierTestIsAlreadyDeclared() {}",
|
||||
"",
|
||||
" class Test {}",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class NonStaticImportTest {
|
||||
@Test
|
||||
void candidateTypesDoNotClash() {
|
||||
assertThat(NonStaticImport.NON_STATIC_IMPORT_CANDIDATE_TYPES)
|
||||
.doesNotContainAnyElementsOf(StaticImport.STATIC_IMPORT_CANDIDATE_TYPES);
|
||||
}
|
||||
|
||||
@Test
|
||||
void candidateMembersAreNotRedundant() {
|
||||
assertThat(NonStaticImport.NON_STATIC_IMPORT_CANDIDATE_MEMBERS.keySet())
|
||||
.doesNotContainAnyElementsOf(NonStaticImport.NON_STATIC_IMPORT_CANDIDATE_TYPES);
|
||||
|
||||
assertThat(NonStaticImport.NON_STATIC_IMPORT_CANDIDATE_MEMBERS.values())
|
||||
.doesNotContainAnyElementsOf(NonStaticImport.NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS);
|
||||
}
|
||||
|
||||
@Test
|
||||
void candidateMembersDoNotClash() {
|
||||
assertThat(NonStaticImport.NON_STATIC_IMPORT_CANDIDATE_MEMBERS.entries())
|
||||
.doesNotContainAnyElementsOf(StaticImport.STATIC_IMPORT_CANDIDATE_MEMBERS.entries());
|
||||
}
|
||||
|
||||
@Test
|
||||
void candidateIdentifiersDoNotClash() {
|
||||
assertThat(NonStaticImport.NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS)
|
||||
.doesNotContainAnyElementsOf(StaticImport.STATIC_IMPORT_CANDIDATE_MEMBERS.values());
|
||||
}
|
||||
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(NonStaticImport.class, getClass())
|
||||
.addSourceLines(
|
||||
"pkg/A.java",
|
||||
"package pkg;",
|
||||
"",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static com.google.common.base.Strings.nullToEmpty;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static com.google.common.collect.ImmutableList.copyOf;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.lang.Integer.MAX_VALUE;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.lang.Integer.MIN_VALUE;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.time.Clock.systemUTC;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.time.Instant.MIN;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.time.ZoneOffset.SHORT_IDS;",
|
||||
"import static java.time.ZoneOffset.UTC;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.util.Collections.min;",
|
||||
"import static java.util.Locale.ENGLISH;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.util.Locale.ROOT;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.util.Optional.empty;",
|
||||
"import static pkg.A.WithMethodThatIsSelectivelyFlagged.list;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.time.Instant;",
|
||||
"import java.time.ZoneOffset;",
|
||||
"import java.util.Locale;",
|
||||
"import java.util.Map;",
|
||||
"import pkg.A.Wrapper.ZERO;",
|
||||
"",
|
||||
"class A {",
|
||||
" private Integer MIN_VALUE = 12;",
|
||||
"",
|
||||
" void m() {",
|
||||
" nullToEmpty(null);",
|
||||
" copyOf(ImmutableList.of());",
|
||||
" int max = MAX_VALUE;",
|
||||
" int min = MIN_VALUE;",
|
||||
" systemUTC();",
|
||||
" Instant minInstant = MIN;",
|
||||
" Map<String, String> shortIds = SHORT_IDS;",
|
||||
" ZoneOffset utc = UTC;",
|
||||
" min(ImmutableSet.of());",
|
||||
" Locale english = ENGLISH;",
|
||||
" Locale root = ROOT;",
|
||||
" empty();",
|
||||
"",
|
||||
" list();",
|
||||
" new ZERO();",
|
||||
" }",
|
||||
"",
|
||||
" static final class WithMethodThatIsSelectivelyFlagged {",
|
||||
" static ImmutableList<String> list() {",
|
||||
" return ImmutableList.of();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" static final class Wrapper {",
|
||||
" static final class ZERO {}",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(NonStaticImport.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static com.google.common.collect.ImmutableList.copyOf;",
|
||||
"import static com.google.common.collect.ImmutableSet.of;",
|
||||
"import static java.time.Clock.systemUTC;",
|
||||
"import static java.time.Instant.MAX;",
|
||||
"import static java.time.Instant.MIN;",
|
||||
"import static java.util.Collections.min;",
|
||||
"import static java.util.Locale.ROOT;",
|
||||
"import static java.util.Optional.empty;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.time.Clock;",
|
||||
"import java.time.Instant;",
|
||||
"import java.util.Locale;",
|
||||
"import java.util.Optional;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" systemUTC();",
|
||||
" Clock.systemUTC();",
|
||||
"",
|
||||
" Optional<Integer> o1 = empty();",
|
||||
" Optional<Integer> o2 = Optional.empty();",
|
||||
"",
|
||||
" Object l1 = copyOf(ImmutableList.of());",
|
||||
" Object l2 = ImmutableList.copyOf(ImmutableList.of());",
|
||||
"",
|
||||
" Locale lo1 = ROOT;",
|
||||
" Locale lo2 = Locale.ROOT;",
|
||||
"",
|
||||
" Instant i1 = MIN;",
|
||||
" Instant i2 = MAX;",
|
||||
"",
|
||||
" ImmutableSet.of(min(of()));",
|
||||
" }",
|
||||
"",
|
||||
" private static final class WithCustomConstant {",
|
||||
" private static final Instant MIN = Instant.EPOCH;",
|
||||
" private static final Instant OTHER = MIN;",
|
||||
" private static final Instant OTHER_MAX = MAX;",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.time.Clock;",
|
||||
"import java.time.Instant;",
|
||||
"import java.util.Collections;",
|
||||
"import java.util.Locale;",
|
||||
"import java.util.Optional;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Clock.systemUTC();",
|
||||
" Clock.systemUTC();",
|
||||
"",
|
||||
" Optional<Integer> o1 = Optional.empty();",
|
||||
" Optional<Integer> o2 = Optional.empty();",
|
||||
"",
|
||||
" Object l1 = ImmutableList.copyOf(ImmutableList.of());",
|
||||
" Object l2 = ImmutableList.copyOf(ImmutableList.of());",
|
||||
"",
|
||||
" Locale lo1 = Locale.ROOT;",
|
||||
" Locale lo2 = Locale.ROOT;",
|
||||
"",
|
||||
" Instant i1 = Instant.MIN;",
|
||||
" Instant i2 = Instant.MAX;",
|
||||
"",
|
||||
" ImmutableSet.of(Collections.min(ImmutableSet.of()));",
|
||||
" }",
|
||||
"",
|
||||
" private static final class WithCustomConstant {",
|
||||
" private static final Instant MIN = Instant.EPOCH;",
|
||||
" private static final Instant OTHER = MIN;",
|
||||
" private static final Instant OTHER_MAX = Instant.MAX;",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -9,21 +9,24 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
final class StaticImportTest {
|
||||
@Test
|
||||
void candidateMethodsAreNotRedundant() {
|
||||
void candidateTypesDoNotClash() {
|
||||
assertThat(StaticImport.STATIC_IMPORT_CANDIDATE_TYPES)
|
||||
.doesNotContainAnyElementsOf(NonStaticImport.NON_STATIC_IMPORT_CANDIDATE_TYPES);
|
||||
}
|
||||
|
||||
@Test
|
||||
void candidateMembersAreNotRedundant() {
|
||||
assertThat(StaticImport.STATIC_IMPORT_CANDIDATE_MEMBERS.keySet())
|
||||
.doesNotContainAnyElementsOf(StaticImport.STATIC_IMPORT_CANDIDATE_TYPES);
|
||||
}
|
||||
|
||||
@Test
|
||||
void exemptedMembersAreNotVacuous() {
|
||||
assertThat(StaticImport.STATIC_IMPORT_EXEMPTED_MEMBERS.keySet())
|
||||
.isSubsetOf(StaticImport.STATIC_IMPORT_CANDIDATE_TYPES);
|
||||
}
|
||||
void candidateMembersDoNotClash() {
|
||||
assertThat(StaticImport.STATIC_IMPORT_CANDIDATE_MEMBERS.entries())
|
||||
.doesNotContainAnyElementsOf(NonStaticImport.NON_STATIC_IMPORT_CANDIDATE_MEMBERS.entries());
|
||||
|
||||
@Test
|
||||
void exemptedMembersAreNotRedundant() {
|
||||
assertThat(StaticImport.STATIC_IMPORT_EXEMPTED_MEMBERS.values())
|
||||
.doesNotContainAnyElementsOf(StaticImport.STATIC_IMPORT_EXEMPTED_IDENTIFIERS);
|
||||
assertThat(StaticImport.STATIC_IMPORT_CANDIDATE_MEMBERS.values())
|
||||
.doesNotContainAnyElementsOf(NonStaticImport.NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -41,34 +41,19 @@ final class AssertJMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
|
||||
void testAbstractMapAssertIsEmpty() {
|
||||
assertThat(ImmutableMap.of(1, 0)).containsExactlyEntriesOf(ImmutableMap.of());
|
||||
assertThat(ImmutableMap.of(2, 0)).containsExactlyEntriesOf(ImmutableBiMap.of());
|
||||
assertThat(ImmutableMap.of(3, 0)).containsExactlyEntriesOf(ImmutableSortedMap.of());
|
||||
assertThat(ImmutableMap.of(4, 0)).containsExactlyEntriesOf(new HashMap<>());
|
||||
assertThat(ImmutableMap.of(5, 0)).containsExactlyEntriesOf(new LinkedHashMap<>());
|
||||
assertThat(ImmutableMap.of(6, 0)).containsExactlyEntriesOf(new TreeMap<>());
|
||||
assertThat(ImmutableMap.of(7, 0)).hasSameSizeAs(ImmutableMap.of());
|
||||
assertThat(ImmutableMap.of(8, 0)).hasSameSizeAs(ImmutableBiMap.of());
|
||||
assertThat(ImmutableMap.of(9, 0)).hasSameSizeAs(ImmutableSortedMap.of());
|
||||
assertThat(ImmutableMap.of(10, 0)).hasSameSizeAs(new HashMap<>());
|
||||
assertThat(ImmutableMap.of(11, 0)).hasSameSizeAs(new LinkedHashMap<>());
|
||||
assertThat(ImmutableMap.of(12, 0)).hasSameSizeAs(new TreeMap<>());
|
||||
assertThat(ImmutableMap.of(13, 0)).isEqualTo(ImmutableMap.of());
|
||||
assertThat(ImmutableMap.of(14, 0)).isEqualTo(ImmutableBiMap.of());
|
||||
assertThat(ImmutableMap.of(15, 0)).isEqualTo(ImmutableSortedMap.of());
|
||||
assertThat(ImmutableMap.of(16, 0)).isEqualTo(new HashMap<>());
|
||||
assertThat(ImmutableMap.of(17, 0)).isEqualTo(new LinkedHashMap<>());
|
||||
assertThat(ImmutableMap.of(18, 0)).isEqualTo(new TreeMap<>());
|
||||
assertThat(ImmutableMap.of(19, 0)).containsOnlyKeys(ImmutableList.of());
|
||||
assertThat(ImmutableMap.of(20, 0)).containsOnlyKeys(new ArrayList<>());
|
||||
assertThat(ImmutableMap.of(21, 0)).containsOnlyKeys(ImmutableSet.of());
|
||||
assertThat(ImmutableMap.of(22, 0)).containsOnlyKeys(new HashSet<>());
|
||||
assertThat(ImmutableMap.of(23, 0)).containsOnlyKeys(ImmutableSortedSet.of());
|
||||
assertThat(ImmutableMap.of(24, 0)).containsOnlyKeys(new TreeSet<>());
|
||||
assertThat(ImmutableMap.of(25, 0)).containsOnlyKeys(ImmutableMultiset.of());
|
||||
assertThat(ImmutableMap.of(26, 0)).containsOnlyKeys(ImmutableSortedMultiset.of());
|
||||
assertThat(ImmutableMap.of(27, 0)).containsExactly();
|
||||
assertThat(ImmutableMap.of(28, 0)).containsOnly();
|
||||
assertThat(ImmutableMap.of(29, 0)).containsOnlyKeys();
|
||||
assertThat(ImmutableMap.of(2, 0)).containsExactlyEntriesOf(ImmutableMap.of(1, 2));
|
||||
assertThat(ImmutableMap.of(3, 0)).containsExactlyInAnyOrderEntriesOf(ImmutableMap.of());
|
||||
assertThat(ImmutableMap.of(4, 0))
|
||||
.containsExactlyInAnyOrderEntriesOf(ImmutableMap.of(1, 2, 3, 4));
|
||||
assertThat(ImmutableMap.of(5, 0)).hasSameSizeAs(ImmutableMap.of());
|
||||
assertThat(ImmutableMap.of(6, 0)).hasSameSizeAs(ImmutableMap.of(1, 2));
|
||||
assertThat(ImmutableMap.of(7, 0)).isEqualTo(ImmutableMap.of());
|
||||
assertThat(ImmutableMap.of(8, 0)).isEqualTo(ImmutableMap.of("foo", "bar"));
|
||||
assertThat(ImmutableMap.of(9, 0)).containsOnlyKeys(ImmutableList.of());
|
||||
assertThat(ImmutableMap.of(10, 0)).containsOnlyKeys(ImmutableList.of(1));
|
||||
assertThat(ImmutableMap.of(11, 0)).containsExactly();
|
||||
assertThat(ImmutableMap.of(12, 0)).containsOnly();
|
||||
assertThat(ImmutableMap.of(13, 0)).containsOnlyKeys();
|
||||
}
|
||||
|
||||
void testAssertThatMapIsEmpty() {
|
||||
@@ -84,11 +69,7 @@ final class AssertJMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<MapAssert<Integer, Integer>> testAbstractMapAssertIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableMap.of(1, 0)).isNotEqualTo(ImmutableMap.of()),
|
||||
assertThat(ImmutableMap.of(2, 0)).isNotEqualTo(ImmutableBiMap.of()),
|
||||
assertThat(ImmutableMap.of(3, 0)).isNotEqualTo(ImmutableSortedMap.of()),
|
||||
assertThat(ImmutableMap.of(4, 0)).isNotEqualTo(new HashMap<>()),
|
||||
assertThat(ImmutableMap.of(5, 0)).isNotEqualTo(new LinkedHashMap<>()),
|
||||
assertThat(ImmutableMap.of(6, 0)).isNotEqualTo(new TreeMap<>()));
|
||||
assertThat(ImmutableMap.of(2, 0)).isNotEqualTo(ImmutableMap.of("foo", "bar")));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testAssertThatMapIsNotEmpty() {
|
||||
|
||||
@@ -41,34 +41,19 @@ final class AssertJMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
|
||||
void testAbstractMapAssertIsEmpty() {
|
||||
assertThat(ImmutableMap.of(1, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(2, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(2, 0)).containsExactlyEntriesOf(ImmutableMap.of(1, 2));
|
||||
assertThat(ImmutableMap.of(3, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(4, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(4, 0))
|
||||
.containsExactlyInAnyOrderEntriesOf(ImmutableMap.of(1, 2, 3, 4));
|
||||
assertThat(ImmutableMap.of(5, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(6, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(6, 0)).hasSameSizeAs(ImmutableMap.of(1, 2));
|
||||
assertThat(ImmutableMap.of(7, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(8, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(8, 0)).isEqualTo(ImmutableMap.of("foo", "bar"));
|
||||
assertThat(ImmutableMap.of(9, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(10, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(10, 0)).containsOnlyKeys(ImmutableList.of(1));
|
||||
assertThat(ImmutableMap.of(11, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(12, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(13, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(14, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(15, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(16, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(17, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(18, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(19, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(20, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(21, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(22, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(23, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(24, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(25, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(26, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(27, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(28, 0)).isEmpty();
|
||||
assertThat(ImmutableMap.of(29, 0)).isEmpty();
|
||||
}
|
||||
|
||||
void testAssertThatMapIsEmpty() {
|
||||
@@ -84,11 +69,7 @@ final class AssertJMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<MapAssert<Integer, Integer>> testAbstractMapAssertIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
assertThat(ImmutableMap.of(1, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(2, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(3, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(4, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(5, 0)).isNotEmpty(),
|
||||
assertThat(ImmutableMap.of(6, 0)).isNotEmpty());
|
||||
assertThat(ImmutableMap.of(2, 0)).isNotEqualTo(ImmutableMap.of("foo", "bar")));
|
||||
}
|
||||
|
||||
ImmutableSet<AbstractAssert<?, ?>> testAssertThatMapIsNotEmpty() {
|
||||
|
||||
@@ -20,4 +20,36 @@ final class BigDecimalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<BigDecimal> testBigDecimalValueOf() {
|
||||
return ImmutableSet.of(new BigDecimal(2), new BigDecimal(2L), new BigDecimal(2.0));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testBigDecimalSignumIsZero() {
|
||||
return ImmutableSet.of(
|
||||
BigDecimal.valueOf(1).compareTo(BigDecimal.ZERO) == 0,
|
||||
BigDecimal.ZERO.compareTo(BigDecimal.valueOf(2)) == 0,
|
||||
BigDecimal.valueOf(3).compareTo(BigDecimal.ZERO) != 0,
|
||||
BigDecimal.ZERO.compareTo(BigDecimal.valueOf(4)) != 0);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testBigDecimalSignumIsPositive() {
|
||||
return ImmutableSet.of(
|
||||
BigDecimal.valueOf(1).compareTo(BigDecimal.ZERO) > 0,
|
||||
BigDecimal.ZERO.compareTo(BigDecimal.valueOf(2)) < 0,
|
||||
BigDecimal.valueOf(3).signum() > 0,
|
||||
BigDecimal.valueOf(4).signum() >= 1,
|
||||
BigDecimal.valueOf(5).compareTo(BigDecimal.ZERO) <= 0,
|
||||
BigDecimal.ZERO.compareTo(BigDecimal.valueOf(6)) >= 0,
|
||||
BigDecimal.valueOf(7).signum() <= 0,
|
||||
BigDecimal.valueOf(8).signum() < 1);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testBigDecimalSignumIsNegative() {
|
||||
return ImmutableSet.of(
|
||||
BigDecimal.valueOf(1).compareTo(BigDecimal.ZERO) < 0,
|
||||
BigDecimal.ZERO.compareTo(BigDecimal.valueOf(2)) > 0,
|
||||
BigDecimal.valueOf(3).signum() < 0,
|
||||
BigDecimal.valueOf(4).signum() <= -1,
|
||||
BigDecimal.valueOf(5).compareTo(BigDecimal.ZERO) >= 0,
|
||||
BigDecimal.ZERO.compareTo(BigDecimal.valueOf(6)) <= 0,
|
||||
BigDecimal.valueOf(7).signum() >= 0,
|
||||
BigDecimal.valueOf(8).signum() > -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,36 @@ final class BigDecimalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<BigDecimal> testBigDecimalValueOf() {
|
||||
return ImmutableSet.of(BigDecimal.valueOf(2), BigDecimal.valueOf(2L), BigDecimal.valueOf(2.0));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testBigDecimalSignumIsZero() {
|
||||
return ImmutableSet.of(
|
||||
BigDecimal.valueOf(1).signum() == 0,
|
||||
BigDecimal.valueOf(2).signum() == 0,
|
||||
BigDecimal.valueOf(3).signum() != 0,
|
||||
BigDecimal.valueOf(4).signum() != 0);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testBigDecimalSignumIsPositive() {
|
||||
return ImmutableSet.of(
|
||||
BigDecimal.valueOf(1).signum() == 1,
|
||||
BigDecimal.valueOf(2).signum() == 1,
|
||||
BigDecimal.valueOf(3).signum() == 1,
|
||||
BigDecimal.valueOf(4).signum() == 1,
|
||||
BigDecimal.valueOf(5).signum() != 1,
|
||||
BigDecimal.valueOf(6).signum() != 1,
|
||||
BigDecimal.valueOf(7).signum() != 1,
|
||||
BigDecimal.valueOf(8).signum() != 1);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testBigDecimalSignumIsNegative() {
|
||||
return ImmutableSet.of(
|
||||
BigDecimal.valueOf(1).signum() == -1,
|
||||
BigDecimal.valueOf(2).signum() == -1,
|
||||
BigDecimal.valueOf(3).signum() == -1,
|
||||
BigDecimal.valueOf(4).signum() == -1,
|
||||
BigDecimal.valueOf(5).signum() != -1,
|
||||
BigDecimal.valueOf(6).signum() != -1,
|
||||
BigDecimal.valueOf(7).signum() != -1,
|
||||
BigDecimal.valueOf(8).signum() != -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,13 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.sun.tools.javac.util.Convert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(FixChoosers.class);
|
||||
return ImmutableSet.of(Convert.class, FixChoosers.class);
|
||||
}
|
||||
|
||||
ImmutableSet<BugCheckerRefactoringTestHelper> testBugCheckerRefactoringTestHelperIdentity() {
|
||||
@@ -26,4 +27,8 @@ final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase {
|
||||
.addInputLines("A.java", "class A {}")
|
||||
.addOutputLines("A.java", "class A {}");
|
||||
}
|
||||
|
||||
String testConstantsFormat() {
|
||||
return String.format("\"%s\"", Convert.quote("foo"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,14 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.sun.tools.javac.util.Constants;
|
||||
import com.sun.tools.javac.util.Convert;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(FixChoosers.class);
|
||||
return ImmutableSet.of(Convert.class, FixChoosers.class);
|
||||
}
|
||||
|
||||
ImmutableSet<BugCheckerRefactoringTestHelper> testBugCheckerRefactoringTestHelperIdentity() {
|
||||
@@ -24,4 +26,8 @@ final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase {
|
||||
.addInputLines("A.java", "class A {}")
|
||||
.expectUnchanged();
|
||||
}
|
||||
|
||||
String testConstantsFormat() {
|
||||
return Constants.format("foo");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
String::compareTo,
|
||||
Comparator.comparing(identity()),
|
||||
Comparator.comparing(s -> s),
|
||||
Comparator.comparing(s -> 0),
|
||||
Collections.<String>reverseOrder(reverseOrder()),
|
||||
Comparator.<String>reverseOrder().reversed());
|
||||
}
|
||||
@@ -45,7 +46,8 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<Comparator<String>> testCustomComparator() {
|
||||
return ImmutableSet.of(
|
||||
Comparator.comparing(identity(), Comparator.comparingInt(String::length)),
|
||||
Comparator.comparing(s -> s, Comparator.comparingInt(String::length)));
|
||||
Comparator.comparing(s -> s, Comparator.comparingInt(String::length)),
|
||||
Comparator.comparing(s -> "foo", Comparator.comparingInt(String::length)));
|
||||
}
|
||||
|
||||
Comparator<String> testThenComparing() {
|
||||
@@ -86,7 +88,8 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<Comparator<String>> testThenComparingNaturalOrder() {
|
||||
return ImmutableSet.of(
|
||||
Comparator.<String>naturalOrder().thenComparing(identity()),
|
||||
Comparator.<String>naturalOrder().thenComparing(s -> s));
|
||||
Comparator.<String>naturalOrder().thenComparing(s -> s),
|
||||
Comparator.<String>naturalOrder().thenComparing(s -> 0));
|
||||
}
|
||||
|
||||
ImmutableSet<Integer> testCompareTo() {
|
||||
|
||||
@@ -28,7 +28,12 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
|
||||
ImmutableSet<Comparator<String>> testNaturalOrder() {
|
||||
return ImmutableSet.of(
|
||||
naturalOrder(), naturalOrder(), naturalOrder(), naturalOrder(), naturalOrder());
|
||||
naturalOrder(),
|
||||
naturalOrder(),
|
||||
naturalOrder(),
|
||||
Comparator.comparing(s -> 0),
|
||||
naturalOrder(),
|
||||
naturalOrder());
|
||||
}
|
||||
|
||||
ImmutableSet<Comparator<String>> testReverseOrder() {
|
||||
@@ -38,7 +43,9 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
|
||||
ImmutableSet<Comparator<String>> testCustomComparator() {
|
||||
return ImmutableSet.of(
|
||||
Comparator.comparingInt(String::length), Comparator.comparingInt(String::length));
|
||||
Comparator.comparingInt(String::length),
|
||||
Comparator.comparingInt(String::length),
|
||||
Comparator.comparing(s -> "foo", Comparator.comparingInt(String::length)));
|
||||
}
|
||||
|
||||
Comparator<String> testThenComparing() {
|
||||
@@ -73,7 +80,8 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<Comparator<String>> testThenComparingNaturalOrder() {
|
||||
return ImmutableSet.of(
|
||||
Comparator.<String>naturalOrder().thenComparing(naturalOrder()),
|
||||
Comparator.<String>naturalOrder().thenComparing(naturalOrder()));
|
||||
Comparator.<String>naturalOrder().thenComparing(naturalOrder()),
|
||||
Comparator.<String>naturalOrder().thenComparing(s -> 0));
|
||||
}
|
||||
|
||||
ImmutableSet<Integer> testCompareTo() {
|
||||
|
||||
@@ -76,11 +76,22 @@ final class ImmutableListMultimapRulesTest implements RefasterRuleCollectionTest
|
||||
|
||||
ImmutableSet<ImmutableListMultimap<Integer, Integer>> testIndexIterableToImmutableListMultimap() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableList.of(1).stream().collect(toImmutableListMultimap(n -> n * 2, identity())),
|
||||
Streams.stream(ImmutableList.of(2)::iterator)
|
||||
.collect(toImmutableListMultimap(Integer::valueOf, n -> n)),
|
||||
Streams.stream(ImmutableList.of(1).iterator())
|
||||
.collect(toImmutableListMultimap(n -> n * 2, identity())),
|
||||
Streams.stream(ImmutableList.of(2).iterator())
|
||||
.collect(toImmutableListMultimap(n -> n * 2, v -> v)),
|
||||
Streams.stream(ImmutableList.of(3).iterator())
|
||||
.collect(toImmutableListMultimap(n -> n.intValue(), identity())));
|
||||
.collect(toImmutableListMultimap(n -> n * 2, v -> 0)),
|
||||
Streams.stream(ImmutableList.of(4)::iterator)
|
||||
.collect(toImmutableListMultimap(Integer::valueOf, identity())),
|
||||
Streams.stream(ImmutableList.of(5)::iterator)
|
||||
.collect(toImmutableListMultimap(Integer::valueOf, v -> v)),
|
||||
Streams.stream(ImmutableList.of(6)::iterator)
|
||||
.collect(toImmutableListMultimap(Integer::valueOf, v -> 0)),
|
||||
ImmutableList.of(7).stream()
|
||||
.collect(toImmutableListMultimap(n -> n.intValue(), identity())),
|
||||
ImmutableList.of(8).stream().collect(toImmutableListMultimap(n -> n.intValue(), v -> v)),
|
||||
ImmutableList.of(9).stream().collect(toImmutableListMultimap(n -> n.intValue(), v -> 0)));
|
||||
}
|
||||
|
||||
ImmutableListMultimap<String, Integer> testTransformMultimapValuesToImmutableListMultimap() {
|
||||
|
||||
@@ -64,9 +64,17 @@ final class ImmutableListMultimapRulesTest implements RefasterRuleCollectionTest
|
||||
|
||||
ImmutableSet<ImmutableListMultimap<Integer, Integer>> testIndexIterableToImmutableListMultimap() {
|
||||
return ImmutableSet.of(
|
||||
Multimaps.index(ImmutableList.of(1), n -> n * 2),
|
||||
Multimaps.index(ImmutableList.of(2)::iterator, Integer::valueOf),
|
||||
Multimaps.index(ImmutableList.of(3).iterator(), n -> n.intValue()));
|
||||
Multimaps.index(ImmutableList.of(1).iterator(), n -> n * 2),
|
||||
Multimaps.index(ImmutableList.of(2).iterator(), n -> n * 2),
|
||||
Streams.stream(ImmutableList.of(3).iterator())
|
||||
.collect(toImmutableListMultimap(n -> n * 2, v -> 0)),
|
||||
Multimaps.index(ImmutableList.of(4)::iterator, Integer::valueOf),
|
||||
Multimaps.index(ImmutableList.of(5)::iterator, Integer::valueOf),
|
||||
Streams.stream(ImmutableList.of(6)::iterator)
|
||||
.collect(toImmutableListMultimap(Integer::valueOf, v -> 0)),
|
||||
Multimaps.index(ImmutableList.of(7), n -> n.intValue()),
|
||||
Multimaps.index(ImmutableList.of(8), n -> n.intValue()),
|
||||
ImmutableList.of(9).stream().collect(toImmutableListMultimap(n -> n.intValue(), v -> 0)));
|
||||
}
|
||||
|
||||
ImmutableListMultimap<String, Integer> testTransformMultimapValuesToImmutableListMultimap() {
|
||||
|
||||
@@ -34,11 +34,21 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<ImmutableMap<Integer, Integer>> testIterableToImmutableMap() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableList.of(1).stream().collect(toImmutableMap(identity(), n -> n * 2)),
|
||||
Streams.stream(ImmutableList.of(2)::iterator)
|
||||
.collect(toImmutableMap(n -> n, Integer::valueOf)),
|
||||
Streams.stream(ImmutableList.of(3).iterator())
|
||||
ImmutableList.of(2).stream().collect(toImmutableMap(k -> k, n -> n * 2)),
|
||||
ImmutableList.of(3).stream().collect(toImmutableMap(k -> 0, n -> n * 2)),
|
||||
Streams.stream(ImmutableList.of(4)::iterator)
|
||||
.collect(toImmutableMap(identity(), Integer::valueOf)),
|
||||
Streams.stream(ImmutableList.of(5)::iterator)
|
||||
.collect(toImmutableMap(k -> k, Integer::valueOf)),
|
||||
Streams.stream(ImmutableList.of(6)::iterator)
|
||||
.collect(toImmutableMap(k -> 0, Integer::valueOf)),
|
||||
Streams.stream(ImmutableList.of(7).iterator())
|
||||
.collect(toImmutableMap(identity(), n -> n.intValue())),
|
||||
ImmutableMap.copyOf(Maps.asMap(ImmutableSet.of(4), Integer::valueOf)));
|
||||
Streams.stream(ImmutableList.of(8).iterator())
|
||||
.collect(toImmutableMap(k -> k, n -> n.intValue())),
|
||||
Streams.stream(ImmutableList.of(9).iterator())
|
||||
.collect(toImmutableMap(k -> 0, n -> n.intValue())),
|
||||
ImmutableMap.copyOf(Maps.asMap(ImmutableSet.of(10), Integer::valueOf)));
|
||||
}
|
||||
|
||||
ImmutableSet<ImmutableMap<String, Integer>> testEntryIterableToImmutableMap() {
|
||||
@@ -63,10 +73,20 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<ImmutableMap<Integer, Integer>> testIndexIterableToImmutableMap() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableList.of(1).stream().collect(toImmutableMap(n -> n * 2, identity())),
|
||||
Streams.stream(ImmutableList.of(2)::iterator)
|
||||
.collect(toImmutableMap(Integer::valueOf, n -> n)),
|
||||
Streams.stream(ImmutableList.of(3).iterator())
|
||||
.collect(toImmutableMap(n -> n.intValue(), identity())));
|
||||
ImmutableList.of(2).stream().collect(toImmutableMap(n -> n * 2, v -> v)),
|
||||
ImmutableList.of(3).stream().collect(toImmutableMap(n -> n * 2, v -> 0)),
|
||||
Streams.stream(ImmutableList.of(4)::iterator)
|
||||
.collect(toImmutableMap(Integer::valueOf, identity())),
|
||||
Streams.stream(ImmutableList.of(5)::iterator)
|
||||
.collect(toImmutableMap(Integer::valueOf, v -> v)),
|
||||
Streams.stream(ImmutableList.of(6)::iterator)
|
||||
.collect(toImmutableMap(Integer::valueOf, v -> 0)),
|
||||
Streams.stream(ImmutableList.of(7).iterator())
|
||||
.collect(toImmutableMap(n -> n.intValue(), identity())),
|
||||
Streams.stream(ImmutableList.of(8).iterator())
|
||||
.collect(toImmutableMap(n -> n.intValue(), v -> v)),
|
||||
Streams.stream(ImmutableList.of(9).iterator())
|
||||
.collect(toImmutableMap(n -> n.intValue(), v -> 0)));
|
||||
}
|
||||
|
||||
ImmutableSet<ImmutableMap<String, Integer>> testTransformMapValuesToImmutableMap() {
|
||||
|
||||
@@ -33,9 +33,17 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<ImmutableMap<Integer, Integer>> testIterableToImmutableMap() {
|
||||
return ImmutableSet.of(
|
||||
Maps.toMap(ImmutableList.of(1), n -> n * 2),
|
||||
Maps.toMap(ImmutableList.of(2)::iterator, Integer::valueOf),
|
||||
Maps.toMap(ImmutableList.of(3).iterator(), n -> n.intValue()),
|
||||
Maps.toMap(ImmutableSet.of(4), Integer::valueOf));
|
||||
Maps.toMap(ImmutableList.of(2), n -> n * 2),
|
||||
ImmutableList.of(3).stream().collect(toImmutableMap(k -> 0, n -> n * 2)),
|
||||
Maps.toMap(ImmutableList.of(4)::iterator, Integer::valueOf),
|
||||
Maps.toMap(ImmutableList.of(5)::iterator, Integer::valueOf),
|
||||
Streams.stream(ImmutableList.of(6)::iterator)
|
||||
.collect(toImmutableMap(k -> 0, Integer::valueOf)),
|
||||
Maps.toMap(ImmutableList.of(7).iterator(), n -> n.intValue()),
|
||||
Maps.toMap(ImmutableList.of(8).iterator(), n -> n.intValue()),
|
||||
Streams.stream(ImmutableList.of(9).iterator())
|
||||
.collect(toImmutableMap(k -> 0, n -> n.intValue())),
|
||||
Maps.toMap(ImmutableSet.of(10), Integer::valueOf));
|
||||
}
|
||||
|
||||
ImmutableSet<ImmutableMap<String, Integer>> testEntryIterableToImmutableMap() {
|
||||
@@ -54,8 +62,16 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<ImmutableMap<Integer, Integer>> testIndexIterableToImmutableMap() {
|
||||
return ImmutableSet.of(
|
||||
Maps.uniqueIndex(ImmutableList.of(1), n -> n * 2),
|
||||
Maps.uniqueIndex(ImmutableList.of(2)::iterator, Integer::valueOf),
|
||||
Maps.uniqueIndex(ImmutableList.of(3).iterator(), n -> n.intValue()));
|
||||
Maps.uniqueIndex(ImmutableList.of(2), n -> n * 2),
|
||||
ImmutableList.of(3).stream().collect(toImmutableMap(n -> n * 2, v -> 0)),
|
||||
Maps.uniqueIndex(ImmutableList.of(4)::iterator, Integer::valueOf),
|
||||
Maps.uniqueIndex(ImmutableList.of(5)::iterator, Integer::valueOf),
|
||||
Streams.stream(ImmutableList.of(6)::iterator)
|
||||
.collect(toImmutableMap(Integer::valueOf, v -> 0)),
|
||||
Maps.uniqueIndex(ImmutableList.of(7).iterator(), n -> n.intValue()),
|
||||
Maps.uniqueIndex(ImmutableList.of(8).iterator(), n -> n.intValue()),
|
||||
Streams.stream(ImmutableList.of(9).iterator())
|
||||
.collect(toImmutableMap(n -> n.intValue(), v -> 0)));
|
||||
}
|
||||
|
||||
ImmutableSet<ImmutableMap<String, Integer>> testTransformMapValuesToImmutableMap() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
@@ -29,7 +30,10 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
(Runnable) () -> assertNotSame(null, null),
|
||||
(Runnable) () -> assertNull(null),
|
||||
(Runnable) () -> assertSame(null, null),
|
||||
(Runnable) () -> assertTrue(true));
|
||||
(Runnable) () -> assertTrue(true),
|
||||
(Runnable) () -> assertEquals(0, 0),
|
||||
(Runnable) () -> assertEquals(0, 0, "foo"),
|
||||
(Runnable) () -> assertEquals(0, 0, () -> "foo"));
|
||||
}
|
||||
|
||||
void testThrowNewAssertionError() {
|
||||
@@ -170,4 +174,28 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
void testAssertThatWithFailMessageSupplierIsInstanceOf() {
|
||||
assertInstanceOf(Object.class, new Object(), () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatByteIsEqualTo() {
|
||||
assertEquals((byte) 0, (byte) 0);
|
||||
}
|
||||
|
||||
void testAssertThatByteWithFailMessageStringIsEqualTo() {
|
||||
assertEquals((byte) 0, (byte) 0, "foo");
|
||||
}
|
||||
|
||||
void testAssertThatByteWithFailMessageSupplierIsEqualTo() {
|
||||
assertEquals((byte) 0, (byte) 0, () -> "foo");
|
||||
}
|
||||
|
||||
void testAssertThatCharIsEqualTo() {
|
||||
assertEquals('a', 'a');
|
||||
}
|
||||
|
||||
void testAssertThatCharWithFailMessageStringIsEqualTo() {
|
||||
assertEquals('a', 'a', "foo");
|
||||
}
|
||||
|
||||
void testAssertThatCharWithFailMessageSupplierIsEqualTo() {
|
||||
assertEquals('a', 'a', () -> "foo");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
@@ -33,7 +34,10 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
(Runnable) () -> assertNotSame(null, null),
|
||||
(Runnable) () -> assertNull(null),
|
||||
(Runnable) () -> assertSame(null, null),
|
||||
(Runnable) () -> assertTrue(true));
|
||||
(Runnable) () -> assertTrue(true),
|
||||
(Runnable) () -> assertEquals(0, 0),
|
||||
(Runnable) () -> assertEquals(0, 0, "foo"),
|
||||
(Runnable) () -> assertEquals(0, 0, () -> "foo"));
|
||||
}
|
||||
|
||||
void testThrowNewAssertionError() {
|
||||
@@ -180,4 +184,28 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
void testAssertThatWithFailMessageSupplierIsInstanceOf() {
|
||||
assertThat(new Object()).withFailMessage(() -> "foo").isInstanceOf(Object.class);
|
||||
}
|
||||
|
||||
void testAssertThatByteIsEqualTo() {
|
||||
assertThat((byte) 0).isEqualTo((byte) 0);
|
||||
}
|
||||
|
||||
void testAssertThatByteWithFailMessageStringIsEqualTo() {
|
||||
assertThat((byte) 0).withFailMessage("foo").isEqualTo((byte) 0);
|
||||
}
|
||||
|
||||
void testAssertThatByteWithFailMessageSupplierIsEqualTo() {
|
||||
assertThat((byte) 0).withFailMessage(() -> "foo").isEqualTo((byte) 0);
|
||||
}
|
||||
|
||||
void testAssertThatCharIsEqualTo() {
|
||||
assertThat('a').isEqualTo('a');
|
||||
}
|
||||
|
||||
void testAssertThatCharWithFailMessageStringIsEqualTo() {
|
||||
assertThat('a').withFailMessage("foo").isEqualTo('a');
|
||||
}
|
||||
|
||||
void testAssertThatCharWithFailMessageSupplierIsEqualTo() {
|
||||
assertThat('a').withFailMessage(() -> "foo").isEqualTo('a');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,4 +164,30 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
boolean testDoubleIsFinite() {
|
||||
return Doubles.isFinite(1);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIntegerSignumIsPositive() {
|
||||
return ImmutableSet.of(
|
||||
Integer.signum(1) > 0,
|
||||
Integer.signum(2) >= 1,
|
||||
Integer.signum(3) <= 0,
|
||||
Integer.signum(4) < 1);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIntegerSignumIsNegative() {
|
||||
return ImmutableSet.of(
|
||||
Integer.signum(1) < 0,
|
||||
Integer.signum(2) <= -1,
|
||||
Integer.signum(3) >= 0,
|
||||
Integer.signum(4) > -1);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testLongSignumIsPositive() {
|
||||
return ImmutableSet.of(
|
||||
Long.signum(1L) > 0, Long.signum(2L) >= 1, Long.signum(3L) <= 0, Long.signum(4L) < 1);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testLongSignumIsNegative() {
|
||||
return ImmutableSet.of(
|
||||
Long.signum(1L) < 0, Long.signum(2L) <= -1, Long.signum(3L) >= 0, Long.signum(4L) > -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,4 +164,30 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
boolean testDoubleIsFinite() {
|
||||
return Double.isFinite(1);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIntegerSignumIsPositive() {
|
||||
return ImmutableSet.of(
|
||||
Integer.signum(1) == 1,
|
||||
Integer.signum(2) == 1,
|
||||
Integer.signum(3) != 1,
|
||||
Integer.signum(4) != 1);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIntegerSignumIsNegative() {
|
||||
return ImmutableSet.of(
|
||||
Integer.signum(1) == -1,
|
||||
Integer.signum(2) == -1,
|
||||
Integer.signum(3) != -1,
|
||||
Integer.signum(4) != -1);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testLongSignumIsPositive() {
|
||||
return ImmutableSet.of(
|
||||
Long.signum(1L) == 1, Long.signum(2L) == 1, Long.signum(3L) != 1, Long.signum(4L) != 1);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testLongSignumIsNegative() {
|
||||
return ImmutableSet.of(
|
||||
Long.signum(1L) == -1, Long.signum(2L) == -1, Long.signum(3L) != -1, Long.signum(4L) != -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,20 +202,26 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).flatMap(Mono::just, 1),
|
||||
Flux.just(2).flatMapSequential(Mono::just, 1),
|
||||
Flux.just(3).map(Mono::just).concatMap(identity()));
|
||||
Flux.just(3).map(Mono::just).concatMap(identity()),
|
||||
Flux.just(4).map(Mono::just).concatMap(v -> v),
|
||||
Flux.just(5).map(Mono::just).concatMap(v -> Mono.empty()));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMapWithPrefetch() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).flatMap(Mono::just, 1, 3),
|
||||
Flux.just(2).flatMapSequential(Mono::just, 1, 4),
|
||||
Flux.just(3).map(Mono::just).concatMap(identity(), 5));
|
||||
Flux.just(3).map(Mono::just).concatMap(identity(), 5),
|
||||
Flux.just(4).map(Mono::just).concatMap(v -> v, 6),
|
||||
Flux.just(5).map(Mono::just).concatMap(v -> Mono.empty(), 7));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testMonoFlatMapIterable() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just(1).map(ImmutableSet::of).flatMapIterable(identity()),
|
||||
Mono.just(2).flux().concatMapIterable(ImmutableSet::of));
|
||||
Mono.just(2).map(ImmutableSet::of).flatMapIterable(v -> v),
|
||||
Mono.just(3).map(ImmutableSet::of).flatMapIterable(v -> ImmutableSet.of()),
|
||||
Mono.just(4).flux().concatMapIterable(ImmutableSet::of));
|
||||
}
|
||||
|
||||
Flux<Integer> testMonoFlatMapIterableIdentity() {
|
||||
@@ -225,13 +231,17 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMapIterable() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).flatMapIterable(ImmutableList::of),
|
||||
Flux.just(2).map(ImmutableList::of).concatMapIterable(identity()));
|
||||
Flux.just(2).map(ImmutableList::of).concatMapIterable(identity()),
|
||||
Flux.just(3).map(ImmutableList::of).concatMapIterable(v -> v),
|
||||
Flux.just(4).map(ImmutableList::of).concatMapIterable(v -> ImmutableSet.of()));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMapIterableWithPrefetch() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).flatMapIterable(ImmutableList::of, 3),
|
||||
Flux.just(2).map(ImmutableList::of).concatMapIterable(identity(), 3));
|
||||
Flux.just(1).flatMapIterable(ImmutableList::of, 5),
|
||||
Flux.just(2).map(ImmutableList::of).concatMapIterable(identity(), 5),
|
||||
Flux.just(3).map(ImmutableList::of).concatMapIterable(v -> v, 5),
|
||||
Flux.just(4).map(ImmutableList::of).concatMapIterable(v -> ImmutableSet.of(), 5));
|
||||
}
|
||||
|
||||
Flux<String> testMonoFlatMapToFlux() {
|
||||
@@ -372,25 +382,30 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Flux.just(1).filter(Number.class::isInstance).cast(Number.class);
|
||||
}
|
||||
|
||||
Mono<String> testMonoFlatMap() {
|
||||
return Mono.just("foo").map(Mono::just).flatMap(identity());
|
||||
ImmutableSet<Mono<String>> testMonoFlatMap() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just("foo").map(Mono::just).flatMap(identity()),
|
||||
Mono.just("bar").map(Mono::just).flatMap(v -> v),
|
||||
Mono.just("baz").map(Mono::just).flatMap(v -> Mono.empty()));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testMonoFlatMapMany() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just(1).map(Mono::just).flatMapMany(identity()),
|
||||
Mono.just(2).flux().concatMap(Mono::just),
|
||||
Mono.just(3).flux().concatMap(Mono::just, 2),
|
||||
Mono.just(4).flux().concatMapDelayError(Mono::just),
|
||||
Mono.just(5).flux().concatMapDelayError(Mono::just, 2),
|
||||
Mono.just(6).flux().concatMapDelayError(Mono::just, false, 2),
|
||||
Mono.just(7).flux().flatMap(Mono::just, 2),
|
||||
Mono.just(8).flux().flatMap(Mono::just, 2, 3),
|
||||
Mono.just(9).flux().flatMapDelayError(Mono::just, 2, 3),
|
||||
Mono.just(10).flux().flatMapSequential(Mono::just, 2),
|
||||
Mono.just(11).flux().flatMapSequential(Mono::just, 2, 3),
|
||||
Mono.just(12).flux().flatMapSequentialDelayError(Mono::just, 2, 3),
|
||||
Mono.just(13).flux().switchMap(Mono::just));
|
||||
Mono.just(2).map(Mono::just).flatMapMany(v -> v),
|
||||
Mono.just(3).map(Mono::just).flatMapMany(v -> Flux.empty()),
|
||||
Mono.just(4).flux().concatMap(Mono::just),
|
||||
Mono.just(5).flux().concatMap(Mono::just, 2),
|
||||
Mono.just(6).flux().concatMapDelayError(Mono::just),
|
||||
Mono.just(7).flux().concatMapDelayError(Mono::just, 2),
|
||||
Mono.just(8).flux().concatMapDelayError(Mono::just, false, 2),
|
||||
Mono.just(9).flux().flatMap(Mono::just, 2),
|
||||
Mono.just(10).flux().flatMap(Mono::just, 2, 3),
|
||||
Mono.just(11).flux().flatMapDelayError(Mono::just, 2, 3),
|
||||
Mono.just(12).flux().flatMapSequential(Mono::just, 2),
|
||||
Mono.just(13).flux().flatMapSequential(Mono::just, 2, 3),
|
||||
Mono.just(14).flux().flatMapSequentialDelayError(Mono::just, 2, 3),
|
||||
Mono.just(15).flux().switchMap(Mono::just));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<String>> testConcatMapIterableIdentity() {
|
||||
@@ -511,7 +526,7 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
|
||||
ImmutableSet<Context> testContextEmpty() {
|
||||
return ImmutableSet.of(Context.of(new HashMap<>()), Context.of(ImmutableMap.of()));
|
||||
return ImmutableSet.of(Context.of(ImmutableMap.of()), Context.of(ImmutableMap.of(1, 2)));
|
||||
}
|
||||
|
||||
ImmutableSet<PublisherProbe<Void>> testPublisherProbeEmpty() {
|
||||
@@ -528,14 +543,16 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
|
||||
ImmutableSet<StepVerifier.Step<Integer>> testStepVerifierStepIdentity() {
|
||||
return ImmutableSet.of(
|
||||
StepVerifier.create(Mono.just(1)).expectNext(),
|
||||
StepVerifier.create(Mono.just(2)).expectNextCount(0L));
|
||||
Mono.just(1).as(StepVerifier::create).expectNext(),
|
||||
Mono.just(2).as(StepVerifier::create).expectNextCount(0L),
|
||||
Mono.just(3).as(StepVerifier::create).expectNextSequence(ImmutableList.of()),
|
||||
Mono.just(4).as(StepVerifier::create).expectNextSequence(ImmutableList.of(5)));
|
||||
}
|
||||
|
||||
ImmutableSet<StepVerifier.Step<String>> testStepVerifierStepExpectNext() {
|
||||
return ImmutableSet.of(
|
||||
StepVerifier.create(Mono.just("foo")).expectNextMatches(s -> s.equals("bar")),
|
||||
StepVerifier.create(Mono.just("baz")).expectNextMatches("qux"::equals));
|
||||
Mono.just("foo").as(StepVerifier::create).expectNextMatches(s -> s.equals("bar")),
|
||||
Mono.just("baz").as(StepVerifier::create).expectNextMatches("qux"::equals));
|
||||
}
|
||||
|
||||
StepVerifier.Step<?> testFluxAsStepVerifierExpectNext() {
|
||||
@@ -546,37 +563,40 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyComplete() {
|
||||
return StepVerifier.create(Mono.empty()).expectComplete().verify();
|
||||
return Mono.empty().as(StepVerifier::create).expectComplete().verify();
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyError() {
|
||||
return StepVerifier.create(Mono.empty()).expectError().verify();
|
||||
return Mono.empty().as(StepVerifier::create).expectError().verify();
|
||||
}
|
||||
|
||||
ImmutableSet<Duration> testStepVerifierLastStepVerifyErrorClass() {
|
||||
return ImmutableSet.of(
|
||||
StepVerifier.create(Mono.empty()).expectError(IllegalArgumentException.class).verify(),
|
||||
StepVerifier.create(Mono.empty())
|
||||
Mono.empty().as(StepVerifier::create).expectError(IllegalArgumentException.class).verify(),
|
||||
Mono.empty()
|
||||
.as(StepVerifier::create)
|
||||
.verifyErrorMatches(IllegalStateException.class::isInstance),
|
||||
StepVerifier.create(Mono.empty())
|
||||
Mono.empty()
|
||||
.as(StepVerifier::create)
|
||||
.verifyErrorSatisfies(t -> assertThat(t).isInstanceOf(AssertionError.class)));
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyErrorMatches() {
|
||||
return StepVerifier.create(Mono.empty())
|
||||
return Mono.empty()
|
||||
.as(StepVerifier::create)
|
||||
.expectErrorMatches(IllegalArgumentException.class::equals)
|
||||
.verify();
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyErrorSatisfies() {
|
||||
return StepVerifier.create(Mono.empty()).expectErrorSatisfies(t -> {}).verify();
|
||||
return Mono.empty().as(StepVerifier::create).expectErrorSatisfies(t -> {}).verify();
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyErrorMessage() {
|
||||
return StepVerifier.create(Mono.empty()).expectErrorMessage("foo").verify();
|
||||
return Mono.empty().as(StepVerifier::create).expectErrorMessage("foo").verify();
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyTimeout() {
|
||||
return StepVerifier.create(Mono.empty()).expectTimeout(Duration.ZERO).verify();
|
||||
return Mono.empty().as(StepVerifier::create).expectTimeout(Duration.ZERO).verify();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,20 +205,26 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).concatMap(Mono::just),
|
||||
Flux.just(2).concatMap(Mono::just),
|
||||
Flux.just(3).concatMap(Mono::just));
|
||||
Flux.just(3).concatMap(Mono::just),
|
||||
Flux.just(4).concatMap(Mono::just),
|
||||
Flux.just(5).map(Mono::just).concatMap(v -> Mono.empty()));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMapWithPrefetch() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).concatMap(Mono::just, 3),
|
||||
Flux.just(2).concatMap(Mono::just, 4),
|
||||
Flux.just(3).concatMap(Mono::just, 5));
|
||||
Flux.just(3).concatMap(Mono::just, 5),
|
||||
Flux.just(4).concatMap(Mono::just, 6),
|
||||
Flux.just(5).map(Mono::just).concatMap(v -> Mono.empty(), 7));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testMonoFlatMapIterable() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just(1).flatMapIterable(ImmutableSet::of),
|
||||
Mono.just(2).flatMapIterable(ImmutableSet::of));
|
||||
Mono.just(2).flatMapIterable(ImmutableSet::of),
|
||||
Mono.just(3).map(ImmutableSet::of).flatMapIterable(v -> ImmutableSet.of()),
|
||||
Mono.just(4).flatMapIterable(ImmutableSet::of));
|
||||
}
|
||||
|
||||
Flux<Integer> testMonoFlatMapIterableIdentity() {
|
||||
@@ -228,13 +234,17 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMapIterable() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).concatMapIterable(ImmutableList::of),
|
||||
Flux.just(2).concatMapIterable(ImmutableList::of));
|
||||
Flux.just(2).concatMapIterable(ImmutableList::of),
|
||||
Flux.just(3).concatMapIterable(ImmutableList::of),
|
||||
Flux.just(4).map(ImmutableList::of).concatMapIterable(v -> ImmutableSet.of()));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMapIterableWithPrefetch() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).concatMapIterable(ImmutableList::of, 3),
|
||||
Flux.just(2).concatMapIterable(ImmutableList::of, 3));
|
||||
Flux.just(1).concatMapIterable(ImmutableList::of, 5),
|
||||
Flux.just(2).concatMapIterable(ImmutableList::of, 5),
|
||||
Flux.just(3).concatMapIterable(ImmutableList::of, 5),
|
||||
Flux.just(4).map(ImmutableList::of).concatMapIterable(v -> ImmutableSet.of(), 5));
|
||||
}
|
||||
|
||||
Flux<String> testMonoFlatMapToFlux() {
|
||||
@@ -365,15 +375,18 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Flux.just(1).ofType(Number.class);
|
||||
}
|
||||
|
||||
Mono<String> testMonoFlatMap() {
|
||||
return Mono.just("foo").flatMap(Mono::just);
|
||||
ImmutableSet<Mono<String>> testMonoFlatMap() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just("foo").flatMap(Mono::just),
|
||||
Mono.just("bar").flatMap(Mono::just),
|
||||
Mono.just("baz").map(Mono::just).flatMap(v -> Mono.empty()));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testMonoFlatMapMany() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just(1).flatMapMany(Mono::just),
|
||||
Mono.just(2).flatMapMany(Mono::just),
|
||||
Mono.just(3).flatMapMany(Mono::just),
|
||||
Mono.just(3).map(Mono::just).flatMapMany(v -> Flux.empty()),
|
||||
Mono.just(4).flatMapMany(Mono::just),
|
||||
Mono.just(5).flatMapMany(Mono::just),
|
||||
Mono.just(6).flatMapMany(Mono::just),
|
||||
@@ -383,7 +396,9 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Mono.just(10).flatMapMany(Mono::just),
|
||||
Mono.just(11).flatMapMany(Mono::just),
|
||||
Mono.just(12).flatMapMany(Mono::just),
|
||||
Mono.just(13).flatMapMany(Mono::just));
|
||||
Mono.just(13).flatMapMany(Mono::just),
|
||||
Mono.just(14).flatMapMany(Mono::just),
|
||||
Mono.just(15).flatMapMany(Mono::just));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<String>> testConcatMapIterableIdentity() {
|
||||
@@ -500,7 +515,7 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
|
||||
ImmutableSet<Context> testContextEmpty() {
|
||||
return ImmutableSet.of(Context.empty(), Context.empty());
|
||||
return ImmutableSet.of(Context.empty(), Context.of(ImmutableMap.of(1, 2)));
|
||||
}
|
||||
|
||||
ImmutableSet<PublisherProbe<Void>> testPublisherProbeEmpty() {
|
||||
@@ -516,13 +531,17 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
|
||||
ImmutableSet<StepVerifier.Step<Integer>> testStepVerifierStepIdentity() {
|
||||
return ImmutableSet.of(StepVerifier.create(Mono.just(1)), StepVerifier.create(Mono.just(2)));
|
||||
return ImmutableSet.of(
|
||||
Mono.just(1).as(StepVerifier::create),
|
||||
Mono.just(2).as(StepVerifier::create),
|
||||
Mono.just(3).as(StepVerifier::create),
|
||||
Mono.just(4).as(StepVerifier::create).expectNextSequence(ImmutableList.of(5)));
|
||||
}
|
||||
|
||||
ImmutableSet<StepVerifier.Step<String>> testStepVerifierStepExpectNext() {
|
||||
return ImmutableSet.of(
|
||||
StepVerifier.create(Mono.just("foo")).expectNext("bar"),
|
||||
StepVerifier.create(Mono.just("baz")).expectNext("qux"));
|
||||
Mono.just("foo").as(StepVerifier::create).expectNext("bar"),
|
||||
Mono.just("baz").as(StepVerifier::create).expectNext("qux"));
|
||||
}
|
||||
|
||||
StepVerifier.Step<?> testFluxAsStepVerifierExpectNext() {
|
||||
@@ -530,34 +549,35 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyComplete() {
|
||||
return StepVerifier.create(Mono.empty()).verifyComplete();
|
||||
return Mono.empty().as(StepVerifier::create).verifyComplete();
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyError() {
|
||||
return StepVerifier.create(Mono.empty()).verifyError();
|
||||
return Mono.empty().as(StepVerifier::create).verifyError();
|
||||
}
|
||||
|
||||
ImmutableSet<Duration> testStepVerifierLastStepVerifyErrorClass() {
|
||||
return ImmutableSet.of(
|
||||
StepVerifier.create(Mono.empty()).verifyError(IllegalArgumentException.class),
|
||||
StepVerifier.create(Mono.empty()).verifyError(IllegalStateException.class),
|
||||
StepVerifier.create(Mono.empty()).verifyError(AssertionError.class));
|
||||
Mono.empty().as(StepVerifier::create).verifyError(IllegalArgumentException.class),
|
||||
Mono.empty().as(StepVerifier::create).verifyError(IllegalStateException.class),
|
||||
Mono.empty().as(StepVerifier::create).verifyError(AssertionError.class));
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyErrorMatches() {
|
||||
return StepVerifier.create(Mono.empty())
|
||||
return Mono.empty()
|
||||
.as(StepVerifier::create)
|
||||
.verifyErrorMatches(IllegalArgumentException.class::equals);
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyErrorSatisfies() {
|
||||
return StepVerifier.create(Mono.empty()).verifyErrorSatisfies(t -> {});
|
||||
return Mono.empty().as(StepVerifier::create).verifyErrorSatisfies(t -> {});
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyErrorMessage() {
|
||||
return StepVerifier.create(Mono.empty()).verifyErrorMessage("foo");
|
||||
return Mono.empty().as(StepVerifier::create).verifyErrorMessage("foo");
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyTimeout() {
|
||||
return StepVerifier.create(Mono.empty()).verifyTimeout(Duration.ZERO);
|
||||
return Mono.empty().as(StepVerifier::create).verifyTimeout(Duration.ZERO);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +258,8 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
ImmutableSet<Stream<Integer>> testStreamsConcat() {
|
||||
return ImmutableSet.of(
|
||||
Stream.of(Stream.of(1), Stream.of(2)).flatMap(identity()),
|
||||
Stream.of(Stream.of(3), Stream.of(4)).flatMap(v -> v));
|
||||
Stream.of(Stream.of(3), Stream.of(4)).flatMap(v -> v),
|
||||
Stream.of(Stream.of(5), Stream.of(6)).flatMap(v -> Stream.empty()));
|
||||
}
|
||||
|
||||
Stream<Integer> testStreamTakeWhile() {
|
||||
|
||||
@@ -258,7 +258,9 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
|
||||
ImmutableSet<Stream<Integer>> testStreamsConcat() {
|
||||
return ImmutableSet.of(
|
||||
Streams.concat(Stream.of(1), Stream.of(2)), Streams.concat(Stream.of(3), Stream.of(4)));
|
||||
Streams.concat(Stream.of(1), Stream.of(2)),
|
||||
Streams.concat(Stream.of(3), Stream.of(4)),
|
||||
Stream.of(Stream.of(5), Stream.of(6)).flatMap(v -> Stream.empty()));
|
||||
}
|
||||
|
||||
Stream<Integer> testStreamTakeWhile() {
|
||||
|
||||
63768
integration-tests/checkstyle-10.12.4-expected-changes.patch
Normal file
63768
integration-tests/checkstyle-10.12.4-expected-changes.patch
Normal file
File diff suppressed because it is too large
Load Diff
140
integration-tests/checkstyle-10.12.4-expected-warnings.txt
Normal file
140
integration-tests/checkstyle-10.12.4-expected-warnings.txt
Normal file
@@ -0,0 +1,140 @@
|
||||
src/it/java/com/google/checkstyle/test/chapter7javadoc/rule711generalform/InvalidJavadocPositionTest.java:[35,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/it/java/com/google/checkstyle/test/chapter7javadoc/rule734nonrequiredjavadoc/InvalidJavadocPositionTest.java:[35,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/it/java/com/sun/checkstyle/test/chapter5comments/rule52documentationcomments/InvalidJavadocPositionTest.java:[35,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAbbreviationAsWordInNameTest.java:[117,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `enum` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAbbreviationAsWordInNameTest.java:[169,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAbbreviationAsWordInNameTest.java:[91,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `class` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAnnotationLocationTest.java:[104,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `enum` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAnnotationLocationTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `class` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAnnotationLocationTest.java:[71,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAnonInnerLengthTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAvoidEscapedUnicodeCharactersTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAvoidNoArgumentSuperConstructorCallTest.java:[41,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionEqualsAvoidNullTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `equals` is already defined in this class or a supertype)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionLambdaBodyLengthTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMissingJavadocTypeTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `class` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMissingOverrideTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `class` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMissingOverrideTest.java:[67,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionNeedBracesTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `do` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionOuterTypeNumberTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionUnnecessarySemicolonAfterTypeMemberDeclarationTest.java:[41,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionUnnecessarySemicolonInTryWithResourcesTest.java:[41,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/DetailAstImplTest.java:[597,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/PackageNamesLoaderTest.java:[58,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/api/FilterSetTest.java:[49,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/api/FullIdentTest.java:[41,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/AvoidEscapedUnicodeCharactersCheckTest.java:[77,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/DescendantTokenCheckTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/OrderedPropertiesCheckTest.java:[49,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/UniquePropertiesCheckTest.java:[65,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheckTest.java:[193,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `class` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheckTest.java:[206,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `enum` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheckTest.java:[217,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheckTest.java:[228,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `package` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationUseStyleCheckTest.java:[103,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyBlockCheckTest.java:[49,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyCatchBlockCheckTest.java:[46,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/LeftCurlyCheckTest.java:[59,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyCheckTest.java:[50,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/ArrayTrailingCommaCheckTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/AvoidDoubleBraceInitializationCheckTest.java:[37,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/AvoidInlineConditionalsCheckTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/AvoidNoArgumentSuperConstructorCallCheckTest.java:[37,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/CovariantEqualsCheckTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/DeclarationOrderCheckTest.java:[44,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/DefaultComesLastCheckTest.java:[55,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/ExplicitInitializationCheckTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/FallThroughCheckTest.java:[38,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/FinalLocalVariableCheckTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheckTest.java:[105,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalCatchCheckTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalInstantiationCheckTest.java:[48,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalThrowsCheckTest.java:[37,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalTokenCheckTest.java:[57,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `native` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/NestedIfDepthCheckTest.java:[37,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/NestedTryDepthCheckTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/NoArrayTrailingCommaCheckTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/NoEnumTrailingCommaCheckTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/OverloadMethodsDeclarationOrderCheckTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/ParameterAssignmentCheckTest.java:[45,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/RequireThisCheckTest.java:[290,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `static` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/RequireThisCheckTest.java:[373,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `for` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/ReturnCountCheckTest.java:[48,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/UnnecessaryParenthesesCheckTest.java:[125,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `return` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/UnnecessaryParenthesesCheckTest.java:[44,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/UnnecessarySemicolonAfterOuterTypeDeclarationCheckTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/UnnecessarySemicolonAfterTypeMemberDeclarationCheckTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/UnnecessarySemicolonInEnumerationCheckTest.java:[38,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/UnnecessarySemicolonInTryWithResourcesCheckTest.java:[38,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/design/InterfaceIsTypeCheckTest.java:[37,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/design/MutableExceptionCheckTest.java:[54,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/design/ThrowsCountCheckTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheckTest.java:[99,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `null` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheckTest.java:[81,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/InvalidJavadocPositionCheckTest.java:[59,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocContentLocationCheckTest.java:[57,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocContentLocationCheckTest.java:[75,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `package` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocContentLocationCheckTest.java:[83,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocNodeImplTest.java:[30,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTagInfoTest.java:[230,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `throws` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTagInfoTest.java:[294,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `return` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTagTest.java:[58,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTypeCheckTest.java:[83,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `protected` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTypeCheckTest.java:[89,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `public` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocVariableCheckTest.java:[60,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/MissingJavadocTypeCheckTest.java:[102,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `public` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/MissingJavadocTypeCheckTest.java:[94,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `protected` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/InlineTagUtilTest.java:[38,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `extractInlineTags` is already defined in this class or a supertype)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/metrics/ClassDataAbstractionCouplingCheckTest.java:[189,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `new` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/metrics/ClassFanOutComplexityCheckTest.java:[188,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `extends` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/metrics/ClassFanOutComplexityCheckTest.java:[196,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `implements` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/metrics/ClassFanOutComplexityCheckTest.java:[266,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `throws` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/naming/AbbreviationAsWordInNameCheckTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/naming/AccessModifierOptionTest.java:[45,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `case` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/naming/ConstantNameCheckTest.java:[67,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/naming/LocalFinalVariableNameCheckTest.java:[48,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/naming/LocalVariableNameCheckTest.java:[48,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/naming/MethodNameCheckTest.java:[48,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/naming/PackageNameCheckTest.java:[60,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/naming/ParameterNameCheckTest.java:[48,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `catch` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/naming/ParameterNameCheckTest.java:[78,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/naming/PatternVariableNameCheckTest.java:[47,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/naming/TypeNameCheckTest.java:[44,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpSinglelineCheckTest.java:[120,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpSinglelineJavaCheckTest.java:[195,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/sizes/AnonInnerLengthCheckTest.java:[56,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/sizes/LambdaBodyLengthCheckTest.java:[56,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/sizes/MethodCountCheckTest.java:[94,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `enum` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/sizes/MethodLengthCheckTest.java:[93,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `abstract` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/sizes/OuterTypeNumberCheckTest.java:[73,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/sizes/ParameterNumberCheckTest.java:[58,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/sizes/RecordComponentNumberCheckTest.java:[62,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyForInitializerPadCheckTest.java:[50,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyForIteratorPadCheckTest.java:[49,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyLineSeparatorCheckTest.java:[51,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/FileTabCharacterCheckTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/GenericWhitespaceCheckTest.java:[62,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/MethodParamPadCheckTest.java:[50,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceAfterCheckTest.java:[174,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `synchronized` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceAfterCheckTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceBeforeCaseDefaultColonCheckTest.java:[38,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceBeforeCheckTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/OperatorWrapCheckTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/ParenPadCheckTest.java:[44,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/TypecastParenPadCheckTest.java:[41,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAfterCheckTest.java:[46,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/filters/IntMatchFilterElementTest.java:[45,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/filters/SeverityMatchFilterTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressFilterElementTest.java:[185,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `equals` is already defined in this class or a supertype)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressWarningsFilterTest.java:[83,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressWithNearbyCommentFilterTest.java:[210,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionCommentFilterTest.java:[142,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionSingleFilterTest.java:[42,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/grammar/antlr4/Antlr4AstRegressionTest.java:[34,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `package` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/grammar/comments/CommentsTest.java:[53,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/grammar/java8/DefaultMethodsTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `switch` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/gui/BaseCellEditorTest.java:[31,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/utils/CheckUtilTest.java:[71,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `equals` is already defined in this class or a supertype)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/xpath/XpathQueryGeneratorTest.java:[205,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `package` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/xpath/XpathQueryGeneratorTest.java:[219,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `import` is not a valid identifier)
|
||||
src/test/java/com/puppycrawl/tools/checkstyle/xpath/XpathQueryGeneratorTest.java:[265,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `switch` is not a valid identifier)
|
||||
185
integration-tests/checkstyle-10.12.4-init.patch
Normal file
185
integration-tests/checkstyle-10.12.4-init.patch
Normal file
@@ -0,0 +1,185 @@
|
||||
--- a/pom.xml
|
||||
+++ b/pom.xml
|
||||
@@ -334,6 +334,12 @@
|
||||
<version>1.1.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
+ <dependency>
|
||||
+ <groupId>org.assertj</groupId>
|
||||
+ <artifactId>assertj-core</artifactId>
|
||||
+ <version>${assertj.version}</version>
|
||||
+ <scope>test</scope>
|
||||
+ </dependency>
|
||||
<dependency>
|
||||
<groupId>nl.jqno.equalsverifier</groupId>
|
||||
<artifactId>equalsverifier</artifactId>
|
||||
@@ -2397,8 +2403,10 @@
|
||||
<arg>-Xpkginfo:always</arg>
|
||||
<arg>-XDcompilePolicy=simple</arg>
|
||||
<arg>
|
||||
- -Xplugin:ErrorProne
|
||||
+ -Xplugin:ErrorProne ${error-prone.flags}
|
||||
</arg>
|
||||
+ <arg>-Xmaxwarns</arg>
|
||||
+ <arg>1000000</arg>
|
||||
</compilerArgs>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
@@ -2406,6 +2414,16 @@
|
||||
<artifactId>error_prone_core</artifactId>
|
||||
<version>${error-prone.version}</version>
|
||||
</path>
|
||||
+ <path>
|
||||
+ <groupId>tech.picnic.error-prone-support</groupId>
|
||||
+ <artifactId>error-prone-contrib</artifactId>
|
||||
+ <version>${error-prone-support.version}</version>
|
||||
+ </path>
|
||||
+ <path>
|
||||
+ <groupId>tech.picnic.error-prone-support</groupId>
|
||||
+ <artifactId>refaster-runner</artifactId>
|
||||
+ <version>${error-prone-support.version}</version>
|
||||
+ </path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</execution>
|
||||
@@ -2449,9 +2467,10 @@
|
||||
<arg>-Xpkginfo:always</arg>
|
||||
<arg>-XDcompilePolicy=simple</arg>
|
||||
<arg>
|
||||
- -Xplugin:ErrorProne \
|
||||
- -XepExcludedPaths:.*[\\/]resources[\\/].*
|
||||
+ -Xplugin:ErrorProne ${error-prone.flags}
|
||||
</arg>
|
||||
+ <arg>-Xmaxwarns</arg>
|
||||
+ <arg>1000000</arg>
|
||||
</compilerArgs>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
@@ -2459,6 +2478,16 @@
|
||||
<artifactId>error_prone_core</artifactId>
|
||||
<version>${error-prone.version}</version>
|
||||
</path>
|
||||
+ <path>
|
||||
+ <groupId>tech.picnic.error-prone-support</groupId>
|
||||
+ <artifactId>error-prone-contrib</artifactId>
|
||||
+ <version>${error-prone-support.version}</version>
|
||||
+ </path>
|
||||
+ <path>
|
||||
+ <groupId>tech.picnic.error-prone-support</groupId>
|
||||
+ <artifactId>refaster-runner</artifactId>
|
||||
+ <version>${error-prone-support.version}</version>
|
||||
+ </path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</execution>
|
||||
--- a/src/main/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinter.java
|
||||
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinter.java
|
||||
@@ -63,6 +63,8 @@ public final class DetailNodeTreeStringPrinter {
|
||||
* @return DetailNode tree
|
||||
* @throws IllegalArgumentException if there is an error parsing the Javadoc.
|
||||
*/
|
||||
+ // Invoking `getParseErrorMessage` requires that `status.getParseErrorMessage()` is `null`.
|
||||
+ @SuppressWarnings("CheckArgumentWithMessage")
|
||||
public static DetailNode parseJavadocAsDetailNode(DetailAST blockComment) {
|
||||
final JavadocDetailNodeParser parser = new JavadocDetailNodeParser();
|
||||
final ParseStatus status = parser.parseJavadocAsDetailNode(blockComment);
|
||||
--- a/src/main/java/com/puppycrawl/tools/checkstyle/Main.java
|
||||
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/Main.java
|
||||
@@ -626,6 +626,8 @@ public final class Main {
|
||||
+ "reported to standard out in plain format. Checkstyle requires a configuration "
|
||||
+ "XML file that configures the checks to apply.",
|
||||
mixinStandardHelpOptions = true)
|
||||
+ // XXX: Don't reorder arguments to `picocli.CommandLine.Option#names`.
|
||||
+ @SuppressWarnings("LexicographicalAnnotationAttributeListing")
|
||||
private static final class CliOptions {
|
||||
|
||||
/** Width of CLI help option. */
|
||||
--- a/src/main/java/com/puppycrawl/tools/checkstyle/SarifLogger.java
|
||||
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/SarifLogger.java
|
||||
@@ -139,6 +139,9 @@ public class SarifLogger extends AbstractAutomaticBean implements AuditListener
|
||||
@Override
|
||||
public void auditFinished(AuditEvent event) {
|
||||
final String version = SarifLogger.class.getPackage().getImplementationVersion();
|
||||
+ // Here `version` may be `null`, while `String#replace` requires non-`null` arguments.
|
||||
+ // XXX: Investigate better nullness handling by `IdentityConversion`.
|
||||
+ @SuppressWarnings("IdentityConversion")
|
||||
final String rendered = report
|
||||
.replace(VERSION_PLACEHOLDER, String.valueOf(version))
|
||||
.replace(RESULTS_PLACEHOLDER, String.join(",\n", results));
|
||||
--- a/src/main/java/com/puppycrawl/tools/checkstyle/site/SiteUtil.java
|
||||
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/site/SiteUtil.java
|
||||
@@ -419,6 +419,10 @@ public final class SiteUtil {
|
||||
* @return a set of properties for the given class.
|
||||
*/
|
||||
public static Set<String> getPropertiesForDocumentation(Class<?> clss, Object instance) {
|
||||
+ // XXX: File PR to replace `.collect(toSet())` with `.collect(toCollection(HashSet::new))`.
|
||||
+ // XXX: Update `CollectorMutability` to recognize cases such as this one, where the created
|
||||
+ // collection is clearly modified.
|
||||
+ @SuppressWarnings("CollectorMutability")
|
||||
final Set<String> properties =
|
||||
getProperties(clss).stream()
|
||||
.filter(prop -> {
|
||||
--- a/src/test/java/com/puppycrawl/tools/checkstyle/CheckerTest.java
|
||||
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/CheckerTest.java
|
||||
@@ -93,6 +93,8 @@ import de.thetaphi.forbiddenapis.SuppressForbidden;
|
||||
* @noinspectionreason ClassWithTooManyDependencies - complex tests require a large number
|
||||
* of imports
|
||||
*/
|
||||
+// This class is referenced from another package.
|
||||
+@SuppressWarnings("JUnitClassModifiers")
|
||||
public class CheckerTest extends AbstractModuleTestSupport {
|
||||
|
||||
@TempDir
|
||||
--- a/src/test/java/com/puppycrawl/tools/checkstyle/ConfigurationLoaderTest.java
|
||||
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/ConfigurationLoaderTest.java
|
||||
@@ -46,6 +46,8 @@ import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
|
||||
/**
|
||||
* Unit test for ConfigurationLoader.
|
||||
*/
|
||||
+// This class is referenced from another package.
|
||||
+@SuppressWarnings("JUnitClassModifiers")
|
||||
public class ConfigurationLoaderTest extends AbstractPathTestSupport {
|
||||
|
||||
@Override
|
||||
--- a/src/test/java/com/puppycrawl/tools/checkstyle/PackageObjectFactoryTest.java
|
||||
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/PackageObjectFactoryTest.java
|
||||
@@ -98,6 +98,8 @@ public class PackageObjectFactoryTest {
|
||||
public void testCtorNullPackageException1() {
|
||||
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
try {
|
||||
+ // XXX: Don't suggest `ImmutableSet.of(elem)` for nullable `elem`.
|
||||
+ @SuppressWarnings("ImmutableSetOf1")
|
||||
final Object test = new PackageObjectFactory(Collections.singleton(null), classLoader);
|
||||
assertWithMessage("Exception is expected but got " + test).fail();
|
||||
}
|
||||
@@ -126,6 +128,8 @@ public class PackageObjectFactoryTest {
|
||||
public void testCtorNullPackageException3() {
|
||||
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
try {
|
||||
+ // XXX: Don't suggest `ImmutableSet.of(elem)` for nullable `elem`.
|
||||
+ @SuppressWarnings("ImmutableSetOf1")
|
||||
final Object test = new PackageObjectFactory(Collections.singleton(null), classLoader,
|
||||
TRY_IN_ALL_REGISTERED_PACKAGES);
|
||||
assertWithMessage("Exception is expected but got " + test).fail();
|
||||
--- a/src/test/java/com/puppycrawl/tools/checkstyle/TreeWalkerTest.java
|
||||
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/TreeWalkerTest.java
|
||||
@@ -79,6 +79,8 @@ import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
|
||||
* @noinspectionreason ClassWithTooManyDependencies - complex tests require a
|
||||
* large number of imports
|
||||
*/
|
||||
+// This class is referenced from another package.
|
||||
+@SuppressWarnings("JUnitClassModifiers")
|
||||
public class TreeWalkerTest extends AbstractModuleTestSupport {
|
||||
|
||||
@TempDir
|
||||
--- a/src/test/java/com/puppycrawl/tools/checkstyle/utils/CheckUtilTest.java
|
||||
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/utils/CheckUtilTest.java
|
||||
@@ -47,6 +47,8 @@ import com.puppycrawl.tools.checkstyle.checks.coding.NestedIfDepthCheck;
|
||||
import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck;
|
||||
import com.puppycrawl.tools.checkstyle.checks.naming.AccessModifierOption;
|
||||
|
||||
+// This class is referenced from another package.
|
||||
+@SuppressWarnings("JUnitClassModifiers")
|
||||
public class CheckUtilTest extends AbstractModuleTestSupport {
|
||||
|
||||
@Override
|
||||
183
integration-tests/checkstyle-10.12.4.sh
Executable file
183
integration-tests/checkstyle-10.12.4.sh
Executable file
@@ -0,0 +1,183 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e -u -o pipefail
|
||||
|
||||
integration_test_root="$(readlink -f "$(dirname "${0}")")"
|
||||
error_prone_support_root="${integration_test_root}/.."
|
||||
repos_root="${integration_test_root}/.repos"
|
||||
|
||||
test_name="$(basename "${0}" .sh)"
|
||||
project=checkstyle
|
||||
repository=https://github.com/checkstyle/checkstyle.git
|
||||
revision=checkstyle-10.12.4
|
||||
|
||||
if [ "${#}" -gt 2 ] || ([ "${#}" = 2 ] && [ "${1:---sync}" != '--sync' ]); then
|
||||
echo "Usage: ${0} [--sync] [<report_directory>]"
|
||||
exit 1
|
||||
fi
|
||||
do_sync="$([ "${#}" = 0 ] || [ "${1:-}" != '--sync' ] || echo 1)"
|
||||
report_directory="$([ "${#}" = 0 ] || ([ -z "${do_sync}" ] && echo "${1}") || ([ "${#}" = 1 ] || echo "${2}"))"
|
||||
|
||||
if [ -n "${report_directory}" ]; then
|
||||
mkdir -p "${report_directory}"
|
||||
else
|
||||
report_directory="$(mktemp -d)"
|
||||
trap 'rm -rf -- "${report_directory}"' INT TERM HUP EXIT
|
||||
fi
|
||||
|
||||
# XXX: Configure Renovate to manage the AssertJ version declared here.
|
||||
shared_build_flags="
|
||||
-Perror-prone-compile,error-prone-test-compile
|
||||
-Dassertj.version=3.24.2
|
||||
-Derror-prone.version=$(
|
||||
mvn -f "${error_prone_support_root}" help:evaluate -Dexpression=version.error-prone -q -DforceStdout
|
||||
)
|
||||
-Derror-prone-support.version=$(
|
||||
mvn -f "${error_prone_support_root}" help:evaluate -Dexpression=project.version -q -DforceStdout
|
||||
)
|
||||
-DadditionalSourceDirectories=\${project.basedir}\${file.separator}src\${file.separator}it\${file.separator}java,\${project.basedir}\${file.separator}src\${file.separator}xdocs-examples\${file.separator}java
|
||||
"
|
||||
|
||||
# XXX: Configure Renovate to manage the fmt-maven-plugin version declared here.
|
||||
# XXX: Once GitHub actions uses Maven 3.9.2+, we can inline this variable with
|
||||
# version reference `${fmt.version}`, and `-Dfmt.version=2.21.1` added to
|
||||
# `shared_build_flags`.
|
||||
format_goal='com.spotify.fmt:fmt-maven-plugin:2.21.1:format'
|
||||
|
||||
error_prone_shared_flags='-XepExcludedPaths:(\Q${project.basedir}${file.separator}src${file.separator}\E(it|test|xdocs-examples)\Q${file.separator}resources\E|\Q${project.build.directory}${file.separator}\E).*'
|
||||
|
||||
error_prone_patch_flags="${error_prone_shared_flags} -XepPatchLocation:IN_PLACE -XepPatchChecks:$(
|
||||
find "${error_prone_support_root}" -path "*/META-INF/services/com.google.errorprone.bugpatterns.BugChecker" -print0 \
|
||||
| xargs -0 grep -hoP '[^.]+$' \
|
||||
| paste -s -d ','
|
||||
)"
|
||||
|
||||
error_prone_validation_flags="${error_prone_shared_flags} -XepDisableAllChecks $(
|
||||
find "${error_prone_support_root}" -path "*/META-INF/services/com.google.errorprone.bugpatterns.BugChecker" -print0 \
|
||||
| xargs -0 grep -hoP '[^.]+$' \
|
||||
| sed -r 's,(.*),-Xep:\1:WARN,' \
|
||||
| paste -s -d ' '
|
||||
)"
|
||||
|
||||
echo "Shared build flags: ${shared_build_flags}"
|
||||
echo "Error Prone patch flags: ${error_prone_patch_flags}"
|
||||
echo "Error Prone validation flags: ${error_prone_validation_flags}"
|
||||
|
||||
mkdir -p "${repos_root}"
|
||||
|
||||
# Make sure that the targeted tag of the project's Git repository is checked
|
||||
# out.
|
||||
project_root="${repos_root}/${project}"
|
||||
if [ ! -d "${project_root}" ]; then
|
||||
# The repository has not yet been cloned; create a shallow clone.
|
||||
git clone --branch "${revision}" --depth 1 "${repository}" "${project_root}"
|
||||
else
|
||||
# The repository does already appear to exist. Try to check out the requested
|
||||
# tag if possible, and fetch it otherwise.
|
||||
#
|
||||
# Under certain circumstances this does not cause the relevant tag to be
|
||||
# created, so if necessary we manually create it.
|
||||
git -C "${project_root}" checkout --force "${revision}" 2>/dev/null \
|
||||
|| (
|
||||
git -C "${project_root}" fetch --depth 1 "${repository}" "${revision}" \
|
||||
&& git -C "${project_root}" checkout --force FETCH_HEAD \
|
||||
&& (git -C "${project_root}" tag "${revision}" || true)
|
||||
)
|
||||
fi
|
||||
|
||||
pushd "${project_root}"
|
||||
|
||||
# Make sure that Git is sufficiently configured to enable committing to the
|
||||
# project's Git repository.
|
||||
git config user.email || git config user.email "integration-test@example.com"
|
||||
git config user.name || git config user.name "Integration Test"
|
||||
|
||||
# Prepare the code for analysis by (a) applying the minimal set of changes
|
||||
# required to run Error Prone with Error Prone Support and (b) formatting the
|
||||
# code using the same method by which it will be formatted after each
|
||||
# compilation round. The initial formatting operation ensures that subsequent
|
||||
# modifications can be rendered in a clean manner.
|
||||
git clean -fdx
|
||||
git apply < "${integration_test_root}/${test_name}-init.patch"
|
||||
git commit -m 'dependency: Introduce Error Prone Support' .
|
||||
mvn ${shared_build_flags} "${format_goal}"
|
||||
git commit -m 'minor: Reformat using Google Java Format' .
|
||||
diff_base="$(git rev-parse HEAD)"
|
||||
|
||||
# Apply Error Prone Support-suggested changes until a fixed point is reached.
|
||||
function apply_patch() {
|
||||
local extra_build_args="${1}"
|
||||
|
||||
mvn ${shared_build_flags} ${extra_build_args} \
|
||||
package "${format_goal}" \
|
||||
-Derror-prone.flags="${error_prone_patch_flags}" \
|
||||
-DskipTests
|
||||
|
||||
if ! git diff --exit-code; then
|
||||
git commit -m 'minor: Apply patches' .
|
||||
|
||||
# Changes were applied, so another compilation round may apply yet more
|
||||
# changes. For performance reasons we perform incremental compilation,
|
||||
# enabled using a misleading flag. (See
|
||||
# https://issues.apache.org/jira/browse/MCOMPILER-209 for details.)
|
||||
apply_patch '-Dmaven.compiler.useIncrementalCompilation=false'
|
||||
elif [ "${extra_build_args}" != 'clean' ]; then
|
||||
# No changes were applied. We'll attempt one more round in which all files
|
||||
# are recompiled, because there are cases in which violations are missed
|
||||
# during incremental compilation.
|
||||
apply_patch 'clean'
|
||||
fi
|
||||
}
|
||||
apply_patch ''
|
||||
|
||||
# Run one more full build and log the output.
|
||||
#
|
||||
# By also running the tests, we validate that the (majority of) applied changes
|
||||
# are behavior preserving. Some tests are skipped:
|
||||
# - The `metadataFilesGenerationAllFiles` test is skipped because it makes line
|
||||
# number assertions that will fail when the code is formatted or patched.
|
||||
# - The `allCheckSectionJavaDocs` test is skipped because is validates that
|
||||
# Javadoc has certain closing tags that are removed by Google Java Format.
|
||||
validation_build_log="${report_directory}/${test_name}-validation-build-log.txt"
|
||||
mvn ${shared_build_flags} \
|
||||
clean package \
|
||||
-Derror-prone.flags="${error_prone_validation_flags}" \
|
||||
-Dtest='
|
||||
!MetadataGeneratorUtilTest#metadataFilesGenerationAllFiles,
|
||||
!XdocsJavaDocsTest#allCheckSectionJavaDocs' \
|
||||
| tee "${validation_build_log}" \
|
||||
|| failure=1
|
||||
|
||||
# Collect the applied changes.
|
||||
expected_changes="${integration_test_root}/${test_name}-expected-changes.patch"
|
||||
actual_changes="${report_directory}/${test_name}-changes.patch"
|
||||
(git diff "${diff_base}"..HEAD | grep -vP '^(diff|index)' || true) > "${actual_changes}"
|
||||
|
||||
# Collect the warnings reported by Error Prone Support checks.
|
||||
expected_warnings="${integration_test_root}/${test_name}-expected-warnings.txt"
|
||||
actual_warnings="${report_directory}/${test_name}-validation-build-warnings.txt"
|
||||
(grep -oP "(?<=^\\Q[WARNING] ${PWD}/\\E).*" "${validation_build_log}" | grep -P '\] \[' || true) | LC_ALL=C sort > "${actual_warnings}"
|
||||
|
||||
# Persist or validate the applied changes and reported warnings.
|
||||
if [ -n "${do_sync}" ]; then
|
||||
echo 'Saving changes...'
|
||||
cp "${actual_changes}" "${expected_changes}"
|
||||
cp "${actual_warnings}" "${expected_warnings}"
|
||||
else
|
||||
echo 'Inspecting changes...'
|
||||
# XXX: This "diff of diffs" also contains vacuous sections, introduced due to
|
||||
# line offset differences. Try to omit those from the final output.
|
||||
if ! diff -u "${expected_changes}" "${actual_changes}"; then
|
||||
echo 'There are unexpected changes.'
|
||||
failure=1
|
||||
fi
|
||||
echo 'Inspecting emitted warnings...'
|
||||
if ! diff -u "${expected_warnings}" "${actual_warnings}"; then
|
||||
echo 'Diagnostics output changed.'
|
||||
failure=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "${failure:-}" ]; then
|
||||
exit 1
|
||||
fi
|
||||
183
pom.xml
183
pom.xml
@@ -47,9 +47,9 @@
|
||||
<module>refaster-test-support</module>
|
||||
</modules>
|
||||
|
||||
<scm>
|
||||
<scm child.scm.developerConnection.inherit.append.path="false" child.scm.url.inherit.append.path="false">
|
||||
<developerConnection>scm:git:git@github.com:PicnicSupermarket/error-prone-support.git</developerConnection>
|
||||
<tag>v0.12.0</tag>
|
||||
<tag>HEAD</tag>
|
||||
<url>https://github.com/PicnicSupermarket/error-prone-support</url>
|
||||
</scm>
|
||||
<issueManagement>
|
||||
@@ -100,6 +100,10 @@
|
||||
<!-- The test JVMs are short-running. By disabling certain
|
||||
expensive JIT optimizations we actually speed up most tests. -->
|
||||
-XX:TieredStopAtLevel=1
|
||||
<!-- The test JVMs run in a non-interactive and generally
|
||||
multi-core context, where the Parallel Garbage Collector generally
|
||||
has the highest throughput. -->
|
||||
-XX:+UseParallelGC
|
||||
<!-- We cap memory usage. This may be relevant for build agents,
|
||||
but also prevents excessive memory usage by heavily parallelized
|
||||
local builds. -->
|
||||
@@ -141,7 +145,7 @@
|
||||
<groupId.error-prone>com.google.errorprone</groupId.error-prone>
|
||||
<!-- The build timestamp is derived from the most recent commit
|
||||
timestamp in support of reproducible builds. -->
|
||||
<project.build.outputTimestamp>2023-10-04T14:40:37Z</project.build.outputTimestamp>
|
||||
<project.build.outputTimestamp>${git.commit.time}</project.build.outputTimestamp>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<!-- Glob pattern identifying Refaster rule definition files. These
|
||||
Java classes don't contain "regular" code, and thus require special
|
||||
@@ -201,16 +205,16 @@
|
||||
<version.auto-value>1.10.4</version.auto-value>
|
||||
<version.error-prone>${version.error-prone-orig}</version.error-prone>
|
||||
<version.error-prone-fork>v${version.error-prone-orig}-picnic-1</version.error-prone-fork>
|
||||
<version.error-prone-orig>2.22.0</version.error-prone-orig>
|
||||
<version.error-prone-slf4j>0.1.20</version.error-prone-slf4j>
|
||||
<version.error-prone-orig>2.23.0</version.error-prone-orig>
|
||||
<version.error-prone-slf4j>0.1.21</version.error-prone-slf4j>
|
||||
<version.guava-beta-checker>1.0</version.guava-beta-checker>
|
||||
<version.jdk>11</version.jdk>
|
||||
<version.maven>3.8.7</version.maven>
|
||||
<version.mockito>5.6.0</version.mockito>
|
||||
<version.mockito>5.8.0</version.mockito>
|
||||
<version.nopen-checker>1.0.1</version.nopen-checker>
|
||||
<version.nullaway>0.10.14</version.nullaway>
|
||||
<version.pitest-git>1.1.2</version.pitest-git>
|
||||
<version.surefire>3.1.2</version.surefire>
|
||||
<version.nullaway>0.10.18</version.nullaway>
|
||||
<version.pitest-git>1.1.4</version.pitest-git>
|
||||
<version.surefire>3.2.2</version.surefire>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -268,7 +272,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson</groupId>
|
||||
<artifactId>jackson-bom</artifactId>
|
||||
<version>2.15.3</version>
|
||||
<version>2.16.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -333,7 +337,7 @@
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-bom</artifactId>
|
||||
<version>2022.0.12</version>
|
||||
<version>2023.0.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -345,12 +349,12 @@
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>1.6.11</version>
|
||||
<version>1.6.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>2.2.17</version>
|
||||
<version>2.2.19</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
@@ -382,7 +386,7 @@
|
||||
<dependency>
|
||||
<groupId>net.bytebuddy</groupId>
|
||||
<artifactId>byte-buddy</artifactId>
|
||||
<version>1.14.9</version>
|
||||
<version>1.14.10</version>
|
||||
</dependency>
|
||||
<!-- Specified so that Renovate will file Maven upgrade PRs, which
|
||||
subsequently will cause `maven-enforcer-plugin` to require that
|
||||
@@ -407,7 +411,7 @@
|
||||
<dependency>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
<artifactId>checker-qual</artifactId>
|
||||
<version>3.39.0</version>
|
||||
<version>3.41.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
@@ -427,7 +431,7 @@
|
||||
<dependency>
|
||||
<groupId>org.junit</groupId>
|
||||
<artifactId>junit-bom</artifactId>
|
||||
<version>5.10.0</version>
|
||||
<version>5.10.1</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -441,7 +445,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongodb-driver-core</artifactId>
|
||||
<version>4.11.0</version>
|
||||
<version>4.11.1</version>
|
||||
<!-- XXX: Drop this exclusion once we forgo enforcement of JDK
|
||||
11 bytecode version compatibility. -->
|
||||
<exclusions>
|
||||
@@ -461,14 +465,14 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>5.3.30</version>
|
||||
<version>5.3.31</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test</artifactId>
|
||||
<version>2.7.16</version>
|
||||
<version>2.7.18</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
@@ -529,6 +533,14 @@
|
||||
<forkMode>never</forkMode>
|
||||
<failOnError>false</failOnError>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>check-source-format</id>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>de.thetaphi</groupId>
|
||||
@@ -580,7 +592,7 @@
|
||||
<plugin>
|
||||
<groupId>io.github.git-commit-id</groupId>
|
||||
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>7.0.0</version>
|
||||
<configuration>
|
||||
<injectAllReactorProjects>true</injectAllReactorProjects>
|
||||
<runOnlyOnce>true</runOnlyOnce>
|
||||
@@ -599,7 +611,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.3.1</version>
|
||||
<configuration>
|
||||
<checkstyleRules>
|
||||
<!-- We only enable rules that are not enforced by
|
||||
@@ -704,6 +716,10 @@
|
||||
<!-- Instead, please use
|
||||
`com.google.errorprone.annotations.Immutable`. -->
|
||||
</property>
|
||||
<property name="illegalClasses" value="org.jetbrains.annotations.CheckReturnValue">
|
||||
<!-- Instead, please use
|
||||
`com.google.errorprone.annotations.CheckReturnValue`. -->
|
||||
</property>
|
||||
<property name="illegalClasses" value="org.jetbrains.annotations.VisibleForTesting">
|
||||
<!-- Instead, please use
|
||||
`com.google.common.annotations.VisibleForTesting`. -->
|
||||
@@ -810,6 +826,7 @@
|
||||
<module name="RedundantModifier" />
|
||||
<module name="SimplifyBooleanExpression" />
|
||||
<module name="SimplifyBooleanReturn" />
|
||||
<module name="SummaryJavadoc" />
|
||||
<module name="SuppressWarningsHolder">
|
||||
<property name="aliasList" value="com.puppycrawl.tools.checkstyle.checks.coding.UnusedLocalVariableCheck=unused" />
|
||||
</module>
|
||||
@@ -828,28 +845,21 @@
|
||||
<module name="io.spring.nohttp.checkstyle.check.NoHttpCheck" />
|
||||
</module>
|
||||
</checkstyleRules>
|
||||
<excludeGeneratedSources>true</excludeGeneratedSources>
|
||||
<failOnViolation>false</failOnViolation>
|
||||
<includeTestSourceDirectory>true</includeTestSourceDirectory>
|
||||
<!-- The plugin's "excludes" property accepts an Ant
|
||||
pattern, but does not match against the full path. So
|
||||
rather than explicitly excluding generated sources, we
|
||||
have to explicitly include "original" sources. -->
|
||||
<sourceDirectories>
|
||||
<sourceDirectory>${project.build.sourceDirectory}</sourceDirectory>
|
||||
</sourceDirectories>
|
||||
<testSourceDirectories>
|
||||
<testSourceDirectory>${project.build.testSourceDirectory}</testSourceDirectory>
|
||||
<!-- Refaster input and output test files represent
|
||||
valid Java code, exposed as resources on the test
|
||||
classpath. -->
|
||||
<testSourceDirectory>${basedir}/src/test/resources</testSourceDirectory>
|
||||
</testSourceDirectories>
|
||||
<resourceIncludes>**/*</resourceIncludes>
|
||||
<!-- XXX: The generated
|
||||
`target/generated-sources/license/THIRD-PARTY.txt`
|
||||
files are not excluded by the `excludeGeneratedSources`
|
||||
setting. Consider filing an issue for this. -->
|
||||
<resourceExcludes>THIRD-PARTY.txt</resourceExcludes>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>10.12.4</version>
|
||||
<version>10.12.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.spring.nohttp</groupId>
|
||||
@@ -869,7 +879,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<version>3.3.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@@ -950,7 +960,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.6.0</version>
|
||||
<version>3.6.1</version>
|
||||
<configuration>
|
||||
<!-- XXX: Drop `ignoreAllNonTestScoped` once
|
||||
https://issues.apache.org/jira/browse/MNG-6058 is
|
||||
@@ -1033,18 +1043,7 @@
|
||||
</requireMavenVersion>
|
||||
<requireNoRepositories />
|
||||
<requirePluginVersions />
|
||||
<requireUpperBoundDeps>
|
||||
<excludes>
|
||||
<!-- XXX:
|
||||
`com.google.errorprone:error_prone_test_helpers`
|
||||
pulls in a more recent version of Truth
|
||||
than
|
||||
`com.google.testing.compile:compile-testing`,
|
||||
but the latter is incompatible with said
|
||||
never version. -->
|
||||
<exclude>com.google.truth:truth</exclude>
|
||||
</excludes>
|
||||
</requireUpperBoundDeps>
|
||||
<requireUpperBoundDeps />
|
||||
</rules>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
@@ -1112,7 +1111,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.6.0</version>
|
||||
<version>3.6.3</version>
|
||||
<configuration>
|
||||
<additionalJOptions>
|
||||
<additionalJOption>--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</additionalJOption>
|
||||
@@ -1198,12 +1197,12 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>3.4.0</version>
|
||||
<version>3.5.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<version>2.3.0</version>
|
||||
<configuration>
|
||||
<includedLicenses>
|
||||
<!-- The SPDX IDs of licenses of third-party
|
||||
@@ -1302,11 +1301,19 @@
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>tidy-maven-plugin</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>check-pom</id>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.16.1</version>
|
||||
<version>2.16.2</version>
|
||||
<configuration>
|
||||
<updateBuildOutputTimestampPolicy>never</updateBuildOutputTimestampPolicy>
|
||||
</configuration>
|
||||
@@ -1345,7 +1352,7 @@
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.10</version>
|
||||
<version>0.8.11</version>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<!-- Refaster rules are tested using a custom method
|
||||
@@ -1357,7 +1364,7 @@
|
||||
<plugin>
|
||||
<groupId>org.pitest</groupId>
|
||||
<artifactId>pitest-maven</artifactId>
|
||||
<version>1.15.1</version>
|
||||
<version>1.15.3</version>
|
||||
<configuration>
|
||||
<excludedClasses>
|
||||
<!-- AutoValue generated classes. -->
|
||||
@@ -1396,7 +1403,7 @@
|
||||
<dependency>
|
||||
<groupId>org.pitest</groupId>
|
||||
<artifactId>pitest-junit5-plugin</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.2.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
@@ -1538,7 +1545,7 @@
|
||||
`BugChecker` test code and the Refaster test files) does not
|
||||
exhibit anti-patterns other than those associated with the
|
||||
check/rule under test. Ideally all test cases are realistic. -->
|
||||
<error-prone.self-check-args>-XepAllSuggestionsAsWarnings -Xep:MethodReferenceUsage:OFF</error-prone.self-check-args>
|
||||
<error-prone.self-check-args>-Xep:MethodReferenceUsage:OFF</error-prone.self-check-args>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
@@ -1563,6 +1570,31 @@
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<!-- A counterpart to the `disallow-warnings` profile which
|
||||
explicitly "tones down" plugins enabled by the `build-checks`
|
||||
profile. Necessary for dealing with plugins that default to failing
|
||||
the build upon encountering a violation. -->
|
||||
<id>avoid-errors</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>verification.warn</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>tidy-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<!-- By default, we verify various aspects of a module and the
|
||||
artifact(s) it produces. We define these checks in a profile so
|
||||
@@ -1583,14 +1615,6 @@
|
||||
<plugin>
|
||||
<groupId>com.spotify.fmt</groupId>
|
||||
<artifactId>fmt-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>check-source-format</id>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>de.thetaphi</groupId>
|
||||
@@ -1669,6 +1693,10 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>tidy-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.gaul</groupId>
|
||||
<artifactId>modernizer-maven-plugin</artifactId>
|
||||
@@ -1703,15 +1731,17 @@
|
||||
failing the build on the first error
|
||||
encountered. -->
|
||||
-XepAllErrorsAsWarnings
|
||||
-XepAllSuggestionsAsWarnings
|
||||
<!-- We want to enable almost all Error
|
||||
Prone bug pattern checkers, so we enable
|
||||
all and then selectively deactivate some. -->
|
||||
-XepAllDisabledChecksAsWarnings
|
||||
<!-- Some generated classes violate Error
|
||||
Prone bug patterns. We cannot in all cases
|
||||
avoid that, so we simply tell Error Prone
|
||||
not to warn about generated code. -->
|
||||
-XepDisableWarningsInGeneratedCode
|
||||
<!-- We want to enable almost all Error
|
||||
Prone bug pattern checkers, so we enable
|
||||
all and then selectively deactivate some. -->
|
||||
-XepAllDisabledChecksAsWarnings
|
||||
-XepExcludedPaths:\Q${project.build.directory}${file.separator}\E.*
|
||||
<!-- We don't target Android. -->
|
||||
-Xep:AndroidJdkLibsChecker:OFF
|
||||
<!-- XXX: Enable this once we open-source
|
||||
@@ -1738,11 +1768,8 @@
|
||||
-XepOpt:NullAway:CheckOptionalEmptiness=true
|
||||
-XepOpt:Nullness:Conservative=false
|
||||
-XepOpt:StatementSwitchToExpressionSwitch:EnableAssignmentSwitchConversion=true
|
||||
-XepOpt:StatementSwitchToExpressionSwitch:EnableDirectConversion=true
|
||||
-XepOpt:StatementSwitchToExpressionSwitch:EnableReturnSwitchConversion=true
|
||||
<!-- XXX: Enable once this check respects
|
||||
the compilation source version. See
|
||||
https://github.com/google/error-prone/pull/3646.
|
||||
-XepOpt:StatementSwitchToExpressionSwitch:EnableDirectConversion=true -->
|
||||
<!-- Append additional custom arguments. -->
|
||||
${error-prone.patch-args}
|
||||
${error-prone.self-check-args}
|
||||
@@ -1775,10 +1802,10 @@
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<!-- The `build-checks` and `error-prone` profiles enable a bunch
|
||||
of additional compile checks. By default, those warnings break the
|
||||
build. This profile allows one to collect all build warnings
|
||||
without failing the build. -->
|
||||
<!-- The `build-checks` and `error-prone` profiles enable numerous
|
||||
additional validations. By default, any violations break the build.
|
||||
This profile allows one to collect all violations without failing
|
||||
the build. -->
|
||||
<id>disallow-warnings</id>
|
||||
<activation>
|
||||
<property>
|
||||
|
||||
@@ -55,6 +55,11 @@
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
package tech.picnic.errorprone.refaster.matchers;
|
||||
|
||||
import static com.google.common.base.Verify.verify;
|
||||
import static com.google.errorprone.matchers.FieldMatchers.staticField;
|
||||
import static com.google.errorprone.matchers.Matchers.allOf;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.argumentCount;
|
||||
import static com.google.errorprone.matchers.Matchers.isPrimitiveType;
|
||||
import static com.google.errorprone.matchers.Matchers.isSameType;
|
||||
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.toType;
|
||||
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.NewArrayTree;
|
||||
import com.sun.source.tree.NewClassTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* A matcher of expressions that are guaranteed to yield "empty" instances, as defined by their
|
||||
* respective types.
|
||||
*/
|
||||
// XXX: Also match (effectively) final variables that reference provably-empty objects.
|
||||
// XXX: Also handle `#copyOf(someEmptyInstance)`, `#sortedCopyOf(someEmptyInstance)`,
|
||||
// `Sets.immutableEnumSet(emptyIterable)` (and other `Sets` methods), `EnumSet.noneOf(...)`,
|
||||
// `emptyCollection.stream()`, `emptyStream.collect(...)`, `emptyMap.{keySet,values,entrySet}()`,
|
||||
// etc.
|
||||
// XXX: Also recognize null-hostile "container" expression types that can only reference empty
|
||||
// instances, such as `ImmutableCollection<Void>` and `Flux<Void>`.
|
||||
// XXX: Also recognize empty instances of `Optional`, `OptionalInt`, `OptionalLong`, and
|
||||
// `OptionalDouble`.
|
||||
// XXX: Also recognize empty builders and `emptyBuilder.build()` invocations.
|
||||
public final class IsEmpty implements Matcher<ExpressionTree> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Pattern EMPTY_INSTANCE_FACTORY_METHOD_PATTERN = Pattern.compile("empty.*");
|
||||
private static final Matcher<Tree> EMPTY_COLLECTION_CONSTRUCTOR_ARGUMENT =
|
||||
anyOf(isPrimitiveType(), isSubtypeOf(Comparator.class));
|
||||
// XXX: Extend this list to include additional JDK collection types with a public constructor.
|
||||
private static final Matcher<ExpressionTree> MUTABLE_COLLECTION_TYPE =
|
||||
anyOf(
|
||||
isSameType(ArrayList.class),
|
||||
isSameType(HashMap.class),
|
||||
isSameType(HashSet.class),
|
||||
isSameType(LinkedHashMap.class),
|
||||
isSameType(LinkedHashSet.class),
|
||||
isSameType(LinkedList.class),
|
||||
isSameType(Stack.class),
|
||||
isSameType(TreeMap.class),
|
||||
isSameType(TreeSet.class),
|
||||
isSameType(Vector.class));
|
||||
private static final Matcher<ExpressionTree> EMPTY_INSTANCE_FACTORY =
|
||||
anyOf(
|
||||
staticField(Collections.class.getName(), "EMPTY_LIST"),
|
||||
staticField(Collections.class.getName(), "EMPTY_MAP"),
|
||||
staticField(Collections.class.getName(), "EMPTY_SET"),
|
||||
toType(
|
||||
MethodInvocationTree.class,
|
||||
allOf(
|
||||
argumentCount(0),
|
||||
anyOf(
|
||||
staticMethod()
|
||||
.onClass(Collections.class.getName())
|
||||
.withNameMatching(EMPTY_INSTANCE_FACTORY_METHOD_PATTERN),
|
||||
staticMethod()
|
||||
.onDescendantOfAny(
|
||||
ImmutableCollection.class.getName(),
|
||||
ImmutableMap.class.getName(),
|
||||
ImmutableMultimap.class.getName(),
|
||||
List.class.getName(),
|
||||
Map.class.getName(),
|
||||
Set.class.getName(),
|
||||
Stream.class.getName())
|
||||
.named("of"),
|
||||
staticMethod()
|
||||
.onClassAny(
|
||||
Stream.class.getName(),
|
||||
"reactor.core.publisher.Flux",
|
||||
"reactor.core.publisher.Mono",
|
||||
"reactor.util.context.Context")
|
||||
.named("empty"),
|
||||
staticMethod()
|
||||
.onDescendantOf("reactor.core.publisher.Flux")
|
||||
.named("just")))));
|
||||
|
||||
/** Instantiates a new {@link IsEmpty} instance. */
|
||||
public IsEmpty() {}
|
||||
|
||||
@Override
|
||||
public boolean matches(ExpressionTree tree, VisitorState state) {
|
||||
return isEmptyArrayCreation(tree)
|
||||
|| EMPTY_INSTANCE_FACTORY.matches(tree, state)
|
||||
|| isEmptyCollectionConstructor(tree, state);
|
||||
}
|
||||
|
||||
private boolean isEmptyCollectionConstructor(ExpressionTree tree, VisitorState state) {
|
||||
if (!(tree instanceof NewClassTree) || !MUTABLE_COLLECTION_TYPE.matches(tree, state)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<? extends ExpressionTree> arguments = ((NewClassTree) tree).getArguments();
|
||||
if (arguments.stream().allMatch(a -> EMPTY_COLLECTION_CONSTRUCTOR_ARGUMENT.matches(a, state))) {
|
||||
/*
|
||||
* This is a default constructor, or a constructor that creates an empty collection using
|
||||
* custom (re)size/load factor parameters and/or a custom `Comparator`.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This looks like a copy constructor, in which case the resultant collection is empty if its
|
||||
* argument is.
|
||||
*/
|
||||
verify(arguments.size() == 1, "Unexpected %s-ary constructor", arguments.size());
|
||||
return matches(arguments.get(0), state);
|
||||
}
|
||||
|
||||
private static boolean isEmptyArrayCreation(ExpressionTree tree) {
|
||||
if (!(tree instanceof NewArrayTree)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NewArrayTree newArray = (NewArrayTree) tree;
|
||||
return (!newArray.getDimensions().isEmpty()
|
||||
&& ASTHelpers.constValue(newArray.getDimensions().get(0), Integer.class) == 0)
|
||||
|| (newArray.getInitializers() != null && newArray.getInitializers().isEmpty());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package tech.picnic.errorprone.refaster.matchers;
|
||||
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.toType;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.LambdaExpressionTree;
|
||||
import com.sun.source.tree.LambdaExpressionTree.BodyKind;
|
||||
import java.util.function.DoubleUnaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntUnaryOperator;
|
||||
import java.util.function.LongUnaryOperator;
|
||||
|
||||
/** A matcher of expressions that represent identity operations. */
|
||||
// XXX: In selected contexts many other method invocations can be considered identity operations;
|
||||
// see the `IdentityConversion` check. Review whether those can/should be captured by this matcher
|
||||
// as well.
|
||||
public final class IsIdentityOperation implements Matcher<ExpressionTree> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> DELEGATE =
|
||||
anyOf(
|
||||
staticMethod()
|
||||
.onDescendantOfAny(
|
||||
DoubleUnaryOperator.class.getName(),
|
||||
Function.class.getName(),
|
||||
IntUnaryOperator.class.getName(),
|
||||
LongUnaryOperator.class.getName())
|
||||
.named("identity"),
|
||||
isIdentityLambdaExpression());
|
||||
|
||||
/** Instantiates a new {@link IsIdentityOperation} instance. */
|
||||
public IsIdentityOperation() {}
|
||||
|
||||
@Override
|
||||
public boolean matches(ExpressionTree tree, VisitorState state) {
|
||||
return DELEGATE.matches(tree, state);
|
||||
}
|
||||
|
||||
// XXX: Also support selected block expressions, including ones that perform a vacuous parameter
|
||||
// transformation such as those identified by the `IdentityConversion` check.
|
||||
private static Matcher<ExpressionTree> isIdentityLambdaExpression() {
|
||||
return toType(
|
||||
LambdaExpressionTree.class,
|
||||
(tree, state) ->
|
||||
tree.getBodyKind() == BodyKind.EXPRESSION
|
||||
&& tree.getParameters().size() == 1
|
||||
&& ASTHelpers.getSymbol(tree.getParameters().get(0))
|
||||
.equals(ASTHelpers.getSymbol(tree.getBody())));
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.tree.TypeCastTree;
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import com.sun.source.util.TreePathScanner;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
@@ -34,15 +34,11 @@ abstract class AbstractMatcherTestChecker extends BugChecker implements Compilat
|
||||
|
||||
@Override
|
||||
public Description matchCompilationUnit(CompilationUnitTree compilationUnit, VisitorState state) {
|
||||
new TreeScanner<@Nullable Void, TreePath>() {
|
||||
new TreePathScanner<@Nullable Void, @Nullable Void>() {
|
||||
@Override
|
||||
public @Nullable Void scan(@Nullable Tree tree, TreePath treePath) {
|
||||
if (tree == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TreePath path = new TreePath(treePath, tree);
|
||||
public @Nullable Void scan(@Nullable Tree tree, @Nullable Void unused) {
|
||||
if (tree instanceof ExpressionTree) {
|
||||
TreePath path = new TreePath(getCurrentPath(), tree);
|
||||
ExpressionTree expressionTree = (ExpressionTree) tree;
|
||||
if (!isMethodSelect(expressionTree, path)
|
||||
&& delegate.matches(expressionTree, state.withPath(path))) {
|
||||
@@ -50,11 +46,11 @@ abstract class AbstractMatcherTestChecker extends BugChecker implements Compilat
|
||||
}
|
||||
}
|
||||
|
||||
return super.scan(tree, path);
|
||||
return super.scan(tree, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitImport(ImportTree tree, TreePath path) {
|
||||
public @Nullable Void visitImport(ImportTree tree, @Nullable Void unused) {
|
||||
/*
|
||||
* We're not interested in matching import statements. While components of these
|
||||
* can be `ExpressionTree`s, they will never be matched by Refaster.
|
||||
@@ -63,24 +59,24 @@ abstract class AbstractMatcherTestChecker extends BugChecker implements Compilat
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitMethod(MethodTree tree, TreePath path) {
|
||||
public @Nullable Void visitMethod(MethodTree tree, @Nullable Void unused) {
|
||||
/*
|
||||
* We're not interested in matching e.g. parameter and return type declarations. While these
|
||||
* can be `ExpressionTree`s, they will never be matched by Refaster.
|
||||
*/
|
||||
return scan(tree.getBody(), new TreePath(path, tree));
|
||||
return scan(tree.getBody(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitTypeCast(TypeCastTree tree, TreePath path) {
|
||||
public @Nullable Void visitTypeCast(TypeCastTree tree, @Nullable Void unused) {
|
||||
/*
|
||||
* We're not interested in matching the parenthesized type subtree that is part of a type
|
||||
* cast expression. While such trees can be `ExpressionTree`s, they will never be matched by
|
||||
* Refaster.
|
||||
*/
|
||||
return scan(tree.getExpression(), new TreePath(path, tree));
|
||||
return scan(tree.getExpression(), null);
|
||||
}
|
||||
}.scan(compilationUnit, state.getPath());
|
||||
}.scan(compilationUnit, null);
|
||||
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,443 @@
|
||||
package tech.picnic.errorprone.refaster.matchers;
|
||||
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class IsEmptyTest {
|
||||
@Test
|
||||
void matches() {
|
||||
CompilationTestHelper.newInstance(MatcherTestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableMap;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import com.google.common.collect.ImmutableSetMultimap;",
|
||||
"import java.util.ArrayList;",
|
||||
"import java.util.Collections;",
|
||||
"import java.util.Comparator;",
|
||||
"import java.util.HashMap;",
|
||||
"import java.util.HashSet;",
|
||||
"import java.util.LinkedHashMap;",
|
||||
"import java.util.LinkedHashSet;",
|
||||
"import java.util.LinkedList;",
|
||||
"import java.util.List;",
|
||||
"import java.util.Map;",
|
||||
"import java.util.Random;",
|
||||
"import java.util.Set;",
|
||||
"import java.util.Stack;",
|
||||
"import java.util.TreeMap;",
|
||||
"import java.util.TreeSet;",
|
||||
"import java.util.Vector;",
|
||||
"import java.util.stream.Stream;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"import reactor.util.context.Context;",
|
||||
"",
|
||||
"class A {",
|
||||
" int[] negative1() {",
|
||||
" return new int[1];",
|
||||
" }",
|
||||
"",
|
||||
" int[][] negative2() {",
|
||||
" return new int[1][0];",
|
||||
" }",
|
||||
"",
|
||||
" int[] negative3() {",
|
||||
" return new int[] {0};",
|
||||
" }",
|
||||
"",
|
||||
" int[][] negative4() {",
|
||||
" return new int[][] {{0}};",
|
||||
" }",
|
||||
"",
|
||||
" Random negative5() {",
|
||||
" return new Random();",
|
||||
" }",
|
||||
"",
|
||||
" List<Integer> negative6() {",
|
||||
" return new ArrayList<>(ImmutableList.of(1));",
|
||||
" }",
|
||||
"",
|
||||
" Map<Integer, Integer> negative7() {",
|
||||
" return new HashMap<>(ImmutableMap.of(1, 2));",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> negative8() {",
|
||||
" return new HashSet<>(ImmutableList.of(1));",
|
||||
" }",
|
||||
"",
|
||||
" Map<Integer, Integer> negative9() {",
|
||||
" return new LinkedHashMap<>(ImmutableMap.of(1, 2));",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> negative10() {",
|
||||
" return new LinkedHashSet<>(ImmutableList.of(1));",
|
||||
" }",
|
||||
"",
|
||||
" List<Integer> negative11() {",
|
||||
" return new LinkedList<>(ImmutableList.of(1));",
|
||||
" }",
|
||||
"",
|
||||
" Map<Integer, Integer> negative12() {",
|
||||
" return new HashMap<>(ImmutableMap.of(1, 2));",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> negative13() {",
|
||||
" return new HashSet<>(ImmutableList.of(1));",
|
||||
" }",
|
||||
"",
|
||||
" List<Integer> negative14() {",
|
||||
" return new Vector<>(ImmutableList.of(1));",
|
||||
" }",
|
||||
"",
|
||||
" ImmutableList<Integer> negative15() {",
|
||||
" return ImmutableList.of(1);",
|
||||
" }",
|
||||
"",
|
||||
" ImmutableSet<Integer> negative16() {",
|
||||
" return ImmutableSet.of(1);",
|
||||
" }",
|
||||
"",
|
||||
" ImmutableMap<Integer, Integer> negative17() {",
|
||||
" return ImmutableMap.of(1, 2);",
|
||||
" }",
|
||||
"",
|
||||
" ImmutableSetMultimap<Integer, Integer> negative18() {",
|
||||
" return ImmutableSetMultimap.of(1, 2);",
|
||||
" }",
|
||||
"",
|
||||
" List<Integer> negative19() {",
|
||||
" return List.of(1);",
|
||||
" }",
|
||||
"",
|
||||
" Map<Integer, Integer> negative20() {",
|
||||
" return Map.of(1, 2);",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> negative21() {",
|
||||
" return Set.of(1);",
|
||||
" }",
|
||||
"",
|
||||
" Stream<Integer> negative22() {",
|
||||
" return Stream.of(1);",
|
||||
" }",
|
||||
"",
|
||||
" int[] positive1() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new int[0];",
|
||||
" }",
|
||||
"",
|
||||
" int[][] positive2() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new int[0][1];",
|
||||
" }",
|
||||
"",
|
||||
" int[] positive3() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new int[] {};",
|
||||
" }",
|
||||
"",
|
||||
" int[][] positive4() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new int[][] {};",
|
||||
" }",
|
||||
"",
|
||||
" List<Integer> positive5() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new ArrayList<>();",
|
||||
" }",
|
||||
"",
|
||||
" List<String> positive6() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new ArrayList<>(1);",
|
||||
" }",
|
||||
"",
|
||||
" List<String> positive7() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new ArrayList<>(",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableList.of());",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive8() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new HashMap<>();",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive9() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new HashMap<>(1);",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive10() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new HashMap<>(1, 1.0F);",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive11() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new HashMap<>(",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableMap.of());",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> positive12() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new HashSet<>();",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> positive13() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new HashSet<>(1);",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> positive14() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new HashSet<>(1, 1.0F);",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> positive15() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new HashSet<>(",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableList.of());",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive16() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new LinkedHashMap<>();",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive17() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new LinkedHashMap<>(1);",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive18() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new LinkedHashMap<>(1, 1.0F);",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive19() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new LinkedHashMap<>(1, 1.0F, false);",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive20() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new LinkedHashMap<>(",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableMap.of());",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> positive21() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new LinkedHashSet<>();",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> positive22() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new LinkedHashSet<>(1);",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> positive23() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new LinkedHashSet<>(1, 1.0F);",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> positive24() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new LinkedHashSet<>(",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableList.of());",
|
||||
" }",
|
||||
"",
|
||||
" List<Integer> positive25() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new LinkedList<>();",
|
||||
" }",
|
||||
"",
|
||||
" List<String> positive26() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new LinkedList<>(",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableList.of());",
|
||||
" }",
|
||||
"",
|
||||
" List<Integer> positive27() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new Stack<>();",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive28() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new TreeMap<>();",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive29() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new TreeMap<>(Comparator.naturalOrder());",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive30() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new TreeMap<>(",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableMap.of());",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> positive31() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new TreeSet<>();",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> positive32() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new TreeSet<>(Comparator.naturalOrder());",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> positive33() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new TreeSet<>(",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableList.of());",
|
||||
" }",
|
||||
"",
|
||||
" List<Integer> positive34() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new Vector<>();",
|
||||
" }",
|
||||
"",
|
||||
" List<Integer> positive35() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new Vector<>(1);",
|
||||
" }",
|
||||
"",
|
||||
" List<Integer> positive36() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new Vector<>(1, 2);",
|
||||
" }",
|
||||
"",
|
||||
" List<Integer> positive37() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return new Vector<>(",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableList.of());",
|
||||
" }",
|
||||
"",
|
||||
" List<Integer> positive38() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Collections.EMPTY_LIST;",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive39() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Collections.EMPTY_MAP;",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> positive40() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Collections.EMPTY_SET;",
|
||||
" }",
|
||||
"",
|
||||
" List<Integer> positive41() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Collections.emptyList();",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive42() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Collections.emptyMap();",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> positive43() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Collections.emptySet();",
|
||||
" }",
|
||||
"",
|
||||
" ImmutableList<Integer> positive44() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return ImmutableList.of();",
|
||||
" }",
|
||||
"",
|
||||
" ImmutableSet<Integer> positive45() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return ImmutableSet.of();",
|
||||
" }",
|
||||
"",
|
||||
" ImmutableMap<String, Integer> positive46() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return ImmutableMap.of();",
|
||||
" }",
|
||||
"",
|
||||
" ImmutableSetMultimap<String, Integer> positive47() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return ImmutableSetMultimap.of();",
|
||||
" }",
|
||||
"",
|
||||
" List<Integer> positive48() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return List.of();",
|
||||
" }",
|
||||
"",
|
||||
" Map<String, String> positive49() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Map.of();",
|
||||
" }",
|
||||
"",
|
||||
" Set<Integer> positive50() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Set.of();",
|
||||
" }",
|
||||
"",
|
||||
" Stream<Integer> positive51() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Stream.of();",
|
||||
" }",
|
||||
"",
|
||||
" Stream<Integer> positive52() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Stream.empty();",
|
||||
" }",
|
||||
"",
|
||||
" Flux<Integer> positive53() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Flux.empty();",
|
||||
" }",
|
||||
"",
|
||||
" Mono<Integer> positive54() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Mono.empty();",
|
||||
" }",
|
||||
"",
|
||||
" Context positive55() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Context.empty();",
|
||||
" }",
|
||||
"",
|
||||
" Flux<Integer> positive56() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Flux.just();",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
/** A {@link BugChecker} that simply delegates to {@link IsEmpty}. */
|
||||
@BugPattern(summary = "Flags expressions matched by `IsEmpty`", severity = ERROR)
|
||||
public static final class MatcherTestChecker extends AbstractMatcherTestChecker {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// XXX: This is a false positive reported by Checkstyle. See
|
||||
// https://github.com/checkstyle/checkstyle/issues/10161#issuecomment-1242732120.
|
||||
@SuppressWarnings("RedundantModifier")
|
||||
public MatcherTestChecker() {
|
||||
super(new IsEmpty());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package tech.picnic.errorprone.refaster.matchers;
|
||||
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class IsIdentityOperationTest {
|
||||
@Test
|
||||
void matches() {
|
||||
CompilationTestHelper.newInstance(MatcherTestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.function.BinaryOperator;",
|
||||
"import java.util.function.DoubleUnaryOperator;",
|
||||
"import java.util.function.Function;",
|
||||
"import java.util.function.IntUnaryOperator;",
|
||||
"import java.util.function.LongUnaryOperator;",
|
||||
"import java.util.function.UnaryOperator;",
|
||||
"",
|
||||
"class A {",
|
||||
" BinaryOperator<String> negative1() {",
|
||||
" return (a, b) -> a;",
|
||||
" }",
|
||||
"",
|
||||
" UnaryOperator<String> negative2() {",
|
||||
" return a -> a + a;",
|
||||
" }",
|
||||
"",
|
||||
" DoubleUnaryOperator positive1() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return DoubleUnaryOperator.identity();",
|
||||
" }",
|
||||
"",
|
||||
" Function<Integer, Integer> positive2() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return Function.identity();",
|
||||
" }",
|
||||
"",
|
||||
" UnaryOperator<String> positive3() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return UnaryOperator.identity();",
|
||||
" }",
|
||||
"",
|
||||
" IntUnaryOperator positive4() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return IntUnaryOperator.identity();",
|
||||
" }",
|
||||
"",
|
||||
" LongUnaryOperator positive5() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return LongUnaryOperator.identity();",
|
||||
" }",
|
||||
"",
|
||||
" UnaryOperator positive6() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return a -> a;",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
/** A {@link BugChecker} that simply delegates to {@link IsIdentityOperation}. */
|
||||
@BugPattern(summary = "Flags expressions matched by `IsIdentityOperation`", severity = ERROR)
|
||||
public static final class MatcherTestChecker extends AbstractMatcherTestChecker {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// XXX: This is a false positive reported by Checkstyle. See
|
||||
// https://github.com/checkstyle/checkstyle/issues/10161#issuecomment-1242732120.
|
||||
@SuppressWarnings("RedundantModifier")
|
||||
public MatcherTestChecker() {
|
||||
super(new IsIdentityOperation());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,10 @@ import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.ImmutableListMultimap.toImmutableListMultimap;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
|
||||
import static com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode.TEXT_MATCH;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
import static java.util.Comparator.naturalOrder;
|
||||
import static tech.picnic.errorprone.refaster.runner.Refaster.INCLUDED_RULES_PATTERN_FLAG;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableRangeMap;
|
||||
@@ -19,6 +17,7 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Range;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.ErrorProneFlags;
|
||||
import com.google.errorprone.SubContext;
|
||||
@@ -123,10 +122,12 @@ public final class RefasterRuleCollection extends BugChecker implements Compilat
|
||||
String className = clazz.getSimpleName();
|
||||
|
||||
BugCheckerRefactoringTestHelper.newInstance(RefasterRuleCollection.class, clazz)
|
||||
.setArgs(ImmutableList.of("-XepOpt:" + RULE_COLLECTION_FLAG + '=' + className))
|
||||
.setArgs(
|
||||
"--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
|
||||
"-XepOpt:" + RULE_COLLECTION_FLAG + '=' + className)
|
||||
.addInput(className + "TestInput.java")
|
||||
.addOutput(className + "TestOutput.java")
|
||||
.doTest(TEXT_MATCH);
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -51,11 +51,11 @@ bundle install
|
||||
# Deployment
|
||||
|
||||
The website is regenerated and deployed using the
|
||||
[`deploy-website.yaml`][error-prone-support-website-deploy-workflow] GitHub
|
||||
[`deploy-website.yml`][error-prone-support-website-deploy-workflow] GitHub
|
||||
Actions workflow any time a change is merged to `master`.
|
||||
|
||||
[error-prone-support-website]: https://error-prone.picnic.tech
|
||||
[error-prone-support-website-deploy-workflow]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/deploy-website.yaml
|
||||
[error-prone-support-website-deploy-workflow]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/deploy-website.yml
|
||||
[jekyll]: https://jekyllrb.com
|
||||
[jekyll-docs]: https://jekyllrb.com/docs
|
||||
[jekyll-docs-installation]: https://jekyllrb.com/docs/installation
|
||||
|
||||
Reference in New Issue
Block a user