mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
Compare commits
120 Commits
sschroever
...
sschroever
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd9c248777 | ||
|
|
9954663bd5 | ||
|
|
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.8
|
||||
- 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.8
|
||||
- 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.8
|
||||
- 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.8
|
||||
- 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.8
|
||||
- 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.8
|
||||
- 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>
|
||||
@@ -122,6 +122,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",
|
||||
|
||||
@@ -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,6 +24,7 @@ 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.Optional;
|
||||
@@ -247,14 +248,46 @@ final class ComparatorRules {
|
||||
* 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 MinOfCollection<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);
|
||||
}
|
||||
}
|
||||
@@ -314,14 +347,46 @@ final class ComparatorRules {
|
||||
* 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 MaxOfCollection<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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
@@ -11,6 +12,10 @@ import com.google.errorprone.refaster.annotation.MayOptionallyUse;
|
||||
import com.google.errorprone.refaster.annotation.NotMatches;
|
||||
import com.google.errorprone.refaster.annotation.Placeholder;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.Optional;
|
||||
@@ -27,6 +32,23 @@ import tech.picnic.errorprone.refaster.matchers.IsLikelyTrivialComputation;
|
||||
final class OptionalRules {
|
||||
private OptionalRules() {}
|
||||
|
||||
// XXX: Move or drop.
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface BeforeExample {}
|
||||
|
||||
// XXX: Move or drop.
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface AfterExample {}
|
||||
|
||||
// XXX: Move or drop.
|
||||
interface RefasterExpressionExamples<T> {
|
||||
ImmutableList<T> before();
|
||||
|
||||
ImmutableList<T> after();
|
||||
}
|
||||
|
||||
/** Prefer {@link Optional#empty()} over the more contrived alternative. */
|
||||
static final class OptionalEmpty<T> {
|
||||
@BeforeTemplate
|
||||
@@ -53,6 +75,40 @@ final class OptionalRules {
|
||||
Optional<T> after(T object) {
|
||||
return Optional.ofNullable(object);
|
||||
}
|
||||
|
||||
@BeforeExample
|
||||
@SuppressWarnings({
|
||||
"TernaryOperatorOptionalNegativeFiltering",
|
||||
"TernaryOperatorOptionalPositiveFiltering"
|
||||
} /* Special cases. */)
|
||||
ImmutableList<Optional<String>> input() {
|
||||
return ImmutableList.of(
|
||||
toString() == null ? Optional.empty() : Optional.of(toString()),
|
||||
toString() != null ? Optional.of(toString()) : Optional.empty());
|
||||
}
|
||||
|
||||
@AfterExample
|
||||
ImmutableList<Optional<String>> output() {
|
||||
return ImmutableList.of(Optional.ofNullable(toString()), Optional.ofNullable(toString()));
|
||||
}
|
||||
|
||||
static final class Examples implements RefasterExpressionExamples<Optional<String>> {
|
||||
@Override
|
||||
@SuppressWarnings({
|
||||
"TernaryOperatorOptionalNegativeFiltering",
|
||||
"TernaryOperatorOptionalPositiveFiltering"
|
||||
} /* Special cases. */)
|
||||
public ImmutableList<Optional<String>> before() {
|
||||
return ImmutableList.of(
|
||||
toString() == null ? Optional.empty() : Optional.of(toString()),
|
||||
toString() != null ? Optional.of(toString()) : Optional.empty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<Optional<String>> after() {
|
||||
return ImmutableList.of(Optional.ofNullable(toString()), Optional.ofNullable(toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Optional#isEmpty()} over the more verbose alternative. */
|
||||
@@ -66,6 +122,16 @@ final class OptionalRules {
|
||||
boolean after(Optional<T> optional) {
|
||||
return optional.isEmpty();
|
||||
}
|
||||
|
||||
@BeforeExample
|
||||
ImmutableList<Boolean> input() {
|
||||
return ImmutableList.of(!Optional.empty().isPresent(), !Optional.of("foo").isPresent());
|
||||
}
|
||||
|
||||
@AfterExample
|
||||
ImmutableList<Boolean> output() {
|
||||
return ImmutableList.of(Optional.empty().isEmpty(), Optional.of("foo").isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Optional#isPresent()} over the inverted alternative. */
|
||||
@@ -79,6 +145,16 @@ final class OptionalRules {
|
||||
boolean after(Optional<T> optional) {
|
||||
return optional.isPresent();
|
||||
}
|
||||
|
||||
@BeforeExample
|
||||
ImmutableList<Boolean> input() {
|
||||
return ImmutableList.of(!Optional.empty().isEmpty(), !Optional.of("foo").isEmpty());
|
||||
}
|
||||
|
||||
@AfterExample
|
||||
ImmutableList<Boolean> output() {
|
||||
return ImmutableList.of(Optional.empty().isPresent(), Optional.of("foo").isPresent());
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Optional#orElseThrow()} over the less explicit {@link Optional#get()}. */
|
||||
|
||||
@@ -33,6 +33,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 +41,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 +482,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 +564,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 +1205,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 +1918,60 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,8 +161,9 @@ final class TestNGToAssertJRules {
|
||||
|
||||
@AfterTemplate
|
||||
@DoNotCall
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after() {
|
||||
throw new AssertionError();
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,14 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Comparator.<String>reverseOrder().compare("baz", "qux"));
|
||||
}
|
||||
|
||||
String testMinOfArray() {
|
||||
return Arrays.stream(new String[0]).min(naturalOrder()).orElseThrow();
|
||||
}
|
||||
|
||||
String testMinOfCollection() {
|
||||
return ImmutableSet.of("foo", "bar").stream().min(naturalOrder()).orElseThrow();
|
||||
}
|
||||
|
||||
int testMinOfVarargs() {
|
||||
return Stream.of(1, 2).min(naturalOrder()).orElseThrow();
|
||||
}
|
||||
@@ -135,6 +143,14 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Collections.min(ImmutableSet.of("a", "b"), (a, b) -> 1));
|
||||
}
|
||||
|
||||
String testMaxOfArray() {
|
||||
return Arrays.stream(new String[0]).max(naturalOrder()).orElseThrow();
|
||||
}
|
||||
|
||||
String testMaxOfCollection() {
|
||||
return ImmutableSet.of("foo", "bar").stream().max(naturalOrder()).orElseThrow();
|
||||
}
|
||||
|
||||
int testMaxOfVarargs() {
|
||||
return Stream.of(1, 2).max(naturalOrder()).orElseThrow();
|
||||
}
|
||||
|
||||
@@ -98,6 +98,14 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of("foo".compareTo("bar"), "qux".compareTo("baz"));
|
||||
}
|
||||
|
||||
String testMinOfArray() {
|
||||
return Collections.min(Arrays.asList(new String[0]), naturalOrder());
|
||||
}
|
||||
|
||||
String testMinOfCollection() {
|
||||
return Collections.min(ImmutableSet.of("foo", "bar"), naturalOrder());
|
||||
}
|
||||
|
||||
int testMinOfVarargs() {
|
||||
return Collections.min(Arrays.asList(1, 2), naturalOrder());
|
||||
}
|
||||
@@ -126,6 +134,14 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Comparators.min("a", "b", (a, b) -> 1));
|
||||
}
|
||||
|
||||
String testMaxOfArray() {
|
||||
return Collections.max(Arrays.asList(new String[0]), naturalOrder());
|
||||
}
|
||||
|
||||
String testMaxOfCollection() {
|
||||
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() {
|
||||
|
||||
@@ -21,7 +21,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 +184,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 +209,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 +435,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 +655,16 @@ 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);
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxFromStreamSupplier() {
|
||||
return Flux.fromStream(Stream.of(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,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 +188,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 +216,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 +430,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 +635,16 @@ 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);
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxFromStreamSupplier() {
|
||||
return Flux.fromStream(() -> Stream.of(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
167
pom.xml
167
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.30.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.8</version.maven>
|
||||
<version.mockito>5.12.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.13.0</version.rewrite-templating>
|
||||
<version.surefire>3.2.3</version.surefire>
|
||||
</properties>
|
||||
|
||||
@@ -296,7 +296,7 @@
|
||||
<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>
|
||||
@@ -328,7 +328,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 +338,14 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava-bom</artifactId>
|
||||
<version>33.2.0-jre</version>
|
||||
<version>33.2.1-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 +360,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 +377,17 @@
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>2.2.21</version>
|
||||
<version>2.2.22</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 +412,7 @@
|
||||
<dependency>
|
||||
<groupId>net.bytebuddy</groupId>
|
||||
<artifactId>byte-buddy</artifactId>
|
||||
<version>1.14.14</version>
|
||||
<version>1.14.19</version>
|
||||
</dependency>
|
||||
<!-- Specified so that Renovate will file Maven upgrade PRs, which
|
||||
subsequently will cause `maven-enforcer-plugin` to require that
|
||||
@@ -420,24 +425,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 +452,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 +471,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 +481,33 @@
|
||||
<dependency>
|
||||
<groupId>org.openrewrite.recipe</groupId>
|
||||
<artifactId>rewrite-recipe-bom</artifactId>
|
||||
<version>2.11.0</version>
|
||||
<version>2.16.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.11</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.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-bom</artifactId>
|
||||
<version>6.2.4</version>
|
||||
<version>6.3.1</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -520,7 +525,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>
|
||||
@@ -624,7 +629,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 +648,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<version>3.4.0</version>
|
||||
<configuration>
|
||||
<checkstyleRules>
|
||||
<!-- We only enable rules that are not enforced by
|
||||
@@ -679,6 +684,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 +897,7 @@
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>10.16.0</version>
|
||||
<version>10.17.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.spring.nohttp</groupId>
|
||||
@@ -911,7 +917,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 +965,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 +1024,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 +1079,9 @@
|
||||
<requireJavaVersion>
|
||||
<version>${version.jdk}</version>
|
||||
</requireJavaVersion>
|
||||
<requireMatchingCoordinates>
|
||||
<moduleNameMustMatchArtifactId>true</moduleNameMustMatchArtifactId>
|
||||
</requireMatchingCoordinates>
|
||||
<requireMavenVersion>
|
||||
<version>${version.maven}</version>
|
||||
</requireMavenVersion>
|
||||
@@ -1068,7 +1109,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 +1127,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 +1144,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 +1188,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 +1217,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 +1258,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 +1274,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 +1370,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 +1405,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 +1418,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 +1426,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 +1541,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>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package tech.picnic.errorprone.refaster.test;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.DynamicTest;
|
||||
import org.junit.jupiter.api.TestFactory;
|
||||
|
||||
// XXX: Drop these annotations.
|
||||
@Disabled
|
||||
@SuppressWarnings("all")
|
||||
abstract class MyAbstractTest {
|
||||
@TestFactory
|
||||
Stream<DynamicTest> dynamicTests() {
|
||||
MatchInWrongMethodRules.class.getDeclaredClasses();
|
||||
|
||||
return Stream.of(
|
||||
DynamicTest.dynamicTest("A " + getClass(), () -> {}),
|
||||
DynamicTest.dynamicTest("A", () -> {}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
package tech.picnic.errorprone.refaster.test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.DynamicTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestFactory;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.extension.Extension;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.jupiter.api.extension.TestInstanceFactory;
|
||||
import org.junit.jupiter.api.extension.TestInstanceFactoryContext;
|
||||
import org.junit.jupiter.api.extension.TestInstantiationException;
|
||||
|
||||
// XXX: Drop these annotations.
|
||||
@Disabled
|
||||
@SuppressWarnings("all")
|
||||
public class MyTest extends MyAbstractTest {
|
||||
public static final class MyTestInstanceFactory implements TestInstanceFactory {
|
||||
@Override
|
||||
public Object createTestInstance(
|
||||
TestInstanceFactoryContext factoryContext, ExtensionContext extensionContext)
|
||||
throws TestInstantiationException {
|
||||
return new MySubTest();
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Name
|
||||
@Test
|
||||
void foo() {
|
||||
// Options:
|
||||
// 1. Add examples to the Refaster rule, generate the tests from those
|
||||
//
|
||||
// 2. Define as test, and use a custom test annotation, which:
|
||||
// - Generates the relevant test resources
|
||||
// - Executes them.
|
||||
// ^ Might be nicer to generate a subclass and use a `TestInstanceFactory` to instantiate that.
|
||||
// XXX: That turns out not to work.
|
||||
//
|
||||
// ^ Other option: provide super class that declares a `TestFactory` based on the subclass name.
|
||||
|
||||
}
|
||||
|
||||
// Extensions can be defined at any level. TBD how useful.
|
||||
// static final class MyExtension implements Extension, {
|
||||
//
|
||||
// }
|
||||
// @ExtendWith(MyExtension.class)
|
||||
|
||||
static class MySubTest extends MyTest {}
|
||||
|
||||
@TestFactory
|
||||
Stream<DynamicTest> dynamicTestsFromStreamInJava8() {
|
||||
|
||||
Function<String, String> resolver = s -> s;
|
||||
|
||||
List<String> domainNames =
|
||||
Arrays.asList("www.somedomain.com", "www.anotherdomain.com", "www.yetanotherdomain.com");
|
||||
List<String> outputList = Arrays.asList("154.174.10.56", "211.152.104.132", "178.144.120.156");
|
||||
|
||||
return domainNames.stream()
|
||||
.map(
|
||||
dom ->
|
||||
DynamicTest.dynamicTest(
|
||||
"Resolving: " + dom,
|
||||
() -> {
|
||||
int id = domainNames.indexOf(dom);
|
||||
|
||||
assertEquals(outputList.get(id), resolver.apply(dom));
|
||||
}));
|
||||
}
|
||||
|
||||
static final class PrimitiveOrReferenceEquality
|
||||
implements ExpressionTestCase<ImmutableSet<Boolean>> {
|
||||
public ImmutableSet<Boolean> before() {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP.equals(RoundingMode.DOWN),
|
||||
Objects.equals(RoundingMode.UP, RoundingMode.DOWN),
|
||||
!RoundingMode.UP.equals(RoundingMode.DOWN),
|
||||
!Objects.equals(RoundingMode.UP, RoundingMode.DOWN));
|
||||
}
|
||||
|
||||
public ImmutableSet<Boolean> after() {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP == RoundingMode.DOWN,
|
||||
RoundingMode.UP == RoundingMode.DOWN,
|
||||
RoundingMode.UP != RoundingMode.DOWN,
|
||||
RoundingMode.UP != RoundingMode.DOWN);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: This variant can verify that the values are equal.
|
||||
static final class PrimitiveOrReferenceEquality2 implements ExpressionTestCase2<Boolean> {
|
||||
public void before(Consumer<Boolean> sink) {
|
||||
sink.accept(RoundingMode.UP.equals(RoundingMode.DOWN));
|
||||
sink.accept(Objects.equals(RoundingMode.UP, RoundingMode.DOWN));
|
||||
sink.accept(!RoundingMode.UP.equals(RoundingMode.DOWN));
|
||||
sink.accept(!Objects.equals(RoundingMode.UP, RoundingMode.DOWN));
|
||||
}
|
||||
|
||||
public void after(Consumer<Boolean> sink) {
|
||||
sink.accept(RoundingMode.UP == RoundingMode.DOWN);
|
||||
sink.accept(RoundingMode.UP == RoundingMode.DOWN);
|
||||
sink.accept(RoundingMode.UP != RoundingMode.DOWN);
|
||||
sink.accept(RoundingMode.UP != RoundingMode.DOWN);
|
||||
}
|
||||
}
|
||||
|
||||
// With this setup we could validate equality, and (in theory) even report the exact source in
|
||||
// case of an error.
|
||||
// @Test
|
||||
void primitiveOrReferenceEquality(BiConsumer<Boolean, Boolean> testCase) {
|
||||
testCase.accept(
|
||||
RoundingMode.UP.equals(RoundingMode.DOWN), RoundingMode.UP == RoundingMode.DOWN);
|
||||
testCase.accept(
|
||||
Objects.equals(RoundingMode.UP, RoundingMode.DOWN), RoundingMode.UP == RoundingMode.DOWN);
|
||||
testCase.accept(
|
||||
!RoundingMode.UP.equals(RoundingMode.DOWN), RoundingMode.UP != RoundingMode.DOWN);
|
||||
testCase.accept(
|
||||
!Objects.equals(RoundingMode.UP, RoundingMode.DOWN), RoundingMode.UP != RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// With this setup we could validate equality, and (in theory) even report the exact source in
|
||||
// case of an error.
|
||||
// @Test
|
||||
void primitiveOrReferenceEquality2(BiConsumer<Supplier<Boolean>, Supplier<Boolean>> testCase) {
|
||||
testCase.accept(
|
||||
() -> RoundingMode.UP.equals(RoundingMode.DOWN),
|
||||
() -> RoundingMode.UP == RoundingMode.DOWN);
|
||||
testCase.accept(
|
||||
() -> Objects.equals(RoundingMode.UP, RoundingMode.DOWN),
|
||||
() -> RoundingMode.UP == RoundingMode.DOWN);
|
||||
testCase.accept(
|
||||
() -> !RoundingMode.UP.equals(RoundingMode.DOWN),
|
||||
() -> RoundingMode.UP != RoundingMode.DOWN);
|
||||
testCase.accept(
|
||||
() -> !Objects.equals(RoundingMode.UP, RoundingMode.DOWN),
|
||||
() -> RoundingMode.UP != RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
interface ExpressionTestCase<T> {
|
||||
T before();
|
||||
|
||||
T after();
|
||||
}
|
||||
|
||||
interface ExpressionTestCase2<T> {
|
||||
void before(Consumer<T> sink);
|
||||
|
||||
void after(Consumer<T> sink);
|
||||
}
|
||||
|
||||
// record ExpressionTestCaseX<T>(Supplier<T> before, Supplier<T> after);
|
||||
}
|
||||
@@ -1,8 +1,29 @@
|
||||
# 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"
|
||||
- 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 +34,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 +48,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 +62,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