Merge master into sschroevers/refaster-speed-up

This commit is contained in:
Rick Ossendrijver
2025-01-17 15:14:13 +01:00
89 changed files with 3313 additions and 793 deletions

View File

@@ -14,11 +14,11 @@ jobs:
distribution: [ temurin ]
experimental: [ false ]
include:
- os: macos-14
- os: macos-15
jdk: 17.0.13
distribution: temurin
experimental: false
- os: windows-2022
- os: windows-2025
jdk: 17.0.13
distribution: temurin
experimental: false
@@ -26,14 +26,16 @@ jobs:
continue-on-error: ${{ matrix.experimental }}
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with:
disable-sudo: true
egress-policy: block
allowed-endpoints: >
api.adoptium.net:443
github.com:443
github-registry-files.githubusercontent.com:443
jitpack.io:443
maven.pkg.github.com:443
objects.githubusercontent.com:443
repo.maven.apache.org:443
# We run the build twice for each supported JDK: once against the
@@ -42,7 +44,7 @@ jobs:
# additionally enabling all checks defined in this project and any Error
# Prone checks available only from other artifact repositories.
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
with:
java-version: ${{ matrix.jdk }}
java-distribution: ${{ matrix.distribution }}
@@ -53,6 +55,8 @@ jobs:
run: mvn -T1C install javadoc:jar
- name: Build project with self-check against Error Prone fork
run: mvn -T1C clean verify -Perror-prone-fork -Pnon-maven-central -Pself-check -s settings.xml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Remove installed project artifacts
run: mvn dependency:purge-local-repository -DmanualInclude='${project.groupId}' -DresolutionFuzziness=groupId

View File

@@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with:
disable-sudo: true
egress-policy: block
@@ -34,19 +34,19 @@ jobs:
repo.maven.apache.org:443
uploads.github.com:443
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
with:
java-version: 17.0.13
java-distribution: temurin
maven-version: 3.9.9
- name: Initialize CodeQL
uses: github/codeql-action/init@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
uses: github/codeql-action/init@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
with:
languages: ${{ matrix.language }}
- name: Perform minimal build
if: matrix.language == 'java'
run: mvn -T1C clean package -DskipTests -Dverification.skip
- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
uses: github/codeql-action/analyze@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
with:
category: /language:${{ matrix.language }}

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with:
disable-sudo: true
egress-policy: block
@@ -21,6 +21,7 @@ jobs:
api.github.com:443
bestpractices.coreinfrastructure.org:443
blog.picnic.nl:443
docs.github.com:443
errorprone.info:443
github.com:443
img.shields.io:443
@@ -42,7 +43,7 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- uses: ruby/setup-ruby@a2bbe5b1b236842c1cb7dd11e8e3b51e0a616acc # v1.202.0
- uses: ruby/setup-ruby@bfefad842bb982ff05b233bcbc1571d97a87e69f # v1.206.0
with:
working-directory: ./website
bundler-cache: true
@@ -74,7 +75,7 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with:
disable-sudo: true
egress-policy: block

View File

@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with:
disable-sudo: true
egress-policy: block
@@ -48,6 +48,6 @@ jobs:
results_format: sarif
publish_results: ${{ github.ref == 'refs/heads/master' }}
- name: Update GitHub's code scanning dashboard
uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
uses: github/codeql-action/upload-sarif@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
with:
sarif_file: results.sarif

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with:
disable-sudo: true
egress-policy: block
@@ -22,7 +22,7 @@ jobs:
objects.githubusercontent.com:443
repo.maven.apache.org:443
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
with:
checkout-fetch-depth: 2
java-version: 17.0.13
@@ -38,7 +38,7 @@ jobs:
- name: Aggregate Pitest reports
run: mvn pitest-git:aggregate -DkilledEmoji=":tada:" -DmutantEmoji=":zombie:" -DtrailingText="Mutation testing report by [Pitest](https://pitest.org/). Review any surviving mutants by inspecting the line comments under [_Files changed_](${{ github.event.number }}/files)."
- name: Upload Pitest reports as artifact
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: pitest-reports
path: ./target/pit-reports-ci

View File

@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with:
disable-sudo: true
egress-policy: block
@@ -31,7 +31,7 @@ jobs:
objects.githubusercontent.com:443
repo.maven.apache.org:443
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
with:
java-version: 17.0.13
java-distribution: temurin

View File

@@ -22,7 +22,7 @@ jobs:
integration-test: [ "checkstyle", "metrics", "prometheus-java-client" ]
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with:
disable-sudo: true
egress-policy: block
@@ -43,7 +43,7 @@ jobs:
repo.maven.apache.org:443
repository.sonatype.org:443
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
with:
checkout-ref: "refs/pull/${{ github.event.issue.number }}/head"
java-version: 17.0.13
@@ -55,7 +55,7 @@ jobs:
run: xvfb-run "./integration-tests/${{ matrix.integration-test }}.sh" "${{ runner.temp }}/artifacts"
- name: Upload artifacts on failure
if: ${{ failure() }}
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: "integration-test-${{ matrix.integration-test }}"
path: "${{ runner.temp }}/artifacts"

View File

@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
with:
disable-sudo: true
egress-policy: block
@@ -35,7 +35,7 @@ jobs:
*.sonarcloud.io:443
sonarcloud.io:443
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
with:
checkout-fetch-depth: 0
java-version: 17.0.13

View File

@@ -205,12 +205,13 @@ Relevant Maven build parameters:
version of Error Prone. This is useful e.g. when testing a locally built
Error Prone SNAPSHOT.
- `-Perror-prone-fork` runs the build using Picnic's [Error Prone
fork][error-prone-fork-repo], hosted on [Jitpack][error-prone-fork-jitpack].
This fork generally contains a few changes on top of the latest Error Prone
release.
fork][error-prone-fork-repo], hosted using [GitHub
Packages][error-prone-fork-packages]. This fork generally contains a few
changes on top of the latest Error Prone release. Using this profile
generally requires passing `-s settings.xml`, with [suitably
configured][github-packages-auth] `GITHUB_ACTOR` and `GITHUB_TOKEN`
environment variables.
- `-Pself-check` runs the checks defined by this project against itself.
Pending a release of [google/error-prone#3301][error-prone-pull-3301], this
flag must currently be used in combination with `-Perror-prone-fork`.
Other highly relevant commands:
@@ -235,8 +236,9 @@ Other highly relevant commands:
against _all_ code in the current working directory. For more information
check the [PIT Maven plugin][pitest-maven].
When running the project's tests in IntelliJ IDEA, you might see the following
error:
Opening the project in IntelliJ IDEA may require running `mvn clean install`
first. Additionally, when running the project's tests using the IDE, you might
see the following error:
```
java: exporting a package from system module jdk.compiler is not allowed with --release
@@ -274,14 +276,14 @@ channel; please see our [security policy][security] for details.
[contributing]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/CONTRIBUTING.md
[contributing-pull-request]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/CONTRIBUTING.md#-opening-a-pull-request
[error-prone-bugchecker]: https://github.com/google/error-prone/blob/master/check_api/src/main/java/com/google/errorprone/bugpatterns/BugChecker.java
[error-prone-fork-jitpack]: https://jitpack.io/#PicnicSupermarket/error-prone
[error-prone-fork-packages]: https://github.com/PicnicSupermarket/error-prone/packages
[error-prone-fork-repo]: https://github.com/PicnicSupermarket/error-prone
[error-prone-gradle-installation-guide]: https://github.com/tbroyer/gradle-errorprone-plugin
[error-prone-installation-guide]: https://errorprone.info/docs/installation#maven
[error-prone-orig-repo]: https://github.com/google/error-prone
[error-prone-pull-3301]: https://github.com/google/error-prone/pull/3301
[github-actions-build-badge]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yml/badge.svg
[github-actions-build-master]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yml?query=branch:master&event=push
[github-packages-auth]: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-apache-maven-registry#authenticating-to-github-packages
[google-java-format]: https://github.com/google/google-java-format
[idea-288052]: https://youtrack.jetbrains.com/issue/IDEA-288052
[license-badge]: https://img.shields.io/github/license/PicnicSupermarket/error-prone-support

View File

@@ -15,24 +15,6 @@
<url>https://error-prone.picnic.tech</url>
<dependencies>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotation</artifactId>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_check_api</artifactId>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>error-prone-utils</artifactId>
@@ -72,6 +54,24 @@
<artifactId>auto-value-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotation</artifactId>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_check_api</artifactId>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>

View File

@@ -15,31 +15,6 @@
<url>https://error-prone.picnic.tech</url>
<dependencies>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>documentation-support</artifactId>
@@ -87,6 +62,31 @@
<artifactId>auto-value-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>

View File

@@ -0,0 +1,325 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.PERFORMANCE;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.auto.value.AutoValue;
import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.annotations.Var;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import java.util.Collections;
import java.util.Formattable;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags {@link String#format} and {@link String#formatted} invocations
* that can be omitted by delegating to another format method.
*/
// XXX: The special-casing of Throwable applies only to SLF4J 1.6.0+; see
// https://www.slf4j.org/faq.html#paramException. That should be documented.
// XXX: Some of the `Matcher`s defined here are also declared by the `Slf4jLogStatement` and
// `RedundantStringConversion` checks. Look into deduplicating them.
// XXX: Should we also simplify e.g. `LOG.error(String.join("sep", arg1, arg2), throwable)`? Perhaps
// that's too obscure.
// XXX: This check currently only flags string format expressions that are a direct argument to
// another format-capable method invocation. Indirect cases, such as where the result is assigned to
// a variable, are currently not covered.
@AutoService(BugChecker.class)
@BugPattern(
summary = "String formatting can be deferred",
link = BUG_PATTERNS_BASE_URL + "EagerStringFormatting",
linkType = CUSTOM,
severity = WARNING,
tags = {PERFORMANCE, SIMPLIFICATION})
public final class EagerStringFormatting extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> FORMATTABLE = isSubtypeOf(Formattable.class);
private static final Matcher<ExpressionTree> LOCALE = isSubtypeOf(Locale.class);
private static final Matcher<ExpressionTree> SLF4J_MARKER = isSubtypeOf("org.slf4j.Marker");
private static final Matcher<ExpressionTree> THROWABLE = isSubtypeOf(Throwable.class);
private static final Matcher<ExpressionTree> REQUIRE_NON_NULL_INVOCATION =
staticMethod().onClass(Objects.class.getCanonicalName()).named("requireNonNull");
private static final Matcher<ExpressionTree> GUAVA_GUARD_INVOCATION =
anyOf(
staticMethod()
.onClass(Preconditions.class.getCanonicalName())
.namedAnyOf("checkArgument", "checkNotNull", "checkState"),
staticMethod()
.onClass(Verify.class.getCanonicalName())
.namedAnyOf("verify", "verifyNotNull"));
private static final Matcher<ExpressionTree> SLF4J_LOGGER_INVOCATION =
instanceMethod()
.onDescendantOf("org.slf4j.Logger")
.namedAnyOf("trace", "debug", "info", "warn", "error");
private static final Matcher<ExpressionTree> STATIC_FORMAT_STRING =
staticMethod().onClass(String.class.getCanonicalName()).named("format");
private static final Matcher<ExpressionTree> INSTANCE_FORMAT_STRING =
instanceMethod().onDescendantOf(String.class.getCanonicalName()).named("formatted");
private static final String MESSAGE_NEVER_NULL_ARGUMENT =
"String formatting never yields `null` expression";
/** Instantiates a new {@link EagerStringFormatting} instance. */
public EagerStringFormatting() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
Tree parent = state.getPath().getParentPath().getLeaf();
if (!(parent instanceof MethodInvocationTree methodInvocation)) {
/*
* Fast path: this isn't a method invocation whose result is an argument to another method
* invocation.
*/
// XXX: This logic assumes that the string format operation isn't redundantly wrapped in
// parentheses. Similar assumptions likely exist throughout the code base. Investigate how to
// structurally cover such cases.
return Description.NO_MATCH;
}
return StringFormatExpression.tryCreate(tree, state)
.map(expr -> analyzeFormatStringContext(expr, methodInvocation, state))
.orElse(Description.NO_MATCH);
}
private Description analyzeFormatStringContext(
StringFormatExpression stringFormat, MethodInvocationTree context, VisitorState state) {
if (REQUIRE_NON_NULL_INVOCATION.matches(context, state)) {
return analyzeRequireNonNullStringFormatContext(stringFormat, context);
}
if (GUAVA_GUARD_INVOCATION.matches(context, state)) {
return analyzeGuavaGuardStringFormatContext(stringFormat, context, state);
}
if (SLF4J_LOGGER_INVOCATION.matches(context, state)) {
return analyzeSlf4jLoggerStringFormatContext(stringFormat, context, state);
}
/*
* The string formatting operation does not appear to happen in a context that admits of
* simplification or optimization.
*/
return Description.NO_MATCH;
}
private Description analyzeRequireNonNullStringFormatContext(
StringFormatExpression stringFormat, MethodInvocationTree context) {
List<? extends ExpressionTree> arguments = context.getArguments();
if (arguments.size() != 2 || arguments.get(0).equals(stringFormat.expression())) {
/* Vacuous validation that string formatting doesn't yield `null`. */
return buildDescription(context).setMessage(MESSAGE_NEVER_NULL_ARGUMENT).build();
}
if (stringFormat.arguments().stream()
.anyMatch(EagerStringFormatting::isNonFinalLocalVariable)) {
/*
* The format operation depends on a variable that isn't final or effectively final; moving
* it into a lambda expression would cause a compilation error.
*/
return buildDescription(context)
.setMessage(message() + " (but this requires introducing an effectively final variable)")
.build();
}
/* Suggest that the string formatting is deferred. */
return describeMatch(context, SuggestedFix.prefixWith(stringFormat.expression(), "() -> "));
}
private Description analyzeGuavaGuardStringFormatContext(
StringFormatExpression stringFormat, MethodInvocationTree context, VisitorState state) {
List<? extends ExpressionTree> arguments = context.getArguments();
if (arguments.get(0).equals(stringFormat.expression())) {
/*
* Vacuous `checkNotNull` or `verifyNotNull` validation that string formatting doesn't yield
* `null`.
*/
return buildDescription(context).setMessage(MESSAGE_NEVER_NULL_ARGUMENT).build();
}
if (stringFormat.simplifiableFormatString().isEmpty() || arguments.size() > 2) {
/*
* The format string cannot be simplified, or the format string produces a format string
* itself, or its result is the input to another format operation. These are complex cases
* that we'll only flag.
*/
return createSimplificationSuggestion(context, "Guava");
}
return describeMatch(context, stringFormat.suggestFlattening("%s", state));
}
private Description analyzeSlf4jLoggerStringFormatContext(
StringFormatExpression stringFormat, MethodInvocationTree context, VisitorState state) {
if (stringFormat.simplifiableFormatString().isEmpty()) {
/* We can't simplify this case; only flag it. */
return createSimplificationSuggestion(context, "SLF4J");
}
List<? extends ExpressionTree> arguments = context.getArguments();
int leftOffset = SLF4J_MARKER.matches(arguments.get(0), state) ? 1 : 0;
int rightOffset = THROWABLE.matches(arguments.get(arguments.size() - 1), state) ? 1 : 0;
if (arguments.size() != leftOffset + 1 + rightOffset) {
/*
* The format string produces a format string itself, or its result is the input to another
* format operation. This is a complex case that we'll only flag.
*/
return createSimplificationSuggestion(context, "SLF4J");
}
return describeMatch(context, stringFormat.suggestFlattening("{}", state));
}
private static boolean isNonFinalLocalVariable(Tree tree) {
Symbol symbol = ASTHelpers.getSymbol(tree);
return symbol instanceof VarSymbol
&& symbol.owner instanceof MethodSymbol
&& !ASTHelpers.isConsideredFinal(symbol);
}
private Description createSimplificationSuggestion(MethodInvocationTree context, String library) {
return buildDescription(context)
.setMessage(
"%s (assuming that %s's simplified formatting support suffices)"
.formatted(message(), library))
.build();
}
/** Description of a string format expression. */
@AutoValue
abstract static class StringFormatExpression {
/** The full string format expression. */
abstract MethodInvocationTree expression();
/** The format string expression. */
abstract Tree formatString();
/** The string format arguments to be plugged into its format string. */
abstract ImmutableList<ExpressionTree> arguments();
/**
* The constant format string, if it contains only {@code %s} placeholders, and the number of
* said placeholders matches the number of format arguments.
*/
abstract Optional<String> simplifiableFormatString();
private SuggestedFix suggestFlattening(String newPlaceholder, VisitorState state) {
return SuggestedFix.replace(
expression(),
Stream.concat(
Stream.of(deriveFormatStringExpression(newPlaceholder, state)),
arguments().stream().map(arg -> SourceCode.treeToString(arg, state)))
.collect(joining(", ")));
}
private String deriveFormatStringExpression(String newPlaceholder, VisitorState state) {
String formatString =
String.format(
simplifiableFormatString()
.orElseThrow(() -> new VerifyException("Format string cannot be simplified")),
Collections.nCopies(arguments().size(), newPlaceholder).toArray());
/*
* If the suggested replacement format string is the same as the original, then use the
* expression's existing source code representation. This way string constant references are
* not unnecessarily replaced.
*/
return formatString.equals(ASTHelpers.constValue(formatString(), String.class))
? SourceCode.treeToString(formatString(), state)
: SourceCode.toStringConstantExpression(formatString, state);
}
private static Optional<StringFormatExpression> tryCreate(
MethodInvocationTree tree, VisitorState state) {
if (INSTANCE_FORMAT_STRING.matches(tree, state)) {
return Optional.of(
create(
tree,
requireNonNull(ASTHelpers.getReceiver(tree), "Receiver unexpectedly absent"),
ImmutableList.copyOf(tree.getArguments()),
state));
}
if (STATIC_FORMAT_STRING.matches(tree, state)) {
List<? extends ExpressionTree> arguments = tree.getArguments();
int argOffset = LOCALE.matches(arguments.get(0), state) ? 1 : 0;
return Optional.of(
create(
tree,
arguments.get(argOffset),
ImmutableList.copyOf(arguments.subList(argOffset + 1, arguments.size())),
state));
}
return Optional.empty();
}
private static StringFormatExpression create(
MethodInvocationTree expression,
Tree formatString,
ImmutableList<ExpressionTree> arguments,
VisitorState state) {
return new AutoValue_EagerStringFormatting_StringFormatExpression(
expression,
formatString,
arguments,
Optional.ofNullable(ASTHelpers.constValue(formatString, String.class))
.filter(template -> isSimplifiable(template, arguments, state)));
}
private static boolean isSimplifiable(
String formatString, ImmutableList<ExpressionTree> arguments, VisitorState state) {
if (arguments.stream().anyMatch(arg -> FORMATTABLE.matches(arg, state))) {
/* `Formattable` arguments can have arbitrary format semantics. */
return false;
}
@Var int placeholderCount = 0;
for (int p = formatString.indexOf('%'); p != -1; p = formatString.indexOf('%', p + 2)) {
if (p == formatString.length() - 1) {
/* Malformed format string with trailing `%`. */
return false;
}
char modifier = formatString.charAt(p + 1);
if (modifier == 's') {
placeholderCount++;
} else if (modifier != '%') {
/* Only `%s` and `%%` (a literal `%`) are supported. */
return false;
}
}
return placeholderCount == arguments.size();
}
}
}

View File

@@ -113,7 +113,7 @@ public final class ExplicitArgumentEnumeration extends BugChecker
.put(OBJECT_ENUMERABLE_ASSERT, "doesNotContainAnyElementsOf", "doesNotContain")
.put(OBJECT_ENUMERABLE_ASSERT, "hasSameElementsAs", "containsOnly")
.put(STEP_VERIFIER_STEP, "expectNextSequence", "expectNext")
.build();
.buildOrThrow();
/** Instantiates a new {@link ExplicitArgumentEnumeration} instance. */
public ExplicitArgumentEnumeration() {}

View File

@@ -30,6 +30,7 @@ import com.sun.source.tree.Tree;
import com.sun.source.util.TreeScanner;
import com.sun.tools.javac.code.Symbol;
import java.time.Clock;
import java.time.InstantSource;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.Locale;
@@ -69,6 +70,7 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
ImmutableSet.of(
ASTHelpers.class.getCanonicalName(),
Clock.class.getCanonicalName(),
InstantSource.class.getCanonicalName(),
Strings.class.getCanonicalName(),
VisitorState.class.getCanonicalName(),
ZoneOffset.class.getCanonicalName(),
@@ -129,6 +131,7 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
"builder",
"copyOf",
"create",
"EPOCH",
"from",
"getDefaultInstance",
"INSTANCE",
@@ -182,7 +185,7 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
}
}
return imports.build();
return imports.buildOrThrow();
}
private static boolean shouldNotBeStaticallyImported(String type, String member) {

View File

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

View File

@@ -54,7 +54,7 @@ public final class SpringMvcAnnotation extends BugChecker implements AnnotationT
.put("PATCH", "PatchMapping")
.put("POST", "PostMapping")
.put("PUT", "PutMapping")
.build();
.buildOrThrow();
/** Instantiates a new {@link SpringMvcAnnotation} instance. */
public SpringMvcAnnotation() {}

View File

@@ -16,10 +16,12 @@ import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MemberReferenceTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MemberReferenceTree;
import com.sun.source.tree.MethodInvocationTree;
import java.time.Clock;
import java.time.Instant;
@@ -41,7 +43,8 @@ import java.time.ZonedDateTime;
linkType = CUSTOM,
severity = WARNING,
tags = FRAGILE_CODE)
public final class TimeZoneUsage extends BugChecker implements MethodInvocationTreeMatcher {
public final class TimeZoneUsage extends BugChecker
implements MethodInvocationTreeMatcher, MemberReferenceTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> BANNED_TIME_METHOD =
anyOf(
@@ -59,6 +62,10 @@ public final class TimeZoneUsage extends BugChecker implements MethodInvocationT
"tickMillis",
"tickMinutes",
"tickSeconds"),
staticMethod()
.onClassAny(Instant.class.getCanonicalName())
.named("now")
.withNoParameters(),
staticMethod()
.onClassAny(
LocalDate.class.getCanonicalName(),
@@ -67,17 +74,22 @@ public final class TimeZoneUsage extends BugChecker implements MethodInvocationT
OffsetDateTime.class.getCanonicalName(),
OffsetTime.class.getCanonicalName(),
ZonedDateTime.class.getCanonicalName())
.named("now"),
staticMethod()
.onClassAny(Instant.class.getCanonicalName())
.named("now")
.withNoParameters());
.named("now"));
/** Instantiates a new {@link TimeZoneUsage} instance. */
public TimeZoneUsage() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
return getDescription(tree, state);
}
@Override
public Description matchMemberReference(MemberReferenceTree tree, VisitorState state) {
return getDescription(tree, state);
}
private Description getDescription(ExpressionTree tree, VisitorState state) {
return BANNED_TIME_METHOD.matches(tree, state)
? buildDescription(tree).build()
: Description.NO_MATCH;

View File

@@ -18,6 +18,7 @@ final class AssertJCharSequenceRules {
@BeforeTemplate
void before(CharSequence charSequence) {
Refaster.anyOf(
assertThat(charSequence.isEmpty()).isTrue(),
assertThat(charSequence.length()).isEqualTo(0L),
assertThat(charSequence.length()).isNotPositive());
}
@@ -33,6 +34,7 @@ final class AssertJCharSequenceRules {
@BeforeTemplate
AbstractAssert<?, ?> before(CharSequence charSequence) {
return Refaster.anyOf(
assertThat(charSequence.isEmpty()).isFalse(),
assertThat(charSequence.length()).isNotEqualTo(0),
assertThat(charSequence.length()).isPositive());
}

View File

@@ -5,6 +5,9 @@ import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.Collection;
import org.assertj.core.api.AbstractIntegerAssert;
import org.assertj.core.api.AbstractIterableAssert;
import org.assertj.core.api.AbstractIterableSizeAssert;
import org.assertj.core.api.EnumerableAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@@ -21,6 +24,11 @@ final class AssertJEnumerableRules {
enumAssert.hasSizeLessThan(1));
}
@BeforeTemplate
void before(AbstractIterableAssert<?, ?, E, ?> enumAssert) {
enumAssert.size().isNotPositive();
}
@AfterTemplate
void after(EnumerableAssert<?, E> enumAssert) {
enumAssert.isEmpty();
@@ -34,30 +42,113 @@ final class AssertJEnumerableRules {
enumAssert.hasSizeGreaterThan(0), enumAssert.hasSizeGreaterThanOrEqualTo(1));
}
@BeforeTemplate
AbstractIntegerAssert<?> before(AbstractIterableAssert<?, ?, E, ?> enumAssert) {
return Refaster.anyOf(enumAssert.size().isNotEqualTo(0), enumAssert.size().isPositive());
}
@AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert) {
return enumAssert.isNotEmpty();
}
}
static final class EnumerableAssertHasSameSizeAs<S, T> {
static final class EnumerableAssertHasSize<E> {
@BeforeTemplate
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, Iterable<T> iterable) {
AbstractIterableSizeAssert<?, ?, E, ?> before(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isEqualTo(size);
}
@AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
return enumAssert.hasSize(size);
}
}
static final class EnumerableAssertHasSizeLessThan<E> {
@BeforeTemplate
AbstractIterableSizeAssert<?, ?, E, ?> before(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isLessThan(size);
}
@AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
return enumAssert.hasSizeLessThan(size);
}
}
static final class EnumerableAssertHasSizeLessThanOrEqualTo<E> {
@BeforeTemplate
AbstractIterableSizeAssert<?, ?, E, ?> before(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isLessThanOrEqualTo(size);
}
@AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
return enumAssert.hasSizeLessThanOrEqualTo(size);
}
}
static final class EnumerableAssertHasSizeGreaterThan<E> {
@BeforeTemplate
AbstractIterableSizeAssert<?, ?, E, ?> before(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isGreaterThan(size);
}
@AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
return enumAssert.hasSizeGreaterThan(size);
}
}
static final class EnumerableAssertHasSizeGreaterThanOrEqualTo<E> {
@BeforeTemplate
AbstractIterableSizeAssert<?, ?, E, ?> before(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isGreaterThanOrEqualTo(size);
}
@AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
return enumAssert.hasSizeGreaterThanOrEqualTo(size);
}
}
static final class EnumerableAssertHasSizeBetween<E> {
@BeforeTemplate
AbstractIterableSizeAssert<?, ?, E, ?> before(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int lower, int upper) {
return enumAssert.size().isBetween(lower, upper);
}
@AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int lower, int upper) {
return enumAssert.hasSizeBetween(lower, upper);
}
}
static final class EnumerableAssertHasSameSizeAs<S, E> {
@BeforeTemplate
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, Iterable<E> iterable) {
return enumAssert.hasSize(Iterables.size(iterable));
}
@BeforeTemplate
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, Collection<T> iterable) {
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, Collection<E> iterable) {
return enumAssert.hasSize(iterable.size());
}
@BeforeTemplate
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, T[] iterable) {
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, E[] iterable) {
return enumAssert.hasSize(iterable.length);
}
@AfterTemplate
EnumerableAssert<?, S> after(EnumerableAssert<?, S> enumAssert, Iterable<T> iterable) {
EnumerableAssert<?, S> after(EnumerableAssert<?, S> enumAssert, Iterable<E> iterable) {
return enumAssert.hasSameSizeAs(iterable);
}
}

View File

@@ -0,0 +1,90 @@
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.Iterables;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Collection;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractIntegerAssert;
import org.assertj.core.api.IterableAssert;
import org.assertj.core.api.ObjectAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@OnlineDocumentation
final class AssertJIterableRules {
private AssertJIterableRules() {}
static final class AssertThatIterableIsEmpty<E> {
@BeforeTemplate
void before(Iterable<E> iterable) {
assertThat(iterable.iterator()).isExhausted();
}
@BeforeTemplate
void before(Collection<E> iterable) {
assertThat(iterable.isEmpty()).isTrue();
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Collection<E> iterable) {
assertThat(iterable).isEmpty();
}
}
static final class AssertThatIterableIsNotEmpty<E> {
@BeforeTemplate
AbstractAssert<?, ?> before(Iterable<E> iterable) {
return assertThat(iterable.iterator()).hasNext();
}
@BeforeTemplate
AbstractAssert<?, ?> before(Collection<E> iterable) {
return assertThat(iterable.isEmpty()).isFalse();
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
IterableAssert<E> after(Iterable<E> iterable) {
return assertThat(iterable).isNotEmpty();
}
}
static final class AssertThatIterableSize<E> {
@BeforeTemplate
AbstractIntegerAssert<?> before(Iterable<E> iterable) {
return assertThat(Iterables.size(iterable));
}
@BeforeTemplate
AbstractIntegerAssert<?> before(Collection<E> iterable) {
return assertThat(iterable.size());
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractIntegerAssert<?> after(Iterable<E> iterable) {
return assertThat(iterable).size();
}
}
// XXX: In practice this rule isn't very useful, as it only matches invocations of
// `assertThat(E)`. In most cases a more specific overload of `assertThat` is invoked, in which
// case this rule won't match. Look into a more robust approach.
static final class AssertThatIterableHasOneElementEqualTo<S, E extends S> {
@BeforeTemplate
ObjectAssert<S> before(Iterable<S> iterable, E element) {
return assertThat(Iterables.getOnlyElement(iterable)).isEqualTo(element);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
IterableAssert<S> after(Iterable<S> iterable, E element) {
return assertThat(iterable).containsExactly(element);
}
}
}

View File

@@ -0,0 +1,43 @@
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Iterator;
import org.assertj.core.api.AbstractBooleanAssert;
import org.assertj.core.api.IteratorAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@OnlineDocumentation
final class AssertJIteratorRules {
private AssertJIteratorRules() {}
static final class AssertThatHasNext<T> {
@BeforeTemplate
AbstractBooleanAssert<?> before(Iterator<T> iterator) {
return assertThat(iterator.hasNext()).isTrue();
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
IteratorAssert<T> after(Iterator<T> iterator) {
return assertThat(iterator).hasNext();
}
}
static final class AssertThatIsExhausted<T> {
@BeforeTemplate
AbstractBooleanAssert<?> before(Iterator<T> iterator) {
return assertThat(iterator.hasNext()).isFalse();
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
IteratorAssert<T> after(Iterator<T> iterator) {
return assertThat(iterator).isExhausted();
}
}
}

View File

@@ -11,7 +11,6 @@ import com.google.errorprone.refaster.annotation.Matches;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractBooleanAssert;
import org.assertj.core.api.AbstractCollectionAssert;
@@ -182,13 +181,13 @@ final class AssertJMapRules {
static final class AssertThatMapContainsOnlyKeys<K, V> {
@BeforeTemplate
AbstractCollectionAssert<?, Collection<? extends K>, K, ?> before(
Map<K, V> map, Set<? extends K> keys) {
Map<K, V> map, Iterable<? extends K> keys) {
return assertThat(map.keySet()).hasSameElementsAs(keys);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
MapAssert<K, V> after(Map<K, V> map, Set<? extends K> keys) {
MapAssert<K, V> after(Map<K, V> map, Iterable<? extends K> keys) {
return assertThat(map).containsOnlyKeys(keys);
}
}

View File

@@ -3,7 +3,6 @@ package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multiset;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
@@ -12,7 +11,6 @@ import com.google.errorprone.refaster.annotation.Matches;
import com.google.errorprone.refaster.annotation.NotMatches;
import com.google.errorprone.refaster.annotation.Repeated;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.OptionalDouble;
@@ -22,9 +20,7 @@ import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Stream;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractCollectionAssert;
import org.assertj.core.api.AbstractComparableAssert;
import org.assertj.core.api.AbstractDoubleAssert;
import org.assertj.core.api.AbstractIntegerAssert;
import org.assertj.core.api.AbstractLongAssert;
@@ -254,120 +250,19 @@ final class AssertJRules {
}
}
//
// Iterable
//
static final class AssertThatIterableIsEmpty<E> {
@BeforeTemplate
void before(Iterable<E> iterable) {
Refaster.anyOf(
assertThat(iterable).hasSize(0),
assertThat(iterable.iterator().hasNext()).isFalse(),
assertThat(Iterables.size(iterable)).isEqualTo(0L),
assertThat(Iterables.size(iterable)).isNotPositive());
}
@BeforeTemplate
void before(Collection<E> iterable) {
Refaster.anyOf(
assertThat(iterable.isEmpty()).isTrue(),
assertThat(iterable.size()).isEqualTo(0L),
assertThat(iterable.size()).isNotPositive());
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Collection<E> iterable) {
assertThat(iterable).isEmpty();
}
}
static final class AssertThatIterableIsNotEmpty<E> {
@BeforeTemplate
AbstractAssert<?, ?> before(Iterable<E> iterable) {
return Refaster.anyOf(
assertThat(iterable.iterator().hasNext()).isTrue(),
assertThat(Iterables.size(iterable)).isNotEqualTo(0),
assertThat(Iterables.size(iterable)).isPositive());
}
@BeforeTemplate
AbstractAssert<?, ?> before(Collection<E> iterable) {
return Refaster.anyOf(
assertThat(iterable.isEmpty()).isFalse(),
assertThat(iterable.size()).isNotEqualTo(0),
assertThat(iterable.size()).isPositive());
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
IterableAssert<E> after(Iterable<E> iterable) {
return assertThat(iterable).isNotEmpty();
}
}
static final class AssertThatIterableHasSize<E> {
@BeforeTemplate
AbstractIntegerAssert<?> before(Iterable<E> iterable, int length) {
return assertThat(Iterables.size(iterable)).isEqualTo(length);
}
@BeforeTemplate
AbstractIntegerAssert<?> before(Collection<E> iterable, int length) {
return assertThat(iterable.size()).isEqualTo(length);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
IterableAssert<E> after(Iterable<E> iterable, int length) {
return assertThat(iterable).hasSize(length);
}
}
static final class AssertThatIterableHasOneElementEqualTo<S, T extends S> {
@BeforeTemplate
ObjectAssert<S> before(Iterable<S> iterable, T element) {
return assertThat(Iterables.getOnlyElement(iterable)).isEqualTo(element);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
IterableAssert<S> after(Iterable<S> iterable, T element) {
return assertThat(iterable).containsExactly(element);
}
}
// XXX: This overload is here because `assertThat` has an overload for `Comparable` types.
// Unfortunately this still doesn't convince Refaster to match this rule in the context of
// Comparable types. Figure out why! Note that this also affects the `AssertThatOptional` rule.
static final class AssertThatIterableHasOneComparableElementEqualTo<
S extends Comparable<? super S>, T extends S> {
@BeforeTemplate
AbstractComparableAssert<?, S> before(Iterable<S> iterable, T element) {
return assertThat(Iterables.getOnlyElement(iterable)).isEqualTo(element);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
IterableAssert<S> after(Iterable<S> iterable, T element) {
return assertThat(iterable).containsExactly(element);
}
}
//
// List
//
static final class AssertThatListsAreEqual<S, T extends S> {
@BeforeTemplate
ListAssert<S> before(List<S> list1, List<T> list2) {
ListAssert<S> before(List<S> list1, Iterable<T> list2) {
return assertThat(list1).isEqualTo(list2);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(List<S> list1, List<T> list2) {
ListAssert<S> after(List<S> list1, Iterable<T> list2) {
return assertThat(list1).containsExactlyElementsOf(list2);
}
}
@@ -378,7 +273,7 @@ final class AssertJRules {
static final class AssertThatSetsAreEqual<S, T extends S> {
@BeforeTemplate
AbstractCollectionAssert<?, ?, S, ?> before(Set<S> set1, Set<T> set2) {
AbstractCollectionAssert<?, ?, S, ?> before(Set<S> set1, Iterable<T> set2) {
return Refaster.anyOf(
assertThat(set1).isEqualTo(set2),
assertThat(set1).containsExactlyInAnyOrderElementsOf(set2));
@@ -386,7 +281,7 @@ final class AssertJRules {
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractCollectionAssert<?, ?, S, ?> after(Set<S> set1, Set<T> set2) {
AbstractCollectionAssert<?, ?, S, ?> after(Set<S> set1, Iterable<T> set2) {
return assertThat(set1).hasSameElementsAs(set2);
}
}
@@ -397,13 +292,13 @@ final class AssertJRules {
static final class AssertThatMultisetsAreEqual<S, T extends S> {
@BeforeTemplate
AbstractCollectionAssert<?, ?, S, ?> before(Multiset<S> multiset1, Multiset<T> multiset2) {
AbstractCollectionAssert<?, ?, S, ?> before(Multiset<S> multiset1, Iterable<T> multiset2) {
return assertThat(multiset1).isEqualTo(multiset2);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractCollectionAssert<?, ?, S, ?> after(Multiset<S> multiset1, Multiset<T> multiset2) {
AbstractCollectionAssert<?, ?, S, ?> after(Multiset<S> multiset1, Iterable<T> multiset2) {
return assertThat(multiset1).containsExactlyInAnyOrderElementsOf(multiset2);
}
}

View File

@@ -12,6 +12,7 @@ import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractBooleanAssert;
import org.assertj.core.api.AbstractStringAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@@ -31,19 +32,6 @@ final class AssertJStringRules {
}
}
static final class AssertThatStringIsEmpty {
@BeforeTemplate
void before(String string) {
assertThat(string.isEmpty()).isTrue();
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(String string) {
assertThat(string).isEmpty();
}
}
static final class AbstractStringAssertStringIsNotEmpty {
@BeforeTemplate
AbstractStringAssert<?> before(AbstractStringAssert<?> stringAssert) {
@@ -56,16 +44,29 @@ final class AssertJStringRules {
}
}
static final class AssertThatStringIsNotEmpty {
static final class AssertThatStringContains {
@BeforeTemplate
AbstractAssert<?, ?> before(String string) {
return assertThat(string.isEmpty()).isFalse();
AbstractBooleanAssert<?> before(String string, CharSequence substring) {
return assertThat(string.contains(substring)).isTrue();
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractAssert<?, ?> after(String string) {
return assertThat(string).isNotEmpty();
AbstractStringAssert<?> after(String string, CharSequence substring) {
return assertThat(string).contains(substring);
}
}
static final class AssertThatStringDoesNotContain {
@BeforeTemplate
AbstractBooleanAssert<?> before(String string, CharSequence substring) {
return assertThat(string.contains(substring)).isFalse();
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractStringAssert<?> after(String string, CharSequence substring) {
return assertThat(string).doesNotContain(substring);
}
}

View File

@@ -121,18 +121,18 @@ final class AssortedRules {
*/
static final class DisjointSets<T> {
@BeforeTemplate
boolean before(Set<T> set1, Set<T> set2) {
return Sets.intersection(set1, set2).isEmpty();
boolean before(Set<T> collection1, Set<T> collection2) {
return Sets.intersection(collection1, collection2).isEmpty();
}
@BeforeTemplate
boolean before2(Set<T> set1, Set<T> set2) {
return set1.stream().noneMatch(set2::contains);
boolean before2(Collection<T> collection1, Collection<T> collection2) {
return collection1.stream().noneMatch(collection2::contains);
}
@AfterTemplate
boolean after(Set<T> set1, Set<T> set2) {
return disjoint(set1, set2);
boolean after(Collection<T> collection1, Collection<T> collection2) {
return disjoint(collection1, collection2);
}
}

View File

@@ -0,0 +1,33 @@
package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster rules related to expressions dealing with {@link CharSequence}s. */
@OnlineDocumentation
final class CharSequenceRules {
private CharSequenceRules() {}
/**
* Prefer {@link CharSequence#isEmpty()} over alternatives that consult the char sequence's
* length.
*/
// XXX: Drop this rule once we (and OpenRewrite) no longer support projects targeting Java 14 or
// below.
static final class CharSequenceIsEmpty {
@BeforeTemplate
boolean before(CharSequence charSequence) {
return Refaster.anyOf(
charSequence.length() == 0, charSequence.length() <= 0, charSequence.length() < 1);
}
@AfterTemplate
@AlsoNegation
boolean after(CharSequence charSequence) {
return charSequence.isEmpty();
}
}
}

View File

@@ -158,14 +158,14 @@ final class CollectionRules {
}
}
static final class SetRemoveAllCollection<T, S extends T> {
static final class CollectionRemoveAllFromCollectionBlock<T, S extends T> {
@BeforeTemplate
void before(Set<T> removeFrom, Collection<S> elementsToRemove) {
void before(Collection<T> removeFrom, Collection<S> elementsToRemove) {
elementsToRemove.forEach(removeFrom::remove);
}
@BeforeTemplate
void before2(Set<T> removeFrom, Collection<S> elementsToRemove) {
void before2(Collection<T> removeFrom, Collection<S> elementsToRemove) {
for (T element : elementsToRemove) {
removeFrom.remove(element);
}
@@ -175,14 +175,14 @@ final class CollectionRules {
// that this is supported out of the box. After doing so, also drop the `S extends T` type
// constraint; ideally this check applies to any `S`.
@BeforeTemplate
void before3(Set<T> removeFrom, Collection<S> elementsToRemove) {
void before3(Collection<T> removeFrom, Collection<S> elementsToRemove) {
for (S element : elementsToRemove) {
removeFrom.remove(element);
}
}
@AfterTemplate
void after(Set<T> removeFrom, Collection<S> elementsToRemove) {
void after(Collection<T> removeFrom, Collection<S> elementsToRemove) {
removeFrom.removeAll(elementsToRemove);
}
}

View File

@@ -36,8 +36,7 @@ final class ImmutableListMultimapRules {
* Prefer {@link ImmutableListMultimap#builder()} over the associated constructor on constructions
* that produce a less-specific type.
*/
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
// https://github.com/google/error-prone/pull/2706.
// XXX: This rule may drop generic type information, leading to non-compilable code.
static final class ImmutableListMultimapBuilder<K, V> {
@BeforeTemplate
ImmutableMultimap.Builder<K, V> before() {

View File

@@ -28,8 +28,7 @@ final class ImmutableListRules {
private ImmutableListRules() {}
/** Prefer {@link ImmutableList#builder()} over the associated constructor. */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
// https://github.com/google/error-prone/pull/2706.
// XXX: This rule may drop generic type information, leading to non-compilable code.
static final class ImmutableListBuilder<T> {
@BeforeTemplate
ImmutableList.Builder<T> before() {

View File

@@ -15,6 +15,7 @@ import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Matches;
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.Repeated;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Collection;
import java.util.Iterator;
@@ -31,8 +32,7 @@ final class ImmutableMapRules {
private ImmutableMapRules() {}
/** Prefer {@link ImmutableMap#builder()} over the associated constructor. */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
// https://github.com/google/error-prone/pull/2706.
// XXX: This rule may drop generic type information, leading to non-compilable code.
static final class ImmutableMapBuilder<K, V> {
@BeforeTemplate
ImmutableMap.Builder<K, V> before() {
@@ -45,12 +45,28 @@ final class ImmutableMapRules {
}
}
/**
* Prefer {@link ImmutableMap.Builder#buildOrThrow()} over the less explicit {@link
* ImmutableMap.Builder#build()}.
*/
static final class ImmutableMapBuilderBuildOrThrow<K, V> {
@BeforeTemplate
ImmutableMap<K, V> before(ImmutableMap.Builder<K, V> builder) {
return builder.build();
}
@AfterTemplate
ImmutableMap<K, V> after(ImmutableMap.Builder<K, V> builder) {
return builder.buildOrThrow();
}
}
/** Prefer {@link ImmutableMap#of(Object, Object)} over more contrived alternatives. */
static final class EntryToImmutableMap<K, V> {
@BeforeTemplate
ImmutableMap<K, V> before(Map.Entry<? extends K, ? extends V> entry) {
return Refaster.anyOf(
ImmutableMap.<K, V>builder().put(entry).build(),
ImmutableMap.<K, V>builder().put(entry).buildOrThrow(),
Stream.of(entry).collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)));
}
@@ -105,16 +121,17 @@ final class ImmutableMapRules {
/** Prefer {@link ImmutableMap#copyOf(Iterable)} over more contrived alternatives. */
static final class EntryIterableToImmutableMap<K, V> {
@BeforeTemplate
ImmutableMap<K, V> before(Map<? extends K, ? extends V> iterable) {
Map<K, V> before(Map<? extends K, ? extends V> iterable) {
return Refaster.anyOf(
ImmutableMap.copyOf(iterable.entrySet()),
ImmutableMap.<K, V>builder().putAll(iterable).build());
ImmutableMap.<K, V>builder().putAll(iterable).buildOrThrow(),
Map.copyOf(iterable));
}
@BeforeTemplate
ImmutableMap<K, V> before(Iterable<? extends Map.Entry<? extends K, ? extends V>> iterable) {
return Refaster.anyOf(
ImmutableMap.<K, V>builder().putAll(iterable).build(),
ImmutableMap.<K, V>builder().putAll(iterable).buildOrThrow(),
Streams.stream(iterable).collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)));
}
@@ -140,8 +157,6 @@ final class ImmutableMapRules {
@Placeholder(allowsIdentity = true)
abstract V valueFunction(@MayOptionallyUse E element);
// XXX: We could add variants in which the entry is created some other way, but we have another
// rule that covers canonicalization to `Map.entry`.
@BeforeTemplate
ImmutableMap<K, V> before(Stream<E> stream) {
return stream
@@ -225,7 +240,11 @@ final class ImmutableMapRules {
static final class ImmutableMapOf<K, V> {
@BeforeTemplate
Map<K, V> before() {
return Refaster.anyOf(ImmutableMap.<K, V>builder().build(), emptyMap(), Map.of());
return Refaster.anyOf(
ImmutableMap.<K, V>builder().buildOrThrow(),
ImmutableMap.ofEntries(),
emptyMap(),
Map.of());
}
@AfterTemplate
@@ -244,7 +263,10 @@ final class ImmutableMapRules {
@BeforeTemplate
Map<K, V> before(K k1, V v1) {
return Refaster.anyOf(
ImmutableMap.<K, V>builder().put(k1, v1).build(), singletonMap(k1, v1), Map.of(k1, v1));
ImmutableMap.<K, V>builder().put(k1, v1).buildOrThrow(),
ImmutableMap.ofEntries(Map.entry(k1, v1)),
singletonMap(k1, v1),
Map.of(k1, v1));
}
@AfterTemplate
@@ -262,7 +284,8 @@ final class ImmutableMapRules {
static final class ImmutableMapOf2<K, V> {
@BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2) {
return Map.of(k1, v1, k2, v2);
return Refaster.anyOf(
ImmutableMap.ofEntries(Map.entry(k1, v1), Map.entry(k2, v2)), Map.of(k1, v1, k2, v2));
}
@AfterTemplate
@@ -280,7 +303,9 @@ final class ImmutableMapRules {
static final class ImmutableMapOf3<K, V> {
@BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3) {
return Map.of(k1, v1, k2, v2, k3, v3);
return Refaster.anyOf(
ImmutableMap.ofEntries(Map.entry(k1, v1), Map.entry(k2, v2), Map.entry(k3, v3)),
Map.of(k1, v1, k2, v2, k3, v3));
}
@AfterTemplate
@@ -300,7 +325,10 @@ final class ImmutableMapRules {
static final class ImmutableMapOf4<K, V> {
@BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
return Map.of(k1, v1, k2, v2, k3, v3, k4, v4);
return Refaster.anyOf(
ImmutableMap.ofEntries(
Map.entry(k1, v1), Map.entry(k2, v2), Map.entry(k3, v3), Map.entry(k4, v4)),
Map.of(k1, v1, k2, v2, k3, v3, k4, v4));
}
@AfterTemplate
@@ -320,7 +348,14 @@ final class ImmutableMapRules {
static final class ImmutableMapOf5<K, V> {
@BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
return Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
return Refaster.anyOf(
ImmutableMap.ofEntries(
Map.entry(k1, v1),
Map.entry(k2, v2),
Map.entry(k3, v3),
Map.entry(k4, v4),
Map.entry(k5, v5)),
Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5));
}
@AfterTemplate
@@ -338,14 +373,14 @@ final class ImmutableMapRules {
abstract boolean keyFilter(@MayOptionallyUse K key);
@BeforeTemplate
ImmutableMap<K, V> before(ImmutableMap<K, V> map) {
ImmutableMap<K, V> before(Map<K, V> map) {
return map.entrySet().stream()
.filter(e -> keyFilter(e.getKey()))
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
}
@AfterTemplate
ImmutableMap<K, V> after(ImmutableMap<K, V> map) {
ImmutableMap<K, V> after(Map<K, V> map) {
return ImmutableMap.copyOf(Maps.filterKeys(map, k -> keyFilter(k)));
}
}
@@ -359,18 +394,34 @@ final class ImmutableMapRules {
abstract boolean valueFilter(@MayOptionallyUse V value);
@BeforeTemplate
ImmutableMap<K, V> before(ImmutableMap<K, V> map) {
ImmutableMap<K, V> before(Map<K, V> map) {
return map.entrySet().stream()
.filter(e -> valueFilter(e.getValue()))
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
}
@AfterTemplate
ImmutableMap<K, V> after(ImmutableMap<K, V> map) {
ImmutableMap<K, V> after(Map<K, V> map) {
return ImmutableMap.copyOf(Maps.filterValues(map, v -> valueFilter(v)));
}
}
/**
* Prefer {@link ImmutableMap#ofEntries(Map.Entry[])} over alternatives that don't communicate the
* immutability of the resulting map at the type level.
*/
static final class ImmutableMapOfEntries<K, V> {
@BeforeTemplate
Map<K, V> before(@Repeated Map.Entry<? extends K, ? extends V> entries) {
return Map.ofEntries(entries);
}
@AfterTemplate
ImmutableMap<K, V> after(@Repeated Map.Entry<? extends K, ? extends V> entries) {
return ImmutableMap.ofEntries(entries);
}
}
// XXX: Add a rule for this:
// Maps.transformValues(streamOfEntries.collect(groupBy(fun)), ImmutableMap::copyOf)
// ->

View File

@@ -21,8 +21,7 @@ final class ImmutableMultisetRules {
private ImmutableMultisetRules() {}
/** Prefer {@link ImmutableMultiset#builder()} over the associated constructor. */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
// https://github.com/google/error-prone/pull/2706.
// XXX: This rule may drop generic type information, leading to non-compilable code.
static final class ImmutableMultisetBuilder<T> {
@BeforeTemplate
ImmutableMultiset.Builder<T> before() {

View File

@@ -29,8 +29,7 @@ final class ImmutableSetMultimapRules {
private ImmutableSetMultimapRules() {}
/** Prefer {@link ImmutableSetMultimap#builder()} over the associated constructor. */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
// https://github.com/google/error-prone/pull/2706.
// XXX: This rule may drop generic type information, leading to non-compilable code.
static final class ImmutableSetMultimapBuilder<K, V> {
@BeforeTemplate
ImmutableSetMultimap.Builder<K, V> before() {

View File

@@ -29,8 +29,7 @@ final class ImmutableSetRules {
private ImmutableSetRules() {}
/** Prefer {@link ImmutableSet#builder()} over the associated constructor. */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
// https://github.com/google/error-prone/pull/2706.
// XXX: This rule may drop generic type information, leading to non-compilable code.
static final class ImmutableSetBuilder<T> {
@BeforeTemplate
ImmutableSet.Builder<T> before() {

View File

@@ -37,8 +37,7 @@ final class ImmutableSortedMapRules {
* Prefer {@link ImmutableSortedMap#naturalOrder()} over the alternative that requires explicitly
* providing the {@link Comparator}.
*/
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
// https://github.com/google/error-prone/pull/2706.
// XXX: This rule may drop generic type information, leading to non-compilable code.
static final class ImmutableSortedMapNaturalOrderBuilder<K extends Comparable<? super K>, V> {
@BeforeTemplate
ImmutableSortedMap.Builder<K, V> before() {
@@ -55,8 +54,7 @@ final class ImmutableSortedMapRules {
* Prefer {@link ImmutableSortedMap#reverseOrder()} over the alternative that requires explicitly
* providing the {@link Comparator}.
*/
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
// https://github.com/google/error-prone/pull/2706.
// XXX: This rule may drop generic type information, leading to non-compilable code.
static final class ImmutableSortedMapReverseOrderBuilder<K extends Comparable<? super K>, V> {
@BeforeTemplate
ImmutableSortedMap.Builder<K, V> before() {
@@ -73,7 +71,7 @@ final class ImmutableSortedMapRules {
static final class EmptyImmutableSortedMap<K extends Comparable<? super K>, V> {
@BeforeTemplate
ImmutableSortedMap<K, V> before() {
return ImmutableSortedMap.<K, V>naturalOrder().build();
return ImmutableSortedMap.<K, V>naturalOrder().buildOrThrow();
}
@AfterTemplate
@@ -91,7 +89,7 @@ final class ImmutableSortedMapRules {
static final class PairToImmutableSortedMap<K extends Comparable<? super K>, V> {
@BeforeTemplate
ImmutableSortedMap<K, V> before(K key, V value) {
return ImmutableSortedMap.<K, V>naturalOrder().put(key, value).build();
return ImmutableSortedMap.<K, V>naturalOrder().put(key, value).buildOrThrow();
}
@AfterTemplate
@@ -107,7 +105,7 @@ final class ImmutableSortedMapRules {
@BeforeTemplate
ImmutableSortedMap<K, V> before(Map.Entry<? extends K, ? extends V> entry) {
return Refaster.anyOf(
ImmutableSortedMap.<K, V>naturalOrder().put(entry).build(),
ImmutableSortedMap.<K, V>naturalOrder().put(entry).buildOrThrow(),
Stream.of(entry)
.collect(
toImmutableSortedMap(naturalOrder(), Map.Entry::getKey, Map.Entry::getValue)));
@@ -128,7 +126,7 @@ final class ImmutableSortedMapRules {
return Refaster.anyOf(
ImmutableSortedMap.copyOf(iterable, naturalOrder()),
ImmutableSortedMap.copyOf(iterable.entrySet()),
ImmutableSortedMap.<K, V>naturalOrder().putAll(iterable).build());
ImmutableSortedMap.<K, V>naturalOrder().putAll(iterable).buildOrThrow());
}
@BeforeTemplate
@@ -136,7 +134,7 @@ final class ImmutableSortedMapRules {
Iterable<? extends Map.Entry<? extends K, ? extends V>> iterable) {
return Refaster.anyOf(
ImmutableSortedMap.copyOf(iterable, naturalOrder()),
ImmutableSortedMap.<K, V>naturalOrder().putAll(iterable).build(),
ImmutableSortedMap.<K, V>naturalOrder().putAll(iterable).buildOrThrow(),
Streams.stream(iterable)
.collect(
toImmutableSortedMap(

View File

@@ -0,0 +1,114 @@
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableTable.toImmutableTable;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Table;
import com.google.common.collect.Tables;
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.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster rules related to expressions dealing with {@link ImmutableTable}s. */
@OnlineDocumentation
final class ImmutableTableRules {
private ImmutableTableRules() {}
/** Prefer {@link ImmutableTable#builder()} over the associated constructor. */
// XXX: This rule may drop generic type information, leading to non-compilable code.
static final class ImmutableTableBuilder<R, C, V> {
@BeforeTemplate
ImmutableTable.Builder<R, C, V> before() {
return new ImmutableTable.Builder<>();
}
@AfterTemplate
ImmutableTable.Builder<R, C, V> after() {
return ImmutableTable.builder();
}
}
/**
* Prefer {@link ImmutableTable.Builder#buildOrThrow()} over the less explicit {@link
* ImmutableTable.Builder#build()}.
*/
static final class ImmutableTableBuilderBuildOrThrow<R, C, V> {
@BeforeTemplate
ImmutableTable<R, C, V> before(ImmutableTable.Builder<R, C, V> builder) {
return builder.build();
}
@AfterTemplate
ImmutableTable<R, C, V> after(ImmutableTable.Builder<R, C, V> builder) {
return builder.buildOrThrow();
}
}
/** Prefer {@link ImmutableTable#of(Object, Object, Object)} over more contrived alternatives. */
static final class CellToImmutableTable<R, C, V> {
@BeforeTemplate
ImmutableTable<R, C, V> before(Table.Cell<? extends R, ? extends C, ? extends V> cell) {
return Refaster.anyOf(
ImmutableTable.<R, C, V>builder().put(cell).buildOrThrow(),
Stream.of(cell)
.collect(
toImmutableTable(
Table.Cell::getRowKey, Table.Cell::getColumnKey, Table.Cell::getValue)));
}
@AfterTemplate
ImmutableTable<R, C, V> after(Table.Cell<? extends R, ? extends C, ? extends V> cell) {
return ImmutableTable.of(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
}
}
/**
* Don't map a stream's elements to table cells, only to subsequently collect them into an {@link
* ImmutableTable}. The collection can be performed directly.
*/
abstract static class StreamOfCellsToImmutableTable<E, R, C, V> {
@Placeholder(allowsIdentity = true)
abstract R rowFunction(@MayOptionallyUse E element);
@Placeholder(allowsIdentity = true)
abstract C columnFunction(@MayOptionallyUse E element);
@Placeholder(allowsIdentity = true)
abstract V valueFunction(@MayOptionallyUse E element);
@BeforeTemplate
ImmutableTable<R, C, V> before(Stream<E> stream) {
return stream
.map(e -> Tables.immutableCell(rowFunction(e), columnFunction(e), valueFunction(e)))
.collect(
toImmutableTable(
Table.Cell::getRowKey, Table.Cell::getColumnKey, Table.Cell::getValue));
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ImmutableTable<R, C, V> after(Stream<E> stream) {
return stream.collect(
toImmutableTable(e -> rowFunction(e), e -> columnFunction(e), e -> valueFunction(e)));
}
}
/** Prefer {@link ImmutableTable#of()} over more contrived alternatives . */
static final class ImmutableTableOf<R, C, V> {
@BeforeTemplate
ImmutableTable<R, C, V> before() {
return ImmutableTable.<R, C, V>builder().buildOrThrow();
}
@AfterTemplate
ImmutableTable<R, C, V> after() {
return ImmutableTable.of();
}
}
}

View File

@@ -5,6 +5,8 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.fail;
import static org.assertj.core.api.Assertions.offset;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
@@ -34,7 +36,8 @@ import tech.picnic.errorprone.refaster.annotation.TypeMigration;
* <p>Note that, while both libraries throw an {@link AssertionError} in case of an assertion
* failure, the exact subtype used generally differs.
*/
// XXX: Not all JUnit `Assertions` methods have an associated Refaster rule yet; expand this class.
// XXX: The `AssertThat*Array*ContainsExactly*` rules assume that `expected` and `actual` are not
// both `null`.
// XXX: Introduce a `@Matcher` on `Executable` and `ThrowingSupplier` expressions, such that they
// are only matched if they are also compatible with the `ThrowingCallable` functional interface.
// When implementing such a matcher, note that expressions with a non-void return type such as
@@ -50,39 +53,6 @@ import tech.picnic.errorprone.refaster.annotation.TypeMigration;
"assertAll(String, Collection<Executable>)",
"assertAll(String, Executable[])",
"assertAll(String, Stream<Executable>)",
"assertArrayEquals(boolean[], boolean[])",
"assertArrayEquals(boolean[], boolean[], String)",
"assertArrayEquals(boolean[], boolean[], Supplier<String>)",
"assertArrayEquals(byte[], byte[])",
"assertArrayEquals(byte[], byte[], String)",
"assertArrayEquals(byte[], byte[], Supplier<String>)",
"assertArrayEquals(char[], char[])",
"assertArrayEquals(char[], char[], String)",
"assertArrayEquals(char[], char[], Supplier<String>)",
"assertArrayEquals(double[], double[])",
"assertArrayEquals(double[], double[], double)",
"assertArrayEquals(double[], double[], double, String)",
"assertArrayEquals(double[], double[], double, Supplier<String>)",
"assertArrayEquals(double[], double[], String)",
"assertArrayEquals(double[], double[], Supplier<String>)",
"assertArrayEquals(float[], float[])",
"assertArrayEquals(float[], float[], float)",
"assertArrayEquals(float[], float[], float, String)",
"assertArrayEquals(float[], float[], float, Supplier<String>)",
"assertArrayEquals(float[], float[], String)",
"assertArrayEquals(float[], float[], Supplier<String>)",
"assertArrayEquals(int[], int[])",
"assertArrayEquals(int[], int[], String)",
"assertArrayEquals(int[], int[], Supplier<String>)",
"assertArrayEquals(long[], long[])",
"assertArrayEquals(long[], long[], String)",
"assertArrayEquals(long[], long[], Supplier<String>)",
"assertArrayEquals(Object[], Object[])",
"assertArrayEquals(Object[], Object[], String)",
"assertArrayEquals(Object[], Object[], Supplier<String>)",
"assertArrayEquals(short[], short[])",
"assertArrayEquals(short[], short[], String)",
"assertArrayEquals(short[], short[], Supplier<String>)",
"assertEquals(Byte, Byte)",
"assertEquals(Byte, byte)",
"assertEquals(byte, Byte)",
@@ -302,6 +272,436 @@ import tech.picnic.errorprone.refaster.annotation.TypeMigration;
final class JUnitToAssertJRules {
private JUnitToAssertJRules() {}
static final class AssertThatBooleanArrayContainsExactly {
@BeforeTemplate
void before(boolean[] actual, boolean[] expected) {
assertArrayEquals(expected, actual);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(boolean[] actual, boolean[] expected) {
assertThat(actual).containsExactly(expected);
}
}
static final class AssertThatBooleanArrayWithFailMessageContainsExactly {
@BeforeTemplate
void before(boolean[] actual, String message, boolean[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(boolean[] actual, String message, boolean[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatBooleanArrayWithFailMessageSupplierContainsExactly {
@BeforeTemplate
void before(boolean[] actual, Supplier<String> message, boolean[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(boolean[] actual, Supplier<String> message, boolean[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatByteArrayContainsExactly {
@BeforeTemplate
void before(byte[] actual, byte[] expected) {
assertArrayEquals(expected, actual);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(byte[] actual, byte[] expected) {
assertThat(actual).containsExactly(expected);
}
}
static final class AssertThatByteArrayWithFailMessageContainsExactly {
@BeforeTemplate
void before(byte[] actual, String message, byte[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(byte[] actual, String message, byte[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatByteArrayWithFailMessageSupplierContainsExactly {
@BeforeTemplate
void before(byte[] actual, Supplier<String> message, byte[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(byte[] actual, Supplier<String> message, byte[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatCharArrayContainsExactly {
@BeforeTemplate
void before(char[] actual, char[] expected) {
assertArrayEquals(expected, actual);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(char[] actual, char[] expected) {
assertThat(actual).containsExactly(expected);
}
}
static final class AssertThatCharArrayWithFailMessageContainsExactly {
@BeforeTemplate
void before(char[] actual, String message, char[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(char[] actual, String message, char[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatCharArrayWithFailMessageSupplierContainsExactly {
@BeforeTemplate
void before(char[] actual, Supplier<String> message, char[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(char[] actual, Supplier<String> message, char[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatShortArrayContainsExactly {
@BeforeTemplate
void before(short[] actual, short[] expected) {
assertArrayEquals(expected, actual);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(short[] actual, short[] expected) {
assertThat(actual).containsExactly(expected);
}
}
static final class AssertThatShortArrayWithFailMessageContainsExactly {
@BeforeTemplate
void before(short[] actual, String message, short[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(short[] actual, String message, short[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatShortArrayWithFailMessageSupplierContainsExactly {
@BeforeTemplate
void before(short[] actual, Supplier<String> message, short[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(short[] actual, Supplier<String> message, short[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatIntArrayContainsExactly {
@BeforeTemplate
void before(int[] actual, int[] expected) {
assertArrayEquals(expected, actual);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(int[] actual, int[] expected) {
assertThat(actual).containsExactly(expected);
}
}
static final class AssertThatIntArrayWithFailMessageContainsExactly {
@BeforeTemplate
void before(int[] actual, String message, int[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(int[] actual, String message, int[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatIntArrayWithFailMessageSupplierContainsExactly {
@BeforeTemplate
void before(int[] actual, Supplier<String> message, int[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(int[] actual, Supplier<String> message, int[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatLongArrayContainsExactly {
@BeforeTemplate
void before(long[] actual, long[] expected) {
assertArrayEquals(expected, actual);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(long[] actual, long[] expected) {
assertThat(actual).containsExactly(expected);
}
}
static final class AssertThatLongArrayWithFailMessageContainsExactly {
@BeforeTemplate
void before(long[] actual, String message, long[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(long[] actual, String message, long[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatLongArrayWithFailMessageSupplierContainsExactly {
@BeforeTemplate
void before(long[] actual, Supplier<String> message, long[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(long[] actual, Supplier<String> message, long[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatFloatArrayContainsExactly {
@BeforeTemplate
void before(float[] actual, float[] expected) {
assertArrayEquals(expected, actual);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float[] actual, float[] expected) {
assertThat(actual).containsExactly(expected);
}
}
static final class AssertThatFloatArrayWithFailMessageContainsExactly {
@BeforeTemplate
void before(float[] actual, String message, float[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float[] actual, String message, float[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatFloatArrayWithFailMessageSupplierContainsExactly {
@BeforeTemplate
void before(float[] actual, Supplier<String> message, float[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float[] actual, Supplier<String> message, float[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatFloatArrayContainsExactlyWithOffset {
@BeforeTemplate
void before(float[] actual, float[] expected, float delta) {
assertArrayEquals(expected, actual, delta);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float[] actual, float[] expected, float delta) {
assertThat(actual).containsExactly(expected, offset(delta));
}
}
static final class AssertThatFloatArrayWithFailMessageContainsExactlyWithOffset {
@BeforeTemplate
void before(float[] actual, String message, float[] expected, float delta) {
assertArrayEquals(expected, actual, delta, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float[] actual, String message, float[] expected, float delta) {
assertThat(actual).withFailMessage(message).containsExactly(expected, offset(delta));
}
}
static final class AssertThatFloatArrayWithFailMessageSupplierContainsExactlyWithOffset {
@BeforeTemplate
void before(float[] actual, Supplier<String> message, float[] expected, float delta) {
assertArrayEquals(expected, actual, delta, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float[] actual, Supplier<String> message, float[] expected, float delta) {
assertThat(actual).withFailMessage(message).containsExactly(expected, offset(delta));
}
}
static final class AssertThatDoubleArrayContainsExactly {
@BeforeTemplate
void before(double[] actual, double[] expected) {
assertArrayEquals(expected, actual);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double[] actual, double[] expected) {
assertThat(actual).containsExactly(expected);
}
}
static final class AssertThatDoubleArrayWithFailMessageContainsExactly {
@BeforeTemplate
void before(double[] actual, String message, double[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double[] actual, String message, double[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatDoubleArrayWithFailMessageSupplierContainsExactly {
@BeforeTemplate
void before(double[] actual, Supplier<String> message, double[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double[] actual, Supplier<String> message, double[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatDoubleArrayContainsExactlyWithOffset {
@BeforeTemplate
void before(double[] actual, double[] expected, double delta) {
assertArrayEquals(expected, actual, delta);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double[] actual, double[] expected, double delta) {
assertThat(actual).containsExactly(expected, offset(delta));
}
}
static final class AssertThatDoubleArrayWithFailMessageContainsExactlyWithOffset {
@BeforeTemplate
void before(double[] actual, String message, double[] expected, double delta) {
assertArrayEquals(expected, actual, delta, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double[] actual, String message, double[] expected, double delta) {
assertThat(actual).withFailMessage(message).containsExactly(expected, offset(delta));
}
}
static final class AssertThatDoubleArrayWithFailMessageSupplierContainsExactlyWithOffset {
@BeforeTemplate
void before(
double[] actual, Supplier<String> messageSupplier, double[] expected, double delta) {
assertArrayEquals(expected, actual, delta, messageSupplier);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double[] actual, Supplier<String> messageSupplier, double[] expected, double delta) {
assertThat(actual).withFailMessage(messageSupplier).containsExactly(expected, offset(delta));
}
}
static final class AssertThatObjectArrayContainsExactly {
@BeforeTemplate
void before(Object[] actual, Object[] expected) {
assertArrayEquals(expected, actual);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object[] actual, Object[] expected) {
assertThat(actual).containsExactly(expected);
}
}
static final class AssertThatObjectArrayWithFailMessageContainsExactly {
@BeforeTemplate
void before(Object[] actual, String message, Object[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object[] actual, String message, Object[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class AssertThatObjectArrayWithFailMessageSupplierContainsExactly {
@BeforeTemplate
void before(Object[] actual, Supplier<String> message, Object[] expected) {
assertArrayEquals(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object[] actual, Supplier<String> message, Object[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
static final class Fail<T> {
@BeforeTemplate
T before() {

View File

@@ -3,6 +3,7 @@ package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Objects.requireNonNullElse;
import static java.util.Objects.requireNonNullElseGet;
import static java.util.function.Predicate.not;
import com.google.common.base.MoreObjects;
import com.google.errorprone.refaster.Refaster;
@@ -94,11 +95,14 @@ final class NullRules {
}
}
/** Prefer {@link Objects#isNull(Object)} over the equivalent lambda function. */
/**
* Prefer {@link Objects#isNull(Object)} over the equivalent lambda function or more contrived
* alternatives.
*/
static final class IsNullFunction<T> {
@BeforeTemplate
Predicate<T> before() {
return o -> o == null;
return Refaster.anyOf(o -> o == null, not(Objects::nonNull));
}
@AfterTemplate
@@ -107,11 +111,14 @@ final class NullRules {
}
}
/** Prefer {@link Objects#nonNull(Object)} over the equivalent lambda function. */
/**
* Prefer {@link Objects#nonNull(Object)} over the equivalent lambda function or more contrived
* alternatives.
*/
static final class NonNullFunction<T> {
@BeforeTemplate
Predicate<T> before() {
return o -> o != null;
return Refaster.anyOf(o -> o != null, not(Objects::isNull));
}
@AfterTemplate

View File

@@ -889,6 +889,38 @@ final class ReactorRules {
}
}
/**
* Prefer immediately unwrapping {@link Optional} transformation results inside {@link
* Flux#mapNotNull(Function)} over more contrived alternatives.
*/
abstract static class FluxMapNotNullTransformationOrElse<T, S> {
@Placeholder(allowsIdentity = true)
abstract Optional<S> transformation(@MayOptionallyUse T value);
@BeforeTemplate
Flux<S> before(Flux<T> flux) {
return flux.map(v -> transformation(v)).mapNotNull(o -> o.orElse(null));
}
@AfterTemplate
Flux<S> after(Flux<T> flux) {
return flux.mapNotNull(x -> transformation(x).orElse(null));
}
}
/** Prefer {@link Flux#mapNotNull(Function)} over more contrived alternatives. */
static final class FluxMapNotNullOrElse<T> {
@BeforeTemplate
Flux<T> before(Flux<Optional<T>> flux) {
return flux.filter(Optional::isPresent).map(Optional::orElseThrow);
}
@AfterTemplate
Flux<T> after(Flux<Optional<T>> flux) {
return flux.mapNotNull(x -> x.orElse(null));
}
}
/** Prefer {@link Mono#flux()}} over more contrived alternatives. */
static final class MonoFlux<T> {
@BeforeTemplate

View File

@@ -29,11 +29,14 @@ final class StringRules {
private StringRules() {}
/** Prefer {@link String#isEmpty()} over alternatives that consult the string's length. */
// XXX: Now that we build with JDK 15+, this rule can be generalized to cover all `CharSequence`
// subtypes. This does require a mechanism (perhaps an annotation, or a separate Maven module) to
// make sure that non-String expressions are rewritten only if client code also targets JDK 15+.
// XXX: Drop this rule once we (and OpenRewrite) no longer support projects targeting Java 14 or
// below. The `CharSequenceIsEmpty` rule then suffices. (This rule exists so that e.g. projects
// that target JDK 11 can disable `CharSequenceIsEmpty` without losing a valuable rule.)
// XXX: Look into a more general approach to supporting different Java language levels, such as
// rule selection based on some annotation, or a separate Maven module.
static final class StringIsEmpty {
@BeforeTemplate
@SuppressWarnings("CharSequenceIsEmpty" /* This is a more specific template. */)
boolean before(String str) {
return Refaster.anyOf(str.length() == 0, str.length() <= 0, str.length() < 1);
}

View File

@@ -53,65 +53,13 @@ import tech.picnic.errorprone.refaster.annotation.TypeMigration;
// XXX: As-is these rules do not result in a complete migration:
// - Expressions containing comments are skipped due to a limitation of Refaster.
// - Assertions inside lambda expressions are also skipped. Unclear why.
// XXX: The `assertEquals` tests for this class generally use the same expression for `expected` and
// XXX: Many of the test expressions for these rules use the same expression for `expected` and
// `actual`, which makes the validation weaker than necessary; fix this. (And investigate whether we
// can introduce validation for this.)
@OnlineDocumentation
@TypeMigration(
of = Assert.class,
unmigratedMethods = {
// XXX: Add migrations for the methods below.
"assertEquals(Boolean, Boolean)",
"assertEquals(Boolean, boolean)",
"assertEquals(boolean, Boolean)",
"assertEquals(Boolean, Boolean, String)",
"assertEquals(Boolean, boolean, String)",
"assertEquals(boolean, Boolean, String)",
"assertEquals(Byte, Byte)",
"assertEquals(Byte, byte)",
"assertEquals(byte, Byte)",
"assertEquals(Byte, Byte, String)",
"assertEquals(Byte, byte, String)",
"assertEquals(byte, Byte, String)",
"assertEquals(char, Character)",
"assertEquals(char, Character, String)",
"assertEquals(Character, char)",
"assertEquals(Character, char, String)",
"assertEquals(Character, Character)",
"assertEquals(Character, Character, String)",
"assertEquals(Double, Double)",
"assertEquals(Double, double)",
"assertEquals(double, Double)",
"assertEquals(Double, Double, String)",
"assertEquals(Double, double, String)",
"assertEquals(double, Double, String)",
"assertEquals(double[], double[], double)",
"assertEquals(double[], double[], double, String)",
"assertEquals(Float, Float)",
"assertEquals(Float, float)",
"assertEquals(float, Float)",
"assertEquals(Float, Float, String)",
"assertEquals(Float, float, String)",
"assertEquals(float, Float, String)",
"assertEquals(float[], float[], float)",
"assertEquals(float[], float[], float, String)",
"assertEquals(int, Integer)",
"assertEquals(int, Integer, String)",
"assertEquals(Integer, int)",
"assertEquals(Integer, int, String)",
"assertEquals(Integer, Integer)",
"assertEquals(Integer, Integer, String)",
"assertEquals(Long, Long)",
"assertEquals(Long, long)",
"assertEquals(long, Long)",
"assertEquals(Long, Long, String)",
"assertEquals(Long, long, String)",
"assertEquals(Short, Short)",
"assertEquals(Short, short)",
"assertEquals(short, Short)",
"assertEquals(Short, Short, String)",
"assertEquals(Short, short, String)",
"assertEquals(short, Short, String)",
/*
* These `assertEqualsDeep` methods cannot (easily) be expressed using AssertJ because they
* mix regular equality and array equality:
@@ -357,41 +305,161 @@ final class TestNGToAssertJRules {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(boolean actual, Boolean expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Boolean actual, boolean expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Boolean actual, Boolean expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(byte actual, byte expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(byte actual, Byte expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Byte actual, byte expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Byte actual, Byte expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(char actual, char expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(char actual, Character expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Character actual, char expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Character actual, Character expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(short actual, short expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(short actual, Short expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Short actual, short expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Short actual, Short expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(int actual, int expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(int actual, Integer expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Integer actual, int expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Integer actual, Integer expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(long actual, long expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(long actual, Long expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Long actual, long expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Long actual, Long expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(float actual, float expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(float actual, Float expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Float actual, float expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Float actual, Float expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(double actual, double expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(double actual, Double expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Double actual, double expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Double actual, Double expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Object actual, Object expected) {
assertEquals(actual, expected);
@@ -420,41 +488,156 @@ final class TestNGToAssertJRules {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(boolean actual, String message, Boolean expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Boolean actual, String message, boolean expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Boolean actual, String message, Boolean expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(byte actual, String message, byte expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(byte actual, String message, Byte expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Byte actual, String message, byte expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Byte actual, String message, Byte expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(char actual, String message, char expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(char actual, String message, Character expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Character actual, String message, char expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Character actual, String message, Character expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(short actual, String message, short expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(short actual, String message, Short expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Short actual, String message, short expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Short actual, String message, Short expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(int actual, String message, int expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(int actual, String message, Integer expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Integer actual, String message, int expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Integer actual, String message, Integer expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(long actual, String message, long expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Long actual, String message, long expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Long actual, String message, Long expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(float actual, String message, float expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(float actual, String message, Float expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Float actual, String message, float expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Float actual, String message, Float expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(double actual, String message, double expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(double actual, String message, Double expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Double actual, String message, double expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Double actual, String message, Double expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Object actual, String message, Object expected) {
assertEquals(actual, expected, message);
@@ -485,7 +668,7 @@ final class TestNGToAssertJRules {
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float actual, float expected, float delta) {
void after(Float actual, float expected, float delta) {
assertThat(actual).isCloseTo(expected, offset(delta));
}
}
@@ -635,6 +818,58 @@ final class TestNGToAssertJRules {
}
}
static final class AssertEqualFloatArraysWithDelta {
@BeforeTemplate
void before(float[] actual, float[] expected, float delta) {
assertEquals(actual, expected, delta);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float[] actual, float[] expected, float delta) {
assertThat(actual).containsExactly(expected, offset(delta));
}
}
static final class AssertEqualFloatArraysWithDeltaWithMessage {
@BeforeTemplate
void before(float[] actual, String message, float[] expected, float delta) {
assertEquals(actual, expected, delta, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float[] actual, String message, float[] expected, float delta) {
assertThat(actual).withFailMessage(message).containsExactly(expected, offset(delta));
}
}
static final class AssertEqualDoubleArraysWithDelta {
@BeforeTemplate
void before(double[] actual, double[] expected, double delta) {
assertEquals(actual, expected, delta);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double[] actual, double[] expected, double delta) {
assertThat(actual).containsExactly(expected, offset(delta));
}
}
static final class AssertEqualDoubleArraysWithDeltaWithMessage {
@BeforeTemplate
void before(double[] actual, String message, double[] expected, double delta) {
assertEquals(actual, expected, delta, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double[] actual, String message, double[] expected, double delta) {
assertThat(actual).withFailMessage(message).containsExactly(expected, offset(delta));
}
}
static final class AssertEqualArraysIrrespectiveOfOrder {
@BeforeTemplate
void before(Object[] actual, Object[] expected) {

View File

@@ -0,0 +1,286 @@
package tech.picnic.errorprone.bugpatterns;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class EagerStringFormattingTest {
@Test
void identification() {
CompilationTestHelper.newInstance(EagerStringFormatting.class, getClass())
.expectErrorMessage("DEFER", m -> m.contains("String formatting can be deferred\n"))
.expectErrorMessage(
"DEFER_EXTRA_VARIABLE",
m ->
m.contains(
"String formatting can be deferred (but this requires introducing an effectively final variable)"))
.expectErrorMessage(
"DEFER_SIMPLIFIED_GUAVA",
m ->
m.contains(
"String formatting can be deferred (assuming that Guava's simplified formatting support suffices)"))
.expectErrorMessage(
"DEFER_SIMPLIFIED_SLF4J",
m ->
m.contains(
"String formatting can be deferred (assuming that SLF4J's simplified formatting support suffices)"))
.expectErrorMessage(
"VACUOUS", m -> m.contains("String formatting never yields `null` expression"))
.addSourceLines(
"A.java",
"import static com.google.common.base.Preconditions.checkArgument;",
"import static com.google.common.base.Preconditions.checkNotNull;",
"import static com.google.common.base.Preconditions.checkState;",
"import static com.google.common.base.Verify.verify;",
"import static com.google.common.base.Verify.verifyNotNull;",
"import static java.util.Objects.requireNonNull;",
"",
"import java.util.Formattable;",
"import java.util.Locale;",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"import org.slf4j.Marker;",
"",
"class A {",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
"",
" private int nonFinalField = 0;",
"",
" void m() {",
" Formattable formattable = (formatter, flags, width, precision) -> {};",
" int effectivelyFinalLocal = 0;",
" /* A local variable that is also not effectively final. */",
" int nonFinalLocal = 0;",
" nonFinalLocal = 1;",
"",
" String.format(\"%s\", \"foo\");",
" String.format(Locale.US, \"%s\", \"foo\");",
" \"%s\".formatted(\"foo\");",
" String.format(\"%s\", \"foo\", \"bar\");",
" String.format(\"%s %s\", \"foo\", \"bar\");",
" String.format(\"%s %s %%\", \"foo\", \"bar\");",
"",
" System.out.println(String.format(\"%s\", nonFinalLocal));",
"",
" requireNonNull(\"never-null\");",
" requireNonNull(\"never-null\", () -> String.format(\"Format string: %s\", nonFinalField));",
" // BUG: Diagnostic matches: VACUOUS",
" requireNonNull(String.format(\"Never-null format string: %s\", nonFinalField));",
" // BUG: Diagnostic matches: VACUOUS",
" requireNonNull(\"Never-null format string: %s\".formatted(nonFinalField), \"message\");",
" // BUG: Diagnostic matches: VACUOUS",
" requireNonNull(",
" String.format(\"Never-null format string\"), String.format(\"Malformed format string: %\"));",
" // BUG: Diagnostic matches: DEFER_EXTRA_VARIABLE",
" requireNonNull(\"never-null\", String.format(\"Format string: %s\", nonFinalLocal));",
" // BUG: Diagnostic matches: DEFER",
" requireNonNull(\"never-null\", String.format(\"Format string: %s\", effectivelyFinalLocal));",
" // BUG: Diagnostic matches: DEFER",
" requireNonNull(",
" \"never-null\",",
" String.format(",
" \"Custom format string: %s, %d, %s\", getClass(), nonFinalField, \"string-constant\"));",
"",
" checkArgument(true);",
" checkNotNull(\"never-null\");",
" checkState(false);",
" verify(true);",
" verifyNotNull(\"never-null\");",
" checkArgument(false, \"Without format string\");",
" checkNotNull(\"never-null\", \"Without format string\");",
" checkState(true, \"Without format string\");",
" verify(false, \"Without format string\");",
" verifyNotNull(\"never-null\", \"Without format string\");",
" checkArgument(true, \"With format string: %s\", nonFinalLocal);",
" checkNotNull(\"never-null\", \"With format string: %s\", nonFinalLocal);",
" checkState(false, \"With format string: %s\", nonFinalLocal);",
" verify(true, \"With format string: %s\", nonFinalLocal);",
" verifyNotNull(\"never-null\", \"With format string: %s\", nonFinalLocal);",
" // BUG: Diagnostic matches: VACUOUS",
" checkNotNull(String.format(\"Never-null format string: %s\", nonFinalLocal));",
" // BUG: Diagnostic matches: VACUOUS",
" verifyNotNull(\"Never-null format string: %s\".formatted(nonFinalLocal), \"message\");",
" // BUG: Diagnostic matches: VACUOUS",
" checkNotNull(",
" String.format(\"Never-null format string\"), String.format(\"Malformed format string: %\"));",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
" checkArgument(true, String.format(toString()));",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
" checkNotNull(\"never-null\", toString().formatted());",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
" checkState(true, String.format(\"Custom format string: %d\", nonFinalLocal));",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
" verify(true, \"Mismatched format string:\".formatted(nonFinalLocal));",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
" verifyNotNull(\"never-null\", \"Mismatched format string: %d\".formatted());",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
" checkArgument(true, String.format(\"Malformed format string: %\"));",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
" checkNotNull(\"never-null\", \"Format string with `Formattable`: %s\".formatted(formattable));",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
" checkState(true, String.format(\"Generated format string: %%s\"), nonFinalLocal);",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA",
" verify(",
" true,",
" \"Format string with format string argument: %s\",",
" String.format(\"Format string argument: %s\", nonFinalLocal));",
" // BUG: Diagnostic matches: DEFER",
" verifyNotNull(",
" \"never-null\", String.format(\"Format string: %s, %s\", nonFinalLocal, nonFinalLocal));",
" // BUG: Diagnostic matches: DEFER",
" checkArgument(true, \"Format string: %s%%\".formatted(nonFinalLocal));",
" // BUG: Diagnostic matches: DEFER",
" checkNotNull(",
" \"never-null\", String.format(Locale.US, \"Format string with locale: %s\", nonFinalLocal));",
"",
" LOG.trace(\"Without format string\");",
" LOG.debug(\"With format string: {}\", nonFinalLocal);",
" LOG.info((Marker) null, \"With marker\");",
" LOG.warn((Marker) null, \"With marker and format string: {}\", nonFinalLocal);",
" LOG.error(\"With throwable\", new RuntimeException());",
" LOG.trace(\"With throwable and format string: {}\", nonFinalLocal, new RuntimeException());",
" LOG.debug((Marker) null, \"With marker and throwable\", new RuntimeException());",
" LOG.info(",
" (Marker) null,",
" \"With marker, throwable and format string: {}\",",
" nonFinalLocal,",
" new RuntimeException());",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
" LOG.warn(String.format(toString()));",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
" LOG.error(toString().formatted());",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
" LOG.trace(String.format(\"Custom format string: %d\", nonFinalLocal));",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
" LOG.debug(\"Mismatched format string:\".formatted(nonFinalLocal));",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
" LOG.info(\"Mismatched format string %d:\".formatted());",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
" LOG.warn(String.format(\"Malformed format string: %\"));",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
" LOG.error(\"Format string with `Formattable`: %s\".formatted(formattable));",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
" LOG.trace(String.format(\"Generated format string: {}\"), nonFinalLocal);",
" // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J",
" LOG.debug(",
" \"Format string with format string argument: {}\",",
" String.format(\"Format string argument: %s\", nonFinalLocal));",
" // BUG: Diagnostic matches: DEFER",
" LOG.info(String.format(\"Vacuous format string %%\"));",
" // BUG: Diagnostic matches: DEFER",
" LOG.warn(String.format(\"With format string: %s, %s\", nonFinalLocal, nonFinalLocal));",
" // BUG: Diagnostic matches: DEFER",
" LOG.error(String.format(Locale.ROOT, \"With vacuous localized format string %%\"));",
" // BUG: Diagnostic matches: DEFER",
" LOG.trace((Marker) null, String.format(\"With marker and format string: %s\", nonFinalLocal));",
" // BUG: Diagnostic matches: DEFER",
" LOG.debug(",
" String.format(\"With throwable and format string: %s\", nonFinalLocal),",
" new RuntimeException());",
" // BUG: Diagnostic matches: DEFER",
" LOG.info(",
" (Marker) null,",
" String.format(\"With marker, throwable and format string: %s\", nonFinalLocal),",
" new RuntimeException());",
" }",
"}")
.doTest();
}
@Test
void replacement() {
BugCheckerRefactoringTestHelper.newInstance(EagerStringFormatting.class, getClass())
.addInputLines(
"A.java",
"import static com.google.common.base.Preconditions.checkArgument;",
"import static com.google.common.base.Preconditions.checkNotNull;",
"import static com.google.common.base.Preconditions.checkState;",
"import static com.google.common.base.Verify.verify;",
"import static com.google.common.base.Verify.verifyNotNull;",
"import static java.util.Objects.requireNonNull;",
"",
"import java.util.Locale;",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"import org.slf4j.Marker;",
"",
"class A {",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
" private static final String GUAVA_COMPATIBLE_PATTERN = \"with-only-%s-placeholder\";",
" private static final String GUAVA_INCOMPATIBLE_PATTERN = \"with-%%-marker\";",
"",
" void m() {",
" requireNonNull(\"never-null\", String.format(\"Format string: %s\", 0));",
"",
" checkArgument(true, String.format(\"Vacuous format string %%\"));",
" checkNotNull(\"never-null\", \"Format string: %s %s%%\".formatted(1, 2));",
" checkState(false, String.format(Locale.US, \"Format string with locale: %s\", 3));",
" verify(true, GUAVA_COMPATIBLE_PATTERN.formatted(4));",
" verifyNotNull(\"never-null\", String.format(Locale.ENGLISH, GUAVA_COMPATIBLE_PATTERN, 5));",
" checkArgument(false, GUAVA_INCOMPATIBLE_PATTERN.formatted());",
" checkNotNull(\"never-null\", String.format(GUAVA_INCOMPATIBLE_PATTERN));",
"",
" LOG.trace(\"Vacuous format string %%\".formatted());",
" LOG.debug(String.format(\"With format string: %s, %s%%\", 6, 7));",
" LOG.info(String.format(Locale.ROOT, \"With vacuous localized format string %%\"));",
" LOG.warn((Marker) null, \"With marker and format string: %s\".formatted(8));",
" LOG.error(",
" String.format(Locale.US, \"With throwable and format string: %s, %s\", 9, 10),",
" new RuntimeException());",
" LOG.trace(",
" (Marker) null,",
" \"With marker, throwable and format string: %s\".formatted(11),",
" new RuntimeException());",
" LOG.debug(GUAVA_COMPATIBLE_PATTERN.formatted(12));",
" LOG.info(String.format(Locale.ENGLISH, GUAVA_COMPATIBLE_PATTERN, 13));",
" LOG.warn(GUAVA_INCOMPATIBLE_PATTERN.formatted());",
" LOG.error(String.format(GUAVA_INCOMPATIBLE_PATTERN));",
" }",
"}")
.addOutputLines(
"A.java",
"import static com.google.common.base.Preconditions.checkArgument;",
"import static com.google.common.base.Preconditions.checkNotNull;",
"import static com.google.common.base.Preconditions.checkState;",
"import static com.google.common.base.Verify.verify;",
"import static com.google.common.base.Verify.verifyNotNull;",
"import static java.util.Objects.requireNonNull;",
"",
"import java.util.Locale;",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"import org.slf4j.Marker;",
"",
"class A {",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
" private static final String GUAVA_COMPATIBLE_PATTERN = \"with-only-%s-placeholder\";",
" private static final String GUAVA_INCOMPATIBLE_PATTERN = \"with-%%-marker\";",
"",
" void m() {",
" requireNonNull(\"never-null\", () -> String.format(\"Format string: %s\", 0));",
"",
" checkArgument(true, \"Vacuous format string %\");",
" checkNotNull(\"never-null\", \"Format string: %s %s%\", 1, 2);",
" checkState(false, \"Format string with locale: %s\", 3);",
" verify(true, GUAVA_COMPATIBLE_PATTERN, 4);",
" verifyNotNull(\"never-null\", GUAVA_COMPATIBLE_PATTERN, 5);",
" checkArgument(false, \"with-%-marker\");",
" checkNotNull(\"never-null\", \"with-%-marker\");",
"",
" LOG.trace(\"Vacuous format string %\");",
" LOG.debug(\"With format string: {}, {}%\", 6, 7);",
" LOG.info(\"With vacuous localized format string %\");",
" LOG.warn((Marker) null, \"With marker and format string: {}\", 8);",
" LOG.error(\"With throwable and format string: {}, {}\", 9, 10, new RuntimeException());",
" LOG.trace(",
" (Marker) null, \"With marker, throwable and format string: {}\", 11, new RuntimeException());",
" LOG.debug(\"with-only-{}-placeholder\", 12);",
" LOG.info(\"with-only-{}-placeholder\", 13);",
" LOG.warn(\"with-%-marker\");",
" LOG.error(\"with-%-marker\");",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -55,6 +55,10 @@ final class NonStaticImportTest {
"// BUG: Diagnostic contains:",
"import static java.time.Instant.MIN;",
"// BUG: Diagnostic contains:",
"import static java.time.InstantSource.system;",
"// BUG: Diagnostic contains:",
"import static java.time.LocalDate.EPOCH;",
"// BUG: Diagnostic contains:",
"import static java.time.ZoneOffset.SHORT_IDS;",
"import static java.time.ZoneOffset.UTC;",
"// BUG: Diagnostic contains:",
@@ -71,6 +75,7 @@ final class NonStaticImportTest {
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableSet;",
"import java.time.Instant;",
"import java.time.LocalDate;",
"import java.time.ZoneOffset;",
"import java.util.Locale;",
"import java.util.Map;",
@@ -82,8 +87,10 @@ final class NonStaticImportTest {
" void m() {",
" nullToEmpty(null);",
" copyOf(ImmutableList.of());",
" LocalDate epoch = EPOCH;",
" int max = MAX_VALUE;",
" int min = MIN_VALUE;",
" system();",
" systemUTC();",
" Instant minInstant = MIN;",
" Map<String, String> shortIds = SHORT_IDS;",

View File

@@ -21,6 +21,7 @@ final class TimeZoneUsageTest {
"import java.time.OffsetTime;",
"import java.time.ZoneId;",
"import java.time.ZonedDateTime;",
"import reactor.core.publisher.Mono;",
"",
"class A {",
" void m() {",
@@ -31,68 +32,122 @@ final class TimeZoneUsageTest {
" Clock.tick(clock, Duration.ZERO);",
"",
" // BUG: Diagnostic contains:",
" Clock.systemUTC();",
" clock.getZone();",
" // BUG: Diagnostic contains:",
" Clock.systemDefaultZone();",
" Mono.fromSupplier(clock::getZone);",
" // BUG: Diagnostic contains:",
" clock.withZone(UTC);",
" // BUG: Diagnostic contains:",
" Mono.<ZoneId>empty().map(clock::withZone);",
" // BUG: Diagnostic contains:",
" Clock.system(UTC);",
" // BUG: Diagnostic contains:",
" Mono.<ZoneId>empty().map(Clock::system);",
" // BUG: Diagnostic contains:",
" Clock.systemDefaultZone();",
" // BUG: Diagnostic contains:",
" Mono.fromSupplier(Clock::systemDefaultZone);",
" // BUG: Diagnostic contains:",
" Clock.systemUTC();",
" // BUG: Diagnostic contains:",
" Mono.fromSupplier(Clock::systemUTC);",
" // BUG: Diagnostic contains:",
" Clock.tickMillis(UTC);",
" // BUG: Diagnostic contains:",
" Mono.<ZoneId>empty().map(Clock::tickMillis);",
" // BUG: Diagnostic contains:",
" Clock.tickMinutes(UTC);",
" // BUG: Diagnostic contains:",
" Mono.<ZoneId>empty().map(Clock::tickMinutes);",
" // BUG: Diagnostic contains:",
" Clock.tickSeconds(UTC);",
" // BUG: Diagnostic contains:",
" clock.getZone();",
" // BUG: Diagnostic contains:",
" clock.withZone(UTC);",
" Mono.<ZoneId>empty().map(Clock::tickSeconds);",
"",
" Instant.now(clock);",
" Mono.<Clock>empty().map(Instant::now);",
" // BUG: Diagnostic contains:",
" Instant.now();",
" // This is equivalent to `clock.instant()`, which is fine.",
" Instant.now(clock);",
" // BUG: Diagnostic contains:",
" Mono.fromSupplier(Instant::now);",
"",
" // BUG: Diagnostic contains:",
" LocalDate.now();",
" // BUG: Diagnostic contains:",
" Mono.fromSupplier(LocalDate::now);",
" // BUG: Diagnostic contains:",
" LocalDate.now(clock);",
" // BUG: Diagnostic contains:",
" Mono.<Clock>empty().map(LocalDate::now);",
" // BUG: Diagnostic contains:",
" LocalDate.now(UTC);",
" // BUG: Diagnostic contains:",
" Mono.<ZoneId>empty().map(LocalDate::now);",
"",
" // BUG: Diagnostic contains:",
" LocalDateTime.now();",
" // BUG: Diagnostic contains:",
" Mono.fromSupplier(LocalDateTime::now);",
" // BUG: Diagnostic contains:",
" LocalDateTime.now(clock);",
" // BUG: Diagnostic contains:",
" Mono.<Clock>empty().map(LocalDateTime::now);",
" // BUG: Diagnostic contains:",
" LocalDateTime.now(UTC);",
" // BUG: Diagnostic contains:",
" Mono.<ZoneId>empty().map(LocalDateTime::now);",
"",
" // BUG: Diagnostic contains:",
" LocalTime.now();",
" // BUG: Diagnostic contains:",
" Mono.fromSupplier(LocalTime::now);",
" // BUG: Diagnostic contains:",
" LocalTime.now(clock);",
" // BUG: Diagnostic contains:",
" Mono.<Clock>empty().map(LocalTime::now);",
" // BUG: Diagnostic contains:",
" LocalTime.now(UTC);",
" // BUG: Diagnostic contains:",
" Mono.<ZoneId>empty().map(LocalTime::now);",
"",
" // BUG: Diagnostic contains:",
" OffsetDateTime.now();",
" // BUG: Diagnostic contains:",
" Mono.fromSupplier(OffsetDateTime::now);",
" // BUG: Diagnostic contains:",
" OffsetDateTime.now(clock);",
" // BUG: Diagnostic contains:",
" Mono.<Clock>empty().map(OffsetDateTime::now);",
" // BUG: Diagnostic contains:",
" OffsetDateTime.now(UTC);",
" // BUG: Diagnostic contains:",
" Mono.<ZoneId>empty().map(OffsetDateTime::now);",
"",
" // BUG: Diagnostic contains:",
" OffsetTime.now();",
" // BUG: Diagnostic contains:",
" Mono.fromSupplier(OffsetTime::now);",
" // BUG: Diagnostic contains:",
" OffsetTime.now(clock);",
" // BUG: Diagnostic contains:",
" Mono.<Clock>empty().map(OffsetTime::now);",
" // BUG: Diagnostic contains:",
" OffsetTime.now(UTC);",
" // BUG: Diagnostic contains:",
" Mono.<ZoneId>empty().map(OffsetTime::now);",
"",
" // BUG: Diagnostic contains:",
" ZonedDateTime.now();",
" // BUG: Diagnostic contains:",
" Mono.fromSupplier(ZonedDateTime::now);",
" // BUG: Diagnostic contains:",
" ZonedDateTime.now(clock);",
" // BUG: Diagnostic contains:",
" Mono.<Clock>empty().map(ZonedDateTime::now);",
" // BUG: Diagnostic contains:",
" ZonedDateTime.now(UTC);",
" // BUG: Diagnostic contains:",
" Mono.<ZoneId>empty().map(ZonedDateTime::now);",
" }",
"",
" abstract class ForwardingClock extends Clock {",

View File

@@ -23,6 +23,8 @@ final class RefasterRulesTest {
AssertJEnumerableRules.class,
AssertJFloatRules.class,
AssertJIntegerRules.class,
AssertJIterableRules.class,
AssertJIteratorRules.class,
AssertJLongRules.class,
AssertJMapRules.class,
AssertJNumberRules.class,
@@ -36,13 +38,13 @@ final class RefasterRulesTest {
AssortedRules.class,
BigDecimalRules.class,
BugCheckerRules.class,
CharSequenceRules.class,
ClassRules.class,
CollectionRules.class,
ComparatorRules.class,
DoubleStreamRules.class,
EqualityRules.class,
FileRules.class,
InputStreamRules.class,
ImmutableEnumSetRules.class,
ImmutableListRules.class,
ImmutableListMultimapRules.class,
@@ -53,6 +55,8 @@ final class RefasterRulesTest {
ImmutableSortedMapRules.class,
ImmutableSortedMultisetRules.class,
ImmutableSortedSetRules.class,
ImmutableTableRules.class,
InputStreamRules.class,
IntStreamRules.class,
JUnitRules.class,
JUnitToAssertJRules.class,

View File

@@ -8,13 +8,16 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJCharSequenceRulesTest implements RefasterRuleCollectionTestCase {
void testAssertThatCharSequenceIsEmpty() {
assertThat("foo".length()).isEqualTo(0L);
assertThat("foo".length()).isNotPositive();
assertThat("foo".isEmpty()).isTrue();
assertThat("bar".length()).isEqualTo(0L);
assertThat("baz".length()).isNotPositive();
}
ImmutableSet<AbstractAssert<?, ?>> testAssertThatCharSequenceIsNotEmpty() {
return ImmutableSet.of(
assertThat("foo".length()).isNotEqualTo(0), assertThat("bar".length()).isPositive());
assertThat("foo".isEmpty()).isFalse(),
assertThat("bar".length()).isNotEqualTo(0),
assertThat("baz".length()).isPositive());
}
AbstractAssert<?, ?> testAssertThatCharSequenceHasSize() {

View File

@@ -9,11 +9,15 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJCharSequenceRulesTest implements RefasterRuleCollectionTestCase {
void testAssertThatCharSequenceIsEmpty() {
assertThat("foo").isEmpty();
assertThat("foo").isEmpty();
assertThat("bar").isEmpty();
assertThat("baz").isEmpty();
}
ImmutableSet<AbstractAssert<?, ?>> testAssertThatCharSequenceIsNotEmpty() {
return ImmutableSet.of(assertThat("foo").isNotEmpty(), assertThat("bar").isNotEmpty());
return ImmutableSet.of(
assertThat("foo").isNotEmpty(),
assertThat("bar").isNotEmpty(),
assertThat("baz").isNotEmpty());
}
AbstractAssert<?, ?> testAssertThatCharSequenceHasSize() {

View File

@@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.EnumerableAssert;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
@@ -14,14 +15,42 @@ final class AssertJEnumerableRulesTest implements RefasterRuleCollectionTestCase
}
void testEnumerableAssertIsEmpty() {
assertThat(ImmutableSet.of()).hasSize(0);
assertThat(ImmutableSet.of()).hasSizeLessThanOrEqualTo(0);
assertThat(ImmutableSet.of()).hasSizeLessThan(1);
assertThat(ImmutableSet.of(1)).hasSize(0);
assertThat(ImmutableSet.of(2)).hasSizeLessThanOrEqualTo(0);
assertThat(ImmutableSet.of(3)).hasSizeLessThan(1);
assertThat(ImmutableSet.of(4)).size().isNotPositive();
}
ImmutableSet<EnumerableAssert<?, Character>> testEnumerableAssertIsNotEmpty() {
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertIsNotEmpty() {
return ImmutableSet.of(
assertThat("foo").hasSizeGreaterThan(0), assertThat("bar").hasSizeGreaterThanOrEqualTo(1));
assertThat(ImmutableSet.of(1)).hasSizeGreaterThan(0),
assertThat(ImmutableSet.of(2)).hasSizeGreaterThanOrEqualTo(1),
assertThat(ImmutableSet.of(3)).size().isNotEqualTo(0),
assertThat(ImmutableSet.of(4)).size().isPositive());
}
AbstractAssert<?, ?> testEnumerableAssertHasSize() {
return assertThat(ImmutableSet.of(1)).size().isEqualTo(2);
}
AbstractAssert<?, ?> testEnumerableAssertHasSizeLessThan() {
return assertThat(ImmutableSet.of(1)).size().isLessThan(2);
}
AbstractAssert<?, ?> testEnumerableAssertHasSizeLessThanOrEqualTo() {
return assertThat(ImmutableSet.of(1)).size().isLessThanOrEqualTo(2);
}
AbstractAssert<?, ?> testEnumerableAssertHasSizeGreaterThan() {
return assertThat(ImmutableSet.of(1)).size().isGreaterThan(2);
}
AbstractAssert<?, ?> testEnumerableAssertHasSizeGreaterThanOrEqualTo() {
return assertThat(ImmutableSet.of(1)).size().isGreaterThanOrEqualTo(2);
}
AbstractAssert<?, ?> testEnumerableAssertHasSizeBetween() {
return assertThat(ImmutableSet.of(1)).size().isBetween(2, 3);
}
ImmutableSet<EnumerableAssert<?, Integer>> testEnumerableAssertHasSameSizeAs() {

View File

@@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.EnumerableAssert;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
@@ -14,13 +15,42 @@ final class AssertJEnumerableRulesTest implements RefasterRuleCollectionTestCase
}
void testEnumerableAssertIsEmpty() {
assertThat(ImmutableSet.of()).isEmpty();
assertThat(ImmutableSet.of()).isEmpty();
assertThat(ImmutableSet.of()).isEmpty();
assertThat(ImmutableSet.of(1)).isEmpty();
assertThat(ImmutableSet.of(2)).isEmpty();
assertThat(ImmutableSet.of(3)).isEmpty();
assertThat(ImmutableSet.of(4)).isEmpty();
}
ImmutableSet<EnumerableAssert<?, Character>> testEnumerableAssertIsNotEmpty() {
return ImmutableSet.of(assertThat("foo").isNotEmpty(), assertThat("bar").isNotEmpty());
ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertIsNotEmpty() {
return ImmutableSet.of(
assertThat(ImmutableSet.of(1)).isNotEmpty(),
assertThat(ImmutableSet.of(2)).isNotEmpty(),
assertThat(ImmutableSet.of(3)).isNotEmpty(),
assertThat(ImmutableSet.of(4)).isNotEmpty());
}
AbstractAssert<?, ?> testEnumerableAssertHasSize() {
return assertThat(ImmutableSet.of(1)).hasSize(2);
}
AbstractAssert<?, ?> testEnumerableAssertHasSizeLessThan() {
return assertThat(ImmutableSet.of(1)).hasSizeLessThan(2);
}
AbstractAssert<?, ?> testEnumerableAssertHasSizeLessThanOrEqualTo() {
return assertThat(ImmutableSet.of(1)).hasSizeLessThanOrEqualTo(2);
}
AbstractAssert<?, ?> testEnumerableAssertHasSizeGreaterThan() {
return assertThat(ImmutableSet.of(1)).hasSizeGreaterThan(2);
}
AbstractAssert<?, ?> testEnumerableAssertHasSizeGreaterThanOrEqualTo() {
return assertThat(ImmutableSet.of(1)).hasSizeGreaterThanOrEqualTo(2);
}
AbstractAssert<?, ?> testEnumerableAssertHasSizeBetween() {
return assertThat(ImmutableSet.of(1)).hasSizeBetween(2, 3);
}
ImmutableSet<EnumerableAssert<?, Integer>> testEnumerableAssertHasSameSizeAs() {

View File

@@ -0,0 +1,35 @@
package tech.picnic.errorprone.refasterrules;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractIntegerAssert;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJIterableRulesTest implements RefasterRuleCollectionTestCase {
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(Iterables.class);
}
void testAssertThatIterableIsEmpty() {
assertThat(ImmutableSet.of(1).iterator()).isExhausted();
assertThat(ImmutableSet.of(2).isEmpty()).isTrue();
}
ImmutableSet<AbstractAssert<?, ?>> testAssertThatIterableIsNotEmpty() {
return ImmutableSet.of(
assertThat(ImmutableSet.of(1).iterator()).hasNext(),
assertThat(ImmutableSet.of(2).isEmpty()).isFalse());
}
ImmutableSet<AbstractIntegerAssert<?>> testAssertThatIterableSize() {
return ImmutableSet.of(
assertThat(Iterables.size(ImmutableSet.of(1))), assertThat(ImmutableSet.of(2).size()));
}
AbstractAssert<?, ?> testAssertThatIterableHasOneElementEqualTo() {
return assertThat(Iterables.getOnlyElement(ImmutableSet.of(new Object()))).isEqualTo("foo");
}
}

View File

@@ -0,0 +1,34 @@
package tech.picnic.errorprone.refasterrules;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractIntegerAssert;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJIterableRulesTest implements RefasterRuleCollectionTestCase {
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(Iterables.class);
}
void testAssertThatIterableIsEmpty() {
assertThat(ImmutableSet.of(1)).isEmpty();
assertThat(ImmutableSet.of(2)).isEmpty();
}
ImmutableSet<AbstractAssert<?, ?>> testAssertThatIterableIsNotEmpty() {
return ImmutableSet.of(
assertThat(ImmutableSet.of(1)).isNotEmpty(), assertThat(ImmutableSet.of(2)).isNotEmpty());
}
ImmutableSet<AbstractIntegerAssert<?>> testAssertThatIterableSize() {
return ImmutableSet.of(
assertThat(ImmutableSet.of(1)).size(), assertThat(ImmutableSet.of(2)).size());
}
AbstractAssert<?, ?> testAssertThatIterableHasOneElementEqualTo() {
return assertThat(ImmutableSet.of(new Object())).containsExactly("foo");
}
}

View File

@@ -0,0 +1,17 @@
package tech.picnic.errorprone.refasterrules;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableSet;
import org.assertj.core.api.AbstractAssert;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJIteratorRulesTest implements RefasterRuleCollectionTestCase {
AbstractAssert<?, ?> testAssertThatHasNext() {
return assertThat(ImmutableSet.of().iterator().hasNext()).isTrue();
}
AbstractAssert<?, ?> testAssertThatIsExhausted() {
return assertThat(ImmutableSet.of().iterator().hasNext()).isFalse();
}
}

View File

@@ -0,0 +1,17 @@
package tech.picnic.errorprone.refasterrules;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableSet;
import org.assertj.core.api.AbstractAssert;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJIteratorRulesTest implements RefasterRuleCollectionTestCase {
AbstractAssert<?, ?> testAssertThatHasNext() {
return assertThat(ImmutableSet.of().iterator()).hasNext();
}
AbstractAssert<?, ?> testAssertThatIsExhausted() {
return assertThat(ImmutableSet.of().iterator()).isExhausted();
}
}

View File

@@ -21,16 +21,16 @@ final class AssertJStringRulesTest implements RefasterRuleCollectionTestCase {
assertThat("foo").isEqualTo("");
}
void testAssertThatStringIsEmpty() {
assertThat("foo".isEmpty()).isTrue();
}
AbstractStringAssert<?> testAbstractStringAssertStringIsNotEmpty() {
return assertThat("foo").isNotEqualTo("");
}
AbstractAssert<?, ?> testAssertThatStringIsNotEmpty() {
return assertThat("foo".isEmpty()).isFalse();
AbstractAssert<?, ?> testAssertThatStringContains() {
return assertThat("foo".contains("bar")).isTrue();
}
AbstractAssert<?, ?> testAssertThatStringDoesNotContain() {
return assertThat("foo".contains("bar")).isFalse();
}
AbstractAssert<?, ?> testAssertThatMatches() {

View File

@@ -22,16 +22,16 @@ final class AssertJStringRulesTest implements RefasterRuleCollectionTestCase {
assertThat("foo").isEmpty();
}
void testAssertThatStringIsEmpty() {
assertThat("foo").isEmpty();
}
AbstractStringAssert<?> testAbstractStringAssertStringIsNotEmpty() {
return assertThat("foo").isNotEmpty();
}
AbstractAssert<?, ?> testAssertThatStringIsNotEmpty() {
return assertThat("foo").isNotEmpty();
AbstractAssert<?, ?> testAssertThatStringContains() {
return assertThat("foo").contains("bar");
}
AbstractAssert<?, ?> testAssertThatStringDoesNotContain() {
return assertThat("foo").doesNotContain("bar");
}
AbstractAssert<?, ?> testAssertThatMatches() {

View File

@@ -0,0 +1,16 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.ImmutableSet;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class CharSequenceRulesTest implements RefasterRuleCollectionTestCase {
ImmutableSet<Boolean> testCharSequenceIsEmpty() {
return ImmutableSet.of(
new StringBuilder("foo").length() == 0,
new StringBuilder("bar").length() <= 0,
new StringBuilder("baz").length() < 1,
new StringBuilder("qux").length() != 0,
new StringBuilder("quux").length() > 0,
new StringBuilder("corge").length() >= 1);
}
}

View File

@@ -0,0 +1,16 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.ImmutableSet;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class CharSequenceRulesTest implements RefasterRuleCollectionTestCase {
ImmutableSet<Boolean> testCharSequenceIsEmpty() {
return ImmutableSet.of(
new StringBuilder("foo").isEmpty(),
new StringBuilder("bar").isEmpty(),
new StringBuilder("baz").isEmpty(),
!new StringBuilder("qux").isEmpty(),
!new StringBuilder("quux").isEmpty(),
!new StringBuilder("corge").isEmpty());
}
}

View File

@@ -62,7 +62,7 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
return Iterables.removeAll(new ArrayList<>(), ImmutableSet.of("foo"));
}
void testSetRemoveAllCollection() {
void testCollectionRemoveAllFromCollectionBlock() {
ImmutableSet.of("foo").forEach(new HashSet<>()::remove);
for (Number element : ImmutableList.of(1)) {
new HashSet<Number>().remove(element);

View File

@@ -58,7 +58,7 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
return new ArrayList<>().removeAll(ImmutableSet.of("foo"));
}
void testSetRemoveAllCollection() {
void testCollectionRemoveAllFromCollectionBlock() {
new HashSet<>().removeAll(ImmutableSet.of("foo"));
new HashSet<Number>().removeAll(ImmutableList.of(1));
new HashSet<Number>().removeAll(ImmutableSet.of(2));

View File

@@ -24,9 +24,13 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
return new ImmutableMap.Builder<>();
}
ImmutableMap<Object, Object> testImmutableMapBuilderBuildOrThrow() {
return ImmutableMap.builder().build();
}
ImmutableSet<ImmutableMap<String, Integer>> testEntryToImmutableMap() {
return ImmutableSet.of(
ImmutableMap.<String, Integer>builder().put(Map.entry("foo", 1)).build(),
ImmutableMap.<String, Integer>builder().put(Map.entry("foo", 1)).buildOrThrow(),
Stream.of(Map.entry("foo", 1))
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)));
}
@@ -51,13 +55,14 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
ImmutableMap.copyOf(Maps.asMap(ImmutableSet.of(10), Integer::valueOf)));
}
ImmutableSet<ImmutableMap<String, Integer>> testEntryIterableToImmutableMap() {
ImmutableSet<Map<String, Integer>> testEntryIterableToImmutableMap() {
return ImmutableSet.of(
ImmutableMap.copyOf(ImmutableMap.of("foo", 1).entrySet()),
ImmutableMap.<String, Integer>builder().putAll(ImmutableMap.of("foo", 1)).build(),
ImmutableMap.<String, Integer>builder().putAll(ImmutableMap.of("foo", 1)).buildOrThrow(),
Map.copyOf(ImmutableMap.of("foo", 1)),
ImmutableMap.<String, Integer>builder()
.putAll(ImmutableMap.of("foo", 1).entrySet())
.build(),
.buildOrThrow(),
ImmutableMap.of("foo", 1).entrySet().stream()
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)),
Streams.stream(Iterables.cycle(Map.entry("foo", 1)))
@@ -100,32 +105,51 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
ImmutableSet<Map<String, String>> testImmutableMapOf() {
return ImmutableSet.of(
ImmutableMap.<String, String>builder().build(),
ImmutableMap.<String, String>builder().buildOrThrow(),
ImmutableMap.ofEntries(),
Collections.<String, String>emptyMap(),
Map.<String, String>of());
}
ImmutableSet<Map<String, String>> testImmutableMapOf1() {
return ImmutableSet.of(
ImmutableMap.<String, String>builder().put("k1", "v1").build(),
ImmutableMap.<String, String>builder().put("k1", "v1").buildOrThrow(),
ImmutableMap.ofEntries(Map.entry("k1", "v1")),
Collections.singletonMap("k1", "v1"),
Map.of("k1", "v1"));
}
Map<String, String> testImmutableMapOf2() {
return Map.of("k1", "v1", "k2", "v2");
ImmutableSet<Map<String, String>> testImmutableMapOf2() {
return ImmutableSet.of(
ImmutableMap.ofEntries(Map.entry("k1", "v1"), Map.entry("k2", "v2")),
Map.of("k1", "v1", "k2", "v2"));
}
Map<String, String> testImmutableMapOf3() {
return Map.of("k1", "v1", "k2", "v2", "k3", "v3");
ImmutableSet<Map<String, String>> testImmutableMapOf3() {
return ImmutableSet.of(
ImmutableMap.ofEntries(Map.entry("k1", "v1"), Map.entry("k2", "v2"), Map.entry("k3", "v3")),
Map.of("k1", "v1", "k2", "v2", "k3", "v3"));
}
Map<String, String> testImmutableMapOf4() {
return Map.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4");
ImmutableSet<Map<String, String>> testImmutableMapOf4() {
return ImmutableSet.of(
ImmutableMap.ofEntries(
Map.entry("k1", "v1"),
Map.entry("k2", "v2"),
Map.entry("k3", "v3"),
Map.entry("k4", "v4")),
Map.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4"));
}
Map<String, String> testImmutableMapOf5() {
return Map.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4", "k5", "v5");
ImmutableSet<Map<String, String>> testImmutableMapOf5() {
return ImmutableSet.of(
ImmutableMap.ofEntries(
Map.entry("k1", "v1"),
Map.entry("k2", "v2"),
Map.entry("k3", "v3"),
Map.entry("k4", "v4"),
Map.entry("k5", "v5")),
Map.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4", "k5", "v5"));
}
ImmutableMap<String, Integer> testImmutableMapCopyOfMapsFilterKeys() {
@@ -139,4 +163,11 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
.filter(entry -> entry.getValue() > 0)
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
}
ImmutableSet<Map<String, Integer>> testImmutableMapOfEntries() {
return ImmutableSet.of(
Map.ofEntries(),
Map.ofEntries(Map.entry("foo", 1)),
Map.ofEntries(Map.entry("bar", 2), Map.entry("baz", 3)));
}
}

View File

@@ -24,6 +24,10 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableMap.builder();
}
ImmutableMap<Object, Object> testImmutableMapBuilderBuildOrThrow() {
return ImmutableMap.builder().buildOrThrow();
}
ImmutableSet<ImmutableMap<String, Integer>> testEntryToImmutableMap() {
return ImmutableSet.of(
ImmutableMap.of(Map.entry("foo", 1).getKey(), Map.entry("foo", 1).getValue()),
@@ -46,8 +50,9 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
Maps.toMap(ImmutableSet.of(10), Integer::valueOf));
}
ImmutableSet<ImmutableMap<String, Integer>> testEntryIterableToImmutableMap() {
ImmutableSet<Map<String, Integer>> testEntryIterableToImmutableMap() {
return ImmutableSet.of(
ImmutableMap.copyOf(ImmutableMap.of("foo", 1)),
ImmutableMap.copyOf(ImmutableMap.of("foo", 1)),
ImmutableMap.copyOf(ImmutableMap.of("foo", 1)),
ImmutableMap.copyOf(ImmutableMap.of("foo", 1).entrySet()),
@@ -83,28 +88,39 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
}
ImmutableSet<Map<String, String>> testImmutableMapOf() {
return ImmutableSet.of(ImmutableMap.of(), ImmutableMap.of(), ImmutableMap.of());
return ImmutableSet.of(
ImmutableMap.of(), ImmutableMap.of(), ImmutableMap.of(), ImmutableMap.of());
}
ImmutableSet<Map<String, String>> testImmutableMapOf1() {
return ImmutableSet.of(
ImmutableMap.of("k1", "v1"), ImmutableMap.of("k1", "v1"), ImmutableMap.of("k1", "v1"));
ImmutableMap.of("k1", "v1"),
ImmutableMap.of("k1", "v1"),
ImmutableMap.of("k1", "v1"),
ImmutableMap.of("k1", "v1"));
}
Map<String, String> testImmutableMapOf2() {
return ImmutableMap.of("k1", "v1", "k2", "v2");
ImmutableSet<Map<String, String>> testImmutableMapOf2() {
return ImmutableSet.of(
ImmutableMap.of("k1", "v1", "k2", "v2"), ImmutableMap.of("k1", "v1", "k2", "v2"));
}
Map<String, String> testImmutableMapOf3() {
return ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3");
ImmutableSet<Map<String, String>> testImmutableMapOf3() {
return ImmutableSet.of(
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3"),
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3"));
}
Map<String, String> testImmutableMapOf4() {
return ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4");
ImmutableSet<Map<String, String>> testImmutableMapOf4() {
return ImmutableSet.of(
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4"),
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4"));
}
Map<String, String> testImmutableMapOf5() {
return ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4", "k5", "v5");
ImmutableSet<Map<String, String>> testImmutableMapOf5() {
return ImmutableSet.of(
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4", "k5", "v5"),
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4", "k5", "v5"));
}
ImmutableMap<String, Integer> testImmutableMapCopyOfMapsFilterKeys() {
@@ -114,4 +130,11 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
ImmutableMap<String, Integer> testImmutableMapCopyOfMapsFilterValues() {
return ImmutableMap.copyOf(Maps.filterValues(ImmutableMap.of("foo", 1), v -> v > 0));
}
ImmutableSet<Map<String, Integer>> testImmutableMapOfEntries() {
return ImmutableSet.of(
ImmutableMap.ofEntries(),
ImmutableMap.ofEntries(Map.entry("foo", 1)),
ImmutableMap.ofEntries(Map.entry("bar", 2), Map.entry("baz", 3)));
}
}

View File

@@ -32,16 +32,16 @@ final class ImmutableSortedMapRulesTest implements RefasterRuleCollectionTestCas
}
ImmutableSortedMap<String, Integer> testEmptyImmutableSortedMap() {
return ImmutableSortedMap.<String, Integer>naturalOrder().build();
return ImmutableSortedMap.<String, Integer>naturalOrder().buildOrThrow();
}
ImmutableSortedMap<String, Integer> testPairToImmutableSortedMap() {
return ImmutableSortedMap.<String, Integer>naturalOrder().put("foo", 1).build();
return ImmutableSortedMap.<String, Integer>naturalOrder().put("foo", 1).buildOrThrow();
}
ImmutableSet<ImmutableSortedMap<String, Integer>> testEntryToImmutableSortedMap() {
return ImmutableSet.of(
ImmutableSortedMap.<String, Integer>naturalOrder().put(Map.entry("foo", 1)).build(),
ImmutableSortedMap.<String, Integer>naturalOrder().put(Map.entry("foo", 1)).buildOrThrow(),
Stream.of(Map.entry("foo", 1))
.collect(toImmutableSortedMap(naturalOrder(), Map.Entry::getKey, Map.Entry::getValue)));
}
@@ -52,10 +52,10 @@ final class ImmutableSortedMapRulesTest implements RefasterRuleCollectionTestCas
ImmutableSortedMap.copyOf(ImmutableSortedMap.of("foo", 1).entrySet()),
ImmutableSortedMap.<String, Integer>naturalOrder()
.putAll(ImmutableSortedMap.of("foo", 1))
.build(),
.buildOrThrow(),
ImmutableSortedMap.<String, Integer>naturalOrder()
.putAll(ImmutableSortedMap.of("foo", 1).entrySet())
.build(),
.buildOrThrow(),
ImmutableSortedMap.of("foo", 1).entrySet().stream()
.collect(toImmutableSortedMap(naturalOrder(), Map.Entry::getKey, Map.Entry::getValue)),
Streams.stream(Iterables.cycle(Map.entry("foo", 1)))

View File

@@ -0,0 +1,48 @@
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableTable.toImmutableTable;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Table;
import com.google.common.collect.Tables;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class ImmutableTableRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(Table.class);
}
ImmutableTable.Builder<String, Integer, String> testImmutableTableBuilder() {
return new ImmutableTable.Builder<>();
}
ImmutableTable<Object, Object, Object> testImmutableTableBuilderBuildOrThrow() {
return ImmutableTable.builder().build();
}
ImmutableSet<ImmutableTable<String, Integer, String>> testCellToImmutableTable() {
return ImmutableSet.of(
ImmutableTable.<String, Integer, String>builder()
.put(Tables.immutableCell("foo", 1, "bar"))
.buildOrThrow(),
Stream.of(Tables.immutableCell("baz", 2, "qux"))
.collect(
toImmutableTable(
Table.Cell::getRowKey, Table.Cell::getColumnKey, Table.Cell::getValue)));
}
ImmutableTable<Integer, String, Integer> testStreamOfCellsToImmutableTable() {
return Stream.of(1, 2, 3)
.map(n -> Tables.immutableCell(n, n.toString(), n * 2))
.collect(
toImmutableTable(
Table.Cell::getRowKey, Table.Cell::getColumnKey, Table.Cell::getValue));
}
ImmutableTable<String, String, String> testImmutableTableOf() {
return ImmutableTable.<String, String, String>builder().buildOrThrow();
}
}

View File

@@ -0,0 +1,45 @@
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableTable.toImmutableTable;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Table;
import com.google.common.collect.Tables;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class ImmutableTableRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(Table.class);
}
ImmutableTable.Builder<String, Integer, String> testImmutableTableBuilder() {
return ImmutableTable.builder();
}
ImmutableTable<Object, Object, Object> testImmutableTableBuilderBuildOrThrow() {
return ImmutableTable.builder().buildOrThrow();
}
ImmutableSet<ImmutableTable<String, Integer, String>> testCellToImmutableTable() {
return ImmutableSet.of(
ImmutableTable.of(
Tables.immutableCell("foo", 1, "bar").getRowKey(),
Tables.immutableCell("foo", 1, "bar").getColumnKey(),
Tables.immutableCell("foo", 1, "bar").getValue()),
ImmutableTable.of(
Tables.immutableCell("baz", 2, "qux").getRowKey(),
Tables.immutableCell("baz", 2, "qux").getColumnKey(),
Tables.immutableCell("baz", 2, "qux").getValue()));
}
ImmutableTable<Integer, String, Integer> testStreamOfCellsToImmutableTable() {
return Stream.of(1, 2, 3).collect(toImmutableTable(n -> n, n -> n.toString(), n -> n * 2));
}
ImmutableTable<String, String, String> testImmutableTableOf() {
return ImmutableTable.of();
}
}

View File

@@ -1,5 +1,7 @@
package tech.picnic.errorprone.refasterrules;
import static org.assertj.core.api.Assertions.offset;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
@@ -24,6 +26,8 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
assertInstanceOf(null, null),
assertThrows(null, null),
assertThrowsExactly(null, null),
offset(0.0),
(Runnable) () -> assertArrayEquals((int[]) null, null),
(Runnable) () -> assertFalse(true),
(Runnable) () -> assertNotNull(null),
(Runnable) () -> assertNotSame(null, null),
@@ -32,6 +36,138 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
(Runnable) () -> assertTrue(true));
}
void testAssertThatBooleanArrayContainsExactly() {
assertArrayEquals(new boolean[] {true}, new boolean[] {false});
}
void testAssertThatBooleanArrayWithFailMessageContainsExactly() {
assertArrayEquals(new boolean[] {true}, new boolean[] {false}, "foo");
}
void testAssertThatBooleanArrayWithFailMessageSupplierContainsExactly() {
assertArrayEquals(new boolean[] {true}, new boolean[] {false}, () -> "foo");
}
void testAssertThatByteArrayContainsExactly() {
assertArrayEquals(new byte[] {1}, new byte[] {2});
}
void testAssertThatByteArrayWithFailMessageContainsExactly() {
assertArrayEquals(new byte[] {1}, new byte[] {2}, "foo");
}
void testAssertThatByteArrayWithFailMessageSupplierContainsExactly() {
assertArrayEquals(new byte[] {1}, new byte[] {2}, () -> "foo");
}
void testAssertThatCharArrayContainsExactly() {
assertArrayEquals(new char[] {'a'}, new char[] {'b'});
}
void testAssertThatCharArrayWithFailMessageContainsExactly() {
assertArrayEquals(new char[] {'a'}, new char[] {'b'}, "foo");
}
void testAssertThatCharArrayWithFailMessageSupplierContainsExactly() {
assertArrayEquals(new char[] {'a'}, new char[] {'b'}, () -> "foo");
}
void testAssertThatShortArrayContainsExactly() {
assertArrayEquals(new short[] {1}, new short[] {2});
}
void testAssertThatShortArrayWithFailMessageContainsExactly() {
assertArrayEquals(new short[] {1}, new short[] {2}, "foo");
}
void testAssertThatShortArrayWithFailMessageSupplierContainsExactly() {
assertArrayEquals(new short[] {1}, new short[] {2}, () -> "foo");
}
void testAssertThatIntArrayContainsExactly() {
assertArrayEquals(new int[] {1}, new int[] {2});
}
void testAssertThatIntArrayWithFailMessageContainsExactly() {
assertArrayEquals(new int[] {1}, new int[] {2}, "foo");
}
void testAssertThatIntArrayWithFailMessageSupplierContainsExactly() {
assertArrayEquals(new int[] {1}, new int[] {2}, () -> "foo");
}
void testAssertThatLongArrayContainsExactly() {
assertArrayEquals(new long[] {1L}, new long[] {2L});
}
void testAssertThatLongArrayWithFailMessageContainsExactly() {
assertArrayEquals(new long[] {1L}, new long[] {2L}, "foo");
}
void testAssertThatLongArrayWithFailMessageSupplierContainsExactly() {
assertArrayEquals(new long[] {1L}, new long[] {2L}, () -> "foo");
}
void testAssertThatFloatArrayContainsExactly() {
assertArrayEquals(new float[] {1.0F}, new float[] {2.0F});
}
void testAssertThatFloatArrayWithFailMessageContainsExactly() {
assertArrayEquals(new float[] {1.0F}, new float[] {2.0F}, "foo");
}
void testAssertThatFloatArrayWithFailMessageSupplierContainsExactly() {
assertArrayEquals(new float[] {1.0F}, new float[] {2.0F}, () -> "foo");
}
void testAssertThatFloatArrayContainsExactlyWithOffset() {
assertArrayEquals(new float[] {1.0F}, new float[] {2.0F}, 0.1f);
}
void testAssertThatFloatArrayWithFailMessageContainsExactlyWithOffset() {
assertArrayEquals(new float[] {1.0F}, new float[] {2.0F}, 0.1f, "foo");
}
void testAssertThatFloatArrayWithFailMessageSupplierContainsExactlyWithOffset() {
assertArrayEquals(new float[] {1.0F}, new float[] {2.0F}, 0.1f, () -> "foo");
}
void testAssertThatDoubleArrayContainsExactly() {
assertArrayEquals(new double[] {1.0}, new double[] {2.0});
}
void testAssertThatDoubleArrayWithFailMessageContainsExactly() {
assertArrayEquals(new double[] {1.0}, new double[] {2.0}, "foo");
}
void testAssertThatDoubleArrayWithFailMessageSupplierContainsExactly() {
assertArrayEquals(new double[] {1.0}, new double[] {2.0}, () -> "foo");
}
void testAssertThatDoubleArrayContainsExactlyWithOffset() {
assertArrayEquals(new double[] {1.0}, new double[] {2.0}, 0.1);
}
void testAssertThatDoubleArrayWithFailMessageContainsExactlyWithOffset() {
assertArrayEquals(new double[] {1.0}, new double[] {2.0}, 0.1, "foo");
}
void testAssertThatDoubleArrayWithFailMessageSupplierContainsExactlyWithOffset() {
assertArrayEquals(new double[] {1.0}, new double[] {2.0}, 0.1, () -> "foo");
}
void testAssertThatObjectArrayContainsExactly() {
assertArrayEquals(new Object[] {"foo"}, new Object[] {"bar"});
}
void testAssertThatObjectArrayWithFailMessageContainsExactly() {
assertArrayEquals(new Object[] {"foo"}, new Object[] {"bar"}, "foo");
}
void testAssertThatObjectArrayWithFailMessageSupplierContainsExactly() {
assertArrayEquals(new Object[] {"foo"}, new Object[] {"bar"}, () -> "foo");
}
Object testFail() {
return Assertions.fail();
}

View File

@@ -3,6 +3,8 @@ package tech.picnic.errorprone.refasterrules;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.offset;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
@@ -27,6 +29,8 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
assertInstanceOf(null, null),
assertThrows(null, null),
assertThrowsExactly(null, null),
offset(0.0),
(Runnable) () -> assertArrayEquals((int[]) null, null),
(Runnable) () -> assertFalse(true),
(Runnable) () -> assertNotNull(null),
(Runnable) () -> assertNotSame(null, null),
@@ -35,6 +39,150 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
(Runnable) () -> assertTrue(true));
}
void testAssertThatBooleanArrayContainsExactly() {
assertThat(new boolean[] {false}).containsExactly(new boolean[] {true});
}
void testAssertThatBooleanArrayWithFailMessageContainsExactly() {
assertThat(new boolean[] {false}).withFailMessage("foo").containsExactly(new boolean[] {true});
}
void testAssertThatBooleanArrayWithFailMessageSupplierContainsExactly() {
assertThat(new boolean[] {false})
.withFailMessage(() -> "foo")
.containsExactly(new boolean[] {true});
}
void testAssertThatByteArrayContainsExactly() {
assertThat(new byte[] {2}).containsExactly(new byte[] {1});
}
void testAssertThatByteArrayWithFailMessageContainsExactly() {
assertThat(new byte[] {2}).withFailMessage("foo").containsExactly(new byte[] {1});
}
void testAssertThatByteArrayWithFailMessageSupplierContainsExactly() {
assertThat(new byte[] {2}).withFailMessage(() -> "foo").containsExactly(new byte[] {1});
}
void testAssertThatCharArrayContainsExactly() {
assertThat(new char[] {'b'}).containsExactly(new char[] {'a'});
}
void testAssertThatCharArrayWithFailMessageContainsExactly() {
assertThat(new char[] {'b'}).withFailMessage("foo").containsExactly(new char[] {'a'});
}
void testAssertThatCharArrayWithFailMessageSupplierContainsExactly() {
assertThat(new char[] {'b'}).withFailMessage(() -> "foo").containsExactly(new char[] {'a'});
}
void testAssertThatShortArrayContainsExactly() {
assertThat(new short[] {2}).containsExactly(new short[] {1});
}
void testAssertThatShortArrayWithFailMessageContainsExactly() {
assertThat(new short[] {2}).withFailMessage("foo").containsExactly(new short[] {1});
}
void testAssertThatShortArrayWithFailMessageSupplierContainsExactly() {
assertThat(new short[] {2}).withFailMessage(() -> "foo").containsExactly(new short[] {1});
}
void testAssertThatIntArrayContainsExactly() {
assertThat(new int[] {2}).containsExactly(new int[] {1});
}
void testAssertThatIntArrayWithFailMessageContainsExactly() {
assertThat(new int[] {2}).withFailMessage("foo").containsExactly(new int[] {1});
}
void testAssertThatIntArrayWithFailMessageSupplierContainsExactly() {
assertThat(new int[] {2}).withFailMessage(() -> "foo").containsExactly(new int[] {1});
}
void testAssertThatLongArrayContainsExactly() {
assertThat(new long[] {2L}).containsExactly(new long[] {1L});
}
void testAssertThatLongArrayWithFailMessageContainsExactly() {
assertThat(new long[] {2L}).withFailMessage("foo").containsExactly(new long[] {1L});
}
void testAssertThatLongArrayWithFailMessageSupplierContainsExactly() {
assertThat(new long[] {2L}).withFailMessage(() -> "foo").containsExactly(new long[] {1L});
}
void testAssertThatFloatArrayContainsExactly() {
assertThat(new float[] {2.0F}).containsExactly(new float[] {1.0F});
}
void testAssertThatFloatArrayWithFailMessageContainsExactly() {
assertThat(new float[] {2.0F}).withFailMessage("foo").containsExactly(new float[] {1.0F});
}
void testAssertThatFloatArrayWithFailMessageSupplierContainsExactly() {
assertThat(new float[] {2.0F}).withFailMessage(() -> "foo").containsExactly(new float[] {1.0F});
}
void testAssertThatFloatArrayContainsExactlyWithOffset() {
assertThat(new float[] {2.0F}).containsExactly(new float[] {1.0F}, offset(0.1f));
}
void testAssertThatFloatArrayWithFailMessageContainsExactlyWithOffset() {
assertThat(new float[] {2.0F})
.withFailMessage("foo")
.containsExactly(new float[] {1.0F}, offset(0.1f));
}
void testAssertThatFloatArrayWithFailMessageSupplierContainsExactlyWithOffset() {
assertThat(new float[] {2.0F})
.withFailMessage(() -> "foo")
.containsExactly(new float[] {1.0F}, offset(0.1f));
}
void testAssertThatDoubleArrayContainsExactly() {
assertThat(new double[] {2.0}).containsExactly(new double[] {1.0});
}
void testAssertThatDoubleArrayWithFailMessageContainsExactly() {
assertThat(new double[] {2.0}).withFailMessage("foo").containsExactly(new double[] {1.0});
}
void testAssertThatDoubleArrayWithFailMessageSupplierContainsExactly() {
assertThat(new double[] {2.0}).withFailMessage(() -> "foo").containsExactly(new double[] {1.0});
}
void testAssertThatDoubleArrayContainsExactlyWithOffset() {
assertThat(new double[] {2.0}).containsExactly(new double[] {1.0}, offset(0.1));
}
void testAssertThatDoubleArrayWithFailMessageContainsExactlyWithOffset() {
assertThat(new double[] {2.0})
.withFailMessage("foo")
.containsExactly(new double[] {1.0}, offset(0.1));
}
void testAssertThatDoubleArrayWithFailMessageSupplierContainsExactlyWithOffset() {
assertThat(new double[] {2.0})
.withFailMessage(() -> "foo")
.containsExactly(new double[] {1.0}, offset(0.1));
}
void testAssertThatObjectArrayContainsExactly() {
assertThat(new Object[] {"bar"}).containsExactly(new Object[] {"foo"});
}
void testAssertThatObjectArrayWithFailMessageContainsExactly() {
assertThat(new Object[] {"bar"}).withFailMessage("foo").containsExactly(new Object[] {"foo"});
}
void testAssertThatObjectArrayWithFailMessageSupplierContainsExactly() {
assertThat(new Object[] {"bar"})
.withFailMessage(() -> "foo")
.containsExactly(new Object[] {"foo"});
}
Object testFail() {
return org.assertj.core.api.Assertions.fail();
}

View File

@@ -1,16 +1,18 @@
package tech.picnic.errorprone.refasterrules;
import static java.util.function.Predicate.not;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSet;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import java.util.function.Predicate;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class NullRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(MoreObjects.class, Optional.class);
return ImmutableSet.of(MoreObjects.class, Optional.class, not(null));
}
ImmutableSet<Boolean> testIsNull() {
@@ -30,11 +32,11 @@ final class NullRulesTest implements RefasterRuleCollectionTestCase {
return Optional.ofNullable("foo").orElseGet(() -> "bar");
}
long testIsNullFunction() {
return Stream.of("foo").filter(s -> s == null).count();
ImmutableSet<Predicate<String>> testIsNullFunction() {
return ImmutableSet.of(s -> s == null, not(Objects::nonNull));
}
long testNonNullFunction() {
return Stream.of("foo").filter(s -> s != null).count();
ImmutableSet<Predicate<String>> testNonNullFunction() {
return ImmutableSet.of(s -> s != null, not(Objects::isNull));
}
}

View File

@@ -2,18 +2,19 @@ package tech.picnic.errorprone.refasterrules;
import static java.util.Objects.requireNonNullElse;
import static java.util.Objects.requireNonNullElseGet;
import static java.util.function.Predicate.not;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSet;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import java.util.function.Predicate;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class NullRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(MoreObjects.class, Optional.class);
return ImmutableSet.of(MoreObjects.class, Optional.class, not(null));
}
ImmutableSet<Boolean> testIsNull() {
@@ -32,11 +33,11 @@ final class NullRulesTest implements RefasterRuleCollectionTestCase {
return requireNonNullElseGet("foo", () -> "bar");
}
long testIsNullFunction() {
return Stream.of("foo").filter(Objects::isNull).count();
ImmutableSet<Predicate<String>> testIsNullFunction() {
return ImmutableSet.of(Objects::isNull, Objects::isNull);
}
long testNonNullFunction() {
return Stream.of("foo").filter(Objects::nonNull).count();
ImmutableSet<Predicate<String>> testNonNullFunction() {
return ImmutableSet.of(Objects::nonNull, Objects::nonNull);
}
}

View File

@@ -325,6 +325,14 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
Flux.just(1).switchMap(n -> Mono.fromSupplier(() -> n * 2)));
}
Flux<String> testFluxMapNotNullTransformationOrElse() {
return Flux.just(1).map(x -> Optional.of(x.toString())).mapNotNull(x -> x.orElse(null));
}
Flux<Integer> testFluxMapNotNullOrElse() {
return Flux.just(Optional.of(1)).filter(Optional::isPresent).map(Optional::orElseThrow);
}
ImmutableSet<Flux<String>> testMonoFlux() {
return ImmutableSet.of(
Mono.just("foo").flatMapMany(Mono::just),

View File

@@ -325,6 +325,14 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
Flux.just(1).mapNotNull(n -> n * 2));
}
Flux<String> testFluxMapNotNullTransformationOrElse() {
return Flux.just(1).mapNotNull(x -> Optional.of(x.toString()).orElse(null));
}
Flux<Integer> testFluxMapNotNullOrElse() {
return Flux.just(Optional.of(1)).mapNotNull(x -> x.orElse(null));
}
ImmutableSet<Flux<String>> testMonoFlux() {
return ImmutableSet.of(
Mono.just("foo").flux(), Mono.just("bar").flux(), Mono.just("baz").flux());

View File

@@ -28,9 +28,9 @@ final class StringRulesTest implements RefasterRuleCollectionTestCase {
"foo".length() == 0,
"bar".length() <= 0,
"baz".length() < 1,
"foo".length() != 0,
"bar".length() > 0,
"baz".length() >= 1);
"qux".length() != 0,
"quux".length() > 0,
"corge".length() >= 1);
}
boolean testStringIsEmptyPredicate() {

View File

@@ -31,9 +31,9 @@ final class StringRulesTest implements RefasterRuleCollectionTestCase {
"foo".isEmpty(),
"bar".isEmpty(),
"baz".isEmpty(),
!"foo".isEmpty(),
!"bar".isEmpty(),
!"baz".isEmpty());
!"qux".isEmpty(),
!"quux".isEmpty(),
!"corge".isEmpty());
}
boolean testStringIsEmptyPredicate() {

View File

@@ -96,31 +96,80 @@ final class TestNGToAssertJRulesTest implements RefasterRuleCollectionTestCase {
}
void testAssertEqual() {
assertEquals(true, true);
assertEquals((byte) 0, (byte) 0);
assertEquals((char) 0, (char) 0);
assertEquals((short) 0, (short) 0);
assertEquals(0, 0);
assertEquals(0L, 0L);
assertEquals(0.0F, 0.0F);
assertEquals(0.0, 0.0);
assertEquals(new Object(), new Object());
assertEquals(true, false);
assertEquals(true, Boolean.FALSE);
assertEquals(Boolean.TRUE, false);
assertEquals(Boolean.TRUE, Boolean.FALSE);
assertEquals((byte) 0, (byte) 1);
assertEquals((byte) 0, Byte.decode("1"));
assertEquals(Byte.decode("0"), (byte) 1);
assertEquals(Byte.decode("0"), Byte.decode("1"));
assertEquals('a', 'b');
assertEquals('a', Character.valueOf('b'));
assertEquals(Character.valueOf('a'), 'b');
assertEquals(Character.valueOf('a'), Character.valueOf('b'));
assertEquals((short) 0, (short) 1);
assertEquals((short) 0, Short.decode("1"));
assertEquals(Short.decode("0"), (short) 1);
assertEquals(Short.decode("0"), Short.decode("1"));
assertEquals(0, 1);
assertEquals(0, Integer.valueOf(1));
assertEquals(Integer.valueOf(0), 1);
assertEquals(Integer.valueOf(0), Integer.valueOf(1));
assertEquals(0L, 1L);
assertEquals(0L, Long.valueOf(1));
assertEquals(Long.valueOf(0), 1L);
assertEquals(Long.valueOf(0), Long.valueOf(1));
assertEquals(0.0F, 1.0F);
assertEquals(0.0F, Float.valueOf(1.0F));
assertEquals(Float.valueOf(0.0F), 1.0F);
assertEquals(Float.valueOf(0.0F), Float.valueOf(1.0F));
assertEquals(0.0, 1.0);
assertEquals(0.0, Double.valueOf(1.0));
assertEquals(Double.valueOf(0.0), 1.0);
assertEquals(Double.valueOf(0.0), Double.valueOf(1.0));
assertEquals(new Object(), new StringBuilder());
assertEquals("actual", "expected");
assertEquals(ImmutableMap.of(), ImmutableMap.of());
assertEquals(ImmutableMap.of(), ImmutableMap.of(1, 2));
}
void testAssertEqualWithMessage() {
assertEquals(true, true, "foo");
assertEquals((byte) 0, (byte) 0, "bar");
assertEquals((char) 0, (char) 0, "baz");
assertEquals((short) 0, (short) 0, "qux");
assertEquals(0, 0, "quux");
assertEquals(0L, 0L, "quuz");
assertEquals(0.0F, 0.0F, "corge");
assertEquals(0.0, 0.0, "grault");
assertEquals(new Object(), new Object(), "garply");
assertEquals("actual", "expected", "waldo");
assertEquals(ImmutableMap.of(), ImmutableMap.of(), "plugh");
assertEquals(true, false, "foo");
assertEquals(true, Boolean.FALSE, "bar");
assertEquals(Boolean.TRUE, false, "baz");
assertEquals(Boolean.TRUE, Boolean.FALSE, "qux");
assertEquals((byte) 0, (byte) 1, "quux");
assertEquals((byte) 0, Byte.decode("1"), "corge");
assertEquals(Byte.decode("0"), (byte) 1, "grault");
assertEquals(Byte.decode("0"), Byte.decode("1"), "garply");
assertEquals('a', 'b', "waldo");
assertEquals('a', Character.valueOf('b'), "fred");
assertEquals(Character.valueOf('a'), 'b', "plugh");
assertEquals(Character.valueOf('a'), Character.valueOf('b'), "xyzzy");
assertEquals((short) 0, (short) 1, "thud");
assertEquals((short) 0, Short.decode("1"), "foo");
assertEquals(Short.decode("0"), (short) 1, "bar");
assertEquals(Short.decode("0"), Short.decode("1"), "baz");
assertEquals(0, 1, "qux");
assertEquals(0, Integer.valueOf(1), "quux");
assertEquals(Integer.valueOf(0), 1, "corge");
assertEquals(Integer.valueOf(0), Integer.valueOf(1), "grault");
assertEquals(0L, 1L, "garply");
// XXX: Ambiguous method call, as the relevant overload is missing. See testng-team/testng#3199.
// assertEquals(0L, Long.valueOf(1), "waldo");
assertEquals(Long.valueOf(0), 1L, "fred");
assertEquals(Long.valueOf(0), Long.valueOf(1), "plugh");
assertEquals(0.0F, 1.0F, "xyzzy");
assertEquals(0.0F, Float.valueOf(1.0F), "thud");
assertEquals(Float.valueOf(0.0F), 1.0F, "foo");
assertEquals(Float.valueOf(0.0F), Float.valueOf(1.0F), "bar");
assertEquals(0.0, 1.0, "baz");
assertEquals(0.0, Double.valueOf(1.0), "qux");
assertEquals(Double.valueOf(0.0), 1.0, "quux");
assertEquals(Double.valueOf(0.0), Double.valueOf(1.0), "corge");
assertEquals(new Object(), new StringBuilder(), "grault");
assertEquals("actual", "expected", "garply");
assertEquals(ImmutableMap.of(), ImmutableMap.of(1, 2), "waldo");
}
void testAssertEqualFloatsWithDelta() {
@@ -163,6 +212,22 @@ final class TestNGToAssertJRulesTest implements RefasterRuleCollectionTestCase {
assertEquals(new Object[0], new Object[0], "garply");
}
void testAssertEqualFloatArraysWithDelta() {
assertEquals(new float[0], new float[0], 0.0F);
}
void testAssertEqualFloatArraysWithDeltaWithMessage() {
assertEquals(new float[0], new float[0], 0.0F, "foo");
}
void testAssertEqualDoubleArraysWithDelta() {
assertEquals(new double[0], new double[0], 0.0);
}
void testAssertEqualDoubleArraysWithDeltaWithMessage() {
assertEquals(new double[0], new double[0], 0.0, "foo");
}
void testAssertEqualArraysIrrespectiveOfOrder() {
assertEqualsNoOrder(new Object[0], new Object[0]);
}

View File

@@ -101,31 +101,80 @@ final class TestNGToAssertJRulesTest implements RefasterRuleCollectionTestCase {
}
void testAssertEqual() {
assertThat(true).isEqualTo(true);
assertThat((byte) 0).isEqualTo((byte) 0);
assertThat((char) 0).isEqualTo((char) 0);
assertThat((short) 0).isEqualTo((short) 0);
assertThat(0).isEqualTo(0);
assertThat(0L).isEqualTo(0L);
assertThat(0.0F).isEqualTo(0.0F);
assertThat(0.0).isEqualTo(0.0);
assertThat(new Object()).isEqualTo(new Object());
assertThat(true).isEqualTo(false);
assertThat(true).isEqualTo(Boolean.FALSE);
assertThat(Boolean.TRUE).isEqualTo(false);
assertThat(Boolean.TRUE).isEqualTo(Boolean.FALSE);
assertThat((byte) 0).isEqualTo((byte) 1);
assertThat((byte) 0).isEqualTo(Byte.decode("1"));
assertThat(Byte.decode("0")).isEqualTo((byte) 1);
assertThat(Byte.decode("0")).isEqualTo(Byte.decode("1"));
assertThat('a').isEqualTo('b');
assertThat('a').isEqualTo(Character.valueOf('b'));
assertThat(Character.valueOf('a')).isEqualTo('b');
assertThat(Character.valueOf('a')).isEqualTo(Character.valueOf('b'));
assertThat((short) 0).isEqualTo((short) 1);
assertThat((short) 0).isEqualTo(Short.decode("1"));
assertThat(Short.decode("0")).isEqualTo((short) 1);
assertThat(Short.decode("0")).isEqualTo(Short.decode("1"));
assertThat(0).isEqualTo(1);
assertThat(0).isEqualTo(Integer.valueOf(1));
assertThat(Integer.valueOf(0)).isEqualTo(1);
assertThat(Integer.valueOf(0)).isEqualTo(Integer.valueOf(1));
assertThat(0L).isEqualTo(1L);
assertThat(0L).isEqualTo(Long.valueOf(1));
assertThat(Long.valueOf(0)).isEqualTo(1L);
assertThat(Long.valueOf(0)).isEqualTo(Long.valueOf(1));
assertThat(0.0F).isEqualTo(1.0F);
assertThat(0.0F).isEqualTo(Float.valueOf(1.0F));
assertThat(Float.valueOf(0.0F)).isEqualTo(1.0F);
assertThat(Float.valueOf(0.0F)).isEqualTo(Float.valueOf(1.0F));
assertThat(0.0).isEqualTo(1.0);
assertThat(0.0).isEqualTo(Double.valueOf(1.0));
assertThat(Double.valueOf(0.0)).isEqualTo(1.0);
assertThat(Double.valueOf(0.0)).isEqualTo(Double.valueOf(1.0));
assertThat(new Object()).isEqualTo(new StringBuilder());
assertThat("actual").isEqualTo("expected");
assertThat(ImmutableMap.of()).isEqualTo(ImmutableMap.of());
assertThat(ImmutableMap.of()).isEqualTo(ImmutableMap.of(1, 2));
}
void testAssertEqualWithMessage() {
assertThat(true).withFailMessage("foo").isEqualTo(true);
assertThat((byte) 0).withFailMessage("bar").isEqualTo((byte) 0);
assertThat((char) 0).withFailMessage("baz").isEqualTo((char) 0);
assertThat((short) 0).withFailMessage("qux").isEqualTo((short) 0);
assertThat(0).withFailMessage("quux").isEqualTo(0);
assertThat(0L).withFailMessage("quuz").isEqualTo(0L);
assertThat(0.0F).withFailMessage("corge").isEqualTo(0.0F);
assertThat(0.0).withFailMessage("grault").isEqualTo(0.0);
assertThat(new Object()).withFailMessage("garply").isEqualTo(new Object());
assertThat("actual").withFailMessage("waldo").isEqualTo("expected");
assertThat(ImmutableMap.of()).withFailMessage("plugh").isEqualTo(ImmutableMap.of());
assertThat(true).withFailMessage("foo").isEqualTo(false);
assertThat(true).withFailMessage("bar").isEqualTo(Boolean.FALSE);
assertThat(Boolean.TRUE).withFailMessage("baz").isEqualTo(false);
assertThat(Boolean.TRUE).withFailMessage("qux").isEqualTo(Boolean.FALSE);
assertThat((byte) 0).withFailMessage("quux").isEqualTo((byte) 1);
assertThat((byte) 0).withFailMessage("corge").isEqualTo(Byte.decode("1"));
assertThat(Byte.decode("0")).withFailMessage("grault").isEqualTo((byte) 1);
assertThat(Byte.decode("0")).withFailMessage("garply").isEqualTo(Byte.decode("1"));
assertThat('a').withFailMessage("waldo").isEqualTo('b');
assertThat('a').withFailMessage("fred").isEqualTo(Character.valueOf('b'));
assertThat(Character.valueOf('a')).withFailMessage("plugh").isEqualTo('b');
assertThat(Character.valueOf('a')).withFailMessage("xyzzy").isEqualTo(Character.valueOf('b'));
assertThat((short) 0).withFailMessage("thud").isEqualTo((short) 1);
assertThat((short) 0).withFailMessage("foo").isEqualTo(Short.decode("1"));
assertThat(Short.decode("0")).withFailMessage("bar").isEqualTo((short) 1);
assertThat(Short.decode("0")).withFailMessage("baz").isEqualTo(Short.decode("1"));
assertThat(0).withFailMessage("qux").isEqualTo(1);
assertThat(0).withFailMessage("quux").isEqualTo(Integer.valueOf(1));
assertThat(Integer.valueOf(0)).withFailMessage("corge").isEqualTo(1);
assertThat(Integer.valueOf(0)).withFailMessage("grault").isEqualTo(Integer.valueOf(1));
assertThat(0L).withFailMessage("garply").isEqualTo(1L);
// XXX: Ambiguous method call, as the relevant overload is missing. See testng-team/testng#3199.
// assertEquals(0L, Long.valueOf(1), "waldo");
assertThat(Long.valueOf(0)).withFailMessage("fred").isEqualTo(1L);
assertThat(Long.valueOf(0)).withFailMessage("plugh").isEqualTo(Long.valueOf(1));
assertThat(0.0F).withFailMessage("xyzzy").isEqualTo(1.0F);
assertThat(0.0F).withFailMessage("thud").isEqualTo(Float.valueOf(1.0F));
assertThat(Float.valueOf(0.0F)).withFailMessage("foo").isEqualTo(1.0F);
assertThat(Float.valueOf(0.0F)).withFailMessage("bar").isEqualTo(Float.valueOf(1.0F));
assertThat(0.0).withFailMessage("baz").isEqualTo(1.0);
assertThat(0.0).withFailMessage("qux").isEqualTo(Double.valueOf(1.0));
assertThat(Double.valueOf(0.0)).withFailMessage("quux").isEqualTo(1.0);
assertThat(Double.valueOf(0.0)).withFailMessage("corge").isEqualTo(Double.valueOf(1.0));
assertThat(new Object()).withFailMessage("grault").isEqualTo(new StringBuilder());
assertThat("actual").withFailMessage("garply").isEqualTo("expected");
assertThat(ImmutableMap.of()).withFailMessage("waldo").isEqualTo(ImmutableMap.of(1, 2));
}
void testAssertEqualFloatsWithDelta() {
@@ -168,6 +217,22 @@ final class TestNGToAssertJRulesTest implements RefasterRuleCollectionTestCase {
assertThat(new Object[0]).withFailMessage("garply").containsExactly(new Object[0]);
}
void testAssertEqualFloatArraysWithDelta() {
assertThat(new float[0]).containsExactly(new float[0], offset(0.0F));
}
void testAssertEqualFloatArraysWithDeltaWithMessage() {
assertThat(new float[0]).withFailMessage("foo").containsExactly(new float[0], offset(0.0F));
}
void testAssertEqualDoubleArraysWithDelta() {
assertThat(new double[0]).containsExactly(new double[0], offset(0.0));
}
void testAssertEqualDoubleArraysWithDeltaWithMessage() {
assertThat(new double[0]).withFailMessage("foo").containsExactly(new double[0], offset(0.0));
}
void testAssertEqualArraysIrrespectiveOfOrder() {
assertThat(new Object[0]).containsExactlyInAnyOrder(new Object[0]);
}

View File

@@ -15,26 +15,6 @@
<url>https://error-prone.picnic.tech</url>
<dependencies>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>error-prone-utils</artifactId>
@@ -45,6 +25,26 @@
<artifactId>auto-service-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>

View File

@@ -15,31 +15,6 @@
<url>https://error-prone.picnic.tech</url>
<dependencies>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>documentation-support</artifactId>
@@ -68,6 +43,31 @@
<artifactId>auto-service-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.googlejavaformat</groupId>
<artifactId>google-java-format</artifactId>

View File

@@ -16,22 +16,22 @@
<dependencies>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>provided</scope>
</dependency>

View File

@@ -63,9 +63,11 @@ public final class SourceCode {
* found.
* @return A non-{@code null} string.
* @apiNote This method differs from {@link com.sun.tools.javac.util.Constants#format(Object)} in
* that it does not superfluously escape single quote characters. It is different from {@link
* that it does not superfluously escape single quote characters (the latter only does the
* "clean thing" starting from JDK 23). It is different from {@link
* VisitorState#getConstantExpression(Object)} in that it is more performant and accepts any
* {@link CharSequence} instance.
* @see <a href="https://bugs.openjdk.org/browse/JDK-8325078">JDK-8325078</a>
*/
// XXX: Drop this method if https://github.com/google/error-prone/pull/4586 is merged and released
// with the proposed `CharSequence` compatibility change.

View File

@@ -14875,7 +14875,7 @@
final String defaultValue = getDefaultValue(propertyName, field, instance);
--- a/src/main/java/com/puppycrawl/tools/checkstyle/site/SiteUtil.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/site/SiteUtil.java
@@ -19,6 +19,14 @@
@@ -19,6 +19,15 @@
package com.puppycrawl.tools.checkstyle.site;
@@ -14886,11 +14886,12 @@
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.puppycrawl.tools.checkstyle.Checker;
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
@@ -55,7 +63,6 @@ import java.net.URI;
@@ -55,7 +64,6 @@ import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -14898,7 +14899,7 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
@@ -72,7 +79,6 @@ import java.util.Optional;
@@ -72,7 +80,6 @@ import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;
@@ -14906,7 +14907,31 @@
import java.util.stream.IntStream;
import java.util.stream.Stream;
import javax.annotation.Nullable;
@@ -156,7 +162,7 @@ public final class SiteUtil {
@@ -131,12 +138,17 @@ public final class SiteUtil {
/** Class name and their corresponding parent module name. */
private static final Map<Class<?>, String> CLASS_TO_PARENT_MODULE =
- Map.ofEntries(
- Map.entry(AbstractCheck.class, TreeWalker.class.getSimpleName()),
- Map.entry(TreeWalkerFilter.class, TreeWalker.class.getSimpleName()),
- Map.entry(AbstractFileSetCheck.class, Checker.class.getSimpleName()),
- Map.entry(Filter.class, Checker.class.getSimpleName()),
- Map.entry(BeforeExecutionFileFilter.class, Checker.class.getSimpleName()));
+ ImmutableMap.of(
+ AbstractCheck.class,
+ TreeWalker.class.getSimpleName(),
+ TreeWalkerFilter.class,
+ TreeWalker.class.getSimpleName(),
+ AbstractFileSetCheck.class,
+ Checker.class.getSimpleName(),
+ Filter.class,
+ Checker.class.getSimpleName(),
+ BeforeExecutionFileFilter.class,
+ Checker.class.getSimpleName());
/** Set of properties that every check has. */
private static final Set<String> CHECK_PROPERTIES = getProperties(AbstractCheck.class);
@@ -156,7 +168,7 @@ public final class SiteUtil {
/** Set of properties that are undocumented. Those are internal properties. */
private static final Set<String> UNDOCUMENTED_PROPERTIES =
@@ -14915,7 +14940,7 @@
"SuppressWithNearbyCommentFilter.fileContents", "SuppressionCommentFilter.fileContents");
/** Properties that can not be gathered from class instance. */
@@ -294,27 +300,25 @@ public final class SiteUtil {
@@ -294,27 +306,25 @@ public final class SiteUtil {
/** Path to main source code folder. */
private static final String MAIN_FOLDER_PATH =
@@ -14932,16 +14957,16 @@
+ new File(Path.of(MAIN_FOLDER_PATH, CHECKS, NAMING, "AbstractNameCheck.java").toString()),
new File(
- Paths.get(MAIN_FOLDER_PATH, CHECKS, NAMING, "AbstractNameCheck.java").toString()),
- new File(
- Paths.get(MAIN_FOLDER_PATH, CHECKS, "javadoc", "AbstractJavadocCheck.java")
- .toString()),
- new File(Paths.get(MAIN_FOLDER_PATH, "api", "AbstractFileSetCheck.java").toString()),
+ Path.of(MAIN_FOLDER_PATH, CHECKS, "javadoc", "AbstractJavadocCheck.java").toString()),
+ new File(Path.of(MAIN_FOLDER_PATH, "api", "AbstractFileSetCheck.java").toString()),
new File(
- Paths.get(MAIN_FOLDER_PATH, CHECKS, "header", "AbstractHeaderCheck.java").toString()),
- Paths.get(MAIN_FOLDER_PATH, CHECKS, "javadoc", "AbstractJavadocCheck.java")
- .toString()),
- new File(Paths.get(MAIN_FOLDER_PATH, "api", "AbstractFileSetCheck.java").toString()),
+ Path.of(MAIN_FOLDER_PATH, CHECKS, "header", "AbstractHeaderCheck.java").toString()),
new File(
- Paths.get(MAIN_FOLDER_PATH, CHECKS, "header", "AbstractHeaderCheck.java").toString()),
- new File(
- Paths.get(MAIN_FOLDER_PATH, CHECKS, "metrics", "AbstractClassCouplingCheck.java")
+ Path.of(MAIN_FOLDER_PATH, CHECKS, "metrics", "AbstractClassCouplingCheck.java")
.toString()),
@@ -14951,7 +14976,7 @@
.toString()));
/** Private utility constructor. */
@@ -475,7 +479,7 @@ public final class SiteUtil {
@@ -475,7 +485,7 @@ public final class SiteUtil {
* @throws MacroExecutionException if an I/O error occurs.
*/
public static Set<Path> getXdocsTemplatesFilePaths() throws MacroExecutionException {
@@ -14960,7 +14985,7 @@
try (Stream<Path> stream =
Files.find(
directory,
@@ -483,7 +487,7 @@ public final class SiteUtil {
@@ -483,7 +493,7 @@ public final class SiteUtil {
(path, attr) -> {
return attr.isRegularFile() && path.toString().endsWith(".xml.template");
})) {
@@ -14969,7 +14994,7 @@
} catch (IOException ioException) {
throw new MacroExecutionException("Failed to find xdocs templates", ioException);
}
@@ -510,7 +514,7 @@ public final class SiteUtil {
@@ -510,7 +520,7 @@ public final class SiteUtil {
}
// If parent class is not found, check interfaces
@@ -14978,7 +15003,7 @@
final Class<?>[] interfaces = moduleClass.getInterfaces();
for (Class<?> interfaceClass : interfaces) {
parentModuleName = CLASS_TO_PARENT_MODULE.get(interfaceClass);
@@ -520,7 +524,7 @@ public final class SiteUtil {
@@ -520,7 +530,7 @@ public final class SiteUtil {
}
}
@@ -14987,7 +15012,7 @@
final String message =
String.format(
Locale.ROOT, "Failed to find parent module for %s", moduleClass.getSimpleName());
@@ -544,7 +548,7 @@ public final class SiteUtil {
@@ -544,7 +554,7 @@ public final class SiteUtil {
prop -> {
return !isGlobalProperty(clss, prop) && !isUndocumentedProperty(clss, prop);
})
@@ -14996,7 +15021,7 @@
properties.addAll(getNonExplicitProperties(instance, clss));
return new TreeSet<>(properties);
}
@@ -663,7 +667,7 @@ public final class SiteUtil {
@@ -663,7 +673,7 @@ public final class SiteUtil {
treeWalkerConfig.addChild(scraperCheckConfig);
try {
checker.configure(defaultConfiguration);
@@ -15005,7 +15030,7 @@
checker.process(filesToProcess);
checker.destroy();
} catch (CheckstyleException checkstyleException) {
@@ -986,9 +990,7 @@ public final class SiteUtil {
@@ -986,9 +996,7 @@ public final class SiteUtil {
if (value != null && Array.getLength(value) > 0) {
result =
removeSquareBrackets(
@@ -15016,7 +15041,7 @@
}
if (result.isEmpty()) {
@@ -1020,8 +1022,7 @@ public final class SiteUtil {
@@ -1020,8 +1028,7 @@ public final class SiteUtil {
result = "";
} else {
try (Stream<?> valuesStream = getValuesStream(value)) {
@@ -15026,7 +15051,7 @@
}
}
@@ -1062,10 +1063,7 @@ public final class SiteUtil {
@@ -1062,10 +1069,7 @@ public final class SiteUtil {
private static String getIntArrayPropertyValue(Object value) {
try (IntStream stream = getIntStream(value)) {
String result =
@@ -15038,7 +15063,7 @@
if (result.isEmpty()) {
result = CURLY_BRACKETS;
}
@@ -1170,11 +1168,11 @@ public final class SiteUtil {
@@ -1170,11 +1174,11 @@ public final class SiteUtil {
*/
public static List<Integer> getDifference(int[] tokens, int... subtractions) {
final Set<Integer> subtractionsSet =
@@ -15052,7 +15077,7 @@
}
/**
@@ -1221,7 +1219,7 @@ public final class SiteUtil {
@@ -1221,7 +1225,7 @@ public final class SiteUtil {
throw new MacroExecutionException("Failed to get parent path for " + templatePath);
}
return templatePathParent
@@ -15377,7 +15402,7 @@
- if (name == null) {
- throw new IllegalArgumentException(String.format(Locale.ROOT, TOKEN_ID_EXCEPTION_FORMAT, id));
- }
+ checkArgument(name != null, String.format(Locale.ROOT, TOKEN_ID_EXCEPTION_FORMAT, id));
+ checkArgument(name != null, TOKEN_ID_EXCEPTION_FORMAT, id);
return name;
}
@@ -15389,11 +15414,11 @@
- throw new IllegalArgumentException(
- String.format(Locale.ROOT, TOKEN_NAME_EXCEPTION_FORMAT, name));
- }
+ checkArgument(id != null, String.format(Locale.ROOT, TOKEN_NAME_EXCEPTION_FORMAT, name));
+ checkArgument(id != null, TOKEN_NAME_EXCEPTION_FORMAT, name);
return id;
}
@@ -165,10 +163,9 @@ public final class TokenUtil {
@@ -165,10 +163,7 @@ public final class TokenUtil {
* @throws IllegalArgumentException when name is unknown
*/
public static String getShortDescription(String name) {
@@ -15401,13 +15426,11 @@
- throw new IllegalArgumentException(
- String.format(Locale.ROOT, TOKEN_NAME_EXCEPTION_FORMAT, name));
- }
+ checkArgument(
+ TOKEN_NAME_TO_VALUE.containsKey(name),
+ String.format(Locale.ROOT, TOKEN_NAME_EXCEPTION_FORMAT, name));
+ checkArgument(TOKEN_NAME_TO_VALUE.containsKey(name), TOKEN_NAME_EXCEPTION_FORMAT, name);
final String tokenTypes = "com.puppycrawl.tools.checkstyle.api.tokentypes";
final ResourceBundle bundle = ResourceBundle.getBundle(tokenTypes, Locale.ROOT);
@@ -344,7 +341,7 @@ public final class TokenUtil {
@@ -344,7 +339,7 @@ public final class TokenUtil {
public static BitSet asBitSet(String... tokens) {
return Arrays.stream(tokens)
.map(String::trim)
@@ -15418,12 +15441,13 @@
}
--- a/src/main/java/com/puppycrawl/tools/checkstyle/utils/UnmodifiableCollectionUtil.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/utils/UnmodifiableCollectionUtil.java
@@ -19,13 +19,15 @@
@@ -19,13 +19,16 @@
package com.puppycrawl.tools.checkstyle.utils;
+import static java.util.stream.Collectors.toUnmodifiableList;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import java.util.Arrays;
import java.util.Collection;
@@ -15435,7 +15459,7 @@
/**
* <div>Note: it simply wraps the existing JDK methods to provide a workaround for Pitest survival
@@ -57,7 +59,7 @@ public final class UnmodifiableCollectionUtil {
@@ -57,7 +60,7 @@ public final class UnmodifiableCollectionUtil {
* @return An unmodifiable List containing elements of the specified type.
*/
public static <S, T> List<T> unmodifiableList(Collection<S> items, Class<T> elementType) {
@@ -15444,7 +15468,16 @@
}
/**
@@ -92,6 +94,6 @@ public final class UnmodifiableCollectionUtil {
@@ -81,7 +84,7 @@ public final class UnmodifiableCollectionUtil {
* @return an immutable copy of the input map
*/
public static <K, V> Map<K, V> copyOfMap(Map<? extends K, ? extends V> map) {
- return Map.copyOf(map);
+ return ImmutableMap.copyOf(map);
}
/**
@@ -92,6 +95,6 @@ public final class UnmodifiableCollectionUtil {
* @return immutable set
*/
public static <T> Set<T> singleton(T obj) {
@@ -56937,6 +56970,15 @@
private static final Map<String, Class<?>> FULLY_QUALIFIED_CLASS_NAMES =
ImmutableMap.<String, Class<?>>builder()
.put("int", int.class)
@@ -97,7 +96,7 @@ public class XdocsJavaDocsTest extends AbstractModuleTestSupport {
.put("URI", URI.class)
.put("WrapOption", WrapOption.class)
.put("PARAM_LITERAL", int[].class)
- .build();
+ .buildOrThrow();
private static final List<List<Node>> CHECK_PROPERTIES = new ArrayList<>();
private static final Map<String, String> CHECK_PROPERTY_DOC = new HashMap<>();
@@ -115,14 +114,14 @@ public class XdocsJavaDocsTest extends AbstractModuleTestSupport {
}

View File

@@ -1,3 +1,5 @@
src/it/java/com/google/checkstyle/test/base/AbstractIndentationTestSupport.java:[100,21] [EagerStringFormatting] String formatting can be deferred (assuming that Guava's simplified formatting support suffices)
src/it/java/com/google/checkstyle/test/base/AbstractIndentationTestSupport.java:[85,21] [EagerStringFormatting] String formatting can be deferred (assuming that Guava's simplified formatting support suffices)
src/it/java/com/google/checkstyle/test/chapter7javadoc/rule734nonrequiredjavadoc/NonRequiredJavadocTest.java:[33,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/com/sun/checkstyle/test/chapter5comments/rule52documentationcomments/InvalidJavadocPositionTest.java:[35,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAbbreviationAsWordInNameTest.java:[116,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `enum` is not a valid identifier)
@@ -105,6 +107,8 @@ src/test/java/com/puppycrawl/tools/checkstyle/checks/design/InterfaceIsTypeCheck
src/test/java/com/puppycrawl/tools/checkstyle/checks/design/MutableExceptionCheckTest.java:[54,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheckTest.java:[100,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `null` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheckTest.java:[81,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndentationCheckTest.java:[69,21] [EagerStringFormatting] String formatting can be deferred (assuming that Guava's simplified formatting support suffices)
src/test/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndentationCheckTest.java:[80,21] [EagerStringFormatting] String formatting can be deferred (assuming that Guava's simplified formatting support suffices)
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/InvalidJavadocPositionCheckTest.java:[59,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocContentLocationCheckTest.java:[57,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocContentLocationCheckTest.java:[75,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `package` is not a valid identifier)

View File

@@ -7,7 +7,7 @@
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <version>3.26.3<!-- Renovate: org.assertj:assertj-bom --></version>
+ <version>3.27.2<!-- Renovate: org.assertj:assertj-bom --></version>
+ <scope>test</scope>
+ </dependency>
<dependency>

View File

@@ -3028,17 +3028,16 @@
SharedMetricRegistries.getDefault();
});
- assertTrue(exception.getMessage().contains("Default registry name has not been set."));
+ assertThat(exception.getMessage().contains("Default registry name has not been set.")).isTrue();
+ assertThat(exception.getMessage()).contains("Default registry name has not been set.");
}
@Test
@@ -81,7 +80,8 @@ class SharedMetricRegistriesTest {
@@ -81,7 +80,7 @@ class SharedMetricRegistriesTest {
SharedMetricRegistries.setDefault("foobah");
SharedMetricRegistries.setDefault("borg");
});
- assertTrue(exception.getMessage().contains("Default metric registry name is already set."));
+ assertThat(exception.getMessage().contains("Default metric registry name is already set."))
+ .isTrue();
+ assertThat(exception.getMessage()).contains("Default metric registry name is already set.");
}
@Test
@@ -4943,27 +4942,25 @@
SharedHealthCheckRegistries.getDefault();
});
- assertTrue(exception.getMessage().contains("Default registry name has not been set."));
+ assertThat(exception.getMessage().contains("Default registry name has not been set.")).isTrue();
+ assertThat(exception.getMessage()).contains("Default registry name has not been set.");
}
@Test
@@ -85,7 +84,8 @@ class SharedHealthCheckRegistriesTest {
@@ -85,7 +84,7 @@ class SharedHealthCheckRegistriesTest {
SharedHealthCheckRegistries.setDefault("default");
SharedHealthCheckRegistries.setDefault("default");
});
- assertTrue(exception.getMessage().contains("Default health check registry is already set."));
+ assertThat(exception.getMessage().contains("Default health check registry is already set."))
+ .isTrue();
+ assertThat(exception.getMessage()).contains("Default health check registry is already set.");
}
@Test
@@ -97,6 +97,7 @@ class SharedHealthCheckRegistriesTest {
@@ -97,6 +96,6 @@ class SharedHealthCheckRegistriesTest {
SharedHealthCheckRegistries.setDefault("default", new HealthCheckRegistry());
SharedHealthCheckRegistries.setDefault("default", new HealthCheckRegistry());
});
- assertTrue(exception.getMessage().contains("Default health check registry is already set."));
+ assertThat(exception.getMessage().contains("Default health check registry is already set."))
+ .isTrue();
+ assertThat(exception.getMessage()).contains("Default health check registry is already set.");
}
}
--- a/metrics-healthchecks/src/test/java/io/dropwizard/metrics5/health/jvm/ThreadDeadlockHealthCheckTest.java
@@ -5137,7 +5134,7 @@
- Mockito.verify(registry, Mockito.atLeast(1)).registerGauge(argumentCaptor.capture(), any());
- assertTrue(argumentCaptor.getValue().getKey().contains("some-other-name"));
+ verify(registry, atLeast(1)).registerGauge(argumentCaptor.capture(), any());
+ assertThat(argumentCaptor.getValue().getKey().contains("some-other-name")).isTrue();
+ assertThat(argumentCaptor.getValue().getKey()).contains("some-other-name");
}
}
--- a/metrics-httpclient/src/test/java/io/dropwizard/metrics5/httpclient/InstrumentedHttpClientsTest.java
@@ -5215,7 +5212,7 @@
- Mockito.verify(registry, Mockito.atLeast(1)).registerGauge(argumentCaptor.capture(), any());
- assertTrue(argumentCaptor.getValue().getKey().contains("some-other-name"));
+ verify(registry, atLeast(1)).registerGauge(argumentCaptor.capture(), any());
+ assertThat(argumentCaptor.getValue().getKey().contains("some-other-name")).isTrue();
+ assertThat(argumentCaptor.getValue().getKey()).contains("some-other-name");
}
}
--- a/metrics-httpclient5/src/test/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpAsyncClientsTest.java
@@ -5305,7 +5302,7 @@
- Mockito.verify(registry, Mockito.atLeast(1)).registerGauge(argumentCaptor.capture(), any());
- assertTrue(argumentCaptor.getValue().getKey().contains("some-other-name"));
+ verify(registry, atLeast(1)).registerGauge(argumentCaptor.capture(), any());
+ assertThat(argumentCaptor.getValue().getKey().contains("some-other-name")).isTrue();
+ assertThat(argumentCaptor.getValue().getKey()).contains("some-other-name");
}
}
--- a/metrics-httpclient5/src/test/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpClientsTest.java

View File

@@ -4459,6 +4459,15 @@
"values from otel have precedence over builder",
new TestCase()
.expectedProperties(
@@ -113,7 +113,7 @@ class OtelAutoConfigTest {
.put("otel.exporter.otlp.timeout", Optional.of("13s"))
.put("otel.exporter.otlp.metrics.timeout", Optional.empty())
.put("otel.service.name", Optional.of("otel-service"))
- .build())
+ .buildOrThrow())
.expectedResourceAttributes(
ImmutableMap.of(
"key",
@@ -128,7 +128,7 @@ class OtelAutoConfigTest {
"otel-version"))
.exporterBuilder(OtelAutoConfigTest::setBuilderValues)
@@ -4468,15 +4477,44 @@
"values from prom properties have precedence over builder and otel",
new TestCase()
.expectedProperties(
@@ -177,7 +177,7 @@ class OtelAutoConfigTest {
@@ -143,7 +143,7 @@ class OtelAutoConfigTest {
.put("otel.exporter.otlp.metrics.timeout", Optional.of("23s"))
.put("otel.exporter.otlp.timeout", Optional.of("13s"))
.put("otel.service.name", Optional.of("prom-service"))
- .build())
+ .buildOrThrow())
.expectedResourceAttributes(
ImmutableMap.of(
"key",
@@ -176,8 +176,8 @@ class OtelAutoConfigTest {
.put(
"io.prometheus.exporter.opentelemetry.resourceAttributes",
"key=prom-value")
.build())),
- .build())),
- Arguments.of(
+ .buildOrThrow())),
+ arguments(
"values from prom properties builder have precedence over builder and otel",
new TestCase()
.expectedProperties(
@@ -192,7 +192,7 @@ class OtelAutoConfigTest {
.put("otel.exporter.otlp.metrics.timeout", Optional.of("23s"))
.put("otel.exporter.otlp.timeout", Optional.of("13s"))
.put("otel.service.name", Optional.of("prom-service"))
- .build())
+ .buildOrThrow())
.expectedResourceAttributes(
ImmutableMap.of(
"key",
@@ -233,7 +233,7 @@ class OtelAutoConfigTest {
.put(
"otel.resource.attributes",
"key=otel-value,service.namespace=otel-namespace,service.instance.id=otel-instance,service.version=otel-version")
- .build();
+ .buildOrThrow();
}
private static void setBuilderValues(OpenTelemetryExporter.Builder builder) {
@@ -250,8 +250,8 @@ class OtelAutoConfigTest {
.resourceAttribute("key", "builder-value");
}
@@ -4565,7 +4603,12 @@
}
--- a/prometheus-metrics-exporter-opentelemetry/src/test/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusMetricDataTest.java
+++ b/prometheus-metrics-exporter-opentelemetry/src/test/java/io/prometheus/metrics/exporter/opentelemetry/otelmodel/PrometheusMetricDataTest.java
@@ -7,7 +7,7 @@ import io.prometheus.metrics.model.snapshots.Unit;
@@ -3,14 +3,15 @@ package io.prometheus.metrics.exporter.opentelemetry.otelmodel;
import static java.util.Map.entry;
import static org.junit.jupiter.api.Assertions.*;
+import com.google.common.collect.ImmutableMap;
import io.prometheus.metrics.model.snapshots.Unit;
import java.util.Map;
import org.junit.jupiter.api.Test;
@@ -4573,7 +4616,11 @@
+final class PrometheusMetricDataTest {
Map<Object, Object> translations =
Map.ofEntries(
- Map.ofEntries(
+ ImmutableMap.ofEntries(
entry("days", "d"),
entry("hours", "h"),
entry("minutes", "min"),
--- a/prometheus-metrics-exporter-pushgateway/src/main/java/io/prometheus/metrics/exporter/pushgateway/DefaultJobLabelDetector.java
+++ b/prometheus-metrics-exporter-pushgateway/src/main/java/io/prometheus/metrics/exporter/pushgateway/DefaultJobLabelDetector.java
@@ -3,7 +3,6 @@ package io.prometheus.metrics.exporter.pushgateway;
@@ -5921,7 +5968,7 @@
import static io.prometheus.metrics.instrumentation.dropwizard5.labels.MapperConfig.METRIC_GLOB_REGEX;
import java.util.HashMap;
@@ -32,10 +33,9 @@ class GraphiteNamePattern {
@@ -32,10 +33,11 @@ class GraphiteNamePattern {
* @param pattern The glob style pattern to be used.
*/
GraphiteNamePattern(final String pattern) throws IllegalArgumentException {
@@ -5931,11 +5978,13 @@
- }
+ checkArgument(
+ VALIDATION_PATTERN.matcher(pattern).matches(),
+ String.format("Provided pattern [%s] does not matches [%s]", pattern, METRIC_GLOB_REGEX));
+ "Provided pattern [%s] does not matches [%s]",
+ pattern,
+ METRIC_GLOB_REGEX);
initializePattern(pattern);
}
@@ -84,7 +84,7 @@ class GraphiteNamePattern {
@@ -84,7 +86,7 @@ class GraphiteNamePattern {
escapedPattern.append("([^.]*)").append(quoted);
}
@@ -5954,7 +6003,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
@@ -106,21 +108,19 @@ public final class MapperConfig {
@@ -106,21 +108,21 @@ public final class MapperConfig {
}
private void validateMatch(final String match) {
@@ -5966,9 +6015,9 @@
- }
+ checkArgument(
+ MATCH_EXPRESSION_PATTERN.matcher(match).matches(),
+ String.format(
+ "Match expression [%s] does not match required pattern %s",
+ match, MATCH_EXPRESSION_PATTERN));
+ "Match expression [%s] does not match required pattern %s",
+ match,
+ MATCH_EXPRESSION_PATTERN);
}
private void validateLabels(final Map<String, String> labels) {
@@ -5980,11 +6029,13 @@
- }
+ checkArgument(
+ LABEL_PATTERN.matcher(key).matches(),
+ String.format("Label [%s] does not match required pattern %s", match, LABEL_PATTERN));
+ "Label [%s] does not match required pattern %s",
+ match,
+ LABEL_PATTERN);
}
}
}
@@ -149,7 +149,6 @@ public final class MapperConfig {
@@ -149,7 +151,6 @@ public final class MapperConfig {
public int hashCode() {
int result = match != null ? match.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);

145
pom.xml
View File

@@ -113,7 +113,7 @@
-Xmx${argLine.xmx}
<!-- Configure the Byte Buddy Java agent used by Mockito to create
mocks. -->
-javaagent:${org.mockito:mockito-core:jar}
-javaagent:${project.build.directory}/test-agents/mockito-core.jar
<!-- This argument cannot be set through Surefire's
'systemPropertyVariables' configuration setting. Setting the file
encoding is necessary because forked unit test invocations
@@ -144,11 +144,6 @@
specified. Used by the `patch` and `self-check` profiles. -->
<error-prone.patch-args />
<error-prone.self-check-args />
<!-- The Maven `groupId` under which Error Prone dependencies are
published. We use an official Error Prone release by default. This
property allows the `error-prone-fork` profile below to build the
project using Picnic's Error Prone fork instead. -->
<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-11-03T15:58:19Z</project.build.outputTimestamp>
@@ -210,51 +205,26 @@
<version.auto-service>1.1.1</version.auto-service>
<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-fork>${version.error-prone-orig}-picnic-2</version.error-prone-fork>
<version.error-prone-orig>2.36.0</version.error-prone-orig>
<version.error-prone-slf4j>0.1.28</version.error-prone-slf4j>
<version.guava-beta-checker>1.0</version.guava-beta-checker>
<version.jdk>17</version.jdk>
<version.jmh>1.37</version.jmh>
<version.maven>3.9.9</version.maven>
<version.mockito>5.14.2</version.mockito>
<version.mockito>5.15.2</version.mockito>
<!-- XXX: Consider providing our own implementation with similar
functionality, and designing it such that JMH classes would not need to
be annotated `@Open`. -->
<version.nopen>1.0.1</version.nopen>
<version.nullaway>0.12.2</version.nullaway>
<version.nullaway>0.12.3</version.nullaway>
<version.pitest-git>1.1.4</version.pitest-git>
<version.rewrite-templating>1.20.1</version.rewrite-templating>
<version.rewrite-templating>1.21.0</version.rewrite-templating>
<version.surefire>3.2.3</version.surefire>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotation</artifactId>
<version>${version.error-prone}</version>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotations</artifactId>
<version>${version.error-prone}</version>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_check_api</artifactId>
<version>${version.error-prone}</version>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_core</artifactId>
<version>${version.error-prone}</version>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<version>${version.error-prone}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>documentation-support</artifactId>
@@ -337,6 +307,31 @@
<artifactId>auto-value-annotations</artifactId>
<version>${version.auto-value}</version>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotation</artifactId>
<version>${version.error-prone}</version>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<version>${version.error-prone}</version>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_check_api</artifactId>
<version>${version.error-prone}</version>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<version>${version.error-prone}</version>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<version>${version.error-prone}</version>
</dependency>
<dependency>
<groupId>com.google.googlejavaformat</groupId>
<artifactId>google-java-format</artifactId>
@@ -377,14 +372,14 @@
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-bom</artifactId>
<version>1.14.2</version>
<version>1.14.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-bom</artifactId>
<version>2024.0.1</version>
<version>2024.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -396,7 +391,7 @@
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.6.14</version>
<version>1.6.15</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
@@ -454,14 +449,14 @@
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-bom</artifactId>
<version>3.26.3</version>
<version>3.27.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
<version>3.48.3</version>
<version>3.48.4</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
@@ -476,7 +471,7 @@
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>3.19.16</version>
<version>3.19.18</version>
</dependency>
<dependency>
<groupId>org.jspecify</groupId>
@@ -500,7 +495,7 @@
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-core</artifactId>
<version>5.2.1</version>
<version>5.3.0</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
@@ -520,7 +515,7 @@
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-recipe-bom</artifactId>
<version>2.23.2</version>
<version>3.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -534,7 +529,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>6.2.1</version>
<version>6.2.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -950,7 +945,7 @@
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>10.21.0</version>
<version>10.21.1</version>
</dependency>
<dependency>
<groupId>io.spring.nohttp</groupId>
@@ -1076,10 +1071,16 @@
</configuration>
<executions>
<execution>
<id>set-additional-properties</id>
<id>copy-test-agents</id>
<goals>
<goal>properties</goal>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeGroupIds>org.mockito</includeGroupIds>
<includeArtifactIds>mockito-core</includeArtifactIds>
<stripVersion>true</stripVersion>
<outputDirectory>${project.build.directory}/test-agents</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
@@ -1499,7 +1500,7 @@
<plugin>
<groupId>org.gaul</groupId>
<artifactId>modernizer-maven-plugin</artifactId>
<version>2.9.0</version>
<version>3.0.0</version>
<configuration>
<exclusionPatterns>
<!-- The plugin suggests replacing usages of
@@ -1560,7 +1561,7 @@
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>1.17.3</version>
<version>1.17.4</version>
<configuration>
<excludedClasses>
<!-- AutoValue generated classes. -->
@@ -1638,52 +1639,8 @@
<profile>
<id>error-prone-fork</id>
<properties>
<groupId.error-prone>com.github.PicnicSupermarket.error-prone</groupId.error-prone>
<version.error-prone>${version.error-prone-fork}</version.error-prone>
</properties>
<dependencyManagement>
<!-- Even when we directly depend on the Picnic Error Prone
fork, some other dependencies depend on the official (i.e.,
non-forked) `error_prone_annotations`. Here we fix which
version is pulled in. -->
<dependencies>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<version>${version.error-prone-orig}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<configuration>
<rules>
<banDuplicateClasses>
<!-- The original
`error_prone_annotations` dependency
contains the same classes as those
provided by the corresponding Picnic
Error Prone fork artifact. -->
<dependencies combine.children="append">
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<ignoreClasses>
<ignoreClass>*</ignoreClass>
</ignoreClasses>
</dependency>
</dependencies>
</banDuplicateClasses>
</rules>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
<profile>
<!-- Error Prone checks that are not available from Maven Central;
@@ -1933,7 +1890,7 @@
declarations once properly supported. See
https://youtrack.jetbrains.com/issue/IDEA-342187. -->
<path>
<groupId>${groupId.error-prone}</groupId>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<version>${version.error-prone}</version>
</path>

View File

@@ -15,19 +15,6 @@
<url>https://error-prone.picnic.tech</url>
<dependencies>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_check_api</artifactId>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_core</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>refaster-support</artifactId>
@@ -37,6 +24,19 @@
<artifactId>auto-service-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_check_api</artifactId>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>

View File

@@ -15,31 +15,6 @@
<url>https://error-prone.picnic.tech</url>
<dependencies>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>refaster-compiler</artifactId>
@@ -66,6 +41,31 @@
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>

View File

@@ -15,43 +15,36 @@
<url>https://error-prone.picnic.tech</url>
<dependencies>
<!-- This dependency is listed out-of-order so as not to confuse the
`maven-dependency-plugin` when the `error-prone-fork` profile is
enabled: the `error_prone_annotation` dependency pulls in the
non-forked `error_prone_annotations` artifact through a dependency on
Guava. -->
<?SORTPOM IGNORE?>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<?SORTPOM RESUME?>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>

View File

@@ -15,28 +15,6 @@
<url>https://error-prone.picnic.tech</url>
<dependencies>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotation</artifactId>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_check_api</artifactId>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_test_helpers</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>refaster-runner</artifactId>
@@ -46,6 +24,28 @@
<artifactId>auto-service-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotation</artifactId>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_check_api</artifactId>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_test_helpers</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>

View File

@@ -5,13 +5,13 @@
<profile>
<!-- The build defines an optional `error-prone-fork` profile using
which the code is built against a Picnic-managed fork of Error
Prone. This fork is hosted by Jitpack.io. See
https://jitpack.io/#PicnicSupermarket/error-prone. -->
Prone. This fork is hosted using GitHub Packages. See
https://github.com/PicnicSupermarket/error-prone/packages. -->
<id>error-prone-fork</id>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
<id>error-prone-fork</id>
<url>https://maven.pkg.github.com/PicnicSupermarket/error-prone</url>
</repository>
</repositories>
</profile>
@@ -29,4 +29,11 @@
</profile>
</profiles>
<servers>
<server>
<id>error-prone-fork</id>
<username>${env.GITHUB_ACTOR}</username>
<password>${env.GITHUB_TOKEN}</password>
</server>
</servers>
</settings>

View File

@@ -86,7 +86,7 @@ for eps_version in ${eps_versions}; do
-Ppatch \
-Pself-check \
-Dverification.skip \
-Dversion.error-prone-orig="${ep_version}" \
-Dversion.error-prone="${ep_version}" \
&& echo "SUCCESS: { \"eps_version\": \"${eps_version}\", \"ep_version\": \"${ep_version}\" }" || true
# Undo any changes applied by the checks.
git checkout -- '*.java'