Compare commits

...

110 Commits

Author SHA1 Message Date
Stephan Schroevers
a1ca5b2505 Introduce ReturnValueUnused matcher for Refaster use
WIP:
1. As-is this isn't actually useful, because currently there's no way to
   express that a certain matcher should apply to a whole expression
   (rather than just a "free variable"/template parameter).
2. There are some XXXes.
3. Assuming (1) is resolved somehow, we should add at least one Refaster
   template demonstrating how this is used. Example transformation we'd
   want to be able to do in case the expression's return value is
   ignored: `flux.blockLast()` -> `flux.then().block()`.
2024-02-10 16:51:43 +01:00
Picnic-Bot
da3ec2ce90 Upgrade pitest-maven-plugin 1.15.6 -> 1.15.7 (#1020)
See:
- https://github.com/hcoles/pitest/releases/tag/1.15.7
- https://github.com/hcoles/pitest/compare/1.15.6...1.15.7
2024-02-10 14:50:46 +01:00
Picnic-Bot
b8abceab73 Upgrade SLF4J 2.0.11 -> 2.0.12 (#1019)
See:
- https://www.slf4j.org/news.html
- https://github.com/qos-ch/slf4j/compare/v_2.0.11...v_2.0.12
2024-02-10 14:30:48 +01:00
Picnic-Bot
c594a16c7c Upgrade OpenRewrite 2.6.3 -> 2.6.4 (#1018)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.6.4
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.6.3...v2.6.4
2024-02-10 13:59:53 +01:00
Picnic-Bot
2c95de3879 Upgrade AssertJ 3.25.2 -> 3.25.3 (#1014)
See:
- https://github.com/assertj/assertj/releases/tag/assertj-build-3.25.3
- https://github.com/assertj/assertj/compare/assertj-build-3.25.2...assertj-build-3.25.3
2024-02-10 13:18:06 +01:00
Picnic-Bot
048167b021 Upgrade OpenRewrite Templating 1.4.4 -> 1.5.0 (#1021)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.5.0
- https://github.com/openrewrite/rewrite-templating/compare/v1.4.4...v1.5.0
2024-02-10 13:08:12 +01:00
Picnic-Bot
bf06625211 Upgrade Truth 1.3.0 -> 1.4.0 (#1013)
See:
- https://github.com/google/truth/releases/tag/v1.4.0
- https://github.com/google/truth/compare/v1.3.0...v1.4.0
2024-02-10 12:59:01 +01:00
Rick Ossendrijver
9a2a1915eb Introduce error-prone-guidelines module (#1002)
And move all applicable checks to this new module.
2024-02-10 12:06:22 +01:00
Picnic-Bot
a01e5e4cf1 Upgrade actions/upload-artifact v4.3.0 -> v4.3.1 (#1017)
See:
- https://github.com/actions/upload-artifact/releases/tag/v4.3.1
2024-02-10 11:24:34 +01:00
Rick Ossendrijver
6195ede1f5 Introduce error-prone-experimental module (#1003)
And move the known-incomplete `MethodReferenceUsage` check to it.
2024-02-10 11:06:16 +01:00
Rick Ossendrijver
03ba14b229 Make Checkstyle integration test macOS-compatible (#867) 2024-02-10 10:40:48 +01:00
Rick Ossendrijver
c771d5f6b9 Introduce error-prone-utils module (#1000)
By extracting the `tech.picnic.errorprone.bugpatterns.util` package into a new 
Maven module (and renaming the package to `tech.picnic.errorprone.utils`), the 
utility classes it contains will also become usable by other Maven modules.
2024-02-09 16:09:06 +01:00
Picnic-Bot
0ba806432d Upgrade actions/upload-pages-artifact v3.0.0 -> v3.0.1 (#1022)
See:
- https://github.com/actions/upload-pages-artifact/releases/tag/v3.0.1
2024-02-09 13:53:34 +01:00
Rick Ossendrijver
f66e513042 Update {,Non}StaticImport checks (#992)
Summary of changes:
- Disallow static import of `Mono` and `Flux` members.
- Allow static import of `empty` methods.
- Disallow static import of `Optional#empty`.
2024-02-09 13:03:56 +01:00
Picnic-Bot
0a3537669a Upgrade actions/deploy-pages v4.0.3 -> v4.0.4 (#1016)
See:
- https://github.com/actions/deploy-pages/releases/tag/v4.0.4
2024-02-09 12:52:50 +01:00
Picnic-Bot
c96fdf5ed2 Upgrade JUnit 5 5.10.1 -> 5.10.2 (#1015)
See:
- https://junit.org/junit5/docs/current/release-notes/
- https://github.com/junit-team/junit5/releases/tag/r5.10.2
- https://github.com/junit-team/junit5/compare/r5.10.1...r5.10.2
2024-02-09 11:27:53 +01:00
Picnic-Bot
a4ab37d2a9 Upgrade Spring Security 5.3.13.RELEASE -> 5.8.9 (#1009)
See:
- https://github.com/spring-projects/spring-security/releases/tag/5.4.8
- https://github.com/spring-projects/spring-security/releases/tag/5.4.9
- https://github.com/spring-projects/spring-security/releases/tag/5.4.10
- https://github.com/spring-projects/spring-security/releases/tag/5.5.2
- https://github.com/spring-projects/spring-security/releases/tag/5.5.3
- https://github.com/spring-projects/spring-security/releases/tag/5.5.4
- https://github.com/spring-projects/spring-security/releases/tag/5.5.5
- https://github.com/spring-projects/spring-security/releases/tag/5.5.6
- https://github.com/spring-projects/spring-security/releases/tag/5.5.7
- https://github.com/spring-projects/spring-security/releases/tag/5.5.8
- https://github.com/spring-projects/spring-security/releases/tag/5.6.0-M1
- https://github.com/spring-projects/spring-security/releases/tag/5.6.0-M2
- https://github.com/spring-projects/spring-security/releases/tag/5.6.0-M3
- https://github.com/spring-projects/spring-security/releases/tag/5.6.0-RC1
- https://github.com/spring-projects/spring-security/releases/tag/5.6.0
- https://github.com/spring-projects/spring-security/releases/tag/5.6.1
- https://github.com/spring-projects/spring-security/releases/tag/5.6.2
- https://github.com/spring-projects/spring-security/releases/tag/5.6.3
- https://github.com/spring-projects/spring-security/releases/tag/5.6.4
- https://github.com/spring-projects/spring-security/releases/tag/5.6.5
- https://github.com/spring-projects/spring-security/releases/tag/5.6.6
- https://github.com/spring-projects/spring-security/releases/tag/5.6.7
- https://github.com/spring-projects/spring-security/releases/tag/5.6.8
- https://github.com/spring-projects/spring-security/releases/tag/5.6.9
- https://github.com/spring-projects/spring-security/releases/tag/5.6.10
- https://github.com/spring-projects/spring-security/releases/tag/5.6.11
- https://github.com/spring-projects/spring-security/releases/tag/5.6.12
- https://github.com/spring-projects/spring-security/releases/tag/5.7.0-M1
- https://github.com/spring-projects/spring-security/releases/tag/5.7.0-M2
- https://github.com/spring-projects/spring-security/releases/tag/5.7.0-M3
- https://github.com/spring-projects/spring-security/releases/tag/5.7.0-RC1
- https://github.com/spring-projects/spring-security/releases/tag/5.7.0
- https://github.com/spring-projects/spring-security/releases/tag/5.7.1
- https://github.com/spring-projects/spring-security/releases/tag/5.7.2
- https://github.com/spring-projects/spring-security/releases/tag/5.7.3
- https://github.com/spring-projects/spring-security/releases/tag/5.7.4
- https://github.com/spring-projects/spring-security/releases/tag/5.7.5
- https://github.com/spring-projects/spring-security/releases/tag/5.7.6
- https://github.com/spring-projects/spring-security/releases/tag/5.7.7
- https://github.com/spring-projects/spring-security/releases/tag/5.7.8
- https://github.com/spring-projects/spring-security/releases/tag/5.7.9
- https://github.com/spring-projects/spring-security/releases/tag/5.7.10
- https://github.com/spring-projects/spring-security/releases/tag/5.7.11
- https://github.com/spring-projects/spring-security/releases/tag/5.8.0-M1
- https://github.com/spring-projects/spring-security/releases/tag/5.8.0-M2
- https://github.com/spring-projects/spring-security/releases/tag/5.8.0-M3
- https://github.com/spring-projects/spring-security/releases/tag/5.8.0-RC1
- https://github.com/spring-projects/spring-security/releases/tag/5.8.0
- https://github.com/spring-projects/spring-security/releases/tag/5.8.1
- https://github.com/spring-projects/spring-security/releases/tag/5.8.2
- https://github.com/spring-projects/spring-security/releases/tag/5.8.3
- https://github.com/spring-projects/spring-security/releases/tag/5.8.4
- https://github.com/spring-projects/spring-security/releases/tag/5.8.5
- https://github.com/spring-projects/spring-security/releases/tag/5.8.6
- https://github.com/spring-projects/spring-security/releases/tag/5.8.7
- https://github.com/spring-projects/spring-security/releases/tag/5.8.8
- https://github.com/spring-projects/spring-security/releases/tag/5.8.9
- https://github.com/spring-projects/spring-security/compare/5.3.13.RELEASE...5.8.9
2024-02-01 08:07:06 +01:00
Vincent Koeman
07fe6df3af Extend TimeRules Refaster rule collection (#979)
By introducing `SomeDateType{Plus,Minus}SomeUnit` Refaster rules, that suggest
e.g. `LocalDate#plusDays(long)` over more contrived alternatives.
2024-01-31 08:52:53 +01:00
Stephan Schroevers
79ac13809f Run builds on macOS 14 rather than macOS 12 (#1011)
See https://github.blog/changelog/2024-01-30-github-actions-introducing-the-new-m1-macos-runner-available-to-open-source/
2024-01-31 08:43:47 +01:00
Picnic-Bot
f7f561bc9e Upgrade Maven API 3.8.7 -> 3.9.5 (#434)
See:
- https://maven.apache.org/release-notes-all.html
- https://github.com/apache/maven/releases/tag/maven-3.9.0
- https://github.com/apache/maven/releases/tag/maven-3.9.1
- https://github.com/apache/maven/releases/tag/maven-3.9.2
- https://github.com/apache/maven/releases/tag/maven-3.9.3
- https://github.com/apache/maven/releases/tag/maven-3.9.4
- https://github.com/apache/maven/releases/tag/maven-3.9.5
- https://github.com/apache/maven/compare/maven-3.8.7...maven-3.9.5
2024-01-30 15:55:27 +01:00
Stephan Schroevers
90066f87d1 Sync Checkstyle integration test (#999)
Summary of changes:
- Update the set of expected changes for compatibility with the latest
  features, except for the `ErrorProneRuntimeClasspath` check.
- Test against version 10.12.7 rather than 10.13.0.
- Omit the targeted tag from file names, so that similar upgrade PRs can be
  tested using an `/integration-test` GitHub comment.
2024-01-30 15:18:18 +01:00
Maxence Labusquiere
32d5c114c1 Have RequestMappingAnnotation recognize @CurrentSecurityContext parameters (#1006) 2024-01-30 14:54:44 +01:00
Picnic-Bot
e3d94a9ac4 Upgrade Checkstyle 10.12.7 -> 10.13.0 (#1008)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.13.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.12.7...checkstyle-10.13.0
2024-01-30 10:42:47 +01:00
Picnic-Bot
e086be4fea Upgrade NullAway 0.10.21 -> 0.10.22 (#1007)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.10.22
- https://github.com/uber/NullAway/compare/v0.10.21...v0.10.22
2024-01-30 10:24:52 +01:00
Stephan Schroevers
5f80fb5370 Have ErrorProneRuntimeClasspath ignore non-public types (#972) 2024-01-29 10:57:45 +01:00
Picnic-Bot
ba27fc588d Upgrade CodeQL v3.22.12 -> v3.23.2 (#1004)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v3.22.12...v3.23.2
2024-01-29 07:40:12 +01:00
Picnic-Bot
000c33c85f Upgrade ruby/setup-ruby v1.165.1 -> v1.170.0 (#1005)
See:
- https://github.com/ruby/setup-ruby/releases/tag/v1.170.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.169.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.168.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.167.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.166.0
2024-01-29 07:20:47 +01:00
Rick Ossendrijver
a926e5534c Allow static imports of ZERO and ONE identifiers (#996) 2024-01-28 19:32:15 +01:00
Stephan Schroevers
e65e2ce730 Prevent ExplicitEnumOrdering from throwing an NPE (#998) 2024-01-28 13:25:04 +01:00
Picnic-Bot
d4be298022 Upgrade license-maven-plugin 2.3.0 -> 2.4.0 (#991)
See:
- https://github.com/mojohaus/license-maven-plugin/releases/tag/2.4.0
- https://github.com/mojohaus/license-maven-plugin/compare/2.3.0...2.4.0
2024-01-28 12:51:00 +01:00
Picnic-Bot
4f6d32191e Upgrade pitest-maven-plugin 1.15.3 -> 1.15.6 (#984)
See:
- https://github.com/hcoles/pitest/releases/tag/1.15.4
- https://github.com/hcoles/pitest/releases/tag/1.15.5
- https://github.com/hcoles/pitest/releases/tag/1.15.6
- https://github.com/hcoles/pitest/compare/1.15.3...1.15.6
2024-01-27 16:58:13 +01:00
Picnic-Bot
aa592e5e16 Upgrade fmt-maven-plugin 2.22 -> 2.22.1 (#987)
See:
- https://github.com/spotify/fmt-maven-plugin/releases/tag/2.22.1
- https://github.com/spotify/fmt-maven-plugin/compare/2.22.0...2.22.1
2024-01-27 16:43:52 +01:00
Picnic-Bot
a183f921c9 Upgrade OpenRewrite Templating 1.4.3 -> 1.4.4 (#989)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.4.4
- https://github.com/openrewrite/rewrite-templating/compare/v1.4.3...v1.4.4
2024-01-27 16:37:00 +01:00
Picnic-Bot
7d4dc16d6f Upgrade actions/upload-artifact v4.2.0 -> v4.3.0 (#990)
See:
- https://github.com/actions/upload-artifact/releases/tag/v4.3.0
2024-01-27 16:26:19 +01:00
Picnic-Bot
33ebcac257 Upgrade swagger-annotations 1.6.12 -> 1.6.13 (#997)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v1.6.13
- https://github.com/swagger-api/swagger-core/compare/v1.6.12...v1.6.13
2024-01-27 14:32:40 +01:00
Picnic-Bot
4849bb5ae2 Upgrade OpenRewrite 2.6.2 -> 2.6.3 (#988)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.6.3
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.6.2...v2.6.3
2024-01-27 10:50:45 +01:00
Picnic-Bot
a73624da1d Upgrade AssertJ 3.25.1 -> 3.25.2 (#994)
See:
- https://github.com/assertj/assertj/releases/tag/assertj-build-3.25.2
- https://github.com/assertj/assertj/compare/assertj-build-3.25.1...assertj-build-3.25.2
2024-01-26 22:05:12 +01:00
Picnic-Bot
7ef4537ff4 Upgrade Mockito 5.9.0 -> 5.10.0 (#995)
See:
- https://github.com/mockito/mockito/releases/tag/v5.10.0
- https://github.com/mockito/mockito/compare/v5.9.0...v5.10.0
2024-01-26 13:03:27 +01:00
Stephan Schroevers
7e0e1216ec Actually skip test failures during SonarCloud analysis (#986) 2024-01-25 19:49:44 +01:00
Stephan Schroevers
aa1cfd9071 Publish Error Prone compatibility matrix on website (#938)
The new `website/generate-version-compatibility-overview.sh` script
tests all combinations, and stores the result in a Jekyll data file.

Resolves #724.
2024-01-22 10:53:31 +01:00
Stephan Schroevers
0aa612073f Introduce additional Reactor Refaster rules (#969)
In various contexts, suggest more efficient and/or less verbose
constructs.
2024-01-21 13:36:06 +01:00
Picnic-Bot
9e6d35569f Upgrade Truth 1.2.0 -> 1.3.0 (#983)
See:
- https://github.com/google/truth/releases/tag/v1.3.0
- https://github.com/google/truth/compare/v1.2.0...v1.3.0
2024-01-20 13:34:08 +01:00
Stephan Schroevers
dc65917ef1 Avoid NPE in IsEmpty matcher (#978) 2024-01-20 12:34:50 +01:00
Picnic-Bot
f12474e8e6 Upgrade actions/upload-artifact v4.1.0 -> v4.2.0 (#982)
See:
- https://github.com/actions/upload-artifact/releases/tag/v4.2.0
2024-01-20 10:42:45 +01:00
Picnic-Bot
8f152b1135 Upgrade OpenRewrite Templating 1.4.2 -> 1.4.3 (#981)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.4.3
- https://github.com/openrewrite/rewrite-templating/compare/v1.4.2...v1.4.3
2024-01-18 10:19:06 +01:00
Picnic-Bot
b88fc8e542 Upgrade OpenRewrite 2.6.1 -> 2.6.2 (#980)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.6.2
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.6.1...v2.6.2
2024-01-18 09:48:07 +01:00
Picnic-Bot
8f2ac01ac8 Upgrade OpenRewrite 2.5.4 -> 2.6.1 (#961)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.6.0
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.6.1
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.5.4...v2.6.1
2024-01-16 14:08:32 +01:00
Stephan Schroevers
51317fbace Introduce {Max,Min}ByNaturalOrder Refaster rules (#970) 2024-01-16 12:03:28 +01:00
Picnic-Bot
e48492628e Upgrade fmt-maven-plugin 2.21.1 -> 2.22 (#968)
See:
- https://github.com/spotify/fmt-maven-plugin/releases/tag/2.22.0
- https://github.com/spotify/fmt-maven-plugin/compare/2.21.1...2.22.0
2024-01-15 11:10:16 +01:00
Picnic-Bot
b2552e6feb Upgrade Mockito 5.8.0 -> 5.9.0 (#977)
See:
- https://github.com/mockito/mockito/releases/tag/v5.9.0
- https://github.com/mockito/mockito/compare/v5.8.0...v5.9.0
2024-01-15 08:53:09 +01:00
Picnic-Bot
0c2180b151 Upgrade NullAway 0.10.19 -> 0.10.21 (#975)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.10.20
- https://github.com/uber/NullAway/releases/tag/v0.10.21
- https://github.com/uber/NullAway/compare/v0.10.19...v0.10.21
2024-01-15 07:30:32 +01:00
Picnic-Bot
b404737433 Upgrade actions/upload-artifact v4.0.0 -> v4.1.0 (#967)
See:
- https://github.com/actions/upload-artifact/releases/tag/v4.1.0
2024-01-15 07:12:20 +01:00
Picnic-Bot
54bba95ffa Upgrade actions/deploy-pages v4.0.2 -> v4.0.3 (#966)
See:
- https://github.com/actions/deploy-pages/releases/tag/v4.0.3
- https://github.com/actions/deploy-pages/compare/v4.0.2...v4.0.3
2024-01-14 21:13:07 +01:00
Stephan Schroevers
6222bcb0d4 Introduce additional Multimap Refaster rules (#971) 2024-01-14 19:28:54 +01:00
Stephan Schroevers
641bb5c566 Introduce InputStreamRules Refaster rule collection (#963) 2024-01-14 19:21:42 +01:00
Stephan Schroevers
09317abb18 Fix the mutation test setup (#976)
This largely reverts commit dff67fecbc,
avoiding the issue described in pitest/pitest-junit5-plugin#105.
2024-01-14 19:04:57 +01:00
Stephan Schroevers
dff67fecbc Drop unnecessary dependency declarations (#973) 2024-01-13 20:53:00 +01:00
Stephan Schroevers
d126336742 Drop workaround for resolved Refaster bug (#974)
Issue google/error-prone#2456 was fixed in Error Prone 2.22.0.
2024-01-13 20:43:01 +01:00
Stephan Schroevers
b8eabff9bc Run org.kordamp.maven:pomchecker-maven-plugin:1.10.0:check-maven-central (#491)
This new Maven goal validates that the `pom.xml` files meet the criteria
for being deployed to Maven Central.
2024-01-13 17:34:26 +01:00
Stephan Schroevers
0b04e0fb3f Build with Maven 3.9.6 (#964)
Using the `setup-maven-action` GitHub action we can both simplify the
build configuration and configure the version of Maven to use.

See https://github.com/s4u/setup-maven-action
2024-01-13 17:17:01 +01:00
Stephan Schroevers
14506ed392 Introduce RefasterMethodParameterOrder check (#775)
While there, simplify some `EqualityRules` Refaster rules, as a suggested
parameter order change highlighted that they could be collapsed.
2024-01-13 16:13:00 +01:00
Picnic-Bot
664adb4aa4 Upgrade org.openrewrite:rewrite-templating 1.3.14 -> 1.4.2 (#962)
Upgrade OpenRewrite Templating 1.3.14 -> 1.4.2 (#962)

See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.4.0
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.4.1
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.4.2
- https://github.com/openrewrite/rewrite-templating/compare/v1.3.14...v1.4.2
2024-01-13 15:53:09 +01:00
Stephan Schroevers
f35d62061d Work around IntelliJ IDEA bug IDEA-342187 (#958)
This reverts some of the changes in
3578a8cbec.

See https://youtrack.jetbrains.com/issue/IDEA-342187
2024-01-13 15:06:27 +01:00
Picnic-Bot
a89f986763 Upgrade SLF4J 2.0.10 -> 2.0.11 (#957)
See:
- https://www.slf4j.org/news.html
- https://github.com/qos-ch/slf4j/compare/v_2.0.10...v_2.0.11
2024-01-12 10:59:49 +01:00
Picnic-Bot
6ad94b5c29 Upgrade Surefire 3.2.3 -> 3.2.5 (#960)
See:
- https://github.com/apache/maven-surefire/releases/tag/surefire-3.2.5
- https://github.com/apache/maven-surefire/compare/surefire-3.2.3...surefire-3.2.5
2024-01-11 12:55:11 +01:00
Picnic-Bot
63fe19b487 Upgrade Project Reactor 2023.0.1 -> 2023.0.2 (#959)
See:
- https://github.com/reactor/reactor/releases/tag/2023.0.2
- https://github.com/reactor/reactor/compare/2023.0.1...2023.0.2
2024-01-11 08:40:49 +01:00
Stephan Schroevers
fbd9b0689c Make BugPattern{,Test}Extractor tests more maintainable (#937)
As we're moving to a Java-based website generator located in the same
package as the `Extractor` implementations, there is no need to validate
the exact format of generated files; only that the data can be
deserialized again.

While there, track the source file from which data is extracted.
2024-01-10 13:40:37 +01:00
Stephan Schroevers
c7a288cf29 Update year to 2024 in footer_custom.html and LICENSE.md (#955) 2024-01-09 09:06:03 +01:00
Rick Ossendrijver
931632d90b Show original Cody in README and on website home page (#956)
This reverts commit 7529b99251.
2024-01-09 08:51:27 +01:00
Phil Werli
71de432645 Extend OptionalIdentity Refaster rule (#951)
By flagging expressions of the form `optional.or(() -> Optional.empty())` and 
`optional.or(Optional::empty)`.
2024-01-08 09:08:20 +01:00
Picnic-Bot
97a4cb0227 Upgrade errorprone-slf4j 0.1.21 -> 0.1.22 (#953)
See:
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.22
- https://github.com/KengoTODA/errorprone-slf4j/compare/v0.1.21...v0.1.22
2024-01-06 14:12:07 +01:00
Picnic-Bot
6b1cb4c2e9 Upgrade Google Java Format 1.19.1 -> 1.19.2 (#952)
See:
- https://github.com/google/google-java-format/releases/tag/v1.19.2
- https://github.com/google/google-java-format/compare/v1.19.1...v1.19.2
2024-01-06 13:56:10 +01:00
Picnic-Bot
e0cb7eb1f9 Upgrade Error Prone 2.24.0 -> 2.24.1 (#950)
See:
- https://github.com/google/error-prone/releases/tag/v2.24.1
- https://github.com/google/error-prone/compare/v2.24.0...v2.24.1
- https://github.com/PicnicSupermarket/error-prone/compare/v2.24.0-picnic-1...v2.24.1-picnic-1
2024-01-05 23:26:17 +01:00
Tim te Beek
a2f44f82f2 Derive OpenRewrite recipes from a subset of Refaster rules (#925)
Using OpenRewrite's `rewrite-templating` annotation processor, Refaster rules
are now converted into matching recipes and bundled as part of the 
`error-prone-contrib` artifact. Note that not all rules are supported yet.
2024-01-05 21:59:22 +01:00
Picnic-Bot
0ec8ebe8ab Upgrade AssertJ 3.25.0 -> 3.25.1 (#949)
See:
- https://github.com/assertj/assertj/releases/tag/assertj-build-3.25.1
- https://github.com/assertj/assertj/compare/assertj-build-3.25.0...assertj-build-3.25.1
2024-01-03 11:06:47 +01:00
Stephan Schroevers
e1be5d23e9 Prevent likely static import class with FailWithMessage{,AndThrowable} Refaster rules (#939)
This is a workaround for google/error-prone#3584. While there, drop an
unused method from `JUnitToAssertJRules`.
2024-01-02 11:04:38 +01:00
Picnic-Bot
12f2feaacf Upgrade CodeQL v2.22.8 -> v3.22.12 (#948)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v3.22.11...v3.22.12
- https://github.com/github/codeql-action/compare/v2.22.12...v3.22.11
- https://github.com/github/codeql-action/compare/v2.22.11...v2.22.12
- https://github.com/github/codeql-action/compare/v2.22.10...v2.22.11
- https://github.com/github/codeql-action/compare/v2.22.9...v2.22.10
- https://github.com/github/codeql-action/compare/v2.22.8...v2.22.9
- https://github.com/github/codeql-action/compare/v2.22.8...v3.22.12
2024-01-02 08:01:36 +01:00
Picnic-Bot
423a306719 Upgrade TestNG 7.8.0 -> 7.9.0 (#942)
See:
- https://github.com/testng-team/testng/releases/tag/7.9.0
- https://github.com/testng-team/testng/compare/7.8.0...7.9.0
2024-01-01 20:13:44 +01:00
Picnic-Bot
b5327f2e97 Upgrade NullAway 0.10.18 -> 0.10.19 (#941)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.10.19
- https://github.com/uber/NullAway/compare/v0.10.18...v0.10.19
2024-01-01 20:02:32 +01:00
Picnic-Bot
059e1dbbe7 Upgrade ruby/setup-ruby v1.161.0 -> v1.165.1 (#947)
See:
- https://github.com/ruby/setup-ruby/releases/tag/v1.165.1
- https://github.com/ruby/setup-ruby/releases/tag/v1.165.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.164.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.163.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.162.0
2024-01-01 17:00:29 +01:00
Picnic-Bot
cef7f3409f Upgrade Checkstyle 10.12.6 -> 10.12.7 (#944)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.12.7
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.12.6...checkstyle-10.12.7
2024-01-01 16:39:07 +01:00
Picnic-Bot
82bcb405c3 Upgrade AssertJ 3.24.2 -> 3.25.0 (#946)
See:
- https://github.com/assertj/assertj/releases/tag/assertj-build-3.25.0
- https://github.com/assertj/assertj/compare/assertj-build-3.24.2...assertj-build-3.25.0
2024-01-01 16:22:11 +01:00
Stephan Schroevers
0440df8911 Have ThrowsCheckedException also consider supertypes (#914)
This prevents the `MonoFromSupplier` Refaster rule from suggesting
noncompilable code.
2024-01-01 12:26:43 +01:00
Picnic-Bot
25eaf11171 Upgrade SLF4J 2.0.9 -> 2.0.10 (#943)
See:
- https://www.slf4j.org/news.html
- https://github.com/qos-ch/slf4j/compare/v_2.0.9...v_2.0.10
2023-12-31 14:26:29 +01:00
Picnic-Bot
3578a8cbec Upgrade maven-compiler-plugin 3.10.1 -> 3.12.1 (#515)
See:
- https://github.com/apache/maven-compiler-plugin/releases/tag/maven-compiler-plugin-3.11.0
- https://github.com/apache/maven-compiler-plugin/releases/tag/maven-compiler-plugin-3.12.0
- https://github.com/apache/maven-compiler-plugin/releases/tag/maven-compiler-plugin-3.12.1
- https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.10.1...maven-compiler-plugin-3.12.1
2023-12-26 12:04:50 +01:00
Picnic-Bot
4e1158d4df Upgrade Jackson 2.16.0 -> 2.16.1 (#940)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.16.1
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.16.0...jackson-bom-2.16.1
2023-12-25 13:00:59 +01:00
Stephan Schroevers
0109632b70 Update Error Prone -XepExcludedPaths flag to be Windows-compatible (#927)
Prior to these changes the provided pattern would never match on
Windows, as Error Prone matches against file URIs, which in practice
will always contain forward slashes, even on Windows.
2023-12-24 18:52:42 +01:00
Picnic-Bot
1650b6b00d Upgrade actions/deploy-pages v4.0.0 -> v4.0.2 (#936)
See:
- https://github.com/actions/deploy-pages/releases/tag/v4.0.2
- https://github.com/actions/deploy-pages/releases/tag/v4.0.1
2023-12-24 16:38:51 +01:00
Picnic-Bot
967a446909 Upgrade Error Prone 2.23.0 -> 2.24.0 (#935)
See:
- https://github.com/google/error-prone/releases/tag/v2.24.0
- https://github.com/google/error-prone/compare/v2.23.0...v2.24.0
- https://github.com/PicnicSupermarket/error-prone/compare/v2.23.0-picnic-1...v2.24.0-picnic-1
2023-12-23 10:17:42 +01:00
Picnic-Bot
4d30329448 Upgrade actions/deploy-pages v3.0.1 -> v4.0.0 (#932)
See:
- https://github.com/actions/deploy-pages/releases/tag/v4.0.0
2023-12-22 11:50:52 +01:00
Picnic-Bot
66967fb903 Upgrade actions/upload-pages-artifact v2.0.0 -> v3.0.0 (#933)
See:
- https://github.com/actions/upload-pages-artifact/releases/tag/v3.0.0
2023-12-22 10:41:58 +01:00
Picnic-Bot
e6854a9147 Upgrade Google Java Format 1.18.1 -> 1.19.1 (#929)
See:
- https://github.com/google/google-java-format/releases/tag/v1.19.0
- https://github.com/google/google-java-format/releases/tag/v1.19.1
- https://github.com/google/google-java-format/compare/v1.18.1...v1.19.1
2023-12-22 09:14:11 +01:00
Picnic-Bot
1ca0f536c4 Upgrade Byte Buddy 1.14.10 -> 1.14.11 (#934)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.11
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.10...byte-buddy-1.14.11
2023-12-22 08:54:11 +01:00
Stephan Schroevers
d569156a6b Introduce ErrorProneRuntimeClasspath check (#882)
Prefer "type-safe" type references were possible, but use string
literals if the references type may not be available at runtime.
2023-12-20 22:14:22 +01:00
Picnic-Bot
e7c3d39059 Upgrade Checkstyle 10.12.5 -> 10.12.6 (#911)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.12.6
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.12.5...checkstyle-10.12.6
2023-12-20 14:23:09 +01:00
Picnic-Bot
9d66379486 Upgrade Swagger 2.2.19 -> 2.2.20 (#928)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.20
- https://github.com/swagger-api/swagger-core/compare/v2.2.19...v2.2.20
2023-12-20 13:21:48 +01:00
Picnic-Bot
d01002de06 Upgrade Truth 1.1.5 -> 1.2.0 (#930)
See:
- https://github.com/google/truth/releases/tag/v1.2.0
- https://github.com/google/truth/compare/v1.1.5...v1.2.0
2023-12-20 08:35:00 +01:00
Picnic-Bot
0c857b3d90 Upgrade Guava 32.1.3-jre -> 33.0.0-jre (#931)
See:
- https://guava.dev/releases/33.0.0-jre/api/diffs/
- https://github.com/google/guava/releases/tag/v33.0.0
- https://github.com/google/guava/compare/v32.0.0...v33.0.0
2023-12-20 08:03:40 +01:00
Rick Ossendrijver
cc36aa993c Disallow static import of com.google.errorprone.{VisitorState,util.ASTHelpers} members (#922) 2023-12-18 18:00:15 +01:00
Picnic-Bot
379bbf3f83 Upgrade Checker Framework Annotations 3.41.0 -> 3.42.0 (#924)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.42.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.41.0...checker-framework-3.42.0
2023-12-18 13:35:44 +01:00
Stephan Schroevers
a0b1f7091e Introduce UnqualifiedSuggestedFixImport check (#880)
Usage of `SuggestedFix.Builder#add{,Static}Import` does not always yield
valid code, so this check suggests alternatives instead.
2023-12-18 12:51:28 +01:00
Stephan Schroevers
626246bcc0 Introduce CanonicalClassNameUsage check (#881)
Error Prone checks deal with source code and type matchers, both of
which generally involve canonical type names, rather than the strings
produced by `Class#getName()`. This distinction is particularly relevant
when dealing with nested types.
2023-12-18 09:19:13 +01:00
Picnic-Bot
22272d6059 Upgrade Surefire 3.2.2 -> 3.2.3 (#920)
See:
- https://github.com/apache/maven-surefire/releases/tag/surefire-3.2.3
- https://github.com/apache/maven-surefire/compare/surefire-3.2.2...surefire-3.2.3
2023-12-18 09:06:32 +01:00
Stephan Schroevers
ff3be8ae3f Skip SonarCloud analysis of PRs from forked repositories (#926)
Because such analysis will fail due to unavailability of the relevant
secrets. Working around this is nontrivial and a likely source of
security issues.
2023-12-18 08:34:30 +01:00
Austin Richardson
7c2078b771 Require static importing of some com.fasterxml.jackson.annotation enums (#910)
Types to be imported statically:
- `com.fasterxml.jackson.annotation.JsonCreator.Mode`
- `com.fasterxml.jackson.annotation.JsonFormat.Shape`
- `com.fasterxml.jackson.annotation.JsonInclude.Include`
- `com.fasterxml.jackson.annotation.JsonProperty.Access`
2023-12-18 07:17:00 +01:00
Rick Ossendrijver
7529b99251 Show Christmas Cody in README and on website home page (#923) 2023-12-16 13:14:33 +01:00
Picnic-Bot
a966c1a17a Upgrade actions/upload-artifact v3.1.3 -> v4.0.0 (#921)
See:
- https://github.com/actions/upload-artifact/releases/tag/v4.0.0
- https://github.com/actions/upload-artifact/compare/v3.1.3...v4.0.0
2023-12-15 08:25:01 +01:00
Picnic-Bot
cc3e30f253 Upgrade Project Reactor 2023.0.0 -> 2023.0.1 (#918)
See:
- https://github.com/reactor/reactor/releases/tag/2023.0.1
- https://github.com/reactor/reactor/compare/2023.0.0...2023.0.1
2023-12-14 09:07:04 +01:00
Picnic-Bot
b73b05a5c4 Upgrade dawidd6/action-download-artifact v2.28.1 -> v3.0.0 (#919)
See:
- https://github.com/dawidd6/action-download-artifact/releases/tag/v3.0.0
2023-12-14 08:54:36 +01:00
Picnic-Bot
74de2535f5 Upgrade AspectJ 1.9.20.1 -> 1.9.21 (#916)
See:
- https://github.com/eclipse-aspectj/aspectj/releases/tag/V1_9_21
- https://github.com/eclipse-aspectj/aspectj/compare/V1_9_20_1...V1_9_21
2023-12-14 07:09:49 +01:00
172 changed files with 9289 additions and 3107 deletions

View File

@@ -14,7 +14,7 @@ jobs:
distribution: [ temurin ]
experimental: [ false ]
include:
- os: macos-12
- os: macos-14
jdk: 17.0.8
distribution: temurin
experimental: false
@@ -30,16 +30,12 @@ jobs:
# on Maven Central, and once against the Picnic Error Prone fork,
# additionally enabling all checks defined in this project and any Error
# Prone checks available only from other artifact repositories.
- name: Check out code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@fa2c7e4517ed008b1f73e7e0195a9eecf5582cd4 # v1.11.0
with:
java-version: ${{ matrix.jdk }}
distribution: ${{ matrix.distribution }}
cache: maven
java-distribution: ${{ matrix.distribution }}
maven-version: 3.9.6
- name: Display build environment details
run: mvn --version
- name: Build project against vanilla Error Prone, compile Javadoc

View File

@@ -21,24 +21,20 @@ jobs:
security-events: write
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@fa2c7e4517ed008b1f73e7e0195a9eecf5582cd4 # v1.11.0
with:
java-version: 17.0.8
distribution: temurin
cache: maven
java-distribution: temurin
maven-version: 3.9.6
- name: Initialize CodeQL
uses: github/codeql-action/init@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8
uses: github/codeql-action/init@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # v3.23.2
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@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8
uses: github/codeql-action/analyze@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # v3.23.2
with:
category: /language:${{ matrix.language }}

View File

@@ -15,7 +15,7 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- uses: ruby/setup-ruby@8575951200e472d5f2d95c625da0c7bec8217c42 # v1.161.0
- uses: ruby/setup-ruby@bd03e04863f52d169e18a2b190e8fa6b84938215 # v1.170.0
with:
working-directory: ./website
bundler-cache: true
@@ -32,7 +32,7 @@ jobs:
# "Refaster rules" terminology on our website and in the code.
run: bundle exec htmlproofer --disable_external true --check-external-hash false ./_site
- name: Upload website as artifact
uses: actions/upload-pages-artifact@a753861a5debcf57bf8b404356158c8e1e33150c # v2.0.0
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1
with:
path: ./website/_site
deploy:
@@ -48,4 +48,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@13b55b33dd8996121833dbc1db458c793a334630 # v3.0.1
uses: actions/deploy-pages@decdde0ac072f6dcbe43649d82d9c635fff5b4e4 # v4.0.4

View File

@@ -31,6 +31,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@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8
uses: github/codeql-action/upload-sarif@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # v3.23.2
with:
sarif_file: results.sarif

View File

@@ -11,17 +11,13 @@ jobs:
analyze-pr:
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
fetch-depth: 2
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@fa2c7e4517ed008b1f73e7e0195a9eecf5582cd4 # v1.11.0
with:
checkout-fetch-depth: 2
java-version: 17.0.8
distribution: temurin
cache: maven
java-distribution: temurin
maven-version: 3.9.6
- name: Run Pitest
# By running with features `+GIT(from[HEAD~1]), +gitci`, Pitest only
# analyzes lines changed in the associated pull request, as GitHub
@@ -32,7 +28,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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: pitest-reports
path: ./target/pit-reports-ci

View File

@@ -19,18 +19,14 @@ jobs:
pull-requests: write
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@fa2c7e4517ed008b1f73e7e0195a9eecf5582cd4 # v1.11.0
with:
java-version: 17.0.8
distribution: temurin
cache: maven
java-distribution: temurin
maven-version: 3.9.6
- name: Download Pitest analysis artifact
uses: dawidd6/action-download-artifact@f29d1b6a8930683e80acedfbe6baa2930cd646b4 # v2.28.1
uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
name: pitest-reports

View File

@@ -18,26 +18,22 @@ jobs:
github.event.issue.pull_request && contains(github.event.comment.body, '/integration-test')
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
ref: refs/pull/${{ github.event.issue.number }}/head
- name: Set up JDK
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@fa2c7e4517ed008b1f73e7e0195a9eecf5582cd4 # v1.11.0
with:
checkout-ref: "refs/pull/${{ github.event.issue.number }}/head"
java-version: 17.0.8
distribution: temurin
cache: maven
java-distribution: temurin
maven-version: 3.9.6
- name: Install project to local Maven repository
run: mvn -T1C install -DskipTests -Dverification.skip
- name: Run integration test
run: xvfb-run ./integration-tests/checkstyle-10.12.4.sh "${{ runner.temp }}/artifacts"
run: xvfb-run ./integration-tests/checkstyle.sh "${{ runner.temp }}/artifacts"
- name: Upload artifacts on failure
if: ${{ failure() }}
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: integration-test-checkstyle-10.12.4
name: integration-test-checkstyle
path: "${{ runner.temp }}/artifacts"
- name: Remove installed project artifacts
run: mvn build-helper:remove-project-artifact

View File

@@ -11,21 +11,20 @@ permissions:
contents: read
jobs:
analyze:
# Analysis of code in forked repositories is skipped, as such workflow runs
# do not have access to the requisite secrets.
if: github.event.pull_request.head.repo.full_name == github.repository
permissions:
contents: read
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
fetch-depth: 0
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@fa2c7e4517ed008b1f73e7e0195a9eecf5582cd4 # v1.11.0
with:
checkout-fetch-depth: 0
java-version: 17.0.8
distribution: temurin
cache: maven
java-distribution: temurin
maven-version: 3.9.6
- name: Create missing `test` directory
# XXX: Drop this step in favour of actually having a test.
run: mkdir refaster-compiler/src/test

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2017-2023 Picnic Technologies BV
Copyright (c) 2017-2024 Picnic Technologies BV
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -65,6 +65,8 @@ it, read the installation guide for Maven or Gradle below.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!-- Prefer using the latest release. -->
<version>3.12.0</version>
<configuration>
<annotationProcessorPaths>
<!-- Error Prone itself. -->
@@ -94,8 +96,6 @@ it, read the installation guide for Maven or Gradle below.
</arg>
<arg>-XDcompilePolicy=simple</arg>
</compilerArgs>
<!-- Some checks raise warnings rather than errors. -->
<showWarnings>true</showWarnings>
<!-- Enable this if you'd like to fail your build upon warnings. -->
<!-- <failOnWarning>true</failOnWarning> -->
</configuration>

View File

@@ -12,6 +12,7 @@
<name>Picnic :: Error Prone Support :: Documentation Support</name>
<description>Data extraction support for the purpose of documentation generation.</description>
<url>https://error-prone.picnic.tech</url>
<dependencies>
<dependency>
@@ -40,6 +41,14 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-guava</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
<groupId>com.google.auto</groupId>
<artifactId>auto-common</artifactId>
@@ -73,6 +82,8 @@
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<!-- XXX: Explicitly declared as a workaround for
https://github.com/pitest/pitest-junit5-plugin/issues/105. -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>

View File

@@ -4,6 +4,7 @@ import static com.google.common.base.Verify.verify;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static java.util.Objects.requireNonNull;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.google.auto.common.AnnotationMirrors;
import com.google.auto.service.AutoService;
import com.google.auto.value.AutoValue;
@@ -17,6 +18,7 @@ import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.ClassTree;
import com.sun.tools.javac.code.Attribute;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import java.net.URI;
import java.util.Optional;
import javax.lang.model.element.AnnotationValue;
import tech.picnic.errorprone.documentation.BugPatternExtractor.BugPatternDocumentation;
@@ -45,7 +47,8 @@ public final class BugPatternExtractor implements Extractor<BugPatternDocumentat
}
return Optional.of(
new AutoValue_BugPatternExtractor_BugPatternDocumentation(
BugPatternDocumentation.create(
state.getPath().getCompilationUnit().getSourceFile().toUri(),
symbol.getQualifiedName().toString(),
annotation.name().isEmpty() ? tree.getSimpleName().toString() : annotation.name(),
ImmutableList.copyOf(annotation.altNames()),
@@ -91,7 +94,36 @@ public final class BugPatternExtractor implements Extractor<BugPatternDocumentat
}
@AutoValue
@JsonDeserialize(as = AutoValue_BugPatternExtractor_BugPatternDocumentation.class)
abstract static class BugPatternDocumentation {
static BugPatternDocumentation create(
URI source,
String fullyQualifiedName,
String name,
ImmutableList<String> altNames,
String link,
ImmutableList<String> tags,
String summary,
String explanation,
SeverityLevel severityLevel,
boolean canDisable,
ImmutableList<String> suppressionAnnotations) {
return new AutoValue_BugPatternExtractor_BugPatternDocumentation(
source,
fullyQualifiedName,
name,
altNames,
link,
tags,
summary,
explanation,
severityLevel,
canDisable,
suppressionAnnotations);
}
abstract URI source();
abstract String fullyQualifiedName();
abstract String name();

View File

@@ -4,6 +4,13 @@ import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import static java.util.function.Predicate.not;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.google.auto.service.AutoService;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
@@ -15,6 +22,7 @@ import com.sun.source.tree.ClassTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.util.TreeScanner;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -52,7 +60,9 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
.map(
tests ->
new AutoValue_BugPatternTestExtractor_TestCases(
ASTHelpers.getSymbol(tree).className(), tests));
state.getPath().getCompilationUnit().getSourceFile().toUri(),
ASTHelpers.getSymbol(tree).className(),
tests));
}
private static final class BugPatternTestCollector
@@ -67,7 +77,7 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
"com.google.errorprone.CompilationTestHelper",
"com.google.errorprone.BugCheckerRefactoringTestHelper")
.named("newInstance")
.withParameters("java.lang.Class", "java.lang.Class");
.withParameters(Class.class.getCanonicalName(), Class.class.getCanonicalName());
private static final Matcher<ExpressionTree> IDENTIFICATION_SOURCE_LINES =
instanceMethod()
.onDescendantOf("com.google.errorprone.CompilationTestHelper")
@@ -198,32 +208,78 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
}
@AutoValue
@JsonDeserialize(as = AutoValue_BugPatternTestExtractor_TestCases.class)
abstract static class TestCases {
static TestCases create(URI source, String testClass, ImmutableList<TestCase> testCases) {
return new AutoValue_BugPatternTestExtractor_TestCases(source, testClass, testCases);
}
abstract URI source();
abstract String testClass();
abstract ImmutableList<TestCase> testCases();
}
@AutoValue
@JsonDeserialize(as = AutoValue_BugPatternTestExtractor_TestCase.class)
abstract static class TestCase {
static TestCase create(String classUnderTest, ImmutableList<TestEntry> entries) {
return new AutoValue_BugPatternTestExtractor_TestCase(classUnderTest, entries);
}
abstract String classUnderTest();
abstract ImmutableList<TestEntry> entries();
}
@JsonSubTypes({
@JsonSubTypes.Type(AutoValue_BugPatternTestExtractor_IdentificationTestEntry.class),
@JsonSubTypes.Type(AutoValue_BugPatternTestExtractor_ReplacementTestEntry.class)
})
@JsonTypeInfo(include = As.EXISTING_PROPERTY, property = "type", use = JsonTypeInfo.Id.DEDUCTION)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder("type")
interface TestEntry {
TestType type();
String path();
}
@AutoValue
abstract static class ReplacementTestEntry implements TestEntry {
abstract String input();
abstract String output();
enum TestType {
IDENTIFICATION,
REPLACEMENT
}
}
@AutoValue
abstract static class IdentificationTestEntry implements TestEntry {
static IdentificationTestEntry create(String path, String code) {
return new AutoValue_BugPatternTestExtractor_IdentificationTestEntry(path, code);
}
@JsonProperty
@Override
public final TestType type() {
return TestType.IDENTIFICATION;
}
abstract String code();
}
@AutoValue
abstract static class ReplacementTestEntry implements TestEntry {
static ReplacementTestEntry create(String path, String input, String output) {
return new AutoValue_BugPatternTestExtractor_ReplacementTestEntry(path, input, output);
}
@JsonProperty
@Override
public final TestType type() {
return TestType.REPLACEMENT;
}
abstract String input();
abstract String output();
}
}

View File

@@ -1,10 +1,5 @@
package tech.picnic.errorprone.documentation;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.VisitorState;
import com.sun.source.tree.ClassTree;
@@ -15,10 +10,7 @@ import com.sun.source.util.TaskListener;
import com.sun.source.util.TreePath;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.util.Context;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -39,9 +31,6 @@ final class DocumentationGeneratorTaskListener implements TaskListener {
ServiceLoader.load(
Extractor.class, DocumentationGeneratorTaskListener.class.getClassLoader()));
private static final ObjectMapper OBJECT_MAPPER =
new ObjectMapper().setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
private final Context context;
private final Path docsPath;
@@ -94,13 +83,7 @@ final class DocumentationGeneratorTaskListener implements TaskListener {
}
private <T> void writeToFile(String identifier, String className, T data) {
File file = docsPath.resolve(String.format("%s-%s.json", identifier, className)).toFile();
try (FileWriter fileWriter = new FileWriter(file, UTF_8)) {
OBJECT_MAPPER.writeValue(fileWriter, data);
} catch (IOException e) {
throw new UncheckedIOException(String.format("Cannot write to file '%s'", file.getPath()), e);
}
Json.write(docsPath.resolve(String.format("%s-%s.json", identifier, className)), data);
}
private static String getSimpleClassName(URI path) {

View File

@@ -0,0 +1,45 @@
package tech.picnic.errorprone.documentation;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.guava.GuavaModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import com.google.errorprone.annotations.FormatMethod;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
/**
* Utility class that offers mutually consistent JSON serialization and deserialization operations,
* without further specifying the exact schema used.
*/
final class Json {
private static final ObjectMapper OBJECT_MAPPER =
new ObjectMapper()
.setVisibility(PropertyAccessor.FIELD, Visibility.ANY)
.registerModules(new GuavaModule(), new ParameterNamesModule());
private Json() {}
static <T> T read(Path path, Class<T> clazz) {
try {
return OBJECT_MAPPER.readValue(path.toFile(), clazz);
} catch (IOException e) {
throw failure(e, "Failure reading from '%s'", path);
}
}
static <T> void write(Path path, T object) {
try {
OBJECT_MAPPER.writeValue(path.toFile(), object);
} catch (IOException e) {
throw failure(e, "Failure writing to '%s'", path);
}
}
@FormatMethod
private static UncheckedIOException failure(IOException cause, String format, Object... args) {
return new UncheckedIOException(String.format(format, args), cause);
}
}

View File

@@ -1,13 +1,17 @@
package tech.picnic.errorprone.documentation;
import static java.nio.charset.StandardCharsets.UTF_8;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.io.Resources;
import java.io.IOException;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugPattern;
import java.net.URI;
import java.nio.file.Path;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import tech.picnic.errorprone.documentation.BugPatternExtractor.BugPatternDocumentation;
final class BugPatternExtractorTest {
@Test
@@ -23,7 +27,7 @@ final class BugPatternExtractorTest {
}
@Test
void minimalBugPattern(@TempDir Path outputDirectory) throws IOException {
void minimalBugPattern(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"MinimalBugChecker.java",
@@ -36,11 +40,25 @@ final class BugPatternExtractorTest {
"@BugPattern(summary = \"MinimalBugChecker summary\", severity = SeverityLevel.ERROR)",
"public final class MinimalBugChecker extends BugChecker {}");
verifyGeneratedFileContent(outputDirectory, "MinimalBugChecker");
verifyGeneratedFileContent(
outputDirectory,
"MinimalBugChecker",
BugPatternDocumentation.create(
URI.create("file:///MinimalBugChecker.java"),
"pkg.MinimalBugChecker",
"MinimalBugChecker",
ImmutableList.of(),
"",
ImmutableList.of(),
"MinimalBugChecker summary",
"",
ERROR,
/* canDisable= */ true,
ImmutableList.of(SuppressWarnings.class.getCanonicalName())));
}
@Test
void completeBugPattern(@TempDir Path outputDirectory) throws IOException {
void completeBugPattern(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"CompleteBugChecker.java",
@@ -64,11 +82,25 @@ final class BugPatternExtractorTest {
" suppressionAnnotations = {BugPattern.class, Test.class})",
"public final class CompleteBugChecker extends BugChecker {}");
verifyGeneratedFileContent(outputDirectory, "CompleteBugChecker");
verifyGeneratedFileContent(
outputDirectory,
"CompleteBugChecker",
BugPatternDocumentation.create(
URI.create("file:///CompleteBugChecker.java"),
"pkg.CompleteBugChecker",
"OtherName",
ImmutableList.of("Check"),
"https://error-prone.picnic.tech",
ImmutableList.of("Simplification"),
"CompleteBugChecker summary",
"Example explanation",
SUGGESTION,
/* canDisable= */ false,
ImmutableList.of(BugPattern.class.getCanonicalName(), "org.junit.jupiter.api.Test")));
}
@Test
void undocumentedSuppressionBugPattern(@TempDir Path outputDirectory) throws IOException {
void undocumentedSuppressionBugPattern(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"UndocumentedSuppressionBugPattern.java",
@@ -84,23 +116,27 @@ final class BugPatternExtractorTest {
" documentSuppression = false)",
"public final class UndocumentedSuppressionBugPattern extends BugChecker {}");
verifyGeneratedFileContent(outputDirectory, "UndocumentedSuppressionBugPattern");
verifyGeneratedFileContent(
outputDirectory,
"UndocumentedSuppressionBugPattern",
BugPatternDocumentation.create(
URI.create("file:///UndocumentedSuppressionBugPattern.java"),
"pkg.UndocumentedSuppressionBugPattern",
"UndocumentedSuppressionBugPattern",
ImmutableList.of(),
"",
ImmutableList.of(),
"UndocumentedSuppressionBugPattern summary",
"",
WARNING,
/* canDisable= */ true,
ImmutableList.of()));
}
private static void verifyGeneratedFileContent(Path outputDirectory, String testClass)
throws IOException {
String resourceName = String.format("bugpattern-%s.json", testClass);
assertThat(outputDirectory.resolve(resourceName))
.content(UTF_8)
.isEqualToIgnoringWhitespace(
getResource(
String.join("-", BugPatternExtractorTest.class.getSimpleName(), resourceName)));
}
// XXX: Once we support only JDK 15+, drop this method in favour of including the resources as
// text blocks in this class.
private static String getResource(String resourceName) throws IOException {
return Resources.toString(
Resources.getResource(BugPatternExtractorTest.class, resourceName), UTF_8);
private static void verifyGeneratedFileContent(
Path outputDirectory, String testClass, BugPatternDocumentation expected) {
assertThat(outputDirectory.resolve(String.format("bugpattern-%s.json", testClass)))
.exists()
.returns(expected, path -> Json.read(path, BugPatternDocumentation.class));
}
}

View File

@@ -1,13 +1,16 @@
package tech.picnic.errorprone.documentation;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.io.Resources;
import java.io.IOException;
import com.google.common.collect.ImmutableList;
import java.net.URI;
import java.nio.file.Path;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.IdentificationTestEntry;
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.ReplacementTestEntry;
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.TestCase;
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.TestCases;
final class BugPatternTestExtractorTest {
@Test
@@ -246,7 +249,7 @@ final class BugPatternTestExtractorTest {
}
@Test
void singleFileCompilationTestHelper(@TempDir Path outputDirectory) throws IOException {
void singleFileCompilationTestHelper(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"SingleFileCompilationTestHelperTest.java",
@@ -263,12 +266,22 @@ final class BugPatternTestExtractorTest {
" }",
"}");
verifyGeneratedFileContent(outputDirectory, "SingleFileCompilationTestHelperTest");
verifyGeneratedFileContent(
outputDirectory,
"SingleFileCompilationTestHelperTest",
TestCases.create(
URI.create("file:///SingleFileCompilationTestHelperTest.java"),
"SingleFileCompilationTestHelperTest",
ImmutableList.of(
TestCase.create(
"SingleFileCompilationTestHelperTest.TestChecker",
ImmutableList.of(
IdentificationTestEntry.create(
"A.java", "// BUG: Diagnostic contains:\nclass A {}\n"))))));
}
@Test
void singleFileCompilationTestHelperWithSetArgs(@TempDir Path outputDirectory)
throws IOException {
void singleFileCompilationTestHelperWithSetArgs(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"SingleFileCompilationTestHelperWithSetArgsTest.java",
@@ -286,11 +299,22 @@ final class BugPatternTestExtractorTest {
" }",
"}");
verifyGeneratedFileContent(outputDirectory, "SingleFileCompilationTestHelperWithSetArgsTest");
verifyGeneratedFileContent(
outputDirectory,
"SingleFileCompilationTestHelperWithSetArgsTest",
TestCases.create(
URI.create("file:///SingleFileCompilationTestHelperWithSetArgsTest.java"),
"SingleFileCompilationTestHelperWithSetArgsTest",
ImmutableList.of(
TestCase.create(
"SingleFileCompilationTestHelperWithSetArgsTest.TestChecker",
ImmutableList.of(
IdentificationTestEntry.create(
"A.java", "// BUG: Diagnostic contains:\nclass A {}\n"))))));
}
@Test
void multiFileCompilationTestHelper(@TempDir Path outputDirectory) throws IOException {
void multiFileCompilationTestHelper(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"MultiFileCompilationTestHelperTest.java",
@@ -308,11 +332,24 @@ final class BugPatternTestExtractorTest {
" }",
"}");
verifyGeneratedFileContent(outputDirectory, "MultiFileCompilationTestHelperTest");
verifyGeneratedFileContent(
outputDirectory,
"MultiFileCompilationTestHelperTest",
TestCases.create(
URI.create("file:///MultiFileCompilationTestHelperTest.java"),
"MultiFileCompilationTestHelperTest",
ImmutableList.of(
TestCase.create(
"MultiFileCompilationTestHelperTest.TestChecker",
ImmutableList.of(
IdentificationTestEntry.create(
"A.java", "// BUG: Diagnostic contains:\nclass A {}\n"),
IdentificationTestEntry.create(
"B.java", "// BUG: Diagnostic contains:\nclass B {}\n"))))));
}
@Test
void singleFileBugCheckerRefactoringTestHelper(@TempDir Path outputDirectory) throws IOException {
void singleFileBugCheckerRefactoringTestHelper(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"SingleFileBugCheckerRefactoringTestHelperTest.java",
@@ -330,12 +367,23 @@ final class BugPatternTestExtractorTest {
" }",
"}");
verifyGeneratedFileContent(outputDirectory, "SingleFileBugCheckerRefactoringTestHelperTest");
verifyGeneratedFileContent(
outputDirectory,
"SingleFileBugCheckerRefactoringTestHelperTest",
TestCases.create(
URI.create("file:///SingleFileBugCheckerRefactoringTestHelperTest.java"),
"SingleFileBugCheckerRefactoringTestHelperTest",
ImmutableList.of(
TestCase.create(
"SingleFileBugCheckerRefactoringTestHelperTest.TestChecker",
ImmutableList.of(
ReplacementTestEntry.create(
"A.java", "class A {}\n", "class A { /* This is a change. */ }\n"))))));
}
@Test
void singleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestMode(
@TempDir Path outputDirectory) throws IOException {
@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest.java",
@@ -359,11 +407,21 @@ final class BugPatternTestExtractorTest {
verifyGeneratedFileContent(
outputDirectory,
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest");
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest",
TestCases.create(
URI.create(
"file:///SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest.java"),
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest",
ImmutableList.of(
TestCase.create(
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest.TestChecker",
ImmutableList.of(
ReplacementTestEntry.create(
"A.java", "class A {}\n", "class A { /* This is a change. */ }\n"))))));
}
@Test
void multiFileBugCheckerRefactoringTestHelper(@TempDir Path outputDirectory) throws IOException {
void multiFileBugCheckerRefactoringTestHelper(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"MultiFileBugCheckerRefactoringTestHelperTest.java",
@@ -383,12 +441,24 @@ final class BugPatternTestExtractorTest {
" }",
"}");
verifyGeneratedFileContent(outputDirectory, "MultiFileBugCheckerRefactoringTestHelperTest");
verifyGeneratedFileContent(
outputDirectory,
"MultiFileBugCheckerRefactoringTestHelperTest",
TestCases.create(
URI.create("file:///MultiFileBugCheckerRefactoringTestHelperTest.java"),
"MultiFileBugCheckerRefactoringTestHelperTest",
ImmutableList.of(
TestCase.create(
"MultiFileBugCheckerRefactoringTestHelperTest.TestChecker",
ImmutableList.of(
ReplacementTestEntry.create(
"A.java", "class A {}\n", "class A { /* This is a change. */ }\n"),
ReplacementTestEntry.create(
"B.java", "class B {}\n", "class B { /* This is a change. */ }\n"))))));
}
@Test
void compilationAndBugCheckerRefactoringTestHelpers(@TempDir Path outputDirectory)
throws IOException {
void compilationAndBugCheckerRefactoringTestHelpers(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"CompilationAndBugCheckerRefactoringTestHelpersTest.java",
@@ -412,12 +482,27 @@ final class BugPatternTestExtractorTest {
"}");
verifyGeneratedFileContent(
outputDirectory, "CompilationAndBugCheckerRefactoringTestHelpersTest");
outputDirectory,
"CompilationAndBugCheckerRefactoringTestHelpersTest",
TestCases.create(
URI.create("file:///CompilationAndBugCheckerRefactoringTestHelpersTest.java"),
"CompilationAndBugCheckerRefactoringTestHelpersTest",
ImmutableList.of(
TestCase.create(
"CompilationAndBugCheckerRefactoringTestHelpersTest.TestChecker",
ImmutableList.of(
IdentificationTestEntry.create(
"A.java", "// BUG: Diagnostic contains:\nclass A {}\n"))),
TestCase.create(
"CompilationAndBugCheckerRefactoringTestHelpersTest.TestChecker",
ImmutableList.of(
ReplacementTestEntry.create(
"A.java", "class A {}\n", "class A { /* This is a change. */ }\n"))))));
}
@Test
void compilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNames(
@TempDir Path outputDirectory) throws IOException {
@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.java",
@@ -446,23 +531,28 @@ final class BugPatternTestExtractorTest {
verifyGeneratedFileContent(
outputDirectory,
"CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest");
"CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest",
TestCases.create(
URI.create(
"file:///CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.java"),
"pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest",
ImmutableList.of(
TestCase.create(
"pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.CustomTestChecker",
ImmutableList.of(
IdentificationTestEntry.create(
"A.java", "// BUG: Diagnostic contains:\nclass A {}\n"))),
TestCase.create(
"pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.CustomTestChecker2",
ImmutableList.of(
ReplacementTestEntry.create(
"A.java", "class A {}\n", "class A { /* This is a change. */ }\n"))))));
}
private static void verifyGeneratedFileContent(Path outputDirectory, String testClass)
throws IOException {
String resourceName = String.format("bugpattern-test-%s.json", testClass);
assertThat(outputDirectory.resolve(resourceName))
.content(UTF_8)
.isEqualToIgnoringWhitespace(
getResource(
String.join("-", BugPatternTestExtractorTest.class.getSimpleName(), resourceName)));
}
// XXX: Once we support only JDK 15+, drop this method in favour of including the resources as
// text blocks in this class.
private static String getResource(String resourceName) throws IOException {
return Resources.toString(
Resources.getResource(BugPatternTestExtractorTest.class, resourceName), UTF_8);
private static void verifyGeneratedFileContent(
Path outputDirectory, String testClass, TestCases expected) {
assertThat(outputDirectory.resolve(String.format("bugpattern-test-%s.json", testClass)))
.exists()
.returns(expected, path -> Json.read(path, TestCases.class));
}
}

View File

@@ -0,0 +1,62 @@
package tech.picnic.errorprone.documentation;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.google.auto.value.AutoValue;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
final class JsonTest {
private static final TestObject TEST_OBJECT = new AutoValue_JsonTest_TestObject("foo", 42);
private static final String TEST_JSON = "{\"string\":\"foo\",\"number\":42}";
@Test
void write(@TempDir Path directory) {
Path file = directory.resolve("test.json");
Json.write(file, TEST_OBJECT);
assertThat(file).content(UTF_8).isEqualTo(TEST_JSON);
}
@Test
void writeFailure(@TempDir Path directory) {
assertThatThrownBy(() -> Json.write(directory, TEST_OBJECT))
.isInstanceOf(UncheckedIOException.class)
.hasMessageContaining("Failure writing to '%s'", directory)
.hasCauseInstanceOf(FileNotFoundException.class);
}
@Test
void read(@TempDir Path directory) throws IOException {
Path file = directory.resolve("test.json");
Files.writeString(file, TEST_JSON, UTF_8);
assertThat(Json.read(file, TestObject.class)).isEqualTo(TEST_OBJECT);
}
@Test
void readFailure(@TempDir Path directory) {
assertThatThrownBy(() -> Json.read(directory, TestObject.class))
.isInstanceOf(UncheckedIOException.class)
.hasMessageContaining("Failure reading from '%s'", directory)
.hasCauseInstanceOf(FileNotFoundException.class);
}
@AutoValue
@JsonDeserialize(as = AutoValue_JsonTest_TestObject.class)
abstract static class TestObject {
abstract String string();
abstract int number();
}
}

View File

@@ -1,19 +0,0 @@
{
"fullyQualifiedName": "pkg.CompleteBugChecker",
"name": "OtherName",
"altNames": [
"Check"
],
"link": "https://error-prone.picnic.tech",
"tags": [
"Simplification"
],
"summary": "CompleteBugChecker summary",
"explanation": "Example explanation",
"severityLevel": "SUGGESTION",
"canDisable": false,
"suppressionAnnotations": [
"com.google.errorprone.BugPattern",
"org.junit.jupiter.api.Test"
]
}

View File

@@ -1,14 +0,0 @@
{
"fullyQualifiedName": "pkg.MinimalBugChecker",
"name": "MinimalBugChecker",
"altNames": [],
"link": "",
"tags": [],
"summary": "MinimalBugChecker summary",
"explanation": "",
"severityLevel": "ERROR",
"canDisable": true,
"suppressionAnnotations": [
"java.lang.SuppressWarnings"
]
}

View File

@@ -1,12 +0,0 @@
{
"fullyQualifiedName": "pkg.UndocumentedSuppressionBugPattern",
"name": "UndocumentedSuppressionBugPattern",
"altNames": [],
"link": "",
"tags": [],
"summary": "UndocumentedSuppressionBugPattern summary",
"explanation": "",
"severityLevel": "WARNING",
"canDisable": true,
"suppressionAnnotations": []
}

View File

@@ -1,24 +0,0 @@
{
"testClass": "CompilationAndBugCheckerRefactoringTestHelpersTest",
"testCases": [
{
"classUnderTest": "CompilationAndBugCheckerRefactoringTestHelpersTest.TestChecker",
"entries": [
{
"path": "A.java",
"code": "// BUG: Diagnostic contains:\nclass A {}\n"
}
]
},
{
"classUnderTest": "CompilationAndBugCheckerRefactoringTestHelpersTest.TestChecker",
"entries": [
{
"path": "A.java",
"input": "class A {}\n",
"output": "class A { /* This is a change. */ }\n"
}
]
}
]
}

View File

@@ -1,24 +0,0 @@
{
"testClass": "pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest",
"testCases": [
{
"classUnderTest": "pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.CustomTestChecker",
"entries": [
{
"path": "A.java",
"code": "// BUG: Diagnostic contains:\nclass A {}\n"
}
]
},
{
"classUnderTest": "pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.CustomTestChecker2",
"entries": [
{
"path": "A.java",
"input": "class A {}\n",
"output": "class A { /* This is a change. */ }\n"
}
]
}
]
}

View File

@@ -1,20 +0,0 @@
{
"testClass": "MultiFileBugCheckerRefactoringTestHelperTest",
"testCases": [
{
"classUnderTest": "MultiFileBugCheckerRefactoringTestHelperTest.TestChecker",
"entries": [
{
"path": "A.java",
"input": "class A {}\n",
"output": "class A { /* This is a change. */ }\n"
},
{
"path": "B.java",
"input": "class B {}\n",
"output": "class B { /* This is a change. */ }\n"
}
]
}
]
}

View File

@@ -1,18 +0,0 @@
{
"testClass": "MultiFileCompilationTestHelperTest",
"testCases": [
{
"classUnderTest": "MultiFileCompilationTestHelperTest.TestChecker",
"entries": [
{
"path": "A.java",
"code": "// BUG: Diagnostic contains:\nclass A {}\n"
},
{
"path": "B.java",
"code": "// BUG: Diagnostic contains:\nclass B {}\n"
}
]
}
]
}

View File

@@ -1,15 +0,0 @@
{
"testClass": "SingleFileBugCheckerRefactoringTestHelperTest",
"testCases": [
{
"classUnderTest": "SingleFileBugCheckerRefactoringTestHelperTest.TestChecker",
"entries": [
{
"path": "A.java",
"input": "class A {}\n",
"output": "class A { /* This is a change. */ }\n"
}
]
}
]
}

View File

@@ -1,15 +0,0 @@
{
"testClass": "SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest",
"testCases": [
{
"classUnderTest": "SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest.TestChecker",
"entries": [
{
"path": "A.java",
"input": "class A {}\n",
"output": "class A { /* This is a change. */ }\n"
}
]
}
]
}

View File

@@ -1,14 +0,0 @@
{
"testClass": "SingleFileCompilationTestHelperTest",
"testCases": [
{
"classUnderTest": "SingleFileCompilationTestHelperTest.TestChecker",
"entries": [
{
"path": "A.java",
"code": "// BUG: Diagnostic contains:\nclass A {}\n"
}
]
}
]
}

View File

@@ -1,14 +0,0 @@
{
"testClass": "SingleFileCompilationTestHelperWithSetArgsTest",
"testCases": [
{
"classUnderTest": "SingleFileCompilationTestHelperWithSetArgsTest.TestChecker",
"entries": [
{
"path": "A.java",
"code": "// BUG: Diagnostic contains:\nclass A {}\n"
}
]
}
]
}

View File

@@ -12,6 +12,7 @@
<name>Picnic :: Error Prone Support :: Contrib</name>
<description>Extra Error Prone plugins by Picnic.</description>
<url>https://error-prone.picnic.tech</url>
<dependencies>
<dependency>
@@ -47,6 +48,10 @@
`annotationProcessorPaths` configuration below. -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>error-prone-utils</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>refaster-support</artifactId>
@@ -60,11 +65,6 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.auto</groupId>
<artifactId>auto-common</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
@@ -77,10 +77,6 @@
<artifactId>auto-value-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.googlejavaformat</groupId>
<artifactId>google-java-format</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
@@ -161,6 +157,8 @@
<artifactId>junit-jupiter-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- XXX: Explicitly declared as a workaround for
https://github.com/pitest/pitest-junit5-plugin/issues/105. -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
@@ -181,6 +179,31 @@
<artifactId>mongodb-driver-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-java</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-java-11</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-templating</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.reactivestreams</groupId>
<artifactId>reactive-streams</artifactId>
@@ -216,6 +239,11 @@
<artifactId>spring-boot-test</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
@@ -231,6 +259,9 @@
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths combine.children="append">
<!-- XXX: Drop the version declarations once
properly supported. See
https://youtrack.jetbrains.com/issue/IDEA-342187. -->
<path>
<groupId>${project.groupId}</groupId>
<artifactId>documentation-support</artifactId>

View File

@@ -4,7 +4,7 @@ import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.LIKELY_ERROR;
import static com.google.errorprone.matchers.Matchers.isType;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;

View File

@@ -8,7 +8,7 @@ import static com.google.errorprone.matchers.Matchers.argument;
import static com.google.errorprone.matchers.Matchers.argumentCount;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.Matchers.nullLiteral;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;

View File

@@ -6,7 +6,7 @@ import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE;
import static com.google.errorprone.matchers.Matchers.annotations;
import static com.google.errorprone.matchers.Matchers.isType;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.Iterables;
@@ -23,7 +23,7 @@ import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import java.util.List;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.SourceCode;
/** A {@link BugChecker} that flags redundant {@code @Autowired} constructor annotations. */
@AutoService(BugChecker.class)

View File

@@ -3,7 +3,7 @@ package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
@@ -26,7 +26,7 @@ import java.util.Optional;
import java.util.function.BiFunction;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.SourceCode;
/** A {@link BugChecker} that flags annotations that could be written more concisely. */
@AutoService(BugChecker.class)

View File

@@ -0,0 +1,92 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.FRAGILE_CODE;
import static com.google.errorprone.matchers.Matchers.allOf;
import static com.google.errorprone.matchers.Matchers.anything;
import static com.google.errorprone.matchers.Matchers.classLiteral;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.Matchers.receiverOfInvocation;
import static com.google.errorprone.matchers.Matchers.toType;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.annotations.Var;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.util.TreePath;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import java.util.regex.Pattern;
/**
* A {@link BugChecker} that flags invocations of {@link Class#getName()} where {@link
* Class#getCanonicalName()} was likely meant.
*
* <p>For top-level types these two methods generally return the same result, but for nested types
* the former separates identifiers using a dollar sign ({@code $}) rather than a dot ({@code .}).
*
* @implNote This check currently only flags {@link Class#getName()} invocations on class literals,
* and doesn't flag method references. This avoids false positives, such as suggesting use of
* {@link Class#getCanonicalName()} in contexts where the canonical name is {@code null}.
*/
@AutoService(BugChecker.class)
@BugPattern(
summary = "This code should likely use the type's canonical name",
link = BUG_PATTERNS_BASE_URL + "CanonicalClassNameUsage",
linkType = CUSTOM,
severity = WARNING,
tags = FRAGILE_CODE)
public final class CanonicalClassNameUsage extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> GET_NAME_INVOCATION =
toType(
MethodInvocationTree.class,
allOf(
receiverOfInvocation(classLiteral(anything())),
instanceMethod().onExactClass(Class.class.getCanonicalName()).named("getName")));
private static final Pattern CANONICAL_NAME_USING_TYPES =
Pattern.compile("(com\\.google\\.errorprone|tech\\.picnic\\.errorprone)\\..*");
/** Instantiates a new {@link CanonicalClassNameUsage} instance. */
public CanonicalClassNameUsage() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (!GET_NAME_INVOCATION.matches(tree, state) || !isPassedToCanonicalNameUsingType(state)) {
/*
* This is not a `class.getName()` invocation of which the result is passed to another method
* known to accept canonical type names.
*/
return Description.NO_MATCH;
}
return describeMatch(
tree, SuggestedFixes.renameMethodInvocation(tree, "getCanonicalName", state));
}
private static boolean isPassedToCanonicalNameUsingType(VisitorState state) {
@Var TreePath path = state.getPath().getParentPath();
while (path.getLeaf() instanceof BinaryTree) {
path = path.getParentPath();
}
return path.getLeaf() instanceof MethodInvocationTree
&& isOwnedByCanonicalNameUsingType(
ASTHelpers.getSymbol((MethodInvocationTree) path.getLeaf()));
}
private static boolean isOwnedByCanonicalNameUsingType(MethodSymbol symbol) {
return CANONICAL_NAME_USING_TYPES.matcher(symbol.owner.getQualifiedName()).matches();
}
}

View File

@@ -4,9 +4,12 @@ import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.FRAGILE_CODE;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
@@ -17,8 +20,12 @@ import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.stream.Collector;
import tech.picnic.errorprone.bugpatterns.util.ThirdPartyLibrary;
import java.util.stream.Collectors;
import tech.picnic.errorprone.utils.ThirdPartyLibrary;
/**
* A {@link BugChecker} that flags {@link Collector Collectors} that don't clearly express
@@ -38,7 +45,7 @@ import tech.picnic.errorprone.bugpatterns.util.ThirdPartyLibrary;
public final class CollectorMutability extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> COLLECTOR_METHOD =
staticMethod().onClass("java.util.stream.Collectors");
staticMethod().onClass(Collectors.class.getCanonicalName());
private static final Matcher<ExpressionTree> LIST_COLLECTOR =
staticMethod().anyClass().named("toList");
private static final Matcher<ExpressionTree> MAP_COLLECTOR =
@@ -58,7 +65,10 @@ public final class CollectorMutability extends BugChecker implements MethodInvoc
if (LIST_COLLECTOR.matches(tree, state)) {
return suggestToCollectionAlternatives(
tree, "com.google.common.collect.ImmutableList.toImmutableList", "ArrayList", state);
tree,
ImmutableList.class.getCanonicalName() + ".toImmutableList",
ArrayList.class.getCanonicalName(),
state);
}
if (MAP_COLLECTOR.matches(tree, state)) {
@@ -67,7 +77,10 @@ public final class CollectorMutability extends BugChecker implements MethodInvoc
if (SET_COLLECTOR.matches(tree, state)) {
return suggestToCollectionAlternatives(
tree, "com.google.common.collect.ImmutableSet.toImmutableSet", "HashSet", state);
tree,
ImmutableSet.class.getCanonicalName() + ".toImmutableSet",
HashSet.class.getCanonicalName(),
state);
}
return Description.NO_MATCH;
@@ -75,20 +88,20 @@ public final class CollectorMutability extends BugChecker implements MethodInvoc
private Description suggestToCollectionAlternatives(
MethodInvocationTree tree,
String fullyQualifiedImmutableReplacement,
String immutableReplacement,
String mutableReplacement,
VisitorState state) {
SuggestedFix.Builder mutableFix = SuggestedFix.builder();
String toCollectionSelect =
SuggestedFixes.qualifyStaticImport(
"java.util.stream.Collectors.toCollection", mutableFix, state);
Collectors.class.getCanonicalName() + ".toCollection", mutableFix, state);
String mutableCollection = SuggestedFixes.qualifyType(state, mutableFix, mutableReplacement);
return buildDescription(tree)
.addFix(replaceMethodInvocation(tree, fullyQualifiedImmutableReplacement, state))
.addFix(replaceMethodInvocation(tree, immutableReplacement, state))
.addFix(
mutableFix
.addImport(String.format("java.util.%s", mutableReplacement))
.replace(tree, String.format("%s(%s::new)", toCollectionSelect, mutableReplacement))
.replace(tree, String.format("%s(%s::new)", toCollectionSelect, mutableCollection))
.build())
.build();
}
@@ -99,17 +112,20 @@ public final class CollectorMutability extends BugChecker implements MethodInvoc
return Description.NO_MATCH;
}
SuggestedFix.Builder mutableFix = SuggestedFix.builder();
String hashMap =
SuggestedFixes.qualifyType(state, mutableFix, HashMap.class.getCanonicalName());
return buildDescription(tree)
.addFix(
replaceMethodInvocation(
tree, "com.google.common.collect.ImmutableMap.toImmutableMap", state))
tree, ImmutableMap.class.getCanonicalName() + ".toImmutableMap", state))
.addFix(
SuggestedFix.builder()
.addImport("java.util.HashMap")
mutableFix
.postfixWith(
tree.getArguments().get(argCount - 1),
(argCount == 2 ? ", (a, b) -> { throw new IllegalStateException(); }" : "")
+ ", HashMap::new")
+ String.format(", %s::new", hashMap))
.build())
.build();
}

View File

@@ -11,7 +11,7 @@ import static com.google.errorprone.matchers.Matchers.not;
import static com.google.errorprone.matchers.Matchers.returnStatement;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.matchers.Matchers.toType;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.Streams;
@@ -39,8 +39,8 @@ import com.sun.tools.javac.code.Symbol;
import java.util.List;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.bugpatterns.util.MoreASTHelpers;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.MoreASTHelpers;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags unnecessary local variable assignments preceding a return
@@ -58,7 +58,10 @@ public final class DirectReturn extends BugChecker implements BlockTreeMatcher {
private static final Matcher<StatementTree> VARIABLE_RETURN = returnStatement(isVariable());
private static final Matcher<ExpressionTree> MOCKITO_MOCK_OR_SPY_WITH_IMPLICIT_TYPE =
allOf(
not(toType(MethodInvocationTree.class, argument(0, isSameType(Class.class.getName())))),
not(
toType(
MethodInvocationTree.class,
argument(0, isSameType(Class.class.getCanonicalName())))),
staticMethod().onClass("org.mockito.Mockito").namedAnyOf("mock", "spy"));
/** Instantiates a new {@link DirectReturn} instance. */

View File

@@ -7,7 +7,7 @@ import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAS
import static com.google.errorprone.matchers.Matchers.annotations;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.isType;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
@@ -21,7 +21,7 @@ import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import java.util.Optional;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.SourceCode;
/** A {@link BugChecker} that flags empty methods that seemingly can simply be deleted. */
@AutoService(BugChecker.class)
@@ -36,7 +36,9 @@ public final class EmptyMethod extends BugChecker implements MethodTreeMatcher {
private static final Matcher<Tree> PERMITTED_ANNOTATION =
annotations(
AT_LEAST_ONE,
anyOf(isType("java.lang.Override"), isType("org.aspectj.lang.annotation.Pointcut")));
anyOf(
isType(Override.class.getCanonicalName()),
isType("org.aspectj.lang.annotation.Pointcut")));
/** Instantiates a new {@link EmptyMethod} instance. */
public EmptyMethod() {}

View File

@@ -7,7 +7,7 @@ import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.FRAGILE_CODE;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import static java.util.stream.Collectors.collectingAndThen;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
@@ -44,7 +44,7 @@ import java.util.stream.Stream;
public final class ExplicitEnumOrdering extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> EXPLICIT_ORDERING =
staticMethod().onClass(Ordering.class.getName()).named("explicit");
staticMethod().onClass(Ordering.class.getCanonicalName()).named("explicit");
/** Instantiates a new {@link ExplicitEnumOrdering} instance. */
public ExplicitEnumOrdering() {}
@@ -72,7 +72,7 @@ public final class ExplicitEnumOrdering extends BugChecker implements MethodInvo
List<? extends ExpressionTree> expressions) {
return expressions.stream()
.map(ASTHelpers::getSymbol)
.filter(Symbol::isEnum)
.filter(s -> s != null && s.isEnum())
.collect(
collectingAndThen(
toImmutableSetMultimap(Symbol::asType, Symbol::toString),

View File

@@ -4,11 +4,11 @@ import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static com.google.errorprone.BugPattern.StandardTags.LIKELY_ERROR;
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.generic;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.subOf;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.type;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.unbound;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.MoreTypes.generic;
import static tech.picnic.errorprone.utils.MoreTypes.subOf;
import static tech.picnic.errorprone.utils.MoreTypes.type;
import static tech.picnic.errorprone.utils.MoreTypes.unbound;
import com.google.auto.service.AutoService;
import com.google.common.collect.Iterables;
@@ -66,7 +66,7 @@ public final class FluxFlatMapUsage extends BugChecker
instanceMethod()
.onDescendantOf(FLUX)
.namedAnyOf("flatMap", "flatMapSequential")
.withParameters(Function.class.getName());
.withParameters(Function.class.getCanonicalName());
private static final Supplier<Type> FLUX_OF_PUBLISHERS =
VisitorState.memoize(
generic(FLUX, subOf(generic(type("org.reactivestreams.Publisher"), unbound()))));

View File

@@ -6,9 +6,10 @@ import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.CONCURRENCY;
import static com.google.errorprone.BugPattern.StandardTags.PERFORMANCE;
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
@@ -24,8 +25,9 @@ import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.util.Position;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import tech.picnic.errorprone.bugpatterns.util.ThirdPartyLibrary;
import tech.picnic.errorprone.utils.ThirdPartyLibrary;
/**
* A {@link BugChecker} that flags {@link reactor.core.publisher.Flux} operator usages that may
@@ -48,7 +50,8 @@ public final class FluxImplicitBlock extends BugChecker implements MethodInvocat
.onDescendantOf("reactor.core.publisher.Flux")
.namedAnyOf("toIterable", "toStream")
.withNoParameters();
private static final Supplier<Type> STREAM = Suppliers.typeFromString(Stream.class.getName());
private static final Supplier<Type> STREAM =
Suppliers.typeFromString(Stream.class.getCanonicalName());
/** Instantiates a new {@link FluxImplicitBlock} instance. */
public FluxImplicitBlock() {}
@@ -64,10 +67,11 @@ public final class FluxImplicitBlock extends BugChecker implements MethodInvocat
if (ThirdPartyLibrary.GUAVA.isIntroductionAllowed(state)) {
description.addFix(
suggestBlockingElementCollection(
tree, "com.google.common.collect.ImmutableList.toImmutableList", state));
tree, ImmutableList.class.getCanonicalName() + ".toImmutableList", state));
}
description.addFix(
suggestBlockingElementCollection(tree, "java.util.stream.Collectors.toList", state));
suggestBlockingElementCollection(
tree, Collectors.class.getCanonicalName() + ".toList", state));
return description.build();
}

View File

@@ -10,9 +10,11 @@ import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.Matchers.not;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static java.util.stream.Collectors.joining;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
@@ -30,10 +32,11 @@ import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.util.SimpleTreeVisitor;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags string concatenations that produce a format string; in such cases
@@ -68,7 +71,7 @@ public final class FormatStringConcatenation extends BugChecker
anyMethod()
.anyClass()
.withAnyName()
.withParameters(String.class.getName(), Throwable.class.getName());
.withParameters(String.class.getCanonicalName(), Throwable.class.getCanonicalName());
// XXX: Drop some of these methods if we use Refaster to replace some with others.
private static final Matcher<ExpressionTree> ASSERTJ_FORMAT_METHOD =
@@ -118,14 +121,14 @@ public final class FormatStringConcatenation extends BugChecker
private static final Matcher<ExpressionTree> GUAVA_FORMAT_METHOD =
anyOf(
staticMethod()
.onClass("com.google.common.base.Preconditions")
.onClass(Preconditions.class.getCanonicalName())
.namedAnyOf("checkArgument", "checkNotNull", "checkState"),
staticMethod().onClass("com.google.common.base.Verify").named("verify"));
staticMethod().onClass(Verify.class.getCanonicalName()).named("verify"));
// XXX: Add `PrintWriter`, maybe others.
private static final Matcher<ExpressionTree> JDK_FORMAT_METHOD =
anyOf(
staticMethod().onClass("java.lang.String").named("format"),
instanceMethod().onExactClass("java.util.Formatter").named("format"));
staticMethod().onClass(String.class.getCanonicalName()).named("format"),
instanceMethod().onExactClass(Formatter.class.getCanonicalName()).named("format"));
private static final Matcher<ExpressionTree> SLF4J_FORMAT_METHOD =
instanceMethod()
.onDescendantOf("org.slf4j.Logger")

View File

@@ -7,9 +7,20 @@ import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.suppliers.Suppliers.OBJECT_TYPE;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableRangeMap;
import com.google.common.collect.ImmutableRangeSet;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableTable;
import com.google.common.primitives.Primitives;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
@@ -20,6 +31,7 @@ import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.matchers.Matchers;
import com.google.errorprone.util.ASTHelpers;
import com.google.errorprone.util.ASTHelpers.TargetType;
import com.sun.source.tree.ExpressionTree;
@@ -29,7 +41,7 @@ import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import java.util.Arrays;
import java.util.List;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.SourceCode;
/** A {@link BugChecker} that flags redundant identity conversions. */
// XXX: Consider detecting cases where a flagged expression is passed to a method, and where removal
@@ -56,24 +68,22 @@ public final class IdentityConversion extends BugChecker implements MethodInvoca
.map(Class::getName)
.collect(toImmutableSet()))
.named("valueOf"),
staticMethod().onClass(String.class.getName()).named("valueOf"),
staticMethod().onClass(String.class.getCanonicalName()).named("valueOf"),
staticMethod()
.onClassAny(
"com.google.common.collect.ImmutableBiMap",
"com.google.common.collect.ImmutableList",
"com.google.common.collect.ImmutableListMultimap",
"com.google.common.collect.ImmutableMap",
"com.google.common.collect.ImmutableMultimap",
"com.google.common.collect.ImmutableMultiset",
"com.google.common.collect.ImmutableRangeMap",
"com.google.common.collect.ImmutableRangeSet",
"com.google.common.collect.ImmutableSet",
"com.google.common.collect.ImmutableSetMultimap",
"com.google.common.collect.ImmutableTable")
ImmutableBiMap.class.getCanonicalName(),
ImmutableList.class.getCanonicalName(),
ImmutableListMultimap.class.getCanonicalName(),
ImmutableMap.class.getCanonicalName(),
ImmutableMultimap.class.getCanonicalName(),
ImmutableMultiset.class.getCanonicalName(),
ImmutableRangeMap.class.getCanonicalName(),
ImmutableRangeSet.class.getCanonicalName(),
ImmutableSet.class.getCanonicalName(),
ImmutableSetMultimap.class.getCanonicalName(),
ImmutableTable.class.getCanonicalName())
.named("copyOf"),
staticMethod()
.onClass("com.google.errorprone.matchers.Matchers")
.namedAnyOf("allOf", "anyOf"),
staticMethod().onClass(Matchers.class.getCanonicalName()).namedAnyOf("allOf", "anyOf"),
staticMethod().onClass("reactor.adapter.rxjava.RxJava2Adapter"),
staticMethod()
.onClass("reactor.core.publisher.Flux")

View File

@@ -11,7 +11,7 @@ import static com.google.errorprone.matchers.Matchers.hasModifier;
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
import static com.google.errorprone.matchers.Matchers.methodReturns;
import static com.google.errorprone.matchers.Matchers.not;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;

View File

@@ -3,7 +3,7 @@ package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.Iterables;
@@ -18,15 +18,14 @@ import com.sun.source.tree.InstanceOfTree;
import com.sun.source.tree.LambdaExpressionTree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.tree.VariableTree;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags lambda expressions that can be replaced with a method reference
* of the form {@code T.class::isInstance}.
*
* @see MethodReferenceUsage
*/
// XXX: Consider folding this logic into the `MethodReferenceUsage` check.
// XXX: Consider folding this logic into the `MethodReferenceUsage` check of the
// `error-prone-experimental` module.
@AutoService(BugChecker.class)
@BugPattern(
summary = "Prefer `Class::isInstance` method reference over equivalent lambda expression",

View File

@@ -11,9 +11,9 @@ import static com.google.errorprone.matchers.Matchers.hasMethod;
import static com.google.errorprone.matchers.Matchers.hasModifier;
import static com.google.errorprone.matchers.Matchers.isType;
import static com.google.errorprone.matchers.Matchers.not;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.bugpatterns.util.MoreJUnitMatchers.TEST_METHOD;
import static tech.picnic.errorprone.bugpatterns.util.MoreMatchers.hasMetaAnnotation;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.MoreJUnitMatchers.TEST_METHOD;
import static tech.picnic.errorprone.utils.MoreMatchers.hasMetaAnnotation;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;

View File

@@ -8,9 +8,9 @@ import static com.google.errorprone.matchers.Matchers.enclosingClass;
import static com.google.errorprone.matchers.Matchers.hasModifier;
import static com.google.errorprone.matchers.Matchers.not;
import static java.util.function.Predicate.not;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.bugpatterns.util.MoreJUnitMatchers.SETUP_OR_TEARDOWN_METHOD;
import static tech.picnic.errorprone.bugpatterns.util.MoreJUnitMatchers.TEST_METHOD;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.MoreJUnitMatchers.SETUP_OR_TEARDOWN_METHOD;
import static tech.picnic.errorprone.utils.MoreJUnitMatchers.TEST_METHOD;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
@@ -28,7 +28,7 @@ import com.sun.source.tree.MethodTree;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import java.util.Optional;
import javax.lang.model.element.Modifier;
import tech.picnic.errorprone.bugpatterns.util.ConflictDetection;
import tech.picnic.errorprone.utils.ConflictDetection;
/** A {@link BugChecker} that flags non-canonical JUnit method declarations. */
// XXX: Consider introducing a class-level check that enforces that test classes:

View File

@@ -7,8 +7,8 @@ import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAS
import static com.google.errorprone.matchers.Matchers.annotations;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.isType;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.bugpatterns.util.MoreMatchers.hasMetaAnnotation;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.MoreMatchers.hasMetaAnnotation;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
@@ -23,7 +23,7 @@ import com.google.errorprone.matchers.MultiMatcher;
import com.google.errorprone.matchers.MultiMatcher.MultiMatchResult;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.MethodTree;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags nullary {@link

View File

@@ -19,17 +19,20 @@ import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.matchers.Matchers.toType;
import static java.util.function.Predicate.not;
import static java.util.stream.Collectors.joining;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.bugpatterns.util.MoreJUnitMatchers.HAS_METHOD_SOURCE;
import static tech.picnic.errorprone.bugpatterns.util.MoreJUnitMatchers.getMethodSourceFactoryNames;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.MoreJUnitMatchers.HAS_METHOD_SOURCE;
import static tech.picnic.errorprone.utils.MoreJUnitMatchers.getMethodSourceFactoryNames;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.util.ASTHelpers;
@@ -55,7 +58,7 @@ import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags JUnit tests with a {@link
@@ -99,14 +102,14 @@ public final class JUnitValueSource extends BugChecker implements MethodTreeMatc
allOf(
staticMethod()
.onClassAny(
Stream.class.getName(),
IntStream.class.getName(),
LongStream.class.getName(),
DoubleStream.class.getName(),
List.class.getName(),
Set.class.getName(),
"com.google.common.collect.ImmutableList",
"com.google.common.collect.ImmutableSet")
Stream.class.getCanonicalName(),
IntStream.class.getCanonicalName(),
LongStream.class.getCanonicalName(),
DoubleStream.class.getCanonicalName(),
List.class.getCanonicalName(),
Set.class.getCanonicalName(),
ImmutableList.class.getCanonicalName(),
ImmutableSet.class.getCanonicalName())
.named("of"),
hasArguments(AT_LEAST_ONE, anything()),
hasArguments(ALL, SUPPORTED_VALUE_FACTORY_VALUES)));
@@ -199,16 +202,21 @@ public final class JUnitValueSource extends BugChecker implements MethodTreeMatc
return getSingleReturnExpression(valueFactoryMethod)
.flatMap(expression -> tryExtractValueSourceAttributeValue(expression, state))
.map(
valueSourceAttributeValue ->
SuggestedFix.builder()
.addImport("org.junit.jupiter.params.provider.ValueSource")
.replace(
methodSourceAnnotation,
String.format(
"@ValueSource(%s = %s)",
toValueSourceAttributeName(parameterType), valueSourceAttributeValue))
.delete(valueFactoryMethod)
.build());
valueSourceAttributeValue -> {
SuggestedFix.Builder fix = SuggestedFix.builder();
String valueSource =
SuggestedFixes.qualifyType(
state, fix, "org.junit.jupiter.params.provider.ValueSource");
return fix.replace(
methodSourceAnnotation,
String.format(
"@%s(%s = %s)",
valueSource,
toValueSourceAttributeName(parameterType),
valueSourceAttributeValue))
.delete(valueFactoryMethod)
.build();
});
}
// XXX: This pattern also occurs a few times inside Error Prone; contribute upstream.

View File

@@ -7,7 +7,7 @@ import static com.google.errorprone.BugPattern.StandardTags.STYLE;
import static java.util.Comparator.comparing;
import static java.util.Comparator.naturalOrder;
import static java.util.stream.Collectors.joining;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.base.Splitter;
@@ -42,9 +42,9 @@ import java.util.Set;
import java.util.stream.Stream;
import javax.inject.Inject;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.bugpatterns.util.AnnotationAttributeMatcher;
import tech.picnic.errorprone.bugpatterns.util.Flags;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.AnnotationAttributeMatcher;
import tech.picnic.errorprone.utils.Flags;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags annotation array listings which aren't sorted lexicographically.

View File

@@ -7,7 +7,7 @@ import static com.google.errorprone.BugPattern.StandardTags.STYLE;
import static com.sun.tools.javac.code.TypeAnnotations.AnnotationType.DECLARATION;
import static com.sun.tools.javac.code.TypeAnnotations.AnnotationType.TYPE;
import static java.util.Comparator.comparing;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.base.VerifyException;
@@ -28,7 +28,7 @@ import com.sun.tools.javac.code.TypeAnnotations.AnnotationType;
import java.util.Comparator;
import java.util.List;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags annotations that are not lexicographically sorted.

View File

@@ -9,7 +9,7 @@ import static com.google.errorprone.matchers.Matchers.isSameType;
import static com.google.errorprone.matchers.Matchers.isVariable;
import static com.google.errorprone.matchers.Matchers.not;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
@@ -25,7 +25,7 @@ import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import java.util.List;
import tech.picnic.errorprone.bugpatterns.util.MoreASTHelpers;
import tech.picnic.errorprone.utils.MoreASTHelpers;
/**
* A {@link BugChecker} that flags the use of {@link org.mockito.Mockito#mock(Class)} and {@link
@@ -50,7 +50,7 @@ public final class MockitoMockClassReference extends BugChecker
private static final long serialVersionUID = 1L;
private static final Matcher<MethodInvocationTree> MOCKITO_MOCK_OR_SPY_WITH_HARDCODED_TYPE =
allOf(
argument(0, allOf(isSameType(Class.class.getName()), not(isVariable()))),
argument(0, allOf(isSameType(Class.class.getCanonicalName()), not(isVariable()))),
staticMethod().onClass("org.mockito.Mockito").namedAnyOf("mock", "spy"));
/** Instantiates a new {@link MockitoMockClassReference} instance. */

View File

@@ -4,7 +4,7 @@ import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.Iterables;
@@ -18,7 +18,7 @@ import com.google.errorprone.matchers.Matcher;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import java.util.List;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags method invocations for which all arguments are wrapped using

View File

@@ -4,7 +4,7 @@ import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.PERFORMANCE;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;

View File

@@ -3,11 +3,11 @@ package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.FRAGILE_CODE;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.bugpatterns.util.MoreMatchers.isSubTypeOf;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.generic;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.raw;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.subOf;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.MoreMatchers.isSubTypeOf;
import static tech.picnic.errorprone.utils.MoreTypes.generic;
import static tech.picnic.errorprone.utils.MoreTypes.raw;
import static tech.picnic.errorprone.utils.MoreTypes.subOf;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;

View File

@@ -6,13 +6,13 @@ import static com.google.errorprone.BugPattern.StandardTags.FRAGILE_CODE;
import static com.google.errorprone.matchers.Matchers.typePredicateMatcher;
import static com.google.errorprone.predicates.TypePredicates.allOf;
import static com.google.errorprone.predicates.TypePredicates.not;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypePredicates.hasTypeParameter;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypePredicates.isSubTypeOf;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.generic;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.raw;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.subOf;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.type;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.MoreTypePredicates.hasTypeParameter;
import static tech.picnic.errorprone.utils.MoreTypePredicates.isSubTypeOf;
import static tech.picnic.errorprone.utils.MoreTypes.generic;
import static tech.picnic.errorprone.utils.MoreTypes.raw;
import static tech.picnic.errorprone.utils.MoreTypes.subOf;
import static tech.picnic.errorprone.utils.MoreTypes.type;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;

View File

@@ -5,7 +5,7 @@ import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
@@ -20,7 +20,7 @@ import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import java.util.function.BiFunction;
import reactor.core.publisher.Mono;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags {@link Mono} operations that are known to be vacuous, given that
@@ -72,7 +72,7 @@ public final class NonEmptyMono extends BugChecker implements MethodInvocationTr
instanceMethod()
.onDescendantOf("reactor.core.publisher.Flux")
.named("reduce")
.withParameters(Object.class.getName(), BiFunction.class.getName()),
.withParameters(Object.class.getCanonicalName(), BiFunction.class.getCanonicalName()),
instanceMethod()
.onDescendantOf("reactor.core.publisher.Mono")
.namedAnyOf("defaultIfEmpty", "hasElement", "single"));

View File

@@ -4,11 +4,13 @@ import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.STYLE;
import static tech.picnic.errorprone.bugpatterns.StaticImport.STATIC_IMPORT_CANDIDATE_MEMBERS;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import 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.annotations.VisibleForTesting;
import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableTable;
@@ -27,8 +29,14 @@ import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.Tree;
import com.sun.source.util.TreeScanner;
import com.sun.tools.javac.code.Symbol;
import java.time.Clock;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.Locale;
import java.util.Optional;
import java.util.regex.Pattern;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags static imports of type members that should *not* be statically
@@ -59,10 +67,14 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
@VisibleForTesting
static final ImmutableSet<String> NON_STATIC_IMPORT_CANDIDATE_TYPES =
ImmutableSet.of(
"com.google.common.base.Strings",
ASTHelpers.class.getCanonicalName(),
Clock.class.getCanonicalName(),
Strings.class.getCanonicalName(),
VisitorState.class.getCanonicalName(),
ZoneOffset.class.getCanonicalName(),
"com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode",
"java.time.Clock",
"java.time.ZoneOffset");
"reactor.core.publisher.Flux",
"reactor.core.publisher.Mono");
/**
* Type members that should never be statically imported.
@@ -81,9 +93,8 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
// specific context is left out.
static final ImmutableSetMultimap<String, String> NON_STATIC_IMPORT_CANDIDATE_MEMBERS =
ImmutableSetMultimap.<String, String>builder()
.put("com.google.common.base.Predicates", "contains")
.putAll(
"java.util.Collections",
Collections.class.getCanonicalName(),
"addAll",
"copy",
"fill",
@@ -94,8 +105,10 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
"rotate",
"sort",
"swap")
.put("java.util.Locale", "ROOT")
.putAll("java.util.regex.Pattern", "compile", "matches", "quote")
.put(Locale.class.getCanonicalName(), "ROOT")
.put(Optional.class.getCanonicalName(), "empty")
.putAll(Pattern.class.getCanonicalName(), "compile", "matches", "quote")
.put(Predicates.class.getCanonicalName(), "contains")
.put("org.springframework.http.MediaType", "ALL")
.build();
@@ -116,7 +129,6 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
"builder",
"copyOf",
"create",
"empty",
"from",
"getDefaultInstance",
"INSTANCE",
@@ -127,10 +139,8 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
"newBuilder",
"newInstance",
"of",
"ONE",
"parse",
"valueOf",
"ZERO");
"valueOf");
/** Instantiates a new {@link NonStaticImport} instance. */
public NonStaticImport() {}

View File

@@ -7,7 +7,7 @@ import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import static java.util.stream.Collectors.joining;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.base.VerifyException;
@@ -17,6 +17,7 @@ import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.fixes.Fix;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.util.ASTHelpers;
@@ -32,7 +33,7 @@ import java.util.Comparator;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Stream;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags {@code Comparator#comparing*} invocations that can be replaced
@@ -55,21 +56,21 @@ public final class PrimitiveComparison extends BugChecker implements MethodInvoc
private static final Matcher<ExpressionTree> STATIC_COMPARISON_METHOD =
anyOf(
staticMethod()
.onClass(Comparator.class.getName())
.onClass(Comparator.class.getCanonicalName())
.namedAnyOf("comparingInt", "comparingLong", "comparingDouble"),
staticMethod()
.onClass(Comparator.class.getName())
.onClass(Comparator.class.getCanonicalName())
.named("comparing")
.withParameters(Function.class.getName()));
.withParameters(Function.class.getCanonicalName()));
private static final Matcher<ExpressionTree> INSTANCE_COMPARISON_METHOD =
anyOf(
instanceMethod()
.onDescendantOf(Comparator.class.getName())
.onDescendantOf(Comparator.class.getCanonicalName())
.namedAnyOf("thenComparingInt", "thenComparingLong", "thenComparingDouble"),
instanceMethod()
.onDescendantOf(Comparator.class.getName())
.onDescendantOf(Comparator.class.getCanonicalName())
.named("thenComparing")
.withParameters(Function.class.getName()));
.withParameters(Function.class.getCanonicalName()));
/** Instantiates a new {@link PrimitiveComparison} instance. */
public PrimitiveComparison() {}
@@ -167,10 +168,11 @@ public final class PrimitiveComparison extends BugChecker implements MethodInvoc
ExpressionTree expr = tree.getMethodSelect();
switch (expr.getKind()) {
case IDENTIFIER:
return SuggestedFix.builder()
.addStaticImport(Comparator.class.getName() + '.' + preferredMethodName)
.replace(expr, preferredMethodName)
.build();
SuggestedFix.Builder fix = SuggestedFix.builder();
String replacement =
SuggestedFixes.qualifyStaticImport(
Comparator.class.getCanonicalName() + '.' + preferredMethodName, fix, state);
return fix.replace(expr, replacement).build();
case MEMBER_SELECT:
MemberSelectTree ms = (MemberSelectTree) tree.getMethodSelect();
return SuggestedFix.replace(

View File

@@ -15,9 +15,11 @@ import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
import static com.google.errorprone.matchers.Matchers.not;
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.primitives.Primitives;
@@ -51,9 +53,9 @@ import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import javax.inject.Inject;
import tech.picnic.errorprone.bugpatterns.util.Flags;
import tech.picnic.errorprone.bugpatterns.util.MethodMatcherFactory;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.Flags;
import tech.picnic.errorprone.utils.MethodMatcherFactory;
import tech.picnic.errorprone.utils.SourceCode;
/** A {@link BugChecker} that flags redundant explicit string conversions. */
@AutoService(BugChecker.class)
@@ -86,7 +88,7 @@ public final class RedundantStringConversion extends BugChecker
private static final Matcher<MethodInvocationTree> WELL_KNOWN_STRING_CONVERSION_METHODS =
anyOf(
instanceMethod()
.onDescendantOfAny(Object.class.getName())
.onDescendantOfAny(Object.class.getCanonicalName())
.named("toString")
.withNoParameters(),
allOf(
@@ -100,7 +102,7 @@ public final class RedundantStringConversion extends BugChecker
.collect(toImmutableSet()))
.named("toString"),
allOf(
staticMethod().onClass(String.class.getName()).named("valueOf"),
staticMethod().onClass(String.class.getCanonicalName()).named("valueOf"),
not(
anyMethod()
.anyClass()
@@ -109,35 +111,37 @@ public final class RedundantStringConversion extends BugChecker
ImmutableList.of(Suppliers.arrayOf(Suppliers.CHAR_TYPE))))))));
private static final Matcher<ExpressionTree> STRINGBUILDER_APPEND_INVOCATION =
instanceMethod()
.onDescendantOf(StringBuilder.class.getName())
.onDescendantOf(StringBuilder.class.getCanonicalName())
.named("append")
.withParameters(String.class.getName());
.withParameters(String.class.getCanonicalName());
private static final Matcher<ExpressionTree> STRINGBUILDER_INSERT_INVOCATION =
instanceMethod()
.onDescendantOf(StringBuilder.class.getName())
.onDescendantOf(StringBuilder.class.getCanonicalName())
.named("insert")
.withParameters(int.class.getName(), String.class.getName());
.withParameters(int.class.getCanonicalName(), String.class.getCanonicalName());
private static final Matcher<ExpressionTree> FORMATTER_INVOCATION =
anyOf(
staticMethod().onClass(String.class.getName()).named("format"),
instanceMethod().onDescendantOf(Formatter.class.getName()).named("format"),
staticMethod().onClass(String.class.getCanonicalName()).named("format"),
instanceMethod().onDescendantOf(Formatter.class.getCanonicalName()).named("format"),
instanceMethod()
.onDescendantOfAny(PrintStream.class.getName(), PrintWriter.class.getName())
.onDescendantOfAny(
PrintStream.class.getCanonicalName(), PrintWriter.class.getCanonicalName())
.namedAnyOf("format", "printf"),
instanceMethod()
.onDescendantOfAny(PrintStream.class.getName(), PrintWriter.class.getName())
.onDescendantOfAny(
PrintStream.class.getCanonicalName(), PrintWriter.class.getCanonicalName())
.namedAnyOf("print", "println")
.withParameters(Object.class.getName()),
.withParameters(Object.class.getCanonicalName()),
staticMethod()
.onClass(Console.class.getName())
.onClass(Console.class.getCanonicalName())
.namedAnyOf("format", "printf", "readline", "readPassword"));
private static final Matcher<ExpressionTree> GUAVA_GUARD_INVOCATION =
anyOf(
staticMethod()
.onClass("com.google.common.base.Preconditions")
.onClass(Preconditions.class.getCanonicalName())
.namedAnyOf("checkArgument", "checkState", "checkNotNull"),
staticMethod()
.onClass("com.google.common.base.Verify")
.onClass(Verify.class.getCanonicalName())
.namedAnyOf("verify", "verifyNotNull"));
private static final Matcher<ExpressionTree> SLF4J_LOGGER_INVOCATION =
instanceMethod()

View File

@@ -11,7 +11,7 @@ import static com.google.errorprone.matchers.Matchers.isSameType;
import static com.google.errorprone.matchers.Matchers.isType;
import static com.google.errorprone.matchers.Matchers.methodHasParameters;
import static com.google.errorprone.matchers.Matchers.not;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
@@ -22,6 +22,10 @@ import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import java.io.InputStream;
import java.time.ZoneId;
import java.util.Locale;
import java.util.TimeZone;
/**
* A {@link BugChecker} that flags {@code @RequestMapping} methods that have one or more parameters
@@ -69,11 +73,13 @@ public final class RequestMappingAnnotation extends BugChecker implements Method
isType(ANN_PACKAGE_PREFIX + "RequestBody"),
isType(ANN_PACKAGE_PREFIX + "RequestHeader"),
isType(ANN_PACKAGE_PREFIX + "RequestParam"),
isType(ANN_PACKAGE_PREFIX + "RequestPart"))),
isSameType("java.io.InputStream"),
isSameType("java.time.ZoneId"),
isSameType("java.util.Locale"),
isSameType("java.util.TimeZone"),
isType(ANN_PACKAGE_PREFIX + "RequestPart"),
isType(
"org.springframework.security.core.annotation.CurrentSecurityContext"))),
isSameType(InputStream.class.getCanonicalName()),
isSameType(Locale.class.getCanonicalName()),
isSameType(TimeZone.class.getCanonicalName()),
isSameType(ZoneId.class.getCanonicalName()),
isSameType("jakarta.servlet.http.HttpServletRequest"),
isSameType("jakarta.servlet.http.HttpServletResponse"),
isSameType("javax.servlet.http.HttpServletRequest"),

View File

@@ -11,7 +11,7 @@ import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
import static com.google.errorprone.matchers.Matchers.isType;
import static com.google.errorprone.matchers.Matchers.not;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableCollection;
@@ -28,7 +28,7 @@ import com.google.errorprone.suppliers.Suppliers;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import javax.inject.Inject;
import tech.picnic.errorprone.bugpatterns.util.Flags;
import tech.picnic.errorprone.utils.Flags;
/** A {@link BugChecker} that flags {@code @RequestParam} parameters with an unsupported type. */
@AutoService(BugChecker.class)

View File

@@ -6,7 +6,7 @@ import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.LIKELY_ERROR;
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.base.Splitter;
@@ -23,7 +23,7 @@ import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree.Kind;
import java.util.List;
import java.util.Optional;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
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

View File

@@ -6,7 +6,7 @@ import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static java.util.function.Predicate.not;
import static java.util.stream.Collectors.joining;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.base.VerifyException;
@@ -18,6 +18,7 @@ import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
import com.google.errorprone.fixes.Fix;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.AssignmentTree;
@@ -26,8 +27,8 @@ import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.NewArrayTree;
import com.sun.source.tree.Tree.Kind;
import java.util.Optional;
import tech.picnic.errorprone.bugpatterns.util.AnnotationAttributeMatcher;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.AnnotationAttributeMatcher;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags {@code @RequestMapping} annotations that can be written more
@@ -114,9 +115,8 @@ public final class SpringMvcAnnotation extends BugChecker implements AnnotationT
.map(arg -> SourceCode.treeToString(arg, state))
.collect(joining(", "));
return SuggestedFix.builder()
.addImport(ANN_PACKAGE_PREFIX + newAnnotation)
.replace(tree, String.format("@%s(%s)", newAnnotation, newArguments))
.build();
SuggestedFix.Builder fix = SuggestedFix.builder();
String annotation = SuggestedFixes.qualifyType(state, fix, ANN_PACKAGE_PREFIX + newAnnotation);
return fix.replace(tree, String.format("@%s(%s)", annotation, newArguments)).build();
}
}

View File

@@ -6,12 +6,28 @@ import static com.google.errorprone.BugPattern.StandardTags.STYLE;
import static java.util.Objects.requireNonNull;
import static tech.picnic.errorprone.bugpatterns.NonStaticImport.NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS;
import static tech.picnic.errorprone.bugpatterns.NonStaticImport.NON_STATIC_IMPORT_CANDIDATE_MEMBERS;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Functions;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicates;
import com.google.common.base.Verify;
import com.google.common.collect.Comparators;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableRangeSet;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ImmutableSortedMultiset;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.MoreCollectors;
import com.google.common.collect.Sets;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
@@ -22,12 +38,25 @@ import com.google.errorprone.fixes.Fix;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matchers;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Type;
import java.nio.charset.StandardCharsets;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/** A {@link BugChecker} that flags type members that can and should be statically imported. */
// XXX: This check is closely linked to `NonStaticImport`. Consider merging the two.
@@ -57,15 +86,25 @@ public final class StaticImport extends BugChecker implements MemberSelectTreeMa
@VisibleForTesting
static final ImmutableSet<String> STATIC_IMPORT_CANDIDATE_TYPES =
ImmutableSet.of(
"com.google.common.base.Preconditions",
"com.google.common.base.Predicates",
"com.google.common.base.Verify",
"com.google.common.collect.MoreCollectors",
"com.google.errorprone.BugPattern.LinkType",
"com.google.errorprone.BugPattern.SeverityLevel",
"com.google.errorprone.BugPattern.StandardTags",
"com.google.errorprone.matchers.Matchers",
"com.google.errorprone.refaster.ImportPolicy",
BugPattern.LinkType.class.getCanonicalName(),
BugPattern.SeverityLevel.class.getCanonicalName(),
BugPattern.StandardTags.class.getCanonicalName(),
Collections.class.getCanonicalName(),
Collectors.class.getCanonicalName(),
Comparator.class.getCanonicalName(),
ImportPolicy.class.getCanonicalName(),
Map.Entry.class.getCanonicalName(),
Matchers.class.getCanonicalName(),
MoreCollectors.class.getCanonicalName(),
Pattern.class.getCanonicalName(),
Preconditions.class.getCanonicalName(),
Predicates.class.getCanonicalName(),
StandardCharsets.class.getCanonicalName(),
Verify.class.getCanonicalName(),
"com.fasterxml.jackson.annotation.JsonCreator.Mode",
"com.fasterxml.jackson.annotation.JsonFormat.Shape",
"com.fasterxml.jackson.annotation.JsonInclude.Include",
"com.fasterxml.jackson.annotation.JsonProperty.Access",
"com.mongodb.client.model.Accumulators",
"com.mongodb.client.model.Aggregates",
"com.mongodb.client.model.Filters",
@@ -73,12 +112,6 @@ public final class StaticImport extends BugChecker implements MemberSelectTreeMa
"com.mongodb.client.model.Projections",
"com.mongodb.client.model.Sorts",
"com.mongodb.client.model.Updates",
"java.nio.charset.StandardCharsets",
"java.util.Collections",
"java.util.Comparator",
"java.util.Map.Entry",
"java.util.regex.Pattern",
"java.util.stream.Collectors",
"org.assertj.core.api.Assertions",
"org.assertj.core.api.InstanceOfAssertFactories",
"org.assertj.core.api.SoftAssertions",
@@ -99,7 +132,7 @@ public final class StaticImport extends BugChecker implements MemberSelectTreeMa
"org.springframework.http.MediaType",
"org.testng.Assert",
"reactor.function.TupleUtils",
"tech.picnic.errorprone.bugpatterns.util.MoreTypes");
"tech.picnic.errorprone.utils.MoreTypes");
/**
* Type members that should be statically imported.
@@ -117,39 +150,39 @@ public final class StaticImport extends BugChecker implements MemberSelectTreeMa
*/
static final ImmutableSetMultimap<String, String> STATIC_IMPORT_CANDIDATE_MEMBERS =
ImmutableSetMultimap.<String, String>builder()
.putAll(Comparators.class.getCanonicalName(), "emptiesFirst", "emptiesLast")
.put(Function.class.getCanonicalName(), "identity")
.put(Functions.class.getCanonicalName(), "identity")
.put(ImmutableList.class.getCanonicalName(), "toImmutableList")
.putAll(
"com.google.common.collect.ImmutableListMultimap",
ImmutableListMultimap.class.getCanonicalName(),
"flatteningToImmutableListMultimap",
"toImmutableListMultimap")
.put("com.google.common.collect.ImmutableList", "toImmutableList")
.put("com.google.common.collect.ImmutableMap", "toImmutableMap")
.put("com.google.common.collect.ImmutableMultiset", "toImmutableMultiset")
.put("com.google.common.collect.ImmutableRangeSet", "toImmutableRangeSet")
.put(ImmutableMap.class.getCanonicalName(), "toImmutableMap")
.put(ImmutableMultiset.class.getCanonicalName(), "toImmutableMultiset")
.put(ImmutableRangeSet.class.getCanonicalName(), "toImmutableRangeSet")
.put(ImmutableSet.class.getCanonicalName(), "toImmutableSet")
.putAll(
"com.google.common.collect.ImmutableSetMultimap",
ImmutableSetMultimap.class.getCanonicalName(),
"flatteningToImmutableSetMultimap",
"toImmutableSetMultimap")
.put("com.google.common.collect.ImmutableSet", "toImmutableSet")
.put("com.google.common.collect.ImmutableSortedMap", "toImmutableSortedMap")
.put("com.google.common.collect.ImmutableSortedMultiset", "toImmutableSortedMultiset")
.put("com.google.common.collect.ImmutableSortedSet", "toImmutableSortedSet")
.put("com.google.common.collect.ImmutableTable", "toImmutableTable")
.put("com.google.common.collect.Sets", "toImmutableEnumSet")
.put("com.google.common.base.Functions", "identity")
.put("java.time.ZoneOffset", "UTC")
.put("java.util.function.Function", "identity")
.put("java.util.function.Predicate", "not")
.put("java.util.UUID", "randomUUID")
.put("org.junit.jupiter.params.provider.Arguments", "arguments")
.put(ImmutableSortedMap.class.getCanonicalName(), "toImmutableSortedMap")
.put(ImmutableSortedMultiset.class.getCanonicalName(), "toImmutableSortedMultiset")
.put(ImmutableSortedSet.class.getCanonicalName(), "toImmutableSortedSet")
.put(ImmutableTable.class.getCanonicalName(), "toImmutableTable")
.putAll(
"java.util.Objects",
Objects.class.getCanonicalName(),
"checkIndex",
"checkFromIndexSize",
"checkFromToIndex",
"requireNonNull",
"requireNonNullElse",
"requireNonNullElseGet")
.putAll("com.google.common.collect.Comparators", "emptiesFirst", "emptiesLast")
.put(Predicate.class.getCanonicalName(), "not")
.put(Sets.class.getCanonicalName(), "toImmutableEnumSet")
.put(UUID.class.getCanonicalName(), "randomUUID")
.put(ZoneOffset.class.getCanonicalName(), "UTC")
.put("org.junit.jupiter.params.provider.Arguments", "arguments")
.build();
/** Instantiates a new {@link StaticImport} instance. */

View File

@@ -4,7 +4,7 @@ import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.base.Splitter;
@@ -28,7 +28,7 @@ import java.util.Formattable;
import java.util.Iterator;
import java.util.List;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags {@link String#format(String, Object...)} invocations which can be
@@ -49,7 +49,7 @@ public final class StringJoin extends BugChecker implements MethodInvocationTree
private static final long serialVersionUID = 1L;
private static final Splitter FORMAT_SPECIFIER_SPLITTER = Splitter.on("%s");
private static final Matcher<ExpressionTree> STRING_FORMAT_INVOCATION =
staticMethod().onClass(String.class.getName()).named("format");
staticMethod().onClass(String.class.getCanonicalName()).named("format");
private static final Supplier<Type> CHAR_SEQUENCE_TYPE =
Suppliers.typeFromClass(CharSequence.class);
private static final Supplier<Type> FORMATTABLE_TYPE = Suppliers.typeFromClass(Formattable.class);

View File

@@ -10,7 +10,7 @@ import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
import static com.google.errorprone.matchers.Matchers.not;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
@@ -45,11 +45,11 @@ public final class TimeZoneUsage extends BugChecker implements MethodInvocationT
anyOf(
allOf(
instanceMethod()
.onDescendantOf(Clock.class.getName())
.onDescendantOf(Clock.class.getCanonicalName())
.namedAnyOf("getZone", "withZone"),
not(enclosingClass(isSubtypeOf(Clock.class)))),
staticMethod()
.onClass(Clock.class.getName())
.onClass(Clock.class.getCanonicalName())
.namedAnyOf(
"system",
"systemDefaultZone",
@@ -59,14 +59,17 @@ public final class TimeZoneUsage extends BugChecker implements MethodInvocationT
"tickSeconds"),
staticMethod()
.onClassAny(
LocalDate.class.getName(),
LocalDateTime.class.getName(),
LocalTime.class.getName(),
OffsetDateTime.class.getName(),
OffsetTime.class.getName(),
ZonedDateTime.class.getName())
LocalDate.class.getCanonicalName(),
LocalDateTime.class.getCanonicalName(),
LocalTime.class.getCanonicalName(),
OffsetDateTime.class.getCanonicalName(),
OffsetTime.class.getCanonicalName(),
ZonedDateTime.class.getCanonicalName())
.named("now"),
staticMethod().onClassAny(Instant.class.getName()).named("now").withNoParameters());
staticMethod()
.onClassAny(Instant.class.getCanonicalName())
.named("now")
.withNoParameters());
/** Instantiates a new {@link TimeZoneUsage} instance. */
public TimeZoneUsage() {}

View File

@@ -530,13 +530,13 @@ final class AssertJRules {
static final class AssertThatStreamContainsAnyElementsOf<S, T extends S, U extends T> {
@BeforeTemplate
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).containsAnyElementsOf(iterable);
}
@BeforeTemplate
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsAnyElementsOf(iterable);
}
@@ -551,13 +551,13 @@ final class AssertJRules {
static final class AssertThatStreamContainsAnyOf<S, T extends S, U extends T> {
@BeforeTemplate
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, U[] array) {
Stream<S> stream, U[] array, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).containsAnyOf(array);
}
@BeforeTemplate
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, U[] array) {
Stream<S> stream, U[] array, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsAnyOf(array);
}
@@ -573,14 +573,14 @@ final class AssertJRules {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsAnyOf" /* Varargs converted to array. */)
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).containsAnyOf(Refaster.asVarargs(elements));
}
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsAnyOf" /* Varargs converted to array. */)
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsAnyOf(Refaster.asVarargs(elements));
}
@@ -596,13 +596,13 @@ final class AssertJRules {
static final class AssertThatStreamContainsAll<S, T extends S, U extends T> {
@BeforeTemplate
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).containsAll(iterable);
}
@BeforeTemplate
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsAll(iterable);
}
@@ -617,13 +617,13 @@ final class AssertJRules {
static final class AssertThatStreamContains<S, T extends S, U extends T> {
@BeforeTemplate
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, U[] array) {
Stream<S> stream, U[] array, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).contains(array);
}
@BeforeTemplate
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, U[] array) {
Stream<S> stream, U[] array, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).contains(array);
}
@@ -639,14 +639,14 @@ final class AssertJRules {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContains" /* Varargs converted to array. */)
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).contains(Refaster.asVarargs(elements));
}
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContains" /* Varargs converted to array. */)
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).contains(Refaster.asVarargs(elements));
}
@@ -661,7 +661,7 @@ final class AssertJRules {
static final class AssertThatStreamContainsExactlyElementsOf<S, T extends S, U extends T> {
@BeforeTemplate
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsExactlyElementsOf(iterable);
}
@@ -676,7 +676,7 @@ final class AssertJRules {
static final class AssertThatStreamContainsExactly<S, T extends S, U extends T> {
@BeforeTemplate
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, U[] array) {
Stream<S> stream, U[] array, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsExactly(array);
}
@@ -692,7 +692,7 @@ final class AssertJRules {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsExactly" /* Varargs converted to array. */)
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsExactly(Refaster.asVarargs(elements));
}
@@ -708,13 +708,13 @@ final class AssertJRules {
S, T extends S, U extends T> {
@BeforeTemplate
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsExactlyInAnyOrderElementsOf(iterable);
}
@BeforeTemplate
AbstractCollectionAssert<?, ?, T, ?> before2(
Stream<S> stream, Collector<S, ?, ? extends Multiset<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends Multiset<T>> collector) {
return assertThat(stream.collect(collector)).containsExactlyInAnyOrderElementsOf(iterable);
}
@@ -729,13 +729,13 @@ final class AssertJRules {
static final class AssertThatStreamContainsExactlyInAnyOrder<S, T extends S, U extends T> {
@BeforeTemplate
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, U[] array) {
Stream<S> stream, U[] array, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsExactlyInAnyOrder(array);
}
@BeforeTemplate
AbstractCollectionAssert<?, ?, T, ?> before2(
Stream<S> stream, Collector<S, ?, ? extends Multiset<T>> collector, U[] array) {
Stream<S> stream, U[] array, Collector<S, ?, ? extends Multiset<T>> collector) {
return assertThat(stream.collect(collector)).containsExactlyInAnyOrder(array);
}
@@ -751,7 +751,7 @@ final class AssertJRules {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsExactlyInAnyOrder" /* Varargs converted to array. */)
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector))
.containsExactlyInAnyOrder(Refaster.asVarargs(elements));
}
@@ -759,7 +759,7 @@ final class AssertJRules {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsExactlyInAnyOrder" /* Varargs converted to array. */)
AbstractCollectionAssert<?, ?, T, ?> before2(
Stream<S> stream, Collector<S, ?, ? extends Multiset<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends Multiset<T>> collector) {
return assertThat(stream.collect(collector))
.containsExactlyInAnyOrder(Refaster.asVarargs(elements));
}
@@ -776,13 +776,13 @@ final class AssertJRules {
static final class AssertThatStreamContainsSequence<S, T extends S, U extends T> {
@BeforeTemplate
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsSequence(iterable);
}
@BeforeTemplate
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, U[] iterable) {
Stream<S> stream, U[] iterable, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsSequence(iterable);
}
@@ -798,7 +798,7 @@ final class AssertJRules {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsSequence" /* Varargs converted to array. */)
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsSequence(Refaster.asVarargs(elements));
}
@@ -814,13 +814,13 @@ final class AssertJRules {
static final class AssertThatStreamContainsSubsequence<S, T extends S, U extends T> {
@BeforeTemplate
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsSubsequence(iterable);
}
@BeforeTemplate
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, U[] iterable) {
Stream<S> stream, U[] iterable, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsSubsequence(iterable);
}
@@ -836,7 +836,7 @@ final class AssertJRules {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsSubsequence" /* Varargs converted to array. */)
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector))
.containsSubsequence(Refaster.asVarargs(elements));
}
@@ -853,13 +853,13 @@ final class AssertJRules {
static final class AssertThatStreamDoesNotContainAnyElementsOf<S, T extends S, U extends T> {
@BeforeTemplate
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).doesNotContainAnyElementsOf(iterable);
}
@BeforeTemplate
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).doesNotContainAnyElementsOf(iterable);
}
@@ -874,13 +874,13 @@ final class AssertJRules {
static final class AssertThatStreamDoesNotContain<S, T extends S, U extends T> {
@BeforeTemplate
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, U[] array) {
Stream<S> stream, U[] array, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).doesNotContain(array);
}
@BeforeTemplate
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, U[] array) {
Stream<S> stream, U[] array, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).doesNotContain(array);
}
@@ -896,14 +896,14 @@ final class AssertJRules {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamDoesNotContain" /* Varargs converted to array. */)
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).doesNotContain(Refaster.asVarargs(elements));
}
@BeforeTemplate
@SuppressWarnings("AssertThatStreamDoesNotContain" /* Varargs converted to array. */)
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).doesNotContain(Refaster.asVarargs(elements));
}
@@ -918,13 +918,13 @@ final class AssertJRules {
static final class AssertThatStreamDoesNotContainSequence<S, T extends S, U extends T> {
@BeforeTemplate
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).doesNotContainSequence(iterable);
}
@BeforeTemplate
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, U[] iterable) {
Stream<S> stream, U[] iterable, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).doesNotContainSequence(iterable);
}
@@ -940,7 +940,7 @@ final class AssertJRules {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamDoesNotContainSequence" /* Varargs converted to array. */)
ListAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector))
.doesNotContainSequence(Refaster.asVarargs(elements));
}
@@ -957,13 +957,13 @@ final class AssertJRules {
static final class AssertThatStreamHasSameElementsAs<S, T extends S, U extends T> {
@BeforeTemplate
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).hasSameElementsAs(iterable);
}
@BeforeTemplate
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).hasSameElementsAs(iterable);
}
@@ -978,13 +978,13 @@ final class AssertJRules {
static final class AssertThatStreamContainsOnly<S, T extends S, U extends T> {
@BeforeTemplate
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, U[] array) {
Stream<S> stream, U[] array, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).containsOnly(array);
}
@BeforeTemplate
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, U[] array) {
Stream<S> stream, U[] array, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsOnly(array);
}
@@ -1000,14 +1000,14 @@ final class AssertJRules {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsOnly" /* Varargs converted to array. */)
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).containsOnly(Refaster.asVarargs(elements));
}
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsOnly" /* Varargs converted to array. */)
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).containsOnly(Refaster.asVarargs(elements));
}
@@ -1022,25 +1022,25 @@ final class AssertJRules {
static final class AssertThatStreamIsSubsetOf<S, T extends S, U extends T> {
@BeforeTemplate
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).isSubsetOf(iterable);
}
@BeforeTemplate
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, U[] iterable) {
Stream<S> stream, U[] iterable, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).isSubsetOf(iterable);
}
@BeforeTemplate
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, Iterable<U> iterable) {
Stream<S> stream, Iterable<U> iterable, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).isSubsetOf(iterable);
}
@BeforeTemplate
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, U[] iterable) {
Stream<S> stream, U[] iterable, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).isSubsetOf(iterable);
}
@@ -1056,14 +1056,14 @@ final class AssertJRules {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamIsSubsetOf" /* Varargs converted to array. */)
IterableAssert<T> before(
Stream<S> stream, Collector<S, ?, ? extends Iterable<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends Iterable<T>> collector) {
return assertThat(stream.collect(collector)).isSubsetOf(Refaster.asVarargs(elements));
}
@BeforeTemplate
@SuppressWarnings("AssertThatStreamIsSubsetOf" /* Varargs converted to array. */)
ListAssert<T> before2(
Stream<S> stream, Collector<S, ?, ? extends List<T>> collector, @Repeated U elements) {
Stream<S> stream, @Repeated U elements, Collector<S, ?, ? extends List<T>> collector) {
return assertThat(stream.collect(collector)).isSubsetOf(Refaster.asVarargs(elements));
}

View File

@@ -455,14 +455,14 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownBy {
@BeforeTemplate
AbstractObjectAssert<?, ?> before(
Class<? extends Throwable> exceptionType, ThrowingCallable throwingCallable) {
ThrowingCallable throwingCallable, Class<? extends Throwable> exceptionType) {
return assertThatExceptionOfType(exceptionType).isThrownBy(throwingCallable);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
Class<? extends Throwable> exceptionType, ThrowingCallable throwingCallable) {
ThrowingCallable throwingCallable, Class<? extends Throwable> exceptionType) {
return assertThatThrownBy(throwingCallable).isInstanceOf(exceptionType);
}
}
@@ -471,8 +471,8 @@ final class AssertJThrowingCallableRules {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
String message) {
return assertThatExceptionOfType(exceptionType)
.isThrownBy(throwingCallable)
@@ -482,8 +482,8 @@ final class AssertJThrowingCallableRules {
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
String message) {
return assertThatThrownBy(throwingCallable).isInstanceOf(exceptionType).hasMessage(message);
}
@@ -493,8 +493,8 @@ final class AssertJThrowingCallableRules {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
String message,
@Repeated Object parameters) {
return assertThatExceptionOfType(exceptionType)
@@ -505,8 +505,8 @@ final class AssertJThrowingCallableRules {
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
String message,
@Repeated Object parameters) {
return assertThatThrownBy(throwingCallable)
@@ -519,8 +519,8 @@ final class AssertJThrowingCallableRules {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
String message) {
return assertThatExceptionOfType(exceptionType)
.isThrownBy(throwingCallable)
@@ -530,8 +530,8 @@ final class AssertJThrowingCallableRules {
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(exceptionType)
@@ -543,8 +543,8 @@ final class AssertJThrowingCallableRules {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
String message) {
return assertThatExceptionOfType(exceptionType)
.isThrownBy(throwingCallable)
@@ -554,8 +554,8 @@ final class AssertJThrowingCallableRules {
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(exceptionType)
@@ -567,8 +567,8 @@ final class AssertJThrowingCallableRules {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
String message) {
return assertThatExceptionOfType(exceptionType)
.isThrownBy(throwingCallable)
@@ -578,8 +578,8 @@ final class AssertJThrowingCallableRules {
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(exceptionType)

View File

@@ -7,6 +7,8 @@ import static java.util.Comparator.comparingInt;
import static java.util.Comparator.comparingLong;
import static java.util.Comparator.naturalOrder;
import static java.util.Comparator.reverseOrder;
import static java.util.stream.Collectors.maxBy;
import static java.util.stream.Collectors.minBy;
import com.google.common.collect.Comparators;
import com.google.common.collect.ImmutableList;
@@ -21,11 +23,13 @@ import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.stream.Collector;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.matchers.IsIdentityOperation;
@@ -383,4 +387,36 @@ final class ComparatorRules {
return Comparators::max;
}
}
/**
* Prefer {@link Comparator#naturalOrder()} over {@link Comparator#reverseOrder()} where possible.
*/
static final class MinByNaturalOrder<T extends Comparable<? super T>> {
@BeforeTemplate
Collector<T, ?, Optional<T>> before() {
return maxBy(reverseOrder());
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Collector<T, ?, Optional<T>> after() {
return minBy(naturalOrder());
}
}
/**
* Prefer {@link Comparator#naturalOrder()} over {@link Comparator#reverseOrder()} where possible.
*/
static final class MaxByNaturalOrder<T extends Comparable<? super T>> {
@BeforeTemplate
Collector<T, ?, Optional<T>> before() {
return minBy(reverseOrder());
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Collector<T, ?, Optional<T>> after() {
return maxBy(naturalOrder());
}
}
}

View File

@@ -157,23 +157,13 @@ final class EqualityRules {
}
/** Avoid contrived ways of handling {@code null} values during equality testing. */
static final class EqualsLhsNullable<T, S> {
static final class Equals<T, S> {
@BeforeTemplate
boolean before(T value1, S value2) {
return Optional.ofNullable(value1).equals(Optional.of(value2));
}
@AfterTemplate
boolean after(T value1, S value2) {
return value2.equals(value1);
}
}
/** Avoid contrived ways of handling {@code null} values during equality testing. */
static final class EqualsRhsNullable<T, S> {
@BeforeTemplate
boolean before(T value1, S value2) {
return Optional.of(value1).equals(Optional.ofNullable(value2));
return Refaster.anyOf(
Optional.of(value1).equals(Optional.of(value2)),
Optional.of(value1).equals(Optional.ofNullable(value2)),
Optional.ofNullable(value2).equals(Optional.of(value1)));
}
@AfterTemplate
@@ -183,7 +173,7 @@ final class EqualityRules {
}
/** Avoid contrived ways of handling {@code null} values during equality testing. */
static final class EqualsLhsAndRhsNullable<T, S> {
static final class ObjectsEquals<T, S> {
@BeforeTemplate
boolean before(T value1, S value2) {
return Optional.ofNullable(value1).equals(Optional.ofNullable(value2));

View File

@@ -118,17 +118,17 @@ final class ImmutableListRules {
*/
static final class ImmutableListSortedCopyOfWithCustomComparator<T> {
@BeforeTemplate
ImmutableList<T> before(Iterable<T> iterable, Comparator<T> cmp) {
ImmutableList<T> before(Comparator<T> cmp, Iterable<T> iterable) {
return Streams.stream(iterable).sorted(cmp).collect(toImmutableList());
}
@BeforeTemplate
ImmutableList<T> before(Collection<T> iterable, Comparator<T> cmp) {
ImmutableList<T> before(Comparator<T> cmp, Collection<T> iterable) {
return iterable.stream().sorted(cmp).collect(toImmutableList());
}
@AfterTemplate
ImmutableList<T> after(Collection<T> iterable, Comparator<? super T> cmp) {
ImmutableList<T> after(Comparator<? super T> cmp, Collection<T> iterable) {
return ImmutableList.sortedCopyOf(cmp, iterable);
}
}

View File

@@ -0,0 +1,41 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.io.ByteStreams;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster rules related to expressions dealing with {@link InputStream}s. */
// XXX: Add a rule for `ByteStreams.skipFully(in, n)` -> `in.skipNBytes(n)` once we have a way to
// target JDK 12+ APIs.
@OnlineDocumentation
final class InputStreamRules {
private InputStreamRules() {}
static final class InputStreamTransferTo {
@BeforeTemplate
long before(InputStream in, OutputStream out) throws IOException {
return ByteStreams.copy(in, out);
}
@AfterTemplate
long after(InputStream in, OutputStream out) throws IOException {
return in.transferTo(out);
}
}
static final class InputStreamReadAllBytes {
@BeforeTemplate
byte[] before(InputStream in) throws IOException {
return ByteStreams.toByteArray(in);
}
@AfterTemplate
byte[] after(InputStream in) throws IOException {
return in.readAllBytes();
}
}
}

View File

@@ -16,7 +16,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.DoNotCall;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -44,21 +43,6 @@ import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class JUnitToAssertJRules {
private JUnitToAssertJRules() {}
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(
Assertions.class,
assertDoesNotThrow(() -> null),
assertInstanceOf(null, null),
assertThrows(null, null),
assertThrowsExactly(null, null),
(Runnable) () -> assertFalse(true),
(Runnable) () -> assertNotNull(null),
(Runnable) () -> assertNotSame(null, null),
(Runnable) () -> assertNull(null),
(Runnable) () -> assertSame(null, null),
(Runnable) () -> assertTrue(true));
}
static final class ThrowNewAssertionError {
@BeforeTemplate
void before() {
@@ -78,8 +62,13 @@ final class JUnitToAssertJRules {
return Assertions.fail(message);
}
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)` once
// https://github.com/google/error-prone/pull/3584 is resolved. Until that time, statically
// importing AssertJ's `fail` is likely to clash with an existing static import of JUnit's
// `fail`. Note that combining Error Prone's `RemoveUnusedImports` and
// `UnnecessarilyFullyQualified` checks and our `StaticImport` check will anyway cause the
// method to be imported statically if possible; just in a less efficient manner.
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
T after(String message) {
return fail(message);
}
@@ -91,8 +80,13 @@ final class JUnitToAssertJRules {
return Assertions.fail(message, throwable);
}
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)` once
// https://github.com/google/error-prone/pull/3584 is resolved. Until that time, statically
// importing AssertJ's `fail` is likely to clash with an existing static import of JUnit's
// `fail`. Note that combining Error Prone's `RemoveUnusedImports` and
// `UnnecessarilyFullyQualified` checks and our `StaticImport` check will anyway cause the
// method to be imported statically if possible; just in a less efficient manner.
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
T after(String message, Throwable throwable) {
return fail(message, throwable);
}
@@ -282,26 +276,26 @@ final class JUnitToAssertJRules {
static final class AssertThatWithFailMessageStringIsSameAs {
@BeforeTemplate
void before(Object actual, Object expected, String message) {
void before(Object actual, String message, Object expected) {
assertSame(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected, String message) {
void after(Object actual, String message, Object expected) {
assertThat(actual).withFailMessage(message).isSameAs(expected);
}
}
static final class AssertThatWithFailMessageSupplierIsSameAs {
@BeforeTemplate
void before(Object actual, Object expected, Supplier<String> supplier) {
void before(Object actual, Supplier<String> supplier, Object expected) {
assertSame(expected, actual, supplier);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected, Supplier<String> supplier) {
void after(Object actual, Supplier<String> supplier, Object expected) {
assertThat(actual).withFailMessage(supplier).isSameAs(expected);
}
}
@@ -321,26 +315,26 @@ final class JUnitToAssertJRules {
static final class AssertThatWithFailMessageStringIsNotSameAs {
@BeforeTemplate
void before(Object actual, Object expected, String message) {
void before(Object actual, String message, Object expected) {
assertNotSame(expected, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected, String message) {
void after(Object actual, String message, Object expected) {
assertThat(actual).withFailMessage(message).isNotSameAs(expected);
}
}
static final class AssertThatWithFailMessageSupplierIsNotSameAs {
@BeforeTemplate
void before(Object actual, Object expected, Supplier<String> supplier) {
void before(Object actual, Supplier<String> supplier, Object expected) {
assertNotSame(expected, actual, supplier);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected, Supplier<String> supplier) {
void after(Object actual, Supplier<String> supplier, Object expected) {
assertThat(actual).withFailMessage(supplier).isNotSameAs(expected);
}
}
@@ -361,13 +355,13 @@ final class JUnitToAssertJRules {
static final class AssertThatThrownByWithFailMessageStringIsExactlyInstanceOf<
T extends Throwable> {
@BeforeTemplate
void before(Executable throwingCallable, Class<T> clazz, String message) {
void before(Executable throwingCallable, String message, Class<T> clazz) {
assertThrowsExactly(clazz, throwingCallable, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(ThrowingCallable throwingCallable, Class<T> clazz, String message) {
void after(ThrowingCallable throwingCallable, String message, Class<T> clazz) {
assertThatThrownBy(throwingCallable).withFailMessage(message).isExactlyInstanceOf(clazz);
}
}
@@ -375,13 +369,13 @@ final class JUnitToAssertJRules {
static final class AssertThatThrownByWithFailMessageSupplierIsExactlyInstanceOf<
T extends Throwable> {
@BeforeTemplate
void before(Executable throwingCallable, Class<T> clazz, Supplier<String> supplier) {
void before(Executable throwingCallable, Supplier<String> supplier, Class<T> clazz) {
assertThrowsExactly(clazz, throwingCallable, supplier);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(ThrowingCallable throwingCallable, Class<T> clazz, Supplier<String> supplier) {
void after(ThrowingCallable throwingCallable, Supplier<String> supplier, Class<T> clazz) {
assertThatThrownBy(throwingCallable).withFailMessage(supplier).isExactlyInstanceOf(clazz);
}
}
@@ -401,26 +395,26 @@ final class JUnitToAssertJRules {
static final class AssertThatThrownByWithFailMessageStringIsInstanceOf<T extends Throwable> {
@BeforeTemplate
void before(Executable throwingCallable, Class<T> clazz, String message) {
void before(Executable throwingCallable, String message, Class<T> clazz) {
assertThrows(clazz, throwingCallable, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(ThrowingCallable throwingCallable, Class<T> clazz, String message) {
void after(ThrowingCallable throwingCallable, String message, Class<T> clazz) {
assertThatThrownBy(throwingCallable).withFailMessage(message).isInstanceOf(clazz);
}
}
static final class AssertThatThrownByWithFailMessageSupplierIsInstanceOf<T extends Throwable> {
@BeforeTemplate
void before(Executable throwingCallable, Class<T> clazz, Supplier<String> supplier) {
void before(Executable throwingCallable, Supplier<String> supplier, Class<T> clazz) {
assertThrows(clazz, throwingCallable, supplier);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(ThrowingCallable throwingCallable, Class<T> clazz, Supplier<String> supplier) {
void after(ThrowingCallable throwingCallable, Supplier<String> supplier, Class<T> clazz) {
assertThatThrownBy(throwingCallable).withFailMessage(supplier).isInstanceOf(clazz);
}
}
@@ -494,26 +488,26 @@ final class JUnitToAssertJRules {
static final class AssertThatWithFailMessageStringIsInstanceOf<T> {
@BeforeTemplate
void before(Object actual, Class<T> clazz, String message) {
void before(Object actual, String message, Class<T> clazz) {
assertInstanceOf(clazz, actual, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Class<T> clazz, String message) {
void after(Object actual, String message, Class<T> clazz) {
assertThat(actual).withFailMessage(message).isInstanceOf(clazz);
}
}
static final class AssertThatWithFailMessageSupplierIsInstanceOf<T> {
@BeforeTemplate
void before(Object actual, Class<T> clazz, Supplier<String> supplier) {
void before(Object actual, Supplier<String> supplier, Class<T> clazz) {
assertInstanceOf(clazz, actual, supplier);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Class<T> clazz, Supplier<String> supplier) {
void after(Object actual, Supplier<String> supplier, Class<T> clazz) {
assertThat(actual).withFailMessage(supplier).isInstanceOf(clazz);
}
}

View File

@@ -6,7 +6,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 java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@@ -28,6 +30,21 @@ final class MultimapRules {
}
}
/** Prefer {@link Multimap#isEmpty()} over more contrived alternatives. */
static final class MultimapIsEmpty<K, V> {
@BeforeTemplate
boolean before(Multimap<K, V> multimap) {
return Refaster.anyOf(
multimap.keySet(), multimap.keys(), multimap.values(), multimap.entries())
.isEmpty();
}
@AfterTemplate
boolean after(Multimap<K, V> multimap) {
return multimap.isEmpty();
}
}
/** Prefer {@link Multimap#size()} over more contrived alternatives. */
static final class MultimapSize<K, V> {
@BeforeTemplate
@@ -41,6 +58,32 @@ final class MultimapRules {
}
}
/** Prefer {@link Multimap#containsKey(Object)} over more contrived alternatives. */
static final class MultimapContainsKey<K, V, T> {
@BeforeTemplate
boolean before(Multimap<K, V> multimap, T key) {
return Refaster.anyOf(multimap.keySet(), multimap.keys()).contains(key);
}
@AfterTemplate
boolean after(Multimap<K, V> multimap, T key) {
return multimap.containsKey(key);
}
}
/** Prefer {@link Multimap#containsValue(Object)} over more contrived alternatives. */
static final class MultimapContainsValue<K, V, T> {
@BeforeTemplate
boolean before(Multimap<K, V> multimap, T value) {
return multimap.values().contains(value);
}
@AfterTemplate
boolean after(Multimap<K, V> multimap, T value) {
return multimap.containsValue(value);
}
}
/**
* Prefer {@link Multimap#get(Object)} over more contrived alternatives.
*
@@ -59,4 +102,30 @@ final class MultimapRules {
return multimap.get(key);
}
}
/** Don't unnecessarily use {@link Multimap#entries()}. */
static final class MultimapKeysStream<K, V> {
@BeforeTemplate
Stream<K> before(Multimap<K, V> multimap) {
return multimap.entries().stream().map(Map.Entry::getKey);
}
@AfterTemplate
Stream<K> after(Multimap<K, V> multimap) {
return multimap.keys().stream();
}
}
/** Don't unnecessarily use {@link Multimap#entries()}. */
static final class MultimapValuesStream<K, V> {
@BeforeTemplate
Stream<V> before(Multimap<K, V> multimap) {
return multimap.entries().stream().map(Map.Entry::getValue);
}
@AfterTemplate
Stream<V> after(Multimap<K, V> multimap) {
return multimap.values().stream();
}
}
}

View File

@@ -388,6 +388,7 @@ final class OptionalRules {
@BeforeTemplate
Optional<T> before(Optional<T> optional, Comparator<? super T> comparator) {
return Refaster.anyOf(
optional.or(Refaster.anyOf(() -> Optional.empty(), Optional::empty)),
optional.stream().findFirst(),
optional.stream().findAny(),
optional.stream().min(comparator),

View File

@@ -5,7 +5,11 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.MoreCollectors.toOptional;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Comparator.naturalOrder;
import static java.util.Comparator.reverseOrder;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.maxBy;
import static java.util.stream.Collectors.minBy;
import static java.util.stream.Collectors.toCollection;
import static org.assertj.core.api.Assertions.assertThat;
import static reactor.function.TupleUtils.function;
@@ -41,6 +45,7 @@ import org.jspecify.annotations.Nullable;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.math.MathFlux;
import reactor.test.StepVerifier;
import reactor.test.publisher.PublisherProbe;
import reactor.util.context.Context;
@@ -100,7 +105,7 @@ final class ReactorRules {
}
/** Prefer {@link Mono#justOrEmpty(Object)} over more contrived alternatives. */
static final class MonoJustOrEmptyObject<@Nullable T> {
static final class MonoJustOrEmptyObject<T extends @Nullable Object> {
@BeforeTemplate
Mono<T> before(T value) {
return Mono.justOrEmpty(Optional.ofNullable(value));
@@ -437,10 +442,12 @@ final class ReactorRules {
static final class FluxEmpty<T, S extends Comparable<? super S>> {
@BeforeTemplate
Flux<T> before(
int prefetch,
Function<? super Object[], ? extends T> combinator,
int prefetch,
Comparator<? super T> comparator) {
return Refaster.anyOf(
Flux.zip(combinator),
Flux.zip(combinator, prefetch),
Flux.concat(),
Flux.concatDelayError(),
Flux.firstWithSignal(),
@@ -456,13 +463,11 @@ final class ReactorRules {
Flux.mergePriorityDelayError(prefetch, comparator),
Flux.mergeSequential(),
Flux.mergeSequential(prefetch),
Flux.mergeSequentialDelayError(prefetch),
Flux.zip(combinator),
Flux.zip(combinator, prefetch));
Flux.mergeSequentialDelayError(prefetch));
}
@BeforeTemplate
Flux<T> before(int prefetch, Function<Object[], T> combinator) {
Flux<T> before(Function<Object[], T> combinator, int prefetch) {
return Refaster.anyOf(
Flux.combineLatest(combinator), Flux.combineLatest(combinator, prefetch));
}
@@ -596,6 +601,11 @@ final class ReactorRules {
/** Avoid contrived alternatives to {@link Mono#flatMapIterable(Function)}. */
static final class MonoFlatMapIterable<T, S, I extends Iterable<? extends S>> {
@BeforeTemplate
Flux<S> before(Mono<T> mono, Function<? super T, I> function) {
return mono.map(function).flatMapMany(Flux::fromIterable);
}
@BeforeTemplate
Flux<S> before(
Mono<T> mono,
@@ -608,7 +618,7 @@ final class ReactorRules {
}
@AfterTemplate
Flux<S> after(Mono<T> mono, Function<? super T, ? extends Iterable<? extends S>> function) {
Flux<S> after(Mono<T> mono, Function<? super T, I> function) {
return mono.flatMapIterable(function);
}
}
@@ -727,7 +737,7 @@ final class ReactorRules {
abstract S transformation(@MayOptionallyUse T value);
@BeforeTemplate
Flux<S> before(Flux<T> flux, boolean delayUntilEnd, int maxConcurrency, int prefetch) {
Flux<S> before(Flux<T> flux, int prefetch, boolean delayUntilEnd, int maxConcurrency) {
return Refaster.anyOf(
flux.concatMap(x -> Mono.just(transformation(x))),
flux.concatMap(x -> Flux.just(transformation(x))),
@@ -795,7 +805,7 @@ final class ReactorRules {
@BeforeTemplate
@SuppressWarnings("java:S138" /* Method is long, but not complex. */)
Publisher<S> before(Flux<T> flux, boolean delayUntilEnd, int maxConcurrency, int prefetch) {
Publisher<S> before(Flux<T> flux, int prefetch, boolean delayUntilEnd, int maxConcurrency) {
return Refaster.anyOf(
flux.concatMap(
x ->
@@ -950,11 +960,12 @@ final class ReactorRules {
}
}
/** Avoid vacuous invocations of {@link Mono#ignoreElement()}. */
/** Avoid vacuous operations prior to invocation of {@link Mono#thenMany(Publisher)}. */
static final class MonoThenMany<T, S> {
@BeforeTemplate
Flux<S> before(Mono<T> mono, Publisher<S> publisher) {
return mono.ignoreElement().thenMany(publisher);
return Refaster.anyOf(
mono.ignoreElement().thenMany(publisher), mono.flux().thenMany(publisher));
}
@AfterTemplate
@@ -992,11 +1003,11 @@ final class ReactorRules {
}
}
/** Avoid vacuous invocations of {@link Mono#ignoreElement()}. */
/** Avoid vacuous operations prior to invocation of {@link Mono#then(Mono)}. */
static final class MonoThenMono<T, S> {
@BeforeTemplate
Mono<S> before(Mono<T> mono1, Mono<S> mono2) {
return mono1.ignoreElement().then(mono2);
return Refaster.anyOf(mono1.ignoreElement().then(mono2), mono1.flux().then(mono2));
}
@BeforeTemplate
@@ -1031,12 +1042,15 @@ final class ReactorRules {
/** Prefer {@link Mono#singleOptional()} over more contrived alternatives. */
// XXX: Consider creating a plugin that flags/discourages `Mono<Optional<T>>` method return
// types, just as we discourage nullable `Boolean`s and `Optional`s.
// XXX: The `mono.transform(Mono::singleOptional)` replacement is a special case of a more general
// rule. Consider introducing an Error Prone check for this.
static final class MonoSingleOptional<T> {
@BeforeTemplate
Mono<Optional<T>> before(Mono<T> mono) {
return Refaster.anyOf(
mono.flux().collect(toOptional()),
mono.map(Optional::of).defaultIfEmpty(Optional.empty()));
mono.map(Optional::of).defaultIfEmpty(Optional.empty()),
mono.transform(Mono::singleOptional));
}
@AfterTemplate
@@ -1125,9 +1139,9 @@ final class ReactorRules {
Function<? super S, P> function,
@Matches(IsIdentityOperation.class)
Function<? super P, ? extends Publisher<? extends T>> identityOperation,
int prefetch,
boolean delayUntilEnd,
int maxConcurrency,
int prefetch) {
int maxConcurrency) {
return Refaster.anyOf(
mono.map(function).flatMapMany(identityOperation),
mono.flux().concatMap(function),
@@ -1579,6 +1593,107 @@ final class ReactorRules {
}
}
/** Prefer {@link Flux#sort()} over more verbose alternatives. */
static final class FluxSort<T extends Comparable<? super T>> {
@BeforeTemplate
Flux<T> before(Flux<T> flux) {
return flux.sort(naturalOrder());
}
@AfterTemplate
Flux<T> after(Flux<T> flux) {
return flux.sort();
}
}
/** Prefer {@link MathFlux#min(Publisher)} over less efficient alternatives. */
static final class FluxTransformMin<T extends Comparable<? super T>> {
@BeforeTemplate
Mono<T> before(Flux<T> flux) {
return flux.sort().next();
}
@AfterTemplate
Mono<T> after(Flux<T> flux) {
return flux.transform(MathFlux::min).singleOrEmpty();
}
}
/**
* Prefer {@link MathFlux#min(Publisher, Comparator)} over less efficient or more verbose
* alternatives.
*/
static final class FluxTransformMinWithComparator<T extends Comparable<? super T>> {
@BeforeTemplate
Mono<T> before(Flux<T> flux, Comparator<? super T> cmp) {
return Refaster.anyOf(
flux.sort(cmp).next(), flux.collect(minBy(cmp)).flatMap(Mono::justOrEmpty));
}
@AfterTemplate
Mono<T> after(Flux<T> flux, Comparator<? super T> cmp) {
return flux.transform(f -> MathFlux.min(f, cmp)).singleOrEmpty();
}
}
/** Prefer {@link MathFlux#max(Publisher)} over less efficient alternatives. */
static final class FluxTransformMax<T extends Comparable<? super T>> {
@BeforeTemplate
Mono<T> before(Flux<T> flux) {
return flux.sort().last();
}
@AfterTemplate
Mono<T> after(Flux<T> flux) {
return flux.transform(MathFlux::max).singleOrEmpty();
}
}
/**
* Prefer {@link MathFlux#max(Publisher, Comparator)} over less efficient or more verbose
* alternatives.
*/
static final class FluxTransformMaxWithComparator<T extends Comparable<? super T>> {
@BeforeTemplate
Mono<T> before(Flux<T> flux, Comparator<? super T> cmp) {
return Refaster.anyOf(
flux.sort(cmp).last(), flux.collect(maxBy(cmp)).flatMap(Mono::justOrEmpty));
}
@AfterTemplate
Mono<T> after(Flux<T> flux, Comparator<? super T> cmp) {
return flux.transform(f -> MathFlux.max(f, cmp)).singleOrEmpty();
}
}
/** Prefer {@link MathFlux#min(Publisher)} over more contrived alternatives. */
static final class MathFluxMin<T extends Comparable<? super T>> {
@BeforeTemplate
Mono<T> before(Publisher<T> publisher) {
return Refaster.anyOf(
MathFlux.min(publisher, naturalOrder()), MathFlux.max(publisher, reverseOrder()));
}
@AfterTemplate
Mono<T> after(Publisher<T> publisher) {
return MathFlux.min(publisher);
}
}
/** Prefer {@link MathFlux#max(Publisher)} over more contrived alternatives. */
static final class MathFluxMax<T extends Comparable<? super T>> {
@BeforeTemplate
Mono<T> before(Publisher<T> publisher) {
return Refaster.anyOf(
MathFlux.min(publisher, reverseOrder()), MathFlux.max(publisher, naturalOrder()));
}
@AfterTemplate
Mono<T> after(Publisher<T> publisher) {
return MathFlux.max(publisher);
}
}
/** Prefer {@link reactor.util.context.Context#empty()}} over more verbose alternatives. */
// XXX: Introduce Refaster rules or a `BugChecker` that maps `(Immutable)Map.of(k, v)` to
// `Context.of(k, v)` and likewise for multi-pair overloads.
@@ -1611,7 +1726,7 @@ final class ReactorRules {
static final class StepVerifierFromMono<T> {
@BeforeTemplate
StepVerifier.FirstStep<? extends T> before(Mono<T> mono) {
return StepVerifier.create(mono);
return Refaster.anyOf(StepVerifier.create(mono), mono.flux().as(StepVerifier::create));
}
@AfterTemplate
@@ -1669,7 +1784,7 @@ final class ReactorRules {
// a `@Matches(DoesNotDropElements.class)` or `@NotMatches(MayDropElements.class)` guard.
static final class FluxAsStepVerifierExpectNext<T, L extends List<T>> {
@BeforeTemplate
StepVerifier.Step<L> before(Flux<T> flux, Collector<? super T, ?, L> listCollector, T object) {
StepVerifier.Step<L> before(Flux<T> flux, T object, Collector<? super T, ?, L> listCollector) {
return flux.collect(listCollector)
.as(StepVerifier::create)
.assertNext(list -> assertThat(list).containsExactly(object));

View File

@@ -237,13 +237,13 @@ final class TestNGToAssertJRules {
static final class AssertSameWithMessage {
@BeforeTemplate
void before(Object actual, Object expected, String message) {
void before(Object actual, String message, Object expected) {
assertSame(actual, expected, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected, String message) {
void after(Object actual, String message, Object expected) {
assertThat(actual).withFailMessage(message).isSameAs(expected);
}
}
@@ -263,13 +263,13 @@ final class TestNGToAssertJRules {
static final class AssertNotSameWithMessage {
@BeforeTemplate
void before(Object actual, Object expected, String message) {
void before(Object actual, String message, Object expected) {
assertNotSame(actual, expected, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected, String message) {
void after(Object actual, String message, Object expected) {
assertThat(actual).withFailMessage(message).isNotSameAs(expected);
}
}
@@ -339,63 +339,63 @@ final class TestNGToAssertJRules {
static final class AssertEqualWithMessage {
@BeforeTemplate
void before(boolean actual, boolean expected, String message) {
void before(boolean actual, String message, boolean expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(byte actual, byte expected, String message) {
void before(byte actual, String message, byte expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(char actual, char expected, String message) {
void before(char actual, String message, char expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(short actual, short expected, String message) {
void before(short actual, String message, short expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(int actual, int expected, String message) {
void before(int actual, String message, int expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(long actual, long expected, String message) {
void before(long actual, String message, long expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(float actual, float expected, String message) {
void before(float actual, String message, float expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(double actual, double expected, String message) {
void before(double actual, String message, double expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Object actual, Object expected, String message) {
void before(Object actual, String message, Object expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(String actual, String expected, String message) {
void before(String actual, String message, String expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Map<?, ?> actual, Map<?, ?> expected, String message) {
void before(Map<?, ?> actual, String message, Map<?, ?> expected) {
assertEquals(actual, expected, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected, String message) {
void after(Object actual, String message, Object expected) {
assertThat(actual).withFailMessage(message).isEqualTo(expected);
}
}
@@ -415,13 +415,13 @@ final class TestNGToAssertJRules {
static final class AssertEqualFloatsWithDeltaWithMessage {
@BeforeTemplate
void before(float actual, float expected, float delta, String message) {
void before(float actual, String message, float expected, float delta) {
assertEquals(actual, expected, delta, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float actual, float expected, float delta, String message) {
void after(float actual, String message, float expected, float delta) {
assertThat(actual).withFailMessage(message).isCloseTo(expected, offset(delta));
}
}
@@ -441,13 +441,13 @@ final class TestNGToAssertJRules {
static final class AssertEqualDoublesWithDeltaWithMessage {
@BeforeTemplate
void before(double actual, double expected, double delta, String message) {
void before(double actual, String message, double expected, double delta) {
assertEquals(actual, expected, delta, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double actual, double expected, double delta, String message) {
void after(double actual, String message, double expected, double delta) {
assertThat(actual).withFailMessage(message).isCloseTo(expected, offset(delta));
}
}
@@ -507,53 +507,53 @@ final class TestNGToAssertJRules {
static final class AssertEqualArrayIterationOrderWithMessage {
@BeforeTemplate
void before(boolean[] actual, boolean[] expected, String message) {
void before(boolean[] actual, String message, boolean[] expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(byte[] actual, byte[] expected, String message) {
void before(byte[] actual, String message, byte[] expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(char[] actual, char[] expected, String message) {
void before(char[] actual, String message, char[] expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(short[] actual, short[] expected, String message) {
void before(short[] actual, String message, short[] expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(int[] actual, int[] expected, String message) {
void before(int[] actual, String message, int[] expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(long[] actual, long[] expected, String message) {
void before(long[] actual, String message, long[] expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(float[] actual, float[] expected, String message) {
void before(float[] actual, String message, float[] expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(double[] actual, double[] expected, String message) {
void before(double[] actual, String message, double[] expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Object[] actual, Object[] expected, String message) {
void before(Object[] actual, String message, Object[] expected) {
assertEquals(actual, expected, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object[] actual, Object[] expected, String message) {
void after(Object[] actual, String message, Object[] expected) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
}
@@ -573,13 +573,13 @@ final class TestNGToAssertJRules {
static final class AssertEqualArraysIrrespectiveOfOrderWithMessage {
@BeforeTemplate
void before(Object[] actual, Object[] expected, String message) {
void before(Object[] actual, String message, Object[] expected) {
assertEqualsNoOrder(actual, expected, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object[] actual, Object[] expected, String message) {
void after(Object[] actual, String message, Object[] expected) {
assertThat(actual).withFailMessage(message).containsExactlyInAnyOrder(expected);
}
}
@@ -601,13 +601,13 @@ final class TestNGToAssertJRules {
static final class AssertEqualIteratorIterationOrderWithMessage {
@BeforeTemplate
void before(Iterator<?> actual, Iterator<?> expected, String message) {
void before(Iterator<?> actual, String message, Iterator<?> expected) {
assertEquals(actual, expected, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
<S, T extends S> void after(Iterator<S> actual, Iterator<T> expected, String message) {
<S, T extends S> void after(Iterator<S> actual, String message, Iterator<T> expected) {
// XXX: This is not `null`-safe.
// XXX: The `ImmutableList.copyOf` should actually *not* be imported statically.
assertThat(actual)
@@ -639,18 +639,18 @@ final class TestNGToAssertJRules {
static final class AssertEqualIterableIterationOrderWithMessage {
@BeforeTemplate
void before(Iterable<?> actual, Iterable<?> expected, String message) {
void before(Iterable<?> actual, String message, Iterable<?> expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Collection<?> actual, Collection<?> expected, String message) {
void before(Collection<?> actual, String message, Collection<?> expected) {
assertEquals(actual, expected, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
<S, T extends S> void after(Iterable<S> actual, Iterable<T> expected, String message) {
<S, T extends S> void after(Iterable<S> actual, String message, Iterable<T> expected) {
assertThat(actual).withFailMessage(message).containsExactlyElementsOf(expected);
}
}
@@ -670,13 +670,13 @@ final class TestNGToAssertJRules {
static final class AssertEqualSetsWithMessage {
@BeforeTemplate
void before(Set<?> actual, Set<?> expected, String message) {
void before(Set<?> actual, String message, Set<?> expected) {
assertEquals(actual, expected, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
<S, T extends S> void after(Set<S> actual, Set<T> expected, String message) {
<S, T extends S> void after(Set<S> actual, String message, Set<T> expected) {
assertThat(actual).withFailMessage(message).hasSameElementsAs(expected);
}
}
@@ -751,68 +751,68 @@ final class TestNGToAssertJRules {
static final class AssertUnequalWithMessage {
@BeforeTemplate
void before(boolean actual, boolean expected, String message) {
void before(boolean actual, String message, boolean expected) {
assertNotEquals(actual, expected, message);
}
@BeforeTemplate
void before(byte actual, byte expected, String message) {
void before(byte actual, String message, byte expected) {
assertNotEquals(actual, expected, message);
}
@BeforeTemplate
void before(char actual, char expected, String message) {
void before(char actual, String message, char expected) {
assertNotEquals(actual, expected, message);
}
@BeforeTemplate
void before(short actual, short expected, String message) {
void before(short actual, String message, short expected) {
assertNotEquals(actual, expected, message);
}
@BeforeTemplate
void before(int actual, int expected, String message) {
void before(int actual, String message, int expected) {
assertNotEquals(actual, expected, message);
}
@BeforeTemplate
void before(long actual, long expected, String message) {
void before(long actual, String message, long expected) {
assertNotEquals(actual, expected, message);
}
@BeforeTemplate
void before(float actual, float expected, String message) {
void before(float actual, String message, float expected) {
assertNotEquals(actual, expected, message);
}
@BeforeTemplate
void before(double actual, double expected, String message) {
void before(double actual, String message, double expected) {
assertNotEquals(actual, expected, message);
}
@BeforeTemplate
void before(Object actual, Object expected, String message) {
void before(Object actual, String message, Object expected) {
assertNotEquals(actual, expected, message);
}
@BeforeTemplate
void before(String actual, String expected, String message) {
void before(String actual, String message, String expected) {
assertNotEquals(actual, expected, message);
}
@BeforeTemplate
void before(Set<?> actual, Set<?> expected, String message) {
void before(Set<?> actual, String message, Set<?> expected) {
assertNotEquals(actual, expected, message);
}
@BeforeTemplate
void before(Map<?, ?> actual, Map<?, ?> expected, String message) {
void before(Map<?, ?> actual, String message, Map<?, ?> expected) {
assertNotEquals(actual, expected, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected, String message) {
void after(Object actual, String message, Object expected) {
assertThat(actual).withFailMessage(message).isNotEqualTo(expected);
}
}
@@ -832,13 +832,13 @@ final class TestNGToAssertJRules {
static final class AssertUnequalFloatsWithDeltaWithMessage {
@BeforeTemplate
void before(float actual, float expected, float delta, String message) {
void before(float actual, String message, float expected, float delta) {
assertNotEquals(actual, expected, delta, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float actual, float expected, float delta, String message) {
void after(float actual, String message, float expected, float delta) {
assertThat(actual).withFailMessage(message).isNotCloseTo(expected, offset(delta));
}
}
@@ -858,13 +858,13 @@ final class TestNGToAssertJRules {
static final class AssertUnequalDoublesWithDeltaWithMessage {
@BeforeTemplate
void before(double actual, double expected, double delta, String message) {
void before(double actual, String message, double expected, double delta) {
assertNotEquals(actual, expected, delta, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double actual, double expected, double delta, String message) {
void after(double actual, String message, double expected, double delta) {
assertThat(actual).withFailMessage(message).isNotCloseTo(expected, offset(delta));
}
}

View File

@@ -0,0 +1,82 @@
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 CanonicalClassNameUsageTest {
@Test
void identification() {
CompilationTestHelper.newInstance(CanonicalClassNameUsage.class, getClass())
.setArgs(
"--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED")
.addSourceLines(
"A.java",
"import static com.google.errorprone.matchers.Matchers.instanceMethod;",
"",
"import com.google.errorprone.VisitorState;",
"import tech.picnic.errorprone.utils.MoreTypes;",
"",
"class A {",
" void m(VisitorState state) {",
" String a = A.class.getName();",
" String b = getClass().getName();",
" A.class.getName().toString();",
" System.out.println(A.class.getName());",
" methodInUnnamedPackage(A.class.getName());",
" instanceMethod().onExactClass(A.class.getCanonicalName());",
" MoreTypes.type(A.class.getCanonicalName());",
" MoreTypes.type(A.class.getCanonicalName() + \".SubType\");",
" instanceMethod().onExactClass(new Object() {}.getClass().getName());",
" instanceMethod().onExactClass(methodInUnnamedPackage(A.class.getName()));",
" // BUG: Diagnostic contains:",
" instanceMethod().onExactClass(A.class.getName());",
" // BUG: Diagnostic contains:",
" MoreTypes.type(A.class.getName());",
" // BUG: Diagnostic contains:",
" state.binaryNameFromClassname(A.class.getName() + \".SubType\");",
" }",
"",
" String methodInUnnamedPackage(String str) {",
" return str;",
" }",
"}")
.doTest();
}
@Test
void replacement() {
BugCheckerRefactoringTestHelper.newInstance(CanonicalClassNameUsage.class, getClass())
.addInputLines(
"A.java",
"import static com.google.errorprone.matchers.Matchers.instanceMethod;",
"",
"import com.google.errorprone.BugPattern;",
"import tech.picnic.errorprone.utils.MoreTypes;",
"",
"class A {",
" void m() {",
" instanceMethod().onDescendantOfAny(A.class.getName(), BugPattern.LinkType.class.getName());",
" MoreTypes.type(String.class.getName());",
" }",
"}")
.addOutputLines(
"A.java",
"import static com.google.errorprone.matchers.Matchers.instanceMethod;",
"",
"import com.google.errorprone.BugPattern;",
"import tech.picnic.errorprone.utils.MoreTypes;",
"",
"class A {",
" void m() {",
" instanceMethod()",
" .onDescendantOfAny(",
" A.class.getCanonicalName(), BugPattern.LinkType.class.getCanonicalName());",
" MoreTypes.type(String.class.getCanonicalName());",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -75,6 +75,8 @@ final class ExplicitEnumOrderingTest {
" Ordering.explicit(IsoEra.BCE, SOURCE, RetentionPolicy.CLASS);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, IsoEra.BCE",
" Ordering.explicit(CLASS, RUNTIME, CE);",
"",
" Ordering.explicit(BCE, null, CE);",
" }",
"}")
.doTest();

View File

@@ -65,6 +65,8 @@ final class NonStaticImportTest {
"// BUG: Diagnostic contains:",
"import static java.util.Optional.empty;",
"import static pkg.A.WithMethodThatIsSelectivelyFlagged.list;",
"// BUG: Diagnostic contains:",
"import static reactor.core.publisher.Flux.just;",
"",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableSet;",
@@ -72,7 +74,7 @@ final class NonStaticImportTest {
"import java.time.ZoneOffset;",
"import java.util.Locale;",
"import java.util.Map;",
"import pkg.A.Wrapper.ZERO;",
"import pkg.A.Wrapper.INSTANCE;",
"",
"class A {",
" private Integer MIN_VALUE = 12;",
@@ -90,9 +92,10 @@ final class NonStaticImportTest {
" Locale english = ENGLISH;",
" Locale root = ROOT;",
" empty();",
" just();",
"",
" list();",
" new ZERO();",
" new INSTANCE();",
" }",
"",
" static final class WithMethodThatIsSelectivelyFlagged {",
@@ -102,7 +105,7 @@ final class NonStaticImportTest {
" }",
"",
" static final class Wrapper {",
" static final class ZERO {}",
" static final class INSTANCE {}",
" }",
"}")
.doTest();

View File

@@ -16,6 +16,7 @@ final class RequestMappingAnnotationTest {
"import java.util.Locale;",
"import java.util.TimeZone;",
"import org.springframework.http.HttpMethod;",
"import org.springframework.security.core.annotation.CurrentSecurityContext;",
"import org.springframework.ui.Model;",
"import org.springframework.validation.BindingResult;",
"import org.springframework.web.bind.annotation.DeleteMapping;",
@@ -63,6 +64,10 @@ final class RequestMappingAnnotationTest {
" A properRequestPart(@RequestPart String part);",
"",
" @RequestMapping",
" A properCurrentSecurityContext(",
" @CurrentSecurityContext(expression = \"authentication.name\") String user);",
"",
" @RequestMapping",
" A properInputStream(InputStream input);",
"",
" @RequestMapping",

View File

@@ -40,12 +40,14 @@ final class StaticImportTest {
"import static java.util.function.Predicate.not;",
"import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;",
"",
"import com.fasterxml.jackson.annotation.JsonCreator;",
"import com.google.common.base.Predicates;",
"import com.google.common.collect.ImmutableMap;",
"import com.google.common.collect.ImmutableMultiset;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.errorprone.refaster.ImportPolicy;",
"import com.google.errorprone.refaster.annotation.UseImportPolicy;",
"import com.mongodb.client.model.Filters;",
"import java.nio.charset.StandardCharsets;",
"import java.time.ZoneOffset;",
"import java.util.Optional;",
@@ -98,6 +100,8 @@ final class StaticImportTest {
" // BUG: Diagnostic contains:",
" MediaType t2 = MediaType.APPLICATION_JSON;",
"",
" // BUG: Diagnostic contains:",
" Filters.empty();",
" Optional.empty();",
"",
" // BUG: Diagnostic contains:",
@@ -106,6 +110,12 @@ final class StaticImportTest {
" }",
"",
" // BUG: Diagnostic contains:",
" @JsonCreator(mode = JsonCreator.Mode.DELEGATING)",
" private static A jsonCreator(int a) {",
" return new A();",
" }",
"",
" // BUG: Diagnostic contains:",
" @UseImportPolicy(ImportPolicy.IMPORT_TOP_LEVEL)",
" void refasterAfterTemplate() {}",
"",
@@ -121,6 +131,7 @@ final class StaticImportTest {
"A.java",
"import static java.util.function.Predicate.not;",
"",
"import com.fasterxml.jackson.annotation.JsonCreator;",
"import com.google.common.base.Predicates;",
"import com.google.common.collect.ImmutableMap;",
"import com.google.common.collect.ImmutableSet;",
@@ -177,6 +188,11 @@ final class StaticImportTest {
" @DateTimeFormat(iso = ISO.DATE_TIME) String dateTime,",
" @DateTimeFormat(iso = ISO.TIME) String time) {}",
"",
" @JsonCreator(mode = JsonCreator.Mode.DELEGATING)",
" private static A jsonCreator(int a) {",
" return new A();",
" }",
"",
" @BugPattern(",
" summary = \"\",",
" linkType = BugPattern.LinkType.NONE,",
@@ -189,6 +205,7 @@ final class StaticImportTest {
"}")
.addOutputLines(
"A.java",
"import static com.fasterxml.jackson.annotation.JsonCreator.Mode.DELEGATING;",
"import static com.google.common.collect.ImmutableMap.toImmutableMap;",
"import static com.google.common.collect.ImmutableSet.toImmutableSet;",
"import static com.google.errorprone.BugPattern.LinkType.NONE;",
@@ -208,6 +225,7 @@ final class StaticImportTest {
"import static org.springframework.http.MediaType.APPLICATION_XHTML_XML;",
"import static org.springframework.http.MediaType.TEXT_HTML;",
"",
"import com.fasterxml.jackson.annotation.JsonCreator;",
"import com.google.common.base.Predicates;",
"import com.google.common.collect.ImmutableMap;",
"import com.google.common.collect.ImmutableSet;",
@@ -261,6 +279,11 @@ final class StaticImportTest {
" @DateTimeFormat(iso = DATE_TIME) String dateTime,",
" @DateTimeFormat(iso = TIME) String time) {}",
"",
" @JsonCreator(mode = DELEGATING)",
" private static A jsonCreator(int a) {",
" return new A();",
" }",
"",
" @BugPattern(summary = \"\", linkType = NONE, severity = SUGGESTION, tags = SIMPLIFICATION)",
" static final class TestBugPattern {}",
"",

View File

@@ -42,6 +42,7 @@ final class RefasterRulesTest {
DoubleStreamRules.class,
EqualityRules.class,
FileRules.class,
InputStreamRules.class,
ImmutableListRules.class,
ImmutableListMultimapRules.class,
ImmutableMapRules.class,

View File

@@ -0,0 +1,56 @@
package tech.picnic.errorprone.refasterrules;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.openrewrite.java.Assertions.java;
import com.google.common.io.Resources;
import java.io.IOException;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openrewrite.java.JavaParser;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;
// XXX: This class currently validates the OpenRewrite recipe generation by applying a single
// recipe. Generalize this setup to cover all generated recipes (for _all_ Refaster rule
// collections), ideally by reusing the `RefasterRulesTest` test resources. (This may introduce
// additional hurdles, as OpenRewrite removes obsolete imports, while Refaster doesn't.)
final class StringRulesRecipesTest implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {
spec.recipe(new StringRulesRecipes());
}
@Test
void stringValueOf() {
// XXX: Use text blocks once supported.
rewriteRun(
java(
"import java.util.Objects;\n"
+ '\n'
+ "class Test {\n"
+ " String test(Object object) {\n"
+ " return Objects.toString(object);\n"
+ " }\n"
+ '}',
"class Test {\n"
+ " String test(Object object) {\n"
+ " return String.valueOf(object);\n"
+ " }\n"
+ '}'));
}
@Disabled("Not all rules are currently supported")
@Test
void allRules() throws IOException {
rewriteRun(
spec ->
spec.parser(JavaParser.fromJavaVersion().classpath("guava", "refaster-test-support")),
java(
loadResource("StringRulesTestInput.java"), loadResource("StringRulesTestOutput.java")));
}
private String loadResource(String resource) throws IOException {
return Resources.toString(Resources.getResource(getClass(), resource), UTF_8);
}
}

View File

@@ -3,6 +3,8 @@ package tech.picnic.errorprone.refasterrules;
import static java.util.Comparator.naturalOrder;
import static java.util.Comparator.reverseOrder;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.maxBy;
import static java.util.stream.Collectors.minBy;
import com.google.common.collect.Comparators;
import com.google.common.collect.ImmutableList;
@@ -10,7 +12,9 @@ import com.google.common.collect.ImmutableSet;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.stream.Collector;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
@@ -161,4 +165,12 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
BinaryOperator<String> testComparatorsMax() {
return BinaryOperator.maxBy(naturalOrder());
}
Collector<Integer, ?, Optional<Integer>> testMinByNaturalOrder() {
return maxBy(reverseOrder());
}
Collector<Integer, ?, Optional<Integer>> testMaxByNaturalOrder() {
return minBy(reverseOrder());
}
}

View File

@@ -3,6 +3,8 @@ package tech.picnic.errorprone.refasterrules;
import static java.util.Comparator.naturalOrder;
import static java.util.Comparator.reverseOrder;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.maxBy;
import static java.util.stream.Collectors.minBy;
import com.google.common.collect.Comparators;
import com.google.common.collect.ImmutableList;
@@ -10,7 +12,9 @@ import com.google.common.collect.ImmutableSet;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.stream.Collector;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
@@ -151,4 +155,12 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
BinaryOperator<String> testComparatorsMax() {
return Comparators::max;
}
Collector<Integer, ?, Optional<Integer>> testMinByNaturalOrder() {
return minBy(naturalOrder());
}
Collector<Integer, ?, Optional<Integer>> testMaxByNaturalOrder() {
return maxBy(naturalOrder());
}
}

View File

@@ -69,15 +69,14 @@ final class EqualityRulesTest implements RefasterRuleCollectionTestCase {
return not(v -> v.isEmpty());
}
boolean testEqualsLhsNullable() {
return Optional.ofNullable("foo").equals(Optional.of("bar"));
ImmutableSet<Boolean> testEquals() {
return ImmutableSet.of(
Optional.of("foo").equals(Optional.of("bar")),
Optional.of("baz").equals(Optional.ofNullable("qux")),
Optional.ofNullable("quux").equals(Optional.of("quuz")));
}
boolean testEqualsRhsNullable() {
return Optional.of("foo").equals(Optional.ofNullable("bar"));
}
boolean testEqualsLhsAndRhsNullable() {
boolean testObjectsEquals() {
return Optional.ofNullable("foo").equals(Optional.ofNullable("bar"));
}
}

View File

@@ -69,15 +69,11 @@ final class EqualityRulesTest implements RefasterRuleCollectionTestCase {
return v -> !v.isEmpty();
}
boolean testEqualsLhsNullable() {
return "bar".equals("foo");
ImmutableSet<Boolean> testEquals() {
return ImmutableSet.of("foo".equals("bar"), "baz".equals("qux"), "quuz".equals("quux"));
}
boolean testEqualsRhsNullable() {
return "foo".equals("bar");
}
boolean testEqualsLhsAndRhsNullable() {
boolean testObjectsEquals() {
return Objects.equals("foo", "bar");
}
}

View File

@@ -0,0 +1,23 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.ByteStreams;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class InputStreamRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(ByteStreams.class);
}
long testInputStreamTransferTo() throws IOException {
return ByteStreams.copy(new ByteArrayInputStream(new byte[0]), new ByteArrayOutputStream());
}
byte[] testInputStreamReadAllBytes() throws IOException {
return ByteStreams.toByteArray(new ByteArrayInputStream(new byte[0]));
}
}

View File

@@ -0,0 +1,23 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.ByteStreams;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class InputStreamRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(ByteStreams.class);
}
long testInputStreamTransferTo() throws IOException {
return new ByteArrayInputStream(new byte[0]).transferTo(new ByteArrayOutputStream());
}
byte[] testInputStreamReadAllBytes() throws IOException {
return new ByteArrayInputStream(new byte[0]).readAllBytes();
}
}

View File

@@ -3,7 +3,6 @@ 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.fail;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
@@ -41,11 +40,11 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
}
Object testFailWithMessage() {
return fail("foo");
return org.assertj.core.api.Assertions.fail("foo");
}
Object testFailWithMessageAndThrowable() {
return fail("foo", new IllegalStateException());
return org.assertj.core.api.Assertions.fail("foo", new IllegalStateException());
}
void testFailWithThrowable() {

View File

@@ -5,26 +5,54 @@ import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class MultimapRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(Multimaps.class);
return ImmutableSet.of(Map.class, Multimaps.class);
}
Set<String> testMultimapKeySet() {
return ImmutableSetMultimap.of("foo", "bar").asMap().keySet();
}
ImmutableSet<Boolean> testMultimapIsEmpty() {
return ImmutableSet.of(
ImmutableSetMultimap.of("foo", 1).keySet().isEmpty(),
ImmutableSetMultimap.of("bar", 2).keys().isEmpty(),
ImmutableSetMultimap.of("baz", 3).values().isEmpty(),
ImmutableSetMultimap.of("qux", 54).entries().isEmpty());
}
int testMultimapSize() {
return ImmutableSetMultimap.of().values().size();
}
ImmutableSet<Boolean> testMultimapContainsKey() {
return ImmutableSet.of(
ImmutableSetMultimap.of("foo", 1).keySet().contains("bar"),
ImmutableSetMultimap.of("baz", 1).keys().contains("qux"));
}
boolean testMultimapContainsValue() {
return ImmutableSetMultimap.of("foo", 1).values().contains(2);
}
ImmutableSet<Collection<Integer>> testMultimapGet() {
return ImmutableSet.of(
ImmutableSetMultimap.of(1, 2).asMap().get(1),
Multimaps.asMap((Multimap<Integer, Integer>) ImmutableSetMultimap.of(1, 2)).get(1));
}
Stream<String> testMultimapKeysStream() {
return ImmutableSetMultimap.of("foo", 1).entries().stream().map(Map.Entry::getKey);
}
Stream<Integer> testMultimapValuesStream() {
return ImmutableSetMultimap.of("foo", 1).entries().stream().map(Map.Entry::getValue);
}
}

View File

@@ -5,26 +5,54 @@ import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class MultimapRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(Multimaps.class);
return ImmutableSet.of(Map.class, Multimaps.class);
}
Set<String> testMultimapKeySet() {
return ImmutableSetMultimap.of("foo", "bar").keySet();
}
ImmutableSet<Boolean> testMultimapIsEmpty() {
return ImmutableSet.of(
ImmutableSetMultimap.of("foo", 1).isEmpty(),
ImmutableSetMultimap.of("bar", 2).isEmpty(),
ImmutableSetMultimap.of("baz", 3).isEmpty(),
ImmutableSetMultimap.of("qux", 54).isEmpty());
}
int testMultimapSize() {
return ImmutableSetMultimap.of().size();
}
ImmutableSet<Boolean> testMultimapContainsKey() {
return ImmutableSet.of(
ImmutableSetMultimap.of("foo", 1).containsKey("bar"),
ImmutableSetMultimap.of("baz", 1).containsKey("qux"));
}
boolean testMultimapContainsValue() {
return ImmutableSetMultimap.of("foo", 1).containsValue(2);
}
ImmutableSet<Collection<Integer>> testMultimapGet() {
return ImmutableSet.of(
ImmutableSetMultimap.of(1, 2).get(1),
((Multimap<Integer, Integer>) ImmutableSetMultimap.of(1, 2)).get(1));
}
Stream<String> testMultimapKeysStream() {
return ImmutableSetMultimap.of("foo", 1).keys().stream();
}
Stream<Integer> testMultimapValuesStream() {
return ImmutableSetMultimap.of("foo", 1).values().stream();
}
}

View File

@@ -118,10 +118,12 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
ImmutableSet<Optional<String>> testOptionalIdentity() {
return ImmutableSet.of(
Optional.of("foo").stream().findFirst(),
Optional.of("bar").stream().findAny(),
Optional.of("baz").stream().min(String::compareTo),
Optional.of("qux").stream().max(String::compareTo));
Optional.of("foo").or(() -> Optional.empty()),
Optional.of("bar").or(Optional::empty),
Optional.of("baz").stream().findFirst(),
Optional.of("qux").stream().findAny(),
Optional.of("quux").stream().min(String::compareTo),
Optional.of("quuz").stream().max(String::compareTo));
}
ImmutableSet<Optional<String>> testOptionalFilter() {

View File

@@ -115,7 +115,12 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
ImmutableSet<Optional<String>> testOptionalIdentity() {
return ImmutableSet.of(
Optional.of("foo"), Optional.of("bar"), Optional.of("baz"), Optional.of("qux"));
Optional.of("foo"),
Optional.of("bar"),
Optional.of("baz"),
Optional.of("qux"),
Optional.of("quux"),
Optional.of("quuz"));
}
ImmutableSet<Optional<String>> testOptionalFilter() {

View File

@@ -2,8 +2,11 @@ package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.MoreCollectors.toOptional;
import static java.util.Comparator.naturalOrder;
import static java.util.Comparator.reverseOrder;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.maxBy;
import static java.util.stream.Collectors.minBy;
import static java.util.stream.Collectors.toCollection;
import static org.assertj.core.api.Assertions.assertThat;
@@ -21,6 +24,7 @@ import java.util.concurrent.Callable;
import java.util.function.Supplier;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.math.MathFlux;
import reactor.test.StepVerifier;
import reactor.test.publisher.PublisherProbe;
import reactor.util.context.Context;
@@ -38,6 +42,9 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
ImmutableCollection.class,
ImmutableMap.class,
assertThat(0),
maxBy(null),
minBy(null),
naturalOrder(),
toCollection(null),
toImmutableList(),
toOptional());
@@ -218,10 +225,11 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
ImmutableSet<Flux<Integer>> testMonoFlatMapIterable() {
return ImmutableSet.of(
Mono.just(1).map(ImmutableSet::of).flatMapIterable(identity()),
Mono.just(2).map(ImmutableSet::of).flatMapIterable(v -> v),
Mono.just(3).map(ImmutableSet::of).flatMapIterable(v -> ImmutableSet.of()),
Mono.just(4).flux().concatMapIterable(ImmutableSet::of));
Mono.just(1).map(ImmutableSet::of).flatMapMany(Flux::fromIterable),
Mono.just(2).map(ImmutableSet::of).flatMapIterable(identity()),
Mono.just(3).map(ImmutableSet::of).flatMapIterable(v -> v),
Mono.just(4).map(ImmutableSet::of).flatMapIterable(v -> ImmutableSet.of()),
Mono.just(5).flux().concatMapIterable(ImmutableSet::of));
}
Flux<Integer> testMonoFlatMapIterableIdentity() {
@@ -336,8 +344,10 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return Flux.just("foo").ignoreElements().thenEmpty(Mono.empty());
}
Flux<String> testMonoThenMany() {
return Mono.just("foo").ignoreElement().thenMany(Flux.just("bar"));
ImmutableSet<Flux<String>> testMonoThenMany() {
return ImmutableSet.of(
Mono.just("foo").ignoreElement().thenMany(Flux.just("bar")),
Mono.just("baz").ignoreElement().thenMany(Flux.just("qux")));
}
Flux<String> testMonoThenMonoFlux() {
@@ -351,7 +361,8 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
ImmutableSet<Mono<?>> testMonoThenMono() {
return ImmutableSet.of(
Mono.just("foo").ignoreElement().then(Mono.just("bar")),
Mono.just("baz").thenEmpty(Mono.<Void>empty()));
Mono.just("baz").flux().then(Mono.just("qux")),
Mono.just("quux").thenEmpty(Mono.<Void>empty()));
}
ImmutableSet<Mono<?>> testFluxThenMono() {
@@ -363,7 +374,8 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
ImmutableSet<Mono<Optional<String>>> testMonoSingleOptional() {
return ImmutableSet.of(
Mono.just("foo").flux().collect(toOptional()),
Mono.just("bar").map(Optional::of).defaultIfEmpty(Optional.empty()));
Mono.just("bar").map(Optional::of).defaultIfEmpty(Optional.empty()),
Mono.just("baz").transform(Mono::singleOptional));
}
Mono<Number> testMonoCast() {
@@ -525,6 +537,40 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return Flux.just(1).collect(toImmutableList()).map(ImmutableSet::copyOf);
}
Flux<Integer> testFluxSort() {
return Flux.just(1).sort(naturalOrder());
}
Mono<Integer> testFluxTransformMin() {
return Flux.just(1).sort().next();
}
ImmutableSet<Mono<Integer>> testFluxTransformMinWithComparator() {
return ImmutableSet.of(
Flux.just(1).sort(reverseOrder()).next(),
Flux.just(2).collect(minBy(reverseOrder())).flatMap(Mono::justOrEmpty));
}
Mono<Integer> testFluxTransformMax() {
return Flux.just(1).sort().last();
}
ImmutableSet<Mono<Integer>> testFluxTransformMaxWithComparator() {
return ImmutableSet.of(
Flux.just(1).sort(reverseOrder()).last(),
Flux.just(2).collect(maxBy(reverseOrder())).flatMap(Mono::justOrEmpty));
}
ImmutableSet<Mono<Integer>> testMathFluxMin() {
return ImmutableSet.of(
MathFlux.min(Flux.just(1), naturalOrder()), MathFlux.max(Flux.just(2), reverseOrder()));
}
ImmutableSet<Mono<Integer>> testMathFluxMax() {
return ImmutableSet.of(
MathFlux.min(Flux.just(1), reverseOrder()), MathFlux.max(Flux.just(2), naturalOrder()));
}
ImmutableSet<Context> testContextEmpty() {
return ImmutableSet.of(Context.of(ImmutableMap.of()), Context.of(ImmutableMap.of(1, 2)));
}
@@ -533,8 +579,9 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableSet.of(PublisherProbe.of(Mono.empty()), PublisherProbe.of(Flux.empty()));
}
StepVerifier.FirstStep<Integer> testStepVerifierFromMono() {
return StepVerifier.create(Mono.just(1));
ImmutableSet<StepVerifier.FirstStep<Integer>> testStepVerifierFromMono() {
return ImmutableSet.of(
StepVerifier.create(Mono.just(1)), Mono.just(2).flux().as(StepVerifier::create));
}
StepVerifier.FirstStep<Integer> testStepVerifierFromFlux() {

View File

@@ -3,8 +3,11 @@ package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.MoreCollectors.toOptional;
import static java.util.Comparator.naturalOrder;
import static java.util.Comparator.reverseOrder;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.maxBy;
import static java.util.stream.Collectors.minBy;
import static java.util.stream.Collectors.toCollection;
import static org.assertj.core.api.Assertions.assertThat;
import static reactor.function.TupleUtils.function;
@@ -24,6 +27,7 @@ import java.util.function.Supplier;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.function.TupleUtils;
import reactor.math.MathFlux;
import reactor.test.StepVerifier;
import reactor.test.publisher.PublisherProbe;
import reactor.util.context.Context;
@@ -41,6 +45,9 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
ImmutableCollection.class,
ImmutableMap.class,
assertThat(0),
maxBy(null),
minBy(null),
naturalOrder(),
toCollection(null),
toImmutableList(),
toOptional());
@@ -223,8 +230,9 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableSet.of(
Mono.just(1).flatMapIterable(ImmutableSet::of),
Mono.just(2).flatMapIterable(ImmutableSet::of),
Mono.just(3).map(ImmutableSet::of).flatMapIterable(v -> ImmutableSet.of()),
Mono.just(4).flatMapIterable(ImmutableSet::of));
Mono.just(3).flatMapIterable(ImmutableSet::of),
Mono.just(4).map(ImmutableSet::of).flatMapIterable(v -> ImmutableSet.of()),
Mono.just(5).flatMapIterable(ImmutableSet::of));
}
Flux<Integer> testMonoFlatMapIterableIdentity() {
@@ -333,8 +341,9 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return Flux.just("foo").thenEmpty(Mono.empty());
}
Flux<String> testMonoThenMany() {
return Mono.just("foo").thenMany(Flux.just("bar"));
ImmutableSet<Flux<String>> testMonoThenMany() {
return ImmutableSet.of(
Mono.just("foo").thenMany(Flux.just("bar")), Mono.just("baz").thenMany(Flux.just("qux")));
}
Flux<String> testMonoThenMonoFlux() {
@@ -347,7 +356,9 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
ImmutableSet<Mono<?>> testMonoThenMono() {
return ImmutableSet.of(
Mono.just("foo").then(Mono.just("bar")), Mono.just("baz").then(Mono.<Void>empty()));
Mono.just("foo").then(Mono.just("bar")),
Mono.just("baz").then(Mono.just("qux")),
Mono.just("quux").then(Mono.<Void>empty()));
}
ImmutableSet<Mono<?>> testFluxThenMono() {
@@ -356,7 +367,10 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
}
ImmutableSet<Mono<Optional<String>>> testMonoSingleOptional() {
return ImmutableSet.of(Mono.just("foo").singleOptional(), Mono.just("bar").singleOptional());
return ImmutableSet.of(
Mono.just("foo").singleOptional(),
Mono.just("bar").singleOptional(),
Mono.just("baz").singleOptional());
}
Mono<Number> testMonoCast() {
@@ -514,6 +528,38 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return Flux.just(1).collect(toImmutableSet());
}
Flux<Integer> testFluxSort() {
return Flux.just(1).sort();
}
Mono<Integer> testFluxTransformMin() {
return Flux.just(1).transform(MathFlux::min).singleOrEmpty();
}
ImmutableSet<Mono<Integer>> testFluxTransformMinWithComparator() {
return ImmutableSet.of(
Flux.just(1).transform(f -> MathFlux.min(f, reverseOrder())).singleOrEmpty(),
Flux.just(2).transform(f -> MathFlux.min(f, reverseOrder())).singleOrEmpty());
}
Mono<Integer> testFluxTransformMax() {
return Flux.just(1).transform(MathFlux::max).singleOrEmpty();
}
ImmutableSet<Mono<Integer>> testFluxTransformMaxWithComparator() {
return ImmutableSet.of(
Flux.just(1).transform(f -> MathFlux.max(f, reverseOrder())).singleOrEmpty(),
Flux.just(2).transform(f -> MathFlux.max(f, reverseOrder())).singleOrEmpty());
}
ImmutableSet<Mono<Integer>> testMathFluxMin() {
return ImmutableSet.of(MathFlux.min(Flux.just(1)), MathFlux.min(Flux.just(2)));
}
ImmutableSet<Mono<Integer>> testMathFluxMax() {
return ImmutableSet.of(MathFlux.max(Flux.just(1)), MathFlux.max(Flux.just(2)));
}
ImmutableSet<Context> testContextEmpty() {
return ImmutableSet.of(Context.empty(), Context.of(ImmutableMap.of(1, 2)));
}
@@ -522,8 +568,9 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableSet.of(PublisherProbe.empty(), PublisherProbe.empty());
}
StepVerifier.FirstStep<Integer> testStepVerifierFromMono() {
return Mono.just(1).as(StepVerifier::create);
ImmutableSet<StepVerifier.FirstStep<Integer>> testStepVerifierFromMono() {
return ImmutableSet.of(
Mono.just(1).as(StepVerifier::create), Mono.just(2).as(StepVerifier::create));
}
StepVerifier.FirstStep<Integer> testStepVerifierFromFlux() {

View File

@@ -17,6 +17,8 @@ import java.time.temporal.ChronoUnit;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class TimeRulesTest implements RefasterRuleCollectionTestCase {
private static final ZonedDateTime ZONED_DATE_TIME = Instant.EPOCH.atZone(ZoneOffset.UTC);
@Override
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(ChronoUnit.class);
@@ -220,4 +222,385 @@ final class TimeRulesTest implements RefasterRuleCollectionTestCase {
Period.ofYears(0),
Period.of(0, 0, 0));
}
ImmutableSet<LocalDate> testLocalDatePlusDays() {
return ImmutableSet.of(
LocalDate.EPOCH.plus(1L, ChronoUnit.DAYS), LocalDate.EPOCH.plus(Period.ofDays(1)));
}
ImmutableSet<LocalDate> testLocalDatePlusWeeks() {
return ImmutableSet.of(
LocalDate.EPOCH.plus(1L, ChronoUnit.WEEKS), LocalDate.EPOCH.plus(Period.ofWeeks(1)));
}
ImmutableSet<LocalDate> testLocalDatePlusMonths() {
return ImmutableSet.of(
LocalDate.EPOCH.plus(1L, ChronoUnit.MONTHS), LocalDate.EPOCH.plus(Period.ofMonths(1)));
}
ImmutableSet<LocalDate> testLocalDatePlusYears() {
return ImmutableSet.of(
LocalDate.EPOCH.plus(1L, ChronoUnit.YEARS), LocalDate.EPOCH.plus(Period.ofYears(1)));
}
ImmutableSet<LocalDate> testLocalDateMinusDays() {
return ImmutableSet.of(
LocalDate.EPOCH.minus(1L, ChronoUnit.DAYS), LocalDate.EPOCH.minus(Period.ofDays(1)));
}
ImmutableSet<LocalDate> testLocalDateMinusWeeks() {
return ImmutableSet.of(
LocalDate.EPOCH.minus(1L, ChronoUnit.WEEKS), LocalDate.EPOCH.minus(Period.ofWeeks(1)));
}
ImmutableSet<LocalDate> testLocalDateMinusMonths() {
return ImmutableSet.of(
LocalDate.EPOCH.minus(1L, ChronoUnit.MONTHS), LocalDate.EPOCH.minus(Period.ofMonths(1)));
}
ImmutableSet<LocalDate> testLocalDateMinusYears() {
return ImmutableSet.of(
LocalDate.EPOCH.minus(1L, ChronoUnit.YEARS), LocalDate.EPOCH.minus(Period.ofYears(1)));
}
ImmutableSet<LocalTime> testLocalTimePlusNanos() {
return ImmutableSet.of(
LocalTime.NOON.plus(1L, ChronoUnit.NANOS), LocalTime.NOON.plus(Duration.ofNanos(1)));
}
ImmutableSet<LocalTime> testLocalTimePlusSeconds() {
return ImmutableSet.of(
LocalTime.NOON.plus(1L, ChronoUnit.SECONDS), LocalTime.NOON.plus(Duration.ofSeconds(1)));
}
ImmutableSet<LocalTime> testLocalTimePlusMinutes() {
return ImmutableSet.of(
LocalTime.NOON.plus(1L, ChronoUnit.MINUTES), LocalTime.NOON.plus(Duration.ofMinutes(1)));
}
ImmutableSet<LocalTime> testLocalTimePlusHours() {
return ImmutableSet.of(
LocalTime.NOON.plus(1L, ChronoUnit.HOURS), LocalTime.NOON.plus(Duration.ofHours(1)));
}
ImmutableSet<LocalTime> testLocalTimeMinusNanos() {
return ImmutableSet.of(
LocalTime.NOON.minus(1L, ChronoUnit.NANOS), LocalTime.NOON.minus(Duration.ofNanos(1)));
}
ImmutableSet<LocalTime> testLocalTimeMinusSeconds() {
return ImmutableSet.of(
LocalTime.NOON.minus(1L, ChronoUnit.SECONDS), LocalTime.NOON.minus(Duration.ofSeconds(1)));
}
ImmutableSet<LocalTime> testLocalTimeMinusMinutes() {
return ImmutableSet.of(
LocalTime.NOON.minus(1L, ChronoUnit.MINUTES), LocalTime.NOON.minus(Duration.ofMinutes(1)));
}
ImmutableSet<LocalTime> testLocalTimeMinusHours() {
return ImmutableSet.of(
LocalTime.NOON.minus(1L, ChronoUnit.HOURS), LocalTime.NOON.minus(Duration.ofHours(1)));
}
ImmutableSet<OffsetTime> testOffsetTimePlusNanos() {
return ImmutableSet.of(
OffsetTime.MIN.plus(1L, ChronoUnit.NANOS), OffsetTime.MIN.plus(Duration.ofNanos(1)));
}
ImmutableSet<OffsetTime> testOffsetTimePlusSeconds() {
return ImmutableSet.of(
OffsetTime.MIN.plus(1L, ChronoUnit.SECONDS), OffsetTime.MIN.plus(Duration.ofSeconds(1)));
}
ImmutableSet<OffsetTime> testOffsetTimePlusMinutes() {
return ImmutableSet.of(
OffsetTime.MIN.plus(1L, ChronoUnit.MINUTES), OffsetTime.MIN.plus(Duration.ofMinutes(1)));
}
ImmutableSet<OffsetTime> testOffsetTimePlusHours() {
return ImmutableSet.of(
OffsetTime.MIN.plus(1L, ChronoUnit.HOURS), OffsetTime.MIN.plus(Duration.ofHours(1)));
}
ImmutableSet<OffsetTime> testOffsetTimeMinusNanos() {
return ImmutableSet.of(
OffsetTime.MAX.minus(1L, ChronoUnit.NANOS), OffsetTime.MAX.minus(Duration.ofNanos(1)));
}
ImmutableSet<OffsetTime> testOffsetTimeMinusSeconds() {
return ImmutableSet.of(
OffsetTime.MAX.minus(1L, ChronoUnit.SECONDS), OffsetTime.MAX.minus(Duration.ofSeconds(1)));
}
ImmutableSet<OffsetTime> testOffsetTimeMinusMinutes() {
return ImmutableSet.of(
OffsetTime.MAX.minus(1L, ChronoUnit.MINUTES), OffsetTime.MAX.minus(Duration.ofMinutes(1)));
}
ImmutableSet<OffsetTime> testOffsetTimeMinusHours() {
return ImmutableSet.of(
OffsetTime.MAX.minus(1L, ChronoUnit.HOURS), OffsetTime.MAX.minus(Duration.ofHours(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimePlusNanos() {
return ImmutableSet.of(
LocalDateTime.MIN.plus(1L, ChronoUnit.NANOS), LocalDateTime.MIN.plus(Duration.ofNanos(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimePlusSeconds() {
return ImmutableSet.of(
LocalDateTime.MIN.plus(1L, ChronoUnit.SECONDS),
LocalDateTime.MIN.plus(Duration.ofSeconds(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimePlusMinutes() {
return ImmutableSet.of(
LocalDateTime.MIN.plus(1L, ChronoUnit.MINUTES),
LocalDateTime.MIN.plus(Duration.ofMinutes(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimePlusHours() {
return ImmutableSet.of(
LocalDateTime.MIN.plus(1L, ChronoUnit.HOURS), LocalDateTime.MIN.plus(Duration.ofHours(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimePlusDays() {
return ImmutableSet.of(
LocalDateTime.MIN.plus(1L, ChronoUnit.DAYS), LocalDateTime.MIN.plus(Period.ofDays(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimePlusWeeks() {
return ImmutableSet.of(
LocalDateTime.MIN.plus(1L, ChronoUnit.WEEKS), LocalDateTime.MIN.plus(Period.ofWeeks(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimePlusMonths() {
return ImmutableSet.of(
LocalDateTime.MIN.plus(1L, ChronoUnit.MONTHS), LocalDateTime.MIN.plus(Period.ofMonths(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimePlusYears() {
return ImmutableSet.of(
LocalDateTime.MIN.plus(1L, ChronoUnit.YEARS), LocalDateTime.MIN.plus(Period.ofYears(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimeMinusNanos() {
return ImmutableSet.of(
LocalDateTime.MAX.minus(1L, ChronoUnit.NANOS),
LocalDateTime.MAX.minus(Duration.ofNanos(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimeMinusSeconds() {
return ImmutableSet.of(
LocalDateTime.MAX.minus(1L, ChronoUnit.SECONDS),
LocalDateTime.MAX.minus(Duration.ofSeconds(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimeMinusMinutes() {
return ImmutableSet.of(
LocalDateTime.MAX.minus(1L, ChronoUnit.MINUTES),
LocalDateTime.MAX.minus(Duration.ofMinutes(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimeMinusHours() {
return ImmutableSet.of(
LocalDateTime.MAX.minus(1L, ChronoUnit.HOURS),
LocalDateTime.MAX.minus(Duration.ofHours(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimeMinusDays() {
return ImmutableSet.of(
LocalDateTime.MAX.minus(1L, ChronoUnit.DAYS), LocalDateTime.MAX.minus(Period.ofDays(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimeMinusWeeks() {
return ImmutableSet.of(
LocalDateTime.MAX.minus(1L, ChronoUnit.WEEKS), LocalDateTime.MAX.minus(Period.ofWeeks(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimeMinusMonths() {
return ImmutableSet.of(
LocalDateTime.MAX.minus(1L, ChronoUnit.MONTHS),
LocalDateTime.MAX.minus(Period.ofMonths(1)));
}
ImmutableSet<LocalDateTime> testLocalDateTimeMinusYears() {
return ImmutableSet.of(
LocalDateTime.MAX.minus(1L, ChronoUnit.YEARS), LocalDateTime.MAX.minus(Period.ofYears(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimePlusNanos() {
return ImmutableSet.of(
OffsetDateTime.MIN.plus(1L, ChronoUnit.NANOS),
OffsetDateTime.MIN.plus(Duration.ofNanos(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimePlusSeconds() {
return ImmutableSet.of(
OffsetDateTime.MIN.plus(1L, ChronoUnit.SECONDS),
OffsetDateTime.MIN.plus(Duration.ofSeconds(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimePlusMinutes() {
return ImmutableSet.of(
OffsetDateTime.MIN.plus(1L, ChronoUnit.MINUTES),
OffsetDateTime.MIN.plus(Duration.ofMinutes(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimePlusHours() {
return ImmutableSet.of(
OffsetDateTime.MIN.plus(1L, ChronoUnit.HOURS),
OffsetDateTime.MIN.plus(Duration.ofHours(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimePlusDays() {
return ImmutableSet.of(
OffsetDateTime.MIN.plus(1L, ChronoUnit.DAYS), OffsetDateTime.MIN.plus(Period.ofDays(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimePlusWeeks() {
return ImmutableSet.of(
OffsetDateTime.MIN.plus(1L, ChronoUnit.WEEKS), OffsetDateTime.MIN.plus(Period.ofWeeks(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimePlusMonths() {
return ImmutableSet.of(
OffsetDateTime.MIN.plus(1L, ChronoUnit.MONTHS),
OffsetDateTime.MIN.plus(Period.ofMonths(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimePlusYears() {
return ImmutableSet.of(
OffsetDateTime.MIN.plus(1L, ChronoUnit.YEARS), OffsetDateTime.MIN.plus(Period.ofYears(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimeMinusNanos() {
return ImmutableSet.of(
OffsetDateTime.MAX.minus(1L, ChronoUnit.NANOS),
OffsetDateTime.MAX.minus(Duration.ofNanos(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimeMinusSeconds() {
return ImmutableSet.of(
OffsetDateTime.MAX.minus(1L, ChronoUnit.SECONDS),
OffsetDateTime.MAX.minus(Duration.ofSeconds(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimeMinusMinutes() {
return ImmutableSet.of(
OffsetDateTime.MAX.minus(1L, ChronoUnit.MINUTES),
OffsetDateTime.MAX.minus(Duration.ofMinutes(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimeMinusHours() {
return ImmutableSet.of(
OffsetDateTime.MAX.minus(1L, ChronoUnit.HOURS),
OffsetDateTime.MAX.minus(Duration.ofHours(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimeMinusDays() {
return ImmutableSet.of(
OffsetDateTime.MAX.minus(1L, ChronoUnit.DAYS), OffsetDateTime.MAX.minus(Period.ofDays(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimeMinusWeeks() {
return ImmutableSet.of(
OffsetDateTime.MAX.minus(1L, ChronoUnit.WEEKS),
OffsetDateTime.MAX.minus(Period.ofWeeks(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimeMinusMonths() {
return ImmutableSet.of(
OffsetDateTime.MAX.minus(1L, ChronoUnit.MONTHS),
OffsetDateTime.MAX.minus(Period.ofMonths(1)));
}
ImmutableSet<OffsetDateTime> testOffsetDateTimeMinusYears() {
return ImmutableSet.of(
OffsetDateTime.MAX.minus(1L, ChronoUnit.YEARS),
OffsetDateTime.MAX.minus(Period.ofYears(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimePlusNanos() {
return ImmutableSet.of(
ZONED_DATE_TIME.plus(1L, ChronoUnit.NANOS), ZONED_DATE_TIME.plus(Duration.ofNanos(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimePlusSeconds() {
return ImmutableSet.of(
ZONED_DATE_TIME.plus(1L, ChronoUnit.SECONDS), ZONED_DATE_TIME.plus(Duration.ofSeconds(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimePlusMinutes() {
return ImmutableSet.of(
ZONED_DATE_TIME.plus(1L, ChronoUnit.MINUTES), ZONED_DATE_TIME.plus(Duration.ofMinutes(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimePlusHours() {
return ImmutableSet.of(
ZONED_DATE_TIME.plus(1L, ChronoUnit.HOURS), ZONED_DATE_TIME.plus(Duration.ofHours(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimePlusDays() {
return ImmutableSet.of(
ZONED_DATE_TIME.plus(1L, ChronoUnit.DAYS), ZONED_DATE_TIME.plus(Period.ofDays(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimePlusWeeks() {
return ImmutableSet.of(
ZONED_DATE_TIME.plus(1L, ChronoUnit.WEEKS), ZONED_DATE_TIME.plus(Period.ofWeeks(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimePlusMonths() {
return ImmutableSet.of(
ZONED_DATE_TIME.plus(1L, ChronoUnit.MONTHS), ZONED_DATE_TIME.plus(Period.ofMonths(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimePlusYears() {
return ImmutableSet.of(
ZONED_DATE_TIME.plus(1L, ChronoUnit.YEARS), ZONED_DATE_TIME.plus(Period.ofYears(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimeMinusNanos() {
return ImmutableSet.of(
ZONED_DATE_TIME.minus(1L, ChronoUnit.NANOS), ZONED_DATE_TIME.minus(Duration.ofNanos(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimeMinusSeconds() {
return ImmutableSet.of(
ZONED_DATE_TIME.minus(1L, ChronoUnit.SECONDS),
ZONED_DATE_TIME.minus(Duration.ofSeconds(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimeMinusMinutes() {
return ImmutableSet.of(
ZONED_DATE_TIME.minus(1L, ChronoUnit.MINUTES),
ZONED_DATE_TIME.minus(Duration.ofMinutes(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimeMinusHours() {
return ImmutableSet.of(
ZONED_DATE_TIME.minus(1L, ChronoUnit.HOURS), ZONED_DATE_TIME.minus(Duration.ofHours(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimeMinusDays() {
return ImmutableSet.of(
ZONED_DATE_TIME.minus(1L, ChronoUnit.DAYS), ZONED_DATE_TIME.minus(Period.ofDays(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimeMinusWeeks() {
return ImmutableSet.of(
ZONED_DATE_TIME.minus(1L, ChronoUnit.WEEKS), ZONED_DATE_TIME.minus(Period.ofWeeks(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimeMinusMonths() {
return ImmutableSet.of(
ZONED_DATE_TIME.minus(1L, ChronoUnit.MONTHS), ZONED_DATE_TIME.minus(Period.ofMonths(1)));
}
ImmutableSet<ZonedDateTime> testZonedDateTimeMinusYears() {
return ImmutableSet.of(
ZONED_DATE_TIME.minus(1L, ChronoUnit.YEARS), ZONED_DATE_TIME.minus(Period.ofYears(1)));
}
}

Some files were not shown because too many files have changed in this diff Show More