Compare commits

..

379 Commits

Author SHA1 Message Date
Stephan Schroevers
cffff17c28 WIP: Matching fails, not sure why 2024-02-10 16:30:20 +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
Picnic-Bot
f0ff5c3fd6 Upgrade dawidd6/action-download-artifact v2.28.0 -> v2.28.1 (#917)
See:
- https://github.com/dawidd6/action-download-artifact/compare/v2.28.0...v2.28.1
2023-12-13 08:57:00 +01:00
Picnic-Bot
738a6706fd Upgrade Checker Framework Annotations 3.40.0 -> 3.41.0 (#907)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.41.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.40.0...checker-framework-3.41.0
2023-12-12 08:16:29 +01:00
Picnic-Bot
fd97ac3676 Upgrade actions/deploy-pages v3.0.0 -> v3.0.1 (#912)
See:
- https://github.com/actions/deploy-pages/releases/tag/v3.0.1
2023-12-12 08:05:08 +01:00
Picnic-Bot
5b011312e1 Upgrade errorprone-slf4j 0.1.20 -> 0.1.21 (#913)
See:
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.21
- https://github.com/KengoTODA/errorprone-slf4j/compare/v0.1.20...v0.1.21
2023-12-11 21:42:20 +01:00
Picnic-Bot
ff3f963820 Upgrade actions/deploy-pages v2.0.5 -> v3.0.0 (#909)
See:
- https://github.com/actions/deploy-pages/releases/tag/v3.0.0
2023-12-06 09:36:11 +01:00
Picnic-Bot
94edab3b4f Upgrade actions/configure-pages v3.0.7 -> v4.0.0 (#908)
See:
- https://github.com/actions/configure-pages/releases/tag/v4.0.0
2023-12-06 09:15:36 +01:00
Picnic-Bot
276529fd34 Upgrade actions/configure-pages v3.0.6 -> v3.0.7 (#906)
See:
- https://github.com/actions/configure-pages/releases/tag/v3.0.7
2023-12-06 09:05:12 +01:00
Picnic-Bot
f5022efe68 Upgrade actions/deploy-pages v2.0.4 -> v2.0.5 (#901)
See:
- https://github.com/actions/deploy-pages/releases/tag/v2.0.5
2023-12-05 18:25:46 +01:00
Picnic-Bot
49e7313e1c Upgrade maven-javadoc-plugin 3.6.2 -> 3.6.3 (#904)
See:
- https://github.com/apache/maven-javadoc-plugin/releases/tag/maven-javadoc-plugin-3.6.3
- https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.2...maven-javadoc-plugin-3.6.3
2023-12-04 08:57:52 +01:00
Picnic-Bot
b3462b0a1e Upgrade ruby/setup-ruby v1.159.0 -> v1.161.0 (#905)
See:
- https://github.com/ruby/setup-ruby/releases/tag/v1.161.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.160.0
2023-12-04 08:27:55 +01:00
Picnic-Bot
a5b71410ae Upgrade actions/setup-java v3.13.0 -> v4.0.0 (#899)
See:
- https://github.com/actions/setup-java/releases/tag/v4.0.0
2023-12-04 07:41:00 +01:00
Picnic-Bot
6b73f03b22 Upgrade CodeQL v2.22.5 -> v2.22.8 (#903)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.22.5...v2.22.8
2023-12-04 07:18:13 +01:00
Picnic-Bot
5d120252ac Upgrade Mockito 5.7.0 -> 5.8.0 (#902)
See:
- https://github.com/mockito/mockito/releases/tag/v5.8.0
- https://github.com/mockito/mockito/compare/v5.7.0...v5.8.0
2023-12-03 19:40:39 +01:00
Picnic-Bot
351b886e6c Upgrade NullAway 0.10.17 -> 0.10.18 (#900)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.10.18
- https://github.com/uber/NullAway/compare/v0.10.17...v0.10.18
2023-12-01 08:42:19 +01:00
Picnic-Bot
ad5dd92b9a Upgrade Pitest Git plugins 1.1.3 -> 1.1.4 (#898) 2023-11-30 18:59:39 +01:00
Rick Ossendrijver
e9a5295e80 Reference conference talk in README (#877)
While there, fix some URLs broken by eafb73814a.
2023-11-30 12:50:42 +01:00
Picnic-Bot
7ae9356c9e Upgrade Pitest Git plugins 1.1.2 -> 1.1.3 (#897) 2023-11-28 08:58:20 +01:00
Stephan Schroevers
5618de49f4 Introduce ConstantsFormat Refaster rule (#883) 2023-11-27 13:12:17 +01:00
Stephan Schroevers
17c7b396d2 Simplify AbstractMatcherTestChecker (#853)
By using `TreePathScanner` rather than directly using `TreeScanner`.
2023-11-27 11:40:16 +01:00
Stephan Schroevers
eafb73814a Apply assorted build improvements (#866)
Summary of changes:
- Consistently use `.yml` instead of `.yaml`.
- Don't install SNAPSHOT artifacts during the CodeQL build, so that
  they don't end up in the Maven cache.
- Sync a bunch of `pom.xml` changes from our internal Maven parent.
2023-11-27 11:16:48 +01:00
Picnic-Bot
7793006b5e Upgrade Spring Boot 2.7.17 -> 2.7.18 (#895)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.18
- https://github.com/spring-projects/spring-boot/compare/v2.7.17...v2.7.18
2023-11-26 15:51:44 +01:00
Picnic-Bot
7733ceaaec Upgrade build-helper-maven-plugin 3.4.0 -> 3.5.0 (#896)
See:
- https://github.com/mojohaus/build-helper-maven-plugin/releases/tag/3.5.0
- https://github.com/mojohaus/build-helper-maven-plugin/compare/3.4.0...3.5.0
2023-11-26 15:06:23 +01:00
Picnic-Bot
53e0a0cb41 Upgrade Project Reactor 2022.0.13 -> 2023.0.0 (#887)
See:
- https://github.com/reactor/reactor/releases/tag/2023.0.0-M1
- https://github.com/reactor/reactor/releases/tag/2023.0.0-M2
- https://github.com/reactor/reactor/releases/tag/2023.0.0-M3
- https://github.com/reactor/reactor/releases/tag/2023.0.0-RC1
- https://github.com/reactor/reactor/releases/tag/2023.0.0
- https://github.com/reactor/reactor/compare/2022.0.13...2023.0.0
2023-11-24 08:10:02 +01:00
Picnic-Bot
1d25b78c4c Upgrade Jackson 2.15.3 -> 2.16.0 (#889)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.16
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.15.3...jackson-bom-2.16.0
2023-11-23 10:58:24 +01:00
Picnic-Bot
b70da48d70 Upgrade MongoDB driver 4.11.0 -> 4.11.1 (#878)
See:
- https://jira.mongodb.org/issues/?jql=project%20%3D%20JAVA%20AND%20fixVersion%20%3E%204.11.0%20AND%20fixVersion%20%3C%3D%204.11.1
- https://github.com/mongodb/mongo-java-driver/releases/tag/r4.11.1
- https://github.com/mongodb/mongo-java-driver/compare/r4.11.0...r4.11.1
2023-11-22 12:44:57 +01:00
Picnic-Bot
01fd608aac Upgrade Checkstyle 10.12.4 -> 10.12.5 (#885)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.12.5
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.12.4...checkstyle-10.12.5
2023-11-22 09:19:45 +01:00
Picnic-Bot
dd0369a645 Upgrade Project Reactor 2022.0.12 -> 2022.0.13 (#886)
See:
- https://github.com/reactor/reactor/releases/tag/2022.0.13
- https://github.com/reactor/reactor/compare/2022.0.12...2022.0.13
2023-11-21 09:20:48 +01:00
Picnic-Bot
74b1104890 Upgrade NullAway 0.10.16 -> 0.10.17 (#892)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.10.17
- https://github.com/uber/NullAway/compare/v0.10.16...v0.10.17
2023-11-21 08:53:45 +01:00
Picnic-Bot
a230bbff12 Upgrade Byte Buddy 1.14.9 -> 1.14.10 (#891)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.10
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.9...byte-buddy-1.14.10
2023-11-21 08:01:19 +01:00
Picnic-Bot
100305ed1f Upgrade Spring 5.3.30 -> 5.3.31 (#888)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.31
- https://github.com/spring-projects/spring-framework/compare/v5.3.30...v5.3.31
2023-11-20 07:41:53 +01:00
Picnic-Bot
96c836e6a9 Upgrade versions-maven-plugin 2.16.1 -> 2.16.2 (#890)
See:
- https://github.com/mojohaus/versions/releases/tag/2.16.2
- https://github.com/mojohaus/versions-maven-plugin/compare/2.16.1...2.16.2
2023-11-20 07:28:35 +01:00
Picnic-Bot
97acfbc3bc Upgrade Surefire 3.2.1 -> 3.2.2 (#876)
See:
- https://github.com/apache/maven-surefire/releases/tag/surefire-3.2.2
- https://github.com/apache/maven-surefire/compare/surefire-3.2.1...surefire-3.2.2
2023-11-16 08:27:12 +01:00
Picnic-Bot
9ce7c6b40b Upgrade maven-javadoc-plugin 3.6.0 -> 3.6.2 (#875)
See:
- https://github.com/apache/maven-javadoc-plugin/releases/tag/maven-javadoc-plugin-3.6.2
- https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.0...maven-javadoc-plugin-3.6.2
2023-11-13 08:39:26 +01:00
Picnic-Bot
57a43a1c85 Upgrade JUnit 5 5.10.0 -> 5.10.1 (#874)
See:
- https://junit.org/junit5/docs/current/release-notes/
- https://github.com/junit-team/junit5/releases/tag/r5.10.1
- https://github.com/junit-team/junit5/compare/r5.10.0...r5.10.1
2023-11-13 08:18:45 +01:00
Picnic-Bot
89c4969a31 Upgrade Swagger 2.2.18 -> 2.2.19 (#879)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.19
- https://github.com/swagger-api/swagger-core/compare/v2.2.18...v2.2.19
2023-11-12 19:10:39 +01:00
Picnic-Bot
dbd4853e3e Upgrade CodeQL v2.22.0 -> v2.22.5 (#872)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.22.0...v2.22.5
2023-11-06 08:14:47 +01:00
Picnic-Bot
62a7dacf4d Upgrade ruby/setup-ruby v1.155.0 -> v1.159.0 (873)
See:
- https://github.com/ruby/setup-ruby/releases/tag/v1.159.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.158.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.157.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.156.0
2023-11-06 07:45:10 +01:00
Picnic-Bot
d23684ee6d Upgrade Mockito 5.6.0 -> 5.7.0 (#871)
See:
- https://github.com/mockito/mockito/releases/tag/v5.7.0
- https://github.com/mockito/mockito/compare/v5.6.0...v5.7.0
2023-11-04 09:41:24 +01:00
Picnic-Bot
fd150af6c6 Upgrade maven-checkstyle-plugin 3.3.0 -> 3.3.1 (#861)
See https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.3.0...maven-checkstyle-plugin-3.3.1
2023-11-03 08:29:27 +01:00
Picnic-Bot
a1a865b87a Upgrade Checker Framework Annotations 3.39.0 -> 3.40.0 (#870)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.40.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.39.0...checker-framework-3.40.0
2023-11-03 08:06:40 +01:00
Picnic-Bot
64000ebb07 Upgrade pitest-maven-plugin 1.15.2 -> 1.15.3 (#869)
See:
- https://github.com/hcoles/pitest/releases/tag/1.15.3
- https://github.com/hcoles/pitest/compare/1.15.2...1.15.3
2023-11-02 10:20:49 +01:00
Picnic-Bot
6122d7a39f Upgrade NullAway 0.10.15 -> 0.10.16 (#868)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.10.16
- https://github.com/uber/NullAway/compare/v0.10.15...v0.10.16
2023-11-02 08:47:51 +01:00
Stephan Schroevers
ca01bbb74a Renew Arcmutate OSS license (#864) 2023-11-01 21:30:36 +01:00
Rick Ossendrijver
4ce9f92489 Disallow static import of BugCheckerRefasctoringTestHelper.TestMode members (#862) 2023-10-30 10:46:50 +01:00
Stephan Schroevers
e8d14993a1 Introduce Checkstyle integration test (#865)
The new `integration-tests/checkstyle-10.12.4.sh` script can be executed
locally or by adding a comment containing the string `/integration-test`
to a pull request.

The integration test comprises a shell script that:
1. Checks out a Checkstyle release tag.
2. Applies a small patch to enable Error Prone Support.
3. Runs the build in Error Prone patch mode, until no further changes
   are applied.
4. Validates that:
   - The build (including tests) still passes.
   - The set of changes matches a pre-recorded diff.
   - The set of Error Prone Support-emitted warnings matches a
     pre-recorded list.

The script also has a `--sync` mode using which the expected diff and 
warnings can be updated. Combined, the script makes it easy to assess
and track the impact of changes to Error Prone Support in relation to
the Checkstyle code base.

Over time this setup will be generalized to include integration tests
against other code bases.
2023-10-30 10:34:14 +01:00
Picnic-Bot
88860800b1 Upgrade license-maven-plugin 2.2.0 -> 2.3.0 (#859)
See:
- https://github.com/mojohaus/license-maven-plugin/releases/tag/2.3.0
- https://github.com/mojohaus/license-maven-plugin/compare/2.2.0...2.3.0
2023-10-27 15:26:59 +02:00
Picnic-Bot
e76dd5c31b Upgrade maven-dependency-plugin 3.6.0 -> 3.6.1 (#854)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MDEP%20AND%20fixVersion%20%3E%203.6.0%20AND%20fixVersion%20%3C%3D%203.6.1
- https://github.com/apache/maven-dependency-plugin/compare/maven-dependency-plugin-3.6.0...maven-dependency-plugin-3.6.1
2023-10-27 12:10:12 +02:00
Picnic-Bot
701db7d61e Upgrade Surefire 3.1.2 -> 3.2.1 (#856)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20SUREFIRE%20AND%20fixVersion%20%3E%203.1.2%20AND%20fixVersion%20%3C%3D%203.2.1
- https://github.com/apache/maven-surefire/releases/tag/surefire-3.2.1
- https://github.com/apache/maven-surefire/compare/surefire-3.1.2...surefire-3.2.1
2023-10-27 11:55:29 +02:00
Picnic-Bot
8781a9ede5 Upgrade git-commit-id-maven-plugin 6.0.0 -> 7.0.0 (#852)
See:
- https://github.com/git-commit-id/git-commit-id-maven-plugin/releases/tag/v7.0.0
- https://github.com/git-commit-id/git-commit-id-maven-plugin/compare/v6.0.0...v7.0.0
2023-10-27 11:33:24 +02:00
Picnic-Bot
dc14c4e970 Upgrade maven-clean-plugin 3.3.1 -> 3.3.2 (#863)
See:
- https://github.com/apache/maven-clean-plugin/releases/tag/maven-clean-plugin-3.3.2
- https://github.com/apache/maven-clean-plugin/compare/maven-clean-plugin-3.3.1...maven-clean-plugin-3.3.2
2023-10-27 11:15:34 +02:00
Cernat Catalin Stefan
a435b657ae Introduce NonStaticImport check (#450)
This check complements the existing `StaticImport` check. We ensure that the 
two checks do not suggest mutually incompatible approaches to static imports.
2023-10-26 11:00:48 +02:00
Picnic-Bot
00edc5ea1f Upgrade pitest-junit5-plugin 1.2.0 -> 1.2.1 (#857)
See https://github.com/pitest/pitest-junit5-plugin/compare/1.2.0...1.2.1
2023-10-26 10:48:08 +02:00
Picnic-Bot
7383a11da7 Upgrade Swagger 2.2.17 -> 2.2.18 (#860)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.18
- https://github.com/swagger-api/swagger-core/compare/v2.2.17...v2.2.18
2023-10-26 09:32:11 +02:00
Picnic-Bot
e4e17664d0 Upgrade ossf/scorecard-action v2.3.0 -> v2.3.1 (#855)
See:
- https://github.com/ossf/scorecard-action/releases/tag/v2.3.1
2023-10-26 09:14:34 +02:00
Picnic-Bot
5972a8e225 Upgrade pitest-maven-plugin 1.15.1 -> 1.15.2 (#858)
See:
- https://github.com/hcoles/pitest/releases/tag/1.15.2
- https://github.com/hcoles/pitest/compare/1.15.1...1.15.2
2023-10-25 17:20:39 +02:00
Rick Ossendrijver
01b30d767b Introduce BugPatternTestExtractor for documentation generation (#494)
This new `Extractor` implementation collects identification and
replacement source code from `BugChecker` unit tests.

While there:
- Refactor the existing `Extractor` setup such that instances are
  service-loaded and need to implement only a single method, thereby
  avoiding the need to align logic between multiple source code 
  locations.
- Extend the validation performed by the `Compilation` test helper
  class.
- Extend the `ErrorProneTestHelperSourceFormat` check to support source
  code passed to the `Compilation` test helper class.
2023-10-24 13:57:37 +02:00
Stephan Schroevers
c2426d3a8d Drop obsolete Maven configuration (#851) 2023-10-23 16:52:17 +02:00
Stephan Schroevers
8130ddf59c Introduce IsIdentityOperation matcher for use by Refaster templates (#749) 2023-10-23 14:52:16 +02:00
Vincent Koeman
c3b950f114 Introduce JUnitNullaryParameterizedTestDeclaration check (#817)
While there, slightly simplify the `AutowiredConstructor` check.
2023-10-23 09:22:51 +02:00
Stephan Schroevers
fa026de336 Introduce IsEmpty matcher for use by Refaster templates (#744)
While there, generalize a number of Refaster rules using this new matcher.
2023-10-23 09:07:47 +02:00
Picnic-Bot
2ff3095fca Upgrade Spring Boot 2.7.16 -> 2.7.17 (#848)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.17
- https://github.com/spring-projects/spring-boot/compare/v2.7.16...v2.7.17
2023-10-21 18:15:27 +02:00
Picnic-Bot
2b2d9f498e Upgrade NullAway 0.10.14 -> 0.10.15 (#846)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.10.15
- https://github.com/uber/NullAway/compare/v0.10.14...v0.10.15
2023-10-20 10:06:21 +02:00
Picnic-Bot
2a5dd7d56d Upgrade Error Prone 2.22.0 -> 2.23.0 (#847)
See:
- https://github.com/google/error-prone/releases/tag/v2.23.0
- https://github.com/google/error-prone/compare/v2.22.0...v2.23.0
- https://github.com/PicnicSupermarket/error-prone/compare/v2.22.0-picnic-1...v2.23.0-picnic-1
2023-10-20 09:13:05 +02:00
Stephan Schroevers
dd021b3757 Introduce {Integer,Long}SignumIs{Positive,Negative} Refaster rules (#822) 2023-10-19 10:46:09 +02:00
Picnic-Bot
c77cc9a35d Upgrade swagger-annotations 1.6.11 -> 1.6.12 (#842)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v1.6.12
- https://github.com/swagger-api/swagger-core/compare/v1.6.11...v1.6.12
2023-10-18 10:36:45 +02:00
Picnic-Bot
7a7a09d208 Upgrade jacoco-maven-plugin 0.8.10 -> 0.8.11 (#843)
See:
- https://github.com/jacoco/jacoco/releases/tag/v0.8.11
- https://github.com/jacoco/jacoco/compare/v0.8.10...v0.8.11
2023-10-18 09:13:28 +02:00
Vincent Koeman
62077dacbb Introduce assorted BigDecimal#signum Refaster rules (#812) 2023-10-18 08:59:36 +02:00
Picnic-Bot
3a76f91d18 Upgrade actions/checkout v4.1.0 -> v4.1.1 (#845)
See:
- https://github.com/actions/checkout/releases/tag/v4.1.1
2023-10-18 08:17:15 +02:00
Stephan Schroevers
82c0dd95ce Build and test against JDK 21 instead of JDK 20 (#832)
See https://jdk.java.net/21/release-notes
2023-10-16 13:11:57 +02:00
Picnic-Bot
a424a3e949 Upgrade Jackson 2.15.2 -> 2.15.3 (#837)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.15.3
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.15.2...jackson-bom-2.15.3
2023-10-15 15:24:37 +02:00
Picnic-Bot
3f530475ab Upgrade MongoDB driver 4.10.2 -> 4.11.0 (#831)
See:
- https://jira.mongodb.org/issues/?jql=project%20%3D%20JAVA%20AND%20fixVersion%20%3E%204.10.2%20AND%20fixVersion%20%3C%3D%204.11.0
- https://github.com/mongodb/mongo-java-driver/releases/tag/r4.11.0
- https://github.com/mongodb/mongo-java-driver/compare/r4.10.2...r4.11.0
2023-10-15 14:54:07 +02:00
Picnic-Bot
24621b7c20 Upgrade Swagger 2.2.16 -> 2.2.17 (#834)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.17
- https://github.com/swagger-api/swagger-core/compare/v2.2.16...v2.2.17
2023-10-15 12:53:37 +02:00
Picnic-Bot
746e757e16 Upgrade Project Reactor 2022.0.11 -> 2022.0.12 (#829)
See:
- https://github.com/reactor/reactor/releases/tag/2022.0.12
- https://github.com/reactor/reactor/compare/2022.0.11...2022.0.12
2023-10-14 17:43:35 +02:00
Picnic-Bot
df42013d5b Upgrade Guava 32.1.2-jre -> 32.1.3-jre (#828)
See:
- https://github.com/google/guava/releases/tag/v32.1.3
- https://github.com/google/guava/compare/v32.1.2...v32.1.3
2023-10-14 09:40:41 +02:00
Picnic-Bot
0336626dc9 Upgrade Arcmutate 1.2.1 -> 1.2.2 (#833) 2023-10-13 16:13:18 +02:00
Vincent Koeman
4e2ceeb252 Introduce StreamOf{1,2,3,4,5} Refaster rules (#814) 2023-10-11 17:52:52 +02:00
Picnic-Bot
05809b1c85 Upgrade Byte Buddy 1.14.8 -> 1.14.9 (#827)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.9
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.8...byte-buddy-1.14.9
2023-10-11 09:14:28 +02:00
Stephan Schroevers
75679396df Introduce PatternRules Refaster rule collection (#771)
While there, configure `StaticImport` to not require static importing of
`com.google.common.base.Predicates.contains`.

The new rules triggered cleanup of some `CompilationTestHelper` usages.

See google/guava#6483.
2023-10-11 08:36:26 +02:00
Picnic-Bot
f1882caf88 Upgrade pitest-maven-plugin 1.15.0 -> 1.15.1 (#830)
See:
- https://github.com/hcoles/pitest/releases/tag/1.15.1
- https://github.com/hcoles/pitest/compare/1.15.0...1.15.1
2023-10-11 08:18:44 +02:00
Picnic-Bot
605d045760 Upgrade ossf/scorecard-action v2.2.0 -> v2.3.0 (#821)
See:
- https://github.com/ossf/scorecard-action/releases/tag/v2.3.0
2023-10-10 09:22:48 +02:00
Rick Ossendrijver
b492a4afd3 Fix and enable ClassRules Refaster rule collection tests (#826) 2023-10-10 08:37:43 +02:00
Phil Werli
583e51c9b0 Introduce {Mono,Flux}OfType Refaster rules (#810) 2023-10-09 11:57:36 +02:00
Vincent Koeman
9ada0783dd Introduce Flux{Empty,Just} Refaster rules (#815) 2023-10-09 11:30:50 +02:00
Picnic-Bot
7ed3e63d2e Upgrade CodeQL v2.21.9 -> v2.22.0 (#824)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.21.9...v2.22.0
2023-10-09 11:20:56 +02:00
Picnic-Bot
465f83b855 Upgrade Arcmutate 1.2.0 -> 1.2.1 (#818) 2023-10-09 10:42:34 +02:00
Picnic-Bot
24f8b2f499 Upgrade Google Java Format 1.18.0 -> 1.18.1 (#819)
See:
- https://github.com/google/google-java-format/releases/tag/v1.18.1
- https://github.com/google/google-java-format/compare/v1.18.0...v1.18.1
2023-10-09 10:33:52 +02:00
Picnic-Bot
f466c75bf3 Upgrade ruby/setup-ruby v1.152.0 -> v1.155.0 (#825)
See:
- https://github.com/ruby/setup-ruby/releases/tag/v1.155.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.154.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.153.0
2023-10-09 09:31:53 +02:00
Stephan Schroevers
c48db5202c Introduce additional Mockito Refaster rules (#777) 2023-10-09 09:23:47 +02:00
Picnic-Bot
629cb577ea Upgrade Immutables Annotations 2.9.3 -> 2.10.0 (#823)
See:
- https://github.com/immutables/immutables/releases/tag/2.10.0
- https://github.com/immutables/immutables/compare/2.9.3...2.10.0
2023-10-09 09:06:03 +02:00
Picnic-Bot
b13d445e56 Upgrade Mockito 5.5.0 -> 5.6.0 (#820)
See:
- https://github.com/mockito/mockito/releases/tag/v5.6.0
- https://github.com/mockito/mockito/compare/v5.5.0...v5.6.0
2023-10-09 08:05:29 +02:00
Stephan Schroevers
b1683a31e9 Introduce ClassRules Refaster rule collection (#811) 2023-10-09 07:42:02 +02:00
Vincent Koeman
ffe4db2cf8 Extend StepVerifierLastStepVerifyErrorClass Refaster rule (#813) 2023-10-08 16:22:36 +02:00
Stephan Schroevers
da5eea8329 Introduce assorted Reactor Refaster rules (#763) 2023-10-06 21:45:22 +02:00
Stephan Schroevers
5596b584ac [maven-release-plugin] prepare for next development iteration 2023-10-04 16:40:37 +02:00
Stephan Schroevers
4800522a09 [maven-release-plugin] prepare release v0.14.0 2023-10-04 16:40:37 +02:00
Stephan Schroevers
9a77a3f35f Drop ScheduledTransactionTrace check (#788)
As well as any other references to New Relic.
2023-10-04 15:30:13 +02:00
Picnic-Bot
ef75b80e7b Upgrade Error Prone 2.21.1 -> 2.22.0 (#800)
See:
- https://github.com/google/error-prone/releases/tag/v2.22.0
- https://github.com/google/error-prone/compare/v2.21.1...v2.22.0
- https://github.com/PicnicSupermarket/error-prone/compare/v2.21.1-picnic-1...v2.22.0-picnic-1
2023-10-04 14:43:27 +02:00
Picnic-Bot
7c618f7e2d Upgrade sonar-maven-plugin 3.9.1.2184 -> 3.10.0.2594 (#792)
See:
- https://github.com/SonarSource/sonar-scanner-maven/releases/tag/3.10.0.2594
- https://github.com/SonarSource/sonar-scanner-maven/compare/3.9.1.2184...3.10.0.2594
2023-10-04 13:44:51 +02:00
Stephan Schroevers
c03ead9e5d Upgrade JDKs used by GitHub Actions builds (#780)
Summary of changes:
- Use JDK 11.0.20 instead of 11.0.19.
- Use JDK 17.0.8 instead of 17.0.7.
- Use JDK 20.0.2 instead of 20.0.1.

See:
- https://www.oracle.com/java/technologies/javase/11-0-20-relnotes.html
- https://www.oracle.com/java/technologies/javase/17-0-8-relnotes.html
- https://www.oracle.com/java/technologies/javase/20-0-2-relnotes.html
2023-10-04 11:22:16 +02:00
Picnic-Bot
8fd87a5b6b Upgrade SLF4J 2.0.7 -> 2.0.9 (#778)
See:
- https://www.slf4j.org/news.html
- https://github.com/qos-ch/slf4j/compare/v_2.0.7...v_2.0.9
2023-10-04 10:59:37 +02:00
Picnic-Bot
82025a729f Upgrade fmt-maven-plugin 2.20 -> 2.21.1 (#804)
See:
- https://github.com/spotify/fmt-maven-plugin/releases/tag/2.21
- https://github.com/spotify/fmt-maven-plugin/releases/tag/2.21.1
- https://github.com/spotify/fmt-maven-plugin/compare/fmt-maven-plugin-2.20...2.21.1
2023-10-04 10:29:27 +02:00
Picnic-Bot
7d912d1b04 Upgrade Swagger 2.2.15 -> 2.2.16 (#795)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.16
- https://github.com/swagger-api/swagger-core/compare/v2.2.15...v2.2.16
2023-10-04 08:45:30 +02:00
Picnic-Bot
a726514e98 Upgrade AspectJ 1.9.20 -> 1.9.20.1 (#781)
See:
- https://github.com/eclipse-aspectj/aspectj/releases/tag/V1_9_20_1
- https://github.com/eclipse/org.aspectj/compare/V1_9_20...V1_9_20_1
2023-10-04 08:36:58 +02:00
Picnic-Bot
aa7de5777c Upgrade Spring 5.3.29 -> 5.3.30 (#791)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.30
- https://github.com/spring-projects/spring-framework/compare/v5.3.29...v5.3.30
2023-10-04 08:25:50 +02:00
Picnic-Bot
6e6efb3c13 Upgrade Project Reactor 2022.0.10 -> 2022.0.11 (#789)
See:
- https://github.com/reactor/reactor/releases/tag/2022.0.11
- https://github.com/reactor/reactor/compare/2022.0.10...2022.0.11
2023-10-03 16:54:15 +02:00
Picnic-Bot
03fd050eae Upgrade AutoValue 1.10.3 -> 1.10.4 (#784)
See:
- https://github.com/google/auto/releases/tag/auto-value-1.10.4
- https://github.com/google/auto/compare/auto-value-1.10.3...auto-value-1.10.4
2023-10-03 16:42:00 +02:00
Picnic-Bot
d1467e0424 Upgrade actions/upload-artifact v3.1.2 -> v3.1.3 (#782)
See:
- https://github.com/actions/upload-artifact/releases/tag/v3.1.3
2023-10-03 16:08:59 +02:00
Picnic-Bot
a2e32ed147 Upgrade maven-enforcer-plugin 3.4.0 -> 3.4.1 (#787)
See:
- https://github.com/apache/maven-enforcer/releases/tag/enforcer-3.4.1
- https://github.com/apache/maven-enforcer/compare/enforcer-3.4.0...enforcer-3.4.1
2023-10-03 15:58:07 +02:00
Picnic-Bot
258708e6a8 Upgrade New Relic Java Agent 8.5.0 -> 8.6.0 (#785)
See:
- https://github.com/newrelic/newrelic-java-agent/releases/tag/v8.6.0
- https://github.com/newrelic/newrelic-java-agent/compare/v8.5.0...v8.6.0
2023-10-03 13:23:08 +02:00
Picnic-Bot
67106a9725 Upgrade actions/setup-java v3.12.0 -> v3.13.0 (#798)
See:
- https://github.com/actions/setup-java/releases/tag/v3.13.0
2023-10-03 13:14:33 +02:00
Picnic-Bot
f979576ab5 Upgrade maven-javadoc-plugin 3.5.0 -> 3.6.0 (#793)
See:
- https://github.com/apache/maven-javadoc-plugin/releases/tag/maven-javadoc-plugin-3.6.0
- https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.5.0...maven-javadoc-plugin-3.6.0
2023-10-03 12:53:51 +02:00
Picnic-Bot
aa3fd03569 Upgrade dawidd6/action-download-artifact v2.27.0 -> v2.28.0 (#796)
See:
- https://github.com/dawidd6/action-download-artifact/compare/v2.27.0...v2.28.0
2023-10-03 11:59:38 +02:00
Picnic-Bot
5602251667 Upgrade actions/checkout v3.6.0 -> v4.1.0 (#779)
See:
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v410
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v400
2023-10-03 11:51:20 +02:00
Picnic-Bot
05cb6387b9 Upgrade Checkstyle 10.12.3 -> 10.12.4 (#807)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.12.4
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.12.3...checkstyle-10.12.4
2023-10-03 11:38:31 +02:00
Picnic-Bot
4e242a5b11 Upgrade Byte Buddy 1.14.7 -> 1.14.8 (#790)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.8
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.7...byte-buddy-1.14.8
2023-10-03 10:31:08 +02:00
Picnic-Bot
87297c9a1d Upgrade versions-maven-plugin 2.16.0 -> 2.16.1 (#797)
See:
- https://github.com/mojohaus/versions/releases/tag/2.16.1
- https://github.com/mojohaus/versions-maven-plugin/compare/2.16.0...2.16.1
2023-10-03 10:17:14 +02:00
Picnic-Bot
15ff85c4ea Upgrade Checker Framework Annotations 3.38.0 -> 3.39.0 (#808)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.39.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.38.0...checker-framework-3.39.0
2023-10-03 10:00:24 +02:00
Picnic-Bot
2c8469fa93 Upgrade Google Java Format 1.17.0 -> 1.18.0 (#809)
See:
- https://github.com/google/google-java-format/releases/tag/v1.18.0
- https://github.com/google/google-java-format/compare/v1.17.0...v1.18.0
2023-10-03 09:28:21 +02:00
Picnic-Bot
f4e0fd2cc3 Upgrade Modernizer Maven Plugin 2.6.0 -> 2.7.0 (#801)
See:
- https://github.com/gaul/modernizer-maven-plugin/releases/tag/modernizer-maven-plugin-2.7.0
- https://github.com/gaul/modernizer-maven-plugin/compare/modernizer-maven-plugin-2.6.0...modernizer-maven-plugin-2.7.0
2023-10-03 08:55:08 +02:00
Picnic-Bot
34fd692064 Upgrade pitest-maven-plugin 1.14.4 -> 1.15.0 (#803)
See:
- https://github.com/hcoles/pitest/releases/tag/1.15.0
- https://github.com/hcoles/pitest/compare/1.14.4...1.15.0
2023-10-03 08:07:16 +02:00
Stephan Schroevers
26bc7e6e8e Disallow autovalue.shaded.* imports (#774) 2023-10-02 18:00:57 +02:00
Picnic-Bot
56cb86a7e1 Upgrade Checker Framework Annotations 3.37.0 -> 3.38.0 (#773)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.38.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.37.0...checker-framework-3.38.0
2023-10-02 17:43:17 +02:00
Picnic-Bot
19cd802ec5 Upgrade NullAway 0.10.12 -> 0.10.14 (#776)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.10.13
- https://github.com/uber/NullAway/releases/tag/v0.10.14
- https://github.com/uber/NullAway/compare/v0.10.12...v0.10.14
2023-10-02 16:29:33 +02:00
Picnic-Bot
1fabb26ed2 Upgrade Spring Boot 2.7.15 -> 2.7.16 (#799)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.16
- https://github.com/spring-projects/spring-boot/compare/v2.7.15...v2.7.16
2023-10-02 16:17:58 +02:00
Picnic-Bot
c1ced1e962 Upgrade CodeQL v2.21.4 -> v2.21.9 (#786)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.21.4...v2.21.9
2023-10-02 09:57:34 +02:00
Picnic-Bot
030ed25be8 Upgrade Forbidden APIs plugin 3.5.1 -> 3.6 (#806)
See:
- https://github.com/policeman-tools/forbidden-apis/wiki/Changes
- https://github.com/policeman-tools/forbidden-apis/compare/3.5.1...3.6
2023-10-02 09:20:01 +02:00
Picnic-Bot
ee0c04a44e Upgrade Arcmutate 1.1.3 -> 1.2.0 (#805) 2023-10-02 07:10:41 +02:00
Stephan Schroevers
87f79dae60 Introduce additional equality Refaster rules (#765) 2023-09-01 15:17:33 +02:00
Stephan Schroevers
1f4a68416f Introduce assorted Optional Refaster rules (#764)
While there, move the `OptionalOrElseGet` Refaster rule test code to the
correct location.
2023-09-01 11:42:13 +02:00
Picnic-Bot
c98fe9273d Upgrade Pitest Git plugins 1.1.1 -> 1.1.2 (#772) 2023-09-01 09:11:09 +02:00
Stephan Schroevers
8b5d1803e4 Introduce CollectionContains Refaster rule (#766) 2023-08-31 15:46:43 +02:00
Stephan Schroevers
507a19d10e Introduce FileRules Refaster rule collection (#767) 2023-08-31 08:58:11 +02:00
Picnic-Bot
43fcbb770d Upgrade Checkstyle 10.12.2 -> 10.12.3 (#769)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.12.3
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.12.2...checkstyle-10.12.3
2023-08-30 10:13:01 +02:00
Stephan Schroevers
7779631320 Introduce StreamIterate Refaster rule (#762) 2023-08-29 09:08:43 +02:00
Stephan Schroevers
48e2f57cb6 [maven-release-plugin] prepare for next development iteration 2023-08-28 19:22:11 +03:00
Stephan Schroevers
352829c61f [maven-release-plugin] prepare release v0.13.0 2023-08-28 19:22:11 +03:00
Picnic-Bot
37d95605b0 Upgrade Byte Buddy 1.14.6 -> 1.14.7 (#768)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.7
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.6...byte-buddy-1.14.7
2023-08-28 10:06:30 +02:00
Stephan Schroevers
6131599d9d Introduce mutation test script for changed code (#757)
While there, optimize the existing `run-mutation-tests.sh` script.
2023-08-28 09:43:06 +02:00
Picnic-Bot
9c158f11d4 Upgrade maven-enforcer-plugin 3.3.0 -> 3.4.0 (#759)
See:
- https://github.com/apache/maven-enforcer/releases/tag/enforcer-3.4.0
- https://github.com/apache/maven-enforcer/compare/enforcer-3.3.0...enforcer-3.4.0
2023-08-25 22:23:19 +02:00
Picnic-Bot
be818486bd Upgrade Mockito 5.4.0 -> 5.5.0 (#758)
See:
- https://github.com/mockito/mockito/releases/tag/v5.5.0
- https://github.com/mockito/mockito/compare/v5.4.0...v5.5.0
2023-08-25 22:05:51 +02:00
Picnic-Bot
1e80097bee Upgrade Spring Boot 2.7.14 -> 2.7.15 (#760)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.15
- https://github.com/spring-projects/spring-boot/compare/v2.7.14...v2.7.15
2023-08-25 21:14:26 +02:00
Picnic-Bot
431c3e67ac Upgrade actions/checkout v3.5.3 -> v3.6.0 (#761)
See:
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v360
2023-08-25 09:34:35 +02:00
Picnic-Bot
e612631cb8 Upgrade AspectJ 1.9.19 -> 1.9.20 (#755)
See:
- https://github.com/eclipse-aspectj/aspectj/releases/tag/V1_9_20
- https://github.com/eclipse/org.aspectj/compare/V1_9_19...V1_9_20
2023-08-17 21:34:51 +02:00
Picnic-Bot
a6bce960cb Upgrade AutoValue 1.10.2 -> 1.10.3 (#752)
See:
- https://github.com/google/auto/releases/tag/auto-value-1.10.3
- https://github.com/google/auto/compare/auto-value-1.10.2...auto-value-1.10.3
2023-08-17 17:12:33 +02:00
Picnic-Bot
e19c2de99d Upgrade pitest-maven-plugin 1.14.3 -> 1.14.4 (#756)
See:
- https://github.com/hcoles/pitest/releases/tag/1.14.4
- https://github.com/hcoles/pitest/compare/1.14.3...1.14.4
2023-08-17 10:36:59 +02:00
Picnic-Bot
7b193f2fd5 Upgrade Byte Buddy 1.14.5 -> 1.14.6 (#753)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.6
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.5...byte-buddy-1.14.6
2023-08-16 09:24:45 +02:00
Picnic-Bot
852442b55b Upgrade Project Reactor 2022.0.9 -> 2022.0.10 (#754)
See:
- https://github.com/reactor/reactor/releases/tag/2022.0.10
- https://github.com/reactor/reactor/compare/2022.0.9...2022.0.10
2023-08-16 09:02:16 +02:00
Rick Ossendrijver
d758fab524 Have Renovate file GitHub CodeQL upgrade PRs once every four weeks (#745)
While there, match on the `depName` of `ruby/setup-ruby`.
2023-08-15 14:08:52 +02:00
Picnic-Bot
88ed3ea9a9 Upgrade CodeQL v2.21.3 -> v2.21.4 (#751)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.21.3...v2.21.4
2023-08-15 11:58:32 +02:00
Giovanni Zotta
7fb0e551d4 Introduce VerifyOnlyElementInFlux Refaster rule (#617) 2023-08-14 14:05:14 +02:00
Mohamed Sameh
4af7b21bf5 Introduce NestedPublishers check (#642)
And introduce a few utility methods that simplify `Tree`- and `Type`-based
matching, allowing the existing (and similar) `NestedOptionals` check to be
simplified as well.
2023-08-14 10:30:45 +02:00
Picnic-Bot
fc5f3bd4cc Upgrade Pitest Git plugins 1.1.0 -> 1.1.1 (#750) 2023-08-14 08:52:14 +02:00
Mohamed Sameh
35a5944b81 Introduce {Flux,{Double,Int,Long,}Stream}TakeWhile Refaster rules (#727) 2023-08-12 15:36:43 +02:00
Picnic-Bot
17cc8e0c31 Upgrade CodeQL v2.21.2 -> v2.21.3 (#746)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.21.2...v2.21.3
2023-08-12 14:39:33 +02:00
Picnic-Bot
b5ba4fa208 Upgrade actions/deploy-pages v2.0.3 -> v2.0.4 (#747)
See:
- https://github.com/actions/deploy-pages/releases/tag/v2.0.4
2023-08-12 14:28:35 +02:00
Picnic-Bot
26b941bbc5 Upgrade Guava 32.1.1-jre -> 32.1.2-jre (#735)
See:
- https://github.com/google/guava/releases/tag/v32.1.2
- https://github.com/google/guava/compare/v32.1.1...v32.1.2
2023-08-12 14:18:05 +02:00
Picnic-Bot
eb3b540537 Upgrade pitest-maven-plugin 1.14.2 -> 1.14.3 (#748)
See:
- https://github.com/hcoles/pitest/releases/tag/1.14.3
- https://github.com/hcoles/pitest/compare/1.14.2...1.14.3
2023-08-12 14:05:50 +02:00
Picnic-Bot
6a11b59517 Upgrade CodeQL v2.20.3 -> v2.21.2 (#722)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.20.3...v2.21.2
2023-08-07 11:47:08 +02:00
Picnic-Bot
62abd51f4d Upgrade errorprone-slf4j 0.1.18 -> 0.1.20 (#741)
See:
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.19
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.20
- https://github.com/KengoTODA/errorprone-slf4j/compare/v0.1.18...v0.1.20
2023-08-07 07:24:39 +02:00
Rick Ossendrijver
67a128a9b6 Fix typos in CanonicalSyntaxAnnotation source (#738) 2023-08-06 16:18:29 +02:00
Picnic-Bot
526227e8ed Upgrade Error Prone 2.21.0 -> 2.21.1 (#743)
See:
- https://github.com/google/error-prone/releases/tag/v2.21.1
- https://github.com/google/error-prone/compare/v2.21.0...v2.21.1
- https://github.com/PicnicSupermarket/error-prone/compare/v2.21.0-picnic-1...v2.21.1-picnic-1
2023-08-06 16:06:25 +02:00
Picnic-Bot
c2e837819e Upgrade Pitest Git plugins 1.0.12 -> 1.1.0 (#742) 2023-08-06 11:15:07 +02:00
Picnic-Bot
fd70be081e Upgrade Arcmutate 1.1.2 -> 1.1.3 (#739) 2023-08-05 20:13:27 +02:00
Picnic-Bot
2c47244571 Upgrade NullAway 0.10.11 -> 0.10.12 (#740)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.10.12
- https://github.com/uber/NullAway/compare/v0.10.11...v0.10.12
2023-08-05 13:27:26 +02:00
Picnic-Bot
8375f1650f Upgrade Error Prone 2.20.0 -> 2.21.0 (#737)
See:
- https://github.com/google/error-prone/releases/tag/v2.21.0
- https://github.com/google/error-prone/compare/v2.20.0...v2.21.0
- https://github.com/PicnicSupermarket/error-prone/compare/v2.20.0-picnic-1...v2.21.0-picnic-1
2023-08-03 11:06:33 +02:00
Picnic-Bot
c4daa04ce1 Upgrade Checker Framework Annotations 3.36.0 -> 3.37.0 (#736)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.37.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.36.0...checker-framework-3.37.0
2023-08-03 10:36:41 +02:00
Picnic-Bot
08f0e52104 Upgrade sortpom-maven-plugin 3.2.1 -> 3.3.0 (#731)
See:
- https://github.com/Ekryd/sortpom/wiki/Versions
- https://github.com/Ekryd/sortpom/releases/tag/sortpom-parent-3.3.0
- https://github.com/Ekryd/sortpom/compare/sortpom-parent-3.2.1...sortpom-parent-3.3.0
2023-08-02 14:39:18 +02:00
Picnic-Bot
10070bd4c8 Upgrade JUnit 5 5.9.3 -> 5.10.0 (#729)
See:
- https://junit.org/junit5/docs/current/release-notes/
- https://github.com/junit-team/junit5/releases/tag/r5.10.0-M1
- https://github.com/junit-team/junit5/releases/tag/r5.10.0-RC1
- https://github.com/junit-team/junit5/releases/tag/r5.10.0-RC2
- https://github.com/junit-team/junit5/releases/tag/r5.10.0
- https://github.com/junit-team/junit5/compare/r5.9.3...r5.10.0
2023-08-01 15:54:26 +02:00
Picnic-Bot
3c38fd3495 Upgrade actions/setup-java v3.11.0 -> v3.12.0 (#730)
See https://github.com/actions/setup-java/releases/tag/v3.12.0
2023-08-01 09:54:17 +02:00
Picnic-Bot
d54ec83844 Upgrade New Relic Java Agent 8.4.0 -> 8.5.0 (#732)
See:
- https://github.com/newrelic/newrelic-java-agent/releases/tag/v8.5.0
- https://github.com/newrelic/newrelic-java-agent/compare/v8.4.0...v8.5.0
2023-08-01 08:12:06 +02:00
Philip Leonard
e03d0de366 Introduce MongoDBTextFilterUsage check (#649) 2023-07-31 17:19:39 +02:00
Picnic-Bot
b40c5d61b9 Upgrade Checkstyle 10.12.1 -> 10.12.2 (#734)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.12.2
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.12.1...checkstyle-10.12.2
2023-07-31 12:54:47 +02:00
Picnic-Bot
6d27e46baf Upgrade Spring 5.3.28 -> 5.3.29 (#723)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.29
- https://github.com/spring-projects/spring-framework/compare/v5.3.28...v5.3.29
2023-07-24 08:15:30 +02:00
Picnic-Bot
8f48497322 Upgrade Spring Boot 2.7.13 -> 2.7.14 (#726)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.14
- https://github.com/spring-projects/spring-boot/compare/v2.7.13...v2.7.14
2023-07-23 12:41:36 +02:00
Stephan Schroevers
38554be3d1 Upgrade Error Prone fork v2.20.0-picnic-1 -> v2.20.0-picnic-2 (#725)
This new release is a workaround for jitpack/jitpack.io#5741.

See https://github.com/PicnicSupermarket/error-prone/compare/v2.20.0-picnic-1...v2.20.0-picnic-2
2023-07-19 09:16:40 +02:00
Picnic-Bot
28cdb91913 Upgrade Project Reactor 2022.0.8 -> 2022.0.9 (#721)
See:
- https://github.com/reactor/reactor/releases/tag/2022.0.9
- https://github.com/reactor/reactor/compare/2022.0.8...2022.0.9
2023-07-13 11:19:52 +02:00
Picnic-Bot
bd6693d23e Upgrade actions/deploy-pages v2.0.2 -> v2.0.3 (#718)
See:
- https://github.com/actions/deploy-pages/releases/tag/v2.0.3
2023-07-11 12:51:40 +02:00
Picnic-Bot
a3ec76845a Upgrade actions/upload-pages-artifact v1.0.9 -> v2.0.0 (#720)
See:
- https://github.com/actions/upload-pages-artifact/releases/tag/v2.0.0
- https://github.com/actions/upload-pages-artifact/releases/tag/v1.0.10
2023-07-11 08:55:31 +02:00
Picnic-Bot
e3b310761d Upgrade Swagger 2.2.14 -> 2.2.15 (#717)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.15
- https://github.com/swagger-api/swagger-core/compare/v2.2.14...v2.2.15
2023-07-10 08:55:50 +02:00
Picnic-Bot
774052f13a Upgrade CodeQL v2.20.2 -> v2.20.3 (#715)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.20.2...v2.20.3
2023-07-07 15:11:45 +02:00
Picnic-Bot
bad7684639 Upgrade Arcmutate 1.1.1 -> 1.1.2 (#714) 2023-07-07 10:40:15 +02:00
Picnic-Bot
dd72b5a08a Upgrade Checker Framework Annotations 3.35.0 -> 3.36.0 (#711)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.36.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.35.0...checker-framework-3.36.0
2023-07-06 11:15:26 +02:00
Picnic-Bot
3eb30c5f93 Upgrade Guava 32.0.1-jre -> 32.1.1-jre (#705)
See:
- https://github.com/google/guava/releases/tag/v32.1.0
- https://github.com/google/guava/releases/tag/v32.1.1
- https://github.com/google/guava/compare/v32.0.1...v32.1.1
2023-07-06 10:22:56 +02:00
Picnic-Bot
2cc0539f8f Upgrade CodeQL v2.20.1 -> v2.20.2 (#707)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.20.1...v2.20.2
2023-07-06 09:38:52 +02:00
Picnic-Bot
9210c30a0a Upgrade Pitest JUnit 5 Accelerator 1.0.5 -> 1.0.6 (#709) 2023-07-06 08:48:05 +02:00
Picnic-Bot
ba362ed460 Upgrade license-maven-plugin 2.1.0 -> 2.2.0 (#712)
See:
- https://github.com/mojohaus/license-maven-plugin/releases/tag/2.2.0
- https://github.com/mojohaus/license-maven-plugin/compare/2.1.0...2.2.0
2023-07-05 17:59:46 +02:00
Picnic-Bot
ab33adfab8 Upgrade Arcmutate 1.1.0 -> 1.1.1 (#708) 2023-07-05 17:48:22 +02:00
Rick Ossendrijver
006665ee6d Introduce MonoSingle Refaster rule (#703) 2023-07-05 13:54:49 +02:00
Picnic-Bot
08c49b9a58 Upgrade Pitest Git plugins 1.0.11 -> 1.0.12 (#710) 2023-07-05 13:42:54 +02:00
Picnic-Bot
777aa970f1 Upgrade ruby/setup-ruby v1.126.0 -> v1.152.0 (#706)
See:
- https://github.com/ruby/setup-ruby/releases/tag/v1.152.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.151.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.150.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.149.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.148.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.147.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.146.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.145.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.144.2
- https://github.com/ruby/setup-ruby/releases/tag/v1.144.1
- https://github.com/ruby/setup-ruby/releases/tag/v1.144.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.143.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.142.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.141.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.140.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.139.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.138.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.137.2
- https://github.com/ruby/setup-ruby/releases/tag/v1.137.1
- https://github.com/ruby/setup-ruby/releases/tag/v1.137.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.136.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.135.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.134.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.133.2
- https://github.com/ruby/setup-ruby/releases/tag/v1.133.1
- https://github.com/ruby/setup-ruby/releases/tag/v1.133.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.132.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.131.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.130.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.129.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.128.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.127.0
2023-07-05 12:18:29 +02:00
Picnic-Bot
a040310870 Upgrade AutoValue 1.10.1 -> 1.10.2 (#704)
See:
- https://github.com/google/auto/releases/tag/auto-value-1.10.2
- https://github.com/google/auto/compare/auto-value-1.10.1...auto-value-1.10.2
2023-06-30 12:59:26 +02:00
Picnic-Bot
d6ab366f31 Upgrade CodeQL v2.2.11 -> v2.20.1 (#670)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.20.0...v2.20.1
- https://github.com/github/codeql-action/compare/v2.3.6...v2.20.0
- https://github.com/github/codeql-action/compare/v2.3.5...v2.3.6
- https://github.com/github/codeql-action/compare/v2.3.4...v2.3.5
- https://github.com/github/codeql-action/compare/v2.3.3...v2.3.4
- https://github.com/github/codeql-action/compare/v2.3.2...v2.3.3
- https://github.com/github/codeql-action/compare/v2.3.1...v2.3.2
- https://github.com/github/codeql-action/compare/v2.3.0...v2.3.1
- https://github.com/github/codeql-action/compare/v2.2.12...v2.3.0
- https://github.com/github/codeql-action/compare/v2.2.11...v2.2.12
2023-06-28 13:20:53 +02:00
Picnic-Bot
d9fefa6824 Upgrade Swagger 2.2.13 -> 2.2.14 (#702)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.14
- https://github.com/swagger-api/swagger-core/compare/v2.2.13...v2.2.14
2023-06-27 08:28:08 +02:00
Picnic-Bot
c8b3a6df82 Upgrade pitest-maven-plugin 1.14.1 -> 1.14.2 (#696)
See:
- https://github.com/hcoles/pitest/releases/tag/1.14.2
- https://github.com/hcoles/pitest/compare/1.14.1...1.14.2
2023-06-26 12:07:21 +02:00
Picnic-Bot
782a790def Upgrade NullAway 0.10.10 -> 0.10.11 (#695)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/compare/v0.10.10...v0.10.11
2023-06-26 11:31:05 +02:00
Picnic-Bot
706b5f401f Upgrade Checkstyle 10.12.0 -> 10.12.1 (#699)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.12.1
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.12.0...checkstyle-10.12.1
2023-06-26 11:20:21 +02:00
Picnic-Bot
9f500fd5bb Upgrade ossf/scorecard-action v2.1.3 -> v2.2.0 (#697)
And link to the new scorecard report page.

See:
- https://github.com/ossf/scorecard-action/releases/tag/v2.2.0
- https://github.com/ossf/scorecard-action/compare/v2.1.3...v2.2.0
2023-06-26 09:50:25 +02:00
Picnic-Bot
f541cd2e52 Upgrade Swagger 2.2.12 -> 2.2.13 (#698)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.13
- https://github.com/swagger-api/swagger-core/compare/v2.2.12...v2.2.13
2023-06-26 09:20:25 +02:00
Picnic-Bot
fc862aad94 Upgrade maven-clean-plugin 3.2.0 -> 3.3.1 (#693)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MCLEAN%20AND%20fixVersion%20%3E%203.2.0%20AND%20fixVersion%20%3C%3D%203.3.1
- https://github.com/apache/maven-clean-plugin/compare/maven-clean-plugin-3.2.0...maven-clean-plugin-3.3.1
2023-06-23 17:47:37 +02:00
Picnic-Bot
42810bc00c Upgrade Spring Boot 2.7.12 -> 2.7.13 (#694)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.13
- https://github.com/spring-projects/spring-boot/compare/v2.7.12...v2.7.13
2023-06-23 11:11:10 +02:00
Picnic-Bot
f17d736356 Upgrade AutoCommon 1.2.1 -> 1.2.2 (#681)
See:
- https://github.com/google/auto/releases/tag/auto-common-1.2.2
- https://github.com/google/auto/compare/auto-common-1.2.1...auto-common-1.2.2
2023-06-23 10:32:40 +02:00
Picnic-Bot
705acc9164 Upgrade Spring 5.3.27 -> 5.3.28 (#687)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.28
- https://github.com/spring-projects/spring-framework/compare/v5.3.27...v5.3.28
2023-06-23 10:19:13 +02:00
Picnic-Bot
bb969a8b80 Upgrade Mockito 5.3.1 -> 5.4.0 (#689)
See:
- https://github.com/mockito/mockito/releases/tag/v5.4.0
- https://github.com/mockito/mockito/compare/v5.3.1...v5.4.0
2023-06-23 10:09:55 +02:00
Picnic-Bot
c5a700c555 Upgrade Truth 1.1.4 -> 1.1.5 (#688)
See:
- https://github.com/google/truth/releases/tag/v1.1.5
- https://github.com/google/truth/compare/v1.1.4...v1.1.5
2023-06-23 09:56:42 +02:00
Picnic-Bot
2837a04433 Upgrade New Relic Java Agent 8.3.0 -> 8.4.0 (#690)
See:
- https://github.com/newrelic/newrelic-java-agent/releases/tag/v8.4.0
- https://github.com/newrelic/newrelic-java-agent/compare/v8.3.0...v8.4.0
2023-06-22 11:55:19 +02:00
Picnic-Bot
74222e8fa5 Upgrade Arcmutate 1.0.5 -> 1.1.0 (#692) 2023-06-22 09:25:43 +02:00
Stephan Schroevers
dc36ff2c0b [maven-release-plugin] prepare for next development iteration 2023-06-21 21:15:38 +02:00
Stephan Schroevers
09208aa49a [maven-release-plugin] prepare release v0.12.0 2023-06-21 21:15:38 +02:00
Stephan Schroevers
b81ec973a1 Upgrade Error Prone 2.19.1 -> 2.20.0 (#685)
Summary of key changes:
- The `MissingRefasterAnnotation` check was contributed to Error Prone,
  and so is deleted here (multiple checks with the same name are not
  supported).
- Similarly, Error Prone now supports the `-XepAllSuggestionsAsWarnings`
  flag out of the box. So the `ErrorProneFork` class is deleted, as it
  has currently no further use.

While there, include a tweak to `run-mutation-tests.sh`.

Fixes #686.

See:
- https://github.com/google/error-prone/releases/tag/v2.20.0
- https://github.com/google/error-prone/compare/v2.19.1...v2.20.0
- https://github.com/PicnicSupermarket/error-prone/compare/v2.19.1-picnic-1...v2.20.0-picnic-1
2023-06-20 15:52:26 +02:00
Picnic-Bot
8fb57b5bab Upgrade actions/upload-artifact v3.1.1 -> v3.1.2 (#664)
See:
- https://github.com/actions/upload-artifact/releases/tag/v3.1.2
2023-06-20 09:01:33 +02:00
Picnic-Bot
f4aaa5852c Upgrade dawidd6/action-download-artifact v2.24.2 -> v2.27.0 (#669)
See:
- https://github.com/dawidd6/action-download-artifact/compare/v2.26.1...v2.27.0
- https://github.com/dawidd6/action-download-artifact/compare/v2.26.0...v2.26.1
- https://github.com/dawidd6/action-download-artifact/compare/v2.25.0...v2.26.0
- https://github.com/dawidd6/action-download-artifact/compare/v2.24.4...v2.25.0
- https://github.com/dawidd6/action-download-artifact/compare/v2.24.3...v2.24.4
- https://github.com/dawidd6/action-download-artifact/compare/v2.24.2...v2.24.3
2023-06-19 11:54:34 +02:00
Picnic-Bot
2148b7ede4 Upgrade actions/upload-pages-artifact v1.0.5 -> v1.0.9 (#665)
See:
- https://github.com/actions/upload-pages-artifact/releases/tag/v1.0.9
- https://github.com/actions/upload-pages-artifact/releases/tag/v1.0.8
- https://github.com/actions/upload-pages-artifact/releases/tag/v1.0.7
- https://github.com/actions/upload-pages-artifact/releases/tag/v1.0.6
2023-06-19 11:30:48 +02:00
Picnic-Bot
b2320779e7 Upgrade actions/configure-pages v2.1.3 -> v3.0.6 (#673)
See:
- https://github.com/actions/configure-pages/releases/tag/v3.0.6
- https://github.com/actions/configure-pages/releases/tag/v3.0.5
- https://github.com/actions/configure-pages/releases/tag/v3.0.4
- https://github.com/actions/configure-pages/releases/tag/v3.0.3
- https://github.com/actions/configure-pages/releases/tag/v3.0.2
- https://github.com/actions/configure-pages/releases/tag/v3.0.1
- https://github.com/actions/configure-pages/releases/tag/v3.0.0
2023-06-19 11:13:20 +02:00
Picnic-Bot
ef0d65d360 Upgrade actions/deploy-pages v1.2.8 -> v2.0.2 (#674)
See:
- https://github.com/actions/deploy-pages/releases/tag/v2.0.2
- https://github.com/actions/deploy-pages/releases/tag/v2.0.1
- https://github.com/actions/deploy-pages/releases/tag/v2.0.0
2023-06-19 11:01:54 +02:00
Picnic-Bot
d29fde8856 Upgrade actions/checkout v3.1.0 -> v3.5.3 (#667)
See:
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v353
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v352
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v351
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v350
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v340
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v330
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v320
2023-06-19 09:18:01 +02:00
Picnic-Bot
524c7efb48 Upgrade actions/deploy-pages v1.2.3 -> v1.2.8 (#663)
See:
- https://github.com/actions/deploy-pages/releases/tag/v1.2.8
- https://github.com/actions/deploy-pages/releases/tag/v1.2.7
- https://github.com/actions/deploy-pages/releases/tag/v1.2.6
- https://github.com/actions/deploy-pages/releases/tag/v1.2.5
- https://github.com/actions/deploy-pages/releases/tag/v1.2.4
2023-06-19 08:56:31 +02:00
Picnic-Bot
a62acfd7b5 Upgrade Project Reactor 2022.0.7 -> 2022.0.8 (#683)
See:
- https://github.com/reactor/reactor/releases/tag/2022.0.8
- https://github.com/reactor/reactor/compare/2022.0.7...2022.0.8
2023-06-16 16:16:06 +02:00
Picnic-Bot
c40e1d6691 Upgrade actions/setup-java v3.8.0 -> v3.11.0 (#668)
See:
- https://github.com/actions/setup-java/releases/tag/v3.9.0
- https://github.com/actions/setup-java/releases/tag/v3.10.0
- https://github.com/actions/setup-java/releases/tag/v3.11.0
2023-06-16 15:35:04 +02:00
Picnic-Bot
57a22bf9de Upgrade Swagger 2.2.11 -> 2.2.12 (#684)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.12
- https://github.com/swagger-api/swagger-core/compare/v2.2.11...v2.2.12
2023-06-16 15:12:15 +02:00
Picnic-Bot
ec982fe011 Upgrade AutoService 1.1.0 -> 1.1.1 (#682)
See:
- https://github.com/google/auto/releases/tag/auto-service-1.1.1
- https://github.com/google/auto/compare/auto-service-1.1.0...auto-service-1.1.1
2023-06-14 12:35:41 +02:00
Picnic-Bot
1860e24e65 Upgrade Guava 32.0.0-jre -> 32.0.1-jre (#677)
See:
- https://github.com/google/guava/releases/tag/v32.0.1
- https://github.com/google/guava/compare/v32.0.0...v32.0.1
2023-06-12 19:04:31 +02:00
Picnic-Bot
cce248c306 Upgrade Surefire 3.1.0 -> 3.1.2 (#666)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20SUREFIRE%20AND%20fixVersion%20%3E%203.1.0%20AND%20fixVersion%20%3C%3D%203.1.2
- https://github.com/apache/maven-surefire/releases/tag/surefire-3.1.2
- https://github.com/apache/maven-surefire/compare/surefire-3.1.0...surefire-3.1.2
2023-06-12 11:56:20 +02:00
Picnic-Bot
96aca8ea2b Upgrade versions-maven-plugin 2.15.0 -> 2.16.0 (#678)
See:
- https://github.com/mojohaus/versions/releases/tag/2.16.0
- https://github.com/mojohaus/versions-maven-plugin/compare/2.15.0...2.16.0
2023-06-10 14:21:16 +02:00
Picnic-Bot
70d2bf9016 Upgrade license-maven-plugin 2.0.1 -> 2.1.0 (#671)
See:
- https://github.com/mojohaus/license-maven-plugin/releases/tag/2.1.0
- https://github.com/mojohaus/license-maven-plugin/compare/2.0.1...2.1.0
2023-06-08 14:25:34 +02:00
Rick Ossendrijver
cee3c58d07 Configure Renovate to pin GitHub Action digests (#675) 2023-06-08 10:23:05 +02:00
Picnic-Bot
c141ebe05d Upgrade swagger-annotations 2.2.10 -> 2.2.11 (#657)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.11
- https://github.com/swagger-api/swagger-core/compare/v2.2.10...v2.2.11
2023-06-07 11:40:15 +02:00
Picnic-Bot
f5a8c412af Upgrade Byte Buddy 1.14.4 -> 1.14.5 (#658)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.5
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.4...byte-buddy-1.14.5
2023-06-07 10:48:54 +02:00
Picnic-Bot
93440826ed Upgrade Arcmutate 1.0.4 -> 1.0.5 (#656) 2023-06-07 08:02:44 +02:00
Picnic-Bot
80dcae319e Upgrade Jackson 2.15.1 -> 2.15.2 (#652)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.15.2
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.15.1...jackson-bom-2.15.2
2023-06-06 16:30:09 +02:00
Picnic-Bot
7371d03db8 Upgrade Truth 1.1.3 -> 1.1.4 (#653)
See:
- https://github.com/google/truth/releases/tag/v1.1.4
- https://github.com/google/truth/compare/release_1_1_3...v1.1.4
2023-06-06 09:47:09 +02:00
Picnic-Bot
c6b98e61ff Upgrade maven-release-plugin 3.0.0 -> 3.0.1 (#662)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MRELEASE%20AND%20fixVersion%20%3E%203.0.0%20AND%20fixVersion%20%3C%3D%203.0.1
- https://github.com/apache/maven-release/releases/tag/maven-release-3.0.1
- https://github.com/apache/maven-release/compare/maven-release-3.0.0...maven-release-3.0.1
2023-06-06 08:34:35 +02:00
Picnic-Bot
ce8f9f60c8 Upgrade New Relic Java Agent 8.2.0 -> 8.3.0 (#659)
See:
- https://github.com/newrelic/newrelic-java-agent/releases/tag/v8.3.0
- https://github.com/newrelic/newrelic-java-agent/compare/v8.2.0...v8.3.0
2023-06-06 07:50:01 +02:00
Picnic-Bot
cdf27acd9c Upgrade Checker Framework Annotations 3.34.0 -> 3.35.0 (#660)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.35.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.34.0...checker-framework-3.35.0
2023-06-06 07:40:05 +02:00
Picnic-Bot
49e5fd1273 Upgrade extra-enforcer-rules 1.6.2 -> 1.7.0 (#661)
See:
- https://github.com/mojohaus/extra-enforcer-rules/releases/tag/1.7.0
- https://github.com/mojohaus/extra-enforcer-rules/compare/1.6.2...1.7.0
2023-06-06 07:20:46 +02:00
Picnic-Bot
5085db25c0 Upgrade Guava 31.1-jre -> 32.0.0-jre (#650)
See:
- https://guava.dev/releases/32.0.0-jre/api/diffs/
- https://github.com/google/guava/releases/tag/v32.0.0
- https://github.com/google/guava/compare/v31.1...v32.0.0
2023-05-30 16:49:11 +02:00
Picnic-Bot
125d24bc13 Upgrade Checkstyle 10.11.0 -> 10.12.0 (#651)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.12.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.11.0...checkstyle-10.12.0
2023-05-30 08:44:15 +02:00
Picnic-Bot
ea02144bff Upgrade pitest-maven-plugin 1.14.0 -> 1.14.1 (#648)
See:
- https://github.com/hcoles/pitest/releases/tag/1.14.1
- https://github.com/hcoles/pitest/compare/1.14.0...1.14.1
2023-05-26 10:13:47 +02:00
Luke Prananta
cc2c49edc3 Introduce OptionalOrElseGet Refaster rule (#527)
While there, introduce `IsLikelyTrivialComputation` Matcher.
2023-05-26 09:19:51 +02:00
Stephan Schroevers
8bc878a05c Improve AbstractMatcherTestChecker (#599)
These changes enable testing of a wider range of `Matcher` implementations. In
a nutshell:
- The `Matcher` under test is now passed `VisitorState` instances with an
  accurate `TreePath`.
- The `Matcher` under test is no longer consulted for method select and cast
  type expressions, mirroring Refaster behavior.
2023-05-26 08:29:26 +02:00
Picnic-Bot
b399ef8910 Upgrade Spring Boot 2.7.11 -> 2.7.12 (#637)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.12
- https://github.com/spring-projects/spring-boot/compare/v2.7.11...v2.7.12
2023-05-24 19:03:38 +02:00
Picnic-Bot
7dba641a79 Upgrade pitest-junit5-plugin 1.1.2 -> 1.2.0 (#638)
See https://github.com/pitest/pitest-junit5-plugin/compare/1.1.2...1.2.0
2023-05-24 17:20:57 +02:00
Picnic-Bot
da1528129f Upgrade maven-source-plugin 3.2.1 -> 3.3.0 (#643)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MSOURCES%20AND%20fixVersion%20%3E%203.2.1%20AND%20fixVersion%20%3C%3D%203.3.0
- https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.2.1...maven-source-plugin-3.3.0
2023-05-24 17:08:20 +02:00
Picnic-Bot
d0bbc5c14b Upgrade pitest-maven-plugin 1.13.1 -> 1.14.0 (#633)
See:
- https://github.com/hcoles/pitest/releases/tag/1.13.2
- https://github.com/hcoles/pitest/releases/tag/1.14.0
- https://github.com/hcoles/pitest/compare/1.13.1...1.14.0
2023-05-24 16:30:06 +02:00
Picnic-Bot
da532c79c7 Upgrade Pitest Git plugins 1.0.10 -> 1.0.11 (#634) 2023-05-24 16:10:58 +02:00
Picnic-Bot
04e2900a48 Upgrade git-commit-id-maven-plugin 5.0.0 -> 6.0.0 (#635)
See:
- https://github.com/git-commit-id/git-commit-id-maven-plugin/releases/tag/v6.0.0
- https://github.com/git-commit-id/git-commit-id-maven-plugin/compare/v5.0.0...v6.0.0
2023-05-24 16:00:11 +02:00
Picnic-Bot
f097095398 Upgrade AutoService 1.0.1 -> 1.1.0 (#647)
See:
- https://github.com/google/auto/releases/tag/auto-service-1.0.2
- https://github.com/google/auto/releases/tag/auto-service-1.1.0
- https://github.com/google/auto/compare/auto-service-1.0.1...auto-service-1.1.0
2023-05-24 13:25:40 +02:00
Philip Leonard
c53a3f64b6 Qualify non-static TestMode imports across BugChecker test classes (#630)
Prefer non-static imports and qualification of
`BugCheckerRefactoringTestHelper#TestMode` members across bug checker test
classes.
2023-05-23 09:31:59 +02:00
Picnic-Bot
cdfcecc204 Upgrade maven-dependency-plugin 3.5.0 -> 3.6.0 (#646)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MDEP%20AND%20fixVersion%20%3E%203.5.0%20AND%20fixVersion%20%3C%3D%203.6.0
- https://github.com/apache/maven-dependency-plugin/compare/maven-dependency-plugin-3.5.0...maven-dependency-plugin-3.6.0
2023-05-23 08:43:31 +02:00
Picnic-Bot
4f4b3fb865 Upgrade maven-checkstyle-plugin 3.2.2 -> 3.3.0 (#645)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MCHECKSTYLE%20AND%20fixVersion%20%3E%203.2.2%20AND%20fixVersion%20%3C%3D%203.3.0
- https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.2.2...maven-checkstyle-plugin-3.3.0
2023-05-23 07:32:41 +02:00
Picnic-Bot
cce36d24df Upgrade TestNG 7.7.1 -> 7.8.0 (#639)
See:
- https://github.com/testng-team/testng/releases/tag/7.8.0
- https://github.com/testng-team/testng/compare/7.7.1...7.8.0
2023-05-22 08:39:36 +02:00
Picnic-Bot
3bbae43da8 Upgrade swagger-annotations 1.6.10 -> 1.6.11 (#629)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v1.6.11
- https://github.com/swagger-api/swagger-core/compare/v1.6.10...v1.6.11
2023-05-17 13:18:26 +02:00
Picnic-Bot
3217a6974d Upgrade swagger-annotations 2.2.9 -> 2.2.10 (#628)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.10
- https://github.com/swagger-api/swagger-core/compare/v2.2.9...v2.2.10
2023-05-17 12:19:30 +02:00
Picnic-Bot
7b71e4ea3e Upgrade Jackson 2.15.0 -> 2.15.1 (#631)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.15.1
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.15.0...jackson-bom-2.15.1
2023-05-17 11:28:55 +02:00
Stephan Schroevers
3df6dc957d [maven-release-plugin] prepare for next development iteration 2023-05-16 17:38:46 +02:00
Stephan Schroevers
a1ecd816ff [maven-release-plugin] prepare release v0.11.1 2023-05-16 17:38:46 +02:00
Stephan Schroevers
03af05889a Make ThirdPartyLibrary compatible with -source 8 (#627)
When targeting Java 8, `unnamedModule` is not properly initialized,
causing an NPE when trying to load a class from it. In that context
`noModule` should be used instead.

Fixes #626.
2023-05-16 09:53:52 +02:00
Stephan Schroevers
f52a93cc4e [maven-release-plugin] prepare for next development iteration 2023-05-14 17:09:09 +02:00
Stephan Schroevers
610085393c [maven-release-plugin] prepare release v0.11.0 2023-05-14 17:09:08 +02:00
Picnic-Bot
08e55fdfb6 Upgrade Error Prone 2.18.0 -> 2.19.1 (#621)
Resolves #622.

See:
- https://github.com/google/error-prone/releases/tag/v2.19.0
- https://github.com/google/error-prone/releases/tag/v2.19.1
- https://github.com/google/error-prone/compare/v2.18.0...v2.19.1
- https://github.com/PicnicSupermarket/error-prone/compare/v2.18.0-picnic-1...v2.19.1-picnic-1
2023-05-14 17:01:46 +02:00
Luke Prananta
137ec4c573 Introduce StreamsConcat Refaster rule (#619) 2023-05-14 16:48:35 +02:00
Luke Prananta
7cf569cca3 Introduce IsRefasterAsVarargs matcher for use by Refaster templates (#623) 2023-05-14 16:33:32 +02:00
Picnic-Bot
d53db2981c Upgrade build-helper-maven-plugin 3.3.0 -> 3.4.0 (#625)
See:
- https://github.com/mojohaus/build-helper-maven-plugin/releases/tag/3.4.0
- https://github.com/mojohaus/build-helper-maven-plugin/compare/build-helper-maven-plugin-3.3.0...3.4.0
2023-05-13 17:23:50 +02:00
Picnic-Bot
454e8662b1 Upgrade Servlet API 4.0.4 -> 6.0.0 (#119)
See https://github.com/eclipse-ee4j/servlet-api/compare/4.0.4-RELEASE...6.0.0
2023-05-13 17:11:29 +02:00
Picnic-Bot
c2f217f055 Upgrade Project Reactor 2022.0.6 -> 2022.0.7 (#620)
See:
- https://github.com/reactor/reactor/releases/tag/2022.0.7
- https://github.com/reactor/reactor/compare/2022.0.6...2022.0.7
2023-05-12 07:44:33 +02:00
Picnic-Bot
45ced8b9d8 Upgrade Checkstyle 10.10.0 -> 10.11.0 (#624)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.11.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.10.0...checkstyle-10.11.0
2023-05-11 21:50:41 +02:00
Picnic-Bot
666fe0d49c Upgrade license-maven-plugin 2.0.0 -> 2.0.1 (#615)
See:
- https://github.com/mojohaus/license-maven-plugin/releases/tag/2.0.1
- https://github.com/mojohaus/license-maven-plugin/compare/license-maven-plugin-2.0.0...2.0.1
2023-05-08 13:29:07 +02:00
Picnic-Bot
e50a7e1795 Upgrade Surefire 3.0.0 -> 3.1.0 (#618)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20SUREFIRE%20AND%20fixVersion%20%3E%203.0.0%20AND%20fixVersion%20%3C%3D%203.1.0
- https://github.com/apache/maven-surefire/compare/surefire-3.0.0...surefire-3.1.0
2023-05-08 09:15:24 +02:00
Picnic-Bot
f403b988d5 Upgrade maven-gpg-plugin 3.0.1 -> 3.1.0 (#616)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MGPG%20AND%20fixVersion%20%3E%203.0.1%20AND%20fixVersion%20%3C%3D%203.1.0
- https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.0.1...maven-gpg-plugin-3.1.0
2023-05-08 07:24:31 +02:00
Stephan Schroevers
3ee28f2c05 [maven-release-plugin] prepare for next development iteration 2023-05-04 12:47:28 +02:00
250 changed files with 76995 additions and 2529 deletions

View File

@@ -42,7 +42,7 @@ Please replace this sentence with log output, if applicable.
<!-- Please complete the following information: -->
- Operating system (e.g. MacOS Monterey).
- Java version (i.e. `java --version`, e.g. `17.0.7`).
- Java version (i.e. `java --version`, e.g. `17.0.8`).
- Error Prone version (e.g. `2.18.0`).
- Error Prone Support version (e.g. `0.9.0`).

View File

@@ -10,16 +10,16 @@ jobs:
strategy:
matrix:
os: [ ubuntu-22.04 ]
jdk: [ 11.0.19, 17.0.7, 20.0.1 ]
jdk: [ 11.0.20, 17.0.8, 21.0.0 ]
distribution: [ temurin ]
experimental: [ false ]
include:
- os: macos-12
jdk: 17.0.7
- os: macos-14
jdk: 17.0.8
distribution: temurin
experimental: false
- os: windows-2022
jdk: 17.0.7
jdk: 17.0.8
distribution: temurin
experimental: false
runs-on: ${{ matrix.os }}
@@ -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@v3.1.0
with:
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@v3.8.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@v3.1.0
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@fa2c7e4517ed008b1f73e7e0195a9eecf5582cd4 # v1.11.0
with:
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@v3.8.0
with:
java-version: 17.0.7
distribution: temurin
cache: maven
java-version: 17.0.8
java-distribution: temurin
maven-version: 3.9.6
- name: Initialize CodeQL
uses: github/codeql-action/init@v2.2.11
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 install -DskipTests -Dverification.skip
run: mvn -T1C clean package -DskipTests -Dverification.skip
- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@v2.2.11
uses: github/codeql-action/analyze@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # v3.23.2
with:
category: /language:${{ matrix.language }}

View File

@@ -12,15 +12,15 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v3.1.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- uses: ruby/setup-ruby@v1.126.0
- uses: ruby/setup-ruby@bd03e04863f52d169e18a2b190e8fa6b84938215 # v1.170.0
with:
working-directory: ./website
bundler-cache: true
- name: Configure Github Pages
uses: actions/configure-pages@v2.1.3
uses: actions/configure-pages@1f0c5cde4bc74cd7e1254d0cb4de8d49e9068c7d # v4.0.0
- name: Generate documentation
run: ./generate-docs.sh
- name: Build website with Jekyll
@@ -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@v1.0.5
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@v1.2.3
uses: actions/deploy-pages@decdde0ac072f6dcbe43649d82d9c635fff5b4e4 # v4.0.4

View File

@@ -21,16 +21,16 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v3.1.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- name: Run OpenSSF Scorecard analysis
uses: ossf/scorecard-action@v2.1.3
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
with:
results_file: results.sarif
results_format: sarif
publish_results: ${{ github.ref == 'refs/heads/master' }}
- name: Update GitHub's code scanning dashboard
uses: github/codeql-action/upload-sarif@v2.2.11
uses: github/codeql-action/upload-sarif@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@v3.1.0
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@fa2c7e4517ed008b1f73e7e0195a9eecf5582cd4 # v1.11.0
with:
fetch-depth: 2
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@v3.8.0
with:
java-version: 17.0.7
distribution: temurin
cache: maven
checkout-fetch-depth: 2
java-version: 17.0.8
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@v3.1.1
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@v3.1.0
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@fa2c7e4517ed008b1f73e7e0195a9eecf5582cd4 # v1.11.0
with:
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@v3.8.0
with:
java-version: 17.0.7
distribution: temurin
cache: maven
java-version: 17.0.8
java-distribution: temurin
maven-version: 3.9.6
- name: Download Pitest analysis artifact
uses: dawidd6/action-download-artifact@v2.24.2
uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
name: pitest-reports

View File

@@ -0,0 +1,39 @@
# If requested by means of a pull request comment, runs integration tests
# against the project, using the code found on the pull request branch.
# XXX: Generalize this to a matrix build of multiple integration tests,
# possibly using multiple JDK or OS versions.
# XXX: Investigate whether the comment can specify which integration tests run
# run. See this example of a dynamic build matrix:
# https://docs.github.com/en/actions/learn-github-actions/expressions#example-returning-a-json-object
name: "Integration tests"
on:
issue_comment:
types: [ created ]
permissions:
contents: read
jobs:
run-integration-tests:
name: On-demand integration test
if: |
github.event.issue.pull_request && contains(github.event.comment.body, '/integration-test')
runs-on: ubuntu-22.04
steps:
- 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
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.sh "${{ runner.temp }}/artifacts"
- name: Upload artifacts on failure
if: ${{ failure() }}
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
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@v3.1.0
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@fa2c7e4517ed008b1f73e7e0195a9eecf5582cd4 # v1.11.0
with:
fetch-depth: 0
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@v3.8.0
with:
java-version: 17.0.7
distribution: temurin
cache: maven
checkout-fetch-depth: 0
java-version: 17.0.8
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

3
.gitignore vendored
View File

@@ -9,3 +9,6 @@
target
*.iml
*.swp
# The Git repositories checked out by the integration test framework.
integration-tests/.repos

View File

@@ -1,5 +1,8 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"helpers:pinGitHubActionDigests"
],
"packageRules": [
{
"matchPackagePatterns": [
@@ -9,10 +12,11 @@
"separateMinorPatch": true
},
{
"matchPackagePatterns": [
"^ruby\\/setup-ruby$"
"matchDepNames": [
"github/codeql-action",
"ruby/setup-ruby"
],
"schedule": "* * 1 * *"
"schedule": "every 4 weeks on Monday"
}
],
"reviewers": [

View File

@@ -80,6 +80,6 @@ Some pointers:
[error-prone-support-developing]: https://github.com/PicnicSupermarket/error-prone-support/tree/master#-developing-error-prone-support
[error-prone-support-full-build]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-full-build.sh
[error-prone-support-issues]: https://github.com/PicnicSupermarket/error-prone-support/issues
[error-prone-support-mutation-tests]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-mutation-tests.sh
[error-prone-support-mutation-tests]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-branch-mutation-tests.sh
[error-prone-support-patch]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/apply-error-prone-suggestions.sh
[error-prone-support-pulls]: https://github.com/PicnicSupermarket/error-prone-support/pulls

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

@@ -15,9 +15,11 @@ focussing on maintainability, consistency and avoidance of common pitfalls.
> Error Prone is a static analysis tool for Java that catches common
> programming mistakes at compile-time.
Read more on how Picnic uses Error Prone (Support) in the blog post [_Picnic
loves Error Prone: producing high-quality and consistent Java
code_][picnic-blog-ep-post].
To learn more about Error Prone (Support), how you can start using Error Prone
in practice, and how we use it at Picnic, watch the conference talk
[_Automating away bugs with Error Prone in practice_][conference-talk]. Also
consider checking out the blog post [_Picnic loves Error Prone: producing
high-quality and consistent Java code_][picnic-blog-ep-post].
[![Maven Central][maven-central-badge]][maven-central-search]
[![Reproducible Builds][reproducible-builds-badge]][reproducible-builds-report]
@@ -63,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. -->
@@ -92,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>
@@ -223,10 +225,13 @@ Other highly relevant commands:
Before running this command, make sure to have installed the project (`mvn
clean install`) and make sure that the current working directory does not
contain unstaged or uncommited changes.
- [`./run-mutation-tests.sh`][script-run-mutation-tests] runs mutation tests
using [Pitest][pitest]. The results can be reviewed by opening the respective
`target/pit-reports/index.html` files. For more information check the [PIT
Maven plugin][pitest-maven].
- [`./run-branch-mutation-tests.sh`][script-run-branch-mutation-tests] uses
[Pitest][pitest] to run mutation tests against code that is modified relative
to the upstream default branch. The results can be reviewed by opening the
respective `target/pit-reports/index.html` files. One can use
[`./run-mutation-tests.sh`][script-run-mutation-tests] to run mutation tests
against _all_ code in the current working directory. For more information
check the [PIT Maven plugin][pitest-maven].
When running the project's tests in IntelliJ IDEA, you might see the following
error:
@@ -262,6 +267,7 @@ channel; please see our [security policy][security] for details.
[bug-checks-identity-conversion]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/IdentityConversion.java
[codeql-badge]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/codeql.yml/badge.svg?branch=master&event=push
[codeql-master]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/codeql.yml?query=branch:master+event:push
[conference-talk]: https://www.youtube.com/watch?v=-47WD-3wKBs
[contributing]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/CONTRIBUTING.md
[contributing-pull-request]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/CONTRIBUTING.md#-opening-a-pull-request
[error-prone-bugchecker]: https://github.com/google/error-prone/blob/master/check_api/src/main/java/com/google/errorprone/bugpatterns/BugChecker.java
@@ -271,8 +277,8 @@ channel; please see our [security policy][security] for details.
[error-prone-installation-guide]: https://errorprone.info/docs/installation#maven
[error-prone-orig-repo]: https://github.com/google/error-prone
[error-prone-pull-3301]: https://github.com/google/error-prone/pull/3301
[github-actions-build-badge]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yaml/badge.svg
[github-actions-build-master]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yaml?query=branch:master&event=push
[github-actions-build-badge]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yml/badge.svg
[github-actions-build-master]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yml?query=branch:master&event=push
[google-java-format]: https://github.com/google/google-java-format
[idea-288052]: https://youtrack.jetbrains.com/issue/IDEA-288052
[license-badge]: https://img.shields.io/github/license/PicnicSupermarket/error-prone-support
@@ -283,7 +289,7 @@ channel; please see our [security policy][security] for details.
[openssf-best-practices-badge]: https://bestpractices.coreinfrastructure.org/projects/7199/badge
[openssf-best-practices-checklist]: https://bestpractices.coreinfrastructure.org/projects/7199
[openssf-scorecard-badge]: https://img.shields.io/ossf-scorecard/github.com/PicnicSupermarket/error-prone-support?label=openssf%20scorecard
[openssf-scorecard-report]: https://api.securityscorecards.dev/projects/github.com/PicnicSupermarket/error-prone-support
[openssf-scorecard-report]: https://securityscorecards.dev/viewer/?uri=github.com/PicnicSupermarket/error-prone-support
[picnic-blog-ep-post]: https://blog.picnic.nl/picnic-loves-error-prone-producing-high-quality-and-consistent-java-code-b8a566be6886
[picnic-blog]: https://blog.picnic.nl
[pitest-badge]: https://img.shields.io/badge/-Mutation%20tested%20with%20PIT-blue.svg
@@ -296,6 +302,7 @@ channel; please see our [security policy][security] for details.
[reproducible-builds-badge]: https://img.shields.io/badge/Reproducible_Builds-ok-success?labelColor=1e5b96
[reproducible-builds-report]: https://github.com/jvm-repo-rebuild/reproducible-central/blob/master/content/tech/picnic/error-prone-support/error-prone-support/README.md
[script-apply-error-prone-suggestions]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/apply-error-prone-suggestions.sh
[script-run-branch-mutation-tests]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-branch-mutation-tests.sh
[script-run-full-build]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-full-build.sh
[script-run-mutation-tests]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-mutation-tests.sh
[security]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/SECURITY.md

View File

@@ -1,7 +1,7 @@
# Arcmutate license for Error Prone Support, requested by sending an email to
# support@arcmutate.com.
expires=07/11/2023
expires=27/10/2025
keyVersion=1
signature=MhZxMbnO6UovNfllM0JuVWkZyvRT3/G5o/uT0Mm36c7200VpZNVu03gTAGivnl9W5RzvZhfpIHccuQ5ctjQkrqhsFSrl4fyqPqu3y5V2fsHIdFXP/G72EGj6Kay9ndLpaEHalqE0bEwxdnHMzEYq5y3O9vUPv8MhUl57xk+rvBo\=
signature=aQLVt0J//7nXDAlJuBe9ru7Dq6oApcLh17rxsgHoJqBkUCd2zvrtRxkcPm5PmF1I8gBDT9PHb+kTf6Kcfz+D1fT0wRrZv38ip56521AQPD6zjRSqak9O2Gisjo+QTPMD7oS009aSWKzQ1SMdtuZ+KIRvw4Gl+frtYzexqnGWEUQ\=
packages=tech.picnic.errorprone.*
type=OSSS

View File

@@ -5,13 +5,14 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.10.0</version>
<version>0.14.1-SNAPSHOT</version>
</parent>
<artifactId>documentation-support</artifactId>
<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,18 +4,22 @@ 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;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.VisitorState;
import com.google.errorprone.annotations.Immutable;
import com.google.errorprone.util.ASTHelpers;
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 com.sun.tools.javac.util.Context;
import java.net.URI;
import java.util.Optional;
import javax.lang.model.element.AnnotationValue;
import tech.picnic.errorprone.documentation.BugPatternExtractor.BugPatternDocumentation;
@@ -23,29 +27,40 @@ import tech.picnic.errorprone.documentation.BugPatternExtractor.BugPatternDocume
* An {@link Extractor} that describes how to extract data from a {@code @BugPattern} annotation.
*/
@Immutable
final class BugPatternExtractor implements Extractor<BugPatternDocumentation> {
@Override
public BugPatternDocumentation extract(ClassTree tree, Context context) {
ClassSymbol symbol = ASTHelpers.getSymbol(tree);
BugPattern annotation = symbol.getAnnotation(BugPattern.class);
requireNonNull(annotation, "BugPattern annotation must be present");
@AutoService(Extractor.class)
@SuppressWarnings("rawtypes" /* See https://github.com/google/auto/issues/870. */)
public final class BugPatternExtractor implements Extractor<BugPatternDocumentation> {
/** Instantiates a new {@link BugPatternExtractor} instance. */
public BugPatternExtractor() {}
return new AutoValue_BugPatternExtractor_BugPatternDocumentation(
symbol.getQualifiedName().toString(),
annotation.name().isEmpty() ? tree.getSimpleName().toString() : annotation.name(),
ImmutableList.copyOf(annotation.altNames()),
annotation.link(),
ImmutableList.copyOf(annotation.tags()),
annotation.summary(),
annotation.explanation(),
annotation.severity(),
annotation.disableable(),
annotation.documentSuppression() ? getSuppressionAnnotations(tree) : ImmutableList.of());
@Override
public String identifier() {
return "bugpattern";
}
@Override
public boolean canExtract(ClassTree tree) {
return ASTHelpers.hasDirectAnnotationWithSimpleName(tree, BugPattern.class.getSimpleName());
public Optional<BugPatternDocumentation> tryExtract(ClassTree tree, VisitorState state) {
ClassSymbol symbol = ASTHelpers.getSymbol(tree);
BugPattern annotation = symbol.getAnnotation(BugPattern.class);
if (annotation == null) {
return Optional.empty();
}
return Optional.of(
BugPatternDocumentation.create(
state.getPath().getCompilationUnit().getSourceFile().toUri(),
symbol.getQualifiedName().toString(),
annotation.name().isEmpty() ? tree.getSimpleName().toString() : annotation.name(),
ImmutableList.copyOf(annotation.altNames()),
annotation.link(),
ImmutableList.copyOf(annotation.tags()),
annotation.summary(),
annotation.explanation(),
annotation.severity(),
annotation.disableable(),
annotation.documentSuppression()
? getSuppressionAnnotations(tree)
: ImmutableList.of()));
}
/**
@@ -79,7 +94,36 @@ final class BugPatternExtractor implements Extractor<BugPatternDocumentation> {
}
@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

@@ -0,0 +1,285 @@
package tech.picnic.errorprone.documentation;
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;
import com.google.errorprone.VisitorState;
import com.google.errorprone.annotations.Immutable;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.util.ASTHelpers;
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;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.TestCases;
/**
* An {@link Extractor} that describes how to extract data from classes that test a {@code
* BugChecker}.
*/
// XXX: Handle other methods from `{BugCheckerRefactoring,Compilation}TestHelper`:
// - Indicate which custom arguments are specified, if any.
// - For replacement tests, indicate which `FixChooser` is used.
// - ... (We don't use all optional features; TBD what else to support.)
@Immutable
@AutoService(Extractor.class)
@SuppressWarnings("rawtypes" /* See https://github.com/google/auto/issues/870. */)
public final class BugPatternTestExtractor implements Extractor<TestCases> {
/** Instantiates a new {@link BugPatternTestExtractor} instance. */
public BugPatternTestExtractor() {}
@Override
public String identifier() {
return "bugpattern-test";
}
@Override
public Optional<TestCases> tryExtract(ClassTree tree, VisitorState state) {
BugPatternTestCollector collector = new BugPatternTestCollector();
collector.scan(tree, state);
return Optional.of(collector.getCollectedTests())
.filter(not(ImmutableList::isEmpty))
.map(
tests ->
new AutoValue_BugPatternTestExtractor_TestCases(
state.getPath().getCompilationUnit().getSourceFile().toUri(),
ASTHelpers.getSymbol(tree).className(),
tests));
}
private static final class BugPatternTestCollector
extends TreeScanner<@Nullable Void, VisitorState> {
private static final Matcher<ExpressionTree> COMPILATION_HELPER_DO_TEST =
instanceMethod()
.onDescendantOf("com.google.errorprone.CompilationTestHelper")
.named("doTest");
private static final Matcher<ExpressionTree> TEST_HELPER_NEW_INSTANCE =
staticMethod()
.onDescendantOfAny(
"com.google.errorprone.CompilationTestHelper",
"com.google.errorprone.BugCheckerRefactoringTestHelper")
.named("newInstance")
.withParameters(Class.class.getCanonicalName(), Class.class.getCanonicalName());
private static final Matcher<ExpressionTree> IDENTIFICATION_SOURCE_LINES =
instanceMethod()
.onDescendantOf("com.google.errorprone.CompilationTestHelper")
.named("addSourceLines");
private static final Matcher<ExpressionTree> REPLACEMENT_DO_TEST =
instanceMethod()
.onDescendantOf("com.google.errorprone.BugCheckerRefactoringTestHelper")
.named("doTest");
private static final Matcher<ExpressionTree> REPLACEMENT_EXPECT_UNCHANGED =
instanceMethod()
.onDescendantOf("com.google.errorprone.BugCheckerRefactoringTestHelper.ExpectOutput")
.named("expectUnchanged");
private static final Matcher<ExpressionTree> REPLACEMENT_OUTPUT_SOURCE_LINES =
instanceMethod()
.onDescendantOf("com.google.errorprone.BugCheckerRefactoringTestHelper.ExpectOutput")
.namedAnyOf("addOutputLines", "expectUnchanged");
private final List<TestCase> collectedTestCases = new ArrayList<>();
private ImmutableList<TestCase> getCollectedTests() {
return ImmutableList.copyOf(collectedTestCases);
}
@Override
public @Nullable Void visitMethodInvocation(MethodInvocationTree node, VisitorState state) {
boolean isReplacementTest = REPLACEMENT_DO_TEST.matches(node, state);
if (isReplacementTest || COMPILATION_HELPER_DO_TEST.matches(node, state)) {
getClassUnderTest(node, state)
.ifPresent(
classUnderTest -> {
List<TestEntry> entries = new ArrayList<>();
if (isReplacementTest) {
extractReplacementTestCases(node, entries, state);
} else {
extractIdentificationTestCases(node, entries, state);
}
if (!entries.isEmpty()) {
collectedTestCases.add(
new AutoValue_BugPatternTestExtractor_TestCase(
classUnderTest, ImmutableList.copyOf(entries).reverse()));
}
});
}
return super.visitMethodInvocation(node, state);
}
private static Optional<String> getClassUnderTest(
MethodInvocationTree tree, VisitorState state) {
if (TEST_HELPER_NEW_INSTANCE.matches(tree, state)) {
return Optional.ofNullable(ASTHelpers.getSymbol(tree.getArguments().get(0)))
.filter(s -> !s.type.allparams().isEmpty())
.map(s -> s.type.allparams().get(0).tsym.getQualifiedName().toString());
}
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
return receiver instanceof MethodInvocationTree
? getClassUnderTest((MethodInvocationTree) receiver, state)
: Optional.empty();
}
private static void extractIdentificationTestCases(
MethodInvocationTree tree, List<TestEntry> sink, VisitorState state) {
if (IDENTIFICATION_SOURCE_LINES.matches(tree, state)) {
String path = ASTHelpers.constValue(tree.getArguments().get(0), String.class);
Optional<String> sourceCode =
getSourceCode(tree).filter(s -> s.contains("// BUG: Diagnostic"));
if (path != null && sourceCode.isPresent()) {
sink.add(
new AutoValue_BugPatternTestExtractor_IdentificationTestEntry(
path, sourceCode.orElseThrow()));
}
}
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
if (receiver instanceof MethodInvocationTree) {
extractIdentificationTestCases((MethodInvocationTree) receiver, sink, state);
}
}
private static void extractReplacementTestCases(
MethodInvocationTree tree, List<TestEntry> sink, VisitorState state) {
if (REPLACEMENT_OUTPUT_SOURCE_LINES.matches(tree, state)) {
/*
* Retrieve the method invocation that contains the input source code. Note that this cast
* is safe, because this code is guarded by an earlier call to `#getClassUnderTest(..)`,
* which ensures that `tree` is part of a longer method invocation chain.
*/
MethodInvocationTree inputTree = (MethodInvocationTree) ASTHelpers.getReceiver(tree);
String path = ASTHelpers.constValue(inputTree.getArguments().get(0), String.class);
Optional<String> inputCode = getSourceCode(inputTree);
if (path != null && inputCode.isPresent()) {
Optional<String> outputCode =
REPLACEMENT_EXPECT_UNCHANGED.matches(tree, state) ? inputCode : getSourceCode(tree);
if (outputCode.isPresent() && !inputCode.equals(outputCode)) {
sink.add(
new AutoValue_BugPatternTestExtractor_ReplacementTestEntry(
path, inputCode.orElseThrow(), outputCode.orElseThrow()));
}
}
}
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
if (receiver instanceof MethodInvocationTree) {
extractReplacementTestCases((MethodInvocationTree) receiver, sink, state);
}
}
// XXX: This logic is duplicated in `ErrorProneTestSourceFormat`. Can we do better?
private static Optional<String> getSourceCode(MethodInvocationTree tree) {
List<? extends ExpressionTree> sourceLines =
tree.getArguments().subList(1, tree.getArguments().size());
StringBuilder source = new StringBuilder();
for (ExpressionTree sourceLine : sourceLines) {
String value = ASTHelpers.constValue(sourceLine, String.class);
if (value == null) {
return Optional.empty();
}
source.append(value).append('\n');
}
return Optional.of(source.toString());
}
}
@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();
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,24 +1,21 @@
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;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskEvent.Kind;
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;
import java.nio.file.Paths;
import java.util.ServiceLoader;
import javax.tools.JavaFileObject;
/**
@@ -27,8 +24,12 @@ import javax.tools.JavaFileObject;
*/
// XXX: Find a better name for this class; it doesn't generate documentation per se.
final class DocumentationGeneratorTaskListener implements TaskListener {
private static final ObjectMapper OBJECT_MAPPER =
new ObjectMapper().setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
@SuppressWarnings({"rawtypes", "unchecked"})
private static final ImmutableList<Extractor<?>> EXTRACTORS =
(ImmutableList)
ImmutableList.copyOf(
ServiceLoader.load(
Extractor.class, DocumentationGeneratorTaskListener.class.getClassLoader()));
private final Context context;
private final Path docsPath;
@@ -51,19 +52,25 @@ final class DocumentationGeneratorTaskListener implements TaskListener {
return;
}
ClassTree classTree = JavacTrees.instance(context).getTree(taskEvent.getTypeElement());
JavaFileObject sourceFile = taskEvent.getSourceFile();
if (classTree == null || sourceFile == null) {
CompilationUnitTree compilationUnit = taskEvent.getCompilationUnit();
ClassTree classTree = JavacTrees.instance(context).getTree(taskEvent.getTypeElement());
if (sourceFile == null || compilationUnit == null || classTree == null) {
return;
}
ExtractorType.findMatchingType(classTree)
.ifPresent(
extractorType ->
writeToFile(
extractorType.getIdentifier(),
getSimpleClassName(sourceFile.toUri()),
extractorType.getExtractor().extract(classTree, context)));
VisitorState state =
VisitorState.createForUtilityPurposes(context)
.withPath(new TreePath(new TreePath(compilationUnit), classTree));
for (Extractor<?> extractor : EXTRACTORS) {
extractor
.tryExtract(classTree, state)
.ifPresent(
data ->
writeToFile(
extractor.identifier(), getSimpleClassName(sourceFile.toUri()), data));
}
}
private void createDocsDirectory() {
@@ -76,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

@@ -1,8 +1,9 @@
package tech.picnic.errorprone.documentation;
import com.google.errorprone.VisitorState;
import com.google.errorprone.annotations.Immutable;
import com.sun.source.tree.ClassTree;
import com.sun.tools.javac.util.Context;
import java.util.Optional;
/**
* Interface implemented by classes that define how to extract data of some type {@link T} from a
@@ -13,21 +14,20 @@ import com.sun.tools.javac.util.Context;
@Immutable
interface Extractor<T> {
/**
* Extracts and returns an instance of {@link T} using the provided arguments.
* Returns the unique identifier of this extractor.
*
* @param tree The {@link ClassTree} to analyze and from which to extract instances of {@link T}.
* @param context The {@link Context} in which the current compilation takes place.
* @return A non-null instance of {@link T}.
* @return A non-{@code null} string.
*/
// XXX: Drop `Context` parameter unless used.
T extract(ClassTree tree, Context context);
String identifier();
/**
* Tells whether this {@link Extractor} can extract documentation content from the given {@link
* ClassTree}.
* Attempts to extract an instance of type {@link T} using the provided arguments.
*
* @param tree The {@link ClassTree} of interest.
* @return {@code true} iff data extraction is supported.
* @param tree The {@link ClassTree} to analyze and from which to extract an instance of type
* {@link T}.
* @param state A {@link VisitorState} describing the context in which the given {@link ClassTree}
* is found.
* @return An instance of type {@link T}, if possible.
*/
boolean canExtract(ClassTree tree);
Optional<T> tryExtract(ClassTree tree, VisitorState state);
}

View File

@@ -1,36 +0,0 @@
package tech.picnic.errorprone.documentation;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.sun.source.tree.ClassTree;
import java.util.EnumSet;
import java.util.Optional;
/** An enumeration of {@link Extractor} types. */
enum ExtractorType {
BUG_PATTERN("bugpattern", new BugPatternExtractor());
private static final ImmutableSet<ExtractorType> TYPES =
Sets.immutableEnumSet(EnumSet.allOf(ExtractorType.class));
private final String identifier;
private final Extractor<?> extractor;
ExtractorType(String identifier, Extractor<?> extractor) {
this.identifier = identifier;
this.extractor = extractor;
}
String getIdentifier() {
return identifier;
}
@SuppressWarnings("java:S1452" /* The extractor returns data of an unspecified type. */)
Extractor<?> getExtractor() {
return extractor;
}
static Optional<ExtractorType> findMatchingType(ClassTree tree) {
return TYPES.stream().filter(type -> type.getExtractor().canExtract(tree)).findFirst();
}
}

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,22 +1,17 @@
package tech.picnic.errorprone.documentation;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static java.nio.charset.StandardCharsets.UTF_8;
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 static org.assertj.core.api.Assertions.assertThatThrownBy;
import com.google.common.io.Resources;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugPattern;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.sun.source.tree.ClassTree;
import java.io.IOException;
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
@@ -32,7 +27,7 @@ final class BugPatternExtractorTest {
}
@Test
void minimalBugPattern(@TempDir Path outputDirectory) throws IOException {
void minimalBugPattern(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"MinimalBugChecker.java",
@@ -45,14 +40,25 @@ final class BugPatternExtractorTest {
"@BugPattern(summary = \"MinimalBugChecker summary\", severity = SeverityLevel.ERROR)",
"public final class MinimalBugChecker extends BugChecker {}");
verifyFileMatchesResource(
verifyGeneratedFileContent(
outputDirectory,
"bugpattern-MinimalBugChecker.json",
"bugpattern-documentation-minimal.json");
"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",
@@ -76,14 +82,25 @@ final class BugPatternExtractorTest {
" suppressionAnnotations = {BugPattern.class, Test.class})",
"public final class CompleteBugChecker extends BugChecker {}");
verifyFileMatchesResource(
verifyGeneratedFileContent(
outputDirectory,
"bugpattern-CompleteBugChecker.json",
"bugpattern-documentation-complete.json");
"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",
@@ -99,55 +116,27 @@ final class BugPatternExtractorTest {
" documentSuppression = false)",
"public final class UndocumentedSuppressionBugPattern extends BugChecker {}");
verifyFileMatchesResource(
verifyGeneratedFileContent(
outputDirectory,
"bugpattern-UndocumentedSuppressionBugPattern.json",
"bugpattern-documentation-undocumented-suppression.json");
}
@Test
void bugPatternAnnotationIsAbsent() {
CompilationTestHelper.newInstance(TestChecker.class, getClass())
.addSourceLines(
"TestChecker.java",
"import com.google.errorprone.bugpatterns.BugChecker;",
"UndocumentedSuppressionBugPattern",
BugPatternDocumentation.create(
URI.create("file:///UndocumentedSuppressionBugPattern.java"),
"pkg.UndocumentedSuppressionBugPattern",
"UndocumentedSuppressionBugPattern",
ImmutableList.of(),
"",
"// BUG: Diagnostic contains: Can extract: false",
"public final class TestChecker extends BugChecker {}")
.doTest();
ImmutableList.of(),
"UndocumentedSuppressionBugPattern summary",
"",
WARNING,
/* canDisable= */ true,
ImmutableList.of()));
}
private static void verifyFileMatchesResource(
Path outputDirectory, String fileName, String resourceName) throws IOException {
assertThat(outputDirectory.resolve(fileName))
.content(UTF_8)
.isEqualToIgnoringWhitespace(getResource(resourceName));
}
// XXX: Once we support only JDK 15+, drop this method in favour of including the resources as
// text blocks in this class. (This also requires renaming the `verifyFileMatchesResource`
// method.)
private static String getResource(String resourceName) throws IOException {
return Resources.toString(
Resources.getResource(BugPatternExtractorTest.class, resourceName), UTF_8);
}
/** A {@link BugChecker} that validates the {@link BugPatternExtractor}. */
@BugPattern(summary = "Validates `BugPatternExtractor` extraction", severity = ERROR)
public static final class TestChecker extends BugChecker implements ClassTreeMatcher {
private static final long serialVersionUID = 1L;
@Override
public Description matchClass(ClassTree tree, VisitorState state) {
BugPatternExtractor extractor = new BugPatternExtractor();
assertThatThrownBy(() -> extractor.extract(tree, state.context))
.isInstanceOf(NullPointerException.class)
.hasMessage("BugPattern annotation must be present");
return buildDescription(tree)
.setMessage(String.format("Can extract: %s", extractor.canExtract(tree)))
.build();
}
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

@@ -0,0 +1,558 @@
package tech.picnic.errorprone.documentation;
import static org.assertj.core.api.Assertions.assertThat;
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
void noTestClass(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerWithoutAnnotation.java",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"public final class TestCheckerWithoutAnnotation extends BugChecker {}");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@Test
void noDoTestInvocation(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class TestCheckerTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\");",
"",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\");",
" }",
"}");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@Test
void nullBugCheckerInstance(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class TestCheckerTest {",
" void m() {",
" CompilationTestHelper.newInstance((Class<BugChecker>) null, getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance((Class<BugChecker>) null, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .doTest();",
" }",
"}");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@Test
void rawBugCheckerInstance(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class TestCheckerTest {",
" private static class TestChecker extends BugChecker {}",
"",
" @SuppressWarnings(\"unchecked\")",
" void m() {",
" @SuppressWarnings(\"rawtypes\")",
" Class bugChecker = TestChecker.class;",
"",
" CompilationTestHelper.newInstance(bugChecker, getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance(bugChecker, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .doTest();",
" }",
"}");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@Test
void scannerSupplierInstance(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"import com.google.errorprone.scanner.ScannerSupplier;",
"",
"final class TestCheckerTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(",
" ScannerSupplier.fromBugCheckerClasses(TestChecker.class), getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance(",
" ScannerSupplier.fromBugCheckerClasses(TestChecker.class), getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .doTest();",
" }",
"}");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@Test
void nonCompileTimeConstantStrings(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class TestCheckerTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .addSourceLines(toString() + \"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .addSourceLines(\"B.java\", \"// BUG: Diagnostic contains:\", \"class B {}\", toString())",
" .doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .addInputLines(toString() + \"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .addInputLines(\"B.java\", \"class B {}\", toString())",
" .addOutputLines(\"B.java\", \"class B { /* This is a change. */ }\")",
" .addInputLines(\"C.java\", \"class C {}\")",
" .addOutputLines(\"C.java\", \"class C { /* This is a change. */ }\", toString())",
" .doTest();",
" }",
"}");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@Test
void nonFluentTestHelperExpressions(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class TestCheckerTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper testHelper =",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .addSourceLines(\"A.java\", \"class A {}\");",
" testHelper.doTest();",
"",
" BugCheckerRefactoringTestHelper.ExpectOutput expectedOutput =",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .addInputLines(\"A.java\", \"class A {}\");",
" expectedOutput.addOutputLines(\"A.java\", \"class A {}\").doTest();",
" expectedOutput.expectUnchanged().doTest();",
" }",
"}");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@Test
void noSource(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class TestCheckerTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass()).doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass()).doTest();",
" }",
"}");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@Test
void noDiagnostics(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class TestCheckerTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .addSourceLines(\"A.java\", \"class A {}\")",
" .doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A {}\")",
" .addInputLines(\"B.java\", \"class B {}\")",
" .expectUnchanged()",
" .doTest();",
" }",
"}");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@Test
void singleFileCompilationTestHelper(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"SingleFileCompilationTestHelperTest.java",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class SingleFileCompilationTestHelperTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .doTest();",
" }",
"}");
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) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"SingleFileCompilationTestHelperWithSetArgsTest.java",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class SingleFileCompilationTestHelperWithSetArgsTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .setArgs(\"-XepAllSuggestionsAsWarnings\")",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .doTest();",
" }",
"}");
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) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"MultiFileCompilationTestHelperTest.java",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class MultiFileCompilationTestHelperTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .addSourceLines(\"B.java\", \"// BUG: Diagnostic contains:\", \"class B {}\")",
" .doTest();",
" }",
"}");
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) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"SingleFileBugCheckerRefactoringTestHelperTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class SingleFileBugCheckerRefactoringTestHelperTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .doTest();",
" }",
"}");
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) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;",
"import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .setArgs(\"-XepAllSuggestionsAsWarnings\")",
" .setFixChooser(FixChoosers.SECOND)",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .doTest(TestMode.TEXT_MATCH);",
" }",
"}");
verifyGeneratedFileContent(
outputDirectory,
"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) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"MultiFileBugCheckerRefactoringTestHelperTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class MultiFileBugCheckerRefactoringTestHelperTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .addInputLines(\"B.java\", \"class B {}\")",
" .addOutputLines(\"B.java\", \"class B { /* This is a change. */ }\")",
" .doTest();",
" }",
"}");
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) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"CompilationAndBugCheckerRefactoringTestHelpersTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class CompilationAndBugCheckerRefactoringTestHelpersTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .doTest();",
" }",
"}");
verifyGeneratedFileContent(
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) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.java",
"package pkg;",
"",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest {",
" private static class CustomTestChecker extends BugChecker {}",
"",
" private static class CustomTestChecker2 extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(CustomTestChecker.class, getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance(CustomTestChecker2.class, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .doTest();",
" }",
"}");
verifyGeneratedFileContent(
outputDirectory,
"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, TestCases expected) {
assertThat(outputDirectory.resolve(String.format("bugpattern-test-%s.json", testClass)))
.exists()
.returns(expected, path -> Json.read(path, TestCases.class));
}
}

View File

@@ -1,5 +1,7 @@
package tech.picnic.errorprone.documentation;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.FileManagers;
import com.google.errorprone.FileObjects;
@@ -7,39 +9,66 @@ import com.sun.tools.javac.api.JavacTaskImpl;
import com.sun.tools.javac.api.JavacTool;
import com.sun.tools.javac.file.JavacFileManager;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import javax.tools.Diagnostic;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
// XXX: Generalize and move this class so that it can also be used by `refaster-compiler`.
// XXX: Add support for this class to the `ErrorProneTestHelperSourceFormat` check.
// XXX: This class is supported by the `ErrorProneTestHelperSourceFormat` check, but until that
// support is covered by unit tests, make sure to update that logic if this class or its methods are
// moved/renamed.
public final class Compilation {
private Compilation() {}
public static void compileWithDocumentationGenerator(
Path outputDirectory, String fileName, String... lines) {
compileWithDocumentationGenerator(outputDirectory.toAbsolutePath().toString(), fileName, lines);
Path outputDirectory, String path, String... lines) {
compileWithDocumentationGenerator(outputDirectory.toAbsolutePath().toString(), path, lines);
}
public static void compileWithDocumentationGenerator(
String outputDirectory, String fileName, String... lines) {
String outputDirectory, String path, String... lines) {
/*
* The compiler options specified here largely match those used by Error Prone's
* `CompilationTestHelper`. A key difference is the stricter linting configuration. When
* compiling using JDK 21+, these lint options also require that certain JDK modules are
* explicitly exported.
*/
compile(
ImmutableList.of("-Xplugin:DocumentationGenerator -XoutputDirectory=" + outputDirectory),
FileObjects.forSourceLines(fileName, lines));
ImmutableList.of(
"--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
"-encoding",
"UTF-8",
"-parameters",
"-proc:none",
"-Werror",
"-Xlint:all,-serial",
"-Xplugin:DocumentationGenerator -XoutputDirectory=" + outputDirectory,
"-XDdev",
"-XDcompilePolicy=simple"),
FileObjects.forSourceLines(path, lines));
}
private static void compile(ImmutableList<String> options, JavaFileObject javaFileObject) {
JavacFileManager javacFileManager = FileManagers.testFileManager();
JavaCompiler compiler = JavacTool.create();
List<Diagnostic<?>> diagnostics = new ArrayList<>();
JavacTaskImpl task =
(JavacTaskImpl)
compiler.getTask(
null,
javacFileManager,
null,
diagnostics::add,
options,
ImmutableList.of(),
ImmutableList.of(javaFileObject));
task.call();
Boolean result = task.call();
assertThat(diagnostics).isEmpty();
assertThat(result).isTrue();
}
}

View File

@@ -1,19 +1,29 @@
package tech.picnic.errorprone.documentation;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.nio.file.attribute.AclEntryPermission.ADD_SUBDIRECTORY;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.condition.OS.WINDOWS;
import com.google.auto.service.AutoService;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
import com.google.errorprone.VisitorState;
import com.google.errorprone.annotations.Immutable;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.Tree;
import java.io.IOException;
import java.nio.file.FileSystemException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.AclEntry;
import java.nio.file.attribute.AclFileAttributeView;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.EnabledOnOs;
@@ -75,4 +85,56 @@ final class DocumentationGeneratorTaskListenerTest {
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Precisely one path must be provided");
}
@Test
void extraction(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"DocumentationGeneratorTaskListenerTestClass.java",
"class DocumentationGeneratorTaskListenerTestClass {}");
// XXX: Once we support only JDK 15+, use a text block for the `expected` string.
assertThat(
outputDirectory.resolve(
"documentation-generator-task-listener-test-DocumentationGeneratorTaskListenerTestClass.json"))
.content(UTF_8)
.isEqualToIgnoringWhitespace(
"{\"className\":\"DocumentationGeneratorTaskListenerTestClass\",\"path\":[\"CLASS: DocumentationGeneratorTaskListenerTestClass\",\"COMPILATION_UNIT\"]}");
}
@Immutable
@AutoService(Extractor.class)
@SuppressWarnings("rawtypes" /* See https://github.com/google/auto/issues/870. */)
public static final class TestExtractor implements Extractor<ExtractionParameters> {
@Override
public String identifier() {
return "documentation-generator-task-listener-test";
}
@Override
public Optional<ExtractionParameters> tryExtract(ClassTree tree, VisitorState state) {
return Optional.of(tree.getSimpleName().toString())
.filter(n -> n.contains(DocumentationGeneratorTaskListenerTest.class.getSimpleName()))
.map(
className ->
new AutoValue_DocumentationGeneratorTaskListenerTest_ExtractionParameters(
className,
Streams.stream(state.getPath())
.map(TestExtractor::describeTree)
.collect(toImmutableList())));
}
private static String describeTree(Tree tree) {
return (tree instanceof ClassTree)
? String.join(": ", String.valueOf(tree.getKind()), ((ClassTree) tree).getSimpleName())
: tree.getKind().toString();
}
}
@AutoValue
abstract static class ExtractionParameters {
abstract String className();
abstract ImmutableList<String> path();
}
}

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

@@ -125,9 +125,6 @@ The following is a list of checks we'd like to see implemented:
statement. Idem for other exception types.
- A Guava-specific check that replaces simple anonymous `CacheLoader` subclass
declarations with `CacheLoader.from(someLambda)`.
- A Spring-specific check that enforces that methods with the `@Scheduled`
annotation are also annotated with New Relic's `@Trace` annotation. Such
methods should ideally not also represent Spring MVC endpoints.
- A Spring-specific check that enforces that `@RequestMapping` annotations,
when applied to a method, explicitly specify one or more target HTTP methods.
- A Spring-specific check that looks for classes in which all `@RequestMapping`

View File

@@ -5,13 +5,14 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.10.0</version>
<version>0.14.1-SNAPSHOT</version>
</parent>
<artifactId>error-prone-contrib</artifactId>
<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>
@@ -73,19 +73,15 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.googlejavaformat</groupId>
<artifactId>google-java-format</artifactId>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.newrelic.agent.java</groupId>
<artifactId>newrelic-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
@@ -126,6 +122,11 @@
<artifactId>jakarta.servlet-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
@@ -156,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>
@@ -171,6 +174,36 @@
<artifactId>mockito-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.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>
@@ -206,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>
@@ -221,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>
@@ -243,17 +284,6 @@
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<configuration>
<ignoredUnusedDeclaredDependencies>
<!-- XXX: Figure out why the plugin thinks this
dependency is unused. -->
<ignoredUnusedDeclaredDependency>${project.groupId}:refaster-support</ignoredUnusedDeclaredDependency>
</ignoredUnusedDeclaredDependencies>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>

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,10 +6,9 @@ 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.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
@@ -17,13 +16,14 @@ import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.MultiMatcher;
import com.google.errorprone.matchers.MultiMatcher.MultiMatchResult;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AnnotationTree;
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)
@@ -48,11 +48,9 @@ public final class AutowiredConstructor extends BugChecker implements ClassTreeM
return Description.NO_MATCH;
}
ImmutableList<AnnotationTree> annotations =
AUTOWIRED_ANNOTATION
.multiMatchResult(Iterables.getOnlyElement(constructors), state)
.matchingNodes();
if (annotations.size() != 1) {
MultiMatchResult<AnnotationTree> hasAutowiredAnnotation =
AUTOWIRED_ANNOTATION.multiMatchResult(Iterables.getOnlyElement(constructors), state);
if (!hasAutowiredAnnotation.matches()) {
return Description.NO_MATCH;
}
@@ -61,7 +59,7 @@ public final class AutowiredConstructor extends BugChecker implements ClassTreeM
* means that the associated import can be removed as well. Rather than adding code for this
* case we leave flagging the unused import to Error Prone's `RemoveUnusedImports` check.
*/
AnnotationTree annotation = Iterables.getOnlyElement(annotations);
AnnotationTree annotation = hasAutowiredAnnotation.onlyMatchingNode();
return describeMatch(annotation, SourceCode.deleteWithTrailingWhitespace(annotation, state));
}
}

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)
@@ -91,8 +91,8 @@ public final class CanonicalAnnotationSyntax extends BugChecker implements Annot
ExpressionTree arg = args.get(0);
if (state.getSourceForNode(arg) == null) {
/*
* The annotation argument isn't doesn't have a source representation, e.g. because `value`
* isn't assigned to explicitly.
* The annotation argument doesn't have a source representation, e.g. because `value` isn't
* assigned explicitly.
*/
return Optional.empty();
}

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
@@ -59,6 +62,7 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
public final class FormatStringConcatenation extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
/**
* AssertJ exposes varargs {@code fail} methods with a {@link Throwable}-accepting overload, the
* latter of which should not be flagged.
@@ -67,7 +71,8 @@ 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 =
anyOf(
@@ -116,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
@@ -37,6 +49,8 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
// the target method such a modification may change the code's semantics or performance.
// XXX: Also flag `Stream#map`, `Mono#map` and `Flux#map` invocations where the given transformation
// is effectively the identity operation.
// XXX: Also flag nullary instance method invocations that represent an identity conversion, such as
// `Boolean#booleanValue()`, `Byte#byteValue()` and friends.
@AutoService(BugChecker.class)
@BugPattern(
summary = "Avoid or clarify identity conversions",
@@ -54,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

@@ -0,0 +1,91 @@
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 com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE;
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.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;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.matchers.MultiMatcher;
import com.google.errorprone.matchers.MultiMatcher.MultiMatchResult;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.MethodTree;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags nullary {@link
* org.junit.jupiter.params.ParameterizedTest @ParameterizedTest} test methods.
*
* <p>Such tests are unnecessarily executed more than necessary. This checker suggests annotating
* the method with {@link org.junit.jupiter.api.Test @Test}, and to drop all declared {@link
* org.junit.jupiter.params.provider.ArgumentsSource argument sources}.
*/
@AutoService(BugChecker.class)
@BugPattern(
summary = "Nullary JUnit test methods should not be parameterized",
link = BUG_PATTERNS_BASE_URL + "JUnitNullaryParameterizedTestDeclaration",
linkType = CUSTOM,
severity = SUGGESTION,
tags = SIMPLIFICATION)
public final class JUnitNullaryParameterizedTestDeclaration extends BugChecker
implements MethodTreeMatcher {
private static final long serialVersionUID = 1L;
private static final MultiMatcher<MethodTree, AnnotationTree> IS_PARAMETERIZED_TEST =
annotations(AT_LEAST_ONE, isType("org.junit.jupiter.params.ParameterizedTest"));
private static final Matcher<AnnotationTree> IS_ARGUMENT_SOURCE =
anyOf(
isType("org.junit.jupiter.params.provider.ArgumentsSource"),
isType("org.junit.jupiter.params.provider.ArgumentsSources"),
hasMetaAnnotation("org.junit.jupiter.params.provider.ArgumentsSource"));
/** Instantiates a new {@link JUnitNullaryParameterizedTestDeclaration} instance. */
public JUnitNullaryParameterizedTestDeclaration() {}
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
if (!tree.getParameters().isEmpty()) {
return Description.NO_MATCH;
}
MultiMatchResult<AnnotationTree> isParameterizedTest =
IS_PARAMETERIZED_TEST.multiMatchResult(tree, state);
if (!isParameterizedTest.matches()) {
return Description.NO_MATCH;
}
/*
* This method is vacuously parameterized. Suggest replacing `@ParameterizedTest` with `@Test`.
* (As each method is checked independently, we cannot in general determine whether this
* suggestion makes a `ParameterizedTest` type import obsolete; that task is left to Error
* Prone's `RemoveUnusedImports` check.)
*/
SuggestedFix.Builder fix = SuggestedFix.builder();
fix.merge(
SuggestedFix.replace(
isParameterizedTest.onlyMatchingNode(),
'@' + SuggestedFixes.qualifyType(state, fix, "org.junit.jupiter.api.Test")));
/*
* Also suggest dropping all (explicit and implicit) `@ArgumentsSource`s. No attempt is made to
* assess whether a dropped `@MethodSource` also makes the referenced factory method(s) unused.
*/
tree.getModifiers().getAnnotations().stream()
.filter(a -> IS_ARGUMENT_SOURCE.matches(a, state))
.forEach(a -> fix.merge(SourceCode.deleteWithTrailingWhitespace(a, state)));
return describeMatch(tree, fix.build());
}
}

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;
@@ -40,10 +40,11 @@ import java.util.List;
import java.util.Optional;
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.
@@ -75,6 +76,7 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
private static final String FLAG_PREFIX = "LexicographicalAnnotationAttributeListing:";
private static final String INCLUDED_ANNOTATIONS_FLAG = FLAG_PREFIX + "Includes";
private static final String EXCLUDED_ANNOTATIONS_FLAG = FLAG_PREFIX + "Excludes";
/**
* The splitter applied to string-typed annotation arguments prior to lexicographical sorting. By
* splitting on {@code =}, strings that represent e.g. inline Spring property declarations are
@@ -94,7 +96,8 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
*
* @param flags Any provided command line flags.
*/
public LexicographicalAnnotationAttributeListing(ErrorProneFlags flags) {
@Inject
LexicographicalAnnotationAttributeListing(ErrorProneFlags flags) {
matcher = createAnnotationAttributeMatcher(flags);
}
@@ -217,7 +220,10 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
private static AnnotationAttributeMatcher createAnnotationAttributeMatcher(
ErrorProneFlags flags) {
return AnnotationAttributeMatcher.create(
flags.getList(INCLUDED_ANNOTATIONS_FLAG), excludedAnnotations(flags));
flags.get(INCLUDED_ANNOTATIONS_FLAG).isPresent()
? Optional.of(flags.getListOrEmpty(INCLUDED_ANNOTATIONS_FLAG))
: Optional.empty(),
excludedAnnotations(flags));
}
private static ImmutableList<String> excludedAnnotations(ErrorProneFlags flags) {

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.
@@ -46,6 +46,7 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
public final class LexicographicalAnnotationListing extends BugChecker
implements MethodTreeMatcher {
private static final long serialVersionUID = 1L;
/**
* A comparator that minimally reorders {@link AnnotationType}s, such that declaration annotations
* are placed before type annotations.

View File

@@ -1,59 +0,0 @@
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.LIKELY_ERROR;
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE;
import static com.google.errorprone.matchers.Matchers.annotations;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.isType;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.MultiMatcher;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
/** A {@link BugChecker} that flags likely missing Refaster annotations. */
@AutoService(BugChecker.class)
@BugPattern(
summary = "The Refaster rule contains a method without any Refaster annotations",
link = BUG_PATTERNS_BASE_URL + "MissingRefasterAnnotation",
linkType = CUSTOM,
severity = WARNING,
tags = LIKELY_ERROR)
public final class MissingRefasterAnnotation extends BugChecker implements ClassTreeMatcher {
private static final long serialVersionUID = 1L;
private static final MultiMatcher<Tree, AnnotationTree> REFASTER_ANNOTATION =
annotations(
AT_LEAST_ONE,
anyOf(
isType("com.google.errorprone.refaster.annotation.Placeholder"),
isType("com.google.errorprone.refaster.annotation.BeforeTemplate"),
isType("com.google.errorprone.refaster.annotation.AfterTemplate")));
/** Instantiates a new {@link MissingRefasterAnnotation} instance. */
public MissingRefasterAnnotation() {}
@Override
public Description matchClass(ClassTree tree, VisitorState state) {
long methodTypes =
tree.getMembers().stream()
.filter(member -> member.getKind() == Tree.Kind.METHOD)
.map(MethodTree.class::cast)
.filter(method -> !ASTHelpers.isGeneratedConstructor(method))
.map(method -> REFASTER_ANNOTATION.matches(method, state))
.distinct()
.count();
return methodTypes < 2 ? Description.NO_MATCH : buildDescription(tree).build();
}
}

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. */
@@ -71,7 +71,7 @@ public final class MockitoMockClassReference extends BugChecker
Tree parent = state.getPath().getParentPath().getLeaf();
switch (parent.getKind()) {
case VARIABLE:
return !ASTHelpers.hasNoExplicitType((VariableTree) parent, state)
return !ASTHelpers.hasImplicitType((VariableTree) parent, state)
&& MoreASTHelpers.areSameType(tree, parent, state);
case ASSIGNMENT:
return MoreASTHelpers.areSameType(tree, parent, state);

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

@@ -0,0 +1,47 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.PERFORMANCE;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import static tech.picnic.errorprone.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.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
/**
* A {@link BugChecker} that flags usages of MongoDB {@code $text} filter usages.
*
* @see <a href="https://www.mongodb.com/docs/manual/text-search/">MongoDB Text Search</a>
*/
@AutoService(BugChecker.class)
@BugPattern(
summary =
"Avoid MongoDB's `$text` filter operator, as it can trigger heavy queries and even cause the server to run out of memory",
link = BUG_PATTERNS_BASE_URL + "MongoDBTextFilterUsage",
linkType = CUSTOM,
severity = SUGGESTION,
tags = PERFORMANCE)
public final class MongoDBTextFilterUsage extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> MONGO_FILTERS_TEXT_METHOD =
staticMethod().onClass("com.mongodb.client.model.Filters").named("text");
/** Instantiates a new {@link MongoDBTextFilterUsage} instance. */
public MongoDBTextFilterUsage() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
return MONGO_FILTERS_TEXT_METHOD.matches(tree, state)
? describeMatch(tree)
: Description.NO_MATCH;
}
}

View File

@@ -3,10 +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.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;
@@ -14,14 +15,19 @@ import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Supplier;
import com.google.errorprone.suppliers.Suppliers;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Type;
import java.util.Optional;
/** A {@link BugChecker} that flags nesting of {@link Optional Optionals}. */
// XXX: Extend this checker to also flag method return types and variable/field types.
// XXX: Consider generalizing this checker and `NestedPublishers` to a single `NestedMonad` check,
// which e.g. also flags nested `Stream`s. Alternatively, combine these and other checkers into an
// even more generic `ConfusingType` checker.
@AutoService(BugChecker.class)
@BugPattern(
summary =
@@ -33,19 +39,16 @@ import java.util.Optional;
public final class NestedOptionals extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Supplier<Type> OPTIONAL = Suppliers.typeFromClass(Optional.class);
private static final Supplier<Type> OPTIONAL_OF_OPTIONAL =
VisitorState.memoize(generic(OPTIONAL, subOf(raw(OPTIONAL))));
private static final Matcher<Tree> IS_OPTIONAL_OF_OPTIONAL =
isSubTypeOf(VisitorState.memoize(generic(OPTIONAL, subOf(raw(OPTIONAL)))));
/** Instantiates a new {@link NestedOptionals} instance. */
public NestedOptionals() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
Type type = OPTIONAL_OF_OPTIONAL.get(state);
if (type == null || !state.getTypes().isSubtype(ASTHelpers.getType(tree), type)) {
return Description.NO_MATCH;
}
return describeMatch(tree);
return IS_OPTIONAL_OF_OPTIONAL.matches(tree, state)
? describeMatch(tree)
: Description.NO_MATCH;
}
}

View File

@@ -0,0 +1,63 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.FRAGILE_CODE;
import static com.google.errorprone.matchers.Matchers.typePredicateMatcher;
import static com.google.errorprone.predicates.TypePredicates.allOf;
import static com.google.errorprone.predicates.TypePredicates.not;
import static tech.picnic.errorprone.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;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Supplier;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Type;
/**
* A {@link BugChecker} that flags {@code Publisher<? extends Publisher>} instances, unless the
* nested {@link org.reactivestreams.Publisher} is a {@link reactor.core.publisher.GroupedFlux}.
*/
// XXX: See the `NestedOptionals` check for some ideas on how to generalize this kind of checker.
@AutoService(BugChecker.class)
@BugPattern(
summary =
"Avoid `Publisher`s that emit other `Publishers`s; "
+ "the resultant code is hard to reason about",
link = BUG_PATTERNS_BASE_URL + "NestedPublishers",
linkType = CUSTOM,
severity = WARNING,
tags = FRAGILE_CODE)
public final class NestedPublishers extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Supplier<Type> PUBLISHER = type("org.reactivestreams.Publisher");
private static final Matcher<ExpressionTree> IS_NON_GROUPED_PUBLISHER_OF_PUBLISHERS =
typePredicateMatcher(
allOf(
isSubTypeOf(generic(PUBLISHER, subOf(raw(PUBLISHER)))),
not(
hasTypeParameter(
0, isSubTypeOf(raw(type("reactor.core.publisher.GroupedFlux")))))));
/** Instantiates a new {@link NestedPublishers} instance. */
public NestedPublishers() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
return IS_NON_GROUPED_PUBLISHER_OF_PUBLISHERS.matches(tree, state)
? describeMatch(tree)
: Description.NO_MATCH;
}
}

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

@@ -0,0 +1,225 @@
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.STYLE;
import static tech.picnic.errorprone.bugpatterns.StaticImport.STATIC_IMPORT_CANDIDATE_MEMBERS;
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;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.CompilationUnitTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.ImportTree;
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.utils.SourceCode;
/**
* A {@link BugChecker} that flags static imports of type members that should *not* be statically
* imported.
*/
// XXX: This check is closely linked to `StaticImport`. Consider merging the two.
// XXX: Add suppression support. If qualification of one more more identifiers is suppressed, then
// the associated static import should *not* be removed.
// XXX: Also introduce logic that disallows statically importing `ZoneOffset.ofHours` and other
// `ofXXX`-style methods.
@AutoService(BugChecker.class)
@BugPattern(
summary = "Member should not be statically imported",
link = BUG_PATTERNS_BASE_URL + "NonStaticImport",
linkType = CUSTOM,
severity = SUGGESTION,
tags = STYLE)
public final class NonStaticImport extends BugChecker implements CompilationUnitTreeMatcher {
private static final long serialVersionUID = 1L;
/**
* Types whose members should not be statically imported, unless exempted by {@link
* StaticImport#STATIC_IMPORT_CANDIDATE_MEMBERS}.
*
* <p>Types listed here should be mutually exclusive with {@link
* StaticImport#STATIC_IMPORT_CANDIDATE_TYPES}.
*/
@VisibleForTesting
static final ImmutableSet<String> NON_STATIC_IMPORT_CANDIDATE_TYPES =
ImmutableSet.of(
ASTHelpers.class.getCanonicalName(),
Clock.class.getCanonicalName(),
Strings.class.getCanonicalName(),
VisitorState.class.getCanonicalName(),
ZoneOffset.class.getCanonicalName(),
"com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode",
"reactor.core.publisher.Flux",
"reactor.core.publisher.Mono");
/**
* Type members that should never be statically imported.
*
* <p>Please note that:
*
* <ul>
* <li>Types listed by {@link #NON_STATIC_IMPORT_CANDIDATE_TYPES} and members listed by {@link
* #NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS} should be omitted from this collection.
* <li>This collection should be mutually exclusive with {@link
* StaticImport#STATIC_IMPORT_CANDIDATE_MEMBERS}.
* </ul>
*/
// XXX: Perhaps the set of exempted `java.util.Collections` methods is too strict. For now any
// method name that could be considered "too vague" or could conceivably mean something else in a
// specific context is left out.
static final ImmutableSetMultimap<String, String> NON_STATIC_IMPORT_CANDIDATE_MEMBERS =
ImmutableSetMultimap.<String, String>builder()
.putAll(
Collections.class.getCanonicalName(),
"addAll",
"copy",
"fill",
"list",
"max",
"min",
"nCopies",
"rotate",
"sort",
"swap")
.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();
/**
* Identifiers that should never be statically imported.
*
* <p>Please note that:
*
* <ul>
* <li>Identifiers listed by {@link StaticImport#STATIC_IMPORT_CANDIDATE_MEMBERS} should be
* mutually exclusive with identifiers listed here.
* <li>This list should contain a superset of the identifiers flagged by {@link
* com.google.errorprone.bugpatterns.BadImport}.
* </ul>
*/
static final ImmutableSet<String> NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS =
ImmutableSet.of(
"builder",
"copyOf",
"create",
"from",
"getDefaultInstance",
"INSTANCE",
"MAX",
"MAX_VALUE",
"MIN",
"MIN_VALUE",
"newBuilder",
"newInstance",
"of",
"parse",
"valueOf");
/** Instantiates a new {@link NonStaticImport} instance. */
public NonStaticImport() {}
@Override
public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) {
ImmutableTable<String, String, UndesiredStaticImport> undesiredStaticImports =
getUndesiredStaticImports(tree, state);
if (!undesiredStaticImports.isEmpty()) {
replaceUndesiredStaticImportUsages(tree, undesiredStaticImports, state);
for (UndesiredStaticImport staticImport : undesiredStaticImports.values()) {
state.reportMatch(
describeMatch(staticImport.importTree(), staticImport.fixBuilder().build()));
}
}
/* Any violations have been flagged against the offending static import statement. */
return Description.NO_MATCH;
}
private static ImmutableTable<String, String, UndesiredStaticImport> getUndesiredStaticImports(
CompilationUnitTree tree, VisitorState state) {
ImmutableTable.Builder<String, String, UndesiredStaticImport> imports =
ImmutableTable.builder();
for (ImportTree importTree : tree.getImports()) {
Tree qualifiedIdentifier = importTree.getQualifiedIdentifier();
if (importTree.isStatic() && qualifiedIdentifier instanceof MemberSelectTree) {
MemberSelectTree memberSelectTree = (MemberSelectTree) qualifiedIdentifier;
String type = SourceCode.treeToString(memberSelectTree.getExpression(), state);
String member = memberSelectTree.getIdentifier().toString();
if (shouldNotBeStaticallyImported(type, member)) {
imports.put(
type,
member,
new AutoValue_NonStaticImport_UndesiredStaticImport(
importTree, SuggestedFix.builder().removeStaticImport(type + '.' + member)));
}
}
}
return imports.build();
}
private static boolean shouldNotBeStaticallyImported(String type, String member) {
return (NON_STATIC_IMPORT_CANDIDATE_TYPES.contains(type)
&& !STATIC_IMPORT_CANDIDATE_MEMBERS.containsEntry(type, member))
|| NON_STATIC_IMPORT_CANDIDATE_MEMBERS.containsEntry(type, member)
|| NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS.contains(member);
}
private static void replaceUndesiredStaticImportUsages(
CompilationUnitTree tree,
ImmutableTable<String, String, UndesiredStaticImport> undesiredStaticImports,
VisitorState state) {
new TreeScanner<@Nullable Void, @Nullable Void>() {
@Override
public @Nullable Void visitIdentifier(IdentifierTree node, @Nullable Void unused) {
Symbol symbol = ASTHelpers.getSymbol(node);
if (symbol != null) {
UndesiredStaticImport staticImport =
undesiredStaticImports.get(
symbol.owner.getQualifiedName().toString(), symbol.name.toString());
if (staticImport != null) {
SuggestedFix.Builder fix = staticImport.fixBuilder();
fix.prefixWith(node, SuggestedFixes.qualifyType(state, fix, symbol.owner) + '.');
}
}
return super.visitIdentifier(node, unused);
}
}.scan(tree, null);
}
@AutoValue
abstract static class UndesiredStaticImport {
abstract ImportTree importTree();
abstract SuggestedFix.Builder fixBuilder();
}
}

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;
@@ -50,9 +52,10 @@ import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import tech.picnic.errorprone.bugpatterns.util.Flags;
import tech.picnic.errorprone.bugpatterns.util.MethodMatcherFactory;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
import javax.inject.Inject;
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)
@@ -85,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(
@@ -99,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()
@@ -108,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()
@@ -155,7 +160,8 @@ public final class RedundantStringConversion extends BugChecker
*
* @param flags Any provided command line flags.
*/
public RedundantStringConversion(ErrorProneFlags flags) {
@Inject
RedundantStringConversion(ErrorProneFlags flags) {
conversionMethodMatcher = createConversionMethodMatcher(flags);
}

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;
@@ -27,7 +27,8 @@ import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Suppliers;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import tech.picnic.errorprone.bugpatterns.util.Flags;
import javax.inject.Inject;
import tech.picnic.errorprone.utils.Flags;
/** A {@link BugChecker} that flags {@code @RequestParam} parameters with an unsupported type. */
@AutoService(BugChecker.class)
@@ -55,7 +56,8 @@ public final class RequestParamType extends BugChecker implements VariableTreeMa
*
* @param flags Any provided command line flags.
*/
public RequestParamType(ErrorProneFlags flags) {
@Inject
RequestParamType(ErrorProneFlags flags) {
hasUnsupportedRequestParamType = hasUnsupportedRequestParamType(flags);
}

View File

@@ -1,94 +0,0 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static com.google.errorprone.BugPattern.StandardTags.LIKELY_ERROR;
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE;
import static com.google.errorprone.matchers.Matchers.annotations;
import static com.google.errorprone.matchers.Matchers.hasAnnotation;
import static com.google.errorprone.matchers.Matchers.isType;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.common.AnnotationMirrors;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.matchers.MultiMatcher;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import tech.picnic.errorprone.bugpatterns.util.ThirdPartyLibrary;
/**
* A {@link BugChecker} that flags methods with Spring's {@code @Scheduled} annotation that lack New
* Relic Agent's {@code @Trace(dispatcher = true)}.
*/
@AutoService(BugChecker.class)
@BugPattern(
summary = "Scheduled operation must start a new New Relic transaction",
link = BUG_PATTERNS_BASE_URL + "ScheduledTransactionTrace",
linkType = CUSTOM,
severity = ERROR,
tags = LIKELY_ERROR)
public final class ScheduledTransactionTrace extends BugChecker implements MethodTreeMatcher {
private static final long serialVersionUID = 1L;
private static final String TRACE_ANNOTATION_FQCN = "com.newrelic.api.agent.Trace";
private static final Matcher<Tree> IS_SCHEDULED =
hasAnnotation("org.springframework.scheduling.annotation.Scheduled");
private static final MultiMatcher<Tree, AnnotationTree> TRACE_ANNOTATION =
annotations(AT_LEAST_ONE, isType(TRACE_ANNOTATION_FQCN));
/** Instantiates a new {@link ScheduledTransactionTrace} instance. */
public ScheduledTransactionTrace() {}
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
if (!ThirdPartyLibrary.NEW_RELIC_AGENT_API.isIntroductionAllowed(state)
|| !IS_SCHEDULED.matches(tree, state)) {
return Description.NO_MATCH;
}
ImmutableList<AnnotationTree> traceAnnotations =
TRACE_ANNOTATION.multiMatchResult(tree, state).matchingNodes();
if (traceAnnotations.isEmpty()) {
/* This method completely lacks the `@Trace` annotation; add it. */
return describeMatch(
tree,
SuggestedFix.builder()
.addImport(TRACE_ANNOTATION_FQCN)
.prefixWith(tree, "@Trace(dispatcher = true)")
.build());
}
AnnotationTree traceAnnotation = Iterables.getOnlyElement(traceAnnotations);
if (isCorrectAnnotation(traceAnnotation)) {
return Description.NO_MATCH;
}
/*
* The `@Trace` annotation is present but does not specify `dispatcher = true`. Add or update
* the `dispatcher` annotation element.
*/
return describeMatch(
traceAnnotation,
SuggestedFixes.updateAnnotationArgumentValues(
traceAnnotation, state, "dispatcher", ImmutableList.of("true"))
.build());
}
private static boolean isCorrectAnnotation(AnnotationTree traceAnnotation) {
return Boolean.TRUE.equals(
AnnotationMirrors.getAnnotationValue(
ASTHelpers.getAnnotationMirror(traceAnnotation), "dispatcher")
.getValue());
}
}

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

@@ -2,14 +2,32 @@ 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 com.google.errorprone.BugPattern.StandardTags.STYLE;
import static java.util.Objects.requireNonNull;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
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.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;
@@ -20,55 +38,73 @@ 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 methods and constants that can and should be statically imported.
*/
/** 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.
// XXX: Tricky cases:
// - `org.springframework.http.HttpStatus` (not always an improvement, and `valueOf` must
// certainly be excluded)
// - `com.google.common.collect.Tables`
// - `ch.qos.logback.classic.Level.{DEBUG, ERROR, INFO, TRACE, WARN"}`
// XXX: Also introduce a check that disallows static imports of certain methods. Candidates:
// - `com.google.common.base.Strings`
// - `java.util.Optional.empty`
// - `java.util.Locale.ROOT`
// - `ZoneOffset.ofHours` and other `ofXXX`-style methods.
// - `java.time.Clock`.
// - Several other `java.time` classes.
// - Likely any of `*.{ZERO, ONE, MIX, MAX, MIN_VALUE, MAX_VALUE}`.
// - `ch.qos.logback.classic.Level.{DEBUG, ERROR, INFO, TRACE, WARN}`
@AutoService(BugChecker.class)
@BugPattern(
summary = "Identifier should be statically imported",
link = BUG_PATTERNS_BASE_URL + "StaticImport",
linkType = CUSTOM,
severity = SUGGESTION,
tags = SIMPLIFICATION)
tags = STYLE)
public final class StaticImport extends BugChecker implements MemberSelectTreeMatcher {
private static final long serialVersionUID = 1L;
/**
* Types whose members should be statically imported, unless exempted by {@link
* #STATIC_IMPORT_EXEMPTED_MEMBERS} or {@link #STATIC_IMPORT_EXEMPTED_IDENTIFIERS}.
* NonStaticImport#NON_STATIC_IMPORT_CANDIDATE_MEMBERS} or {@link
* NonStaticImport#NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS}.
*
* <p>Types listed here should be mutually exclusive with {@link
* NonStaticImport#NON_STATIC_IMPORT_CANDIDATE_TYPES}.
*/
@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",
@@ -76,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",
@@ -102,95 +132,59 @@ 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. */
@VisibleForTesting
/**
* Type members that should be statically imported.
*
* <p>Please note that:
*
* <ul>
* <li>Types listed by {@link #STATIC_IMPORT_CANDIDATE_TYPES} should be omitted from this
* collection.
* <li>This collection should be mutually exclusive with {@link
* NonStaticImport#NON_STATIC_IMPORT_CANDIDATE_MEMBERS}.
* <li>This collection should not list members contained in {@link
* NonStaticImport#NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS}.
* </ul>
*/
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();
/**
* Type members that should never be statically imported.
*
* <p>Identifiers listed by {@link #STATIC_IMPORT_EXEMPTED_IDENTIFIERS} should be omitted from
* this collection.
*/
// XXX: Perhaps the set of exempted `java.util.Collections` methods is too strict. For now any
// method name that could be considered "too vague" or could conceivably mean something else in a
// specific context is left out.
@VisibleForTesting
static final ImmutableSetMultimap<String, String> STATIC_IMPORT_EXEMPTED_MEMBERS =
ImmutableSetMultimap.<String, String>builder()
.put("com.mongodb.client.model.Filters", "empty")
.putAll(
"java.util.Collections",
"addAll",
"copy",
"fill",
"list",
"max",
"min",
"nCopies",
"rotate",
"sort",
"swap")
.putAll("java.util.regex.Pattern", "compile", "matches", "quote")
.put("org.springframework.http.MediaType", "ALL")
.build();
/**
* Identifiers that should never be statically imported.
*
* <p>This should be a superset of the identifiers flagged by {@link
* com.google.errorprone.bugpatterns.BadImport}.
*/
@VisibleForTesting
static final ImmutableSet<String> STATIC_IMPORT_EXEMPTED_IDENTIFIERS =
ImmutableSet.of(
"builder",
"create",
"copyOf",
"from",
"getDefaultInstance",
"INSTANCE",
"newBuilder",
"of",
"valueOf");
/** Instantiates a new {@link StaticImport} instance. */
public StaticImport() {}
@@ -228,13 +222,13 @@ public final class StaticImport extends BugChecker implements MemberSelectTreeMa
private static boolean isCandidate(MemberSelectTree tree) {
String identifier = tree.getIdentifier().toString();
if (STATIC_IMPORT_EXEMPTED_IDENTIFIERS.contains(identifier)) {
if (NON_STATIC_IMPORT_CANDIDATE_IDENTIFIERS.contains(identifier)) {
return false;
}
Type type = ASTHelpers.getType(tree.getExpression());
return type != null
&& !STATIC_IMPORT_EXEMPTED_MEMBERS.containsEntry(type.toString(), identifier);
&& !NON_STATIC_IMPORT_CANDIDATE_MEMBERS.containsEntry(type.toString(), identifier);
}
private static Optional<String> getCandidateSimpleName(StaticImportInfo importInfo) {

View File

@@ -1,89 +0,0 @@
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.method.MethodMatchers.instanceMethod;
import static com.sun.tools.javac.parser.Tokens.TokenKind.RPAREN;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.Streams;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.fixes.Fix;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.util.ASTHelpers;
import com.google.errorprone.util.ErrorProneTokens;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.util.Position;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
/**
* A {@link BugChecker} that flags calls to {@link String#toLowerCase()} and {@link
* String#toUpperCase()}, as these methods implicitly rely on the environment's default locale.
*/
// XXX: Also flag `String::toLowerCase` and `String::toUpperCase` method references. For these cases
// the suggested fix should introduce a lambda expression with a parameter of which the name does
// not coincide with the name of an existing variable name. Such functionality should likely be
// introduced in a utility class.
@AutoService(BugChecker.class)
@BugPattern(
summary = "Specify a `Locale` when calling `String#to{Lower,Upper}Case`",
link = BUG_PATTERNS_BASE_URL + "StringCaseLocaleUsage",
linkType = CUSTOM,
severity = WARNING,
tags = FRAGILE_CODE)
public final class StringCaseLocaleUsage extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> DEFAULT_LOCALE_CASE_CONVERSION =
instanceMethod()
.onExactClass(String.class.getName())
.namedAnyOf("toLowerCase", "toUpperCase")
.withNoParameters();
/** Instantiates a new {@link StringCaseLocaleUsage} instance. */
public StringCaseLocaleUsage() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (!DEFAULT_LOCALE_CASE_CONVERSION.matches(tree, state)) {
return Description.NO_MATCH;
}
int closingParenPosition = getClosingParenPosition(tree, state);
if (closingParenPosition == Position.NOPOS) {
return describeMatch(tree);
}
return buildDescription(tree)
.addFix(suggestLocale(closingParenPosition, "Locale.ROOT"))
.addFix(suggestLocale(closingParenPosition, "Locale.getDefault()"))
.build();
}
private static Fix suggestLocale(int insertPosition, String locale) {
return SuggestedFix.builder()
.addImport("java.util.Locale")
.replace(insertPosition, insertPosition, locale)
.build();
}
private static int getClosingParenPosition(MethodInvocationTree tree, VisitorState state) {
int startPosition = ASTHelpers.getStartPosition(tree);
if (startPosition == Position.NOPOS) {
return Position.NOPOS;
}
return Streams.findLast(
ErrorProneTokens.getTokens(SourceCode.treeToString(tree, state), state.context).stream()
.filter(t -> t.kind() == RPAREN))
.map(token -> startPosition + token.pos())
.orElse(Position.NOPOS);
}
}

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;
@@ -23,12 +23,12 @@ import com.google.errorprone.util.ASTHelpers;
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.Convert;
import com.sun.tools.javac.util.Constants;
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);
@@ -150,7 +150,7 @@ public final class StringJoin extends BugChecker implements MethodInvocationTree
SuggestedFix.Builder fix =
SuggestedFix.builder()
.replace(tree.getMethodSelect(), "String.join")
.replace(arguments.next(), String.format("\"%s\"", Convert.quote(separator)));
.replace(arguments.next(), Constants.format(separator));
while (arguments.hasNext()) {
ExpressionTree argument = arguments.next();

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

@@ -1,39 +0,0 @@
package tech.picnic.errorprone.bugpatterns.util;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.matchers.Matchers;
import com.google.errorprone.predicates.TypePredicate;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AnnotationTree;
import com.sun.tools.javac.code.Symbol;
/**
* A collection of general-purpose {@link Matcher}s.
*
* <p>These methods are additions to the ones found in {@link Matchers}.
*/
public final class MoreMatchers {
private MoreMatchers() {}
/**
* Returns a {@link Matcher} that determines whether a given {@link AnnotationTree} has a
* meta-annotation of the specified type.
*
* @param <T> The type of tree to match against.
* @param annotationType The binary type name of the annotation (e.g.
* "org.jspecify.annotations.Nullable", or "some.package.OuterClassName$InnerClassName")
* @return A {@link Matcher} that matches trees with the specified meta-annotation.
*/
public static <T extends AnnotationTree> Matcher<T> hasMetaAnnotation(String annotationType) {
TypePredicate typePredicate = hasAnnotation(annotationType);
return (tree, state) -> {
Symbol sym = ASTHelpers.getSymbol(tree);
return sym != null && typePredicate.apply(sym.type, state);
};
}
// XXX: Consider moving to a `MoreTypePredicates` utility class.
private static TypePredicate hasAnnotation(String annotationClassName) {
return (type, state) -> ASTHelpers.hasAnnotation(type.tsym, annotationClassName, state);
}
}

View File

@@ -3,80 +3,40 @@ package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ImmutableSortedMultiset;
import com.google.common.collect.ImmutableSortedSet;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Matches;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractBooleanAssert;
import org.assertj.core.api.AbstractCollectionAssert;
import org.assertj.core.api.AbstractMapAssert;
import org.assertj.core.api.MapAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.matchers.IsEmpty;
@OnlineDocumentation
final class AssertJMapRules {
private AssertJMapRules() {}
// XXX: Reduce boilerplate using a `Matcher` that identifies "empty" instances.
static final class AbstractMapAssertIsEmpty<K, V> {
@BeforeTemplate
@SuppressWarnings("unchecked")
void before(AbstractMapAssert<?, ?, K, V> mapAssert) {
void before(
AbstractMapAssert<?, ?, K, V> mapAssert,
@Matches(IsEmpty.class) Map<? extends K, ? extends V> wellTypedMap,
@Matches(IsEmpty.class) Map<?, ?> arbitrarilyTypedMap,
@Matches(IsEmpty.class) Iterable<? extends K> keys) {
Refaster.anyOf(
mapAssert.containsExactlyEntriesOf(
Refaster.anyOf(
ImmutableMap.of(),
ImmutableBiMap.of(),
ImmutableSortedMap.of(),
new HashMap<>(),
new LinkedHashMap<>(),
new TreeMap<>())),
mapAssert.hasSameSizeAs(
Refaster.anyOf(
ImmutableMap.of(),
ImmutableBiMap.of(),
ImmutableSortedMap.of(),
new HashMap<>(),
new LinkedHashMap<>(),
new TreeMap<>())),
mapAssert.isEqualTo(
Refaster.anyOf(
ImmutableMap.of(),
ImmutableBiMap.of(),
ImmutableSortedMap.of(),
new HashMap<>(),
new LinkedHashMap<>(),
new TreeMap<>())),
mapAssert.containsOnlyKeys(
Refaster.anyOf(
ImmutableList.of(),
new ArrayList<>(),
ImmutableSet.of(),
new HashSet<>(),
new LinkedHashSet<>(),
ImmutableSortedSet.of(),
new TreeSet<>(),
ImmutableMultiset.of(),
ImmutableSortedMultiset.of())),
mapAssert.containsExactlyEntriesOf(wellTypedMap),
mapAssert.containsExactlyInAnyOrderEntriesOf(wellTypedMap),
mapAssert.hasSameSizeAs(arbitrarilyTypedMap),
mapAssert.isEqualTo(arbitrarilyTypedMap),
mapAssert.containsOnlyKeys(keys),
mapAssert.containsExactly(),
mapAssert.containsOnly(),
mapAssert.containsOnlyKeys());
@@ -112,15 +72,9 @@ final class AssertJMapRules {
static final class AbstractMapAssertIsNotEmpty<K, V> {
@BeforeTemplate
AbstractMapAssert<?, ?, K, V> before(AbstractMapAssert<?, ?, K, V> mapAssert) {
return mapAssert.isNotEqualTo(
Refaster.anyOf(
ImmutableMap.of(),
ImmutableBiMap.of(),
ImmutableSortedMap.of(),
new HashMap<>(),
new LinkedHashMap<>(),
new TreeMap<>()));
AbstractMapAssert<?, ?, K, V> before(
AbstractMapAssert<?, ?, K, V> mapAssert, @Matches(IsEmpty.class) Map<?, ?> map) {
return mapAssert.isNotEqualTo(map);
}
@AfterTemplate
@@ -148,12 +102,14 @@ final class AssertJMapRules {
static final class AbstractMapAssertContainsExactlyInAnyOrderEntriesOf<K, V> {
@BeforeTemplate
AbstractMapAssert<?, ?, K, V> before(AbstractMapAssert<?, ?, K, V> mapAssert, Map<K, V> map) {
AbstractMapAssert<?, ?, K, V> before(
AbstractMapAssert<?, ?, K, V> mapAssert, Map<? extends K, ? extends V> map) {
return mapAssert.isEqualTo(map);
}
@AfterTemplate
AbstractMapAssert<?, ?, K, V> after(AbstractMapAssert<?, ?, K, V> mapAssert, Map<K, V> map) {
AbstractMapAssert<?, ?, K, V> after(
AbstractMapAssert<?, ?, K, V> mapAssert, Map<? extends K, ? extends V> map) {
return mapAssert.containsExactlyInAnyOrderEntriesOf(map);
}
}
@@ -187,12 +143,12 @@ final class AssertJMapRules {
static final class AbstractMapAssertHasSameSizeAs<K, V> {
@BeforeTemplate
AbstractMapAssert<?, ?, K, V> before(AbstractMapAssert<?, ?, K, V> mapAssert, Map<K, V> map) {
AbstractMapAssert<?, ?, K, V> before(AbstractMapAssert<?, ?, K, V> mapAssert, Map<?, ?> map) {
return mapAssert.hasSize(map.size());
}
@AfterTemplate
AbstractMapAssert<?, ?, K, V> after(AbstractMapAssert<?, ?, K, V> mapAssert, Map<K, V> map) {
AbstractMapAssert<?, ?, K, V> after(AbstractMapAssert<?, ?, K, V> mapAssert, Map<?, ?> map) {
return mapAssert.hasSameSizeAs(map);
}
}
@@ -225,13 +181,14 @@ final class AssertJMapRules {
static final class AssertThatMapContainsOnlyKeys<K, V> {
@BeforeTemplate
AbstractCollectionAssert<?, Collection<? extends K>, K, ?> before(Map<K, V> map, Set<K> keys) {
AbstractCollectionAssert<?, Collection<? extends K>, K, ?> before(
Map<K, V> map, Set<? extends K> keys) {
return assertThat(map.keySet()).hasSameElementsAs(keys);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
MapAssert<K, V> after(Map<K, V> map, Set<K> keys) {
MapAssert<K, V> after(Map<K, V> map, Set<? extends K> keys) {
return assertThat(map).containsOnlyKeys(keys);
}
}

View File

@@ -6,28 +6,23 @@ import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMultiset;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multiset;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Matches;
import com.google.errorprone.refaster.annotation.NotMatches;
import com.google.errorprone.refaster.annotation.Repeated;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Stream;
@@ -47,6 +42,7 @@ import org.assertj.core.api.OptionalIntAssert;
import org.assertj.core.api.OptionalLongAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.matchers.IsArray;
import tech.picnic.errorprone.refaster.matchers.IsEmpty;
/** Refaster rules related to AssertJ expressions and statements. */
// XXX: Most `AbstractIntegerAssert` rules can also be applied for other primitive types. Generate
@@ -181,63 +177,16 @@ final class AssertJRules {
static final class AssertThatObjectEnumerableIsEmpty<E> {
@BeforeTemplate
@SuppressWarnings("unchecked")
void before(ObjectEnumerableAssert<?, E> enumAssert) {
void before(
ObjectEnumerableAssert<?, E> enumAssert,
@Matches(IsEmpty.class) Iterable<? extends E> wellTypedIterable,
@Matches(IsEmpty.class) Iterable<?> arbitrarilyTypedIterable) {
Refaster.anyOf(
enumAssert.containsExactlyElementsOf(
Refaster.anyOf(
ImmutableList.of(),
new ArrayList<>(),
ImmutableSet.of(),
new HashSet<>(),
new LinkedHashSet<>(),
ImmutableSortedSet.of(),
new TreeSet<>(),
ImmutableMultiset.of(),
ImmutableSortedMultiset.of())),
enumAssert.containsExactlyInAnyOrderElementsOf(
Refaster.anyOf(
ImmutableList.of(),
new ArrayList<>(),
ImmutableSet.of(),
new HashSet<>(),
new LinkedHashSet<>(),
ImmutableSortedSet.of(),
new TreeSet<>(),
ImmutableMultiset.of(),
ImmutableSortedMultiset.of())),
enumAssert.hasSameElementsAs(
Refaster.anyOf(
ImmutableList.of(),
new ArrayList<>(),
ImmutableSet.of(),
new HashSet<>(),
new LinkedHashSet<>(),
ImmutableSortedSet.of(),
new TreeSet<>(),
ImmutableMultiset.of(),
ImmutableSortedMultiset.of())),
enumAssert.hasSameSizeAs(
Refaster.anyOf(
ImmutableList.of(),
new ArrayList<>(),
ImmutableSet.of(),
new HashSet<>(),
new LinkedHashSet<>(),
ImmutableSortedSet.of(),
new TreeSet<>(),
ImmutableMultiset.of(),
ImmutableSortedMultiset.of())),
enumAssert.isSubsetOf(
Refaster.anyOf(
ImmutableList.of(),
new ArrayList<>(),
ImmutableSet.of(),
new HashSet<>(),
new LinkedHashSet<>(),
ImmutableSortedSet.of(),
new TreeSet<>(),
ImmutableMultiset.of(),
ImmutableSortedMultiset.of())),
enumAssert.containsExactlyElementsOf(wellTypedIterable),
enumAssert.containsExactlyInAnyOrderElementsOf(wellTypedIterable),
enumAssert.hasSameElementsAs(wellTypedIterable),
enumAssert.hasSameSizeAs(arbitrarilyTypedIterable),
enumAssert.isSubsetOf(wellTypedIterable),
enumAssert.containsExactly(),
enumAssert.containsExactlyInAnyOrder(),
enumAssert.containsOnly(),
@@ -581,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);
}
@@ -602,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);
}
@@ -624,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));
}
@@ -647,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);
}
@@ -668,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);
}
@@ -690,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));
}
@@ -712,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);
}
@@ -727,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);
}
@@ -743,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));
}
@@ -759,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);
}
@@ -780,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);
}
@@ -802,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));
}
@@ -810,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));
}
@@ -827,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);
}
@@ -849,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));
}
@@ -865,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);
}
@@ -887,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));
}
@@ -904,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);
}
@@ -925,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);
}
@@ -947,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));
}
@@ -969,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);
}
@@ -991,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));
}
@@ -1008,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);
}
@@ -1029,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);
}
@@ -1051,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));
}
@@ -1073,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);
}
@@ -1107,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

@@ -103,8 +103,7 @@ final class AssortedRules {
}
@AfterTemplate
@Nullable
T after(Iterator<T> iterator, T defaultValue) {
@Nullable T after(Iterator<T> iterator, T defaultValue) {
return Iterators.getNext(iterator, defaultValue);
}
}

View File

@@ -2,6 +2,7 @@ package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.math.BigDecimal;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@@ -66,4 +67,61 @@ final class BigDecimalRules {
return BigDecimal.valueOf(value);
}
}
/** Prefer using {@link BigDecimal#signum()} over more contrived alternatives. */
static final class BigDecimalSignumIsZero {
@BeforeTemplate
boolean before(BigDecimal value) {
return Refaster.anyOf(
value.compareTo(BigDecimal.ZERO) == 0, BigDecimal.ZERO.compareTo(value) == 0);
}
@AfterTemplate
@AlsoNegation
boolean after(BigDecimal value) {
return value.signum() == 0;
}
}
/**
* Prefer a {@link BigDecimal#signum()} comparison to 1 over more contrived or less clear
* alternatives.
*/
static final class BigDecimalSignumIsPositive {
@BeforeTemplate
boolean before(BigDecimal value) {
return Refaster.anyOf(
value.compareTo(BigDecimal.ZERO) > 0,
BigDecimal.ZERO.compareTo(value) < 0,
value.signum() > 0,
value.signum() >= 1);
}
@AfterTemplate
@AlsoNegation
boolean after(BigDecimal value) {
return value.signum() == 1;
}
}
/**
* Prefer a {@link BigDecimal#signum()} comparison to -1 over more contrived or less clear
* alternatives.
*/
static final class BigDecimalSignumIsNegative {
@BeforeTemplate
boolean before(BigDecimal value) {
return Refaster.anyOf(
value.compareTo(BigDecimal.ZERO) < 0,
BigDecimal.ZERO.compareTo(value) > 0,
value.signum() < 0,
value.signum() <= -1);
}
@AfterTemplate
@AlsoNegation
boolean after(BigDecimal value) {
return value.signum() == -1;
}
}
}

View File

@@ -3,9 +3,12 @@ package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChooser;
import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.sun.tools.javac.util.Constants;
import com.sun.tools.javac.util.Convert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster rules related to {@link com.google.errorprone.bugpatterns.BugChecker} classes. */
@@ -25,6 +28,7 @@ final class BugCheckerRules {
}
@AfterTemplate
@CanIgnoreReturnValue
BugCheckerRefactoringTestHelper after(BugCheckerRefactoringTestHelper helper) {
return helper;
}
@@ -50,4 +54,17 @@ final class BugCheckerRules {
return helper.addInputLines(path, source).expectUnchanged();
}
}
/** Prefer using the {@link Constants} API over more verbose alternatives. */
static final class ConstantsFormat {
@BeforeTemplate
String before(String value) {
return String.format("\"%s\"", Convert.quote(value));
}
@AfterTemplate
String after(String value) {
return Constants.format(value);
}
}
}

View File

@@ -0,0 +1,65 @@
package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.function.Predicate;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster rules related to expressions dealing with classes. */
@OnlineDocumentation
final class ClassRules {
private ClassRules() {}
/** Prefer {@link Class#isInstance(Object)} over more contrived alternatives. */
static final class ClassIsInstance<T, S> {
@BeforeTemplate
boolean before(Class<T> clazz, S object) {
return clazz.isAssignableFrom(object.getClass());
}
@AfterTemplate
boolean after(Class<T> clazz, S object) {
return clazz.isInstance(object);
}
}
/** Prefer using the {@code instanceof} keyword over less idiomatic alternatives. */
static final class Instanceof<T, S> {
@BeforeTemplate
boolean before(S object) {
return Refaster.<T>clazz().isInstance(object);
}
@AfterTemplate
boolean after(S object) {
return Refaster.<T>isInstance(object);
}
}
/** Prefer {@link Class#isInstance(Object)} method references over more verbose alternatives. */
static final class ClassLiteralIsInstancePredicate<T, S> {
@BeforeTemplate
Predicate<S> before() {
return o -> Refaster.<T>isInstance(o);
}
@AfterTemplate
Predicate<S> after() {
return Refaster.<T>clazz()::isInstance;
}
}
/** Prefer {@link Class#isInstance(Object)} method references over more verbose alternatives. */
static final class ClassReferenceIsInstancePredicate<T, S> {
@BeforeTemplate
Predicate<S> before(Class<T> clazz) {
return o -> clazz.isInstance(o);
}
@AfterTemplate
Predicate<S> after(Class<T> clazz) {
return clazz::isInstance;
}
}
}

View File

@@ -74,6 +74,19 @@ final class CollectionRules {
}
}
/** Prefer {@link Collection#contains(Object)} over more contrived alternatives. */
static final class CollectionContains<T, S> {
@BeforeTemplate
boolean before(Collection<T> collection, S value) {
return collection.stream().anyMatch(value::equals);
}
@AfterTemplate
boolean after(Collection<T> collection, S value) {
return collection.contains(value);
}
}
/**
* Don't call {@link Iterables#addAll(Collection, Iterable)} when the elements to be added are
* already part of a {@link Collection}.
@@ -164,6 +177,8 @@ final class CollectionRules {
}
/** Prefer {@link ArrayList#ArrayList(Collection)} over the Guava alternative. */
@SuppressWarnings(
"NonApiType" /* Matching against `List` would unnecessarily constrain the rule. */)
static final class NewArrayListFromCollection<T> {
@BeforeTemplate
ArrayList<T> before(Collection<T> collection) {

View File

@@ -7,26 +7,32 @@ 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.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;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Matches;
import com.google.errorprone.refaster.annotation.Repeated;
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;
/** Refaster rules related to expressions dealing with {@link Comparator}s. */
@OnlineDocumentation
@@ -35,12 +41,12 @@ final class ComparatorRules {
/** Prefer {@link Comparator#naturalOrder()} over more complicated constructs. */
static final class NaturalOrder<T extends Comparable<? super T>> {
// XXX: Drop the `Refaster.anyOf` if/when we decide to rewrite one to the other.
@BeforeTemplate
Comparator<T> before() {
Comparator<T> before(
@Matches(IsIdentityOperation.class) Function<? super T, ? extends T> keyExtractor) {
return Refaster.anyOf(
T::compareTo,
comparing(Refaster.anyOf(identity(), v -> v)),
comparing(keyExtractor),
Collections.<T>reverseOrder(reverseOrder()),
Comparator.<T>reverseOrder().reversed());
}
@@ -71,13 +77,15 @@ final class ComparatorRules {
}
static final class CustomComparator<T> {
// XXX: Drop the `Refaster.anyOf` if/when we decide to rewrite one to the other.
@BeforeTemplate
Comparator<T> before(Comparator<T> cmp) {
return comparing(Refaster.anyOf(identity(), v -> v), cmp);
Comparator<T> before(
Comparator<T> cmp,
@Matches(IsIdentityOperation.class) Function<? super T, ? extends T> keyExtractor) {
return comparing(keyExtractor, cmp);
}
@AfterTemplate
@CanIgnoreReturnValue
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Comparator<T> after(Comparator<T> cmp) {
return cmp;
@@ -181,14 +189,15 @@ final class ComparatorRules {
}
/**
* Where applicable, prefer {@link Comparator#naturalOrder()} over {@link Function#identity()}, as
* it more clearly states intent.
* Where applicable, prefer {@link Comparator#naturalOrder()} over identity function-based
* comparisons, as the former more clearly states intent.
*/
static final class ThenComparingNaturalOrder<T extends Comparable<? super T>> {
// XXX: Drop the `Refaster.anyOf` if/when we decide to rewrite one to the other.
@BeforeTemplate
Comparator<T> before(Comparator<T> cmp) {
return cmp.thenComparing(Refaster.anyOf(identity(), v -> v));
Comparator<T> before(
Comparator<T> cmp,
@Matches(IsIdentityOperation.class) Function<? super T, ? extends T> keyExtractor) {
return cmp.thenComparing(keyExtractor);
}
@AfterTemplate
@@ -219,7 +228,6 @@ final class ComparatorRules {
*/
static final class MinOfVarargs<T> {
@BeforeTemplate
@SuppressWarnings("StreamOfArray" /* In practice individual values are provided. */)
T before(@Repeated T value, Comparator<T> cmp) {
return Stream.of(Refaster.asVarargs(value)).min(cmp).orElseThrow();
}
@@ -287,7 +295,6 @@ final class ComparatorRules {
*/
static final class MaxOfVarargs<T> {
@BeforeTemplate
@SuppressWarnings("StreamOfArray" /* In practice individual values are provided. */)
T before(@Repeated T value, Comparator<T> cmp) {
return Stream.of(Refaster.asVarargs(value)).max(cmp).orElseThrow();
}
@@ -380,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

@@ -1,6 +1,7 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.Streams;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -27,6 +28,7 @@ final class DoubleStreamRules {
}
@AfterTemplate
@CanIgnoreReturnValue
DoubleStream after(DoubleStream stream) {
return stream;
}
@@ -275,4 +277,16 @@ final class DoubleStreamRules {
return stream.allMatch(e -> test(e));
}
}
static final class DoubleStreamTakeWhile {
@BeforeTemplate
DoubleStream before(DoubleStream stream, DoublePredicate predicate) {
return stream.takeWhile(predicate).filter(predicate);
}
@AfterTemplate
DoubleStream after(DoubleStream stream, DoublePredicate predicate) {
return stream.takeWhile(predicate);
}
}
}

View File

@@ -1,10 +1,16 @@
package tech.picnic.errorprone.refasterrules;
import static java.util.function.Predicate.not;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.Placeholder;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@@ -63,6 +69,7 @@ final class EqualityRules {
}
@AfterTemplate
@CanIgnoreReturnValue
boolean after(boolean b) {
return b;
}
@@ -129,4 +136,52 @@ final class EqualityRules {
return a == b;
}
}
/**
* Don't pass a lambda expression to {@link Predicate#not(Predicate)}; instead push the negation
* into the lambda expression.
*/
abstract static class PredicateLambda<T> {
@Placeholder(allowsIdentity = true)
abstract boolean predicate(@MayOptionallyUse T value);
@BeforeTemplate
Predicate<T> before() {
return not(v -> predicate(v));
}
@AfterTemplate
Predicate<T> after() {
return v -> !predicate(v);
}
}
/** Avoid contrived ways of handling {@code null} values during equality testing. */
static final class Equals<T, S> {
@BeforeTemplate
boolean before(T value1, S 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
boolean after(T value1, S value2) {
return value1.equals(value2);
}
}
/** Avoid contrived ways of handling {@code null} values during equality testing. */
static final class ObjectsEquals<T, S> {
@BeforeTemplate
boolean before(T value1, S value2) {
return Optional.ofNullable(value1).equals(Optional.ofNullable(value2));
}
@AfterTemplate
boolean after(T value1, S value2) {
return Objects.equals(value1, value2);
}
}
}

View File

@@ -0,0 +1,43 @@
package tech.picnic.errorprone.refasterrules;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster rules related to expressions dealing with files. */
@OnlineDocumentation
final class FileRules {
private FileRules() {}
/** Prefer {@link Files#readString(Path, Charset)} over more contrived alternatives. */
static final class FilesReadStringWithCharset {
@BeforeTemplate
String before(Path path, Charset charset) throws IOException {
return new String(Files.readAllBytes(path), charset);
}
@AfterTemplate
String after(Path path, Charset charset) throws IOException {
return Files.readString(path, charset);
}
}
/** Prefer {@link Files#readString(Path)} over more verbose alternatives. */
static final class FilesReadString {
@BeforeTemplate
String before(Path path) throws IOException {
return Files.readString(path, UTF_8);
}
@AfterTemplate
String after(Path path) throws IOException {
return Files.readString(path);
}
}
}

View File

@@ -3,7 +3,6 @@ package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableListMultimap.flatteningToImmutableListMultimap;
import static com.google.common.collect.ImmutableListMultimap.toImmutableListMultimap;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.function.Function.identity;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMultimap;
@@ -16,6 +15,7 @@ import com.google.common.collect.Streams;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Matches;
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
@@ -25,6 +25,7 @@ import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.matchers.IsIdentityOperation;
/** Refaster rules related to expressions dealing with {@link ImmutableListMultimap}s. */
@OnlineDocumentation
@@ -173,27 +174,29 @@ final class ImmutableListMultimapRules {
* Prefer {@link Multimaps#index(Iterable, com.google.common.base.Function)} over the stream-based
* alternative.
*/
// XXX: Drop the `Refaster.anyOf` if/when we decide to rewrite one to the other.
static final class IndexIterableToImmutableListMultimap<K, V> {
@BeforeTemplate
ImmutableListMultimap<K, V> before(
Iterator<V> iterable, Function<? super V, ? extends K> keyFunction) {
return Streams.stream(iterable)
.collect(toImmutableListMultimap(keyFunction, Refaster.anyOf(identity(), v -> v)));
Iterator<V> iterable,
Function<? super V, ? extends K> keyFunction,
@Matches(IsIdentityOperation.class) Function<? super V, ? extends V> valueFunction) {
return Streams.stream(iterable).collect(toImmutableListMultimap(keyFunction, valueFunction));
}
@BeforeTemplate
ImmutableListMultimap<K, V> before(
Iterable<V> iterable, Function<? super V, ? extends K> keyFunction) {
return Streams.stream(iterable)
.collect(toImmutableListMultimap(keyFunction, Refaster.anyOf(identity(), v -> v)));
Iterable<V> iterable,
Function<? super V, ? extends K> keyFunction,
@Matches(IsIdentityOperation.class) Function<? super V, ? extends V> valueFunction) {
return Streams.stream(iterable).collect(toImmutableListMultimap(keyFunction, valueFunction));
}
@BeforeTemplate
ImmutableListMultimap<K, V> before(
Collection<V> iterable, Function<? super V, ? extends K> keyFunction) {
return iterable.stream()
.collect(toImmutableListMultimap(keyFunction, Refaster.anyOf(identity(), v -> v)));
Collection<V> iterable,
Function<? super V, ? extends K> keyFunction,
@Matches(IsIdentityOperation.class) Function<? super V, ? extends V> valueFunction) {
return iterable.stream().collect(toImmutableListMultimap(keyFunction, valueFunction));
}
@AfterTemplate

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

@@ -4,7 +4,6 @@ import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static java.util.function.Function.identity;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
@@ -13,6 +12,7 @@ import com.google.common.collect.Streams;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Matches;
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
@@ -23,6 +23,7 @@ import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.matchers.IsIdentityOperation;
/** Refaster rules related to expressions dealing with {@link ImmutableMap}s. */
@OnlineDocumentation
@@ -63,27 +64,29 @@ final class ImmutableMapRules {
* Prefer {@link Maps#toMap(Iterable, com.google.common.base.Function)} over more contrived
* alternatives.
*/
// XXX: Drop the `Refaster.anyOf` if/when we decide to rewrite one to the other.
static final class IterableToImmutableMap<K, V> {
@BeforeTemplate
ImmutableMap<K, V> before(
Iterator<K> iterable, Function<? super K, ? extends V> valueFunction) {
return Streams.stream(iterable)
.collect(toImmutableMap(Refaster.anyOf(identity(), k -> k), valueFunction));
Iterator<K> iterable,
Function<? super K, ? extends V> valueFunction,
@Matches(IsIdentityOperation.class) Function<? super K, ? extends K> keyFunction) {
return Streams.stream(iterable).collect(toImmutableMap(keyFunction, valueFunction));
}
@BeforeTemplate
ImmutableMap<K, V> before(
Iterable<K> iterable, Function<? super K, ? extends V> valueFunction) {
return Streams.stream(iterable)
.collect(toImmutableMap(Refaster.anyOf(identity(), k -> k), valueFunction));
Iterable<K> iterable,
Function<? super K, ? extends V> valueFunction,
@Matches(IsIdentityOperation.class) Function<? super K, ? extends K> keyFunction) {
return Streams.stream(iterable).collect(toImmutableMap(keyFunction, valueFunction));
}
@BeforeTemplate
ImmutableMap<K, V> before(
Collection<K> iterable, Function<? super K, ? extends V> valueFunction) {
return iterable.stream()
.collect(toImmutableMap(Refaster.anyOf(identity(), k -> k), valueFunction));
Collection<K> iterable,
Function<? super K, ? extends V> valueFunction,
@Matches(IsIdentityOperation.class) Function<? super K, ? extends K> keyFunction) {
return iterable.stream().collect(toImmutableMap(keyFunction, valueFunction));
}
@BeforeTemplate
@@ -157,25 +160,29 @@ final class ImmutableMapRules {
* Prefer {@link Maps#uniqueIndex(Iterable, com.google.common.base.Function)} over the
* stream-based alternative.
*/
// XXX: Drop the `Refaster.anyOf` if/when we decide to rewrite one to the other.
static final class IndexIterableToImmutableMap<K, V> {
@BeforeTemplate
ImmutableMap<K, V> before(Iterator<V> iterable, Function<? super V, ? extends K> keyFunction) {
return Streams.stream(iterable)
.collect(toImmutableMap(keyFunction, Refaster.anyOf(identity(), v -> v)));
}
@BeforeTemplate
ImmutableMap<K, V> before(Iterable<V> iterable, Function<? super V, ? extends K> keyFunction) {
return Streams.stream(iterable)
.collect(toImmutableMap(keyFunction, Refaster.anyOf(identity(), v -> v)));
ImmutableMap<K, V> before(
Iterator<V> iterable,
Function<? super V, ? extends K> keyFunction,
@Matches(IsIdentityOperation.class) Function<? super V, ? extends V> valueFunction) {
return Streams.stream(iterable).collect(toImmutableMap(keyFunction, valueFunction));
}
@BeforeTemplate
ImmutableMap<K, V> before(
Collection<V> iterable, Function<? super V, ? extends K> keyFunction) {
return iterable.stream()
.collect(toImmutableMap(keyFunction, Refaster.anyOf(identity(), v -> v)));
Iterable<V> iterable,
Function<? super V, ? extends K> keyFunction,
@Matches(IsIdentityOperation.class) Function<? super V, ? extends V> valueFunction) {
return Streams.stream(iterable).collect(toImmutableMap(keyFunction, valueFunction));
}
@BeforeTemplate
ImmutableMap<K, V> before(
Collection<V> iterable,
Function<? super V, ? extends K> keyFunction,
@Matches(IsIdentityOperation.class) Function<? super V, ? extends V> valueFunction) {
return iterable.stream().collect(toImmutableMap(keyFunction, valueFunction));
}
@AfterTemplate

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

@@ -1,6 +1,7 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.Streams;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -40,6 +41,7 @@ final class IntStreamRules {
}
@AfterTemplate
@CanIgnoreReturnValue
IntStream after(IntStream stream) {
return stream;
}
@@ -288,4 +290,16 @@ final class IntStreamRules {
return stream.allMatch(e -> test(e));
}
}
static final class IntStreamTakeWhile {
@BeforeTemplate
IntStream before(IntStream stream, IntPredicate predicate) {
return stream.takeWhile(predicate).filter(predicate);
}
@AfterTemplate
IntStream after(IntStream stream, IntPredicate predicate) {
return stream.takeWhile(predicate);
}
}
}

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

@@ -1,6 +1,7 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.Streams;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -40,6 +41,7 @@ final class LongStreamRules {
}
@AfterTemplate
@CanIgnoreReturnValue
LongStream after(LongStream stream) {
return stream;
}
@@ -288,4 +290,16 @@ final class LongStreamRules {
return stream.allMatch(e -> test(e));
}
}
static final class LongStreamTakeWhile {
@BeforeTemplate
LongStream before(LongStream stream, LongPredicate predicate) {
return stream.takeWhile(predicate).filter(predicate);
}
@AfterTemplate
LongStream after(LongStream stream, LongPredicate predicate) {
return stream.takeWhile(predicate);
}
}
}

View File

@@ -33,14 +33,12 @@ final class MapRules {
static final class MapGetOrNull<K, V, T> {
@BeforeTemplate
@Nullable
V before(Map<K, V> map, T key) {
@Nullable V before(Map<K, V> map, T key) {
return map.getOrDefault(key, null);
}
@AfterTemplate
@Nullable
V after(Map<K, V> map, T key) {
@Nullable V after(Map<K, V> map, T key) {
return map.get(key);
}
}

View File

@@ -5,10 +5,12 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.verification.VerificationMode;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@@ -50,4 +52,30 @@ final class MockitoRules {
return verify(mock);
}
}
static final class InvocationOnMockGetArguments {
@BeforeTemplate
Object before(InvocationOnMock invocation, int i) {
return invocation.getArguments()[i];
}
@AfterTemplate
Object after(InvocationOnMock invocation, int i) {
return invocation.getArgument(i);
}
}
static final class InvocationOnMockGetArgumentsWithTypeParameter<T> {
@BeforeTemplate
@SuppressWarnings("unchecked")
T before(InvocationOnMock invocation, int i) {
return Refaster.anyOf(
invocation.getArgument(i, Refaster.<T>clazz()), (T) invocation.getArgument(i));
}
@AfterTemplate
T after(InvocationOnMock invocation, int i) {
return invocation.<T>getArgument(i);
}
}
}

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.
*
@@ -50,8 +93,7 @@ final class MultimapRules {
*/
static final class MultimapGet<K, V> {
@BeforeTemplate
@Nullable
Collection<V> before(Multimap<K, V> multimap, K key) {
@Nullable Collection<V> before(Multimap<K, V> multimap, K key) {
return Refaster.anyOf(multimap.asMap(), Multimaps.asMap(multimap)).get(key);
}
@@ -60,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

@@ -3,10 +3,12 @@ package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import com.google.common.collect.Streams;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.NotMatches;
import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Comparator;
@@ -18,6 +20,7 @@ import java.util.function.Supplier;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.matchers.IsLikelyTrivialComputation;
/** Refaster rules related to expressions dealing with {@link Optional}s. */
@OnlineDocumentation
@@ -97,6 +100,20 @@ final class OptionalRules {
}
}
/** Prefer {@link Optional#equals(Object)} over more contrived alternatives. */
static final class OptionalEqualsOptional<T, S> {
@BeforeTemplate
boolean before(Optional<T> optional, S value) {
return Refaster.anyOf(
optional.filter(value::equals).isPresent(), optional.stream().anyMatch(value::equals));
}
@AfterTemplate
boolean after(Optional<T> optional, S value) {
return optional.equals(Optional.of(value));
}
}
/**
* Don't use the ternary operator to extract the first element of a possibly-empty {@link
* Iterator} as an {@link Optional}.
@@ -117,7 +134,7 @@ final class OptionalRules {
/** Prefer {@link Optional#filter(Predicate)} over usage of the ternary operator. */
// XXX: This rule may introduce a compilation error: the `test` expression may reference a
// non-effectively final variable, which is not allowed in the replacement lambda expression.
// Maybe our `Refaster` checker should test `compilesWithFix`?
// Review whether a `@Matcher` can be used to avoid this.
abstract static class TernaryOperatorOptionalPositiveFiltering<T> {
@Placeholder
abstract boolean test(T value);
@@ -137,7 +154,7 @@ final class OptionalRules {
/** Prefer {@link Optional#filter(Predicate)} over usage of the ternary operator. */
// XXX: This rule may introduce a compilation error: the `test` expression may reference a
// non-effectively final variable, which is not allowed in the replacement lambda expression.
// Maybe our `Refaster` checker should test `compilesWithFix`?
// Review whether a `@Matcher` can be used to avoid this.
abstract static class TernaryOperatorOptionalNegativeFiltering<T> {
@Placeholder
abstract boolean test(T value);
@@ -160,6 +177,7 @@ final class OptionalRules {
*/
static final class MapOptionalToBoolean<T> {
@BeforeTemplate
@SuppressWarnings("OptionalOrElseGet" /* Rule is confused by `Refaster#anyOf` usage. */)
boolean before(Optional<T> optional, Function<? super T, Boolean> predicate) {
return optional.map(predicate).orElse(Refaster.anyOf(false, Boolean.FALSE));
}
@@ -223,6 +241,28 @@ final class OptionalRules {
}
}
/**
* Prefer {@link Optional#orElseGet(Supplier)} over {@link Optional#orElse(Object)} if the
* fallback value is not the result of a trivial computation.
*/
// XXX: This rule may introduce a compilation error: the `value` expression may reference a
// non-effectively final variable, which is not allowed in the replacement lambda expression.
// Review whether a `@Matcher` can be used to avoid this.
// XXX: Once `MethodReferenceUsage` is "production ready", replace
// `@NotMatches(IsLikelyTrivialComputation.class)` with `@Matches(RequiresComputation.class)` (and
// reimplement the matcher accordingly).
static final class OptionalOrElseGet<T> {
@BeforeTemplate
T before(Optional<T> optional, @NotMatches(IsLikelyTrivialComputation.class) T value) {
return optional.orElse(value);
}
@AfterTemplate
T after(Optional<T> optional, T value) {
return optional.orElseGet(() -> value);
}
}
/**
* Flatten a stream of {@link Optional}s using {@link Optional#stream()}, rather than using one of
* the more verbose alternatives.
@@ -324,10 +364,14 @@ final class OptionalRules {
Optional<T> before(Optional<T> optional1, Optional<T> optional2) {
// XXX: Note that rewriting the first and third variant will change the code's behavior if
// `optional2` has side-effects.
// XXX: Note that rewriting the first, third and fourth variant will introduce a compilation
// error if `optional2` is not effectively final. Review whether a `@Matcher` can be used to
// avoid this.
return Refaster.anyOf(
optional1.map(Optional::of).orElse(optional2),
optional1.map(Optional::of).orElseGet(() -> optional2),
Stream.of(optional1, optional2).flatMap(Optional::stream).findFirst());
Stream.of(optional1, optional2).flatMap(Optional::stream).findFirst(),
optional1.isPresent() ? optional1 : optional2);
}
@AfterTemplate
@@ -344,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),
@@ -351,6 +396,7 @@ final class OptionalRules {
}
@AfterTemplate
@CanIgnoreReturnValue
Optional<T> after(Optional<T> optional) {
return optional;
}
@@ -392,12 +438,22 @@ final class OptionalRules {
}
}
// XXX: Add a rule for:
// `optional.flatMap(x -> pred(x) ? Optional.empty() : Optional.of(x))` and variants.
// (Maybe canonicalize the inner expression. Maybe we rewrite already.)
/** Prefer {@link Optional#stream()} over more contrived alternatives. */
static final class OptionalStream<T> {
@BeforeTemplate
Stream<T> before(Optional<T> optional) {
return Refaster.anyOf(
optional.map(Stream::of).orElse(Stream.empty()),
optional.map(Stream::of).orElseGet(Stream::empty));
}
@AfterTemplate
Stream<T> after(Optional<T> optional) {
return optional.stream();
}
}
// XXX: Add a rule for:
// `optional.map(Stream::of).orElse(Stream.empty())`
// `optional.map(Stream::of).orElseGet(Stream::empty)`
// -> `optional.stream()`
// `optional.flatMap(x -> pred(x) ? Optional.empty() : Optional.of(x))` and variants.
// (Maybe canonicalize the inner expression. Maybe we rewrite it already.)
}

View File

@@ -0,0 +1,46 @@
package tech.picnic.errorprone.refasterrules;
import static com.google.common.base.Predicates.containsPattern;
import com.google.common.base.Predicates;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster rules related to code dealing with regular expressions. */
@OnlineDocumentation
final class PatternRules {
private PatternRules() {}
/** Prefer {@link Pattern#asPredicate()} over non-JDK alternatives. */
// XXX: This rule could also replace `s -> pattern.matcher(s).find()`, though the lambda
// expression may match functional interfaces other than `Predicate`. If we do add such a rule, we
// should also add a rule that replaces `s -> pattern.matcher(s).matches()` with
// `pattern.asMatchPredicate()`.
static final class PatternAsPredicate {
@BeforeTemplate
Predicate<CharSequence> before(Pattern pattern) {
return Predicates.contains(pattern);
}
@AfterTemplate
Predicate<String> after(Pattern pattern) {
return pattern.asPredicate();
}
}
/** Prefer {@link Pattern#asPredicate()} over non-JDK alternatives. */
static final class PatternCompileAsPredicate {
@BeforeTemplate
Predicate<CharSequence> before(String pattern) {
return containsPattern(pattern);
}
@AfterTemplate
Predicate<String> after(String pattern) {
return Pattern.compile(pattern).asPredicate();
}
}
}

View File

@@ -8,7 +8,9 @@ import com.google.common.primitives.Floats;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@@ -384,4 +386,60 @@ final class PrimitiveRules {
return Double.isFinite(d);
}
}
/** Prefer an {@link Integer#signum(int)} comparison to 1 over less clear alternatives. */
static final class IntegerSignumIsPositive {
@BeforeTemplate
boolean before(int i) {
return Refaster.anyOf(Integer.signum(i) > 0, Integer.signum(i) >= 1);
}
@AfterTemplate
@AlsoNegation
boolean after(int i) {
return Integer.signum(i) == 1;
}
}
/** Prefer an {@link Integer#signum(int)} comparison to -1 over less clear alternatives. */
static final class IntegerSignumIsNegative {
@BeforeTemplate
boolean before(int i) {
return Refaster.anyOf(Integer.signum(i) < 0, Integer.signum(i) <= -1);
}
@AfterTemplate
@AlsoNegation
boolean after(int i) {
return Integer.signum(i) == -1;
}
}
/** Prefer an {@link Long#signum(long)} comparison to 1 over less clear alternatives. */
static final class LongSignumIsPositive {
@BeforeTemplate
boolean before(long l) {
return Refaster.anyOf(Long.signum(l) > 0, Long.signum(l) >= 1);
}
@AfterTemplate
@AlsoNegation
boolean after(long l) {
return Long.signum(l) == 1;
}
}
/** Prefer an {@link Long#signum(long)} comparison to -1 over less clear alternatives. */
static final class LongSignumIsNegative {
@BeforeTemplate
boolean before(long l) {
return Refaster.anyOf(Long.signum(l) < 0, Long.signum(l) <= -1);
}
@AfterTemplate
@AlsoNegation
boolean after(long l) {
return Long.signum(l) == -1;
}
}
}

View File

@@ -5,18 +5,23 @@ 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;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Matches;
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.NotMatches;
import com.google.errorprone.refaster.annotation.Placeholder;
@@ -25,8 +30,8 @@ import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.function.BiConsumer;
@@ -40,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;
@@ -47,6 +53,8 @@ import reactor.util.function.Tuple2;
import tech.picnic.errorprone.refaster.annotation.Description;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.annotation.Severity;
import tech.picnic.errorprone.refaster.matchers.IsEmpty;
import tech.picnic.errorprone.refaster.matchers.IsIdentityOperation;
import tech.picnic.errorprone.refaster.matchers.ThrowsCheckedException;
/** Refaster rules related to Reactor expressions and statements. */
@@ -97,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));
@@ -246,11 +254,43 @@ final class ReactorRules {
}
}
/** Prefer {@link Flux#zipWithIterable(Iterable)} over more contrived alternatives. */
static final class FluxZipWithIterable<T, S> {
@BeforeTemplate
Flux<Tuple2<T, S>> before(Flux<T> flux, Iterable<S> iterable) {
return Flux.zip(flux, Flux.fromIterable(iterable));
}
@AfterTemplate
Flux<Tuple2<T, S>> after(Flux<T> flux, Iterable<S> iterable) {
return flux.zipWithIterable(iterable);
}
}
/** Prefer {@link Flux#zipWithIterable(Iterable, BiFunction)} over more contrived alternatives. */
static final class FluxZipWithIterableBiFunction<T, S, R> {
@BeforeTemplate
Flux<R> before(
Flux<T> flux,
Iterable<S> iterable,
BiFunction<? super T, ? super S, ? extends R> function) {
return flux.zipWith(Flux.fromIterable(iterable), function);
}
@AfterTemplate
Flux<R> after(
Flux<T> flux,
Iterable<S> iterable,
BiFunction<? super T, ? super S, ? extends R> function) {
return flux.zipWithIterable(iterable, function);
}
}
/**
* Prefer {@link Flux#zipWithIterable(Iterable)} with a chained combinator over {@link
* Flux#zipWithIterable(Iterable, BiFunction)}, as the former generally yields more readable code.
*/
static final class FluxZipWithIterable<T, S, R> {
static final class FluxZipWithIterableMapFunction<T, S, R> {
@BeforeTemplate
Flux<R> before(Flux<T> flux, Iterable<S> iterable, BiFunction<T, S, R> combinator) {
return flux.zipWithIterable(iterable, combinator);
@@ -327,7 +367,10 @@ final class ReactorRules {
static final class MonoThenReturn<T, S> {
@BeforeTemplate
Mono<S> before(Mono<T> mono, S object) {
return mono.then(Mono.just(object));
return Refaster.anyOf(
mono.ignoreElement().thenReturn(object),
mono.then().thenReturn(object),
mono.then(Mono.just(object)));
}
@AfterTemplate
@@ -390,6 +433,74 @@ final class ReactorRules {
}
}
/** Prefer {@link Flux#empty()} over more contrived alternatives. */
// XXX: In combination with the `IsEmpty` matcher introduced by
// https://github.com/PicnicSupermarket/error-prone-support/pull/744, the non-varargs overloads of
// most methods referenced here can be rewritten as well. Additionally, some invocations of
// methods such as `Flux#fromIterable`, `Flux#fromArray` and `Flux#justOrEmpty` can also be
// rewritten.
static final class FluxEmpty<T, S extends Comparable<? super S>> {
@BeforeTemplate
Flux<T> before(
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(),
Flux.just(),
Flux.merge(),
Flux.merge(prefetch),
Flux.mergeComparing(comparator),
Flux.mergeComparing(prefetch, comparator),
Flux.mergeComparingDelayError(prefetch, comparator),
Flux.mergeDelayError(prefetch),
Flux.mergePriority(comparator),
Flux.mergePriority(prefetch, comparator),
Flux.mergePriorityDelayError(prefetch, comparator),
Flux.mergeSequential(),
Flux.mergeSequential(prefetch),
Flux.mergeSequentialDelayError(prefetch));
}
@BeforeTemplate
Flux<T> before(Function<Object[], T> combinator, int prefetch) {
return Refaster.anyOf(
Flux.combineLatest(combinator), Flux.combineLatest(combinator, prefetch));
}
@BeforeTemplate
Flux<S> before() {
return Refaster.anyOf(Flux.mergeComparing(), Flux.mergePriority());
}
@BeforeTemplate
Flux<Integer> before(int start) {
return Flux.range(start, 0);
}
@AfterTemplate
Flux<T> after() {
return Flux.empty();
}
}
/** Prefer {@link Flux#just(Object)} over more contrived alternatives. */
static final class FluxJust {
@BeforeTemplate
Flux<Integer> before(int start) {
return Flux.range(start, 1);
}
@AfterTemplate
Flux<Integer> after(int start) {
return Flux.just(start);
}
}
/** Don't unnecessarily transform a {@link Mono} to an equivalent instance. */
static final class MonoIdentity<T> {
@BeforeTemplate
@@ -400,22 +511,37 @@ final class ReactorRules {
@BeforeTemplate
Mono<@Nullable Void> before2(Mono<@Nullable Void> mono) {
return mono.then();
return Refaster.anyOf(mono.ignoreElement(), mono.then());
}
// XXX: Replace this rule with an extension of the `IdentityConversion` rule, supporting
// `Stream#map`, `Mono#map` and `Flux#map`.
// `Stream#map`, `Mono#map` and `Flux#map`. Alternatively, extend the `IsIdentityOperation`
// matcher and use it to constrain the matched `map` argument.
@BeforeTemplate
Mono<ImmutableList<T>> before3(Mono<ImmutableList<T>> mono) {
return mono.map(ImmutableList::copyOf);
}
@AfterTemplate
@CanIgnoreReturnValue
Mono<T> after(Mono<T> mono) {
return mono;
}
}
/** Don't unnecessarily transform a {@link Mono} to a {@link Flux} to expect exactly one item. */
static final class MonoSingle<T> {
@BeforeTemplate
Mono<T> before(Mono<T> mono) {
return mono.flux().single();
}
@AfterTemplate
Mono<T> after(Mono<T> mono) {
return mono.single();
}
}
/** Don't unnecessarily pass an empty publisher to {@link Flux#switchIfEmpty(Publisher)}. */
static final class FluxSwitchIfEmptyOfEmptyPublisher<T> {
@BeforeTemplate
@@ -424,57 +550,109 @@ final class ReactorRules {
}
@AfterTemplate
@CanIgnoreReturnValue
Flux<T> after(Flux<T> flux) {
return flux;
}
}
/** Prefer {@link Flux#concatMap(Function)} over more contrived alternatives. */
static final class FluxConcatMap<T, S> {
static final class FluxConcatMap<T, S, P extends Publisher<? extends S>> {
@BeforeTemplate
Flux<S> before(Flux<T> flux, Function<? super T, ? extends Publisher<? extends S>> function) {
@SuppressWarnings("NestedPublishers")
Flux<S> before(
Flux<T> flux,
Function<? super T, ? extends P> function,
@Matches(IsIdentityOperation.class)
Function<? super P, ? extends Publisher<? extends S>> identityOperation) {
return Refaster.anyOf(
flux.flatMap(function, 1),
flux.flatMapSequential(function, 1),
flux.map(function).concatMap(identity()));
flux.map(function).concatMap(identityOperation));
}
@AfterTemplate
Flux<S> after(Flux<T> flux, Function<? super T, ? extends Publisher<? extends S>> function) {
Flux<S> after(Flux<T> flux, Function<? super T, ? extends P> function) {
return flux.concatMap(function);
}
}
/** Prefer {@link Flux#concatMap(Function, int)} over more contrived alternatives. */
static final class FluxConcatMapWithPrefetch<T, S> {
static final class FluxConcatMapWithPrefetch<T, S, P extends Publisher<? extends S>> {
@BeforeTemplate
@SuppressWarnings("NestedPublishers")
Flux<S> before(
Flux<T> flux,
Function<? super T, ? extends Publisher<? extends S>> function,
int prefetch) {
Function<? super T, ? extends P> function,
int prefetch,
@Matches(IsIdentityOperation.class)
Function<? super P, ? extends Publisher<? extends S>> identityOperation) {
return Refaster.anyOf(
flux.flatMap(function, 1, prefetch),
flux.flatMapSequential(function, 1, prefetch),
flux.map(function).concatMap(identity(), prefetch));
flux.map(function).concatMap(identityOperation, prefetch));
}
@AfterTemplate
Flux<S> after(
Flux<T> flux,
Function<? super T, ? extends Publisher<? extends S>> function,
int prefetch) {
Flux<S> after(Flux<T> flux, Function<? super T, ? extends P> function, int prefetch) {
return flux.concatMap(function, prefetch);
}
}
/**
* Prefer {@link Flux#concatMapIterable(Function)} over {@link Flux#flatMapIterable(Function)}, as
* the former has equivalent semantics but a clearer name.
*/
static final class FluxConcatMapIterable<T, S> {
/** Avoid contrived alternatives to {@link Mono#flatMapIterable(Function)}. */
static final class MonoFlatMapIterable<T, S, I extends Iterable<? extends S>> {
@BeforeTemplate
Flux<S> before(Flux<T> flux, Function<? super T, ? extends Iterable<? extends S>> function) {
return flux.flatMapIterable(function);
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,
Function<? super T, I> function,
@Matches(IsIdentityOperation.class)
Function<? super I, ? extends Iterable<? extends S>> identityOperation) {
return Refaster.anyOf(
mono.map(function).flatMapIterable(identityOperation),
mono.flux().concatMapIterable(function));
}
@AfterTemplate
Flux<S> after(Mono<T> mono, Function<? super T, I> function) {
return mono.flatMapIterable(function);
}
}
/**
* Prefer {@link Mono#flatMapIterable(Function)} to flatten a {@link Mono} of some {@link
* Iterable} over less efficient alternatives.
*/
static final class MonoFlatMapIterableIdentity<T, S extends Iterable<T>> {
@BeforeTemplate
Flux<T> before(Mono<S> mono) {
return mono.flatMapMany(Flux::fromIterable);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Flux<T> after(Mono<S> mono) {
return mono.flatMapIterable(identity());
}
}
/**
* Prefer {@link Flux#concatMapIterable(Function)} over alternatives with less clear syntax or
* semantics.
*/
static final class FluxConcatMapIterable<T, S, I extends Iterable<? extends S>> {
@BeforeTemplate
Flux<S> before(
Flux<T> flux,
Function<? super T, I> function,
@Matches(IsIdentityOperation.class)
Function<? super I, ? extends Iterable<? extends S>> identityOperation) {
return Refaster.anyOf(
flux.flatMapIterable(function), flux.map(function).concatMapIterable(identityOperation));
}
@AfterTemplate
@@ -484,14 +662,20 @@ final class ReactorRules {
}
/**
* Prefer {@link Flux#concatMapIterable(Function, int)} over {@link Flux#flatMapIterable(Function,
* int)}, as the former has equivalent semantics but a clearer name.
* Prefer {@link Flux#concatMapIterable(Function, int)} over alternatives with less clear syntax
* or semantics.
*/
static final class FluxConcatMapIterableWithPrefetch<T, S> {
static final class FluxConcatMapIterableWithPrefetch<T, S, I extends Iterable<? extends S>> {
@BeforeTemplate
Flux<S> before(
Flux<T> flux, Function<? super T, ? extends Iterable<? extends S>> function, int prefetch) {
return flux.flatMapIterable(function, prefetch);
Flux<T> flux,
Function<? super T, I> function,
int prefetch,
@Matches(IsIdentityOperation.class)
Function<? super I, ? extends Iterable<? extends S>> identityOperation) {
return Refaster.anyOf(
flux.flatMapIterable(function, prefetch),
flux.map(function).concatMapIterable(identityOperation, prefetch));
}
@AfterTemplate
@@ -544,6 +728,27 @@ final class ReactorRules {
}
}
/**
* Prefer {@link Mono#map(Function)} over alternatives that unnecessarily create and collect a
* {@link Flux}.
*/
// XXX: This rule assumes that any matched `Collector` does not filter or reorder elements after
// application of the matched `Function`.
// XXX: The `function` parameter is not matched, unless `I` is changed to `Iterable<? extends S>`,
// which would make the rule incorrect.
static final class MonoMapToIterable<T, S, I extends Iterable<? extends S>> {
@BeforeTemplate
Mono<I> before(
Mono<T> mono, Function<? super T, ? extends I> function, Collector<S, ?, I> collector) {
return mono.flatMapIterable(function).collect(collector);
}
@AfterTemplate
Mono<I> after(Mono<T> mono, Function<? super T, ? extends I> function) {
return mono.map(function);
}
}
/**
* Prefer {@link Flux#map(Function)} over alternatives that unnecessarily require an inner
* subscription.
@@ -553,7 +758,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))),
@@ -621,7 +826,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 ->
@@ -723,7 +928,7 @@ final class ReactorRules {
static final class MonoThen<T> {
@BeforeTemplate
Mono<@Nullable Void> before(Mono<T> mono) {
return mono.flux().then();
return Refaster.anyOf(mono.ignoreElement().then(), mono.flux().then());
}
@AfterTemplate
@@ -732,15 +937,141 @@ final class ReactorRules {
}
}
/** Avoid vacuous invocations of {@link Flux#ignoreElements()}. */
static final class FluxThen<T> {
@BeforeTemplate
Mono<@Nullable Void> before(Flux<T> flux) {
return flux.ignoreElements().then();
}
@BeforeTemplate
Mono<@Nullable Void> before2(Flux<@Nullable Void> flux) {
return flux.ignoreElements();
}
@AfterTemplate
Mono<@Nullable Void> after(Flux<T> flux) {
return flux.then();
}
}
/** Avoid vacuous invocations of {@link Mono#ignoreElement()}. */
static final class MonoThenEmpty<T> {
@BeforeTemplate
Mono<@Nullable Void> before(Mono<T> mono, Publisher<@Nullable Void> publisher) {
return mono.ignoreElement().thenEmpty(publisher);
}
@AfterTemplate
Mono<@Nullable Void> after(Mono<T> mono, Publisher<@Nullable Void> publisher) {
return mono.thenEmpty(publisher);
}
}
/** Avoid vacuous invocations of {@link Flux#ignoreElements()}. */
static final class FluxThenEmpty<T> {
@BeforeTemplate
Mono<@Nullable Void> before(Flux<T> flux, Publisher<@Nullable Void> publisher) {
return flux.ignoreElements().thenEmpty(publisher);
}
@AfterTemplate
Mono<@Nullable Void> after(Flux<T> flux, Publisher<@Nullable Void> publisher) {
return flux.thenEmpty(publisher);
}
}
/** 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 Refaster.anyOf(
mono.ignoreElement().thenMany(publisher), mono.flux().thenMany(publisher));
}
@AfterTemplate
Flux<S> after(Mono<T> mono, Publisher<S> publisher) {
return mono.thenMany(publisher);
}
}
/**
* Prefer explicit invocation of {@link Mono#flux()} over implicit conversions from {@link Mono}
* to {@link Flux}.
*/
static final class MonoThenMonoFlux<T, S> {
@BeforeTemplate
Flux<S> before(Mono<T> mono1, Mono<S> mono2) {
return mono1.thenMany(mono2);
}
@AfterTemplate
Flux<S> after(Mono<T> mono1, Mono<S> mono2) {
return mono1.then(mono2).flux();
}
}
/** Avoid vacuous invocations of {@link Flux#ignoreElements()}. */
static final class FluxThenMany<T, S> {
@BeforeTemplate
Flux<S> before(Flux<T> flux, Publisher<S> publisher) {
return flux.ignoreElements().thenMany(publisher);
}
@AfterTemplate
Flux<S> after(Flux<T> flux, Publisher<S> publisher) {
return flux.thenMany(publisher);
}
}
/** 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 Refaster.anyOf(mono1.ignoreElement().then(mono2), mono1.flux().then(mono2));
}
@BeforeTemplate
Mono<@Nullable Void> before2(Mono<T> mono1, Mono<@Nullable Void> mono2) {
return mono1.thenEmpty(mono2);
}
@AfterTemplate
Mono<S> after(Mono<T> mono1, Mono<S> mono2) {
return mono1.then(mono2);
}
}
/** Avoid vacuous invocations of {@link Flux#ignoreElements()}. */
static final class FluxThenMono<T, S> {
@BeforeTemplate
Mono<S> before(Flux<T> flux, Mono<S> mono) {
return flux.ignoreElements().then(mono);
}
@BeforeTemplate
Mono<@Nullable Void> before2(Flux<T> flux, Mono<@Nullable Void> mono) {
return flux.thenEmpty(mono);
}
@AfterTemplate
Mono<S> after(Flux<T> flux, Mono<S> mono) {
return flux.then(mono);
}
}
/** 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
@@ -776,28 +1107,84 @@ final class ReactorRules {
}
}
/** Prefer {@link Mono#flatMap(Function)} over more contrived alternatives. */
static final class MonoFlatMap<S, T> {
/** Prefer {@link Mono#ofType(Class)} over more contrived alternatives. */
static final class MonoOfType<T, S> {
@BeforeTemplate
Mono<T> before(Mono<S> mono, Function<? super S, ? extends Mono<? extends T>> function) {
return mono.map(function).flatMap(identity());
Mono<S> before(Mono<T> mono, Class<S> clazz) {
return mono.filter(clazz::isInstance).cast(clazz);
}
@AfterTemplate
Mono<T> after(Mono<S> mono, Function<? super S, ? extends Mono<? extends T>> function) {
Mono<S> after(Mono<T> mono, Class<S> clazz) {
return mono.ofType(clazz);
}
}
/** Prefer {@link Flux#ofType(Class)} over more contrived alternatives. */
static final class FluxOfType<T, S> {
@BeforeTemplate
Flux<S> before(Flux<T> flux, Class<S> clazz) {
return flux.filter(clazz::isInstance).cast(clazz);
}
@AfterTemplate
Flux<S> after(Flux<T> flux, Class<S> clazz) {
return flux.ofType(clazz);
}
}
/** Prefer {@link Mono#flatMap(Function)} over more contrived alternatives. */
static final class MonoFlatMap<S, T, P extends Mono<? extends T>> {
@BeforeTemplate
@SuppressWarnings("NestedPublishers")
Mono<T> before(
Mono<S> mono,
Function<? super S, ? extends P> function,
@Matches(IsIdentityOperation.class)
Function<? super P, ? extends Mono<? extends T>> identityOperation) {
return mono.map(function).flatMap(identityOperation);
}
@AfterTemplate
Mono<T> after(Mono<S> mono, Function<? super S, ? extends P> function) {
return mono.flatMap(function);
}
}
/** Prefer {@link Mono#flatMapMany(Function)} over more contrived alternatives. */
static final class MonoFlatMapMany<S, T> {
static final class MonoFlatMapMany<S, T, P extends Publisher<? extends T>> {
@BeforeTemplate
Flux<T> before(Mono<S> mono, Function<? super S, ? extends Publisher<? extends T>> function) {
return mono.map(function).flatMapMany(identity());
@SuppressWarnings("NestedPublishers")
Flux<T> before(
Mono<S> mono,
Function<? super S, P> function,
@Matches(IsIdentityOperation.class)
Function<? super P, ? extends Publisher<? extends T>> identityOperation,
int prefetch,
boolean delayUntilEnd,
int maxConcurrency) {
return Refaster.anyOf(
mono.map(function).flatMapMany(identityOperation),
mono.flux().concatMap(function),
mono.flux().concatMap(function, prefetch),
mono.flux().concatMapDelayError(function),
mono.flux().concatMapDelayError(function, prefetch),
mono.flux().concatMapDelayError(function, delayUntilEnd, prefetch),
mono.flux().flatMap(function, maxConcurrency),
mono.flux().flatMap(function, maxConcurrency, prefetch),
mono.flux().flatMapDelayError(function, maxConcurrency, prefetch),
mono.flux().flatMapSequential(function, maxConcurrency),
mono.flux().flatMapSequential(function, maxConcurrency, prefetch),
mono.flux().flatMapSequentialDelayError(function, maxConcurrency, prefetch));
}
@BeforeTemplate
Flux<T> before(Mono<S> mono, Function<? super S, Publisher<? extends T>> function) {
return mono.flux().switchMap(function);
}
@AfterTemplate
Flux<T> after(Mono<S> mono, Function<? super S, ? extends Publisher<? extends T>> function) {
Flux<T> after(Mono<S> mono, Function<? super S, ? extends P> function) {
return mono.flatMapMany(function);
}
}
@@ -1177,6 +1564,22 @@ final class ReactorRules {
}
}
/**
* Do not unnecessarily {@link Flux#filter(Predicate) filter} the result of {@link
* Flux#takeWhile(Predicate)} using the same {@link Predicate}.
*/
static final class FluxTakeWhile<T> {
@BeforeTemplate
Flux<T> before(Flux<T> flux, Predicate<? super T> predicate) {
return flux.takeWhile(predicate).filter(predicate);
}
@AfterTemplate
Flux<T> after(Flux<T> flux, Predicate<? super T> predicate) {
return flux.takeWhile(predicate);
}
}
/**
* Prefer {@link Flux#collect(Collector)} with {@link ImmutableList#toImmutableList()} over
* alternatives that do not explicitly return an immutable collection.
@@ -1211,13 +1614,134 @@ 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 Flux#singleOrEmpty()} over {@link Flux#next()} when the {@link Flux} emits at
* most one element.
*/
// XXX: This is a special case of a more general rule. Consider introducing an Error Prone check
// for this.
// XXX: The `transformer` parameter isn't matched, unless the signature is changed to `? extends
// Publisher<S>`, which would make the rule incorrect.
static final class FluxTransformToMonoSingleOrEmpty<T, S> {
@BeforeTemplate
Mono<S> before(Flux<T> flux, Function<? super Flux<T>, ? extends Mono<S>> transformer) {
return flux.transform(transformer).next();
}
@AfterTemplate
Mono<S> after(Flux<T> flux, Function<? super Flux<T>, ? extends Mono<S>> transformer) {
return flux.transform(transformer).singleOrEmpty();
}
}
/** Prefer {@link reactor.util.context.Context#empty()}} over more verbose alternatives. */
// XXX: Consider introducing an `IsEmpty` matcher that identifies a wide range of guaranteed-empty
// `Collection` and `Map` expressions.
// 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.
static final class ContextEmpty {
@BeforeTemplate
Context before() {
return Context.of(Refaster.anyOf(new HashMap<>(), ImmutableMap.of()));
Context before(@Matches(IsEmpty.class) Map<?, ?> map) {
return Context.of(map);
}
@AfterTemplate
@@ -1243,7 +1767,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
@@ -1266,16 +1790,17 @@ final class ReactorRules {
}
/** Don't unnecessarily have {@link StepVerifier.Step} expect no elements. */
// XXX: Given an `IsEmpty` matcher that identifies a wide range of guaranteed-empty `Iterable`
// expressions, consider also simplifying `step.expectNextSequence(someEmptyIterable)`.
static final class StepVerifierStepIdentity<T> {
@BeforeTemplate
@SuppressWarnings("unchecked")
StepVerifier.Step<T> before(StepVerifier.Step<T> step) {
return Refaster.anyOf(step.expectNext(), step.expectNextCount(0));
StepVerifier.Step<T> before(
StepVerifier.Step<T> step, @Matches(IsEmpty.class) Iterable<? extends T> iterable) {
return Refaster.anyOf(
step.expectNext(), step.expectNextCount(0), step.expectNextSequence(iterable));
}
@AfterTemplate
@CanIgnoreReturnValue
StepVerifier.Step<T> after(StepVerifier.Step<T> step) {
return step;
}
@@ -1295,6 +1820,23 @@ final class ReactorRules {
}
}
/** Avoid list collection when verifying that a {@link Flux} emits exactly one value. */
// XXX: This rule assumes that the matched collector does not drop elements. Consider introducing
// a `@Matches(DoesNotDropElements.class)` or `@NotMatches(MayDropElements.class)` guard.
static final class FluxAsStepVerifierExpectNext<T, L extends List<T>> {
@BeforeTemplate
StepVerifier.Step<L> before(Flux<T> flux, T object, Collector<? super T, ?, L> listCollector) {
return flux.collect(listCollector)
.as(StepVerifier::create)
.assertNext(list -> assertThat(list).containsExactly(object));
}
@AfterTemplate
StepVerifier.Step<T> after(Flux<T> flux, T object) {
return flux.as(StepVerifier::create).expectNext(object);
}
}
/** Prefer {@link StepVerifier.LastStep#verifyComplete()} over more verbose alternatives. */
static final class StepVerifierLastStepVerifyComplete {
@BeforeTemplate
@@ -1327,6 +1869,7 @@ final class ReactorRules {
Duration before(StepVerifier.LastStep step, Class<T> clazz) {
return Refaster.anyOf(
step.expectError(clazz).verify(),
step.verifyErrorMatches(clazz::isInstance),
step.verifyErrorSatisfies(t -> assertThat(t).isInstanceOf(clazz)));
}

View File

@@ -19,13 +19,17 @@ import static java.util.stream.Collectors.summingDouble;
import static java.util.stream.Collectors.summingInt;
import static java.util.stream.Collectors.summingLong;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Matches;
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.NotMatches;
import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.Repeated;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Arrays;
import java.util.Collection;
@@ -41,11 +45,14 @@ import java.util.function.Predicate;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.function.UnaryOperator;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.matchers.IsIdentityOperation;
import tech.picnic.errorprone.refaster.matchers.IsLambdaExpressionOrMethodReference;
import tech.picnic.errorprone.refaster.matchers.IsRefasterAsVarargs;
/** Refaster rules related to expressions dealing with {@link Stream}s. */
@OnlineDocumentation
@@ -100,12 +107,9 @@ final class StreamRules {
* Prefer {@link Arrays#stream(Object[])} over {@link Stream#of(Object[])}, as the former is
* clearer.
*/
// XXX: Introduce a `Matcher` that identifies `Refaster.asVarargs(...)` invocations and annotate
// the `array` parameter as `@NotMatches(IsRefasterAsVarargs.class)`. Then elsewhere
// `@SuppressWarnings("StreamOfArray")` annotations can be dropped.
static final class StreamOfArray<T> {
@BeforeTemplate
Stream<T> before(T[] array) {
Stream<T> before(@NotMatches(IsRefasterAsVarargs.class) T[] array) {
return Stream.of(array);
}
@@ -123,6 +127,7 @@ final class StreamRules {
}
@AfterTemplate
@CanIgnoreReturnValue
Stream<T> after(Stream<T> stream) {
return stream;
}
@@ -352,6 +357,8 @@ final class StreamRules {
stream.filter(predicate).findAny().isEmpty());
}
// XXX: Consider extending `@Matches(IsIdentityOperation.class)` such that it can replace this
// template's `Refaster.anyOf` usage.
@BeforeTemplate
boolean before2(
Stream<T> stream,
@@ -390,6 +397,8 @@ final class StreamRules {
!stream.noneMatch(predicate), stream.filter(predicate).findAny().isPresent());
}
// XXX: Consider extending `@Matches(IsIdentityOperation.class)` such that it can replace this
// template's `Refaster.anyOf` usage.
@BeforeTemplate
boolean before2(
Stream<T> stream,
@@ -410,6 +419,8 @@ final class StreamRules {
return stream.noneMatch(Refaster.anyOf(not(predicate), predicate.negate()));
}
// XXX: Consider extending `@Matches(IsIdentityOperation.class)` such that it can replace this
// template's `Refaster.anyOf` usage.
@BeforeTemplate
boolean before2(
Stream<T> stream,
@@ -624,4 +635,117 @@ final class StreamRules {
return stream.flatMap(mapper).collect(collector);
}
}
static final class StreamsConcat<T> {
@BeforeTemplate
Stream<T> before(
@Repeated Stream<T> stream,
@Matches(IsIdentityOperation.class)
Function<? super Stream<T>, ? extends Stream<? extends T>> mapper) {
return Stream.of(Refaster.asVarargs(stream)).flatMap(mapper);
}
@AfterTemplate
Stream<T> after(@Repeated Stream<T> stream) {
return Streams.concat(Refaster.asVarargs(stream));
}
}
static final class StreamTakeWhile<T> {
@BeforeTemplate
Stream<T> before(Stream<T> stream, Predicate<? super T> predicate) {
return stream.takeWhile(predicate).filter(predicate);
}
@AfterTemplate
Stream<T> after(Stream<T> stream, Predicate<? super T> predicate) {
return stream.takeWhile(predicate);
}
}
/**
* Prefer {@link Stream#iterate(Object, Predicate, UnaryOperator)} over more contrived
* alternatives.
*/
static final class StreamIterate<T> {
@BeforeTemplate
Stream<T> before(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next) {
return Stream.iterate(seed, next).takeWhile(hasNext);
}
@AfterTemplate
Stream<T> after(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next) {
return Stream.iterate(seed, hasNext, next);
}
}
/** Prefer {@link Stream#of(Object)} over more contrived alternatives. */
// XXX: Generalize this and similar rules using an Error Prone check.
static final class StreamOf1<T> {
@BeforeTemplate
Stream<T> before(T e1) {
return ImmutableList.of(e1).stream();
}
@AfterTemplate
Stream<T> after(T e1) {
return Stream.of(e1);
}
}
/** Prefer {@link Stream#of(Object[])} over more contrived alternatives. */
// XXX: Generalize this and similar rules using an Error Prone check.
static final class StreamOf2<T> {
@BeforeTemplate
Stream<T> before(T e1, T e2) {
return ImmutableList.of(e1, e2).stream();
}
@AfterTemplate
Stream<T> after(T e1, T e2) {
return Stream.of(e1, e2);
}
}
/** Prefer {@link Stream#of(Object[])} over more contrived alternatives. */
// XXX: Generalize this and similar rules using an Error Prone check.
static final class StreamOf3<T> {
@BeforeTemplate
Stream<T> before(T e1, T e2, T e3) {
return ImmutableList.of(e1, e2, e3).stream();
}
@AfterTemplate
Stream<T> after(T e1, T e2, T e3) {
return Stream.of(e1, e2, e3);
}
}
/** Prefer {@link Stream#of(Object[])} over more contrived alternatives. */
// XXX: Generalize this and similar rules using an Error Prone check.
static final class StreamOf4<T> {
@BeforeTemplate
Stream<T> before(T e1, T e2, T e3, T e4) {
return ImmutableList.of(e1, e2, e3, e4).stream();
}
@AfterTemplate
Stream<T> after(T e1, T e2, T e3, T e4) {
return Stream.of(e1, e2, e3, e4);
}
}
/** Prefer {@link Stream#of(Object[])} over more contrived alternatives. */
// XXX: Generalize this and similar rules using an Error Prone check.
static final class StreamOf5<T> {
@BeforeTemplate
Stream<T> before(T e1, T e2, T e3, T e4, T e5) {
return ImmutableList.of(e1, e2, e3, e4, e5).stream();
}
@AfterTemplate
Stream<T> after(T e1, T e2, T e3, T e4, T e5) {
return Stream.of(e1, e2, e3, e4, e5);
}
}
}

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