mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
Compare commits
110 Commits
rossendrij
...
v0.14.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4800522a09 | ||
|
|
9a77a3f35f | ||
|
|
ef75b80e7b | ||
|
|
7c618f7e2d | ||
|
|
c03ead9e5d | ||
|
|
8fd87a5b6b | ||
|
|
82025a729f | ||
|
|
7d912d1b04 | ||
|
|
a726514e98 | ||
|
|
aa7de5777c | ||
|
|
6e6efb3c13 | ||
|
|
03fd050eae | ||
|
|
d1467e0424 | ||
|
|
a2e32ed147 | ||
|
|
258708e6a8 | ||
|
|
67106a9725 | ||
|
|
f979576ab5 | ||
|
|
aa3fd03569 | ||
|
|
5602251667 | ||
|
|
05cb6387b9 | ||
|
|
4e242a5b11 | ||
|
|
87297c9a1d | ||
|
|
15ff85c4ea | ||
|
|
2c8469fa93 | ||
|
|
f4e0fd2cc3 | ||
|
|
34fd692064 | ||
|
|
26bc7e6e8e | ||
|
|
56cb86a7e1 | ||
|
|
19cd802ec5 | ||
|
|
1fabb26ed2 | ||
|
|
c1ced1e962 | ||
|
|
030ed25be8 | ||
|
|
ee0c04a44e | ||
|
|
87f79dae60 | ||
|
|
1f4a68416f | ||
|
|
c98fe9273d | ||
|
|
8b5d1803e4 | ||
|
|
507a19d10e | ||
|
|
43fcbb770d | ||
|
|
7779631320 | ||
|
|
48e2f57cb6 | ||
|
|
352829c61f | ||
|
|
37d95605b0 | ||
|
|
6131599d9d | ||
|
|
9c158f11d4 | ||
|
|
be818486bd | ||
|
|
1e80097bee | ||
|
|
431c3e67ac | ||
|
|
e612631cb8 | ||
|
|
a6bce960cb | ||
|
|
e19c2de99d | ||
|
|
7b193f2fd5 | ||
|
|
852442b55b | ||
|
|
d758fab524 | ||
|
|
88ed3ea9a9 | ||
|
|
7fb0e551d4 | ||
|
|
4af7b21bf5 | ||
|
|
fc5f3bd4cc | ||
|
|
35a5944b81 | ||
|
|
17cc8e0c31 | ||
|
|
b5ba4fa208 | ||
|
|
26b941bbc5 | ||
|
|
eb3b540537 | ||
|
|
6a11b59517 | ||
|
|
62abd51f4d | ||
|
|
67a128a9b6 | ||
|
|
526227e8ed | ||
|
|
c2e837819e | ||
|
|
fd70be081e | ||
|
|
2c47244571 | ||
|
|
8375f1650f | ||
|
|
c4daa04ce1 | ||
|
|
08f0e52104 | ||
|
|
10070bd4c8 | ||
|
|
3c38fd3495 | ||
|
|
d54ec83844 | ||
|
|
e03d0de366 | ||
|
|
b40c5d61b9 | ||
|
|
6d27e46baf | ||
|
|
8f48497322 | ||
|
|
38554be3d1 | ||
|
|
28cdb91913 | ||
|
|
bd6693d23e | ||
|
|
a3ec76845a | ||
|
|
e3b310761d | ||
|
|
774052f13a | ||
|
|
bad7684639 | ||
|
|
dd72b5a08a | ||
|
|
3eb30c5f93 | ||
|
|
2cc0539f8f | ||
|
|
9210c30a0a | ||
|
|
ba362ed460 | ||
|
|
ab33adfab8 | ||
|
|
006665ee6d | ||
|
|
08c49b9a58 | ||
|
|
777aa970f1 | ||
|
|
a040310870 | ||
|
|
d6ab366f31 | ||
|
|
d9fefa6824 | ||
|
|
c8b3a6df82 | ||
|
|
782a790def | ||
|
|
706b5f401f | ||
|
|
9f500fd5bb | ||
|
|
f541cd2e52 | ||
|
|
fc862aad94 | ||
|
|
42810bc00c | ||
|
|
f17d736356 | ||
|
|
705acc9164 | ||
|
|
bb969a8b80 | ||
|
|
c5a700c555 |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -42,7 +42,7 @@ Please replace this sentence with log output, if applicable.
|
||||
<!-- Please complete the following information: -->
|
||||
|
||||
- Operating system (e.g. MacOS Monterey).
|
||||
- Java version (i.e. `java --version`, e.g. `17.0.7`).
|
||||
- Java version (i.e. `java --version`, e.g. `17.0.8`).
|
||||
- Error Prone version (e.g. `2.18.0`).
|
||||
- Error Prone Support version (e.g. `0.9.0`).
|
||||
|
||||
|
||||
10
.github/workflows/build.yaml
vendored
10
.github/workflows/build.yaml
vendored
@@ -10,16 +10,16 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-22.04 ]
|
||||
jdk: [ 11.0.19, 17.0.7, 20.0.1 ]
|
||||
jdk: [ 11.0.20, 17.0.8, 20.0.2 ]
|
||||
distribution: [ temurin ]
|
||||
experimental: [ false ]
|
||||
include:
|
||||
- os: macos-12
|
||||
jdk: 17.0.7
|
||||
jdk: 17.0.8
|
||||
distribution: temurin
|
||||
experimental: false
|
||||
- os: windows-2022
|
||||
jdk: 17.0.7
|
||||
jdk: 17.0.8
|
||||
distribution: temurin
|
||||
experimental: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -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@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.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@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
|
||||
with:
|
||||
java-version: 17.0.7
|
||||
java-version: 17.0.8
|
||||
distribution: temurin
|
||||
cache: maven
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2.2.11
|
||||
uses: github/codeql-action/init@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Perform minimal build
|
||||
if: matrix.language == 'java'
|
||||
run: mvn -T1C clean install -DskipTests -Dverification.skip
|
||||
- name: Perform CodeQL analysis
|
||||
uses: github/codeql-action/analyze@v2.2.11
|
||||
uses: github/codeql-action/analyze@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9
|
||||
with:
|
||||
category: /language:${{ matrix.language }}
|
||||
|
||||
8
.github/workflows/deploy-website.yaml
vendored
8
.github/workflows/deploy-website.yaml
vendored
@@ -12,10 +12,10 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ruby/setup-ruby@v1.126.0
|
||||
- uses: ruby/setup-ruby@250fcd6a742febb1123a77a841497ccaa8b9e939 # v1.152.0
|
||||
with:
|
||||
working-directory: ./website
|
||||
bundler-cache: true
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
# "Refaster rules" terminology on our website and in the code.
|
||||
run: bundle exec htmlproofer --disable_external true --check-external-hash false ./_site
|
||||
- name: Upload website as artifact
|
||||
uses: actions/upload-pages-artifact@66b63f4a7de003f4f00cc8e9af4b83b8f2abdb96 # v1.0.9
|
||||
uses: actions/upload-pages-artifact@a753861a5debcf57bf8b404356158c8e1e33150c # v2.0.0
|
||||
with:
|
||||
path: ./website/_site
|
||||
deploy:
|
||||
@@ -48,4 +48,4 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@ee48c7b82e077d7b8ef30b50a719e6a792a50c9a # v2.0.2
|
||||
uses: actions/deploy-pages@9dbe3824824f8a1377b8e298bafde1a50ede43e5 # v2.0.4
|
||||
|
||||
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@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run OpenSSF Scorecard analysis
|
||||
uses: ossf/scorecard-action@v2.1.3
|
||||
uses: ossf/scorecard-action@08b4669551908b1024bb425080c797723083c031 # v2.2.0
|
||||
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@v2.2.11
|
||||
uses: github/codeql-action/upload-sarif@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
8
.github/workflows/pitest-analyze-pr.yml
vendored
8
.github/workflows/pitest-analyze-pr.yml
vendored
@@ -12,14 +12,14 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
with:
|
||||
fetch-depth: 2
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
|
||||
with:
|
||||
java-version: 17.0.7
|
||||
java-version: 17.0.8
|
||||
distribution: temurin
|
||||
cache: maven
|
||||
- name: Run Pitest
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: Aggregate Pitest reports
|
||||
run: mvn pitest-git:aggregate -DkilledEmoji=":tada:" -DmutantEmoji=":zombie:" -DtrailingText="Mutation testing report by [Pitest](https://pitest.org/). Review any surviving mutants by inspecting the line comments under [_Files changed_](${{ github.event.number }}/files)."
|
||||
- name: Upload Pitest reports as artifact
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
||||
with:
|
||||
name: pitest-reports
|
||||
path: ./target/pit-reports-ci
|
||||
|
||||
8
.github/workflows/pitest-update-pr.yml
vendored
8
.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@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
|
||||
with:
|
||||
java-version: 17.0.7
|
||||
java-version: 17.0.8
|
||||
distribution: temurin
|
||||
cache: maven
|
||||
- name: Download Pitest analysis artifact
|
||||
uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
|
||||
uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e # v2.28.0
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
name: pitest-reports
|
||||
|
||||
6
.github/workflows/sonarcloud.yml
vendored
6
.github/workflows/sonarcloud.yml
vendored
@@ -16,14 +16,14 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
|
||||
with:
|
||||
java-version: 17.0.7
|
||||
java-version: 17.0.8
|
||||
distribution: temurin
|
||||
cache: maven
|
||||
- name: Create missing `test` directory
|
||||
|
||||
@@ -12,10 +12,11 @@
|
||||
"separateMinorPatch": true
|
||||
},
|
||||
{
|
||||
"matchPackagePatterns": [
|
||||
"^ruby\\/setup-ruby$"
|
||||
"matchDepNames": [
|
||||
"github/codeql-action",
|
||||
"ruby/setup-ruby"
|
||||
],
|
||||
"schedule": "* * 1 * *"
|
||||
"schedule": "every 4 weeks on Monday"
|
||||
}
|
||||
],
|
||||
"reviewers": [
|
||||
|
||||
@@ -80,6 +80,6 @@ Some pointers:
|
||||
[error-prone-support-developing]: https://github.com/PicnicSupermarket/error-prone-support/tree/master#-developing-error-prone-support
|
||||
[error-prone-support-full-build]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-full-build.sh
|
||||
[error-prone-support-issues]: https://github.com/PicnicSupermarket/error-prone-support/issues
|
||||
[error-prone-support-mutation-tests]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-mutation-tests.sh
|
||||
[error-prone-support-mutation-tests]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-branch-mutation-tests.sh
|
||||
[error-prone-support-patch]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/apply-error-prone-suggestions.sh
|
||||
[error-prone-support-pulls]: https://github.com/PicnicSupermarket/error-prone-support/pulls
|
||||
|
||||
14
README.md
14
README.md
@@ -223,10 +223,13 @@ Other highly relevant commands:
|
||||
Before running this command, make sure to have installed the project (`mvn
|
||||
clean install`) and make sure that the current working directory does not
|
||||
contain unstaged or uncommited changes.
|
||||
- [`./run-mutation-tests.sh`][script-run-mutation-tests] runs mutation tests
|
||||
using [Pitest][pitest]. The results can be reviewed by opening the respective
|
||||
`target/pit-reports/index.html` files. For more information check the [PIT
|
||||
Maven plugin][pitest-maven].
|
||||
- [`./run-branch-mutation-tests.sh`][script-run-branch-mutation-tests] uses
|
||||
[Pitest][pitest] to run mutation tests against code that is modified relative
|
||||
to the upstream default branch. The results can be reviewed by opening the
|
||||
respective `target/pit-reports/index.html` files. One can use
|
||||
[`./run-mutation-tests.sh`][script-run-mutation-tests] to run mutation tests
|
||||
against _all_ code in the current working directory. For more information
|
||||
check the [PIT Maven plugin][pitest-maven].
|
||||
|
||||
When running the project's tests in IntelliJ IDEA, you might see the following
|
||||
error:
|
||||
@@ -283,7 +286,7 @@ channel; please see our [security policy][security] for details.
|
||||
[openssf-best-practices-badge]: https://bestpractices.coreinfrastructure.org/projects/7199/badge
|
||||
[openssf-best-practices-checklist]: https://bestpractices.coreinfrastructure.org/projects/7199
|
||||
[openssf-scorecard-badge]: https://img.shields.io/ossf-scorecard/github.com/PicnicSupermarket/error-prone-support?label=openssf%20scorecard
|
||||
[openssf-scorecard-report]: https://api.securityscorecards.dev/projects/github.com/PicnicSupermarket/error-prone-support
|
||||
[openssf-scorecard-report]: https://securityscorecards.dev/viewer/?uri=github.com/PicnicSupermarket/error-prone-support
|
||||
[picnic-blog-ep-post]: https://blog.picnic.nl/picnic-loves-error-prone-producing-high-quality-and-consistent-java-code-b8a566be6886
|
||||
[picnic-blog]: https://blog.picnic.nl
|
||||
[pitest-badge]: https://img.shields.io/badge/-Mutation%20tested%20with%20PIT-blue.svg
|
||||
@@ -296,6 +299,7 @@ channel; please see our [security policy][security] for details.
|
||||
[reproducible-builds-badge]: https://img.shields.io/badge/Reproducible_Builds-ok-success?labelColor=1e5b96
|
||||
[reproducible-builds-report]: https://github.com/jvm-repo-rebuild/reproducible-central/blob/master/content/tech/picnic/error-prone-support/error-prone-support/README.md
|
||||
[script-apply-error-prone-suggestions]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/apply-error-prone-suggestions.sh
|
||||
[script-run-branch-mutation-tests]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-branch-mutation-tests.sh
|
||||
[script-run-full-build]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-full-build.sh
|
||||
[script-run-mutation-tests]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-mutation-tests.sh
|
||||
[security]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/SECURITY.md
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.12.1-SNAPSHOT</version>
|
||||
<version>0.14.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>documentation-support</artifactId>
|
||||
|
||||
@@ -125,9 +125,6 @@ The following is a list of checks we'd like to see implemented:
|
||||
statement. Idem for other exception types.
|
||||
- A Guava-specific check that replaces simple anonymous `CacheLoader` subclass
|
||||
declarations with `CacheLoader.from(someLambda)`.
|
||||
- A Spring-specific check that enforces that methods with the `@Scheduled`
|
||||
annotation are also annotated with New Relic's `@Trace` annotation. Such
|
||||
methods should ideally not also represent Spring MVC endpoints.
|
||||
- A Spring-specific check that enforces that `@RequestMapping` annotations,
|
||||
when applied to a method, explicitly specify one or more target HTTP methods.
|
||||
- A Spring-specific check that looks for classes in which all `@RequestMapping`
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.12.1-SNAPSHOT</version>
|
||||
<version>0.14.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-contrib</artifactId>
|
||||
@@ -81,11 +81,6 @@
|
||||
<artifactId>guava</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.newrelic.agent.java</groupId>
|
||||
<artifactId>newrelic-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
@@ -176,6 +171,11 @@
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongodb-driver-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.reactivestreams</groupId>
|
||||
<artifactId>reactive-streams</artifactId>
|
||||
|
||||
@@ -91,8 +91,8 @@ public final class CanonicalAnnotationSyntax extends BugChecker implements Annot
|
||||
ExpressionTree arg = args.get(0);
|
||||
if (state.getSourceForNode(arg) == null) {
|
||||
/*
|
||||
* The annotation argument isn't doesn't have a source representation, e.g. because `value`
|
||||
* isn't assigned to explicitly.
|
||||
* The annotation argument doesn't have a source representation, e.g. because `value` isn't
|
||||
* assigned explicitly.
|
||||
*/
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
public final class FormatStringConcatenation extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* AssertJ exposes varargs {@code fail} methods with a {@link Throwable}-accepting overload, the
|
||||
* latter of which should not be flagged.
|
||||
@@ -68,6 +69,7 @@ public final class FormatStringConcatenation extends BugChecker
|
||||
.anyClass()
|
||||
.withAnyName()
|
||||
.withParameters(String.class.getName(), Throwable.class.getName());
|
||||
|
||||
// XXX: Drop some of these methods if we use Refaster to replace some with others.
|
||||
private static final Matcher<ExpressionTree> ASSERTJ_FORMAT_METHOD =
|
||||
anyOf(
|
||||
|
||||
@@ -76,6 +76,7 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
|
||||
private static final String FLAG_PREFIX = "LexicographicalAnnotationAttributeListing:";
|
||||
private static final String INCLUDED_ANNOTATIONS_FLAG = FLAG_PREFIX + "Includes";
|
||||
private static final String EXCLUDED_ANNOTATIONS_FLAG = FLAG_PREFIX + "Excludes";
|
||||
|
||||
/**
|
||||
* The splitter applied to string-typed annotation arguments prior to lexicographical sorting. By
|
||||
* splitting on {@code =}, strings that represent e.g. inline Spring property declarations are
|
||||
@@ -219,7 +220,10 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
|
||||
private static AnnotationAttributeMatcher createAnnotationAttributeMatcher(
|
||||
ErrorProneFlags flags) {
|
||||
return AnnotationAttributeMatcher.create(
|
||||
flags.getList(INCLUDED_ANNOTATIONS_FLAG), excludedAnnotations(flags));
|
||||
flags.get(INCLUDED_ANNOTATIONS_FLAG).isPresent()
|
||||
? Optional.of(flags.getListOrEmpty(INCLUDED_ANNOTATIONS_FLAG))
|
||||
: Optional.empty(),
|
||||
excludedAnnotations(flags));
|
||||
}
|
||||
|
||||
private static ImmutableList<String> excludedAnnotations(ErrorProneFlags flags) {
|
||||
|
||||
@@ -46,6 +46,7 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
|
||||
public final class LexicographicalAnnotationListing extends BugChecker
|
||||
implements MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* A comparator that minimally reorders {@link AnnotationType}s, such that declaration annotations
|
||||
* are placed before type annotations.
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
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.PERFORMANCE;
|
||||
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags usages of MongoDB {@code $text} filter usages.
|
||||
*
|
||||
* @see <a href="https://www.mongodb.com/docs/manual/text-search/">MongoDB Text Search</a>
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary =
|
||||
"Avoid MongoDB's `$text` filter operator, as it can trigger heavy queries and even cause the server to run out of memory",
|
||||
link = BUG_PATTERNS_BASE_URL + "MongoDBTextFilterUsage",
|
||||
linkType = CUSTOM,
|
||||
severity = SUGGESTION,
|
||||
tags = PERFORMANCE)
|
||||
public final class MongoDBTextFilterUsage extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> MONGO_FILTERS_TEXT_METHOD =
|
||||
staticMethod().onClass("com.mongodb.client.model.Filters").named("text");
|
||||
|
||||
/** Instantiates a new {@link MongoDBTextFilterUsage} instance. */
|
||||
public MongoDBTextFilterUsage() {}
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
return MONGO_FILTERS_TEXT_METHOD.matches(tree, state)
|
||||
? describeMatch(tree)
|
||||
: Description.NO_MATCH;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.FRAGILE_CODE;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreMatchers.isSubTypeOf;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.generic;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.raw;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.subOf;
|
||||
@@ -14,14 +15,19 @@ import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.suppliers.Supplier;
|
||||
import com.google.errorprone.suppliers.Suppliers;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import java.util.Optional;
|
||||
|
||||
/** A {@link BugChecker} that flags nesting of {@link Optional Optionals}. */
|
||||
// XXX: Extend this checker to also flag method return types and variable/field types.
|
||||
// XXX: Consider generalizing this checker and `NestedPublishers` to a single `NestedMonad` check,
|
||||
// which e.g. also flags nested `Stream`s. Alternatively, combine these and other checkers into an
|
||||
// even more generic `ConfusingType` checker.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary =
|
||||
@@ -33,19 +39,16 @@ import java.util.Optional;
|
||||
public final class NestedOptionals extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Supplier<Type> OPTIONAL = Suppliers.typeFromClass(Optional.class);
|
||||
private static final Supplier<Type> OPTIONAL_OF_OPTIONAL =
|
||||
VisitorState.memoize(generic(OPTIONAL, subOf(raw(OPTIONAL))));
|
||||
private static final Matcher<Tree> IS_OPTIONAL_OF_OPTIONAL =
|
||||
isSubTypeOf(VisitorState.memoize(generic(OPTIONAL, subOf(raw(OPTIONAL)))));
|
||||
|
||||
/** Instantiates a new {@link NestedOptionals} instance. */
|
||||
public NestedOptionals() {}
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
Type type = OPTIONAL_OF_OPTIONAL.get(state);
|
||||
if (type == null || !state.getTypes().isSubtype(ASTHelpers.getType(tree), type)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
return describeMatch(tree);
|
||||
return IS_OPTIONAL_OF_OPTIONAL.matches(tree, state)
|
||||
? describeMatch(tree)
|
||||
: Description.NO_MATCH;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.FRAGILE_CODE;
|
||||
import static com.google.errorprone.matchers.Matchers.typePredicateMatcher;
|
||||
import static com.google.errorprone.predicates.TypePredicates.allOf;
|
||||
import static com.google.errorprone.predicates.TypePredicates.not;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreTypePredicates.hasTypeParameter;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreTypePredicates.isSubTypeOf;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.generic;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.raw;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.subOf;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.type;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.suppliers.Supplier;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags {@code Publisher<? extends Publisher>} instances, unless the
|
||||
* nested {@link org.reactivestreams.Publisher} is a {@link reactor.core.publisher.GroupedFlux}.
|
||||
*/
|
||||
// XXX: See the `NestedOptionals` check for some ideas on how to generalize this kind of checker.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary =
|
||||
"Avoid `Publisher`s that emit other `Publishers`s; "
|
||||
+ "the resultant code is hard to reason about",
|
||||
link = BUG_PATTERNS_BASE_URL + "NestedPublishers",
|
||||
linkType = CUSTOM,
|
||||
severity = WARNING,
|
||||
tags = FRAGILE_CODE)
|
||||
public final class NestedPublishers extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Supplier<Type> PUBLISHER = type("org.reactivestreams.Publisher");
|
||||
private static final Matcher<ExpressionTree> IS_NON_GROUPED_PUBLISHER_OF_PUBLISHERS =
|
||||
typePredicateMatcher(
|
||||
allOf(
|
||||
isSubTypeOf(generic(PUBLISHER, subOf(raw(PUBLISHER)))),
|
||||
not(
|
||||
hasTypeParameter(
|
||||
0, isSubTypeOf(raw(type("reactor.core.publisher.GroupedFlux")))))));
|
||||
|
||||
/** Instantiates a new {@link NestedPublishers} instance. */
|
||||
public NestedPublishers() {}
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
return IS_NON_GROUPED_PUBLISHER_OF_PUBLISHERS.matches(tree, state)
|
||||
? describeMatch(tree)
|
||||
: Description.NO_MATCH;
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.LIKELY_ERROR;
|
||||
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.hasAnnotation;
|
||||
import static com.google.errorprone.matchers.Matchers.isType;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.common.AnnotationMirrors;
|
||||
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;
|
||||
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.util.ASTHelpers;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import tech.picnic.errorprone.bugpatterns.util.ThirdPartyLibrary;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags methods with Spring's {@code @Scheduled} annotation that lack New
|
||||
* Relic Agent's {@code @Trace(dispatcher = true)}.
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Scheduled operation must start a new New Relic transaction",
|
||||
link = BUG_PATTERNS_BASE_URL + "ScheduledTransactionTrace",
|
||||
linkType = CUSTOM,
|
||||
severity = ERROR,
|
||||
tags = LIKELY_ERROR)
|
||||
public final class ScheduledTransactionTrace extends BugChecker implements MethodTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String TRACE_ANNOTATION_FQCN = "com.newrelic.api.agent.Trace";
|
||||
private static final Matcher<Tree> IS_SCHEDULED =
|
||||
hasAnnotation("org.springframework.scheduling.annotation.Scheduled");
|
||||
private static final MultiMatcher<Tree, AnnotationTree> TRACE_ANNOTATION =
|
||||
annotations(AT_LEAST_ONE, isType(TRACE_ANNOTATION_FQCN));
|
||||
|
||||
/** Instantiates a new {@link ScheduledTransactionTrace} instance. */
|
||||
public ScheduledTransactionTrace() {}
|
||||
|
||||
@Override
|
||||
public Description matchMethod(MethodTree tree, VisitorState state) {
|
||||
if (!ThirdPartyLibrary.NEW_RELIC_AGENT_API.isIntroductionAllowed(state)
|
||||
|| !IS_SCHEDULED.matches(tree, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
ImmutableList<AnnotationTree> traceAnnotations =
|
||||
TRACE_ANNOTATION.multiMatchResult(tree, state).matchingNodes();
|
||||
if (traceAnnotations.isEmpty()) {
|
||||
/* This method completely lacks the `@Trace` annotation; add it. */
|
||||
return describeMatch(
|
||||
tree,
|
||||
SuggestedFix.builder()
|
||||
.addImport(TRACE_ANNOTATION_FQCN)
|
||||
.prefixWith(tree, "@Trace(dispatcher = true)")
|
||||
.build());
|
||||
}
|
||||
|
||||
AnnotationTree traceAnnotation = Iterables.getOnlyElement(traceAnnotations);
|
||||
if (isCorrectAnnotation(traceAnnotation)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
/*
|
||||
* The `@Trace` annotation is present but does not specify `dispatcher = true`. Add or update
|
||||
* the `dispatcher` annotation element.
|
||||
*/
|
||||
return describeMatch(
|
||||
traceAnnotation,
|
||||
SuggestedFixes.updateAnnotationArgumentValues(
|
||||
traceAnnotation, state, "dispatcher", ImmutableList.of("true"))
|
||||
.build());
|
||||
}
|
||||
|
||||
private static boolean isCorrectAnnotation(AnnotationTree traceAnnotation) {
|
||||
return Boolean.TRUE.equals(
|
||||
AnnotationMirrors.getAnnotationValue(
|
||||
ASTHelpers.getAnnotationMirror(traceAnnotation), "dispatcher")
|
||||
.getValue());
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,7 @@ public final class Flags {
|
||||
* provided, or if the flag's value is the empty string.
|
||||
*/
|
||||
public static ImmutableList<String> getList(ErrorProneFlags errorProneFlags, String name) {
|
||||
return errorProneFlags
|
||||
.getList(name)
|
||||
.map(ImmutableList::copyOf)
|
||||
.filter(flags -> !flags.equals(ImmutableList.of("")))
|
||||
.orElseGet(ImmutableList::of);
|
||||
ImmutableList<String> list = errorProneFlags.getListOrEmpty(name);
|
||||
return list.equals(ImmutableList.of("")) ? ImmutableList.of() : list;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ public final class JavaKeywords {
|
||||
*/
|
||||
private static final ImmutableSet<String> BOOLEAN_AND_NULL_LITERALS =
|
||||
ImmutableSet.of("true", "false", "null");
|
||||
|
||||
/**
|
||||
* List of all reserved keywords in the Java language.
|
||||
*
|
||||
@@ -76,6 +77,7 @@ public final class JavaKeywords {
|
||||
"void",
|
||||
"volatile",
|
||||
"while");
|
||||
|
||||
/**
|
||||
* List of all contextual keywords in the Java language.
|
||||
*
|
||||
@@ -100,6 +102,7 @@ public final class JavaKeywords {
|
||||
"var",
|
||||
"with",
|
||||
"yield");
|
||||
|
||||
/** List of all keywords in the Java language. */
|
||||
private static final ImmutableSet<String> ALL_KEYWORDS =
|
||||
Sets.union(RESERVED_KEYWORDS, CONTEXTUAL_KEYWORDS).immutableCopy();
|
||||
|
||||
@@ -18,6 +18,7 @@ import java.util.regex.Pattern;
|
||||
public final class MethodMatcherFactory {
|
||||
private static final Splitter ARGUMENT_TYPE_SPLITTER =
|
||||
Splitter.on(',').trimResults().omitEmptyStrings();
|
||||
|
||||
// XXX: Check whether we can use a parser for "standard" Java signatures here. Maybe
|
||||
// `sun.reflect.generics.parser.SignatureParser`?
|
||||
@SuppressWarnings("java:S5998" /* In practice there will be only modest recursion. */)
|
||||
|
||||
@@ -34,6 +34,7 @@ public final class MoreJUnitMatchers {
|
||||
anyOf(
|
||||
isType("org.junit.jupiter.api.Test"),
|
||||
hasMetaAnnotation("org.junit.jupiter.api.TestTemplate")));
|
||||
|
||||
/** Matches JUnit Jupiter setup and teardown methods. */
|
||||
public static final MultiMatcher<MethodTree, AnnotationTree> SETUP_OR_TEARDOWN_METHOD =
|
||||
annotations(
|
||||
@@ -43,6 +44,7 @@ public final class MoreJUnitMatchers {
|
||||
isType("org.junit.jupiter.api.AfterEach"),
|
||||
isType("org.junit.jupiter.api.BeforeAll"),
|
||||
isType("org.junit.jupiter.api.BeforeEach")));
|
||||
|
||||
/**
|
||||
* Matches methods that have a {@link org.junit.jupiter.params.provider.MethodSource} annotation.
|
||||
*/
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import static com.google.errorprone.matchers.Matchers.typePredicateMatcher;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreTypePredicates.hasAnnotation;
|
||||
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.matchers.Matchers;
|
||||
import com.google.errorprone.predicates.TypePredicate;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.google.errorprone.suppliers.Supplier;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
|
||||
/**
|
||||
* A collection of general-purpose {@link Matcher}s.
|
||||
@@ -25,15 +28,21 @@ public final class MoreMatchers {
|
||||
* @return A {@link Matcher} that matches trees with the specified meta-annotation.
|
||||
*/
|
||||
public static <T extends AnnotationTree> Matcher<T> hasMetaAnnotation(String annotationType) {
|
||||
TypePredicate typePredicate = hasAnnotation(annotationType);
|
||||
return (tree, state) -> {
|
||||
Symbol sym = ASTHelpers.getSymbol(tree);
|
||||
return sym != null && typePredicate.apply(sym.type, state);
|
||||
};
|
||||
return typePredicateMatcher(hasAnnotation(annotationType));
|
||||
}
|
||||
|
||||
// XXX: Consider moving to a `MoreTypePredicates` utility class.
|
||||
private static TypePredicate hasAnnotation(String annotationClassName) {
|
||||
return (type, state) -> ASTHelpers.hasAnnotation(type.tsym, annotationClassName, state);
|
||||
/**
|
||||
* Returns a {@link Matcher} that determines whether the type of a given {@link Tree} is a subtype
|
||||
* of the type returned by the specified {@link Supplier}.
|
||||
*
|
||||
* <p>This method differs from {@link Matchers#isSubtypeOf(Supplier)} in that it does not perform
|
||||
* type erasure.
|
||||
*
|
||||
* @param <T> The type of tree to match against.
|
||||
* @param type The {@link Supplier} that returns the type to match against.
|
||||
* @return A {@link Matcher} that matches trees with the specified type.
|
||||
*/
|
||||
public static <T extends Tree> Matcher<T> isSubTypeOf(Supplier<Type> type) {
|
||||
return typePredicateMatcher(MoreTypePredicates.isSubTypeOf(type));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.predicates.TypePredicate;
|
||||
import com.google.errorprone.predicates.TypePredicates;
|
||||
import com.google.errorprone.suppliers.Supplier;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.util.List;
|
||||
|
||||
/**
|
||||
* A collection of general-purpose {@link TypePredicate}s.
|
||||
*
|
||||
* <p>These methods are additions to the ones found in {@link TypePredicates}.
|
||||
*/
|
||||
// XXX: The methods in this class are tested only indirectly. Consider adding a dedicated test
|
||||
// class, or make sure that each method is explicitly covered by a tested analog in `MoreMatchers`.
|
||||
public final class MoreTypePredicates {
|
||||
private MoreTypePredicates() {}
|
||||
|
||||
/**
|
||||
* Returns a {@link TypePredicate} that matches types that are annotated with the indicated
|
||||
* annotation type.
|
||||
*
|
||||
* @param annotationType The fully-qualified name of the annotation type.
|
||||
* @return A {@link TypePredicate} that matches appropriate types.
|
||||
*/
|
||||
public static TypePredicate hasAnnotation(String annotationType) {
|
||||
return (type, state) -> ASTHelpers.hasAnnotation(type.tsym, annotationType, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link TypePredicate} that matches subtypes of the type returned by the specified
|
||||
* {@link Supplier}.
|
||||
*
|
||||
* @implNote This method does not use {@link ASTHelpers#isSubtype(Type, Type, VisitorState)}, as
|
||||
* that method performs type erasure.
|
||||
* @param bound The {@link Supplier} that returns the type to match against.
|
||||
* @return A {@link TypePredicate} that matches appropriate subtypes.
|
||||
*/
|
||||
public static TypePredicate isSubTypeOf(Supplier<Type> bound) {
|
||||
Supplier<Type> memoizedType = VisitorState.memoize(bound);
|
||||
return (type, state) -> {
|
||||
Type boundType = memoizedType.get(state);
|
||||
return boundType != null && state.getTypes().isSubtype(type, boundType);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link TypePredicate} that matches generic types with a type parameter that matches
|
||||
* the specified {@link TypePredicate} at the indicated index.
|
||||
*
|
||||
* @param index The index of the type parameter to match against.
|
||||
* @param predicate The {@link TypePredicate} to match against the type parameter.
|
||||
* @return A {@link TypePredicate} that matches appropriate generic types.
|
||||
*/
|
||||
public static TypePredicate hasTypeParameter(int index, TypePredicate predicate) {
|
||||
return (type, state) -> {
|
||||
List<Type> typeArguments = type.getTypeArguments();
|
||||
return typeArguments.size() > index && predicate.apply(typeArguments.get(index), state);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -32,13 +32,6 @@ public enum ThirdPartyLibrary {
|
||||
* @see <a href="https://github.com/google/guava">Guava on GitHub</a>
|
||||
*/
|
||||
GUAVA("com.google.common.collect.ImmutableList"),
|
||||
/**
|
||||
* New Relic's Java agent API.
|
||||
*
|
||||
* @see <a href="https://github.com/newrelic/newrelic-java-agent/tree/main/newrelic-api">New Relic
|
||||
* Java agent API on GitHub</a>
|
||||
*/
|
||||
NEW_RELIC_AGENT_API("com.newrelic.api.agent.Agent"),
|
||||
/**
|
||||
* VMWare's Project Reactor.
|
||||
*
|
||||
|
||||
@@ -103,8 +103,7 @@ final class AssortedRules {
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@Nullable
|
||||
T after(Iterator<T> iterator, T defaultValue) {
|
||||
@Nullable T after(Iterator<T> iterator, T defaultValue) {
|
||||
return Iterators.getNext(iterator, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,19 @@ final class CollectionRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Collection#contains(Object)} over more contrived alternatives. */
|
||||
static final class CollectionContains<T, S> {
|
||||
@BeforeTemplate
|
||||
boolean before(Collection<T> collection, S value) {
|
||||
return collection.stream().anyMatch(value::equals);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
boolean after(Collection<T> collection, S value) {
|
||||
return collection.contains(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't call {@link Iterables#addAll(Collection, Iterable)} when the elements to be added are
|
||||
* already part of a {@link Collection}.
|
||||
|
||||
@@ -277,4 +277,16 @@ final class DoubleStreamRules {
|
||||
return stream.allMatch(e -> test(e));
|
||||
}
|
||||
}
|
||||
|
||||
static final class DoubleStreamTakeWhile {
|
||||
@BeforeTemplate
|
||||
DoubleStream before(DoubleStream stream, DoublePredicate predicate) {
|
||||
return stream.takeWhile(predicate).filter(predicate);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
DoubleStream after(DoubleStream stream, DoublePredicate predicate) {
|
||||
return stream.takeWhile(predicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
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.AlsoNegation;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
|
||||
import com.google.errorprone.refaster.annotation.Placeholder;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
@@ -131,4 +136,62 @@ final class EqualityRules {
|
||||
return a == b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't pass a lambda expression to {@link Predicate#not(Predicate)}; instead push the negation
|
||||
* into the lambda expression.
|
||||
*/
|
||||
abstract static class PredicateLambda<T> {
|
||||
@Placeholder(allowsIdentity = true)
|
||||
abstract boolean predicate(@MayOptionallyUse T value);
|
||||
|
||||
@BeforeTemplate
|
||||
Predicate<T> before() {
|
||||
return not(v -> predicate(v));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Predicate<T> after() {
|
||||
return v -> !predicate(v);
|
||||
}
|
||||
}
|
||||
|
||||
/** Avoid contrived ways of handling {@code null} values during equality testing. */
|
||||
static final class EqualsLhsNullable<T, S> {
|
||||
@BeforeTemplate
|
||||
boolean before(T value1, S value2) {
|
||||
return Optional.ofNullable(value1).equals(Optional.of(value2));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
boolean after(T value1, S value2) {
|
||||
return value2.equals(value1);
|
||||
}
|
||||
}
|
||||
|
||||
/** Avoid contrived ways of handling {@code null} values during equality testing. */
|
||||
static final class EqualsRhsNullable<T, S> {
|
||||
@BeforeTemplate
|
||||
boolean before(T value1, S value2) {
|
||||
return Optional.of(value1).equals(Optional.ofNullable(value2));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
boolean after(T value1, S value2) {
|
||||
return value1.equals(value2);
|
||||
}
|
||||
}
|
||||
|
||||
/** Avoid contrived ways of handling {@code null} values during equality testing. */
|
||||
static final class EqualsLhsAndRhsNullable<T, S> {
|
||||
@BeforeTemplate
|
||||
boolean before(T value1, S value2) {
|
||||
return Optional.ofNullable(value1).equals(Optional.ofNullable(value2));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
boolean after(T value1, S value2) {
|
||||
return Objects.equals(value1, value2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with files. */
|
||||
@OnlineDocumentation
|
||||
final class FileRules {
|
||||
private FileRules() {}
|
||||
|
||||
/** Prefer {@link Files#readString(Path, Charset)} over more contrived alternatives. */
|
||||
static final class FilesReadStringWithCharset {
|
||||
@BeforeTemplate
|
||||
String before(Path path, Charset charset) throws IOException {
|
||||
return new String(Files.readAllBytes(path), charset);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(Path path, Charset charset) throws IOException {
|
||||
return Files.readString(path, charset);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Files#readString(Path)} over more verbose alternatives. */
|
||||
static final class FilesReadString {
|
||||
@BeforeTemplate
|
||||
String before(Path path) throws IOException {
|
||||
return Files.readString(path, UTF_8);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(Path path) throws IOException {
|
||||
return Files.readString(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,4 +290,16 @@ final class IntStreamRules {
|
||||
return stream.allMatch(e -> test(e));
|
||||
}
|
||||
}
|
||||
|
||||
static final class IntStreamTakeWhile {
|
||||
@BeforeTemplate
|
||||
IntStream before(IntStream stream, IntPredicate predicate) {
|
||||
return stream.takeWhile(predicate).filter(predicate);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
IntStream after(IntStream stream, IntPredicate predicate) {
|
||||
return stream.takeWhile(predicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,4 +290,16 @@ final class LongStreamRules {
|
||||
return stream.allMatch(e -> test(e));
|
||||
}
|
||||
}
|
||||
|
||||
static final class LongStreamTakeWhile {
|
||||
@BeforeTemplate
|
||||
LongStream before(LongStream stream, LongPredicate predicate) {
|
||||
return stream.takeWhile(predicate).filter(predicate);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
LongStream after(LongStream stream, LongPredicate predicate) {
|
||||
return stream.takeWhile(predicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,14 +33,12 @@ final class MapRules {
|
||||
|
||||
static final class MapGetOrNull<K, V, T> {
|
||||
@BeforeTemplate
|
||||
@Nullable
|
||||
V before(Map<K, V> map, T key) {
|
||||
@Nullable V before(Map<K, V> map, T key) {
|
||||
return map.getOrDefault(key, null);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@Nullable
|
||||
V after(Map<K, V> map, T key) {
|
||||
@Nullable V after(Map<K, V> map, T key) {
|
||||
return map.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,8 +50,7 @@ final class MultimapRules {
|
||||
*/
|
||||
static final class MultimapGet<K, V> {
|
||||
@BeforeTemplate
|
||||
@Nullable
|
||||
Collection<V> before(Multimap<K, V> multimap, K key) {
|
||||
@Nullable Collection<V> before(Multimap<K, V> multimap, K key) {
|
||||
return Refaster.anyOf(multimap.asMap(), Multimaps.asMap(multimap)).get(key);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,6 +100,20 @@ final class OptionalRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Optional#equals(Object)} over more contrived alternatives. */
|
||||
static final class OptionalEqualsOptional<T, S> {
|
||||
@BeforeTemplate
|
||||
boolean before(Optional<T> optional, S value) {
|
||||
return Refaster.anyOf(
|
||||
optional.filter(value::equals).isPresent(), optional.stream().anyMatch(value::equals));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
boolean after(Optional<T> optional, S value) {
|
||||
return optional.equals(Optional.of(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't use the ternary operator to extract the first element of a possibly-empty {@link
|
||||
* Iterator} as an {@link Optional}.
|
||||
@@ -350,13 +364,14 @@ final class OptionalRules {
|
||||
Optional<T> before(Optional<T> optional1, Optional<T> optional2) {
|
||||
// XXX: Note that rewriting the first and third variant will change the code's behavior if
|
||||
// `optional2` has side-effects.
|
||||
// XXX: Note that rewriting the first and third variant will introduce a compilation error if
|
||||
// `optional2` is not effectively final. Review whether a `@Matcher` can be used to avoid
|
||||
// this.
|
||||
// XXX: Note that rewriting the first, third and fourth variant will introduce a compilation
|
||||
// error if `optional2` is not effectively final. Review whether a `@Matcher` can be used to
|
||||
// avoid this.
|
||||
return Refaster.anyOf(
|
||||
optional1.map(Optional::of).orElse(optional2),
|
||||
optional1.map(Optional::of).orElseGet(() -> optional2),
|
||||
Stream.of(optional1, optional2).flatMap(Optional::stream).findFirst());
|
||||
Stream.of(optional1, optional2).flatMap(Optional::stream).findFirst(),
|
||||
optional1.isPresent() ? optional1 : optional2);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -422,12 +437,22 @@ final class OptionalRules {
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Add a rule for:
|
||||
// `optional.flatMap(x -> pred(x) ? Optional.empty() : Optional.of(x))` and variants.
|
||||
// (Maybe canonicalize the inner expression. Maybe we rewrite already.)
|
||||
/** Prefer {@link Optional#stream()} over more contrived alternatives. */
|
||||
static final class OptionalStream<T> {
|
||||
@BeforeTemplate
|
||||
Stream<T> before(Optional<T> optional) {
|
||||
return Refaster.anyOf(
|
||||
optional.map(Stream::of).orElse(Stream.empty()),
|
||||
optional.map(Stream::of).orElseGet(Stream::empty));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Stream<T> after(Optional<T> optional) {
|
||||
return optional.stream();
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Add a rule for:
|
||||
// `optional.map(Stream::of).orElse(Stream.empty())`
|
||||
// `optional.map(Stream::of).orElseGet(Stream::empty)`
|
||||
// -> `optional.stream()`
|
||||
// `optional.flatMap(x -> pred(x) ? Optional.empty() : Optional.of(x))` and variants.
|
||||
// (Maybe canonicalize the inner expression. Maybe we rewrite it already.)
|
||||
}
|
||||
|
||||
@@ -418,6 +418,19 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily transform a {@link Mono} to a {@link Flux} to expect exactly one item. */
|
||||
static final class MonoSingle<T> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(Mono<T> mono) {
|
||||
return mono.flux().single();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(Mono<T> mono) {
|
||||
return mono.single();
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily pass an empty publisher to {@link Flux#switchIfEmpty(Publisher)}. */
|
||||
static final class FluxSwitchIfEmptyOfEmptyPublisher<T> {
|
||||
@BeforeTemplate
|
||||
@@ -435,6 +448,7 @@ final class ReactorRules {
|
||||
/** Prefer {@link Flux#concatMap(Function)} over more contrived alternatives. */
|
||||
static final class FluxConcatMap<T, S> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedPublishers")
|
||||
Flux<S> before(Flux<T> flux, Function<? super T, ? extends Publisher<? extends S>> function) {
|
||||
return Refaster.anyOf(
|
||||
flux.flatMap(function, 1),
|
||||
@@ -451,6 +465,7 @@ final class ReactorRules {
|
||||
/** Prefer {@link Flux#concatMap(Function, int)} over more contrived alternatives. */
|
||||
static final class FluxConcatMapWithPrefetch<T, S> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedPublishers")
|
||||
Flux<S> before(
|
||||
Flux<T> flux,
|
||||
Function<? super T, ? extends Publisher<? extends S>> function,
|
||||
@@ -782,6 +797,7 @@ final class ReactorRules {
|
||||
/** Prefer {@link Mono#flatMap(Function)} over more contrived alternatives. */
|
||||
static final class MonoFlatMap<S, T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedPublishers")
|
||||
Mono<T> before(Mono<S> mono, Function<? super S, ? extends Mono<? extends T>> function) {
|
||||
return mono.map(function).flatMap(identity());
|
||||
}
|
||||
@@ -795,6 +811,7 @@ final class ReactorRules {
|
||||
/** Prefer {@link Mono#flatMapMany(Function)} over more contrived alternatives. */
|
||||
static final class MonoFlatMapMany<S, T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedPublishers")
|
||||
Flux<T> before(Mono<S> mono, Function<? super S, ? extends Publisher<? extends T>> function) {
|
||||
return mono.map(function).flatMapMany(identity());
|
||||
}
|
||||
@@ -1180,6 +1197,22 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not unnecessarily {@link Flux#filter(Predicate) filter} the result of {@link
|
||||
* Flux#takeWhile(Predicate)} using the same {@link Predicate}.
|
||||
*/
|
||||
static final class FluxTakeWhile<T> {
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Flux<T> flux, Predicate<? super T> predicate) {
|
||||
return flux.takeWhile(predicate).filter(predicate);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<T> after(Flux<T> flux, Predicate<? super T> predicate) {
|
||||
return flux.takeWhile(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Flux#collect(Collector)} with {@link ImmutableList#toImmutableList()} over
|
||||
* alternatives that do not explicitly return an immutable collection.
|
||||
@@ -1299,6 +1332,23 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Avoid list collection when verifying that a {@link Flux} emits exactly one value. */
|
||||
// XXX: This rule assumes that the matched collector does not drop elements. Consider introducing
|
||||
// a `@Matches(DoesNotDropElements.class)` or `@NotMatches(MayDropElements.class)` guard.
|
||||
static final class FluxAsStepVerifierExpectNext<T, L extends List<T>> {
|
||||
@BeforeTemplate
|
||||
StepVerifier.Step<L> before(Flux<T> flux, Collector<? super T, ?, L> listCollector, T object) {
|
||||
return flux.collect(listCollector)
|
||||
.as(StepVerifier::create)
|
||||
.assertNext(list -> assertThat(list).containsExactly(object));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
StepVerifier.Step<T> after(Flux<T> flux, T object) {
|
||||
return flux.as(StepVerifier::create).expectNext(object);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link StepVerifier.LastStep#verifyComplete()} over more verbose alternatives. */
|
||||
static final class StepVerifierLastStepVerifyComplete {
|
||||
@BeforeTemplate
|
||||
|
||||
@@ -45,6 +45,7 @@ import java.util.function.Predicate;
|
||||
import java.util.function.ToDoubleFunction;
|
||||
import java.util.function.ToIntFunction;
|
||||
import java.util.function.ToLongFunction;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -639,4 +640,32 @@ final class StreamRules {
|
||||
return Streams.concat(Refaster.asVarargs(stream));
|
||||
}
|
||||
}
|
||||
|
||||
static final class StreamTakeWhile<T> {
|
||||
@BeforeTemplate
|
||||
Stream<T> before(Stream<T> stream, Predicate<? super T> predicate) {
|
||||
return stream.takeWhile(predicate).filter(predicate);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Stream<T> after(Stream<T> stream, Predicate<? super T> predicate) {
|
||||
return stream.takeWhile(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Stream#iterate(Object, Predicate, UnaryOperator)} over more contrived
|
||||
* alternatives.
|
||||
*/
|
||||
static final class StreamIterate<T> {
|
||||
@BeforeTemplate
|
||||
Stream<T> before(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next) {
|
||||
return Stream.iterate(seed, next).takeWhile(hasNext);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Stream<T> after(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next) {
|
||||
return Stream.iterate(seed, hasNext, next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class MongoDBTextFilterUsageTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(MongoDBTextFilterUsage.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.mongodb.client.model.Filters;",
|
||||
"import com.mongodb.client.model.TextSearchOptions;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Filters.eq(\"foo\", \"bar\");",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Filters.text(\"foo\");",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Filters.text(\"foo\", new TextSearchOptions());",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
@@ -36,19 +36,4 @@ final class NestedOptionalsTest {
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void identificationOptionalTypeNotLoaded() {
|
||||
CompilationTestHelper.newInstance(NestedOptionals.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.time.Duration;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Duration.ofSeconds(1);",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class NestedPublishersTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(NestedPublishers.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import org.reactivestreams.Publisher;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.GroupedFlux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Mono.empty();",
|
||||
" Flux.just(1);",
|
||||
" Flux.just(1, 2).groupBy(i -> i).map(groupedFlux -> (GroupedFlux) groupedFlux);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.just(Mono.empty());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(Flux.empty());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.just((Flux) Flux.just(1));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just((Publisher) Mono.just(1));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.just(1).map(Mono::just);",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
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;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
final class ScheduledTransactionTraceTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(ScheduledTransactionTrace.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.newrelic.api.agent.Trace;",
|
||||
"import org.springframework.scheduling.annotation.Scheduled;",
|
||||
"",
|
||||
"class A {",
|
||||
" void notScheduled() {}",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 1)",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" void scheduledButNotTraced() {}",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 1)",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Trace",
|
||||
" void scheduledButImproperlyTraced1() {}",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 1)",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Trace(dispatcher = false)",
|
||||
" void scheduledButImproperlyTraced2() {}",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 1)",
|
||||
" @Trace(dispatcher = true)",
|
||||
" void scheduledAndProperlyTraced() {}",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void identificationWithoutNewRelicAgentApiOnClasspath() {
|
||||
CompilationTestHelper.newInstance(ScheduledTransactionTrace.class, getClass())
|
||||
.withClasspath(Scheduled.class)
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import org.springframework.scheduling.annotation.Scheduled;",
|
||||
"",
|
||||
"class A {",
|
||||
" @Scheduled(fixedDelay = 1)",
|
||||
" void scheduledButNotTraced() {}",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(ScheduledTransactionTrace.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import com.newrelic.api.agent.Trace;",
|
||||
"import org.springframework.scheduling.annotation.Scheduled;",
|
||||
"",
|
||||
"class A {",
|
||||
" @Scheduled(fixedDelay = 1)",
|
||||
" void scheduledButNotTraced() {}",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 1)",
|
||||
" @Trace",
|
||||
" void scheduledButImproperlyTraced1() {}",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 1)",
|
||||
" @Trace(dispatcher = false)",
|
||||
" void scheduledButImproperlyTraced2() {}",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 1)",
|
||||
" @Trace(leaf = true)",
|
||||
" void scheduledButImproperlyTraced3() {}",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import com.newrelic.api.agent.Trace;",
|
||||
"import org.springframework.scheduling.annotation.Scheduled;",
|
||||
"",
|
||||
"class A {",
|
||||
" @Trace(dispatcher = true)",
|
||||
" @Scheduled(fixedDelay = 1)",
|
||||
" void scheduledButNotTraced() {}",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 1)",
|
||||
" @Trace(dispatcher = true)",
|
||||
" void scheduledButImproperlyTraced1() {}",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 1)",
|
||||
" @Trace(dispatcher = true)",
|
||||
" void scheduledButImproperlyTraced2() {}",
|
||||
"",
|
||||
" @Scheduled(fixedDelay = 1)",
|
||||
" @Trace(dispatcher = true, leaf = true)",
|
||||
" void scheduledButImproperlyTraced3() {}",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,29 @@
|
||||
package tech.picnic.errorprone.bugpatterns.util;
|
||||
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.generic;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.subOf;
|
||||
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.type;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
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.AnnotationTreeMatcher;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.suppliers.Supplier;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class MoreMatchersTest {
|
||||
@Test
|
||||
void hasMetaAnnotation() {
|
||||
CompilationTestHelper.newInstance(TestMatcher.class, getClass())
|
||||
CompilationTestHelper.newInstance(HasMetaAnnotationTestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import org.junit.jupiter.api.AfterAll;",
|
||||
@@ -47,9 +55,59 @@ final class MoreMatchersTest {
|
||||
.doTest();
|
||||
}
|
||||
|
||||
/** A {@link BugChecker} that delegates to {@link MoreMatchers#hasMetaAnnotation(String)} . */
|
||||
@Test
|
||||
void isSubTypeOf() {
|
||||
CompilationTestHelper.newInstance(IsSubTypeOfTestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import com.google.common.collect.ImmutableSortedSet;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" ImmutableSet.of(\"foo\");",
|
||||
" ImmutableSortedSet.of(\"foo\");",
|
||||
" ImmutableList.of(\"foo\");",
|
||||
" ImmutableList.of(1);",
|
||||
" ImmutableList.of(1.0);",
|
||||
" ImmutableList.of((Number) 1);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableSet.of(1);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableSet.of(1.0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableSet.of((Number) 1);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableSortedSet.of(1);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableSortedSet.of(1.0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableSortedSet.of((Number) 1);",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isSubTypeOfBoundTypeUnknown() {
|
||||
CompilationTestHelper.newInstance(IsSubTypeOfTestChecker.class, getClass())
|
||||
.withClasspath()
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" System.out.println(toString());",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
/** A {@link BugChecker} that delegates to {@link MoreMatchers#hasMetaAnnotation(String)}. */
|
||||
@BugPattern(summary = "Interacts with `MoreMatchers` for testing purposes", severity = ERROR)
|
||||
public static final class TestMatcher extends BugChecker implements AnnotationTreeMatcher {
|
||||
public static final class HasMetaAnnotationTestChecker extends BugChecker
|
||||
implements AnnotationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<AnnotationTree> DELEGATE =
|
||||
MoreMatchers.hasMetaAnnotation("org.junit.jupiter.api.TestTemplate");
|
||||
@@ -59,4 +117,19 @@ final class MoreMatchersTest {
|
||||
return DELEGATE.matches(tree, state) ? describeMatch(tree) : Description.NO_MATCH;
|
||||
}
|
||||
}
|
||||
|
||||
/** A {@link BugChecker} that delegates to {@link MoreMatchers#isSubTypeOf(Supplier)}. */
|
||||
@BugPattern(summary = "Interacts with `MoreMatchers` for testing purposes", severity = ERROR)
|
||||
public static final class IsSubTypeOfTestChecker extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<Tree> DELEGATE =
|
||||
MoreMatchers.isSubTypeOf(
|
||||
generic(type(ImmutableSet.class.getName()), subOf(type(Number.class.getName()))));
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
return DELEGATE.matches(tree, state) ? describeMatch(tree) : Description.NO_MATCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ final class ThirdPartyLibraryTest {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"// BUG: Diagnostic contains: ASSERTJ: true, GUAVA: true, NEW_RELIC_AGENT_API: true, REACTOR: true",
|
||||
"// BUG: Diagnostic contains: ASSERTJ: true, GUAVA: true, REACTOR: true",
|
||||
"class A {}")
|
||||
.doTest();
|
||||
}
|
||||
@@ -34,16 +34,14 @@ final class ThirdPartyLibraryTest {
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.newrelic.api.agent.Agent;",
|
||||
"import org.assertj.core.api.Assertions;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"// BUG: Diagnostic contains: ASSERTJ: true, GUAVA: true, NEW_RELIC_AGENT_API: true, REACTOR: true",
|
||||
"// BUG: Diagnostic contains: ASSERTJ: true, GUAVA: true, REACTOR: true",
|
||||
"class A {",
|
||||
" void m(Class<?> clazz) {",
|
||||
" m(Assertions.class);",
|
||||
" m(ImmutableList.class);",
|
||||
" m(Agent.class);",
|
||||
" m(Flux.class);",
|
||||
" }",
|
||||
"}")
|
||||
@@ -56,7 +54,7 @@ final class ThirdPartyLibraryTest {
|
||||
.withClasspath(ImmutableList.class, Flux.class)
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"// BUG: Diagnostic contains: ASSERTJ: false, GUAVA: true, NEW_RELIC_AGENT_API: false, REACTOR: true",
|
||||
"// BUG: Diagnostic contains: ASSERTJ: false, GUAVA: true, REACTOR: true",
|
||||
"class A {}")
|
||||
.doTest();
|
||||
}
|
||||
@@ -67,7 +65,7 @@ final class ThirdPartyLibraryTest {
|
||||
.withClasspath()
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"// BUG: Diagnostic contains: ASSERTJ: false, GUAVA: false, NEW_RELIC_AGENT_API: false, REACTOR:",
|
||||
"// BUG: Diagnostic contains: ASSERTJ: false, GUAVA: false, REACTOR:",
|
||||
"// false",
|
||||
"class A {}")
|
||||
.doTest();
|
||||
@@ -82,8 +80,8 @@ final class ThirdPartyLibraryTest {
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
String.format(
|
||||
"// BUG: Diagnostic contains: ASSERTJ: %s, GUAVA: true, NEW_RELIC_AGENT_API: %s, REACTOR: true",
|
||||
ignoreClassPath, ignoreClassPath),
|
||||
"// BUG: Diagnostic contains: ASSERTJ: %s, GUAVA: true, REACTOR: true",
|
||||
ignoreClassPath),
|
||||
"class A {}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ final class RefasterRulesTest {
|
||||
ComparatorRules.class,
|
||||
DoubleStreamRules.class,
|
||||
EqualityRules.class,
|
||||
FileRules.class,
|
||||
ImmutableListRules.class,
|
||||
ImmutableListMultimapRules.class,
|
||||
ImmutableMapRules.class,
|
||||
|
||||
@@ -36,6 +36,10 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(Iterables.size(ImmutableSet.of(1)), ImmutableSet.of(2).asList().size());
|
||||
}
|
||||
|
||||
boolean testCollectionContains() {
|
||||
return ImmutableSet.of("foo").stream().anyMatch("bar"::equals);
|
||||
}
|
||||
|
||||
boolean testCollectionAddAllToCollectionExpression() {
|
||||
return Iterables.addAll(new ArrayList<>(), ImmutableSet.of("foo"));
|
||||
}
|
||||
|
||||
@@ -36,6 +36,10 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(ImmutableSet.of(1).size(), ImmutableSet.of(2).size());
|
||||
}
|
||||
|
||||
boolean testCollectionContains() {
|
||||
return ImmutableSet.of("foo").contains("bar");
|
||||
}
|
||||
|
||||
boolean testCollectionAddAllToCollectionExpression() {
|
||||
return new ArrayList<>().addAll(ImmutableSet.of("foo"));
|
||||
}
|
||||
|
||||
@@ -96,4 +96,8 @@ final class DoubleStreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
boolean testDoubleStreamAllMatch2() {
|
||||
return DoubleStream.of(1).noneMatch(n -> !(n > 1));
|
||||
}
|
||||
|
||||
DoubleStream testDoubleStreamTakeWhile() {
|
||||
return DoubleStream.of(1, 2, 3).takeWhile(i -> i < 2).filter(i -> i < 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,4 +95,8 @@ final class DoubleStreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
boolean testDoubleStreamAllMatch2() {
|
||||
return DoubleStream.of(1).allMatch(n -> n > 1);
|
||||
}
|
||||
|
||||
DoubleStream testDoubleStreamTakeWhile() {
|
||||
return DoubleStream.of(1, 2, 3).takeWhile(i -> i < 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import com.google.common.collect.BoundType;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class EqualityRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(Objects.class);
|
||||
return ImmutableSet.of(Objects.class, Optional.class, not(null));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testPrimitiveOrReferenceEquality() {
|
||||
@@ -60,4 +64,20 @@ final class EqualityRulesTest implements RefasterRuleCollectionTestCase {
|
||||
!(3.0 != 4.0),
|
||||
!(BoundType.OPEN != BoundType.CLOSED));
|
||||
}
|
||||
|
||||
Predicate<String> testPredicateLambda() {
|
||||
return not(v -> v.isEmpty());
|
||||
}
|
||||
|
||||
boolean testEqualsLhsNullable() {
|
||||
return Optional.ofNullable("foo").equals(Optional.of("bar"));
|
||||
}
|
||||
|
||||
boolean testEqualsRhsNullable() {
|
||||
return Optional.of("foo").equals(Optional.ofNullable("bar"));
|
||||
}
|
||||
|
||||
boolean testEqualsLhsAndRhsNullable() {
|
||||
return Optional.ofNullable("foo").equals(Optional.ofNullable("bar"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import com.google.common.collect.BoundType;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class EqualityRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(Objects.class);
|
||||
return ImmutableSet.of(Objects.class, Optional.class, not(null));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testPrimitiveOrReferenceEquality() {
|
||||
@@ -60,4 +64,20 @@ final class EqualityRulesTest implements RefasterRuleCollectionTestCase {
|
||||
3.0 == 4.0,
|
||||
BoundType.OPEN == BoundType.CLOSED);
|
||||
}
|
||||
|
||||
Predicate<String> testPredicateLambda() {
|
||||
return v -> !v.isEmpty();
|
||||
}
|
||||
|
||||
boolean testEqualsLhsNullable() {
|
||||
return "bar".equals("foo");
|
||||
}
|
||||
|
||||
boolean testEqualsRhsNullable() {
|
||||
return "foo".equals("bar");
|
||||
}
|
||||
|
||||
boolean testEqualsLhsAndRhsNullable() {
|
||||
return Objects.equals("foo", "bar");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class FileRulesTest implements RefasterRuleCollectionTestCase {
|
||||
String testFilesReadStringWithCharset() throws IOException {
|
||||
return new String(Files.readAllBytes(Paths.get("foo")), StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
|
||||
String testFilesReadString() throws IOException {
|
||||
return Files.readString(Paths.get("foo"), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class FileRulesTest implements RefasterRuleCollectionTestCase {
|
||||
String testFilesReadStringWithCharset() throws IOException {
|
||||
return Files.readString(Paths.get("foo"), StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
|
||||
String testFilesReadString() throws IOException {
|
||||
return Files.readString(Paths.get("foo"));
|
||||
}
|
||||
}
|
||||
@@ -100,4 +100,8 @@ final class IntStreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
boolean testIntStreamAllMatch2() {
|
||||
return IntStream.of(1).noneMatch(n -> !(n > 1));
|
||||
}
|
||||
|
||||
IntStream testIntStreamTakeWhile() {
|
||||
return IntStream.of(1, 2, 3).takeWhile(i -> i < 2).filter(i -> i < 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,4 +99,8 @@ final class IntStreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
boolean testIntStreamAllMatch2() {
|
||||
return IntStream.of(1).allMatch(n -> n > 1);
|
||||
}
|
||||
|
||||
IntStream testIntStreamTakeWhile() {
|
||||
return IntStream.of(1, 2, 3).takeWhile(i -> i < 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,4 +100,8 @@ final class LongStreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
boolean testLongStreamAllMatch2() {
|
||||
return LongStream.of(1).noneMatch(n -> !(n > 1));
|
||||
}
|
||||
|
||||
LongStream testLongStreamTakeWhile() {
|
||||
return LongStream.of(1, 2, 3).takeWhile(i -> i < 2).filter(i -> i < 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,4 +99,8 @@ final class LongStreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
boolean testLongStreamAllMatch2() {
|
||||
return LongStream.of(1).allMatch(n -> n > 1);
|
||||
}
|
||||
|
||||
LongStream testLongStreamTakeWhile() {
|
||||
return LongStream.of(1, 2, 3).takeWhile(i -> i < 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,12 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Optional::get;
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testOptionalEqualsOptional() {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").filter("bar"::equals).isPresent(),
|
||||
Optional.of("baz").stream().anyMatch("qux"::equals));
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalFirstIteratorElement() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableSet.of("foo").iterator().hasNext()
|
||||
@@ -73,6 +79,13 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Optional.of("foo").orElseGet(() -> Optional.of("bar").orElseThrow());
|
||||
}
|
||||
|
||||
ImmutableSet<String> testOptionalOrElseGet() {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").orElse("bar"),
|
||||
Optional.of("baz").orElse(toString()),
|
||||
Optional.of("qux").orElse(String.valueOf(true)));
|
||||
}
|
||||
|
||||
ImmutableSet<Object> testStreamFlatMapOptional() {
|
||||
return ImmutableSet.of(
|
||||
Stream.of(Optional.empty()).filter(Optional::isPresent).map(Optional::orElseThrow),
|
||||
@@ -99,7 +112,8 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").map(Optional::of).orElse(Optional.of("bar")),
|
||||
Optional.of("baz").map(Optional::of).orElseGet(() -> Optional.of("qux")),
|
||||
Stream.of(Optional.of("quux"), Optional.of("quuz")).flatMap(Optional::stream).findFirst());
|
||||
Stream.of(Optional.of("quux"), Optional.of("quuz")).flatMap(Optional::stream).findFirst(),
|
||||
Optional.of("corge").isPresent() ? Optional.of("corge") : Optional.of("grault"));
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalIdentity() {
|
||||
@@ -120,10 +134,9 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Optional.of(1).stream().map(String::valueOf).findAny();
|
||||
}
|
||||
|
||||
ImmutableSet<String> testOptionalOrElseGet() {
|
||||
ImmutableSet<Stream<String>> testOptionalStream() {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").orElse("bar"),
|
||||
Optional.of("baz").orElse(toString()),
|
||||
Optional.of("qux").orElse(String.valueOf(true)));
|
||||
Optional.of("foo").map(Stream::of).orElse(Stream.empty()),
|
||||
Optional.of("bar").map(Stream::of).orElseGet(Stream::empty));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,12 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Optional::orElseThrow;
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testOptionalEqualsOptional() {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").equals(Optional.of("bar")),
|
||||
Optional.of("baz").equals(Optional.of("qux")));
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalFirstIteratorElement() {
|
||||
return ImmutableSet.of(
|
||||
stream(ImmutableSet.of("foo").iterator()).findFirst(),
|
||||
@@ -70,6 +76,13 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Optional.of("foo").or(() -> Optional.of("bar")).orElseThrow();
|
||||
}
|
||||
|
||||
ImmutableSet<String> testOptionalOrElseGet() {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").orElse("bar"),
|
||||
Optional.of("baz").orElse(toString()),
|
||||
Optional.of("qux").orElseGet(() -> String.valueOf(true)));
|
||||
}
|
||||
|
||||
ImmutableSet<Object> testStreamFlatMapOptional() {
|
||||
return ImmutableSet.of(
|
||||
Stream.of(Optional.empty()).flatMap(Optional::stream),
|
||||
@@ -96,7 +109,8 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").or(() -> Optional.of("bar")),
|
||||
Optional.of("baz").or(() -> Optional.of("qux")),
|
||||
Optional.of("quux").or(() -> Optional.of("quuz")));
|
||||
Optional.of("quux").or(() -> Optional.of("quuz")),
|
||||
Optional.of("corge").or(() -> Optional.of("grault")));
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalIdentity() {
|
||||
@@ -113,10 +127,7 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Optional.of(1).map(String::valueOf);
|
||||
}
|
||||
|
||||
ImmutableSet<String> testOptionalOrElseGet() {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").orElse("bar"),
|
||||
Optional.of("baz").orElse(toString()),
|
||||
Optional.of("qux").orElseGet(() -> String.valueOf(true)));
|
||||
ImmutableSet<Stream<String>> testOptionalStream() {
|
||||
return ImmutableSet.of(Optional.of("foo").stream(), Optional.of("bar").stream());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,6 +145,10 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Mono.<ImmutableList<String>>empty().map(ImmutableList::copyOf));
|
||||
}
|
||||
|
||||
Mono<Integer> testMonoSingle() {
|
||||
return Mono.just(1).flux().single();
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxSwitchIfEmptyOfEmptyPublisher() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).switchIfEmpty(Mono.empty()), Flux.just(2).switchIfEmpty(Flux.empty()));
|
||||
@@ -378,6 +382,10 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Flux.just(1, 4, 3, 2).sort(reverseOrder()).filter(i -> i % 2 == 0);
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxTakeWhile() {
|
||||
return Flux.just(1, 2, 3).takeWhile(i -> i % 2 == 0).filter(i -> i % 2 == 0);
|
||||
}
|
||||
|
||||
Mono<List<Integer>> testFluxCollectToImmutableList() {
|
||||
return Flux.just(1).collectList();
|
||||
}
|
||||
@@ -414,6 +422,13 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
StepVerifier.create(Mono.just("baz")).expectNextMatches("qux"::equals));
|
||||
}
|
||||
|
||||
StepVerifier.Step<?> testFluxAsStepVerifierExpectNext() {
|
||||
return Flux.just(1)
|
||||
.collect(toImmutableList())
|
||||
.as(StepVerifier::create)
|
||||
.assertNext(list -> assertThat(list).containsExactly(2));
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyComplete() {
|
||||
return StepVerifier.create(Mono.empty()).expectComplete().verify();
|
||||
}
|
||||
|
||||
@@ -150,6 +150,10 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Mono.<ImmutableList<String>>empty());
|
||||
}
|
||||
|
||||
Mono<Integer> testMonoSingle() {
|
||||
return Mono.just(1).single();
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxSwitchIfEmptyOfEmptyPublisher() {
|
||||
return ImmutableSet.of(Flux.just(1), Flux.just(2));
|
||||
}
|
||||
@@ -371,6 +375,10 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Flux.just(1, 4, 3, 2).filter(i -> i % 2 == 0).sort(reverseOrder());
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxTakeWhile() {
|
||||
return Flux.just(1, 2, 3).takeWhile(i -> i % 2 == 0);
|
||||
}
|
||||
|
||||
Mono<List<Integer>> testFluxCollectToImmutableList() {
|
||||
return Flux.just(1).collect(toImmutableList());
|
||||
}
|
||||
@@ -405,6 +413,10 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
StepVerifier.create(Mono.just("baz")).expectNext("qux"));
|
||||
}
|
||||
|
||||
StepVerifier.Step<?> testFluxAsStepVerifierExpectNext() {
|
||||
return Flux.just(1).as(StepVerifier::create).expectNext(2);
|
||||
}
|
||||
|
||||
Duration testStepVerifierLastStepVerifyComplete() {
|
||||
return StepVerifier.create(Mono.empty()).verifyComplete();
|
||||
}
|
||||
|
||||
@@ -258,4 +258,12 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Stream.of(Stream.of(1), Stream.of(2)).flatMap(identity()),
|
||||
Stream.of(Stream.of(3), Stream.of(4)).flatMap(v -> v));
|
||||
}
|
||||
|
||||
Stream<Integer> testStreamTakeWhile() {
|
||||
return Stream.of(1, 2, 3).takeWhile(i -> i < 2).filter(i -> i < 2);
|
||||
}
|
||||
|
||||
Stream<Integer> testStreamIterate() {
|
||||
return Stream.iterate(0, i -> i + 1).takeWhile(i -> i < 10);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,4 +258,12 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(
|
||||
Streams.concat(Stream.of(1), Stream.of(2)), Streams.concat(Stream.of(3), Stream.of(4)));
|
||||
}
|
||||
|
||||
Stream<Integer> testStreamTakeWhile() {
|
||||
return Stream.of(1, 2, 3).takeWhile(i -> i < 2);
|
||||
}
|
||||
|
||||
Stream<Integer> testStreamIterate() {
|
||||
return Stream.iterate(0, i -> i < 10, i -> i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
114
pom.xml
114
pom.xml
@@ -4,7 +4,7 @@
|
||||
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.12.1-SNAPSHOT</version>
|
||||
<version>0.14.0</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Picnic :: Error Prone Support</name>
|
||||
@@ -49,7 +49,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:PicnicSupermarket/error-prone-support.git</developerConnection>
|
||||
<tag>v0.12.0</tag>
|
||||
<tag>v0.14.0</tag>
|
||||
<url>https://github.com/PicnicSupermarket/error-prone-support</url>
|
||||
</scm>
|
||||
<issueManagement>
|
||||
@@ -141,7 +141,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-06-21T19:15:38Z</project.build.outputTimestamp>
|
||||
<project.build.outputTimestamp>2023-10-04T14:37:51Z</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
|
||||
@@ -198,18 +198,18 @@
|
||||
one place. We use these to keep dependencies in sync. Version numbers
|
||||
that need to be referenced only once should *not* be listed here. -->
|
||||
<version.auto-service>1.1.1</version.auto-service>
|
||||
<version.auto-value>1.10.1</version.auto-value>
|
||||
<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.20.0</version.error-prone-orig>
|
||||
<version.error-prone-slf4j>0.1.18</version.error-prone-slf4j>
|
||||
<version.error-prone-orig>2.22.0</version.error-prone-orig>
|
||||
<version.error-prone-slf4j>0.1.20</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.3.1</version.mockito>
|
||||
<version.mockito>5.5.0</version.mockito>
|
||||
<version.nopen-checker>1.0.1</version.nopen-checker>
|
||||
<version.nullaway>0.10.10</version.nullaway>
|
||||
<version.pitest-git>1.0.11</version.pitest-git>
|
||||
<version.nullaway>0.10.14</version.nullaway>
|
||||
<version.pitest-git>1.1.2</version.pitest-git>
|
||||
<version.surefire>3.1.2</version.surefire>
|
||||
</properties>
|
||||
|
||||
@@ -275,7 +275,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.auto</groupId>
|
||||
<artifactId>auto-common</artifactId>
|
||||
<version>1.2.1</version>
|
||||
<version>1.2.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.service</groupId>
|
||||
@@ -295,7 +295,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.googlejavaformat</groupId>
|
||||
<artifactId>google-java-format</artifactId>
|
||||
<version>1.17.0</version>
|
||||
<version>1.18.0</version>
|
||||
</dependency>
|
||||
<!-- Specified as a workaround for
|
||||
https://github.com/mojohaus/versions-maven-plugin/issues/244. -->
|
||||
@@ -307,14 +307,14 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava-bom</artifactId>
|
||||
<version>32.0.1-jre</version>
|
||||
<version>32.1.2-jre</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.truth</groupId>
|
||||
<artifactId>truth</artifactId>
|
||||
<version>1.1.4</version>
|
||||
<version>1.1.5</version>
|
||||
</dependency>
|
||||
<!-- Specified as a workaround for
|
||||
https://github.com/mojohaus/versions-maven-plugin/issues/244. -->
|
||||
@@ -323,11 +323,6 @@
|
||||
<artifactId>nopen-checker</artifactId>
|
||||
<version>${version.nopen-checker}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.newrelic.agent.java</groupId>
|
||||
<artifactId>newrelic-api</artifactId>
|
||||
<version>8.4.0</version>
|
||||
</dependency>
|
||||
<!-- Specified as a workaround for
|
||||
https://github.com/mojohaus/versions-maven-plugin/issues/244. -->
|
||||
<dependency>
|
||||
@@ -338,7 +333,7 @@
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-bom</artifactId>
|
||||
<version>2022.0.8</version>
|
||||
<version>2022.0.11</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -355,7 +350,7 @@
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>2.2.12</version>
|
||||
<version>2.2.16</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
@@ -387,7 +382,7 @@
|
||||
<dependency>
|
||||
<groupId>net.bytebuddy</groupId>
|
||||
<artifactId>byte-buddy</artifactId>
|
||||
<version>1.14.5</version>
|
||||
<version>1.14.8</version>
|
||||
</dependency>
|
||||
<!-- Specified so that Renovate will file Maven upgrade PRs, which
|
||||
subsequently will cause `maven-enforcer-plugin` to require that
|
||||
@@ -400,7 +395,7 @@
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<version>1.9.19</version>
|
||||
<version>1.9.20.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
@@ -412,7 +407,7 @@
|
||||
<dependency>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
<artifactId>checker-qual</artifactId>
|
||||
<version>3.35.0</version>
|
||||
<version>3.39.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
@@ -432,7 +427,7 @@
|
||||
<dependency>
|
||||
<groupId>org.junit</groupId>
|
||||
<artifactId>junit-bom</artifactId>
|
||||
<version>5.9.3</version>
|
||||
<version>5.10.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -443,22 +438,37 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongodb-driver-core</artifactId>
|
||||
<version>4.10.2</version>
|
||||
<!-- XXX: Drop this exclusion once we forgo enforcement of JDK
|
||||
11 bytecode version compatibility. -->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>bson-record-codec</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>2.0.7</version>
|
||||
<artifactId>slf4j-bom</artifactId>
|
||||
<version>2.0.9</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>5.3.27</version>
|
||||
<version>5.3.30</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test</artifactId>
|
||||
<version>2.7.12</version>
|
||||
<version>2.7.16</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
@@ -474,7 +484,7 @@
|
||||
<plugin>
|
||||
<groupId>com.github.ekryd.sortpom</groupId>
|
||||
<artifactId>sortpom-maven-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<createBackupFile>false</createBackupFile>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
@@ -511,7 +521,7 @@
|
||||
<plugin>
|
||||
<groupId>com.spotify.fmt</groupId>
|
||||
<artifactId>fmt-maven-plugin</artifactId>
|
||||
<version>2.20</version>
|
||||
<version>2.21.1</version>
|
||||
<configuration>
|
||||
<additionalSourceDirectories>
|
||||
<additionalSourceDirectory>${basedir}/src/test/resources</additionalSourceDirectory>
|
||||
@@ -523,7 +533,7 @@
|
||||
<plugin>
|
||||
<groupId>de.thetaphi</groupId>
|
||||
<artifactId>forbiddenapis</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>3.6</version>
|
||||
<configuration>
|
||||
<bundledSignatures>
|
||||
<bundledSignature>jdk-internal</bundledSignature>
|
||||
@@ -706,13 +716,13 @@
|
||||
<!-- Instead, please use
|
||||
`org.jspecify.annotations.Nullable`. -->
|
||||
</property>
|
||||
<property name="illegalPkgs" value="autovalue.shaded" />
|
||||
<property name="illegalPkgs" value="com.amazonaws.annotation" />
|
||||
<property name="illegalPkgs" value="com.beust.jcommander.internal" />
|
||||
<property name="illegalPkgs" value="com.google.api.client.repackaged" />
|
||||
<property name="illegalPkgs" value="com.google.common.cache">
|
||||
<!-- Instead, please use Caffeine. -->
|
||||
</property>
|
||||
<property name="illegalPkgs" value="com.newrelic.agent.deps" />
|
||||
<property name="illegalPkgs" value="com.tngtech.archunit.thirdparty" />
|
||||
<property name="illegalPkgs" value="jdk" />
|
||||
<property name="illegalPkgs" value="jersey.repackaged" />
|
||||
@@ -839,7 +849,7 @@
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>10.12.0</version>
|
||||
<version>10.12.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.spring.nohttp</groupId>
|
||||
@@ -859,7 +869,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<version>3.3.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@@ -963,7 +973,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.4.1</version>
|
||||
<configuration>
|
||||
<fail>false</fail>
|
||||
<rules>
|
||||
@@ -1002,19 +1012,9 @@
|
||||
</banDuplicateClasses>
|
||||
<banDuplicatePomDependencyVersions />
|
||||
<banDynamicVersions>
|
||||
<!-- XXX: Drop this once the `ignores` section
|
||||
below works as expected. -->
|
||||
<allowSnapshots>true</allowSnapshots>
|
||||
<!-- XXX: It shouldn't be necessary to specify
|
||||
an empty `excludedScopes` parameter, but
|
||||
without this an NPE results. See
|
||||
https://issues.apache.org/jira/browse/MENFORCER-481. -->
|
||||
<excludedScopes />
|
||||
<!-- XXX: This doesn't work. See
|
||||
https://issues.apache.org/jira/browse/MENFORCER-480.
|
||||
<ignores>
|
||||
<ignore>${project.groupId}</ignore>
|
||||
</ignores> -->
|
||||
</ignores>
|
||||
</banDynamicVersions>
|
||||
<dependencyConvergence />
|
||||
<enforceBytecodeVersion>
|
||||
@@ -1112,7 +1112,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<version>3.6.0</version>
|
||||
<configuration>
|
||||
<additionalJOptions>
|
||||
<additionalJOption>--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</additionalJOption>
|
||||
@@ -1189,7 +1189,8 @@
|
||||
</includes>
|
||||
<properties>
|
||||
<configurationParameters>junit.jupiter.execution.parallel.enabled=true
|
||||
junit.jupiter.execution.parallel.mode.default=concurrent</configurationParameters>
|
||||
junit.jupiter.execution.parallel.mode.default=concurrent
|
||||
junit.platform.stacktrace.pruning.enabled=false</configurationParameters>
|
||||
</properties>
|
||||
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
||||
</configuration>
|
||||
@@ -1202,7 +1203,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>2.1.0</version>
|
||||
<version>2.2.0</version>
|
||||
<configuration>
|
||||
<includedLicenses>
|
||||
<!-- The SPDX IDs of licenses of third-party
|
||||
@@ -1305,7 +1306,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.16.0</version>
|
||||
<version>2.16.1</version>
|
||||
<configuration>
|
||||
<updateBuildOutputTimestampPolicy>never</updateBuildOutputTimestampPolicy>
|
||||
</configuration>
|
||||
@@ -1313,7 +1314,7 @@
|
||||
<plugin>
|
||||
<groupId>org.gaul</groupId>
|
||||
<artifactId>modernizer-maven-plugin</artifactId>
|
||||
<version>2.6.0</version>
|
||||
<version>2.7.0</version>
|
||||
<configuration>
|
||||
<exclusionPatterns>
|
||||
<!-- The plugin suggests replacing usages of
|
||||
@@ -1356,7 +1357,7 @@
|
||||
<plugin>
|
||||
<groupId>org.pitest</groupId>
|
||||
<artifactId>pitest-maven</artifactId>
|
||||
<version>1.14.1</version>
|
||||
<version>1.15.0</version>
|
||||
<configuration>
|
||||
<excludedClasses>
|
||||
<!-- AutoValue generated classes. -->
|
||||
@@ -1385,12 +1386,12 @@
|
||||
<dependency>
|
||||
<groupId>com.groupcdg.arcmutate</groupId>
|
||||
<artifactId>base</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<version>1.2.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.groupcdg.pitest</groupId>
|
||||
<artifactId>pitest-accelerator-junit5</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>1.0.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.pitest</groupId>
|
||||
@@ -1410,7 +1411,7 @@
|
||||
<plugin>
|
||||
<groupId>org.sonarsource.scanner.maven</groupId>
|
||||
<artifactId>sonar-maven-plugin</artifactId>
|
||||
<version>3.9.1.2184</version>
|
||||
<version>3.10.0.2594</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
@@ -1720,9 +1721,6 @@
|
||||
-Xep:Java7ApiChecker:OFF
|
||||
<!-- We don't target JDK 8. -->
|
||||
-Xep:Java8ApiChecker:OFF
|
||||
<!-- XXX: Triggers an IOOBE. See
|
||||
https://github.com/google/error-prone/pull/3976. -->
|
||||
-Xep:MemberName:OFF
|
||||
<!-- We don't target Android. -->
|
||||
-Xep:StaticOrDefaultInterfaceMethod:OFF
|
||||
<!-- We generally discourage `var` use. -->
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.12.1-SNAPSHOT</version>
|
||||
<version>0.14.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-compiler</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.12.1-SNAPSHOT</version>
|
||||
<version>0.14.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-runner</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.12.1-SNAPSHOT</version>
|
||||
<version>0.14.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-support</artifactId>
|
||||
|
||||
@@ -23,6 +23,7 @@ public @interface OnlineDocumentation {
|
||||
* the annotated Refaster rule is located.
|
||||
*/
|
||||
String TOP_LEVEL_CLASS_URL_PLACEHOLDER = "${topLevelClassName}";
|
||||
|
||||
/**
|
||||
* The URL placeholder value that will be replaced with the name of the nested class in which the
|
||||
* annotated Refaster rule is located, if applicable.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.12.1-SNAPSHOT</version>
|
||||
<version>0.14.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-test-support</artifactId>
|
||||
|
||||
@@ -42,7 +42,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.inject.Inject;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@@ -180,7 +179,7 @@ public final class RefasterRuleCollection extends BugChecker implements Compilat
|
||||
|
||||
for (Description description : matches) {
|
||||
String ruleName = extractRefasterRuleName(description);
|
||||
Set<Replacement> replacements =
|
||||
ImmutableSet<Replacement> replacements =
|
||||
Iterables.getOnlyElement(description.fixes).getReplacements(endPositions);
|
||||
for (Replacement replacement : replacements) {
|
||||
ruleMatches.put(replacement.range(), ruleName);
|
||||
|
||||
23
run-branch-mutation-tests.sh
Executable file
23
run-branch-mutation-tests.sh
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Executes Pitest to determine the mutation test coverage of changed code. By
|
||||
# default code that is changed relative to the default branch is exercised,
|
||||
# though another change set may be specified; see the Arcmutate Git integration
|
||||
# documentation for details [1]. The results are found in each Maven module's
|
||||
# `target/pit-reports` directory.
|
||||
#
|
||||
# [1] https://docs.arcmutate.com/docs/git-integration.html
|
||||
|
||||
set -e -u -o pipefail
|
||||
|
||||
if [ "${#}" -gt 1 ]; then
|
||||
echo "Usage: ${0} [DiffSpec]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
diffSpec="${1:-+GIT(from[refs/remotes/origin/HEAD])}"
|
||||
|
||||
mvn clean test-compile pitest:mutationCoverage \
|
||||
-DargLine.xmx=2048m \
|
||||
-Dverification.skip \
|
||||
-Dfeatures="${diffSpec}"
|
||||
@@ -13,9 +13,7 @@ fi
|
||||
|
||||
targetTests="${1:-*}"
|
||||
|
||||
mvn clean test pitest:mutationCoverage \
|
||||
mvn clean test-compile pitest:mutationCoverage \
|
||||
-DargLine.xmx=2048m \
|
||||
-Dverification.skip \
|
||||
-Dsurefire.failIfNoSpecifiedTests=false \
|
||||
-Dtest="${targetTests}" \
|
||||
-DtargetTests="${targetTests}"
|
||||
|
||||
Reference in New Issue
Block a user