mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
Compare commits
139 Commits
sschroever
...
rossendrij
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ba4f872be | ||
|
|
3d5678e20e | ||
|
|
c679a3fc0c | ||
|
|
de54b4bf64 | ||
|
|
ea60241782 | ||
|
|
e4f928addb | ||
|
|
059cc9e2db | ||
|
|
1e43c28c95 | ||
|
|
a07e9b3115 | ||
|
|
aec38d2e33 | ||
|
|
5b77663288 | ||
|
|
97c2bbd4b1 | ||
|
|
9c8fbfd36a | ||
|
|
38e6c3fdb5 | ||
|
|
5b1d82cfeb | ||
|
|
0821a95fcc | ||
|
|
f4afe457cb | ||
|
|
fd56ca8b6e | ||
|
|
882794d63b | ||
|
|
73ed6e32c7 | ||
|
|
ca5c3dd3b4 | ||
|
|
f6e9dbb996 | ||
|
|
260021c961 | ||
|
|
ec54e79f3e | ||
|
|
4cbfdba521 | ||
|
|
d94f65a1f0 | ||
|
|
9afdf2ddf3 | ||
|
|
060c901479 | ||
|
|
1feee4f64a | ||
|
|
552ddf6a7d | ||
|
|
5d92c6c6ce | ||
|
|
fa8ca80040 | ||
|
|
b733179cd0 | ||
|
|
3d9aab7c5b | ||
|
|
366cdda3d8 | ||
|
|
5b6dd147ef | ||
|
|
a868b03130 | ||
|
|
fdf9bb5d25 | ||
|
|
363b0c22c7 | ||
|
|
32ec35a354 | ||
|
|
635fe280f8 | ||
|
|
aac9b6bf10 | ||
|
|
c322ea1bbc | ||
|
|
a433a90673 | ||
|
|
5a37d65632 | ||
|
|
77d183f8fd | ||
|
|
2eb4e853c5 | ||
|
|
45a7242cf5 | ||
|
|
c85070ba23 | ||
|
|
a687f09bf0 | ||
|
|
2e4fdcb0db | ||
|
|
1005d93b7e | ||
|
|
136123f6b4 | ||
|
|
4cb5f0079d | ||
|
|
290ddf1972 | ||
|
|
5a163ce2e9 | ||
|
|
4eb0aae452 | ||
|
|
b5b98d899b | ||
|
|
bbf3d79d9a | ||
|
|
1164270589 | ||
|
|
f03d72388a | ||
|
|
2e5d1f1e87 | ||
|
|
4b1c892f04 | ||
|
|
2b6b8de150 | ||
|
|
b275a33eb8 | ||
|
|
7a9aeca248 | ||
|
|
bd5cdefea9 | ||
|
|
a265a450f9 | ||
|
|
5fbb0636aa | ||
|
|
6eb22da201 | ||
|
|
781b4d0c57 | ||
|
|
5234fca96d | ||
|
|
8daedccaea | ||
|
|
886e65d7ac | ||
|
|
ec502cef20 | ||
|
|
f3ff515271 | ||
|
|
d662eb1cbc | ||
|
|
c40b73186b | ||
|
|
6734af6742 | ||
|
|
c5ec2a552d | ||
|
|
a3e3a32332 | ||
|
|
8c3756c4f7 | ||
|
|
c472225f9c | ||
|
|
7a8538a87a | ||
|
|
dba37a3f23 | ||
|
|
e89cfe0aef | ||
|
|
9c1993e5a7 | ||
|
|
d586014379 | ||
|
|
3a441487a3 | ||
|
|
6f6a4c481e | ||
|
|
56f0cc81c9 | ||
|
|
6c58d4cc01 | ||
|
|
a1e47542e7 | ||
|
|
eff958d4c1 | ||
|
|
81704c6534 | ||
|
|
1e229949fc | ||
|
|
28a93e949e | ||
|
|
40ad38bc2a | ||
|
|
e125c6b7e2 | ||
|
|
5596c4530d | ||
|
|
d81fe19836 | ||
|
|
d6838ec947 | ||
|
|
b36a69aa5f | ||
|
|
831b757bb1 | ||
|
|
527fc5785b | ||
|
|
8c8055d381 | ||
|
|
b658c19c03 | ||
|
|
85976e199f | ||
|
|
f6a392e118 | ||
|
|
539fcae745 | ||
|
|
29f1a3d2a6 | ||
|
|
01f139b6a4 | ||
|
|
c61980721e | ||
|
|
471a1ebff1 | ||
|
|
b8d9ff0971 | ||
|
|
e02d836c12 | ||
|
|
abd47eb269 | ||
|
|
5219fd8f6c | ||
|
|
588fc38f81 | ||
|
|
e3aa8a5d12 | ||
|
|
3255c0b6eb | ||
|
|
d2dbd88f25 | ||
|
|
ff824cfa20 | ||
|
|
43303e770a | ||
|
|
cfadbca32a | ||
|
|
e7ca4a5325 | ||
|
|
7bab1eb7fd | ||
|
|
072e39da32 | ||
|
|
ec7e84ac45 | ||
|
|
4228a63ad1 | ||
|
|
6093e6f322 | ||
|
|
ee103a99f6 | ||
|
|
c34065beab | ||
|
|
d9e1f3ad5d | ||
|
|
8a8290587a | ||
|
|
162aa0d458 | ||
|
|
0fb37c45b5 | ||
|
|
0c2ce44742 | ||
|
|
f089157443 |
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-22.04 ]
|
||||
jdk: [ 17.0.10, 21.0.2 ]
|
||||
jdk: [ 17.0.10, 21.0.2, 22.0.2 ]
|
||||
distribution: [ temurin ]
|
||||
experimental: [ false ]
|
||||
include:
|
||||
@@ -26,13 +26,15 @@ jobs:
|
||||
continue-on-error: ${{ matrix.experimental }}
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
github.com:443
|
||||
jitpack.io:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
# We run the build twice for each supported JDK: once against the
|
||||
# original Error Prone release, using only Error Prone checks available
|
||||
@@ -40,11 +42,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 and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
with:
|
||||
java-version: ${{ matrix.jdk }}
|
||||
java-distribution: ${{ matrix.distribution }}
|
||||
maven-version: 3.9.6
|
||||
maven-version: 3.9.9
|
||||
- name: Display build environment details
|
||||
run: mvn --version
|
||||
- name: Build project against vanilla Error Prone, compile Javadoc
|
||||
|
||||
7
.github/workflows/codeql.yml
vendored
7
.github/workflows/codeql.yml
vendored
@@ -22,22 +22,23 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
api.github.com:443
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
uploads.github.com:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
with:
|
||||
java-version: 17.0.10
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
maven-version: 3.9.9
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1
|
||||
with:
|
||||
|
||||
6
.github/workflows/deploy-website.yml
vendored
6
.github/workflows/deploy-website.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
www.youtube.com:443
|
||||
youtrack.jetbrains.com:443
|
||||
- name: Check out code
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
|
||||
11
.github/workflows/openssf-scorecard.yml
vendored
11
.github/workflows/openssf-scorecard.yml
vendored
@@ -21,26 +21,25 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.github.com:443
|
||||
api.osv.dev:443
|
||||
api.scorecard.dev:443
|
||||
api.securityscorecards.dev:443
|
||||
fulcio.sigstore.dev:443
|
||||
github.com:443
|
||||
oss-fuzz-build-logs.storage.googleapis.com:443
|
||||
rekor.sigstore.dev:443
|
||||
tuf-repo-cdn.sigstore.dev:443
|
||||
*.sigstore.dev:443
|
||||
www.bestpractices.dev:443
|
||||
- name: Check out code
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run OpenSSF Scorecard analysis
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
|
||||
uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
|
||||
8
.github/workflows/pitest-analyze-pr.yml
vendored
8
.github/workflows/pitest-analyze-pr.yml
vendored
@@ -12,20 +12,22 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
with:
|
||||
checkout-fetch-depth: 2
|
||||
java-version: 17.0.10
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
maven-version: 3.9.9
|
||||
- name: Run Pitest
|
||||
# By running with features `+GIT(from[HEAD~1]), +gitci`, Pitest only
|
||||
# analyzes lines changed in the associated pull request, as GitHub
|
||||
|
||||
8
.github/workflows/pitest-update-pr.yml
vendored
8
.github/workflows/pitest-update-pr.yml
vendored
@@ -20,20 +20,22 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
api.github.com:443
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
with:
|
||||
java-version: 17.0.10
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
maven-version: 3.9.9
|
||||
- name: Download Pitest analysis artifact
|
||||
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
|
||||
with:
|
||||
|
||||
8
.github/workflows/run-integration-tests.yml
vendored
8
.github/workflows/run-integration-tests.yml
vendored
@@ -19,24 +19,26 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
checkstyle.org:443
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
oss.sonatype.org:443
|
||||
raw.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
repository.sonatype.org:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
with:
|
||||
checkout-ref: "refs/pull/${{ github.event.issue.number }}/head"
|
||||
java-version: 17.0.10
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
maven-version: 3.9.9
|
||||
- name: Install project to local Maven repository
|
||||
run: mvn -T1C install -DskipTests -Dverification.skip
|
||||
- name: Run integration test
|
||||
|
||||
12
.github/workflows/sonarcloud.yml
vendored
12
.github/workflows/sonarcloud.yml
vendored
@@ -19,24 +19,28 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
analysis-sensorcache-eu-central-1-prod.s3.amazonaws.com:443
|
||||
api.adoptium.net:443
|
||||
api.nuget.org:443
|
||||
ea6ne4j2sb.execute-api.eu-central-1.amazonaws.com:443
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
sc-cleancode-sensorcache-eu-central-1-prod.s3.amazonaws.com:443
|
||||
scanner.sonarcloud.io:443
|
||||
*.sonarcloud.io:443
|
||||
sonarcloud.io:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
|
||||
with:
|
||||
checkout-fetch-depth: 0
|
||||
java-version: 17.0.10
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
maven-version: 3.9.9
|
||||
- name: Create missing `test` directory
|
||||
# XXX: Drop this step in favour of actually having a test.
|
||||
run: mkdir refaster-compiler/src/test
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"separateMinorPatch": true
|
||||
},
|
||||
{
|
||||
"matchDepNames": [
|
||||
"matchPackageNames": [
|
||||
"dawidd6/action-download-artifact",
|
||||
"github/codeql-action",
|
||||
"ruby/setup-ruby"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
<version>0.18.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>documentation-support</artifactId>
|
||||
|
||||
@@ -14,7 +14,6 @@ import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ServiceLoader;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
@@ -87,6 +86,6 @@ final class DocumentationGeneratorTaskListener implements TaskListener {
|
||||
}
|
||||
|
||||
private static String getSimpleClassName(URI path) {
|
||||
return Paths.get(path).getFileName().toString().replace(".java", "");
|
||||
return Path.of(path).getFileName().toString().replace(".java", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
<version>0.18.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-contrib</artifactId>
|
||||
@@ -67,6 +67,11 @@
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.service</groupId>
|
||||
<artifactId>auto-service-annotations</artifactId>
|
||||
@@ -122,6 +127,11 @@
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
|
||||
@@ -51,6 +51,7 @@ import tech.picnic.errorprone.utils.SourceCode;
|
||||
// is effectively the identity operation.
|
||||
// XXX: Also flag nullary instance method invocations that represent an identity conversion, such as
|
||||
// `Boolean#booleanValue()`, `Byte#byteValue()` and friends.
|
||||
// XXX: Also flag redundant round-trip conversions such as `path.toFile().toPath()`.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Avoid or clarify identity conversions",
|
||||
|
||||
@@ -18,14 +18,12 @@ import com.google.errorprone.fixes.SuggestedFixes;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.IdentifierTree;
|
||||
import com.sun.source.tree.LiteralTree;
|
||||
import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import tech.picnic.errorprone.refaster.matchers.RequiresComputation;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/**
|
||||
@@ -36,12 +34,12 @@ import tech.picnic.errorprone.utils.SourceCode;
|
||||
* it does, the suggested fix changes the program's semantics. Such fragile code must instead be
|
||||
* refactored such that the side-effectful code does not appear accidental.
|
||||
*/
|
||||
// XXX: Consider also implementing the inverse, in which `.orElseGet(() -> someConstant)` is
|
||||
// flagged.
|
||||
// XXX: Once the `MethodReferenceUsageCheck` becomes generally usable, consider leaving the method
|
||||
// reference cleanup to that check, and express the remainder of the logic in this class using a
|
||||
// Refaster template, i.c.w. a `@Matches` constraint that implements the `requiresComputation`
|
||||
// logic.
|
||||
// XXX: This rule may introduce a compilation error: the `value` expression may reference a
|
||||
// non-effectively final variable, which is not allowed in the replacement lambda expression.
|
||||
// Review whether a `@Matcher` can be used to avoid this.
|
||||
// XXX: Once the `MethodReferenceUsageCheck` bug checker becomes generally usable, consider leaving
|
||||
// the method reference cleanup to that check, and express the remainder of the logic in this class
|
||||
// using a Refaster template, i.c.w. a `@NotMatches(RequiresComputation.class)` constraint.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary =
|
||||
@@ -51,16 +49,17 @@ import tech.picnic.errorprone.utils.SourceCode;
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = PERFORMANCE)
|
||||
public final class OptionalOrElse extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
public final class OptionalOrElseGet extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> REQUIRES_COMPUTATION = new RequiresComputation();
|
||||
private static final Matcher<ExpressionTree> OPTIONAL_OR_ELSE_METHOD =
|
||||
instanceMethod().onExactClass(Optional.class.getCanonicalName()).namedAnyOf("orElse");
|
||||
// XXX: Also exclude invocations of `@Placeholder`-annotated methods.
|
||||
private static final Matcher<ExpressionTree> REFASTER_METHOD =
|
||||
staticMethod().onClass(Refaster.class.getCanonicalName());
|
||||
|
||||
/** Instantiates a new {@link OptionalOrElse} instance. */
|
||||
public OptionalOrElse() {}
|
||||
/** Instantiates a new {@link OptionalOrElseGet} instance. */
|
||||
public OptionalOrElseGet() {}
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
@@ -69,7 +68,8 @@ public final class OptionalOrElse extends BugChecker implements MethodInvocation
|
||||
}
|
||||
|
||||
ExpressionTree argument = Iterables.getOnlyElement(tree.getArguments());
|
||||
if (!requiresComputation(argument) || REFASTER_METHOD.matches(argument, state)) {
|
||||
if (!REQUIRES_COMPUTATION.matches(argument, state)
|
||||
|| REFASTER_METHOD.matches(argument, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
@@ -91,18 +91,6 @@ public final class OptionalOrElse extends BugChecker implements MethodInvocation
|
||||
return describeMatch(tree, fix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given expression contains anything other than a literal or a (possibly
|
||||
* dereferenced) variable or constant.
|
||||
*/
|
||||
private static boolean requiresComputation(ExpressionTree tree) {
|
||||
return !(tree instanceof IdentifierTree
|
||||
|| tree instanceof LiteralTree
|
||||
|| (tree instanceof MemberSelectTree memberSelect
|
||||
&& !requiresComputation(memberSelect.getExpression()))
|
||||
|| ASTHelpers.constValue(tree) != null);
|
||||
}
|
||||
|
||||
/** Returns the nullary method reference matching the given expression, if any. */
|
||||
private static Optional<String> tryMethodReferenceConversion(
|
||||
ExpressionTree tree, VisitorState state) {
|
||||
@@ -118,7 +106,7 @@ public final class OptionalOrElse extends BugChecker implements MethodInvocation
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (requiresComputation(memberSelect.getExpression())) {
|
||||
if (REQUIRES_COMPUTATION.matches(memberSelect.getExpression(), state)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package tech.picnic.errorprone.refasterrules;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
@@ -37,7 +38,12 @@ final class ClassRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Class#isInstance(Object)} method references over more verbose alternatives. */
|
||||
/**
|
||||
* Prefer {@link Class#isInstance(Object)} method references over lambda expressions that require
|
||||
* naming a variable.
|
||||
*/
|
||||
// XXX: Once the `ClassReferenceIsInstancePredicate` rule is dropped, rename this rule to just
|
||||
// `ClassIsInstancePredicate`.
|
||||
static final class ClassLiteralIsInstancePredicate<T, S> {
|
||||
@BeforeTemplate
|
||||
Predicate<S> before() {
|
||||
@@ -50,7 +56,11 @@ final class ClassRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Class#isInstance(Object)} method references over more verbose alternatives. */
|
||||
/**
|
||||
* Prefer {@link Class#isInstance(Object)} method references over lambda expressions that require
|
||||
* naming a variable.
|
||||
*/
|
||||
// XXX: Drop this rule once the `MethodReferenceUsage` rule is enabled by default.
|
||||
static final class ClassReferenceIsInstancePredicate<T, S> {
|
||||
@BeforeTemplate
|
||||
Predicate<S> before(Class<T> clazz) {
|
||||
@@ -62,4 +72,39 @@ final class ClassRules {
|
||||
return clazz::isInstance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Class#cast(Object)} method references over lambda expressions that require naming
|
||||
* a variable.
|
||||
*/
|
||||
// XXX: Once the `ClassReferenceCast` rule is dropped, rename this rule to just `ClassCast`.
|
||||
static final class ClassLiteralCast<T, S> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
Function<T, S> before() {
|
||||
return t -> (S) t;
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Function<T, S> after() {
|
||||
return Refaster.<S>clazz()::cast;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Class#cast(Object)} method references over lambda expressions that require naming
|
||||
* a variable.
|
||||
*/
|
||||
// XXX: Drop this rule once the `MethodReferenceUsage` rule is enabled by default.
|
||||
static final class ClassReferenceCast<T, S> {
|
||||
@BeforeTemplate
|
||||
Function<T, S> before(Class<? extends S> clazz) {
|
||||
return o -> clazz.cast(o);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Function<T, S> after(Class<? extends S> clazz) {
|
||||
return clazz::cast;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.AlsoNegation;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.NotMatches;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -21,6 +23,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsRefasterAsVarargs;
|
||||
|
||||
/** Refaster rules related to expressions dealing with (arbitrary) collections. */
|
||||
// XXX: There are other Guava `Iterables` methods that should not be called if the input is known to
|
||||
@@ -184,6 +187,24 @@ final class CollectionRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily call {@link Stream#distinct()} on an already-unique stream of elements. */
|
||||
// XXX: This rule assumes that the `Set` relies on `Object#equals`, rather than a custom
|
||||
// equivalence relation.
|
||||
// XXX: Expressions that drop or reorder elements from the stream, such as `.filter`, `.skip` and
|
||||
// `sorted`, can similarly be simplified. Covering all cases is better done using an Error Prone
|
||||
// check.
|
||||
static final class SetStream<T> {
|
||||
@BeforeTemplate
|
||||
Stream<?> before(Set<T> set) {
|
||||
return set.stream().distinct();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Stream<?> after(Set<T> set) {
|
||||
return set.stream();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link ArrayList#ArrayList(Collection)} over the Guava alternative. */
|
||||
@SuppressWarnings(
|
||||
"NonApiType" /* Matching against `List` would unnecessarily constrain the rule. */)
|
||||
@@ -276,6 +297,23 @@ final class CollectionRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Arrays#asList(Object[])} over more contrived alternatives. */
|
||||
// XXX: Consider moving this rule to `ImmutableListRules` and having it suggest
|
||||
// `ImmutableList#copyOf`. That would retain immutability, at the cost of no longer handling
|
||||
// `null`s.
|
||||
static final class ArraysAsList<T> {
|
||||
// XXX: This expression produces an unmodifiable list, while the alternative doesn't.
|
||||
@BeforeTemplate
|
||||
List<T> before(@NotMatches(IsRefasterAsVarargs.class) T[] array) {
|
||||
return Arrays.stream(array).toList();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
List<T> after(T[] array) {
|
||||
return Arrays.asList(array);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer calling {@link Collection#toArray()} over more contrived alternatives. */
|
||||
static final class CollectionToArray<T> {
|
||||
@BeforeTemplate
|
||||
|
||||
@@ -24,8 +24,10 @@ import com.google.errorprone.refaster.annotation.Placeholder;
|
||||
import com.google.errorprone.refaster.annotation.Repeated;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
@@ -243,18 +245,77 @@ final class ComparatorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Collections#sort(List)} over more verbose alternatives. */
|
||||
static final class CollectionsSort<T extends Comparable<? super T>> {
|
||||
@BeforeTemplate
|
||||
void before(List<T> collection) {
|
||||
Collections.sort(collection, naturalOrder());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(List<T> collection) {
|
||||
Collections.sort(collection);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Collections#min(Collection)} over more verbose alternatives. */
|
||||
static final class CollectionsMin<T extends Comparable<? super T>> {
|
||||
@BeforeTemplate
|
||||
T before(Collection<T> collection) {
|
||||
return Refaster.anyOf(
|
||||
Collections.min(collection, naturalOrder()), Collections.max(collection, reverseOrder()));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(Collection<T> collection) {
|
||||
return Collections.min(collection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary creation of a {@link Stream} to determine the minimum of a known collection
|
||||
* of values.
|
||||
*/
|
||||
static final class MinOfVarargs<T> {
|
||||
static final class MinOfArray<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
T before(@Repeated T value, Comparator<T> cmp) {
|
||||
T before(T[] array, Comparator<S> cmp) {
|
||||
return Arrays.stream(array).min(cmp).orElseThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(T[] array, Comparator<S> cmp) {
|
||||
return Collections.min(Arrays.asList(array), cmp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary creation of a {@link Stream} to determine the minimum of a known collection
|
||||
* of values.
|
||||
*/
|
||||
static final class CollectionsMinWithComparator<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
T before(Collection<T> collection, Comparator<S> cmp) {
|
||||
return collection.stream().min(cmp).orElseThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(Collection<T> collection, Comparator<S> cmp) {
|
||||
return Collections.min(collection, cmp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary creation of a {@link Stream} to determine the minimum of a known collection
|
||||
* of values.
|
||||
*/
|
||||
static final class MinOfVarargs<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
T before(@Repeated T value, Comparator<S> cmp) {
|
||||
return Stream.of(Refaster.asVarargs(value)).min(cmp).orElseThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(@Repeated T value, Comparator<T> cmp) {
|
||||
T after(@Repeated T value, Comparator<S> cmp) {
|
||||
return Collections.min(Arrays.asList(value), cmp);
|
||||
}
|
||||
}
|
||||
@@ -310,18 +371,64 @@ final class ComparatorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Collections#max(Collection)} over more verbose alternatives. */
|
||||
static final class CollectionsMax<T extends Comparable<? super T>> {
|
||||
@BeforeTemplate
|
||||
T before(Collection<T> collection) {
|
||||
return Refaster.anyOf(
|
||||
Collections.max(collection, naturalOrder()), Collections.min(collection, reverseOrder()));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(Collection<T> collection) {
|
||||
return Collections.max(collection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary creation of a {@link Stream} to determine the maximum of a known collection
|
||||
* of values.
|
||||
*/
|
||||
static final class MaxOfVarargs<T> {
|
||||
static final class MaxOfArray<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
T before(@Repeated T value, Comparator<T> cmp) {
|
||||
T before(T[] array, Comparator<S> cmp) {
|
||||
return Arrays.stream(array).max(cmp).orElseThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(T[] array, Comparator<S> cmp) {
|
||||
return Collections.max(Arrays.asList(array), cmp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary creation of a {@link Stream} to determine the maximum of a known collection
|
||||
* of values.
|
||||
*/
|
||||
static final class CollectionsMaxWithComparator<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
T before(Collection<T> collection, Comparator<S> cmp) {
|
||||
return collection.stream().max(cmp).orElseThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(Collection<T> collection, Comparator<S> cmp) {
|
||||
return Collections.max(collection, cmp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary creation of a {@link Stream} to determine the maximum of a known collection
|
||||
* of values.
|
||||
*/
|
||||
static final class MaxOfVarargs<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
T before(@Repeated T value, Comparator<S> cmp) {
|
||||
return Stream.of(Refaster.asVarargs(value)).max(cmp).orElseThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(@Repeated T value, Comparator<T> cmp) {
|
||||
T after(@Repeated T value, Comparator<S> cmp) {
|
||||
return Collections.max(Arrays.asList(value), cmp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.util.function.Predicate.isEqual;
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
@@ -19,9 +20,9 @@ import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
final class EqualityRules {
|
||||
private EqualityRules() {}
|
||||
|
||||
/** Prefer reference-based quality for enums. */
|
||||
// Primitive value comparisons are not listed, because Error Prone flags those out of the box.
|
||||
static final class PrimitiveOrReferenceEquality<T extends Enum<T>> {
|
||||
/** Prefer reference-based equality for enums. */
|
||||
// Primitive value comparisons are not matched, because Error Prone flags those out of the box.
|
||||
static final class EnumReferenceEquality<T extends Enum<T>> {
|
||||
/**
|
||||
* Enums can be compared by reference. It is safe to do so even in the face of refactorings,
|
||||
* because if the type is ever converted to a non-enum, then Error-Prone will complain about any
|
||||
@@ -43,6 +44,20 @@ final class EqualityRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer reference-based equality for enums. */
|
||||
static final class EnumReferenceEqualityLambda<T extends Enum<T>> {
|
||||
@BeforeTemplate
|
||||
Predicate<T> before(T e) {
|
||||
return Refaster.anyOf(isEqual(e), e::equals);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("java:S1698" /* Reference comparison is valid for enums. */)
|
||||
Predicate<T> after(T e) {
|
||||
return v -> v == e;
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Object#equals(Object)} over the equivalent lambda function. */
|
||||
// XXX: As it stands, this rule is a special case of what `MethodReferenceUsage` tries to achieve.
|
||||
// If/when `MethodReferenceUsage` becomes production ready, we should simply drop this check.
|
||||
|
||||
@@ -2,12 +2,18 @@ package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Repeated;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with files. */
|
||||
@@ -15,6 +21,49 @@ import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
final class FileRules {
|
||||
private FileRules() {}
|
||||
|
||||
/** Prefer the more idiomatic {@link Path#of(URI)} over {@link Paths#get(URI)}. */
|
||||
static final class PathOfUri {
|
||||
@BeforeTemplate
|
||||
Path before(URI uri) {
|
||||
return Paths.get(uri);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Path after(URI uri) {
|
||||
return Path.of(uri);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer the more idiomatic {@link Path#of(String, String...)} over {@link Paths#get(String,
|
||||
* String...)}.
|
||||
*/
|
||||
static final class PathOfString {
|
||||
@BeforeTemplate
|
||||
Path before(String first, @Repeated String more) {
|
||||
return Paths.get(first, more);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Path after(String first, @Repeated String more) {
|
||||
return Path.of(first, more);
|
||||
}
|
||||
}
|
||||
|
||||
/** Avoid redundant conversions from {@link Path} to {@link File}. */
|
||||
// XXX: Review whether a rule such as this one is better handled by the `IdentityConversion` rule.
|
||||
static final class PathInstance {
|
||||
@BeforeTemplate
|
||||
Path before(Path path) {
|
||||
return path.toFile().toPath();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Path after(Path path) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Files#readString(Path, Charset)} over more contrived alternatives. */
|
||||
static final class FilesReadStringWithCharset {
|
||||
@BeforeTemplate
|
||||
@@ -40,4 +89,44 @@ final class FileRules {
|
||||
return Files.readString(path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Files#createTempFile(String, String, FileAttribute[])} over alternatives that
|
||||
* create files with more liberal permissions.
|
||||
*/
|
||||
static final class FilesCreateTempFileToFile {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings({
|
||||
"FilesCreateTempFileInCustomDirectoryToFile" /* This is a more specific template. */,
|
||||
"java:S5443" /* This violation will be rewritten. */,
|
||||
"key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict"
|
||||
})
|
||||
File before(String prefix, String suffix) throws IOException {
|
||||
return Refaster.anyOf(
|
||||
File.createTempFile(prefix, suffix), File.createTempFile(prefix, suffix, null));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings(
|
||||
"java:S5443" /* On POSIX systems the file will only have user read-write permissions. */)
|
||||
File after(String prefix, String suffix) throws IOException {
|
||||
return Files.createTempFile(prefix, suffix).toFile();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Files#createTempFile(Path, String, String, FileAttribute[])} over alternatives
|
||||
* that create files with more liberal permissions.
|
||||
*/
|
||||
static final class FilesCreateTempFileInCustomDirectoryToFile {
|
||||
@BeforeTemplate
|
||||
File before(File directory, String prefix, String suffix) throws IOException {
|
||||
return File.createTempFile(prefix, suffix, directory);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
File after(File directory, String prefix, String suffix) throws IOException {
|
||||
return Files.createTempFile(directory.toPath(), prefix, suffix).toFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,16 +302,22 @@ import tech.picnic.errorprone.refaster.annotation.TypeMigration;
|
||||
final class JUnitToAssertJRules {
|
||||
private JUnitToAssertJRules() {}
|
||||
|
||||
static final class ThrowNewAssertionError {
|
||||
static final class Fail<T> {
|
||||
@BeforeTemplate
|
||||
void before() {
|
||||
Assertions.fail();
|
||||
T before() {
|
||||
return Assertions.fail();
|
||||
}
|
||||
|
||||
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)` once
|
||||
// https://github.com/google/error-prone/pull/3584 is resolved. Until that time, statically
|
||||
// importing AssertJ's `fail` is likely to clash with an existing static import of JUnit's
|
||||
// `fail`. Note that combining Error Prone's `RemoveUnusedImports` and
|
||||
// `UnnecessarilyFullyQualified` checks and our `StaticImport` check will anyway cause the
|
||||
// method to be imported statically if possible; just in a less efficient manner.
|
||||
@AfterTemplate
|
||||
@DoNotCall
|
||||
void after() {
|
||||
throw new AssertionError();
|
||||
T after() {
|
||||
return fail();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,12 +327,7 @@ final class JUnitToAssertJRules {
|
||||
return Assertions.fail(message);
|
||||
}
|
||||
|
||||
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)` once
|
||||
// https://github.com/google/error-prone/pull/3584 is resolved. Until that time, statically
|
||||
// importing AssertJ's `fail` is likely to clash with an existing static import of JUnit's
|
||||
// `fail`. Note that combining Error Prone's `RemoveUnusedImports` and
|
||||
// `UnnecessarilyFullyQualified` checks and our `StaticImport` check will anyway cause the
|
||||
// method to be imported statically if possible; just in a less efficient manner.
|
||||
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)`. See `Fail` comment.
|
||||
@AfterTemplate
|
||||
T after(String message) {
|
||||
return fail(message);
|
||||
@@ -339,28 +340,24 @@ final class JUnitToAssertJRules {
|
||||
return Assertions.fail(message, throwable);
|
||||
}
|
||||
|
||||
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)` once
|
||||
// https://github.com/google/error-prone/pull/3584 is resolved. Until that time, statically
|
||||
// importing AssertJ's `fail` is likely to clash with an existing static import of JUnit's
|
||||
// `fail`. Note that combining Error Prone's `RemoveUnusedImports` and
|
||||
// `UnnecessarilyFullyQualified` checks and our `StaticImport` check will anyway cause the
|
||||
// method to be imported statically if possible; just in a less efficient manner.
|
||||
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)`. See `Fail` comment.
|
||||
@AfterTemplate
|
||||
T after(String message, Throwable throwable) {
|
||||
return fail(message, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
static final class FailWithThrowable {
|
||||
static final class FailWithThrowable<T> {
|
||||
@BeforeTemplate
|
||||
void before(Throwable throwable) {
|
||||
Assertions.fail(throwable);
|
||||
T before(Throwable throwable) {
|
||||
return Assertions.fail(throwable);
|
||||
}
|
||||
|
||||
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)`. See `Fail` comment.
|
||||
@AfterTemplate
|
||||
@DoNotCall
|
||||
void after(Throwable throwable) {
|
||||
throw new AssertionError(throwable);
|
||||
T after(Throwable throwable) {
|
||||
return fail(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsLikelyTrivialComputation;
|
||||
import tech.picnic.errorprone.refaster.matchers.RequiresComputation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with {@link Optional}s. */
|
||||
@OnlineDocumentation
|
||||
@@ -255,24 +255,21 @@ final class OptionalRules {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Optional#orElseGet(Supplier)} over {@link Optional#orElse(Object)} if the
|
||||
* fallback value is not the result of a trivial computation.
|
||||
* Prefer {@link Optional#orElse(Object)} over {@link Optional#orElseGet(Supplier)} if the
|
||||
* fallback value does not require non-trivial computation.
|
||||
*/
|
||||
// XXX: This rule may introduce a compilation error: the `value` expression may reference a
|
||||
// non-effectively final variable, which is not allowed in the replacement lambda expression.
|
||||
// Review whether a `@Matcher` can be used to avoid this.
|
||||
// XXX: Once `MethodReferenceUsage` is "production ready", replace
|
||||
// `@NotMatches(IsLikelyTrivialComputation.class)` with `@Matches(RequiresComputation.class)` (and
|
||||
// reimplement the matcher accordingly).
|
||||
static final class OptionalOrElseGet<T> {
|
||||
// XXX: This rule is the counterpart to the `OptionalOrElseGet` bug checker. Once the
|
||||
// `MethodReferenceUsage` bug checker is "production ready", that bug checker may similarly be
|
||||
// replaced with a Refaster rule.
|
||||
static final class OptionalOrElse<T> {
|
||||
@BeforeTemplate
|
||||
T before(Optional<T> optional, @NotMatches(IsLikelyTrivialComputation.class) T value) {
|
||||
return optional.orElse(value);
|
||||
T before(Optional<T> optional, @NotMatches(RequiresComputation.class) T value) {
|
||||
return optional.orElseGet(() -> value);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(Optional<T> optional, T value) {
|
||||
return optional.orElseGet(() -> value);
|
||||
return optional.orElse(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,7 +370,12 @@ final class OptionalRules {
|
||||
/** Prefer {@link Optional#or(Supplier)} over more verbose alternatives. */
|
||||
static final class OptionalOrOtherOptional<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedOptionals")
|
||||
@SuppressWarnings({
|
||||
"LexicographicalAnnotationAttributeListing" /* `key-*` entry must remain last. */,
|
||||
"NestedOptionals" /* This violation will be rewritten. */,
|
||||
"OptionalOrElse" /* Parameters represent expressions that may require computation. */,
|
||||
"key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict"
|
||||
})
|
||||
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.
|
||||
|
||||
@@ -8,6 +8,8 @@ import com.google.common.primitives.Floats;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
import com.google.common.primitives.Shorts;
|
||||
import com.google.common.primitives.UnsignedInts;
|
||||
import com.google.common.primitives.UnsignedLongs;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.AlsoNegation;
|
||||
@@ -76,6 +78,8 @@ final class PrimitiveRules {
|
||||
}
|
||||
|
||||
/** Prefer {@link Math#toIntExact(long)} over the Guava alternative. */
|
||||
// XXX: This rule changes the exception possibly thrown from `IllegalArgumentException` to
|
||||
// `ArithmeticException`.
|
||||
static final class LongToIntExact {
|
||||
@BeforeTemplate
|
||||
int before(long l) {
|
||||
@@ -192,72 +196,8 @@ final class PrimitiveRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Boolean#compare(boolean, boolean)} over the Guava alternative. */
|
||||
static final class BooleanCompare {
|
||||
@BeforeTemplate
|
||||
int before(boolean a, boolean b) {
|
||||
return Booleans.compare(a, b);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(boolean a, boolean b) {
|
||||
return Boolean.compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Character#compare(char, char)} over the Guava alternative. */
|
||||
static final class CharacterCompare {
|
||||
@BeforeTemplate
|
||||
int before(char a, char b) {
|
||||
return Chars.compare(a, b);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(char a, char b) {
|
||||
return Character.compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Short#compare(short, short)} over the Guava alternative. */
|
||||
static final class ShortCompare {
|
||||
@BeforeTemplate
|
||||
int before(short a, short b) {
|
||||
return Shorts.compare(a, b);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(short a, short b) {
|
||||
return Short.compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Integer#compare(int, int)} over the Guava alternative. */
|
||||
static final class IntegerCompare {
|
||||
@BeforeTemplate
|
||||
int before(int a, int b) {
|
||||
return Ints.compare(a, b);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(int a, int b) {
|
||||
return Integer.compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Long#compare(long, long)} over the Guava alternative. */
|
||||
static final class LongCompare {
|
||||
@BeforeTemplate
|
||||
int before(long a, long b) {
|
||||
return Longs.compare(a, b);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(long a, long b) {
|
||||
return Long.compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Float#compare(float, float)} over the Guava alternative. */
|
||||
// XXX: Drop this rule once https://github.com/google/guava/pull/7371 is released.
|
||||
static final class FloatCompare {
|
||||
@BeforeTemplate
|
||||
int before(float a, float b) {
|
||||
@@ -271,6 +211,7 @@ final class PrimitiveRules {
|
||||
}
|
||||
|
||||
/** Prefer {@link Double#compare(double, double)} over the Guava alternative. */
|
||||
// XXX: Drop this rule once https://github.com/google/guava/pull/7371 is released.
|
||||
static final class DoubleCompare {
|
||||
@BeforeTemplate
|
||||
int before(double a, double b) {
|
||||
@@ -442,4 +383,205 @@ final class PrimitiveRules {
|
||||
return Long.signum(l) == -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Integer#compareUnsigned(int, int)} over third-party alternatives. */
|
||||
static final class IntegerCompareUnsigned {
|
||||
@BeforeTemplate
|
||||
int before(int x, int y) {
|
||||
return UnsignedInts.compare(x, y);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(int x, int y) {
|
||||
return Integer.compareUnsigned(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Long#compareUnsigned(long, long)} over third-party alternatives. */
|
||||
static final class LongCompareUnsigned {
|
||||
@BeforeTemplate
|
||||
long before(long x, long y) {
|
||||
return UnsignedLongs.compare(x, y);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
long after(long x, long y) {
|
||||
return Long.compareUnsigned(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Integer#divideUnsigned(int, int)} over third-party alternatives. */
|
||||
static final class IntegerDivideUnsigned {
|
||||
@BeforeTemplate
|
||||
int before(int x, int y) {
|
||||
return UnsignedInts.divide(x, y);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(int x, int y) {
|
||||
return Integer.divideUnsigned(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Long#divideUnsigned(long, long)} over third-party alternatives. */
|
||||
static final class LongDivideUnsigned {
|
||||
@BeforeTemplate
|
||||
long before(long x, long y) {
|
||||
return UnsignedLongs.divide(x, y);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
long after(long x, long y) {
|
||||
return Long.divideUnsigned(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Integer#remainderUnsigned(int, int)} over third-party alternatives. */
|
||||
static final class IntegerRemainderUnsigned {
|
||||
@BeforeTemplate
|
||||
int before(int x, int y) {
|
||||
return UnsignedInts.remainder(x, y);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(int x, int y) {
|
||||
return Integer.remainderUnsigned(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Long#remainderUnsigned(long, long)} over third-party alternatives. */
|
||||
static final class LongRemainderUnsigned {
|
||||
@BeforeTemplate
|
||||
long before(long x, long y) {
|
||||
return UnsignedLongs.remainder(x, y);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
long after(long x, long y) {
|
||||
return Long.remainderUnsigned(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer JDK's {@link Integer#parseUnsignedInt(String)} over third-party or more verbose
|
||||
* alternatives.
|
||||
*/
|
||||
static final class IntegerParseUnsignedInt {
|
||||
@BeforeTemplate
|
||||
int before(String string) {
|
||||
return Refaster.anyOf(
|
||||
UnsignedInts.parseUnsignedInt(string), Integer.parseUnsignedInt(string, 10));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(String string) {
|
||||
return Integer.parseUnsignedInt(string);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer JDK's {@link Long#parseUnsignedLong(String)} over third-party or more verbose
|
||||
* alternatives.
|
||||
*/
|
||||
static final class LongParseUnsignedLong {
|
||||
@BeforeTemplate
|
||||
long before(String string) {
|
||||
return Refaster.anyOf(
|
||||
UnsignedLongs.parseUnsignedLong(string), Long.parseUnsignedLong(string, 10));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
long after(String string) {
|
||||
return Long.parseUnsignedLong(string);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Integer#parseUnsignedInt(String, int)} over third-party alternatives. */
|
||||
static final class IntegerParseUnsignedIntWithRadix {
|
||||
@BeforeTemplate
|
||||
int before(String string, int radix) {
|
||||
return UnsignedInts.parseUnsignedInt(string, radix);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(String string, int radix) {
|
||||
return Integer.parseUnsignedInt(string, radix);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Long#parseUnsignedLong(String, int)} over third-party alternatives. */
|
||||
static final class LongParseUnsignedLongWithRadix {
|
||||
@BeforeTemplate
|
||||
long before(String string, int radix) {
|
||||
return UnsignedLongs.parseUnsignedLong(string, radix);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
long after(String string, int radix) {
|
||||
return Long.parseUnsignedLong(string, radix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer JDK's {@link Integer#toUnsignedString(int)} over third-party or more verbose
|
||||
* alternatives.
|
||||
*/
|
||||
static final class IntegerToUnsignedString {
|
||||
@BeforeTemplate
|
||||
String before(int i) {
|
||||
return Refaster.anyOf(UnsignedInts.toString(i), Integer.toUnsignedString(i, 10));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(int i) {
|
||||
return Integer.toUnsignedString(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer JDK's {@link Long#toUnsignedString(long)} over third-party or more verbose alternatives.
|
||||
*/
|
||||
static final class LongToUnsignedString {
|
||||
@BeforeTemplate
|
||||
String before(long i) {
|
||||
return Refaster.anyOf(UnsignedLongs.toString(i), Long.toUnsignedString(i, 10));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(long i) {
|
||||
return Long.toUnsignedString(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer JDK's {@link Integer#toUnsignedString(int,int)} over third-party or more verbose
|
||||
* alternatives.
|
||||
*/
|
||||
static final class IntegerToUnsignedStringWithRadix {
|
||||
@BeforeTemplate
|
||||
String before(int i, int radix) {
|
||||
return UnsignedInts.toString(i, radix);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(int i, int radix) {
|
||||
return Integer.toUnsignedString(i, radix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer JDK's {@link Long#toUnsignedString(long,int)} over third-party or more verbose
|
||||
* alternatives.
|
||||
*/
|
||||
static final class LongToUnsignedStringWithRadix {
|
||||
@BeforeTemplate
|
||||
String before(long i, int radix) {
|
||||
return UnsignedLongs.toString(i, radix);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(long i, int radix) {
|
||||
return Long.toUnsignedString(i, radix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import static java.util.stream.Collectors.toCollection;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static reactor.function.TupleUtils.function;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -33,6 +34,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
@@ -40,6 +42,7 @@ import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.Stream;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
@@ -480,15 +483,20 @@ final class ReactorRules {
|
||||
}
|
||||
|
||||
/** Prefer {@link Flux#just(Object)} over more contrived alternatives. */
|
||||
static final class FluxJust {
|
||||
static final class FluxJust<T> {
|
||||
@BeforeTemplate
|
||||
Flux<Integer> before(int start) {
|
||||
return Flux.range(start, 1);
|
||||
Flux<Integer> before(int value) {
|
||||
return Flux.range(value, 1);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
Flux<T> before(T value) {
|
||||
return Mono.just(value).repeat().take(1);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<Integer> after(int start) {
|
||||
return Flux.just(start);
|
||||
Flux<T> after(T value) {
|
||||
return Flux.just(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,6 +565,7 @@ final class ReactorRules {
|
||||
@Matches(IsIdentityOperation.class)
|
||||
Function<? super P, ? extends Publisher<? extends S>> identityOperation) {
|
||||
return Refaster.anyOf(
|
||||
flux.concatMap(function, 0),
|
||||
flux.flatMap(function, 1),
|
||||
flux.flatMapSequential(function, 1),
|
||||
flux.map(function).concatMap(identityOperation));
|
||||
@@ -1197,10 +1206,17 @@ final class ReactorRules {
|
||||
}
|
||||
|
||||
/** Prefer {@link Flux#fromIterable(Iterable)} over less efficient alternatives. */
|
||||
// XXX: Once the `FluxFromStreamSupplier` rule is constrained using
|
||||
// `@NotMatches(IsIdentityOperation.class)`, this rule should also cover
|
||||
// `Flux.fromStream(collection.stream())`.
|
||||
static final class FluxFromIterable<T> {
|
||||
// XXX: Once the `MethodReferenceUsage` check is generally enabled, drop the second
|
||||
// `Refaster.anyOf` variant.
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Collection<T> collection) {
|
||||
return Flux.fromStream(collection.stream());
|
||||
return Flux.fromStream(
|
||||
Refaster.<Supplier<Stream<? extends T>>>anyOf(
|
||||
collection::stream, () -> collection.stream()));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -1903,4 +1919,76 @@ final class ReactorRules {
|
||||
return step.verifyTimeout(duration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Mono#fromFuture(Supplier)} over {@link Mono#fromFuture(CompletableFuture)}, as
|
||||
* the former may defer initiation of the asynchronous computation until subscription.
|
||||
*/
|
||||
static final class MonoFromFutureSupplier<T> {
|
||||
// XXX: Constrain the `future` parameter using `@NotMatches(IsIdentityOperation.class)` once
|
||||
// `IsIdentityOperation` no longer matches nullary method invocations.
|
||||
@BeforeTemplate
|
||||
Mono<T> before(CompletableFuture<T> future) {
|
||||
return Mono.fromFuture(future);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(CompletableFuture<T> future) {
|
||||
return Mono.fromFuture(() -> future);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Mono#fromFuture(Supplier, boolean)} over {@link
|
||||
* Mono#fromFuture(CompletableFuture, boolean)}, as the former may defer initiation of the
|
||||
* asynchronous computation until subscription.
|
||||
*/
|
||||
static final class MonoFromFutureSupplierBoolean<T> {
|
||||
// XXX: Constrain the `future` parameter using `@NotMatches(IsIdentityOperation.class)` once
|
||||
// `IsIdentityOperation` no longer matches nullary method invocations.
|
||||
@BeforeTemplate
|
||||
Mono<T> before(CompletableFuture<T> future, boolean suppressCancel) {
|
||||
return Mono.fromFuture(future, suppressCancel);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(CompletableFuture<T> future, boolean suppressCancel) {
|
||||
return Mono.fromFuture(() -> future, suppressCancel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't propagate {@link Mono} cancellations to an upstream cache value computation, as
|
||||
* completion of such computations may benefit concurrent or subsequent cache usages.
|
||||
*/
|
||||
static final class MonoFromFutureAsyncLoadingCacheGet<K, V> {
|
||||
@BeforeTemplate
|
||||
Mono<V> before(AsyncLoadingCache<K, V> cache, K key) {
|
||||
return Mono.fromFuture(() -> cache.get(key));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<V> after(AsyncLoadingCache<K, V> cache, K key) {
|
||||
return Mono.fromFuture(() -> cache.get(key), /* suppressCancel= */ true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Flux#fromStream(Supplier)} over {@link Flux#fromStream(Stream)}, as the former
|
||||
* yields a {@link Flux} that is more likely to behave as expected when subscribed to more than
|
||||
* once.
|
||||
*/
|
||||
static final class FluxFromStreamSupplier<T> {
|
||||
// XXX: Constrain the `stream` parameter using `@NotMatches(IsIdentityOperation.class)` once
|
||||
// `IsIdentityOperation` no longer matches nullary method invocations.
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Stream<T> stream) {
|
||||
return Flux.fromStream(stream);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<T> after(Stream<T> stream) {
|
||||
return Flux.fromStream(() -> stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,4 +244,11 @@ final class StringRules {
|
||||
return Utf8.encodedLength(str);
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrite `String#copyValueOf(char[])` to `new String(char[])`.
|
||||
// Example:
|
||||
// String.copyValueOf(new char[]);
|
||||
// -->
|
||||
// new String(new char[]);
|
||||
|
||||
}
|
||||
|
||||
@@ -161,8 +161,9 @@ final class TestNGToAssertJRules {
|
||||
|
||||
@AfterTemplate
|
||||
@DoNotCall
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after() {
|
||||
throw new AssertionError();
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,15 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class OptionalOrElseTest {
|
||||
final class OptionalOrElseGetTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(OptionalOrElse.class, getClass())
|
||||
CompilationTestHelper.newInstance(OptionalOrElseGet.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.google.errorprone.refaster.Refaster;",
|
||||
"import java.util.Optional;",
|
||||
"import java.util.function.Supplier;",
|
||||
"",
|
||||
"class A {",
|
||||
" private final Optional<Object> optional = Optional.empty();",
|
||||
@@ -27,6 +28,7 @@ final class OptionalOrElseTest {
|
||||
" optional.orElse(string);",
|
||||
" optional.orElse(this.string);",
|
||||
" optional.orElse(Refaster.anyOf(\"constant\", \"another\"));",
|
||||
" Optional.<Supplier<String>>empty().orElse(() -> \"constant\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Optional.empty().orElse(string + \"constant\");",
|
||||
@@ -67,7 +69,7 @@ final class OptionalOrElseTest {
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(OptionalOrElse.class, getClass())
|
||||
BugCheckerRefactoringTestHelper.newInstance(OptionalOrElseGet.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import java.util.Optional;",
|
||||
@@ -1,26 +1,34 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class ClassRulesTest implements RefasterRuleCollectionTestCase {
|
||||
boolean testClassIsInstance() throws IOException {
|
||||
boolean testClassIsInstance() {
|
||||
return CharSequence.class.isAssignableFrom("foo".getClass());
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testInstanceof() throws IOException {
|
||||
ImmutableSet<Boolean> testInstanceof() {
|
||||
Class<?> clazz = CharSequence.class;
|
||||
return ImmutableSet.of(CharSequence.class.isInstance("foo"), clazz.isInstance("bar"));
|
||||
}
|
||||
|
||||
Predicate<String> testClassLiteralIsInstancePredicate() throws IOException {
|
||||
Predicate<String> testClassLiteralIsInstancePredicate() {
|
||||
return s -> s instanceof CharSequence;
|
||||
}
|
||||
|
||||
Predicate<String> testClassReferenceIsInstancePredicate() throws IOException {
|
||||
Predicate<String> testClassReferenceIsInstancePredicate() {
|
||||
Class<?> clazz = CharSequence.class;
|
||||
return s -> clazz.isInstance(s);
|
||||
}
|
||||
|
||||
Function<Number, Integer> testClassLiteralCast() {
|
||||
return i -> (Integer) i;
|
||||
}
|
||||
|
||||
Function<Number, Integer> testClassReferenceCast() {
|
||||
return i -> Integer.class.cast(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,34 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class ClassRulesTest implements RefasterRuleCollectionTestCase {
|
||||
boolean testClassIsInstance() throws IOException {
|
||||
boolean testClassIsInstance() {
|
||||
return CharSequence.class.isInstance("foo");
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testInstanceof() throws IOException {
|
||||
ImmutableSet<Boolean> testInstanceof() {
|
||||
Class<?> clazz = CharSequence.class;
|
||||
return ImmutableSet.of("foo" instanceof CharSequence, clazz.isInstance("bar"));
|
||||
}
|
||||
|
||||
Predicate<String> testClassLiteralIsInstancePredicate() throws IOException {
|
||||
Predicate<String> testClassLiteralIsInstancePredicate() {
|
||||
return CharSequence.class::isInstance;
|
||||
}
|
||||
|
||||
Predicate<String> testClassReferenceIsInstancePredicate() throws IOException {
|
||||
Predicate<String> testClassReferenceIsInstancePredicate() {
|
||||
Class<?> clazz = CharSequence.class;
|
||||
return clazz::isInstance;
|
||||
}
|
||||
|
||||
Function<Number, Integer> testClassLiteralCast() {
|
||||
return Integer.class::cast;
|
||||
}
|
||||
|
||||
Function<Number, Integer> testClassReferenceCast() {
|
||||
return Integer.class::cast;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,11 @@ import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Stream;
|
||||
@@ -70,6 +72,10 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
Stream<Integer> testSetStream() {
|
||||
return ImmutableSet.of(1).stream().distinct();
|
||||
}
|
||||
|
||||
ArrayList<String> testNewArrayListFromCollection() {
|
||||
return Lists.newArrayList(ImmutableList.of("foo"));
|
||||
}
|
||||
@@ -94,6 +100,10 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(1).asList().toString();
|
||||
}
|
||||
|
||||
List<String> testArraysAsList() {
|
||||
return Arrays.stream(new String[0]).toList();
|
||||
}
|
||||
|
||||
ImmutableSet<Object[]> testCollectionToArray() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableSet.of(1).toArray(new Object[1]),
|
||||
|
||||
@@ -6,9 +6,11 @@ import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Stream;
|
||||
@@ -62,6 +64,10 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
|
||||
new HashSet<Number>().removeAll(ImmutableSet.of(2));
|
||||
}
|
||||
|
||||
Stream<Integer> testSetStream() {
|
||||
return ImmutableSet.of(1).stream();
|
||||
}
|
||||
|
||||
ArrayList<String> testNewArrayListFromCollection() {
|
||||
return new ArrayList<>(ImmutableList.of("foo"));
|
||||
}
|
||||
@@ -86,6 +92,10 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(1).toString();
|
||||
}
|
||||
|
||||
List<String> testArraysAsList() {
|
||||
return Arrays.asList(new String[0]);
|
||||
}
|
||||
|
||||
ImmutableSet<Object[]> testCollectionToArray() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableSet.of(1).toArray(), ImmutableSet.of(2).toArray(), ImmutableSet.of(3).toArray());
|
||||
|
||||
@@ -107,6 +107,24 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Comparator.<String>reverseOrder().compare("baz", "qux"));
|
||||
}
|
||||
|
||||
void testCollectionsSort() {
|
||||
Collections.sort(ImmutableList.of("foo", "bar"), naturalOrder());
|
||||
}
|
||||
|
||||
ImmutableSet<String> testCollectionsMin() {
|
||||
return ImmutableSet.of(
|
||||
Collections.min(ImmutableList.of("foo"), naturalOrder()),
|
||||
Collections.max(ImmutableList.of("bar"), reverseOrder()));
|
||||
}
|
||||
|
||||
String testMinOfArray() {
|
||||
return Arrays.stream(new String[0]).min(naturalOrder()).orElseThrow();
|
||||
}
|
||||
|
||||
String testCollectionsMinWithComparator() {
|
||||
return ImmutableSet.of("foo", "bar").stream().min(naturalOrder()).orElseThrow();
|
||||
}
|
||||
|
||||
int testMinOfVarargs() {
|
||||
return Stream.of(1, 2).min(naturalOrder()).orElseThrow();
|
||||
}
|
||||
@@ -135,6 +153,20 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Collections.min(ImmutableSet.of("a", "b"), (a, b) -> 1));
|
||||
}
|
||||
|
||||
ImmutableSet<String> testCollectionsMax() {
|
||||
return ImmutableSet.of(
|
||||
Collections.max(ImmutableList.of("foo"), naturalOrder()),
|
||||
Collections.min(ImmutableList.of("bar"), reverseOrder()));
|
||||
}
|
||||
|
||||
String testMaxOfArray() {
|
||||
return Arrays.stream(new String[0]).max(naturalOrder()).orElseThrow();
|
||||
}
|
||||
|
||||
String testCollectionsMaxWithComparator() {
|
||||
return ImmutableSet.of("foo", "bar").stream().max(naturalOrder()).orElseThrow();
|
||||
}
|
||||
|
||||
int testMaxOfVarargs() {
|
||||
return Stream.of(1, 2).max(naturalOrder()).orElseThrow();
|
||||
}
|
||||
|
||||
@@ -98,6 +98,23 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of("foo".compareTo("bar"), "qux".compareTo("baz"));
|
||||
}
|
||||
|
||||
void testCollectionsSort() {
|
||||
Collections.sort(ImmutableList.of("foo", "bar"));
|
||||
}
|
||||
|
||||
ImmutableSet<String> testCollectionsMin() {
|
||||
return ImmutableSet.of(
|
||||
Collections.min(ImmutableList.of("foo")), Collections.min(ImmutableList.of("bar")));
|
||||
}
|
||||
|
||||
String testMinOfArray() {
|
||||
return Collections.min(Arrays.asList(new String[0]), naturalOrder());
|
||||
}
|
||||
|
||||
String testCollectionsMinWithComparator() {
|
||||
return Collections.min(ImmutableSet.of("foo", "bar"), naturalOrder());
|
||||
}
|
||||
|
||||
int testMinOfVarargs() {
|
||||
return Collections.min(Arrays.asList(1, 2), naturalOrder());
|
||||
}
|
||||
@@ -126,6 +143,19 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Comparators.min("a", "b", (a, b) -> 1));
|
||||
}
|
||||
|
||||
ImmutableSet<String> testCollectionsMax() {
|
||||
return ImmutableSet.of(
|
||||
Collections.max(ImmutableList.of("foo")), Collections.max(ImmutableList.of("bar")));
|
||||
}
|
||||
|
||||
String testMaxOfArray() {
|
||||
return Collections.max(Arrays.asList(new String[0]), naturalOrder());
|
||||
}
|
||||
|
||||
String testCollectionsMaxWithComparator() {
|
||||
return Collections.max(ImmutableSet.of("foo", "bar"), naturalOrder());
|
||||
}
|
||||
|
||||
int testMaxOfVarargs() {
|
||||
return Collections.max(Arrays.asList(1, 2), naturalOrder());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.util.function.Predicate.isEqual;
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import com.google.common.collect.BoundType;
|
||||
@@ -14,10 +15,10 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
final class EqualityRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(Objects.class, Optional.class, not(null));
|
||||
return ImmutableSet.of(Objects.class, Optional.class, isEqual(null), not(null));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testPrimitiveOrReferenceEquality() {
|
||||
ImmutableSet<Boolean> testEnumReferenceEquality() {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP.equals(RoundingMode.DOWN),
|
||||
Objects.equals(RoundingMode.UP, RoundingMode.DOWN),
|
||||
@@ -27,6 +28,10 @@ final class EqualityRulesTest implements RefasterRuleCollectionTestCase {
|
||||
RoundingMode.UP.ordinal() != RoundingMode.DOWN.ordinal());
|
||||
}
|
||||
|
||||
ImmutableSet<Predicate<RoundingMode>> testEnumReferenceEqualityLambda() {
|
||||
return ImmutableSet.of(isEqual(RoundingMode.DOWN), RoundingMode.UP::equals);
|
||||
}
|
||||
|
||||
boolean testEqualsPredicate() {
|
||||
// XXX: When boxing is involved this rule seems to break. Example:
|
||||
// Stream.of(1).anyMatch(e -> Integer.MIN_VALUE.equals(e));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.util.function.Predicate.isEqual;
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import com.google.common.collect.BoundType;
|
||||
@@ -14,10 +15,10 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
final class EqualityRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@Override
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(Objects.class, Optional.class, not(null));
|
||||
return ImmutableSet.of(Objects.class, Optional.class, isEqual(null), not(null));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testPrimitiveOrReferenceEquality() {
|
||||
ImmutableSet<Boolean> testEnumReferenceEquality() {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP == RoundingMode.DOWN,
|
||||
RoundingMode.UP == RoundingMode.DOWN,
|
||||
@@ -27,6 +28,10 @@ final class EqualityRulesTest implements RefasterRuleCollectionTestCase {
|
||||
RoundingMode.UP != RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
ImmutableSet<Predicate<RoundingMode>> testEnumReferenceEqualityLambda() {
|
||||
return ImmutableSet.of(v -> v == RoundingMode.DOWN, v -> v == RoundingMode.UP);
|
||||
}
|
||||
|
||||
boolean testEqualsPredicate() {
|
||||
// XXX: When boxing is involved this rule seems to break. Example:
|
||||
// Stream.of(1).anyMatch(e -> Integer.MIN_VALUE.equals(e));
|
||||
|
||||
@@ -1,12 +1,28 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class FileRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Path testPathOfUri() {
|
||||
return Paths.get(URI.create("foo"));
|
||||
}
|
||||
|
||||
ImmutableSet<Path> testPathOfString() {
|
||||
return ImmutableSet.of(Paths.get("foo"), Paths.get("bar", "baz", "qux"));
|
||||
}
|
||||
|
||||
Path testPathInstance() {
|
||||
return Path.of("foo").toFile().toPath();
|
||||
}
|
||||
|
||||
String testFilesReadStringWithCharset() throws IOException {
|
||||
return new String(Files.readAllBytes(Paths.get("foo")), StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
@@ -14,4 +30,13 @@ final class FileRulesTest implements RefasterRuleCollectionTestCase {
|
||||
String testFilesReadString() throws IOException {
|
||||
return Files.readString(Paths.get("foo"), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
ImmutableSet<File> testFilesCreateTempFileToFile() throws IOException {
|
||||
return ImmutableSet.of(
|
||||
File.createTempFile("foo", "bar"), File.createTempFile("baz", "qux", null));
|
||||
}
|
||||
|
||||
File testFilesCreateTempFileInCustomDirectoryToFile() throws IOException {
|
||||
return File.createTempFile("foo", "bar", new File("baz"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,28 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class FileRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Path testPathOfUri() {
|
||||
return Path.of(URI.create("foo"));
|
||||
}
|
||||
|
||||
ImmutableSet<Path> testPathOfString() {
|
||||
return ImmutableSet.of(Path.of("foo"), Path.of("bar", "baz", "qux"));
|
||||
}
|
||||
|
||||
Path testPathInstance() {
|
||||
return Path.of("foo");
|
||||
}
|
||||
|
||||
String testFilesReadStringWithCharset() throws IOException {
|
||||
return Files.readString(Paths.get("foo"), StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
@@ -14,4 +30,13 @@ final class FileRulesTest implements RefasterRuleCollectionTestCase {
|
||||
String testFilesReadString() throws IOException {
|
||||
return Files.readString(Paths.get("foo"));
|
||||
}
|
||||
|
||||
ImmutableSet<File> testFilesCreateTempFileToFile() throws IOException {
|
||||
return ImmutableSet.of(
|
||||
Files.createTempFile("foo", "bar").toFile(), Files.createTempFile("baz", "qux").toFile());
|
||||
}
|
||||
|
||||
File testFilesCreateTempFileInCustomDirectoryToFile() throws IOException {
|
||||
return Files.createTempFile(new File("baz").toPath(), "foo", "bar").toFile();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
(Runnable) () -> assertTrue(true));
|
||||
}
|
||||
|
||||
void testThrowNewAssertionError() {
|
||||
Assertions.fail();
|
||||
Object testFail() {
|
||||
return Assertions.fail();
|
||||
}
|
||||
|
||||
Object testFailWithMessage() {
|
||||
@@ -44,8 +44,8 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Assertions.fail("foo", new IllegalStateException());
|
||||
}
|
||||
|
||||
void testFailWithThrowable() {
|
||||
Assertions.fail(new IllegalStateException());
|
||||
Object testFailWithThrowable() {
|
||||
return Assertions.fail(new IllegalStateException());
|
||||
}
|
||||
|
||||
void testAssertThatIsTrue() {
|
||||
|
||||
@@ -35,8 +35,8 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
(Runnable) () -> assertTrue(true));
|
||||
}
|
||||
|
||||
void testThrowNewAssertionError() {
|
||||
throw new AssertionError();
|
||||
Object testFail() {
|
||||
return org.assertj.core.api.Assertions.fail();
|
||||
}
|
||||
|
||||
Object testFailWithMessage() {
|
||||
@@ -47,8 +47,8 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return org.assertj.core.api.Assertions.fail("foo", new IllegalStateException());
|
||||
}
|
||||
|
||||
void testFailWithThrowable() {
|
||||
throw new AssertionError(new IllegalStateException());
|
||||
Object testFailWithThrowable() {
|
||||
return org.assertj.core.api.Assertions.fail(new IllegalStateException());
|
||||
}
|
||||
|
||||
void testAssertThatIsTrue() {
|
||||
|
||||
@@ -83,11 +83,9 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Optional.of("foo").orElseGet(() -> Optional.of("bar").orElseThrow());
|
||||
}
|
||||
|
||||
ImmutableSet<String> testOptionalOrElseGet() {
|
||||
ImmutableSet<String> testOptionalOrElse() {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").orElse("bar"),
|
||||
Optional.of("baz").orElse(toString()),
|
||||
Optional.of("qux").orElse(String.valueOf(true)));
|
||||
Optional.of("foo").orElseGet(() -> "bar"), Optional.of("baz").orElseGet(() -> toString()));
|
||||
}
|
||||
|
||||
ImmutableSet<Object> testStreamFlatMapOptional() {
|
||||
|
||||
@@ -80,11 +80,9 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Optional.of("foo").or(() -> Optional.of("bar")).orElseThrow();
|
||||
}
|
||||
|
||||
ImmutableSet<String> testOptionalOrElseGet() {
|
||||
ImmutableSet<String> testOptionalOrElse() {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").orElse("bar"),
|
||||
Optional.of("baz").orElse(toString()),
|
||||
Optional.of("qux").orElseGet(() -> String.valueOf(true)));
|
||||
Optional.of("foo").orElse("bar"), Optional.of("baz").orElseGet(() -> toString()));
|
||||
}
|
||||
|
||||
ImmutableSet<Object> testStreamFlatMapOptional() {
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.google.common.primitives.Floats;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
import com.google.common.primitives.Shorts;
|
||||
import com.google.common.primitives.UnsignedInts;
|
||||
import com.google.common.primitives.UnsignedLongs;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@@ -22,7 +24,9 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Floats.class,
|
||||
Ints.class,
|
||||
Longs.class,
|
||||
Shorts.class);
|
||||
Shorts.class,
|
||||
UnsignedInts.class,
|
||||
UnsignedLongs.class);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testLessThan() {
|
||||
@@ -105,26 +109,6 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Doubles.hashCode(1);
|
||||
}
|
||||
|
||||
int testBooleanCompare() {
|
||||
return Booleans.compare(false, true);
|
||||
}
|
||||
|
||||
int testCharacterCompare() {
|
||||
return Chars.compare('a', 'b');
|
||||
}
|
||||
|
||||
int testShortCompare() {
|
||||
return Shorts.compare((short) 1, (short) 2);
|
||||
}
|
||||
|
||||
int testIntegerCompare() {
|
||||
return Ints.compare(1, 2);
|
||||
}
|
||||
|
||||
int testLongCompare() {
|
||||
return Longs.compare(1, 2);
|
||||
}
|
||||
|
||||
int testFloatCompare() {
|
||||
return Floats.compare(1, 2);
|
||||
}
|
||||
@@ -190,4 +174,60 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(
|
||||
Long.signum(1L) < 0, Long.signum(2L) <= -1, Long.signum(3L) >= 0, Long.signum(4L) > -1);
|
||||
}
|
||||
|
||||
int testIntegerCompareUnsigned() {
|
||||
return UnsignedInts.compare(1, 2);
|
||||
}
|
||||
|
||||
long testLongCompareUnsigned() {
|
||||
return UnsignedLongs.compare(1, 2);
|
||||
}
|
||||
|
||||
int testIntegerDivideUnsigned() {
|
||||
return UnsignedInts.divide(1, 2);
|
||||
}
|
||||
|
||||
long testLongDivideUnsigned() {
|
||||
return UnsignedLongs.divide(1, 2);
|
||||
}
|
||||
|
||||
int testIntegerRemainderUnsigned() {
|
||||
return UnsignedInts.remainder(1, 2);
|
||||
}
|
||||
|
||||
long testLongRemainderUnsigned() {
|
||||
return UnsignedLongs.remainder(1, 2);
|
||||
}
|
||||
|
||||
ImmutableSet<Integer> testIntegerParseUnsignedInt() {
|
||||
return ImmutableSet.of(UnsignedInts.parseUnsignedInt("1"), Integer.parseUnsignedInt("2", 10));
|
||||
}
|
||||
|
||||
ImmutableSet<Long> testLongParseUnsignedLong() {
|
||||
return ImmutableSet.of(UnsignedLongs.parseUnsignedLong("1"), Long.parseUnsignedLong("2", 10));
|
||||
}
|
||||
|
||||
int testIntegerParseUnsignedIntWithRadix() {
|
||||
return UnsignedInts.parseUnsignedInt("1", 2);
|
||||
}
|
||||
|
||||
long testLongParseUnsignedLongWithRadix() {
|
||||
return UnsignedLongs.parseUnsignedLong("1", 2);
|
||||
}
|
||||
|
||||
ImmutableSet<String> testIntegerToUnsignedString() {
|
||||
return ImmutableSet.of(UnsignedInts.toString(1), Integer.toUnsignedString(2, 10));
|
||||
}
|
||||
|
||||
ImmutableSet<String> testLongToUnsignedString() {
|
||||
return ImmutableSet.of(UnsignedLongs.toString(1), Long.toUnsignedString(2, 10));
|
||||
}
|
||||
|
||||
String testIntegerToUnsignedStringWithRadix() {
|
||||
return UnsignedInts.toString(1, 2);
|
||||
}
|
||||
|
||||
String testLongToUnsignedStringWithRadix() {
|
||||
return UnsignedLongs.toString(1, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.google.common.primitives.Floats;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
import com.google.common.primitives.Shorts;
|
||||
import com.google.common.primitives.UnsignedInts;
|
||||
import com.google.common.primitives.UnsignedLongs;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
@@ -22,7 +24,9 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Floats.class,
|
||||
Ints.class,
|
||||
Longs.class,
|
||||
Shorts.class);
|
||||
Shorts.class,
|
||||
UnsignedInts.class,
|
||||
UnsignedLongs.class);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testLessThan() {
|
||||
@@ -105,26 +109,6 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Double.hashCode(1);
|
||||
}
|
||||
|
||||
int testBooleanCompare() {
|
||||
return Boolean.compare(false, true);
|
||||
}
|
||||
|
||||
int testCharacterCompare() {
|
||||
return Character.compare('a', 'b');
|
||||
}
|
||||
|
||||
int testShortCompare() {
|
||||
return Short.compare((short) 1, (short) 2);
|
||||
}
|
||||
|
||||
int testIntegerCompare() {
|
||||
return Integer.compare(1, 2);
|
||||
}
|
||||
|
||||
int testLongCompare() {
|
||||
return Long.compare(1, 2);
|
||||
}
|
||||
|
||||
int testFloatCompare() {
|
||||
return Float.compare(1, 2);
|
||||
}
|
||||
@@ -190,4 +174,60 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(
|
||||
Long.signum(1L) == -1, Long.signum(2L) == -1, Long.signum(3L) != -1, Long.signum(4L) != -1);
|
||||
}
|
||||
|
||||
int testIntegerCompareUnsigned() {
|
||||
return Integer.compareUnsigned(1, 2);
|
||||
}
|
||||
|
||||
long testLongCompareUnsigned() {
|
||||
return Long.compareUnsigned(1, 2);
|
||||
}
|
||||
|
||||
int testIntegerDivideUnsigned() {
|
||||
return Integer.divideUnsigned(1, 2);
|
||||
}
|
||||
|
||||
long testLongDivideUnsigned() {
|
||||
return Long.divideUnsigned(1, 2);
|
||||
}
|
||||
|
||||
int testIntegerRemainderUnsigned() {
|
||||
return Integer.remainderUnsigned(1, 2);
|
||||
}
|
||||
|
||||
long testLongRemainderUnsigned() {
|
||||
return Long.remainderUnsigned(1, 2);
|
||||
}
|
||||
|
||||
ImmutableSet<Integer> testIntegerParseUnsignedInt() {
|
||||
return ImmutableSet.of(Integer.parseUnsignedInt("1"), Integer.parseUnsignedInt("2"));
|
||||
}
|
||||
|
||||
ImmutableSet<Long> testLongParseUnsignedLong() {
|
||||
return ImmutableSet.of(Long.parseUnsignedLong("1"), Long.parseUnsignedLong("2"));
|
||||
}
|
||||
|
||||
int testIntegerParseUnsignedIntWithRadix() {
|
||||
return Integer.parseUnsignedInt("1", 2);
|
||||
}
|
||||
|
||||
long testLongParseUnsignedLongWithRadix() {
|
||||
return Long.parseUnsignedLong("1", 2);
|
||||
}
|
||||
|
||||
ImmutableSet<String> testIntegerToUnsignedString() {
|
||||
return ImmutableSet.of(Integer.toUnsignedString(1), Integer.toUnsignedString(2));
|
||||
}
|
||||
|
||||
ImmutableSet<String> testLongToUnsignedString() {
|
||||
return ImmutableSet.of(Long.toUnsignedString(1), Long.toUnsignedString(2));
|
||||
}
|
||||
|
||||
String testIntegerToUnsignedStringWithRadix() {
|
||||
return Integer.toUnsignedString(1, 2);
|
||||
}
|
||||
|
||||
String testLongToUnsignedStringWithRadix() {
|
||||
return Long.toUnsignedString(1, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import static java.util.stream.Collectors.minBy;
|
||||
import static java.util.stream.Collectors.toCollection;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@@ -21,7 +22,9 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.math.MathFlux;
|
||||
@@ -182,8 +185,8 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Flux.range(0, 0));
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxJust() {
|
||||
return Flux.range(0, 1);
|
||||
ImmutableSet<Flux<Integer>> testFluxJust() {
|
||||
return ImmutableSet.of(Flux.range(0, 1), Mono.just(2).repeat().take(1));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<?>> testMonoIdentity() {
|
||||
@@ -207,11 +210,12 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMap() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).flatMap(Mono::just, 1),
|
||||
Flux.just(2).flatMapSequential(Mono::just, 1),
|
||||
Flux.just(3).map(Mono::just).concatMap(identity()),
|
||||
Flux.just(4).map(Mono::just).concatMap(v -> v),
|
||||
Flux.just(5).map(Mono::just).concatMap(v -> Mono.empty()));
|
||||
Flux.just(1).concatMap(Mono::just, 0),
|
||||
Flux.just(2).flatMap(Mono::just, 1),
|
||||
Flux.just(3).flatMapSequential(Mono::just, 1),
|
||||
Flux.just(4).map(Mono::just).concatMap(identity()),
|
||||
Flux.just(5).map(Mono::just).concatMap(v -> v),
|
||||
Flux.just(6).map(Mono::just).concatMap(v -> Mono.empty()));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMapWithPrefetch() {
|
||||
@@ -432,8 +436,10 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Flux.just(ImmutableList.of("bar")).concatMap(Flux::fromIterable, 2));
|
||||
}
|
||||
|
||||
Flux<String> testFluxFromIterable() {
|
||||
return Flux.fromStream(ImmutableList.of("foo").stream());
|
||||
ImmutableSet<Flux<String>> testFluxFromIterable() {
|
||||
return ImmutableSet.of(
|
||||
Flux.fromStream(ImmutableList.of("foo")::stream),
|
||||
Flux.fromStream(() -> ImmutableList.of("bar").stream()));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<Integer>> testFluxCountMapMathToIntExact() {
|
||||
@@ -650,4 +656,20 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Duration testStepVerifierLastStepVerifyTimeout() {
|
||||
return Mono.empty().as(StepVerifier::create).expectTimeout(Duration.ZERO).verify();
|
||||
}
|
||||
|
||||
Mono<Void> testMonoFromFutureSupplier() {
|
||||
return Mono.fromFuture(CompletableFuture.completedFuture(null));
|
||||
}
|
||||
|
||||
Mono<Void> testMonoFromFutureSupplierBoolean() {
|
||||
return Mono.fromFuture(CompletableFuture.completedFuture(null), true);
|
||||
}
|
||||
|
||||
Mono<String> testMonoFromFutureAsyncLoadingCacheGet() {
|
||||
return Mono.fromFuture(() -> ((AsyncLoadingCache<Integer, String>) null).get(0));
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxFromStreamSupplier() {
|
||||
return Flux.fromStream(Stream.of(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import static java.util.stream.Collectors.toCollection;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static reactor.function.TupleUtils.function;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@@ -23,7 +24,9 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.function.TupleUtils;
|
||||
@@ -186,8 +189,8 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Flux.empty());
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxJust() {
|
||||
return Flux.just(0);
|
||||
ImmutableSet<Flux<Integer>> testFluxJust() {
|
||||
return ImmutableSet.of(Flux.just(0), Flux.just(2));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<?>> testMonoIdentity() {
|
||||
@@ -214,7 +217,8 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Flux.just(2).concatMap(Mono::just),
|
||||
Flux.just(3).concatMap(Mono::just),
|
||||
Flux.just(4).concatMap(Mono::just),
|
||||
Flux.just(5).map(Mono::just).concatMap(v -> Mono.empty()));
|
||||
Flux.just(5).concatMap(Mono::just),
|
||||
Flux.just(6).map(Mono::just).concatMap(v -> Mono.empty()));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxConcatMapWithPrefetch() {
|
||||
@@ -427,8 +431,9 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Flux.just(ImmutableList.of("bar")).concatMapIterable(identity(), 2));
|
||||
}
|
||||
|
||||
Flux<String> testFluxFromIterable() {
|
||||
return Flux.fromIterable(ImmutableList.of("foo"));
|
||||
ImmutableSet<Flux<String>> testFluxFromIterable() {
|
||||
return ImmutableSet.of(
|
||||
Flux.fromIterable(ImmutableList.of("foo")), Flux.fromIterable(ImmutableList.of("bar")));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<Integer>> testFluxCountMapMathToIntExact() {
|
||||
@@ -631,4 +636,20 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Duration testStepVerifierLastStepVerifyTimeout() {
|
||||
return Mono.empty().as(StepVerifier::create).verifyTimeout(Duration.ZERO);
|
||||
}
|
||||
|
||||
Mono<Void> testMonoFromFutureSupplier() {
|
||||
return Mono.fromFuture(() -> CompletableFuture.completedFuture(null));
|
||||
}
|
||||
|
||||
Mono<Void> testMonoFromFutureSupplierBoolean() {
|
||||
return Mono.fromFuture(() -> CompletableFuture.completedFuture(null), true);
|
||||
}
|
||||
|
||||
Mono<String> testMonoFromFutureAsyncLoadingCacheGet() {
|
||||
return Mono.fromFuture(() -> ((AsyncLoadingCache<Integer, String>) null).get(0), true);
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxFromStreamSupplier() {
|
||||
return Flux.fromStream(() -> Stream.of(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,4 +96,8 @@ final class StringRulesTest implements RefasterRuleCollectionTestCase {
|
||||
int testUtf8EncodedLength() {
|
||||
return "foo".getBytes(UTF_8).length;
|
||||
}
|
||||
|
||||
String testNewStringChar() {
|
||||
return String.copyValueOf(new char[] {'f', 'o', 'o'});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,4 +96,8 @@ final class StringRulesTest implements RefasterRuleCollectionTestCase {
|
||||
int testUtf8EncodedLength() {
|
||||
return Utf8.encodedLength("foo");
|
||||
}
|
||||
|
||||
String testNewStringChar() {
|
||||
return new String(new char[] {'f', 'o', 'o'});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ final class TestNGToAssertJRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
|
||||
void testFail() {
|
||||
throw new AssertionError();
|
||||
fail();
|
||||
}
|
||||
|
||||
void testFailWithMessage() {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
<version>0.18.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-experimental</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
<version>0.18.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-guidelines</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
<version>0.18.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-utils</artifactId>
|
||||
|
||||
@@ -2,205 +2,35 @@
|
||||
|
||||
set -e -u -o pipefail
|
||||
|
||||
integration_test_root="$(cd "$(dirname -- "${0}")" && pwd)"
|
||||
error_prone_support_root="${integration_test_root}/.."
|
||||
repos_root="${integration_test_root}/.repos"
|
||||
|
||||
test_name="$(basename "${0}" .sh)"
|
||||
project=checkstyle
|
||||
repository=https://github.com/checkstyle/checkstyle.git
|
||||
revision=checkstyle-10.14.0
|
||||
|
||||
if [ "${#}" -gt 2 ] || ([ "${#}" = 2 ] && [ "${1:---sync}" != '--sync' ]); then
|
||||
echo "Usage: ${0} [--sync] [<report_directory>]"
|
||||
exit 1
|
||||
fi
|
||||
do_sync="$([ "${#}" = 0 ] || [ "${1:-}" != '--sync' ] || echo 1)"
|
||||
report_directory="$([ "${#}" = 0 ] || ([ -z "${do_sync}" ] && echo "${1}") || ([ "${#}" = 1 ] || echo "${2}"))"
|
||||
|
||||
if [ -n "${report_directory}" ]; then
|
||||
mkdir -p "${report_directory}"
|
||||
else
|
||||
report_directory="$(mktemp -d)"
|
||||
trap 'rm -rf -- "${report_directory}"' INT TERM HUP EXIT
|
||||
fi
|
||||
|
||||
case "$(uname -s)" in
|
||||
Linux*)
|
||||
grep_command=grep
|
||||
sed_command=sed
|
||||
;;
|
||||
Darwin*)
|
||||
grep_command=ggrep
|
||||
sed_command=gsed
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported distribution $(uname -s) for this script."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
project='checkstyle'
|
||||
repository='https://github.com/checkstyle/checkstyle.git'
|
||||
revision='checkstyle-10.14.0'
|
||||
# XXX: Configure Renovate to manage the AssertJ version declared here.
|
||||
shared_build_flags="
|
||||
-Perror-prone-compile,error-prone-test-compile
|
||||
-Dassertj.version=3.24.2
|
||||
-Derror-prone.version=$(
|
||||
mvn -f "${error_prone_support_root}" help:evaluate -Dexpression=version.error-prone -q -DforceStdout
|
||||
)
|
||||
-Derror-prone-support.version=$(
|
||||
mvn -f "${error_prone_support_root}" help:evaluate -Dexpression=project.version -q -DforceStdout
|
||||
)
|
||||
-DadditionalSourceDirectories=\${project.basedir}\${file.separator}src\${file.separator}it\${file.separator}java,\${project.basedir}\${file.separator}src\${file.separator}xdocs-examples\${file.separator}java
|
||||
"
|
||||
|
||||
# XXX: Configure Renovate to manage the fmt-maven-plugin version declared here.
|
||||
# XXX: Once GitHub actions uses Maven 3.9.2+, we can inline this variable with
|
||||
# version reference `${fmt.version}`, and `-Dfmt.version=2.21.1` added to
|
||||
# `shared_build_flags`.
|
||||
format_goal='com.spotify.fmt:fmt-maven-plugin:2.21.1:format'
|
||||
|
||||
error_prone_shared_flags='-XepExcludedPaths:(\Q${project.basedir}${file.separator}src${file.separator}\E(it|test|xdocs-examples)\Q${file.separator}resources\E|\Q${project.build.directory}${file.separator}\E).*'
|
||||
|
||||
error_prone_patch_flags="${error_prone_shared_flags} -XepPatchLocation:IN_PLACE -XepPatchChecks:$(
|
||||
find "${error_prone_support_root}" \
|
||||
-path "*/META-INF/services/com.google.errorprone.bugpatterns.BugChecker" \
|
||||
-not -path "*/error-prone-experimental/*" \
|
||||
-not -path "*/error-prone-guidelines/*" \
|
||||
-print0 \
|
||||
| xargs -0 "${grep_command}" -hoP '[^.]+$' \
|
||||
| paste -s -d ',' -
|
||||
)"
|
||||
|
||||
error_prone_validation_flags="${error_prone_shared_flags} -XepDisableAllChecks $(
|
||||
find "${error_prone_support_root}" \
|
||||
-path "*/META-INF/services/com.google.errorprone.bugpatterns.BugChecker" \
|
||||
-not -path "*/error-prone-experimental/*" \
|
||||
-not -path "*/error-prone-guidelines/*" \
|
||||
-print0 \
|
||||
| xargs -0 "${grep_command}" -hoP '[^.]+$' \
|
||||
| "${sed_command}" -r 's,(.*),-Xep:\1:WARN,' \
|
||||
| paste -s -d ' ' -
|
||||
)"
|
||||
|
||||
echo "Shared build flags: ${shared_build_flags}"
|
||||
echo "Error Prone patch flags: ${error_prone_patch_flags}"
|
||||
echo "Error Prone validation flags: ${error_prone_validation_flags}"
|
||||
|
||||
mkdir -p "${repos_root}"
|
||||
|
||||
# Make sure that the targeted tag of the project's Git repository is checked
|
||||
# out.
|
||||
project_root="${repos_root}/${project}"
|
||||
if [ ! -d "${project_root}" ]; then
|
||||
# The repository has not yet been cloned; create a shallow clone.
|
||||
git clone --branch "${revision}" --depth 1 "${repository}" "${project_root}"
|
||||
else
|
||||
# The repository does already appear to exist. Try to check out the requested
|
||||
# tag if possible, and fetch it otherwise.
|
||||
#
|
||||
# Under certain circumstances this does not cause the relevant tag to be
|
||||
# created, so if necessary we manually create it.
|
||||
git -C "${project_root}" checkout --force "${revision}" 2>/dev/null \
|
||||
|| (
|
||||
git -C "${project_root}" fetch --depth 1 "${repository}" "${revision}" \
|
||||
&& git -C "${project_root}" checkout --force FETCH_HEAD \
|
||||
&& (git -C "${project_root}" tag "${revision}" || true)
|
||||
)
|
||||
fi
|
||||
|
||||
pushd "${project_root}"
|
||||
|
||||
# Make sure that Git is sufficiently configured to enable committing to the
|
||||
# project's Git repository.
|
||||
git config user.email || git config user.email "integration-test@example.com"
|
||||
git config user.name || git config user.name "Integration Test"
|
||||
|
||||
# Prepare the code for analysis by (a) applying the minimal set of changes
|
||||
# required to run Error Prone with Error Prone Support and (b) formatting the
|
||||
# code using the same method by which it will be formatted after each
|
||||
# compilation round. The initial formatting operation ensures that subsequent
|
||||
# modifications can be rendered in a clean manner.
|
||||
git clean -fdx
|
||||
git apply < "${integration_test_root}/${test_name}-init.patch"
|
||||
git commit -m 'dependency: Introduce Error Prone Support' .
|
||||
mvn ${shared_build_flags} "${format_goal}"
|
||||
git commit -m 'minor: Reformat using Google Java Format' .
|
||||
diff_base="$(git rev-parse HEAD)"
|
||||
|
||||
# Apply Error Prone Support-suggested changes until a fixed point is reached.
|
||||
function apply_patch() {
|
||||
local extra_build_args="${1}"
|
||||
|
||||
mvn ${shared_build_flags} ${extra_build_args} \
|
||||
package "${format_goal}" \
|
||||
-Derror-prone.configuration-args="${error_prone_patch_flags}" \
|
||||
-DskipTests
|
||||
|
||||
if ! git diff --exit-code; then
|
||||
git commit -m 'minor: Apply patches' .
|
||||
|
||||
# Changes were applied, so another compilation round may apply yet more
|
||||
# changes. For performance reasons we perform incremental compilation,
|
||||
# enabled using a misleading flag. (See
|
||||
# https://issues.apache.org/jira/browse/MCOMPILER-209 for details.)
|
||||
apply_patch '-Dmaven.compiler.useIncrementalCompilation=false'
|
||||
elif [ "${extra_build_args}" != 'clean' ]; then
|
||||
# No changes were applied. We'll attempt one more round in which all files
|
||||
# are recompiled, because there are cases in which violations are missed
|
||||
# during incremental compilation.
|
||||
apply_patch 'clean'
|
||||
fi
|
||||
}
|
||||
apply_patch ''
|
||||
|
||||
# Run one more full build and log the output.
|
||||
#
|
||||
# By also running the tests, we validate that the (majority of) applied changes
|
||||
# are behavior preserving. Some tests are skipped:
|
||||
additional_build_flags='-Dassertj.version=3.24.2'
|
||||
additional_source_directories='${project.basedir}${file.separator}src${file.separator}it${file.separator}java,${project.basedir}${file.separator}src${file.separator}xdocs-examples${file.separator}java'
|
||||
patch_error_prone_flags=''
|
||||
validation_error_prone_flags=''
|
||||
# Validation skips some tests:
|
||||
# - The `metadataFilesGenerationAllFiles` test is skipped because it makes line
|
||||
# number assertions that will fail when the code is formatted or patched.
|
||||
# - The `allCheckSectionJavaDocs` test is skipped because is validates that
|
||||
# - The `allCheckSectionJavaDocs` test is skipped because it validates that
|
||||
# Javadoc has certain closing tags that are removed by Google Java Format.
|
||||
validation_build_log="${report_directory}/${test_name}-validation-build-log.txt"
|
||||
mvn ${shared_build_flags} \
|
||||
clean package \
|
||||
-Derror-prone.configuration-args="${error_prone_validation_flags}" \
|
||||
-Dtest='
|
||||
!MetadataGeneratorUtilTest#metadataFilesGenerationAllFiles,
|
||||
!XdocsJavaDocsTest#allCheckSectionJavaDocs' \
|
||||
| tee "${validation_build_log}" \
|
||||
|| failure=1
|
||||
validation_build_flags='-Dtest=!MetadataGeneratorUtilTest#metadataFilesGenerationAllFiles,!XdocsJavaDocsTest#allCheckSectionJavaDocs'
|
||||
|
||||
# Collect the applied changes.
|
||||
expected_changes="${integration_test_root}/${test_name}-expected-changes.patch"
|
||||
actual_changes="${report_directory}/${test_name}-changes.patch"
|
||||
(git diff "${diff_base}"..HEAD | "${grep_command}" -vP '^(diff|index)' || true) > "${actual_changes}"
|
||||
|
||||
# Collect the warnings reported by Error Prone Support checks.
|
||||
expected_warnings="${integration_test_root}/${test_name}-expected-warnings.txt"
|
||||
actual_warnings="${report_directory}/${test_name}-validation-build-warnings.txt"
|
||||
("${grep_command}" -oP "(?<=^\\Q[WARNING] ${PWD}/\\E).*" "${validation_build_log}" | "${grep_command}" -P '\] \[' || true) | LC_ALL=C sort > "${actual_warnings}"
|
||||
|
||||
# Persist or validate the applied changes and reported warnings.
|
||||
if [ -n "${do_sync}" ]; then
|
||||
echo 'Saving changes...'
|
||||
cp "${actual_changes}" "${expected_changes}"
|
||||
cp "${actual_warnings}" "${expected_warnings}"
|
||||
else
|
||||
echo 'Inspecting changes...'
|
||||
# XXX: This "diff of diffs" also contains vacuous sections, introduced due to
|
||||
# line offset differences. Try to omit those from the final output.
|
||||
if ! diff -u "${expected_changes}" "${actual_changes}"; then
|
||||
echo 'There are unexpected changes. Inspect the preceding output for details.'
|
||||
failure=1
|
||||
fi
|
||||
echo 'Inspecting emitted warnings...'
|
||||
if ! diff -u "${expected_warnings}" "${actual_warnings}"; then
|
||||
echo 'Diagnostics output changed. Inspect the preceding output for details.'
|
||||
failure=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "${failure:-}" ]; then
|
||||
if [ "${#}" -gt 2 ] || ([ "${#}" = 2 ] && [ "${1:---sync}" != '--sync' ]); then
|
||||
>&2 echo "Usage: ${0} [--sync] [<report_directory>]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"$(dirname "${0}")/run-integration-test.sh" \
|
||||
"${test_name}" \
|
||||
"${project}" \
|
||||
"${repository}" \
|
||||
"${revision}" \
|
||||
"${additional_build_flags}" \
|
||||
"${additional_source_directories}" \
|
||||
"${patch_error_prone_flags}" \
|
||||
"${validation_error_prone_flags}" \
|
||||
"${validation_build_flags}" \
|
||||
$@
|
||||
|
||||
210
integration-tests/run-integration-test.sh
Executable file
210
integration-tests/run-integration-test.sh
Executable file
@@ -0,0 +1,210 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Integration test framework for Maven builds.
|
||||
#
|
||||
# This script is not meant to be invoked manually. Instead it should be invoked
|
||||
# through one of the top-level integration test scripts, such as
|
||||
# `checkstyle.sh`.
|
||||
|
||||
set -e -u -o pipefail
|
||||
|
||||
integration_test_root="$(cd "$(dirname -- "${0}")" && pwd)"
|
||||
error_prone_support_root="${integration_test_root}/.."
|
||||
repos_root="${integration_test_root}/.repos"
|
||||
|
||||
if [ "${#}" -lt 9 ] || [ "${#}" -gt 11 ] || ([ "${#}" = 11 ] && [ "${10:---sync}" != '--sync' ]); then
|
||||
>&2 echo "Usage: $(basename "${0}") <test_name> <project> <repository> <revision> <additional_build_flags> <additional_source_directories> <patch_error_prone_flags> <validation_error_prone_flags> <validation_build_flags> [--sync] [<report_directory>]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test_name="${1}"
|
||||
project="${2}"
|
||||
repository="${3}"
|
||||
revision="${4}"
|
||||
additional_build_flags="${5}"
|
||||
additional_source_directories="${6}"
|
||||
patch_error_prone_flags="${7}"
|
||||
validation_error_prone_flags="${8}"
|
||||
validation_build_flags="${9}"
|
||||
do_sync="$([ "${#}" = 9 ] || [ "${10:-}" != '--sync' ] || echo 1)"
|
||||
report_directory="$([ "${#}" = 9 ] || ([ -z "${do_sync}" ] && echo "${10}") || ([ "${#}" = 10 ] || echo "${11}"))"
|
||||
|
||||
if [ -n "${report_directory}" ]; then
|
||||
mkdir -p "${report_directory}"
|
||||
else
|
||||
report_directory="$(mktemp -d)"
|
||||
trap 'rm -rf -- "${report_directory}"' INT TERM HUP EXIT
|
||||
fi
|
||||
|
||||
case "$(uname -s)" in
|
||||
Linux*)
|
||||
grep_command=grep
|
||||
sed_command=sed
|
||||
;;
|
||||
Darwin*)
|
||||
grep_command=ggrep
|
||||
sed_command=gsed
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported distribution $(uname -s) for this script."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
shared_build_flags="
|
||||
-Perror-prone-compile,error-prone-test-compile
|
||||
-Derror-prone.version=$(
|
||||
mvn -f "${error_prone_support_root}" help:evaluate -Dexpression=version.error-prone -q -DforceStdout
|
||||
)
|
||||
-Derror-prone-support.version=$(
|
||||
mvn -f "${error_prone_support_root}" help:evaluate -Dexpression=project.version -q -DforceStdout
|
||||
)
|
||||
-DadditionalSourceDirectories=${additional_source_directories}
|
||||
${additional_build_flags}
|
||||
"
|
||||
|
||||
# XXX: Configure Renovate to manage the fmt-maven-plugin version declared here.
|
||||
# XXX: Once GitHub actions uses Maven 3.9.2+, we can inline this variable with
|
||||
# version reference `${fmt.version}`, and `-Dfmt.version=2.21.1` added to
|
||||
# `shared_build_flags`.
|
||||
format_goal='com.spotify.fmt:fmt-maven-plugin:2.21.1:format'
|
||||
|
||||
error_prone_shared_flags='-XepExcludedPaths:(\Q${project.basedir}${file.separator}src${file.separator}\E(it|test|xdocs-examples)\Q${file.separator}resources\E|\Q${project.build.directory}${file.separator}\E).*'
|
||||
|
||||
error_prone_patch_flags="${error_prone_shared_flags} -XepPatchLocation:IN_PLACE -XepPatchChecks:$(
|
||||
find "${error_prone_support_root}" \
|
||||
-path "*/META-INF/services/com.google.errorprone.bugpatterns.BugChecker" \
|
||||
-not -path "*/error-prone-experimental/*" \
|
||||
-not -path "*/error-prone-guidelines/*" \
|
||||
-print0 \
|
||||
| xargs -0 "${grep_command}" -hoP '[^.]+$' \
|
||||
| paste -s -d ',' -
|
||||
) ${patch_error_prone_flags}"
|
||||
|
||||
error_prone_validation_flags="${error_prone_shared_flags} -XepDisableAllChecks $(
|
||||
find "${error_prone_support_root}" \
|
||||
-path "*/META-INF/services/com.google.errorprone.bugpatterns.BugChecker" \
|
||||
-not -path "*/error-prone-experimental/*" \
|
||||
-not -path "*/error-prone-guidelines/*" \
|
||||
-print0 \
|
||||
| xargs -0 "${grep_command}" -hoP '[^.]+$' \
|
||||
| "${sed_command}" -r 's,(.*),-Xep:\1:WARN,' \
|
||||
| paste -s -d ' ' -
|
||||
) ${validation_error_prone_flags}"
|
||||
|
||||
echo "Shared build flags: ${shared_build_flags}"
|
||||
echo "Error Prone patch flags: ${error_prone_patch_flags}"
|
||||
echo "Error Prone validation flags: ${error_prone_validation_flags}"
|
||||
|
||||
mkdir -p "${repos_root}"
|
||||
|
||||
# Make sure that the targeted tag of the project's Git repository is checked
|
||||
# out.
|
||||
project_root="${repos_root}/${project}"
|
||||
if [ ! -d "${project_root}" ]; then
|
||||
# The repository has not yet been cloned; create a shallow clone.
|
||||
git clone --branch "${revision}" --depth 1 "${repository}" "${project_root}"
|
||||
else
|
||||
# The repository does already appear to exist. Try to check out the requested
|
||||
# tag if possible, and fetch it otherwise.
|
||||
#
|
||||
# Under certain circumstances this does not cause the relevant tag to be
|
||||
# created, so if necessary we manually create it.
|
||||
git -C "${project_root}" checkout --force "${revision}" 2>/dev/null \
|
||||
|| (
|
||||
git -C "${project_root}" fetch --depth 1 "${repository}" "${revision}" \
|
||||
&& git -C "${project_root}" checkout --force FETCH_HEAD \
|
||||
&& (git -C "${project_root}" tag "${revision}" || true)
|
||||
)
|
||||
fi
|
||||
|
||||
pushd "${project_root}"
|
||||
|
||||
# Make sure that Git is sufficiently configured to enable committing to the
|
||||
# project's Git repository.
|
||||
git config user.email || git config user.email 'integration-test@example.com'
|
||||
git config user.name || git config user.name 'Integration Test'
|
||||
|
||||
# Prepare the code for analysis by (a) applying the minimal set of changes
|
||||
# required to run Error Prone with Error Prone Support and (b) formatting the
|
||||
# code using the same method by which it will be formatted after each
|
||||
# compilation round. The initial formatting operation ensures that subsequent
|
||||
# modifications can be rendered in a clean manner.
|
||||
git clean -fdx
|
||||
git apply < "${integration_test_root}/${test_name}-init.patch"
|
||||
git commit -m 'dependency: Introduce Error Prone Support' .
|
||||
mvn ${shared_build_flags} "${format_goal}"
|
||||
git commit -m 'minor: Reformat using Google Java Format' .
|
||||
diff_base="$(git rev-parse HEAD)"
|
||||
|
||||
# Apply Error Prone Support-suggested changes until a fixed point is reached.
|
||||
function apply_patch() {
|
||||
local extra_build_args="${1}"
|
||||
|
||||
mvn ${shared_build_flags} ${extra_build_args} \
|
||||
package "${format_goal}" \
|
||||
-Derror-prone.configuration-args="${error_prone_patch_flags}" \
|
||||
-DskipTests
|
||||
|
||||
if ! git diff --exit-code; then
|
||||
git commit -m 'minor: Apply patches' .
|
||||
|
||||
# Changes were applied, so another compilation round may apply yet more
|
||||
# changes. For performance reasons we perform incremental compilation,
|
||||
# enabled using a misleading flag. (See
|
||||
# https://issues.apache.org/jira/browse/MCOMPILER-209 for details.)
|
||||
apply_patch '-Dmaven.compiler.useIncrementalCompilation=false'
|
||||
elif [ "${extra_build_args}" != 'clean' ]; then
|
||||
# No changes were applied. We'll attempt one more round in which all files
|
||||
# are recompiled, because there are cases in which violations are missed
|
||||
# during incremental compilation.
|
||||
apply_patch 'clean'
|
||||
fi
|
||||
}
|
||||
apply_patch ''
|
||||
|
||||
# Run one more full build and log the output.
|
||||
#
|
||||
# By also running the tests, we validate that the (majority of) applied changes
|
||||
# are behavior preserving.
|
||||
validation_build_log="${report_directory}/${test_name}-validation-build-log.txt"
|
||||
mvn ${shared_build_flags} \
|
||||
clean package \
|
||||
-Derror-prone.configuration-args="${error_prone_validation_flags}" \
|
||||
${validation_build_flags} \
|
||||
| tee "${validation_build_log}" \
|
||||
|| failure=1
|
||||
|
||||
# Collect the applied changes.
|
||||
expected_changes="${integration_test_root}/${test_name}-expected-changes.patch"
|
||||
actual_changes="${report_directory}/${test_name}-changes.patch"
|
||||
(git diff "${diff_base}"..HEAD | "${grep_command}" -vP '^(diff|index)' || true) > "${actual_changes}"
|
||||
|
||||
# Collect the warnings reported by Error Prone Support checks.
|
||||
expected_warnings="${integration_test_root}/${test_name}-expected-warnings.txt"
|
||||
actual_warnings="${report_directory}/${test_name}-validation-build-warnings.txt"
|
||||
("${grep_command}" -oP "(?<=^\\Q[WARNING] ${PWD}/\\E).*" "${validation_build_log}" | "${grep_command}" -P '\] \[' || true) | LC_ALL=C sort > "${actual_warnings}"
|
||||
|
||||
# Persist or validate the applied changes and reported warnings.
|
||||
if [ -n "${do_sync}" ]; then
|
||||
echo 'Saving changes...'
|
||||
cp "${actual_changes}" "${expected_changes}"
|
||||
cp "${actual_warnings}" "${expected_warnings}"
|
||||
else
|
||||
echo 'Inspecting changes...'
|
||||
# XXX: This "diff of diffs" also contains vacuous sections, introduced due to
|
||||
# line offset differences. Try to omit those from the final output.
|
||||
if ! diff -u "${expected_changes}" "${actual_changes}"; then
|
||||
echo 'There are unexpected changes. Inspect the preceding output for details.'
|
||||
failure=1
|
||||
fi
|
||||
echo 'Inspecting emitted warnings...'
|
||||
if ! diff -u "${expected_warnings}" "${actual_warnings}"; then
|
||||
echo 'Diagnostics output changed. Inspect the preceding output for details.'
|
||||
failure=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "${failure:-}" ]; then
|
||||
exit 1
|
||||
fi
|
||||
174
pom.xml
174
pom.xml
@@ -4,7 +4,7 @@
|
||||
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
<version>0.18.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Picnic :: Error Prone Support</name>
|
||||
@@ -148,7 +148,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>2024-03-15T12:04:44Z</project.build.outputTimestamp>
|
||||
<project.build.outputTimestamp>2024-08-11T13:05:54Z</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
|
||||
@@ -205,19 +205,19 @@
|
||||
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.4</version.auto-value>
|
||||
<version.auto-value>1.11.0</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.27.1</version.error-prone-orig>
|
||||
<version.error-prone-slf4j>0.1.24</version.error-prone-slf4j>
|
||||
<version.error-prone-orig>2.31.0</version.error-prone-orig>
|
||||
<version.error-prone-slf4j>0.1.25</version.error-prone-slf4j>
|
||||
<version.guava-beta-checker>1.0</version.guava-beta-checker>
|
||||
<version.jdk>17</version.jdk>
|
||||
<version.maven>3.9.5</version.maven>
|
||||
<version.mockito>5.11.0</version.mockito>
|
||||
<version.maven>3.9.9</version.maven>
|
||||
<version.mockito>5.13.0</version.mockito>
|
||||
<version.nopen-checker>1.0.1</version.nopen-checker>
|
||||
<version.nullaway>0.10.26</version.nullaway>
|
||||
<version.nullaway>0.11.2</version.nullaway>
|
||||
<version.pitest-git>1.1.4</version.pitest-git>
|
||||
<version.rewrite-templating>1.8.1</version.rewrite-templating>
|
||||
<version.rewrite-templating>1.14.0</version.rewrite-templating>
|
||||
<version.surefire>3.2.3</version.surefire>
|
||||
</properties>
|
||||
|
||||
@@ -296,10 +296,15 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson</groupId>
|
||||
<artifactId>jackson-bom</artifactId>
|
||||
<version>2.17.1</version>
|
||||
<version>2.17.2</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<version>3.1.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto</groupId>
|
||||
<artifactId>auto-common</artifactId>
|
||||
@@ -328,7 +333,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.googlejavaformat</groupId>
|
||||
<artifactId>google-java-format</artifactId>
|
||||
<version>1.22.0</version>
|
||||
<version>1.23.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
@@ -338,14 +343,14 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava-bom</artifactId>
|
||||
<version>33.2.0-jre</version>
|
||||
<version>33.3.0-jre</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.truth</groupId>
|
||||
<artifactId>truth</artifactId>
|
||||
<version>1.4.2</version>
|
||||
<version>1.4.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jakewharton.nopen</groupId>
|
||||
@@ -360,7 +365,7 @@
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-bom</artifactId>
|
||||
<version>2023.0.5</version>
|
||||
<version>2023.0.9</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -377,12 +382,17 @@
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>2.2.21</version>
|
||||
<version>2.2.23</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
<version>1.3.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
@@ -407,7 +417,7 @@
|
||||
<dependency>
|
||||
<groupId>net.bytebuddy</groupId>
|
||||
<artifactId>byte-buddy</artifactId>
|
||||
<version>1.14.14</version>
|
||||
<version>1.15.1</version>
|
||||
</dependency>
|
||||
<!-- Specified so that Renovate will file Maven upgrade PRs, which
|
||||
subsequently will cause `maven-enforcer-plugin` to require that
|
||||
@@ -420,24 +430,24 @@
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<version>1.9.22</version>
|
||||
<version>1.9.22.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-bom</artifactId>
|
||||
<version>3.25.3</version>
|
||||
<version>3.26.3</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
<artifactId>checker-qual</artifactId>
|
||||
<version>3.43.0</version>
|
||||
<version>3.46.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-core</artifactId>
|
||||
<version>2.2</version>
|
||||
<version>3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.immutables</groupId>
|
||||
@@ -447,12 +457,12 @@
|
||||
<dependency>
|
||||
<groupId>org.jspecify</groupId>
|
||||
<artifactId>jspecify</artifactId>
|
||||
<version>0.3.0</version>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit</groupId>
|
||||
<artifactId>junit-bom</artifactId>
|
||||
<version>5.10.2</version>
|
||||
<version>5.11.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -466,7 +476,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongodb-driver-core</artifactId>
|
||||
<version>5.1.0</version>
|
||||
<version>5.1.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openrewrite</groupId>
|
||||
@@ -476,33 +486,33 @@
|
||||
<dependency>
|
||||
<groupId>org.openrewrite.recipe</groupId>
|
||||
<artifactId>rewrite-recipe-bom</artifactId>
|
||||
<version>2.11.0</version>
|
||||
<version>2.17.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-bom</artifactId>
|
||||
<version>2.0.13</version>
|
||||
<version>2.0.16</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>6.1.6</version>
|
||||
<version>6.1.12</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test</artifactId>
|
||||
<version>3.2.5</version>
|
||||
<version>3.3.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-bom</artifactId>
|
||||
<version>6.2.4</version>
|
||||
<version>6.3.3</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -520,7 +530,7 @@
|
||||
<plugin>
|
||||
<groupId>com.github.ekryd.sortpom</groupId>
|
||||
<artifactId>sortpom-maven-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<version>4.0.0</version>
|
||||
<configuration>
|
||||
<createBackupFile>false</createBackupFile>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
@@ -557,7 +567,7 @@
|
||||
<plugin>
|
||||
<groupId>com.spotify.fmt</groupId>
|
||||
<artifactId>fmt-maven-plugin</artifactId>
|
||||
<version>2.22.1</version>
|
||||
<version>2.24</version>
|
||||
<configuration>
|
||||
<additionalSourceDirectories>
|
||||
<additionalSourceDirectory>${basedir}/src/test/resources</additionalSourceDirectory>
|
||||
@@ -624,7 +634,7 @@
|
||||
<plugin>
|
||||
<groupId>io.github.git-commit-id</groupId>
|
||||
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||
<version>8.0.2</version>
|
||||
<version>9.0.1</version>
|
||||
<configuration>
|
||||
<injectAllReactorProjects>true</injectAllReactorProjects>
|
||||
<runOnlyOnce>true</runOnlyOnce>
|
||||
@@ -643,7 +653,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<version>3.5.0</version>
|
||||
<configuration>
|
||||
<checkstyleRules>
|
||||
<!-- We only enable rules that are not enforced by
|
||||
@@ -679,6 +689,7 @@
|
||||
<property name="allowNonPrintableEscapes" value="true" />
|
||||
</module>
|
||||
<module name="AvoidNoArgumentSuperConstructorCall" />
|
||||
<module name="ConstructorsDeclarationGrouping" />
|
||||
<module name="DeclarationOrder">
|
||||
<!-- We don't enforce sorting fields by
|
||||
their visibility modifier, for two
|
||||
@@ -891,7 +902,7 @@
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>10.16.0</version>
|
||||
<version>10.18.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.spring.nohttp</groupId>
|
||||
@@ -911,7 +922,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.3.2</version>
|
||||
<version>3.4.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@@ -959,11 +970,43 @@
|
||||
https://issues.apache.org/jira/browse/MCOMPILER-209. -->
|
||||
<useIncrementalCompilation>false</useIncrementalCompilation>
|
||||
</configuration>
|
||||
<executions>
|
||||
<!-- OpenRewrite recipe sources, generated by the
|
||||
`rewrite-templating` annotation processor and
|
||||
identified as classes whose name ends in `Recipes`, are
|
||||
compiled to target Java 8 for compatibility with the
|
||||
wider OpenRewrite ecosystem. The `maven-jar-plugin` is
|
||||
configured to package these files into a separate JAR. -->
|
||||
<execution>
|
||||
<id>compile-recipes</id>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<compilerArgs combine.self="override">
|
||||
<!-- When Java 8 is targeted we can't use
|
||||
the `add-exports` flag. And since this goal
|
||||
only recompiles already-compiled code,
|
||||
static analysis is irrelevant. As such we
|
||||
clear all compiler arguments, and only
|
||||
suppress source/target/bootstrap classpath
|
||||
warnings. -->
|
||||
<arg>-Xlint:-options</arg>
|
||||
</compilerArgs>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
<includes>
|
||||
<include>**/*Recipes.java</include>
|
||||
</includes>
|
||||
<outputDirectory>${project.build.directory}/openrewrite-recipes</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.7.1</version>
|
||||
<configuration>
|
||||
<!-- XXX: Drop `ignoreAllNonTestScoped` once
|
||||
https://issues.apache.org/jira/browse/MNG-6058 is
|
||||
@@ -986,7 +1029,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<version>3.5.0</version>
|
||||
<configuration>
|
||||
<fail>false</fail>
|
||||
<rules>
|
||||
@@ -1041,6 +1084,9 @@
|
||||
<requireJavaVersion>
|
||||
<version>${version.jdk}</version>
|
||||
</requireJavaVersion>
|
||||
<requireMatchingCoordinates>
|
||||
<moduleNameMustMatchArtifactId>true</moduleNameMustMatchArtifactId>
|
||||
</requireMatchingCoordinates>
|
||||
<requireMavenVersion>
|
||||
<version>${version.maven}</version>
|
||||
</requireMavenVersion>
|
||||
@@ -1068,7 +1114,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>3.2.4</version>
|
||||
<version>3.2.5</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
@@ -1086,7 +1132,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<version>3.4.2</version>
|
||||
<configuration>
|
||||
<skipIfEmpty>true</skipIfEmpty>
|
||||
<archive>
|
||||
@@ -1103,6 +1149,39 @@
|
||||
</archive>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-jar</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<!-- These Java 17 bytecode classes are omitted
|
||||
from the default JAR, as instead we produce a
|
||||
separate artifact with Java 8 bytecode variants. -->
|
||||
<excludes>
|
||||
<excludes>**/*Recipe$*.class</excludes>
|
||||
<excludes>**/*Recipe.class</excludes>
|
||||
<excludes>**/*Recipes.class</excludes>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<!-- Creates a custom JAR with Java 8-compatible
|
||||
OpenRewrite recipe classes. -->
|
||||
<id>create-openrewrite-recipes-jar</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<classesDirectory>${project.build.directory}/openrewrite-recipes</classesDirectory>
|
||||
<classifier>recipes</classifier>
|
||||
<includes>
|
||||
<includes>**/*Recipe$*.class</includes>
|
||||
<includes>**/*Recipe.class</includes>
|
||||
<includes>**/*Recipes.class</includes>
|
||||
</includes>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>create-test-jar</id>
|
||||
<goals>
|
||||
@@ -1114,7 +1193,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.6.3</version>
|
||||
<version>3.8.0</version>
|
||||
<configuration>
|
||||
<additionalJOptions>
|
||||
<additionalJOption>--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</additionalJOption>
|
||||
@@ -1143,7 +1222,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<version>3.1.1</version>
|
||||
<configuration>
|
||||
<autoVersionSubmodules>true</autoVersionSubmodules>
|
||||
<preparationProfiles>release</preparationProfiles>
|
||||
@@ -1184,7 +1263,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.2.5</version>
|
||||
<version>3.3.1</version>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/*Test.java</include>
|
||||
@@ -1200,7 +1279,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<version>3.6.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
@@ -1296,6 +1375,7 @@
|
||||
<!-- -->
|
||||
GPL-2.0-with-classpath-exception
|
||||
| CDDL/GPLv2+CE
|
||||
| CDDL + GPLv2 with classpath exception
|
||||
| GNU General Public License, version 2 (GPL2), with the classpath exception
|
||||
| GNU General Public License, version 2, with the Classpath Exception
|
||||
| GPL2 w/ CPE
|
||||
@@ -1330,7 +1410,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>tidy-maven-plugin</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.3.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>check-pom</id>
|
||||
@@ -1343,7 +1423,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.16.2</version>
|
||||
<version>2.17.1</version>
|
||||
<configuration>
|
||||
<updateBuildOutputTimestampPolicy>never</updateBuildOutputTimestampPolicy>
|
||||
</configuration>
|
||||
@@ -1351,7 +1431,7 @@
|
||||
<plugin>
|
||||
<groupId>org.gaul</groupId>
|
||||
<artifactId>modernizer-maven-plugin</artifactId>
|
||||
<version>2.8.0</version>
|
||||
<version>2.9.0</version>
|
||||
<configuration>
|
||||
<exclusionPatterns>
|
||||
<!-- The plugin suggests replacing usages of
|
||||
@@ -1466,7 +1546,7 @@
|
||||
<plugin>
|
||||
<groupId>org.sonarsource.scanner.maven</groupId>
|
||||
<artifactId>sonar-maven-plugin</artifactId>
|
||||
<version>3.11.0.3922</version>
|
||||
<version>4.0.0.4121</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
<version>0.18.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-compiler</artifactId>
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.PackageSymbol;
|
||||
import com.sun.tools.javac.main.JavaCompiler;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.ObjectOutputStream;
|
||||
@@ -137,10 +136,10 @@ final class RefasterRuleCompilerTaskListener implements TaskListener {
|
||||
return enclosingPackage == null ? "" : enclosingPackage.toString();
|
||||
}
|
||||
|
||||
private static CharSequence toSimpleFlatName(ClassSymbol symbol) {
|
||||
Name flatName = symbol.flatName();
|
||||
private static String toSimpleFlatName(ClassSymbol symbol) {
|
||||
String flatName = symbol.flatName().toString();
|
||||
int lastDot = flatName.lastIndexOf((byte) '.');
|
||||
return lastDot < 0 ? flatName : flatName.subSequence(lastDot + 1, flatName.length());
|
||||
return lastDot < 0 ? flatName : flatName.substring(lastDot + 1);
|
||||
}
|
||||
|
||||
private static void outputCodeTransformer(CodeTransformer codeTransformer, FileObject target)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
<version>0.18.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-runner</artifactId>
|
||||
@@ -58,6 +58,11 @@
|
||||
<artifactId>guava</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
<version>0.18.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-support</artifactId>
|
||||
|
||||
@@ -2,6 +2,7 @@ package tech.picnic.errorprone.refaster.matchers;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ArrayAccessTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.IdentifierTree;
|
||||
@@ -9,34 +10,19 @@ import com.sun.source.tree.LambdaExpressionTree;
|
||||
import com.sun.source.tree.LiteralTree;
|
||||
import com.sun.source.tree.MemberReferenceTree;
|
||||
import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.ParenthesizedTree;
|
||||
import com.sun.source.tree.TypeCastTree;
|
||||
import com.sun.source.tree.UnaryTree;
|
||||
|
||||
/** A matcher of expressions that likely require little to no computation. */
|
||||
public final class IsLikelyTrivialComputation implements Matcher<ExpressionTree> {
|
||||
/** A matcher of expressions that may a non-trivial amount of computation. */
|
||||
public final class RequiresComputation implements Matcher<ExpressionTree> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Instantiates a new {@link IsLikelyTrivialComputation} instance. */
|
||||
public IsLikelyTrivialComputation() {}
|
||||
/** Instantiates a new {@link RequiresComputation} instance. */
|
||||
public RequiresComputation() {}
|
||||
|
||||
@Override
|
||||
public boolean matches(ExpressionTree expressionTree, VisitorState state) {
|
||||
if (expressionTree instanceof MethodInvocationTree methodInvocation) {
|
||||
// XXX: Method invocations are generally *not* trivial computations, but we make an exception
|
||||
// for nullary method invocations on the result of a trivial computation. This exception
|
||||
// allows this `Matcher` to by the `OptionalOrElseGet` Refaster rule, such that it does not
|
||||
// suggest the introduction of lambda expressions that are better expressed as method
|
||||
// references. Once the `MethodReferenceUsage` bug checker is production-ready, this exception
|
||||
// should be removed. (But at that point, instead defining a `RequiresComputation` matcher may
|
||||
// be more appropriate.)
|
||||
if (methodInvocation.getArguments().isEmpty()
|
||||
&& matches(methodInvocation.getMethodSelect())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return matches(expressionTree);
|
||||
}
|
||||
|
||||
@@ -44,11 +30,11 @@ public final class IsLikelyTrivialComputation implements Matcher<ExpressionTree>
|
||||
// Depending on feedback such trees may be matched in the future.
|
||||
private static boolean matches(ExpressionTree expressionTree) {
|
||||
if (expressionTree instanceof ArrayAccessTree arrayAccess) {
|
||||
return matches(arrayAccess.getExpression()) && matches(arrayAccess.getIndex());
|
||||
return matches(arrayAccess.getExpression()) || matches(arrayAccess.getIndex());
|
||||
}
|
||||
|
||||
if (expressionTree instanceof LiteralTree) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expressionTree instanceof LambdaExpressionTree) {
|
||||
@@ -56,11 +42,14 @@ public final class IsLikelyTrivialComputation implements Matcher<ExpressionTree>
|
||||
* Lambda expressions encapsulate computations, but their definition does not involve
|
||||
* significant computation.
|
||||
*/
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expressionTree instanceof IdentifierTree) {
|
||||
return true;
|
||||
// XXX: Generally identifiers don't by themselves represent a computation, though they may be
|
||||
// a stand-in for one if they are a Refaster template method argument. Can we identify such
|
||||
// cases, also when the `Matcher` is invoked by Refaster?
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expressionTree instanceof MemberReferenceTree memberReference) {
|
||||
@@ -80,11 +69,11 @@ public final class IsLikelyTrivialComputation implements Matcher<ExpressionTree>
|
||||
}
|
||||
|
||||
if (expressionTree instanceof UnaryTree unary) {
|
||||
// XXX: Arguably side-effectful options such as pre- and post-increment and -decrement are not
|
||||
// trivial.
|
||||
// XXX: Arguably side-effectful options such as pre- and post-increment and -decrement
|
||||
// represent non-trivial computations.
|
||||
return matches(unary.getExpression());
|
||||
}
|
||||
|
||||
return false;
|
||||
return ASTHelpers.constValue(expressionTree) == null;
|
||||
}
|
||||
}
|
||||
@@ -8,54 +8,69 @@ import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.sun.source.tree.ReturnTree;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class IsLikelyTrivialComputationTest {
|
||||
final class RequiresComputationTest {
|
||||
@Test
|
||||
void matches() {
|
||||
CompilationTestHelper.newInstance(MatcherTestChecker.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.io.OutputStream;",
|
||||
"import java.util.Comparator;",
|
||||
"import java.util.function.Predicate;",
|
||||
"",
|
||||
"class A {",
|
||||
" String negative1() {",
|
||||
" return String.valueOf(1);",
|
||||
" int negative1() {",
|
||||
" int[] arr = new int[0];",
|
||||
" return arr[0];",
|
||||
" }",
|
||||
"",
|
||||
" String negative2() {",
|
||||
" return toString().toString();",
|
||||
" return null;",
|
||||
" }",
|
||||
"",
|
||||
" String negative3() {",
|
||||
" return \"foo\" + toString();",
|
||||
" boolean negative3() {",
|
||||
" return false;",
|
||||
" }",
|
||||
"",
|
||||
" byte negative4() {",
|
||||
" return \"foo\".getBytes()[0];",
|
||||
" int negative4() {",
|
||||
" return 0;",
|
||||
" }",
|
||||
"",
|
||||
" int negative5() {",
|
||||
" int[] arr = new int[0];",
|
||||
" return arr[hashCode()];",
|
||||
" String negative5() {",
|
||||
" return \"foo\" + \"bar\";",
|
||||
" }",
|
||||
"",
|
||||
" int negative6() {",
|
||||
" return 1 * 2;",
|
||||
" Predicate<String> negative6() {",
|
||||
" return v -> \"foo\".equals(v);",
|
||||
" }",
|
||||
"",
|
||||
" Predicate<String> negative7() {",
|
||||
" return toString()::equals;",
|
||||
" A negative7() {",
|
||||
" return this;",
|
||||
" }",
|
||||
"",
|
||||
" String negative8() {",
|
||||
" return (toString());",
|
||||
" Predicate<String> negative8() {",
|
||||
" return \"foo\"::equals;",
|
||||
" }",
|
||||
"",
|
||||
" Object negative9() {",
|
||||
" return (Object) toString();",
|
||||
" OutputStream negative9() {",
|
||||
" return System.out;",
|
||||
" }",
|
||||
"",
|
||||
" int negative10() {",
|
||||
" return -hashCode();",
|
||||
" A negative10() {",
|
||||
" return (this);",
|
||||
" }",
|
||||
"",
|
||||
" Object negative11() {",
|
||||
" return (Object) this;",
|
||||
" }",
|
||||
"",
|
||||
" boolean negative12() {",
|
||||
" boolean[] arr = new boolean[0];",
|
||||
" return !arr[0];",
|
||||
" }",
|
||||
"",
|
||||
" String negative13() {",
|
||||
" return \"foo\" + 0;",
|
||||
" }",
|
||||
"",
|
||||
" String positive1() {",
|
||||
@@ -68,68 +83,63 @@ final class IsLikelyTrivialComputationTest {
|
||||
" return this.toString();",
|
||||
" }",
|
||||
"",
|
||||
" int positive3() {",
|
||||
" int[] arr = new int[0];",
|
||||
" String positive3() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return arr[0];",
|
||||
" return String.valueOf(1);",
|
||||
" }",
|
||||
"",
|
||||
" String positive4() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return null;",
|
||||
" return toString().toString();",
|
||||
" }",
|
||||
"",
|
||||
" boolean positive5() {",
|
||||
" String positive5() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return false;",
|
||||
" return \"foo\" + toString();",
|
||||
" }",
|
||||
"",
|
||||
" int positive6() {",
|
||||
" byte positive6() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return 0;",
|
||||
" return \"foo\".getBytes()[0];",
|
||||
" }",
|
||||
"",
|
||||
" String positive7() {",
|
||||
" int positive7() {",
|
||||
" int[] arr = new int[0];",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return \"foo\" + \"bar\";",
|
||||
" return arr[hashCode()];",
|
||||
" }",
|
||||
"",
|
||||
" Predicate<String> positive8() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return v -> \"foo\".equals(v);",
|
||||
" return toString()::equals;",
|
||||
" }",
|
||||
"",
|
||||
" A positive9() {",
|
||||
" Comparator<String> positive9() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return this;",
|
||||
" return toString().CASE_INSENSITIVE_ORDER;",
|
||||
" }",
|
||||
"",
|
||||
" Predicate<String> positive10() {",
|
||||
" String positive10() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return \"foo\"::equals;",
|
||||
" return (toString());",
|
||||
" }",
|
||||
"",
|
||||
" A positive11() {",
|
||||
" Object positive11() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return (this);",
|
||||
" return (Object) toString();",
|
||||
" }",
|
||||
"",
|
||||
" Object positive12() {",
|
||||
" int positive12() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return (Object) this;",
|
||||
" }",
|
||||
"",
|
||||
" boolean positive13() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return !false;",
|
||||
" return -hashCode();",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
/** A {@link BugChecker} that simply delegates to {@link IsLikelyTrivialComputation}. */
|
||||
/** A {@link BugChecker} that simply delegates to {@link RequiresComputation}. */
|
||||
@BugPattern(
|
||||
summary = "Flags return statement expressions matched by `IsLikelyTrivialComputation`",
|
||||
summary = "Flags return statement expressions matched by `RequiresComputation`",
|
||||
severity = ERROR)
|
||||
public static final class MatcherTestChecker extends AbstractMatcherTestChecker {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -141,7 +151,7 @@ final class IsLikelyTrivialComputationTest {
|
||||
super(
|
||||
(expressionTree, state) ->
|
||||
state.getPath().getParentPath().getLeaf() instanceof ReturnTree
|
||||
&& new IsLikelyTrivialComputation().matches(expressionTree, state));
|
||||
&& new RequiresComputation().matches(expressionTree, state));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
<version>0.18.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-test-support</artifactId>
|
||||
@@ -50,6 +50,11 @@
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
|
||||
@@ -319,7 +319,7 @@ public final class RefasterRuleCollection extends BugChecker implements Compilat
|
||||
return indexedMatches.subRangeMap(Range.closedOpen(startPosition, endPosition));
|
||||
}
|
||||
|
||||
private ImmutableListMultimap<Long, String> getUnexpectedMatchesByLineNumber(
|
||||
private static ImmutableListMultimap<Long, String> getUnexpectedMatchesByLineNumber(
|
||||
ImmutableRangeMap<Integer, String> matches, String ruleUnderTest, VisitorState state) {
|
||||
LineMap lineMap = state.getPath().getCompilationUnit().getLineMap();
|
||||
return matches.asMapOfRanges().entrySet().stream()
|
||||
|
||||
@@ -1,8 +1,30 @@
|
||||
# An overview of Error Prone Support releases, along with compatible Error
|
||||
# Prone releases. This data was generated by `generate-version-compatibility-overview.sh`.
|
||||
releases:
|
||||
- version: 0.18.0
|
||||
compatible:
|
||||
- "2.30.0"
|
||||
- "2.31.0"
|
||||
- version: 0.17.0
|
||||
compatible:
|
||||
- "2.29.2"
|
||||
- "2.29.1"
|
||||
- "2.29.0"
|
||||
- "2.28.0"
|
||||
- "2.27.1"
|
||||
- "2.27.0"
|
||||
- "2.26.1"
|
||||
- "2.26.0"
|
||||
- "2.25.0"
|
||||
- "2.24.1"
|
||||
- "2.24.0"
|
||||
- "2.23.0"
|
||||
- version: 0.16.1
|
||||
compatible:
|
||||
- "2.29.2"
|
||||
- "2.29.1"
|
||||
- "2.29.0"
|
||||
- "2.28.0"
|
||||
- "2.27.1"
|
||||
- "2.27.0"
|
||||
- "2.26.1"
|
||||
@@ -13,6 +35,10 @@ releases:
|
||||
- "2.23.0"
|
||||
- version: 0.16.0
|
||||
compatible:
|
||||
- "2.29.2"
|
||||
- "2.29.1"
|
||||
- "2.29.0"
|
||||
- "2.28.0"
|
||||
- "2.27.1"
|
||||
- "2.27.0"
|
||||
- "2.26.1"
|
||||
@@ -23,6 +49,10 @@ releases:
|
||||
- "2.23.0"
|
||||
- version: 0.15.0
|
||||
compatible:
|
||||
- "2.29.2"
|
||||
- "2.29.1"
|
||||
- "2.29.0"
|
||||
- "2.28.0"
|
||||
- "2.27.1"
|
||||
- "2.27.0"
|
||||
- "2.26.1"
|
||||
@@ -33,6 +63,10 @@ releases:
|
||||
- "2.23.0"
|
||||
- version: 0.14.0
|
||||
compatible:
|
||||
- "2.29.2"
|
||||
- "2.29.1"
|
||||
- "2.29.0"
|
||||
- "2.28.0"
|
||||
- "2.27.1"
|
||||
- "2.27.0"
|
||||
- "2.26.1"
|
||||
|
||||
Reference in New Issue
Block a user