Compare commits

..

156 Commits

Author SHA1 Message Date
Stephan Schroevers
967017eed9 [maven-release-plugin] prepare release v0.1.0 2022-08-10 15:06:30 +02:00
Rick Ossendrijver
b06945b833 Introduce utilities to validate Refaster template collections (#43)
The `Refaster` check is now located in the new `refaster-runner` Maven module.

The new `refaster-test-support` module exposes
`RefasterTemplateCollection#validate`, which for a given template collection
validates:
- That there exist corresponding `*Test{Input,Output}.java` files.
- That each template is exercised by precisely one method in these files.
2022-08-10 14:40:07 +02:00
Rick Ossendrijver
ef562c1644 Rewrite more ThrowableAssertAlternative#withMessage(String, Object...) expressions (#185) 2022-08-10 14:32:44 +02:00
Rick Ossendrijver
efbde936dc Only suggest bulk removal operations on sets (#186)
If a collection may contain duplicates, then removing a single occurrence of
each element in some other set is not equivalent to removing all such
occurrences.
2022-08-10 14:09:36 +02:00
Stephan Schroevers
c57653dd5b Introduce run-mutation-tests.sh (#170)
This script executes Pitest to determine the code base' mutation test coverage.
The set of tests executed can optionally be restricted by name. The results are 
found in each Maven module's `target/pit-reports` directory.
2022-08-09 14:38:19 +02:00
Stephan Schroevers
12b03e95b1 Manage version of org.apache.maven:maven-plugin-api (#183)
By managing the version of this dependency we expect Renovate to file a pull
request any time a new Maven version is released. Through a shared property,
this also enforces that the project is built using the latest Maven release.
2022-08-08 13:57:51 +02:00
Stephan Schroevers
c2f24ac739 Speed up the build (#169)
The build is sped up in two ways:
1. By tweaking the JVM flags passed to the main process.
2. By tweaking the JVM flags passed to the forked Surefire processes.
2022-08-08 13:41:27 +02:00
Rick Ossendrijver
4f5ea8beac Migrate from Travis CI to GitHub Actions (#158)
While there, drop the now-obsolete Takari Maven plugin.
2022-08-07 18:33:25 +02:00
Stephan Schroevers
21646ffcb1 Enable the BugPatternNaming check (#86)
While there, introduce a `.util` subpackage for non-`Bugchecker` classes.
2022-08-07 18:12:10 +02:00
Picnic-Bot
c58dceb9df Upgrade errorprone-slf4j 0.1.12 -> 0.1.13 (#53)
See:
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.13
- https://github.com/KengoTODA/errorprone-slf4j/compare/v0.1.12...v0.1.13
2022-08-07 14:21:02 +02:00
Picnic-Bot
90ef2f4042 Upgrade pitest-maven-plugin 1.9.3 -> 1.9.4 (#178)
See:
- https://github.com/hcoles/pitest/releases/tag/1.9.4
- https://github.com/hcoles/pitest/compare/1.9.3...1.9.4
2022-08-06 10:17:26 +02:00
Picnic-Bot
459a498d6c Upgrade maven-site-plugin 3.12.0 -> 3.12.1 (#177)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MSITE%20AND%20fixVersion%20%3E%203.12.0%20AND%20fixVersion%20%3C%3D%203.12.1%20AND%20statusCategory%20%3D%20Done%20
- https://github.com/apache/maven-site-plugin/compare/maven-site-plugin-3.12.0...maven-site-plugin-3.12.1
2022-08-06 09:39:38 +02:00
Picnic-Bot
78035644dc Upgrade NullAway 0.9.8 -> 0.9.9 (#175)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/compare/v0.9.8...v0.9.9
2022-08-05 09:10:49 +02:00
Picnic-Bot
ef67d41512 Upgrade pitest-maven-plugin 1.9.2 -> 1.9.3 (#159)
See:
- https://github.com/hcoles/pitest/releases/tag/1.9.3
- https://github.com/hcoles/pitest/compare/1.9.2...1.9.3
2022-08-04 16:53:54 +02:00
Picnic-Bot
4cecff923a Upgrade Checker Framework Annotations 3.23.0 -> 3.24.0 (#174)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.24.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.23.0...checker-framework-3.24.0
2022-08-04 08:10:10 +02:00
Stephan Schroevers
38a57db994 Introduce ErrorProneTestHelperSourceFormat check (#147)
This new checker inspects inline code passed to `CompilationTestHelper` and
`BugCheckerRefactoringTestHelper` instances. It requires that this code is
properly formatted and that its imports are organized. Only code that
represents the expected output of a refactoring operation is allowed to have
unused imports, as most `BugChecker`s do not (and are not able to) remove
imports that become obsolete as a result of applying their suggested fix(es).
2022-08-03 21:47:31 +02:00
Stephan Schroevers
336557cf8e Introduce apply-error-prone-suggestions.sh (#171)
This script compiles the code using Error Prone and applies its suggestions. 
The set of checks applied can optionally be restricted by name.
2022-08-03 17:05:38 +02:00
Picnic-Bot
9055dfff19 Upgrade Checkstyle 10.3.1 -> 10.3.2 (#173)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.3.2
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.3.1...checkstyle-10.3.2
2022-08-02 12:26:40 +02:00
Rick Ossendrijver
3712a15195 Implement workaround for MCOMPILER-503 (#149)
By moving around some annotation processor classpath entries we ensure that the
`maven-compiler-plugin` uses the appropriate version of Error Prone.

See https://issues.apache.org/jira/browse/MCOMPILER-503
2022-08-02 09:36:46 +02:00
Picnic-Bot
9d487e4a88 Upgrade New Relic Java Agent 7.8.0 -> 7.9.0 (#168)
See:
- https://github.com/newrelic/newrelic-java-agent/releases/tag/v7.9.0
- https://github.com/newrelic/newrelic-java-agent/compare/v7.8.0...v7.9.0
2022-08-01 17:35:58 +02:00
Picnic-Bot
b2b086761c Upgrade JUnit Jupiter 5.8.2 -> 5.9.0 (#167)
See:
- https://junit.org/junit5/docs/current/release-notes/index.html
- https://github.com/junit-team/junit5/releases/tag/r5.9.0
- https://github.com/junit-team/junit5/compare/r5.8.2...r5.9.0
2022-08-01 17:27:08 +02:00
Picnic-Bot
ff64247b6d Upgrade maven-resources-plugin 3.2.0 -> 3.3.0 (#166)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MRESOURCES%20AND%20fixVersion%20%3E%203.2.0%20AND%20fixVersion%20%3C%3D%203.3.0
- https://github.com/apache/maven-resources-plugin/compare/maven-resources-plugin-3.2.0...maven-resources-plugin-3.3.0
2022-08-01 17:15:19 +02:00
Picnic-Bot
bc7443c72d Upgrade maven-install-plugin 3.0.0 -> 3.0.1 (#164)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MINSTALL%20AND%20fixVersion%20%3E%20%203.0.0%20AND%20fixVersion%20%3C%3D%203.0.1
- https://github.com/apache/maven-install-plugin/compare/maven-install-plugin-3.0.0...maven-install-plugin-3.0.1
2022-08-01 16:21:54 +02:00
Picnic-Bot
abf4d68fba Upgrade extra-enforcer-rules 1.6.0 -> 1.6.1 (#165)
See:
- https://github.com/mojohaus/extra-enforcer-rules/releases/tag/extra-enforcer-rules-1.6.1
- https://github.com/mojohaus/extra-enforcer-rules/compare/extra-enforcer-rules-1.6.0...extra-enforcer-rules-1.6.1
2022-08-01 16:20:24 +02:00
Picnic-Bot
5c5f7d849e Upgrade Guava 31.0.1-jre -> 31.1-jre (#77)
See:
- https://guava.dev/releases/31.1-jre/api/diffs/
- https://github.com/google/guava/releases/tag/v31.1
- https://github.com/google/guava/compare/v31.0.1...v31.1
2022-08-01 14:48:56 +02:00
Picnic-Bot
65c4694936 Upgrade Error Prone 2.10.0 -> 2.14.0 (#76)
This also requires the upgrade of errorprone-slf4j 0.1.4 -> 0.1.12.

See:
- https://github.com/google/error-prone/releases/tag/v2.11.0
- https://github.com/google/error-prone/releases/tag/v2.12.0
- https://github.com/google/error-prone/releases/tag/v2.12.1
- https://github.com/google/error-prone/releases/tag/v2.13.0
- https://github.com/google/error-prone/releases/tag/v2.13.1
- https://github.com/google/error-prone/releases/tag/v2.14.0
- https://github.com/google/error-prone/compare/v2.10.0...v2.14.0
- https://github.com/PicnicSupermarket/error-prone/compare/v2.10.0-picnic-3...v2.14.0-picnic-2
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.5
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.6
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.7
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.8
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.9
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.10
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.11
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.12
- https://github.com/KengoTODA/errorprone-slf4j/compare/v0.1.4...v0.1.12
2022-07-31 15:50:16 +02:00
Picnic-Bot
a45291c7d8 Upgrade Spring Boot 2.7.1 -> 2.7.2 (#163)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.2
- https://github.com/spring-projects/spring-boot/compare/v2.7.1...v2.7.2
2022-07-30 15:11:37 +02:00
Picnic-Bot
71012f31ab Upgrade swagger-annotations 2.2.1 -> 2.2.2 (#162)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.2
- https://github.com/swagger-api/swagger-core/compare/v2.2.1...v2.2.2
2022-07-30 14:43:54 +02:00
Picnic-Bot
6e0905c033 Upgrade maven-install-plugin 2.5.2 -> 3.0.0 (#161)
See: 
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MINSTALL%20AND%20fixVersion%20%3E%20%202.5.2%20AND%20fixVersion%20%3C%3D%203.0.0
- https://github.com/apache/maven-install-plugin/compare/maven-install-plugin-2.5.2...maven-install-plugin-3.0.0
2022-07-21 09:01:43 +02:00
Picnic-Bot
af5ac85428 Upgrade maven-deploy-plugin 2.8.2 -> 3.0.0 (#160)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MDEPLOY%20AND%20fixVersion%20%3E%202.8.2%20AND%20fixVersion%20%3C%3D%203.0.0
- https://github.com/apache/maven-deploy-plugin/compare/maven-deploy-plugin-2.8.2...maven-deploy-plugin-3.0.0
2022-07-21 08:49:42 +02:00
Picnic-Bot
0329c25f78 Upgrade sortpom-maven-plugin 3.1.3 -> 3.2.0 (#157)
See:
- https://github.com/Ekryd/sortpom/wiki/Versions
- https://github.com/Ekryd/sortpom/releases/tag/sortpom-parent-3.2.0
- https://github.com/Ekryd/sortpom/compare/sortpom-parent-3.1.3...sortpom-parent-3.2.0
2022-07-21 08:04:22 +02:00
Picnic-Bot
9e67e2b795 Upgrade Spring 5.3.21 -> 5.3.22 (#155)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.22
- https://github.com/spring-projects/spring-framework/compare/v5.3.21...v5.3.22
2022-07-15 14:52:27 +02:00
Picnic-Bot
4bafea05f4 Upgrade Project Reactor 2020.0.20 -> 2020.0.21 (#154)
See:
- https://github.com/reactor/reactor/releases/tag/2020.0.21
- https://github.com/reactor/reactor/compare/2020.0.20...2020.0.21
2022-07-15 08:46:21 +02:00
Picnic-Bot
8ce9cab2dd Upgrade Checker Framework Annotations 3.22.2 -> 3.23.0 (#153)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.23.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.22.2...checker-framework-3.23.0
2022-07-13 07:34:25 +02:00
Pieter Dirk Soels
ae30625524 Clarify MapToNullable Refaster template (#150) 2022-07-12 12:54:22 +02:00
Picnic-Bot
dc0046ebfc Upgrade extra-enforcer-rules 1.5.1 -> 1.6.0 (#152)
See:
- https://github.com/mojohaus/extra-enforcer-rules/releases/tag/extra-enforcer-rules-1.6.0
- https://github.com/mojohaus/extra-enforcer-rules/compare/extra-enforcer-rules-1.5.1...extra-enforcer-rules-1.6.0
2022-07-12 11:41:23 +02:00
Picnic-Bot
ad6d774818 Upgrade pitest-maven-plugin 1.9.0 -> 1.9.2 (#151)
See:
- https://github.com/hcoles/pitest/releases/tag/1.9.1
- https://github.com/hcoles/pitest/releases/tag/1.9.2
- https://github.com/hcoles/pitest/compare/1.9.0...1.9.2
2022-07-12 11:11:30 +02:00
Stephan Schroevers
405f5874ac Apply Checkstyle to Refaster test resources (#146)
Similar to formatting the `*TemplatesTest{In,Out}put.java` files to enforce
certain style aspects, this is expected to reduce future code review effort.

The test code changes were applied to appease the
`SimplifyBooleanExpression` check.
2022-07-06 13:39:59 +02:00
Stephan Schroevers
bf5199ea3d Fix build-time Refaster template loading (#121)
When using the system classloader, `RefasterCheckTest` is able to
successfully load the Refaster templates from the classpath, causing the
tests to pass. However, when during a build the Java compiler loads
`RefasterCheck`, the templates on the annotation processor classpath are
_not_ exposed through the system classloader.
2022-06-30 13:30:03 +02:00
Gijs de Jong
c500516bb4 Prefer AssertJ's isNull() assertion over isEqualTo(null) (#133) 2022-06-29 18:55:22 +02:00
Picnic-Bot
85d68a4f34 Upgrade Spring Boot 2.5.14 -> 2.7.1 (#81)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v2.6.0-M1
- https://github.com/spring-projects/spring-boot/releases/tag/v2.6.0-M2
- https://github.com/spring-projects/spring-boot/releases/tag/v2.6.0-M3
- https://github.com/spring-projects/spring-boot/releases/tag/v2.6.0-RC1
- https://github.com/spring-projects/spring-boot/releases/tag/v2.6.0
- https://github.com/spring-projects/spring-boot/releases/tag/v2.6.1
- https://github.com/spring-projects/spring-boot/releases/tag/v2.6.2
- https://github.com/spring-projects/spring-boot/releases/tag/v2.6.3
- https://github.com/spring-projects/spring-boot/releases/tag/v2.6.4
- https://github.com/spring-projects/spring-boot/releases/tag/v2.6.5
- https://github.com/spring-projects/spring-boot/releases/tag/v2.6.6
- https://github.com/spring-projects/spring-boot/releases/tag/v2.6.7
- https://github.com/spring-projects/spring-boot/releases/tag/v2.6.8
- https://github.com/spring-projects/spring-boot/releases/tag/v2.6.9
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.0-M1
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.0-M2
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.0-M3
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.0-RC1
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.0
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.1
- https://github.com/spring-projects/spring-boot/compare/v2.5.14...v2.7.1
2022-06-29 10:33:15 +02:00
Rick Ossendrijver
46467951dd Have Checkstyle disallow blank lines at the start of blocks (#141) 2022-06-28 14:11:55 +02:00
Picnic-Bot
6f7ce2067f Upgrade Checkstyle 10.3 -> 10.3.1 (#148)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.3.1
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.3...checkstyle-10.3.1
2022-06-28 12:58:32 +02:00
Gijs de Jong
f30ba36d18 Prefer {Mono,Flux}#cast over {Mono,Flux}#map performing a cast (#127) 2022-06-28 08:51:26 +02:00
Picnic-Bot
65736ce83f Upgrade NullAway 0.9.7 -> 0.9.8 (#145)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/compare/v0.9.7...v0.9.8
2022-06-27 08:19:39 +02:00
Rick Ossendrijver
17d5805d5a Drop public modifier from BugPattern test classes (#136) 2022-06-26 11:20:07 +02:00
Picnic-Bot
ce01b62832 Upgrade pitest-maven-plugin 1.8.1 -> 1.9.0 and pitest-junit5-plugin 0.16 -> 1.0.0 (#143)
See:
- https://github.com/hcoles/pitest/releases/tag/1.9.0
- https://github.com/hcoles/pitest/compare/1.8.1...1.9.0
- https://github.com/pitest/pitest-junit5-plugin/compare/0.16...1.0.0
2022-06-24 14:51:13 +02:00
Picnic-Bot
4ee555c62b Upgrade maven-enforcer-plugin 3.0.0 -> 3.1.0 (#126)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MENFORCER%20AND%20fixVersion%20%3E%203.0.0%20AND%20fixVersion%20%3C%3D%203.1.0%20
- https://github.com/apache/maven-enforcer/compare/enforcer-3.0.0...enforcer-3.1.0
2022-06-21 13:23:32 +02:00
Gijs de Jong
a24bbbe99d Rewrite Web{,Test}Client HTTP method specification expressions (#129) 2022-06-21 07:37:04 +02:00
Gijs de Jong
679e83bc48 Replace unnecessary UriBuilder arguments passed to Web(Test)Client#uri (#128) 2022-06-20 22:37:49 +02:00
Gijs de Jong
0bdc171613 Introduce CollectorMutability check (#135)
This check flags `Collectors.to{List,Map,Set}` usages, suggesting that they be
replaced with expressions that clearly indicate the (im)mutability of the 
resultant collection.

Refaster templates that violated the new check are simplified by removing the
relevant expressions; they were too contrived to be updated some other way.
2022-06-20 11:08:06 +02:00
Picnic-Bot
9b05ec62c6 Upgrade Spring Boot 2.5.6 -> 2.5.14 (#134)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v2.5.7
- https://github.com/spring-projects/spring-boot/releases/tag/v2.5.8
- https://github.com/spring-projects/spring-boot/releases/tag/v2.5.9
- https://github.com/spring-projects/spring-boot/releases/tag/v2.5.10
- https://github.com/spring-projects/spring-boot/releases/tag/v2.5.11
- https://github.com/spring-projects/spring-boot/releases/tag/v2.5.12
- https://github.com/spring-projects/spring-boot/releases/tag/v2.5.13
- https://github.com/spring-projects/spring-boot/releases/tag/v2.5.14
- https://github.com/spring-projects/spring-boot/compare/v2.5.6...v2.5.14
2022-06-20 09:52:31 +02:00
Picnic-Bot
72866183f5 Upgrade Spring 5.3.20 -> 5.3.21 (#139)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.21
- https://github.com/spring-projects/spring-framework/compare/v5.3.20...v5.3.21
2022-06-20 09:08:43 +02:00
Picnic-Bot
9d7f569be5 Upgrade swagger-annotations 2.2.0 -> 2.2.1 (#137)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.1
- https://github.com/swagger-api/swagger-core/compare/v2.2.0...v2.2.1
2022-06-19 17:59:34 +02:00
Picnic-Bot
f72adca292 Upgrade New Relic Java Agent 7.7.0 -> 7.8.0 (#140)
See:
- https://github.com/newrelic/newrelic-java-agent/releases/tag/v7.8.0
- https://github.com/newrelic/newrelic-java-agent/compare/v7.7.0...v7.8.0
2022-06-19 15:35:04 +02:00
Picnic-Bot
5148143ae5 Upgrade Project Reactor 2020.0.19 -> 2020.0.20 (#130)
See:
- https://github.com/reactor/reactor/releases/tag/2020.0.20
- https://github.com/reactor/reactor/compare/2020.0.19...2020.0.20
2022-06-19 15:07:38 +02:00
Picnic-Bot
3d7fbbf7a2 Upgrade pitest-maven-plugin 1.8.0 -> 1.8.1 (#138)
See:
- https://github.com/hcoles/pitest/releases/tag/1.8.1
- https://github.com/hcoles/pitest/compare/1.8.0...1.8.1
2022-06-19 14:57:43 +02:00
Picnic-Bot
8b6864d8a0 Upgrade baseline-error-prone 4.42.0 -> 4.145.0 (#58)
See:
- https://github.com/palantir/gradle-baseline/releases/tag/4.47.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.48.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.49.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.50.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.51.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.52.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.53.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.54.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.55.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.56.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.57.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.58.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.59.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.60.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.61.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.62.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.63.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.64.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.65.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.66.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.67.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.68.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.69.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.70.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.71.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.72.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.73.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.74.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.75.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.76.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.77.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.78.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.79.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.80.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.81.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.82.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.83.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.84.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.85.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.86.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.87.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.88.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.89.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.90.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.91.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.92.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.93.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.94.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.95.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.96.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.97.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.98.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.99.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.100.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.101.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.102.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.103.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.104.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.105.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.106.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.107.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.108.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.109.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.110.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.111.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.112.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.113.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.114.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.115.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.116.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.117.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.118.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.119.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.120.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.121.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.122.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.123.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.124.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.125.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.126.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.127.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.128.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.129.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.130.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.131.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.132.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.133.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.134.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.135.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.136.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.137.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.138.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.139.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.140.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.141.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.142.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.143.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.144.0
- https://github.com/palantir/gradle-baseline/releases/tag/4.145.0
- https://github.com/palantir/gradle-baseline/compare/4.46.0...4.145.0
2022-06-19 14:40:46 +02:00
Picnic-Bot
a03017b5e6 Upgrade Checker Framework Annotations 3.22.1 -> 3.22.2 (#131)
See https://github.com/typetools/checker-framework/compare/checker-framework-3.22.1...checker-framework-3.22.2
2022-06-16 22:23:05 +02:00
Rick Ossendrijver
a227436f19 Introduce .renovaterc.json (#125) 2022-06-15 16:46:12 +02:00
Picnic-Bot
3f6558b7c0 Upgrade fmt-maven-plugin 2.18 -> 2.19 (#132)
See:
- https://github.com/spotify/fmt-maven-plugin/releases/tag/2.19.0
- https://github.com/spotify/fmt-maven-plugin/compare/2.18.0...2.19.0
2022-06-15 08:43:35 +02:00
Picnic-Bot
ce06396521 Upgrade pitest-junit5-plugin 0.15 -> 0.16 (#124)
See https://github.com/pitest/pitest-junit5-plugin/compare/0.15...0.16
2022-06-11 14:39:01 +02:00
Rick Ossendrijver
268766a32a Fix copy-paste error in ReactorTemplates Javadoc (#123) 2022-06-09 09:08:36 +02:00
Rick Ossendrijver
5366effd74 Upgrade Error Prone fork v2.10.0-picnic-1 -> v2.10.0-picnic-3 (#120)
See:
- https://github.com/PicnicSupermarket/error-prone/releases/tag/v2.10.0-picnic-2
- https://github.com/PicnicSupermarket/error-prone/releases/tag/v2.10.0-picnic-3
- https://github.com/PicnicSupermarket/error-prone/compare/v2.10.0-picnic-1...v2.10.0-picnic-3
2022-06-08 12:55:40 +02:00
Picnic-Bot
0a63361500 Upgrade Truth 1.0.1 -> 1.1.3 (#78)
See:
- https://github.com/google/truth/releases/tag/release_1_1
- https://github.com/google/truth/releases/tag/release_1_1_1
- https://github.com/google/truth/releases/tag/release_1_1_2
- https://github.com/google/truth/releases/tag/release_1_1_3
- https://github.com/google/truth/compare/release_1_0_1...release_1_1_3
2022-06-05 20:52:45 +02:00
Picnic-Bot
a074e2fdd6 Upgrade Checker Framework Annotations 3.22.0 -> 3.22.1 (#117)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.22.1
- https://github.com/typetools/checker-framework/compare/checker-framework-3.22.0...checker-framework-3.22.1
2022-06-03 14:59:14 +02:00
Picnic-Bot
f06d4e41cf Upgrade Mockito 4.6.0 -> 4.6.1 (#118)
See:
- https://github.com/mockito/mockito/releases/tag/v4.6.1
- https://github.com/mockito/mockito/compare/v4.6.0...v4.6.1
2022-06-03 09:20:27 +02:00
Rick Ossendrijver
cf7bb657fa Enable Checkstyle's LocalVariableName check (#111) 2022-06-01 16:53:07 +02:00
Rick Ossendrijver
8277b43955 Move Refaster template test resources to proper package (#113) 2022-06-01 14:55:29 +02:00
Picnic-Bot
691f2c8311 Upgrade AssertJ Core 3.22.0 -> 3.23.1 (#116)
See:
- https://assertj.github.io/doc/#assertj-core-release-notes
- https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.22.0...assertj-core-3.23.1
2022-06-01 13:09:17 +02:00
Rick Ossendrijver
362518b0f4 Resolve Refaster template naming and test inconsistencies (#109) 2022-05-31 13:54:17 +02:00
Picnic-Bot
b9a3840e25 Upgrade Checkstyle 10.2 -> 10.3 (#115)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.3
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.2...checkstyle-10.3
2022-05-31 10:40:39 +02:00
Picnic-Bot
14d8bddbec Upgrade sortpom-maven-plugin 3.0.1 -> 3.1.3 (#112)
See:
- https://github.com/Ekryd/sortpom/wiki/Versions
- https://github.com/Ekryd/sortpom/releases/tag/sortpom-parent-3.1.0
- https://github.com/Ekryd/sortpom/releases/tag/sortpom-parent-3.1.1
- https://github.com/Ekryd/sortpom/releases/tag/sortpom-parent-3.1.2
- https://github.com/Ekryd/sortpom/releases/tag/sortpom-parent-3.1.3
- https://github.com/Ekryd/sortpom/compare/sortpom-parent-3.0.1...sortpom-parent-3.1.3
2022-05-31 09:51:13 +02:00
Picnic-Bot
6c7a0b81ea Upgrade Mockito 4.5.1 -> 4.6.0 (#114)
See:
- https://github.com/mockito/mockito/releases/tag/v4.6.0
- https://github.com/mockito/mockito/compare/v4.5.1...v4.6.0
2022-05-31 09:35:59 +02:00
David Mischke
3a3825f7ba Simplify unnecessary String.format(...) expressions passed to AssertJ (#101) 2022-05-26 14:24:23 +02:00
Stephan Schroevers
31e54cc990 Enforce test resources code formatting (#105)
This change should have been part of #75.
2022-05-26 13:56:19 +02:00
Pim Tegelaar
775a2688ca Introduce AssertJThrowingCallableTemplates (#92) 2022-05-26 13:29:35 +02:00
Rick Ossendrijver
3d854a0cc5 Rename RefasterRuleResourceCompiler to RefasterRuleCompiler (#110)
The associated Maven module is renamed from `refaster-resource-compiler` to
just `refaster-compiler`.
2022-05-26 13:21:28 +02:00
Stephan Schroevers
6ee013da58 Drop unnecessary dependency declarations (#106) 2022-05-26 10:51:47 +02:00
David Mischke
962d18dcb5 Drop unnecessary AssertJ usage in StepVerifier expression (#103) 2022-05-23 22:55:09 +02:00
Picnic-Bot
aab308a190 Upgrade pitest-maven-plugin 1.7.6 -> 1.8.0 (#108)
See:
- https://github.com/hcoles/pitest/releases/tag/1.8.0
- https://github.com/hcoles/pitest/compare/1.7.6...1.8.0
2022-05-23 09:21:53 +02:00
Picnic-Bot
009bd5d0d7 Upgrade versions-maven-plugin 2.10.0 -> 2.11.0 (#107)
See:
- https://github.com/mojohaus/versions-maven-plugin/releases/tag/versions-maven-plugin-2.11.0
- https://github.com/mojohaus/versions-maven-plugin/compare/versions-maven-plugin-2.10.0...versions-maven-plugin-2.11.0
2022-05-23 08:45:15 +02:00
Pim Tegelaar
8e57f64e31 Prevent JUnitMethodDeclarationCheck from renaming likely-overridden methods (#93) 2022-05-17 18:15:31 +02:00
Picnic-Bot
53e81f3611 Upgrade Jackson 2.13.2.20220328 -> 2.13.3 (#100)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.13.3
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.13.2.20220328...jackson-bom-2.13.3
2022-05-17 11:41:56 +02:00
Picnic-Bot
8745105251 Upgrade Spring 5.3.19 -> 5.3.20 (#99)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.20
- https://github.com/spring-projects/spring-framework/compare/v5.3.19...v5.3.20
2022-05-17 11:24:18 +02:00
Picnic-Bot
3eb3c20b1d Upgrade Project Reactor 2020.0.18 -> 2020.0.19 (#98)
See:
- https://github.com/reactor/reactor/releases/tag/2020.0.19
- https://github.com/reactor/reactor/compare/2020.0.18...2020.0.19
2022-05-17 10:26:33 +02:00
Picnic-Bot
121618f277 Upgrade NullAway 0.9.6 -> 0.9.7 (#97)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/compare/v0.9.6...v0.9.7
2022-05-17 10:09:59 +02:00
Picnic-Bot
5cf4194168 Upgrade pitest-maven-plugin 1.7.5 -> 1.7.6 (#94)
See:
- https://github.com/hcoles/pitest/releases/tag/1.7.6
- https://github.com/hcoles/pitest/compare/1.7.5...1.7.6
2022-05-10 09:28:27 +02:00
Picnic-Bot
c434cd318c Upgrade New Relic Java Agent 7.6.0 -> 7.7.0
See:
- https://github.com/newrelic/newrelic-java-agent/releases/tag/v7.7.0
- https://github.com/newrelic/newrelic-java-agent/compare/v7.6.0...v7.7.0
2022-05-10 09:02:30 +02:00
Picnic-Bot
22aa9cb213 Upgrade Checker Framework Annotations 3.21.4 -> 3.22.0
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.22.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.21.4...checker-framework-3.22.0
2022-05-10 07:36:16 +02:00
Rick Ossendrijver
3edc483e7c Extend set of parameter types recognized by RequestMappingAnnotationCheck (#91)
While there, restrict the supported set of `WebRequest` subtypes to just
`WebRequest` and `NativeWebRequest`.
2022-04-29 14:15:51 +02:00
Stephan Schroevers
fff5d7b329 Apply assorted Maven parent improvements (#85) 2022-04-29 13:35:14 +02:00
Picnic-Bot
4ca80952ab Upgrade modernizer-maven-plugin 2.3.0 -> 2.4.0 (#90)
See:
- https://github.com/gaul/modernizer-maven-plugin/releases/tag/modernizer-maven-plugin-2.4.0
- https://github.com/gaul/modernizer-maven-plugin/compare/modernizer-maven-plugin-2.3.0...modernizer-maven-plugin-2.4.0
2022-04-26 12:52:11 +02:00
Picnic-Bot
8cecb8bf30 Upgrade Spring 5.3.13 -> 5.3.19 (#74)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.14
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.15
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.16
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.17
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.18
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.19
- https://github.com/spring-projects/spring-framework/compare/v5.3.13...v5.3.19
2022-04-26 12:38:23 +02:00
Picnic-Bot
a937bf0ddf Upgrade Checker Framework Annotations 3.19.0 -> 3.21.4 (#87)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.20.0
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.21.0
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.21.1
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.21.2
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.21.3
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.21.4
- https://github.com/typetools/checker-framework/compare/checker-framework-3.19.0...checker-framework-3.21.4
2022-04-26 12:31:02 +02:00
Picnic-Bot
0b71c2b576 Upgrade versions-maven-plugin 2.8.1 -> 2.10.0 (#89)
See:
- https://github.com/mojohaus/versions-maven-plugin/releases/tag/versions-maven-plugin-2.9.0
- https://github.com/mojohaus/versions-maven-plugin/releases/tag/versions-maven-plugin-2.10.0
- https://github.com/mojohaus/versions-maven-plugin/compare/versions-maven-plugin-2.8.1...versions-maven-plugin-2.10.0
2022-04-26 11:35:51 +02:00
Picnic-Bot
239d38d69f Upgrade extra-enforcer-rules 1.4 -> 1.5.1 (#88)
See:
- https://github.com/mojohaus/extra-enforcer-rules/releases/tag/extra-enforcer-rules-1.5.0
- https://github.com/mojohaus/extra-enforcer-rules/releases/tag/extra-enforcer-rules-1.5.1
- https://github.com/mojohaus/extra-enforcer-rules/compare/extra-enforcer-rules-1.4...extra-enforcer-rules-1.5.1
2022-04-26 11:09:17 +02:00
Picnic-Bot
ab57aa5eb6 Upgrade pitest-maven-plugin 1.7.3 -> 1.7.5 (#72)
See:
- https://github.com/hcoles/pitest/releases/tag/1.7.4
- https://github.com/hcoles/pitest/releases/tag/1.7.5
- https://github.com/hcoles/pitest/compare/1.7.3...1.7.5
2022-04-25 22:46:44 +02:00
Picnic-Bot
49267337cb Upgrade JUnit Jupiter 5.8.1 -> 5.8.2 (#71)
See:
- https://junit.org/junit5/docs/current/release-notes/index.html
- https://github.com/junit-team/junit5/releases/tag/r5.8.2
- https://github.com/junit-team/junit5/compare/r5.8.1...r5.8.2
2022-04-25 13:56:02 +02:00
Picnic-Bot
c201fe1fd2 Upgrade SLF4J API 1.7.32 -> 1.7.36 (#73)
See:
- https://www.slf4j.org/news.html
- https://github.com/qos-ch/slf4j/compare/v_1.7.32...v_1.7.36
2022-04-25 13:48:50 +02:00
Picnic-Bot
fb20b6f93d Upgrade AutoValue 1.8.2 -> 1.9 (#83)
See:
- https://github.com/google/auto/releases/tag/auto-value-1.9
- https://github.com/google/auto/compare/auto-value-1.8.2...auto-value-1.9
2022-04-25 13:36:41 +02:00
Picnic-Bot
9264c25b57 Upgrade fmt-maven-plugin 2.12 -> 2.18 (#75)
This also upgrades Google Java Format 1.11.0 -> 1.15.0, improving support for 
Java 17 syntax, among other things.

See:
- https://github.com/google/google-java-format/releases/tag/v1.12.0
- https://github.com/google/google-java-format/releases/tag/v1.13.0
- https://github.com/google/google-java-format/releases/tag/v1.14.0
- https://github.com/google/google-java-format/releases/tag/v1.15.0
- https://github.com/google/google-java-format/compare/v1.11.0...v1.15.0
- https://github.com/spotify/fmt-maven-plugin/releases/tag/2.13.0
- https://github.com/spotify/fmt-maven-plugin/releases/tag/2.14.0
- https://github.com/spotify/fmt-maven-plugin/releases/tag/2.15.0
- https://github.com/spotify/fmt-maven-plugin/releases/tag/2.16.0
- https://github.com/spotify/fmt-maven-plugin/releases/tag/2.17.0
- https://github.com/spotify/fmt-maven-plugin/releases/tag/2.18.0
- https://github.com/spotify/fmt-maven-plugin/compare/2.12.0...2.18.0
2022-04-25 13:29:19 +02:00
Picnic-Bot
ca628eef6c Upgrade New Relic Java Agent 7.4.3 -> 7.6.0 (#79)
See:
- https://github.com/newrelic/newrelic-java-agent/releases/tag/v7.5.0
- https://github.com/newrelic/newrelic-java-agent/releases/tag/v7.6.0
- https://github.com/newrelic/newrelic-java-agent/compare/v7.4.3...v7.6.0
2022-04-25 09:27:25 +02:00
Picnic-Bot
62168dcd4b Upgrade Checkstyle 10.1 -> 10.2 (#80)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.2
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.1...checkstyle-10.2
2022-04-25 09:17:24 +02:00
Picnic-Bot
96a82eaf85 Upgrade Mockito 4.0.0 -> 4.5.1 (#84)
See:
- https://github.com/mockito/mockito/releases/tag/v4.1.0
- https://github.com/mockito/mockito/releases/tag/v4.2.0
- https://github.com/mockito/mockito/releases/tag/v4.3.0
- https://github.com/mockito/mockito/releases/tag/v4.3.1
- https://github.com/mockito/mockito/releases/tag/v4.4.0
- https://github.com/mockito/mockito/releases/tag/v4.5.0
- https://github.com/mockito/mockito/releases/tag/v4.5.1
- https://github.com/mockito/mockito/compare/v4.0.0...v4.5.1
2022-04-25 09:06:44 +02:00
Picnic-Bot
0c615b4c15 Upgrade Project Reactor 2020.0.13 -> 2020.0.18 (#51)
See:
- https://github.com/reactor/reactor/releases/tag/2020.0.14
- https://github.com/reactor/reactor/releases/tag/2020.0.15
- https://github.com/reactor/reactor/releases/tag/2020.0.16
- https://github.com/reactor/reactor/releases/tag/2020.0.17
- https://github.com/reactor/reactor/releases/tag/2020.0.18
- https://github.com/reactor/reactor/compare/2020.0.13...2020.0.18
2022-04-24 17:05:53 +02:00
Picnic-Bot
6304130ae3 Upgrade swagger-annotations 1.6.3 -> 1.6.6 (#52)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v1.6.4
- https://github.com/swagger-api/swagger-core/releases/tag/v1.6.5
- https://github.com/swagger-api/swagger-core/releases/tag/v1.6.6
- https://github.com/swagger-api/swagger-core/compare/v1.6.3...v1.6.6
2022-04-24 16:57:18 +02:00
Picnic-Bot
1674e99ba4 Upgrade maven-jar-plugin 3.2.0 -> 3.2.2 (#54)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MJAR%20AND%20fixVersion%20%3E%203.2.0%20AND%20fixVersion%20%3C%3D%203.2.2
- https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.2.0...maven-jar-plugin-3.2.2
2022-04-24 16:49:47 +02:00
Picnic-Bot
75bbc8e5b5 Upgrade AspectJ 1.9.7 -> 1.9.9.1 (#55)
See:
- https://github.com/eclipse/org.aspectj/releases/tag/V1_9_8
- https://github.com/eclipse/org.aspectj/releases/tag/V1_9_9
- https://github.com/eclipse/org.aspectj/releases/tag/V1_9_9_1
- https://github.com/eclipse/org.aspectj/compare/V1_9_7...V1_9_9_1
2022-04-24 16:27:16 +02:00
Picnic-Bot
fe3ed2be63 Upgrade jacoco-maven-plugin 0.8.7 -> 0.8.8 (#56)
See:
- https://github.com/jacoco/jacoco/releases/tag/v0.8.8
- https://github.com/jacoco/jacoco/compare/v0.8.7...v0.8.8
2022-04-24 16:20:18 +02:00
Picnic-Bot
f36350f3ba Upgrade Forbidden APIs plugin 3.2 -> 3.3 (#59)
See https://github.com/policeman-tools/forbidden-apis/compare/3.2...3.3
2022-04-24 16:12:47 +02:00
Picnic-Bot
4888ad3aaf Upgrade swagger-annotations 2.1.11 -> 2.2.0 (#60)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.1.12
- https://github.com/swagger-api/swagger-core/releases/tag/v2.1.13
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.0
- https://github.com/swagger-api/swagger-core/compare/v2.1.11...v2.2.0
2022-04-24 16:04:48 +02:00
Picnic-Bot
9daf73f148 Upgrade maven-clean-plugin 3.1.0 -> 3.2.0 (#61)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MCLEAN%20AND%20fixVersion%20%3E%203.1.0%20AND%20fixVersion%20%3C%3D%203.2.0
- https://github.com/apache/maven-clean-plugin/compare/maven-clean-plugin-3.1.0...maven-clean-plugin-3.2.0
2022-04-24 15:55:59 +02:00
Picnic-Bot
b08ca514c1 Upgrade maven-compiler-plugin 3.8.1 -> 3.10.1 (#62)
And drop the redundant `--source` and `--target` flags.

See:
- https://github.com/apache/maven-compiler-plugin/releases/tag/maven-compiler-plugin-3.9.0
- https://github.com/apache/maven-compiler-plugin/releases/tag/maven-compiler-plugin-3.10.0
- https://github.com/apache/maven-compiler-plugin/releases/tag/maven-compiler-plugin-3.10.1
- https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.8.1...maven-compiler-plugin-3.10.1
2022-04-24 15:48:25 +02:00
Picnic-Bot
4eed7dd0e8 Upgrade maven-dependency-plugin 3.1.2 -> 3.3.0 (#63)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MDEP%20AND%20fixVersion%20%3E%203.1.2%20AND%20fixVersion%20%3C%3D%203.3.0
- https://github.com/apache/maven-dependency-plugin/compare/maven-dependency-plugin-3.1.2...maven-dependency-plugin-3.3.0
2022-04-24 15:37:56 +02:00
Picnic-Bot
618c62e7a5 Upgrade maven-javadoc-plugin 3.3.1 -> 3.4.0 (#64)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MJAVADOC%20AND%20fixVersion%20%3E%203.3.1%20AND%20fixVersion%20%3C%3D%203.4.0
- https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.3.1...maven-javadoc-plugin-3.4.0
2022-04-24 15:30:33 +02:00
Picnic-Bot
b46f075ddf Upgrade maven-site-plugin 3.9.1 -> 3.12.0 (#65)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MSITE%20AND%20fixVersion%20%3E%203.9.1%20AND%20fixVersion%20%3C%3D%203.12.0
- https://github.com/apache/maven-site-plugin/compare/maven-site-plugin-3.9.1...maven-site-plugin-3.12.0
2022-04-24 15:12:26 +02:00
Picnic-Bot
64436ff9b6 Upgrade AssertJ Core 3.21.0 -> 3.22.0 (#66)
See:
- https://assertj.github.io/doc/#assertj-core-release-notes
- https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.21.0...assertj-core-3.22.0
2022-04-24 15:03:13 +02:00
Picnic-Bot
e028077f1e Upgrade Checkstyle 9.1 -> 10.1 (#67)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-9.2
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-9.2.1
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-9.3
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.0
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.1
- https://github.com/checkstyle/checkstyle/compare/checkstyle-9.1...checkstyle-10.1
2022-04-24 14:51:37 +02:00
Picnic-Bot
5aa386b5ba Upgrade buildnumber-maven-plugin 1.4 -> 3.0.0 (#69)
See:
- https://github.com/mojohaus/buildnumber-maven-plugin/releases/tag/buildnumber-maven-plugin-3.0.0
- https://github.com/mojohaus/buildnumber-maven-plugin/compare/buildnumber-maven-plugin-1.4...buildnumber-maven-plugin-3.0.0
2022-04-24 14:44:35 +02:00
Picnic-Bot
a480fe908d Upgrade Palantir assertj-error-prone 0.3.0 -> 0.6.0 (#57)
See:
- https://github.com/palantir/assertj-automation/releases/tag/0.4.0
- https://github.com/palantir/assertj-automation/releases/tag/0.5.0
- https://github.com/palantir/assertj-automation/releases/tag/0.6.0
- https://github.com/palantir/assertj-automation/compare/0.3.0...0.6.0
2022-04-24 14:37:29 +02:00
Picnic-Bot
b2316c744c Upgrade Hamcrest 1.3 -> 2.2 (#70)
See:
- https://github.com/hamcrest/JavaHamcrest/releases/tag/v2.1-rc1
- https://github.com/hamcrest/JavaHamcrest/releases/tag/v2.1-rc2
- https://github.com/hamcrest/JavaHamcrest/releases/tag/v2.1-rc3
- https://github.com/hamcrest/JavaHamcrest/releases/tag/v2.1-rc4
- https://github.com/hamcrest/JavaHamcrest/releases/tag/v2.1
- https://github.com/hamcrest/JavaHamcrest/releases/tag/v2.2-rc1
- https://github.com/hamcrest/JavaHamcrest/releases/tag/v2.2
- https://github.com/hamcrest/JavaHamcrest/compare/hamcrest-java-1.3...v2.2
2022-04-24 14:24:54 +02:00
Picnic-Bot
9334babfe8 Upgrade sortpom-maven-plugin 3.0.0 -> 3.0.1 (#48)
See:
- https://github.com/Ekryd/sortpom/wiki/Versions
- https://github.com/Ekryd/sortpom/releases/tag/sortpom-parent-3.0.1
- https://github.com/Ekryd/sortpom/compare/sortpom-parent-3.0.0...sortpom-parent-3.0.1
2022-04-24 14:15:13 +02:00
Picnic-Bot
b6632d393b Upgrade AutoCommon 1.2 -> 1.2.1 (#49)
See:
- https://github.com/google/auto/releases/tag/auto-common-1.2.1
- https://github.com/google/auto/compare/auto-common-1.2...auto-common-1.2.1
2022-04-24 14:01:28 +02:00
Picnic-Bot
53d191ff4f Upgrade NullAway 0.9.2 -> 0.9.6 (#50)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/compare/v0.9.2...v0.9.6
2022-04-24 13:19:49 +02:00
Picnic-Bot
b8ddf3ac20 Upgrade Jackson 2.13.0 -> 2.13.2.20220328 (#47)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.13.1
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.13.2
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.13.0...jackson-bom-2.13.2.20220328
2022-04-24 13:05:17 +02:00
Rick Ossendrijver
e859c2774f JUnitMethodDeclarationCheck: better handle possibly-problematic method renames (#35)
By flagging affected test methods, but not suggesting a specific rename.
2022-04-12 18:16:21 +02:00
Rick Ossendrijver
1cb4ce97ae Require static import of most java.util.Collections methods (#23)
While there, statically import `ZoneOffset.UTC` in a few places.
2022-04-12 17:48:53 +02:00
Pieter Dirk Soels
92fe96286f Prefer Collectors.joining() over Collectors.joining("") (#44) 2022-04-12 14:25:39 +02:00
Vitor Mussatto
d7531abceb Introduce additional Immutable{List,Map,Set}#of Refaster templates (#40) 2022-04-12 11:51:45 +02:00
João Nogueira
cc7074a62f Introduce RequestParamTypeCheck (#33) 2022-04-12 10:45:34 +02:00
Pieter Dirk Soels
91922454b6 Require static import of com.google.errorprone.refaster.ImportPolicy members (#45) 2022-04-12 10:36:44 +02:00
Rick Ossendrijver
eaa98c985c Introduce assorted AssertJ Refaster templates (#37) 2022-04-11 22:25:14 +02:00
Pieter Dirk Soels
94908d6a37 Require static import of java.util.UUID#randomUUID (#42) 2022-04-11 17:55:57 +02:00
Rick Ossendrijver
e8d9221424 Have PrimitiveComparisonCheck retain relevant generic type parameters (#39) 2022-04-11 17:13:06 +02:00
Rick Ossendrijver
fea8f5b2c0 Suggest assorted canonical ZoneOffset usages (#38)
- Statically import `ZoneOffset.UTC`.
- Prefer `Instant#atOffset` over `OffsetDateTime#ofInstant`.
2022-04-11 10:16:37 +02:00
Rick Ossendrijver
2199accedc Drop or rewrite AssertJBigDecimalTemplates rules (#30) 2022-04-11 10:08:15 +02:00
Rick Ossendrijver
83670aeddf Require static import of java.util.regex.Pattern constants (#36)
The meaning of these constants will be apparent from context.

Note that `Pattern.{compile,matches,quote}` should not be statically imported,
as these methods have rather generic names.
2022-04-11 09:19:40 +02:00
Rick Ossendrijver
e8977bea67 Require static import of BugPattern.{LinkType,ServerityLevel,StandardTags} members (#34) 2022-04-11 08:16:20 +02:00
Pieter Dirk Soels
0d051064bb Prefer Duration.ofX(n) over Duration.of(n, ChronoUnit.X) (#41)
`TimeTemplates` now contains Refaster templates for
`Duration.of{Nanos,Millis,Seconds,Minutes,Hours,Days}(n)`.
2022-04-10 16:02:33 +02:00
Rick Ossendrijver
06913b6a5b Drop obsolete README entry (#29)
This issue is was resolved by google/error-prone#2257.
2022-04-10 15:34:36 +02:00
Rick Ossendrijver
d2bbee3ed9 Introduce IdentityConversionCheck (#27)
And remove any Refaster templates it subsumes.
2022-04-08 13:28:12 +02:00
Rick Ossendrijver
793a70c29b Configure static import policy for AssertThatSetContainsExactlyOneElement Refaster template (#32) 2022-01-24 10:02:34 +01:00
Rick Ossendrijver
63b4fae185 Introduce FluxFlatMapUsageCheck (#26)
And two (semi-)related Refaster templates.
2022-01-15 12:39:34 +01:00
Stephan Schroevers
73f8f056b4 Introduce ScheduledTransactionTraceCheck (#31) 2022-01-10 10:21:20 +01:00
Rick Ossendrijver
c1638066cd Define assorted StaticImportCheck exemptions
While there, require that most `org.springframework.http.MediaType` members are
statically imported.
2022-01-03 10:20:46 +01:00
Rick Ossendrijver
08e99fb54e Use matching lambda parameter names in Refaster before- and after-templates (#24) 2022-01-01 14:04:37 +01:00
Rick Ossendrijver
00012c6aa8 Extend StaticImportCheck test coverage (#21) 2021-11-14 14:39:15 +01:00
Rick Ossendrijver
193589d193 Require static import of SpringBootTest.WebEnvironment constants (#19) 2021-11-14 14:26:17 +01:00
Stephan Schroevers
1a1588d413 Upgrade Error Prone 2.9.0 -> 2.10.0 2021-11-14 13:50:26 +01:00
Stephan Schroevers
6656bd8186 Assorted upgrades 2021-11-14 13:50:26 +01:00
Rick Ossendrijver
26a9b46de7 Add Refaster rules for StepVerifier creation (#18) 2021-11-14 13:48:39 +01:00
Phil Werli
17e74f778b Add Refaster rules for redundant Flux#concat invocations (#20) 2021-11-13 18:04:49 +01:00
Stephan Schroevers
e1bdb098de Upgrade AssertJ Core 3.20.2 -> 3.21.0
See:
- https://assertj.github.io/doc/#assertj-core-release-notes
- https://github.com/joel-costigliola/assertj-core/compare/assertj-core-3.20.2...assertj-core-3.21.0
2021-09-25 13:53:58 +02:00
Stephan Schroevers
0be162c837 Assorted upgrades 2021-09-25 13:53:31 +02:00
Stephan Schroevers
edfb2a70e8 Upgrade Guava 30.1.1-jre -> 31.0-jre
And drop Refaster rules for APIs that are now `@Deprecated` or have an
`@InlineMe` annotation.

See:
- https://guava.dev/releases/31.0-jre/api/diffs/
- https://github.com/google/guava/releases/tag/v31.0
- https://github.com/google/guava/compare/v30.1.1...v31.0
2021-09-25 13:17:10 +02:00
278 changed files with 8681 additions and 11298 deletions

37
.github/workflows/build.yaml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Build and verify
on:
pull_request:
push:
branches:
- 'master'
jobs:
build:
runs-on: ubuntu-22.04
strategy:
matrix:
jdk: [ 11.0.16, 17.0.4 ]
steps:
# We run the build twice for each supported JDK: once against the
# original Error Prone release, using only Error Prone checks available
# 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.0.2
- name: Set up JDK
uses: actions/setup-java@v3.4.1
with:
java-version: ${{ matrix.jdk }}
distribution: temurin
cache: maven
- name: Display build environment details
run: mvn --version
- name: Build project against vanilla Error Prone
run: mvn -T1C install
- name: Build project with self-check against Error Prone fork
run: mvn -T1C clean verify -Perror-prone-fork -Pnon-maven-central -Pself-check -s settings.xml
- name: Remove installed project artifacts
run: mvn build-helper:remove-project-artifact
# XXX: Enable Codecov once we "go public".
# XXX: Enable SonarCloud once we "go public".

View File

@@ -1,3 +1,6 @@
-XX:ReservedCodeCacheSize=512m
-XX:SoftRefLRUPolicyMSPerMB=10
-XX:+UseParallelGC
--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED

1
.mvn/maven.config Normal file
View File

@@ -0,0 +1 @@
--batch-mode --errors --strict-checksums

22
.renovaterc.json Normal file
View File

@@ -0,0 +1,22 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"packageRules": [
{
"matchPackagePatterns": [
"^org\\.springframework:spring-framework-bom$",
"^org\\.springframework\\.boot:spring-boot[a-z-]*$"
],
"separateMinorPatch": true
},
{
"matchPackagePatterns": [
"^com\\.palantir\\.baseline:baseline-error-prone$"
],
"schedule": "* * 1 * *"
}
],
"reviewers": [
"rickie",
"Stephan202"
]
}

View File

@@ -1,38 +0,0 @@
---
dist: bionic
language: java
jdk: openjdk11
addons:
sonarcloud:
organization: picnic-technologies
token: "${SONARCLOUD_TOKEN}"
install:
- mvn io.takari:maven:wrapper
script:
# We run the build twice: once against the original Error Prone release,
# using only Error Prone checks available 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.
- ./mvnw clean install
- ./mvnw clean install -Perror-prone-fork -Pnon-maven-central -Pself-check -s settings.xml
# XXX: Enable SonarCloud once we "go public".
# ./mvnw jacoco:prepare-agent surefire:test jacoco:report sonar:sonar
- ./mvnw jacoco:prepare-agent surefire:test jacoco:report
before_cache:
# Don't cache the artifacts we just generated, for multiple reasons: (1) we
# shouldn't need them next time around and (2) if we do, that indicates a
# dependency issue which might otherwise go unnoticed until next time we bump
# the project's version (i.e., when tagging).
- find "${HOME}/.m2/repository" -depth -name '*-SNAPSHOT' -exec rm -r '{}' \;
cache:
directories:
# The local Maven repository in which third party dependencies are stored.
- ${HOME}/.m2/repository
# The Takari Maven Wrapper's storage for downloaded Maven distributions.
- ${HOME}/.m2/wrapper
# The SonarQube analysis cache.
- ${HOME}/.sonar/cache
# XXX: Enable Codecov once we "go public".
#after_success:
# - bash <(curl -s https://codecov.io/bash)

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Compiles the code using Error Prone and applies its suggestions. The set of
# checks applied can optionally be restricted by name.
#
# As this script may modify the project's code, it is important to execute it
# in a clean Git working directory.
set -e -u -o pipefail
if [ "${#}" -gt 1 ]; then
echo "Usage: ./$(basename "${0}") [PatchChecks]"
exit 1
fi
patchChecks=${1:-}
mvn clean test-compile fmt:format \
-T 1.0C \
-Perror-prone \
-Perror-prone-fork \
-Ppatch \
-Pself-check \
-Derror-prone.patch-checks="${patchChecks}" \
-Dverification.skip

View File

@@ -276,10 +276,6 @@ Refaster's expressiveness:
to be lost. In such a case don't statically import the method, so that the
generic type information can be retained. (There may be cases where generic
type information should even be _added_. Find an example.)
- Upon application of a template Refaster can throw a _No binding for
Key{identifier=someAfterTemplateParam}_ exception. When this happens the
template is invalid. Instead perform this check at compile time, such that
such malformed templates cannot be defined in the first place.
- Provide a way to express "match if (not) annotated (with _X_)". See #1 for a
motivating example.
- Provide a way to place match constraints on compile time constants. For

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>0.1.0</version>
</parent>
<artifactId>error-prone-contrib</artifactId>
@@ -41,27 +41,24 @@
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>migration-util</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>refaster-resource-compiler</artifactId>
<!-- This dependency is declared only as a hint to Maven that
compilation depends on it; see the `maven-compiler-plugin`'s
`annotationProcessorPaths` configuration below. -->
<artifactId>refaster-support</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>refaster-support</artifactId>
<artifactId>refaster-test-support</artifactId>
<scope>test</scope>
</dependency>
<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>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service-annotations</artifactId>
@@ -77,11 +74,20 @@
<artifactId>javac</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.googlejavaformat</groupId>
<artifactId>google-java-format</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<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>
@@ -122,6 +128,11 @@
<artifactId>jaxb-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
@@ -132,11 +143,6 @@
<artifactId>assertj-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
@@ -167,16 +173,6 @@
<artifactId>slf4j-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
@@ -192,6 +188,11 @@
<artifactId>spring-webflux</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
@@ -202,15 +203,6 @@
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>com.coveo</groupId>
<artifactId>fmt-maven-plugin</artifactId>
<configuration>
<additionalSourceDirectories>
<additionalSourceDirectory>${basedir}/src/test/resources</additionalSourceDirectory>
</additionalSourceDirectories>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
@@ -218,7 +210,7 @@
<annotationProcessorPaths combine.children="append">
<path>
<groupId>${project.groupId}</groupId>
<artifactId>refaster-resource-compiler</artifactId>
<artifactId>refaster-compiler</artifactId>
<version>${project.version}</version>
</path>
<path>
@@ -226,14 +218,9 @@
<artifactId>refaster-support</artifactId>
<version>${project.version}</version>
</path>
<path>
<groupId>${project.groupId}</groupId>
<artifactId>migration-util</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs combine.children="append">
<arg>-Xplugin:RefasterRuleResourceCompiler</arg>
<arg>-Xplugin:RefasterRuleCompiler</arg>
</compilerArgs>
</configuration>
</plugin>

View File

@@ -1,12 +1,12 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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 com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
@@ -25,12 +25,11 @@ import javax.lang.model.element.AnnotationValue;
/** A {@link BugChecker} which flags ambiguous {@code @JsonCreator}s in enums. */
@AutoService(BugChecker.class)
@BugPattern(
name = "AmbiguousJsonCreator",
summary = "`JsonCreator.Mode` should be set for single-argument creators",
linkType = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.LIKELY_ERROR)
public final class AmbiguousJsonCreatorCheck extends BugChecker implements AnnotationTreeMatcher {
linkType = NONE,
severity = WARNING,
tags = LIKELY_ERROR)
public final class AmbiguousJsonCreator extends BugChecker implements AnnotationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<AnnotationTree> IS_JSON_CREATOR_ANNOTATION =
isType("com.fasterxml.jackson.annotation.JsonCreator");

View File

@@ -0,0 +1,57 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static com.google.errorprone.matchers.Matchers.allOf;
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 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.fixes.SuggestedFix;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.sun.source.tree.MethodInvocationTree;
/**
* A {@link BugChecker} which flags AssertJ {@code isEqualTo(null)} checks for simplification.
*
* <p>This bug checker cannot be replaced with a simple Refaster template, as the Refaster approach
* would require that all overloads of {@link org.assertj.core.api.Assert#isEqualTo(Object)} (such
* as {@link org.assertj.core.api.AbstractStringAssert#isEqualTo(String)}) are explicitly
* enumerated. This bug checker generically matches all such current and future overloads.
*/
@AutoService(BugChecker.class)
@BugPattern(
summary = "Prefer `.isNull()` over `.isEqualTo(null)`",
linkType = NONE,
severity = SUGGESTION,
tags = SIMPLIFICATION)
public final class AssertJIsNull extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<MethodInvocationTree> ASSERT_IS_EQUAL_TO_NULL =
allOf(
instanceMethod().onDescendantOf("org.assertj.core.api.Assert").named("isEqualTo"),
argumentCount(1),
argument(0, nullLiteral()));
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (!ASSERT_IS_EQUAL_TO_NULL.matches(tree, state)) {
return Description.NO_MATCH;
}
SuggestedFix.Builder fix =
SuggestedFix.builder().merge(SuggestedFixes.renameMethodInvocation(tree, "isNull", state));
tree.getArguments().forEach(arg -> fix.merge(SuggestedFix.delete(arg)));
return describeMatch(tree, fix.build());
}
}

View File

@@ -1,15 +1,16 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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.isType;
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.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
@@ -26,12 +27,11 @@ import java.util.List;
/** A {@link BugChecker} which flags redundant {@code @Autowired} constructor annotations. */
@AutoService(BugChecker.class)
@BugPattern(
name = "AutowiredConstructor",
summary = "Omit `@Autowired` on a class' sole constructor, as it is redundant",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION)
public final class AutowiredConstructorCheck extends BugChecker implements ClassTreeMatcher {
linkType = NONE,
severity = SUGGESTION,
tags = SIMPLIFICATION)
public final class AutowiredConstructor extends BugChecker implements ClassTreeMatcher {
private static final long serialVersionUID = 1L;
private static final MultiMatcher<Tree, AnnotationTree> AUTOWIRED_ANNOTATION =
annotations(AT_LEAST_ONE, isType("org.springframework.beans.factory.annotation.Autowired"));
@@ -43,7 +43,7 @@ public final class AutowiredConstructorCheck extends BugChecker implements Class
return Description.NO_MATCH;
}
List<AnnotationTree> annotations =
ImmutableList<AnnotationTree> annotations =
AUTOWIRED_ANNOTATION
.multiMatchResult(Iterables.getOnlyElement(constructors), state)
.matchingNodes();

View File

@@ -1,11 +1,12 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
@@ -24,25 +25,24 @@ 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;
/** A {@link BugChecker} which flags annotations that could be written more concisely. */
@AutoService(BugChecker.class)
@BugPattern(
name = "CanonicalAnnotationSyntax",
summary = "Omit redundant syntax from annotation declarations",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION)
public final class CanonicalAnnotationSyntaxCheck extends BugChecker
implements AnnotationTreeMatcher {
linkType = NONE,
severity = SUGGESTION,
tags = SIMPLIFICATION)
public final class CanonicalAnnotationSyntax extends BugChecker implements AnnotationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Pattern TRAILING_ARRAY_COMMA = Pattern.compile(",\\s*}$");
private static final ImmutableSet<BiFunction<AnnotationTree, VisitorState, Optional<Fix>>>
FIX_FACTORIES =
ImmutableSet.of(
CanonicalAnnotationSyntaxCheck::dropRedundantParentheses,
CanonicalAnnotationSyntaxCheck::dropRedundantValueAttribute,
CanonicalAnnotationSyntaxCheck::dropRedundantCurlies);
CanonicalAnnotationSyntax::dropRedundantParentheses,
CanonicalAnnotationSyntax::dropRedundantValueAttribute,
CanonicalAnnotationSyntax::dropRedundantCurlies);
@Override
public Description matchAnnotation(AnnotationTree tree, VisitorState state) {
@@ -102,7 +102,8 @@ public final class CanonicalAnnotationSyntaxCheck extends BugChecker
return Optional.of(
SuggestedFix.replace(
arg,
simplifyAttributeValue(expr, state).orElseGet(() -> Util.treeToString(expr, state))));
simplifyAttributeValue(expr, state)
.orElseGet(() -> SourceCode.treeToString(expr, state))));
}
private static Optional<Fix> dropRedundantCurlies(AnnotationTree tree, VisitorState state) {
@@ -137,11 +138,11 @@ public final class CanonicalAnnotationSyntaxCheck extends BugChecker
private static Optional<String> simplifySingletonArray(NewArrayTree array, VisitorState state) {
return Optional.of(array.getInitializers())
.filter(initializers -> initializers.size() == 1)
.map(initializers -> Util.treeToString(initializers.get(0), state));
.map(initializers -> SourceCode.treeToString(initializers.get(0), state));
}
private static Optional<String> dropTrailingComma(NewArrayTree array, VisitorState state) {
String src = Util.treeToString(array, state);
String src = SourceCode.treeToString(array, state);
return Optional.of(TRAILING_ARRAY_COMMA.matcher(src))
.filter(Matcher::find)
.map(m -> src.substring(0, m.start()) + '}');

View File

@@ -0,0 +1,117 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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 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.fixes.SuggestedFix;
import com.google.errorprone.fixes.SuggestedFixes;
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.stream.Collector;
/**
* A {@link BugChecker} which flags {@link Collector Collectors} that don't clearly express
* (im)mutability.
*
* <p>Replacing such collectors with alternatives that produce immutable collections is preferred.
* Do note that Guava's immutable collections are null-hostile.
*/
@AutoService(BugChecker.class)
@BugPattern(
summary =
"Avoid `Collectors.to{List,Map,Set}` in favour of alternatives that emphasize (im)mutability",
linkType = NONE,
severity = WARNING,
tags = FRAGILE_CODE)
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");
private static final Matcher<ExpressionTree> LIST_COLLECTOR =
staticMethod().anyClass().named("toList");
private static final Matcher<ExpressionTree> MAP_COLLECTOR =
staticMethod().anyClass().named("toMap");
private static final Matcher<ExpressionTree> SET_COLLECTOR =
staticMethod().anyClass().named("toSet");
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (!COLLECTOR_METHOD.matches(tree, state)) {
return Description.NO_MATCH;
}
if (LIST_COLLECTOR.matches(tree, state)) {
return suggestToCollectionAlternatives(
tree, "com.google.common.collect.ImmutableList.toImmutableList", "ArrayList", state);
}
if (MAP_COLLECTOR.matches(tree, state)) {
return suggestToMapAlternatives(tree, state);
}
if (SET_COLLECTOR.matches(tree, state)) {
return suggestToCollectionAlternatives(
tree, "com.google.common.collect.ImmutableSet.toImmutableSet", "HashSet", state);
}
return Description.NO_MATCH;
}
private Description suggestToCollectionAlternatives(
MethodInvocationTree tree,
String fullyQualifiedImmutableReplacement,
String mutableReplacement,
VisitorState state) {
SuggestedFix.Builder mutableFix = SuggestedFix.builder();
String toCollectionSelect =
SuggestedFixes.qualifyStaticImport(
"java.util.stream.Collectors.toCollection", mutableFix, state);
return buildDescription(tree)
.addFix(replaceMethodInvocation(tree, fullyQualifiedImmutableReplacement, state))
.addFix(
mutableFix
.addImport(String.format("java.util.%s", mutableReplacement))
.replace(tree, String.format("%s(%s::new)", toCollectionSelect, mutableReplacement))
.build())
.build();
}
private Description suggestToMapAlternatives(MethodInvocationTree tree, VisitorState state) {
int argCount = tree.getArguments().size();
if (argCount > 3) {
return Description.NO_MATCH;
}
return buildDescription(tree)
.addFix(
replaceMethodInvocation(
tree, "com.google.common.collect.ImmutableMap.toImmutableMap", state))
.addFix(
SuggestedFix.builder()
.addImport("java.util.HashMap")
.postfixWith(
tree.getArguments().get(argCount - 1),
(argCount == 2 ? ", (a, b) -> { throw new IllegalStateException(); }" : "")
+ ", HashMap::new")
.build())
.build();
}
private static SuggestedFix replaceMethodInvocation(
MethodInvocationTree tree, String fullyQualifiedReplacement, VisitorState state) {
SuggestedFix.Builder fix = SuggestedFix.builder();
String replacement = SuggestedFixes.qualifyStaticImport(fullyQualifiedReplacement, fix, state);
fix.merge(SuggestedFix.replace(tree.getMethodSelect(), replacement));
return fix.build();
}
}

View File

@@ -1,5 +1,8 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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;
@@ -7,9 +10,6 @@ import static com.google.errorprone.matchers.Matchers.isType;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
@@ -26,12 +26,11 @@ import java.util.Optional;
/** A {@link BugChecker} which flags empty methods that seemingly can simply be deleted. */
@AutoService(BugChecker.class)
@BugPattern(
name = "EmptyMethod",
summary = "Empty method can likely be deleted",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION)
public final class EmptyMethodCheck extends BugChecker implements MethodTreeMatcher {
linkType = NONE,
severity = SUGGESTION,
tags = SIMPLIFICATION)
public final class EmptyMethod extends BugChecker implements MethodTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<Tree> PERMITTED_ANNOTATION =
annotations(

View File

@@ -0,0 +1,160 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.STYLE;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static java.util.stream.Collectors.joining;
import com.google.auto.service.AutoService;
import com.google.common.base.Splitter;
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.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.util.ASTHelpers;
import com.google.googlejavaformat.java.Formatter;
import com.google.googlejavaformat.java.FormatterException;
import com.google.googlejavaformat.java.ImportOrderer;
import com.google.googlejavaformat.java.JavaFormatterOptions.Style;
import com.google.googlejavaformat.java.RemoveUnusedImports;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.util.Position;
import java.util.List;
import java.util.Optional;
/**
* A {@link BugChecker} which flags improperly formatted Error Prone test code.
*
* <p>All test code should be formatted in accordance with Google Java Format's {@link Formatter}
* output, and imports should be ordered according to the {@link Style#GOOGLE Google} style.
*
* <p>This checker inspects inline code passed to {@code
* com.google.errorprone.CompilationTestHelper} and {@code
* com.google.errorprone.BugCheckerRefactoringTestHelper}. It requires that this code is properly
* formatted and that its imports are organized. Only code that represents the expected output of a
* refactoring operation is allowed to have unused imports, as most {@link BugChecker}s do not (and
* are not able to) remove imports that become obsolete as a result of applying their suggested
* fix(es).
*/
// XXX: Once we target JDK 17 (optionally?) suggest text block fixes.
// XXX: GJF guesses the line separator to be used by inspecting the source. When using text blocks
// this may cause the current unconditional use of `\n` not to be sufficient when building on
// Windows; TBD.
@AutoService(BugChecker.class)
@BugPattern(
summary = "Test code should follow the Google Java style",
linkType = NONE,
severity = SUGGESTION,
tags = STYLE)
public final class ErrorProneTestHelperSourceFormat extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Formatter FORMATTER = new Formatter();
private static final Matcher<ExpressionTree> INPUT_SOURCE_ACCEPTING_METHOD =
anyOf(
instanceMethod()
.onDescendantOf("com.google.errorprone.CompilationTestHelper")
.named("addSourceLines"),
instanceMethod()
.onDescendantOf("com.google.errorprone.BugCheckerRefactoringTestHelper")
.named("addInputLines"));
private static final Matcher<ExpressionTree> OUTPUT_SOURCE_ACCEPTING_METHOD =
instanceMethod()
.onDescendantOf("com.google.errorprone.BugCheckerRefactoringTestHelper.ExpectOutput")
.named("addOutputLines");
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
boolean isOutputSource = OUTPUT_SOURCE_ACCEPTING_METHOD.matches(tree, state);
if (!isOutputSource && !INPUT_SOURCE_ACCEPTING_METHOD.matches(tree, state)) {
return Description.NO_MATCH;
}
List<? extends ExpressionTree> sourceLines =
tree.getArguments().subList(1, tree.getArguments().size());
if (sourceLines.isEmpty()) {
return buildDescription(tree).setMessage("No source code provided").build();
}
int startPos = ASTHelpers.getStartPosition(sourceLines.get(0));
int endPos = state.getEndPosition(sourceLines.get(sourceLines.size() - 1));
/* Attempt to format the source code only if it fully consists of constant expressions. */
return getConstantSourceCode(sourceLines)
.map(source -> flagFormattingIssues(startPos, endPos, source, isOutputSource, state))
.orElse(Description.NO_MATCH);
}
private Description flagFormattingIssues(
int startPos, int endPos, String source, boolean retainUnusedImports, VisitorState state) {
Tree methodInvocation = state.getPath().getLeaf();
String formatted;
try {
formatted = formatSourceCode(source, retainUnusedImports).trim();
} catch (FormatterException e) {
return buildDescription(methodInvocation)
.setMessage(String.format("Source code is malformed: %s", e.getMessage()))
.build();
}
if (source.trim().equals(formatted)) {
return Description.NO_MATCH;
}
if (startPos == Position.NOPOS || endPos == Position.NOPOS) {
/*
* We have insufficient source information to emit a fix, so we only flag the fact that the
* code isn't properly formatted.
*/
return describeMatch(methodInvocation);
}
/*
* The code isn't properly formatted; replace all lines with the properly formatted
* alternatives.
*/
return describeMatch(
methodInvocation,
SuggestedFix.replace(
startPos,
endPos,
Splitter.on('\n')
.splitToStream(formatted)
.map(state::getConstantExpression)
.collect(joining(", "))));
}
private static String formatSourceCode(String source, boolean retainUnusedImports)
throws FormatterException {
String withReorderedImports = ImportOrderer.reorderImports(source, Style.GOOGLE);
String withOptionallyRemovedImports =
retainUnusedImports
? withReorderedImports
: RemoveUnusedImports.removeUnusedImports(withReorderedImports);
return FORMATTER.formatSource(withOptionallyRemovedImports);
}
private static Optional<String> getConstantSourceCode(
List<? extends ExpressionTree> sourceLines) {
StringBuilder source = new StringBuilder();
for (ExpressionTree sourceLine : sourceLines) {
Object value = ASTHelpers.constValue(sourceLine);
if (value == null) {
return Optional.empty();
}
source.append(value).append('\n');
}
return Optional.of(source.toString());
}
}

View File

@@ -2,6 +2,9 @@ package tech.picnic.errorprone.bugpatterns;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.ImmutableSetMultimap.toImmutableSetMultimap;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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;
@@ -12,9 +15,6 @@ import com.google.common.collect.Multimaps;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
@@ -35,13 +35,11 @@ import java.util.stream.Stream;
*/
@AutoService(BugChecker.class)
@BugPattern(
name = "ExplicitEnumOrdering",
summary = "Make sure `Ordering#explicit` lists all of an enum's values",
linkType = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.FRAGILE_CODE)
public final class ExplicitEnumOrderingCheck extends BugChecker
implements MethodInvocationTreeMatcher {
linkType = NONE,
severity = WARNING,
tags = FRAGILE_CODE)
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");
@@ -73,7 +71,7 @@ public final class ExplicitEnumOrderingCheck extends BugChecker
.collect(
collectingAndThen(
toImmutableSetMultimap(Symbol::asType, Symbol::toString),
ExplicitEnumOrderingCheck::getMissingEnumValues));
ExplicitEnumOrdering::getMissingEnumValues));
}
private static ImmutableSet<String> getMissingEnumValues(

View File

@@ -0,0 +1,85 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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 com.google.auto.service.AutoService;
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.MemberReferenceTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
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.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MemberReferenceTree;
import com.sun.source.tree.MethodInvocationTree;
import java.util.function.Function;
import java.util.function.Supplier;
import reactor.core.publisher.Flux;
/**
* A {@link BugChecker} which flags usages of {@link Flux#flatMap(Function)} and {@link
* Flux#flatMapSequential(Function)}.
*
* <p>{@link Flux#flatMap(Function)} and {@link Flux#flatMapSequential(Function)} eagerly perform up
* to {@link reactor.util.concurrent.Queues#SMALL_BUFFER_SIZE} subscriptions. Additionally, the
* former interleaves values as they are emitted, yielding nondeterministic results. In most cases
* {@link Flux#concatMap(Function)} should be preferred, as it produces consistent results and
* avoids potentially saturating the thread pool on which subscription happens. If {@code
* concatMap}'s single-subscription semantics are undesirable one should invoke a {@code flatMap} or
* {@code flatMapSequential} overload with an explicit concurrency level.
*
* <p>NB: The rarely-used overload {@link Flux#flatMap(Function, Function, Supplier)} is not flagged
* by this check because there is no clear alternative to point to.
*/
@AutoService(BugChecker.class)
@BugPattern(
summary =
"`Flux#flatMap` and `Flux#flatMapSequential` have subtle semantics; "
+ "please use `Flux#concatMap` or explicitly specify the desired amount of concurrency",
linkType = NONE,
severity = ERROR,
tags = LIKELY_ERROR)
public final class FluxFlatMapUsage extends BugChecker
implements MethodInvocationTreeMatcher, MemberReferenceTreeMatcher {
private static final long serialVersionUID = 1L;
private static final String MAX_CONCURRENCY_ARG_NAME = "MAX_CONCURRENCY";
private static final Matcher<ExpressionTree> FLUX_FLATMAP =
instanceMethod()
.onDescendantOf("reactor.core.publisher.Flux")
.namedAnyOf("flatMap", "flatMapSequential")
.withParameters(Function.class.getName());
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (!FLUX_FLATMAP.matches(tree, state)) {
return Description.NO_MATCH;
}
return buildDescription(tree)
.addFix(SuggestedFixes.renameMethodInvocation(tree, "concatMap", state))
.addFix(
SuggestedFix.builder()
.postfixWith(
Iterables.getOnlyElement(tree.getArguments()), ", " + MAX_CONCURRENCY_ARG_NAME)
.build())
.build();
}
@Override
public Description matchMemberReference(MemberReferenceTree tree, VisitorState state) {
if (!FLUX_FLATMAP.matches(tree, state)) {
return Description.NO_MATCH;
}
// Method references are expected to occur very infrequently; generating both variants of
// suggested fixes is not worth the trouble.
return describeMatch(tree);
}
}

View File

@@ -1,5 +1,8 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static com.google.errorprone.matchers.Matchers.allOf;
import static com.google.errorprone.matchers.Matchers.anyMethod;
import static com.google.errorprone.matchers.Matchers.anyOf;
@@ -10,9 +13,6 @@ import static java.util.stream.Collectors.joining;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
@@ -31,6 +31,8 @@ import com.sun.source.util.SimpleTreeVisitor;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nullable;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
/**
* A {@link BugChecker} which flags string concatenations that produce a format string; in such
@@ -48,12 +50,11 @@ import java.util.Optional;
// invocations, as necessary.
@AutoService(BugChecker.class)
@BugPattern(
name = "FormatStringConcatenation",
summary = "Defer string concatenation to the invoked method",
linkType = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.SIMPLIFICATION)
public final class FormatStringConcatenationCheck extends BugChecker
linkType = NONE,
severity = WARNING,
tags = SIMPLIFICATION)
public final class FormatStringConcatenation extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
/**
@@ -210,6 +211,7 @@ public final class FormatStringConcatenationCheck extends BugChecker
this.formatSpecifier = formatSpecifier;
}
@Nullable
@Override
public Void visitBinary(BinaryTree tree, VisitorState state) {
if (tree.getKind() == Kind.PLUS && isStringTyped(tree, state)) {
@@ -222,11 +224,13 @@ public final class FormatStringConcatenationCheck extends BugChecker
return null;
}
@Nullable
@Override
public Void visitParenthesized(ParenthesizedTree tree, VisitorState state) {
return tree.getExpression().accept(this, state);
}
@Nullable
@Override
protected Void defaultAction(Tree tree, VisitorState state) {
appendExpression(tree);
@@ -246,7 +250,7 @@ public final class FormatStringConcatenationCheck extends BugChecker
return state.getConstantExpression(formatString.toString())
+ ", "
+ formatArguments.stream()
.map(tree -> Util.treeToString(tree, state))
.map(tree -> SourceCode.treeToString(tree, state))
.collect(joining(", "));
}
}

View File

@@ -0,0 +1,110 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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.staticMethod;
import static com.google.errorprone.suppliers.Suppliers.OBJECT_TYPE;
import com.google.auto.service.AutoService;
import com.google.common.primitives.Primitives;
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.bugpatterns.TypesWithUndefinedEquality;
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;
import com.google.errorprone.util.ASTHelpers.TargetType;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
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;
/** A {@link BugChecker} that flags redundant identity conversions. */
// XXX: Consider detecting cases where a flagged expression is passed to a method, and where removal
// of the identify conversion would cause a different method overload to be selected. Depending on
// the target method such a modification may change the code's semantics or performance.
@AutoService(BugChecker.class)
@BugPattern(
summary = "Avoid or clarify identity conversions",
linkType = NONE,
severity = WARNING,
tags = SIMPLIFICATION)
public final class IdentityConversion extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> IS_CONVERSION_METHOD =
anyOf(
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")
.named("copyOf"),
staticMethod()
.onClassAny(
Primitives.allWrapperTypes().stream()
.map(Class::getName)
.collect(toImmutableSet()))
.named("valueOf"),
staticMethod().onClass(String.class.getName()).named("valueOf"),
staticMethod().onClass("reactor.adapter.rxjava.RxJava2Adapter"),
staticMethod()
.onClass("reactor.core.publisher.Flux")
.namedAnyOf("concat", "firstWithSignal", "from", "merge"),
staticMethod().onClass("reactor.core.publisher.Mono").namedAnyOf("from", "fromDirect"));
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
List<? extends ExpressionTree> arguments = tree.getArguments();
if (arguments.size() != 1 || !IS_CONVERSION_METHOD.matches(tree, state)) {
return Description.NO_MATCH;
}
ExpressionTree sourceTree = arguments.get(0);
Type sourceType = ASTHelpers.getType(sourceTree);
Type resultType = ASTHelpers.getType(tree);
TargetType targetType = ASTHelpers.targetType(state);
if (sourceType == null || resultType == null || targetType == null) {
return Description.NO_MATCH;
}
if (!state.getTypes().isSameType(sourceType, resultType)
&& !isConvertibleWithWellDefinedEquality(sourceType, targetType.type(), state)) {
return Description.NO_MATCH;
}
return buildDescription(tree)
.setMessage(
"This method invocation appears redundant; remove it or suppress this warning and "
+ "add a comment explaining its purpose")
.addFix(SuggestedFix.replace(tree, SourceCode.treeToString(sourceTree, state)))
.addFix(SuggestedFixes.addSuppressWarnings(state, canonicalName()))
.build();
}
private static boolean isConvertibleWithWellDefinedEquality(
Type sourceType, Type targetType, VisitorState state) {
Types types = state.getTypes();
return !types.isSameType(targetType, OBJECT_TYPE.get(state))
&& types.isConvertible(sourceType, targetType)
&& Arrays.stream(TypesWithUndefinedEquality.values())
.noneMatch(b -> b.matchesType(sourceType, state) || b.matchesType(targetType, state));
}
}

View File

@@ -0,0 +1,201 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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.allOf;
import static com.google.errorprone.matchers.Matchers.annotations;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.enclosingClass;
import static com.google.errorprone.matchers.Matchers.hasModifier;
import static com.google.errorprone.matchers.Matchers.isType;
import static java.util.function.Predicate.not;
import static tech.picnic.errorprone.bugpatterns.util.JavaKeywords.isReservedKeyword;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
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.Matchers;
import com.google.errorprone.matchers.MultiMatcher;
import com.google.errorprone.predicates.TypePredicate;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.ImportTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Symbol;
import java.util.Optional;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
/** A {@link BugChecker} which flags non-canonical JUnit method declarations. */
// XXX: Consider introducing a class-level check which enforces that test classes:
// 1. Are named `*Test` or `Abstract*TestCase`.
// 2. If not `abstract`, are package-private and don't have public methods and subclasses.
// 3. Only have private fields.
// XXX: If implemented, the current logic could flag only `private` JUnit methods.
@AutoService(BugChecker.class)
@BugPattern(
summary = "JUnit method declaration can likely be improved",
linkType = NONE,
severity = SUGGESTION,
tags = SIMPLIFICATION)
public final class JUnitMethodDeclaration extends BugChecker implements MethodTreeMatcher {
private static final long serialVersionUID = 1L;
private static final String TEST_PREFIX = "test";
private static final ImmutableSet<Modifier> ILLEGAL_MODIFIERS =
ImmutableSet.of(Modifier.PRIVATE, Modifier.PROTECTED, Modifier.PUBLIC);
private static final Matcher<MethodTree> HAS_UNMODIFIABLE_SIGNATURE =
anyOf(
annotations(AT_LEAST_ONE, isType("java.lang.Override")),
allOf(
Matchers.not(hasModifier(Modifier.FINAL)),
Matchers.not(hasModifier(Modifier.PRIVATE)),
enclosingClass(hasModifier(Modifier.ABSTRACT))));
private static final MultiMatcher<MethodTree, AnnotationTree> TEST_METHOD =
annotations(
AT_LEAST_ONE,
anyOf(
isType("org.junit.jupiter.api.Test"),
hasMetaAnnotation("org.junit.jupiter.api.TestTemplate")));
private static final MultiMatcher<MethodTree, AnnotationTree> SETUP_OR_TEARDOWN_METHOD =
annotations(
AT_LEAST_ONE,
anyOf(
isType("org.junit.jupiter.api.AfterAll"),
isType("org.junit.jupiter.api.AfterEach"),
isType("org.junit.jupiter.api.BeforeAll"),
isType("org.junit.jupiter.api.BeforeEach")));
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
if (HAS_UNMODIFIABLE_SIGNATURE.matches(tree, state)) {
return Description.NO_MATCH;
}
boolean isTestMethod = TEST_METHOD.matches(tree, state);
if (!isTestMethod && !SETUP_OR_TEARDOWN_METHOD.matches(tree, state)) {
return Description.NO_MATCH;
}
SuggestedFix.Builder fixBuilder = SuggestedFix.builder();
SuggestedFixes.removeModifiers(tree.getModifiers(), state, ILLEGAL_MODIFIERS)
.ifPresent(fixBuilder::merge);
if (isTestMethod) {
suggestTestMethodRenameIfApplicable(tree, fixBuilder, state);
}
return fixBuilder.isEmpty() ? Description.NO_MATCH : describeMatch(tree, fixBuilder.build());
}
private void suggestTestMethodRenameIfApplicable(
MethodTree tree, SuggestedFix.Builder fixBuilder, VisitorState state) {
tryCanonicalizeMethodName(tree)
.ifPresent(
newName ->
findMethodRenameBlocker(newName, state)
.ifPresentOrElse(
blocker -> reportMethodRenameBlocker(tree, blocker, state),
() -> fixBuilder.merge(SuggestedFixes.renameMethod(tree, newName, state))));
}
private void reportMethodRenameBlocker(MethodTree tree, String reason, VisitorState state) {
state.reportMatch(
buildDescription(tree)
.setMessage(
String.format(
"This method's name should not redundantly start with `%s` (but note that %s)",
TEST_PREFIX, reason))
.build());
}
/**
* If applicable, returns a human-readable argument against assigning the given name to an
* existing method.
*
* <p>This method implements imperfect heuristics. Things it currently does not consider include
* the following:
*
* <ul>
* <li>Whether the rename would merely introduce a method overload, rather than clashing with an
* existing method declaration.
* <li>Whether the rename would cause a method in a superclass to be overridden.
* <li>Whether the rename would in fact clash with a static import. (It could be that a static
* import of the same name is only referenced from lexical scopes in which the method under
* consideration cannot be referenced directly.)
* </ul>
*/
private static Optional<String> findMethodRenameBlocker(String methodName, VisitorState state) {
if (isMethodInEnclosingClass(methodName, state)) {
return Optional.of(
String.format("a method named `%s` already exists in this class", methodName));
}
if (isSimpleNameStaticallyImported(methodName, state)) {
return Optional.of(String.format("`%s` is already statically imported", methodName));
}
if (isReservedKeyword(methodName)) {
return Optional.of(String.format("`%s` is a reserved keyword", methodName));
}
return Optional.empty();
}
private static boolean isMethodInEnclosingClass(String methodName, VisitorState state) {
return state.findEnclosing(ClassTree.class).getMembers().stream()
.filter(MethodTree.class::isInstance)
.map(MethodTree.class::cast)
.map(MethodTree::getName)
.map(Name::toString)
.anyMatch(methodName::equals);
}
private static boolean isSimpleNameStaticallyImported(String simpleName, VisitorState state) {
return state.getPath().getCompilationUnit().getImports().stream()
.filter(ImportTree::isStatic)
.map(ImportTree::getQualifiedIdentifier)
.map(tree -> getStaticImportSimpleName(tree, state))
.anyMatch(simpleName::contentEquals);
}
private static CharSequence getStaticImportSimpleName(Tree tree, VisitorState state) {
String source = SourceCode.treeToString(tree, state);
return source.subSequence(source.lastIndexOf('.') + 1, source.length());
}
private static Optional<String> tryCanonicalizeMethodName(MethodTree tree) {
return Optional.ofNullable(ASTHelpers.getSymbol(tree))
.map(sym -> sym.getQualifiedName().toString())
.filter(name -> name.startsWith(TEST_PREFIX))
.map(name -> name.substring(TEST_PREFIX.length()))
.filter(not(String::isEmpty))
.map(name -> Character.toLowerCase(name.charAt(0)) + name.substring(1))
.filter(name -> !Character.isDigit(name.charAt(0)));
}
// XXX: Move to a `MoreMatchers` utility class.
private static Matcher<AnnotationTree> hasMetaAnnotation(String annotationClassName) {
TypePredicate typePredicate = hasAnnotation(annotationClassName);
return (tree, state) -> {
Symbol sym = ASTHelpers.getSymbol(tree);
return sym != null && typePredicate.apply(sym.type, state);
};
}
// XXX: Move to a `MoreTypePredicates` utility class.
private static TypePredicate hasAnnotation(String annotationClassName) {
return (type, state) -> ASTHelpers.hasAnnotation(type.tsym, annotationClassName, state);
}
}

View File

@@ -1,114 +0,0 @@
package tech.picnic.errorprone.bugpatterns;
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 java.util.function.Predicate.not;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
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.predicates.TypePredicate;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.MethodTree;
import com.sun.tools.javac.code.Symbol;
import java.util.Optional;
import javax.lang.model.element.Modifier;
/** A {@link BugChecker} which flags non-canonical JUnit method declarations. */
// XXX: Consider introducing a class-level check which enforces that test classes:
// 1. Are named `*Test` or `Abstract*TestCase`.
// 2. If not `abstract`, don't have public methods and subclasses.
// 3. Only have private fields.
// XXX: If implemented, the current logic could flag only `private` JUnit methods.
@AutoService(BugChecker.class)
@BugPattern(
name = "JUnitMethodDeclaration",
summary = "JUnit method declaration can likely be improved",
linkType = BugPattern.LinkType.NONE,
severity = BugPattern.SeverityLevel.SUGGESTION,
tags = BugPattern.StandardTags.SIMPLIFICATION)
public final class JUnitMethodDeclarationCheck extends BugChecker implements MethodTreeMatcher {
private static final long serialVersionUID = 1L;
private static final String TEST_PREFIX = "test";
private static final ImmutableSet<Modifier> ILLEGAL_MODIFIERS =
ImmutableSet.of(Modifier.PRIVATE, Modifier.PROTECTED, Modifier.PUBLIC);
private static final MultiMatcher<MethodTree, AnnotationTree> OVERRIDE_METHOD =
annotations(AT_LEAST_ONE, isType("java.lang.Override"));
private static final MultiMatcher<MethodTree, AnnotationTree> TEST_METHOD =
annotations(
AT_LEAST_ONE,
anyOf(
isType("org.junit.jupiter.api.Test"),
hasMetaAnnotation("org.junit.jupiter.api.TestTemplate")));
private static final MultiMatcher<MethodTree, AnnotationTree> SETUP_OR_TEARDOWN_METHOD =
annotations(
AT_LEAST_ONE,
anyOf(
isType("org.junit.jupiter.api.AfterAll"),
isType("org.junit.jupiter.api.AfterEach"),
isType("org.junit.jupiter.api.BeforeAll"),
isType("org.junit.jupiter.api.BeforeEach")));
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
// XXX: Perhaps we should also skip analysis of non-`private` non-`final` methods in abstract
// classes?
if (OVERRIDE_METHOD.matches(tree, state)) {
return Description.NO_MATCH;
}
boolean isTestMethod = TEST_METHOD.matches(tree, state);
if (!isTestMethod && !SETUP_OR_TEARDOWN_METHOD.matches(tree, state)) {
return Description.NO_MATCH;
}
SuggestedFix.Builder builder = SuggestedFix.builder();
SuggestedFixes.removeModifiers(tree.getModifiers(), state, ILLEGAL_MODIFIERS)
.ifPresent(builder::merge);
if (isTestMethod) {
// XXX: In theory this rename could clash with an existing method or static import. In that
// case we should emit a warning without a suggested replacement.
tryCanonicalizeMethodName(tree, state).ifPresent(builder::merge);
}
return builder.isEmpty() ? Description.NO_MATCH : describeMatch(tree, builder.build());
}
private static Optional<SuggestedFix> tryCanonicalizeMethodName(
MethodTree tree, VisitorState state) {
return Optional.ofNullable(ASTHelpers.getSymbol(tree))
.map(sym -> sym.getQualifiedName().toString())
.filter(name -> name.startsWith(TEST_PREFIX))
.map(name -> name.substring(TEST_PREFIX.length()))
.filter(not(String::isEmpty))
.map(name -> Character.toLowerCase(name.charAt(0)) + name.substring(1))
.filter(name -> !Character.isDigit(name.charAt(0)))
.map(name -> SuggestedFixes.renameMethod(tree, name, state));
}
// XXX: Move to a `MoreMatchers` utility class.
private static Matcher<AnnotationTree> hasMetaAnnotation(String annotationClassName) {
TypePredicate typePredicate = hasAnnotation(annotationClassName);
return (tree, state) -> {
Symbol sym = ASTHelpers.getSymbol(tree);
return sym != null && typePredicate.apply(sym.type, state);
};
}
// XXX: Move to a `MoreTypePredicates` utility class.
private static TypePredicate hasAnnotation(String annotationClassName) {
return (type, state) -> ASTHelpers.hasAnnotation(type.tsym, annotationClassName, state);
}
}

View File

@@ -1,5 +1,8 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
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;
@@ -9,9 +12,6 @@ import com.google.common.collect.Comparators;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.ErrorProneFlags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
@@ -37,6 +37,9 @@ import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import tech.picnic.errorprone.bugpatterns.util.AnnotationAttributeMatcher;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
/**
* A {@link BugChecker} which flags annotation array listings which aren't sorted lexicographically.
@@ -46,12 +49,11 @@ import java.util.stream.Stream;
*/
@AutoService(BugChecker.class)
@BugPattern(
name = "LexicographicalAnnotationAttributeListing",
summary = "Where possible, sort annotation array attributes lexicographically",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.STYLE)
public final class LexicographicalAnnotationAttributeListingCheck extends BugChecker
linkType = NONE,
severity = SUGGESTION,
tags = STYLE)
public final class LexicographicalAnnotationAttributeListing extends BugChecker
implements AnnotationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final ImmutableSet<String> BLACKLISTED_ANNOTATIONS =
@@ -67,17 +69,17 @@ public final class LexicographicalAnnotationAttributeListingCheck extends BugChe
private final AnnotationAttributeMatcher matcher;
/** Instantiates the default {@link LexicographicalAnnotationAttributeListingCheck}. */
public LexicographicalAnnotationAttributeListingCheck() {
/** Instantiates the default {@link LexicographicalAnnotationAttributeListing}. */
public LexicographicalAnnotationAttributeListing() {
this(ErrorProneFlags.empty());
}
/**
* Instantiates a customized {@link LexicographicalAnnotationAttributeListingCheck}.
* Instantiates a customized {@link LexicographicalAnnotationAttributeListing}.
*
* @param flags Any provided command line flags.
*/
public LexicographicalAnnotationAttributeListingCheck(ErrorProneFlags flags) {
public LexicographicalAnnotationAttributeListing(ErrorProneFlags flags) {
matcher = createAnnotationAttributeMatcher(flags);
}
@@ -128,7 +130,7 @@ public final class LexicographicalAnnotationAttributeListingCheck extends BugChe
/* The elements aren't sorted. Suggest the sorted alternative. */
String suggestion =
desiredOrdering.stream()
.map(expr -> Util.treeToString(expr, state))
.map(expr -> SourceCode.treeToString(expr, state))
.collect(joining(", ", "{", "}"));
return Optional.of(SuggestedFix.builder().replace(array, suggestion));
}
@@ -171,18 +173,21 @@ public final class LexicographicalAnnotationAttributeListingCheck extends BugChe
ImmutableList.Builder<ImmutableList<String>> nodes = ImmutableList.builder();
new TreeScanner<Void, Void>() {
@Nullable
@Override
public Void visitIdentifier(IdentifierTree node, Void ctx) {
nodes.add(tokenize(node));
return super.visitIdentifier(node, ctx);
}
@Nullable
@Override
public Void visitLiteral(LiteralTree node, Void ctx) {
nodes.add(tokenize(node));
return super.visitLiteral(node, ctx);
}
@Nullable
@Override
public Void visitPrimitiveType(PrimitiveTypeTree node, Void ctx) {
nodes.add(tokenize(node));
@@ -194,7 +199,7 @@ public final class LexicographicalAnnotationAttributeListingCheck extends BugChe
* Tokens are split on `=` so that e.g. inline Spring property declarations are properly
* sorted by key, then value.
*/
return ImmutableList.copyOf(Util.treeToString(node, state).split("=", -1));
return ImmutableList.copyOf(SourceCode.treeToString(node, state).split("=", -1));
}
}.scan(array, null);

View File

@@ -1,15 +1,15 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.errorprone.BugPattern.LinkType.NONE;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.STYLE;
import static java.util.Comparator.comparing;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
@@ -20,6 +20,7 @@ import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.MethodTree;
import java.util.List;
import java.util.Optional;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
/**
* A {@link BugChecker} that flags annotations that are not lexicographically sorted.
@@ -29,12 +30,11 @@ import java.util.Optional;
*/
@AutoService(BugChecker.class)
@BugPattern(
name = "LexicographicalAnnotationListing",
summary = "Sort annotations lexicographically where possible",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.STYLE)
public final class LexicographicalAnnotationListingCheck extends BugChecker
linkType = NONE,
severity = SUGGESTION,
tags = STYLE)
public final class LexicographicalAnnotationListing extends BugChecker
implements MethodTreeMatcher {
private static final long serialVersionUID = 1L;
@@ -52,7 +52,7 @@ public final class LexicographicalAnnotationListingCheck extends BugChecker
Optional<Fix> fix = tryFixOrdering(originalOrdering, sortedAnnotations, state);
Description.Builder description = buildDescription(tree);
Description.Builder description = buildDescription(originalOrdering.get(0));
fix.ifPresent(description::addFix);
return description.build();
}
@@ -60,7 +60,7 @@ public final class LexicographicalAnnotationListingCheck extends BugChecker
private static ImmutableList<? extends AnnotationTree> sort(
List<? extends AnnotationTree> annotations, VisitorState state) {
return annotations.stream()
.sorted(comparing(annotation -> Util.treeToString(annotation, state)))
.sorted(comparing(annotation -> SourceCode.treeToString(annotation, state)))
.collect(toImmutableList());
}
@@ -72,7 +72,8 @@ public final class LexicographicalAnnotationListingCheck extends BugChecker
originalAnnotations.stream(),
sortedAnnotations.stream(),
(original, replacement) ->
SuggestedFix.builder().replace(original, Util.treeToString(replacement, state)))
SuggestedFix.builder()
.replace(original, SourceCode.treeToString(replacement, state)))
.reduce(SuggestedFix.Builder::merge)
.map(SuggestedFix.Builder::build);
}

View File

@@ -1,14 +1,14 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.errorprone.BugPattern.LinkType.NONE;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.STYLE;
import com.google.auto.service.AutoService;
import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.LambdaExpressionTreeMatcher;
@@ -51,13 +51,11 @@ import javax.lang.model.element.Name;
// Palantir's `LambdaMethodReference` check seems to suffer a similar issue at this time.
@AutoService(BugChecker.class)
@BugPattern(
name = "MethodReferenceUsage",
summary = "Prefer method references over lambda expressions",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.STYLE)
public final class MethodReferenceUsageCheck extends BugChecker
implements LambdaExpressionTreeMatcher {
linkType = NONE,
severity = SUGGESTION,
tags = STYLE)
public final class MethodReferenceUsage extends BugChecker implements LambdaExpressionTreeMatcher {
private static final long serialVersionUID = 1L;
@Override

View File

@@ -1,5 +1,8 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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;
@@ -7,9 +10,6 @@ import static com.google.errorprone.matchers.Matchers.isType;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
@@ -24,12 +24,11 @@ import com.sun.source.tree.Tree;
/** A {@link BugChecker} that flags likely missing Refaster annotations. */
@AutoService(BugChecker.class)
@BugPattern(
name = "MissingRefasterAnnotation",
summary = "The Refaster template contains a method without any Refaster annotations",
linkType = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.LIKELY_ERROR)
public final class MissingRefasterAnnotationCheck extends BugChecker implements ClassTreeMatcher {
linkType = NONE,
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(

View File

@@ -1,13 +1,13 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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 com.google.auto.service.AutoService;
import com.google.common.collect.Iterables;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
@@ -17,6 +17,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;
/**
* A {@link BugChecker} which flags method invocations for which all arguments are wrapped using
@@ -24,12 +25,11 @@ import java.util.List;
*/
@AutoService(BugChecker.class)
@BugPattern(
name = "MockitoStubbing",
summary = "Don't unnecessarily use Mockito's `eq(...)`",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION)
public final class MockitoStubbingCheck extends BugChecker implements MethodInvocationTreeMatcher {
linkType = NONE,
severity = SUGGESTION,
tags = SIMPLIFICATION)
public final class MockitoStubbing extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> MOCKITO_EQ_METHOD =
staticMethod().onClass("org.mockito.ArgumentMatchers").named("eq");
@@ -45,7 +45,7 @@ public final class MockitoStubbingCheck extends BugChecker implements MethodInvo
for (ExpressionTree arg : arguments) {
suggestedFix.replace(
arg,
Util.treeToString(
SourceCode.treeToString(
Iterables.getOnlyElement(((MethodInvocationTree) arg).getArguments()), state));
}

View File

@@ -1,16 +1,17 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.PERFORMANCE;
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.function.Predicate.not;
import static java.util.stream.Collectors.joining;
import com.google.auto.service.AutoService;
import com.google.common.base.VerifyException;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
@@ -30,6 +31,8 @@ import com.sun.tools.javac.tree.JCTree.JCMemberReference;
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;
/**
* A {@link BugChecker} which flags {@code Comparator#comparing*} invocations that can be replaced
@@ -37,18 +40,15 @@ import java.util.function.Function;
*/
// XXX: Add more documentation. Explain how this is useful in the face of refactoring to more
// specific types.
// XXX: Change this checker's name?
@AutoService(BugChecker.class)
@BugPattern(
name = "PrimitiveComparison",
summary =
"Ensure invocations of `Comparator#comparing{,Double,Int,Long}` match the return type"
+ " of the provided function",
linkType = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.PERFORMANCE)
public final class PrimitiveComparisonCheck extends BugChecker
implements MethodInvocationTreeMatcher {
linkType = NONE,
severity = WARNING,
tags = PERFORMANCE)
public final class PrimitiveComparison extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> STATIC_COMPARISON_METHOD =
anyOf(
@@ -77,23 +77,53 @@ public final class PrimitiveComparisonCheck extends BugChecker
}
return getPotentiallyBoxedReturnType(tree.getArguments().get(0))
.flatMap(cmpType -> tryFix(tree, state, cmpType, isStatic))
.flatMap(cmpType -> attemptMethodInvocationReplacement(tree, cmpType, isStatic, state))
.map(fix -> describeMatch(tree, fix))
.orElse(Description.NO_MATCH);
}
private static Optional<Fix> tryFix(
MethodInvocationTree tree, VisitorState state, Type cmpType, boolean isStatic) {
private static Optional<Fix> attemptMethodInvocationReplacement(
MethodInvocationTree tree, Type cmpType, boolean isStatic, VisitorState state) {
return Optional.ofNullable(ASTHelpers.getSymbol(tree))
.map(methodSymbol -> methodSymbol.getSimpleName().toString())
.flatMap(
actualMethodName ->
Optional.of(getPreferredMethod(state, cmpType, isStatic))
Optional.of(getPreferredMethod(cmpType, isStatic, state))
.filter(not(actualMethodName::equals)))
.map(
preferredMethodName ->
prefixTypeArgumentsIfRelevant(preferredMethodName, tree, cmpType, state))
.map(preferredMethodName -> suggestFix(tree, preferredMethodName, state));
}
private static String getPreferredMethod(VisitorState state, Type cmpType, boolean isStatic) {
/**
* Prefixes the given method name with generic type parameters if it replaces a {@code
* Comparator#comparing{,Double,Long,Int}} method which also has generic type parameters.
*
* <p>Such type parameters are retained as they are likely required.
*
* <p>Note that any type parameter to {@code Comparator#thenComparing} is likely redundant, and in
* any case becomes obsolete once that method is replaced with {@code
* Comparator#thenComparing{Double,Long,Int}}. Conversion in the opposite direction does not
* require the introduction of a generic type parameter.
*/
private static String prefixTypeArgumentsIfRelevant(
String preferredMethodName, MethodInvocationTree tree, Type cmpType, VisitorState state) {
if (tree.getTypeArguments().isEmpty() || preferredMethodName.startsWith("then")) {
return preferredMethodName;
}
String typeArguments =
Stream.concat(
Stream.of(SourceCode.treeToString(tree.getTypeArguments().get(0), state)),
Stream.of(cmpType.tsym.getSimpleName())
.filter(u -> "comparing".equals(preferredMethodName)))
.collect(joining(", ", "<", ">"));
return typeArguments + preferredMethodName;
}
private static String getPreferredMethod(Type cmpType, boolean isStatic, VisitorState state) {
Types types = state.getTypes();
Symtab symtab = state.getSymtab();
@@ -128,9 +158,6 @@ public final class PrimitiveComparisonCheck extends BugChecker
}
}
// XXX: We drop explicitly specified generic type information. In case the number of type
// arguments before and after doesn't match, that's for the better. But if we e.g. replace
// `comparingLong` with `comparingInt`, then we should retain it.
private static Fix suggestFix(
MethodInvocationTree tree, String preferredMethodName, VisitorState state) {
ExpressionTree expr = tree.getMethodSelect();
@@ -143,7 +170,7 @@ public final class PrimitiveComparisonCheck extends BugChecker
case MEMBER_SELECT:
MemberSelectTree ms = (MemberSelectTree) tree.getMethodSelect();
return SuggestedFix.replace(
ms, Util.treeToString(ms.getExpression(), state) + '.' + preferredMethodName);
ms, SourceCode.treeToString(ms.getExpression(), state) + '.' + preferredMethodName);
default:
throw new VerifyException("Unexpected type of expression: " + expr.getKind());
}

View File

@@ -1,5 +1,8 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static com.google.errorprone.matchers.Matchers.allOf;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.isNonNullUsingDataflow;
@@ -12,9 +15,6 @@ import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import com.google.auto.service.AutoService;
import com.google.common.collect.Iterables;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.ErrorProneFlags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
@@ -41,16 +41,17 @@ import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import tech.picnic.errorprone.bugpatterns.util.MethodMatcherFactory;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
/** A {@link BugChecker} which flags redundant explicit string conversions. */
@AutoService(BugChecker.class)
@BugPattern(
name = "RedundantStringConversion",
summary = "Avoid redundant string conversions when possible",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION)
public final class RedundantStringConversionCheck extends BugChecker
linkType = NONE,
severity = SUGGESTION,
tags = SIMPLIFICATION)
public final class RedundantStringConversion extends BugChecker
implements BinaryTreeMatcher, CompoundAssignmentTreeMatcher, MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final String FLAG_PREFIX = "RedundantStringConversion:";
@@ -157,17 +158,17 @@ public final class RedundantStringConversionCheck extends BugChecker
private final Matcher<ExpressionTree> conversionMethodMatcher;
/** Instantiates the default {@link RedundantStringConversionCheck}. */
public RedundantStringConversionCheck() {
/** Instantiates the default {@link RedundantStringConversion}. */
public RedundantStringConversion() {
this(ErrorProneFlags.empty());
}
/**
* Instantiates a customized {@link RedundantStringConversionCheck}.
* Instantiates a customized {@link RedundantStringConversion}.
*
* @param flags Any provided command line flags.
*/
public RedundantStringConversionCheck(ErrorProneFlags flags) {
public RedundantStringConversion(ErrorProneFlags flags) {
conversionMethodMatcher = createConversionMethodMatcher(flags);
}
@@ -326,7 +327,7 @@ public final class RedundantStringConversionCheck extends BugChecker
return trySimplify(tree, state, filter)
.map(
replacement ->
SuggestedFix.builder().replace(tree, Util.treeToString(replacement, state)));
SuggestedFix.builder().replace(tree, SourceCode.treeToString(replacement, state)));
}
private Optional<ExpressionTree> trySimplify(
@@ -350,7 +351,7 @@ public final class RedundantStringConversionCheck extends BugChecker
default:
throw new IllegalStateException(
"Cannot simplify method call with two or more arguments: "
+ Util.treeToString(tree, state));
+ SourceCode.treeToString(tree, state));
}
}
@@ -363,7 +364,7 @@ public final class RedundantStringConversionCheck extends BugChecker
return Optional.of(methodInvocation.getMethodSelect())
.filter(methodSelect -> methodSelect.getKind() == Kind.MEMBER_SELECT)
.map(methodSelect -> ((MemberSelectTree) methodSelect).getExpression())
.filter(expr -> !"super".equals(Util.treeToString(expr, state)));
.filter(expr -> !"super".equals(SourceCode.treeToString(expr, state)));
}
private static Optional<ExpressionTree> trySimplifyUnaryMethod(

View File

@@ -1,12 +1,12 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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 com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
@@ -16,6 +16,7 @@ import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.refaster.Refaster;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
/**
* A {@link BugChecker} which flags unnecessary {@link Refaster#anyOf(Object[])} usages.
@@ -25,13 +26,11 @@ import com.sun.source.tree.MethodInvocationTree;
*/
@AutoService(BugChecker.class)
@BugPattern(
name = "RefasterAnyOfUsage",
summary = "`Refaster#anyOf` should be passed at least two parameters",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION)
public final class RefasterAnyOfUsageCheck extends BugChecker
implements MethodInvocationTreeMatcher {
linkType = NONE,
severity = SUGGESTION,
tags = SIMPLIFICATION)
public final class RefasterAnyOfUsage extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> REFASTER_ANY_OF =
staticMethod().onClass(Refaster.class.getName()).named("anyOf");
@@ -46,7 +45,8 @@ public final class RefasterAnyOfUsageCheck extends BugChecker
case 1:
return describeMatch(
tree,
SuggestedFix.replace(tree, Util.treeToString(tree.getArguments().get(0), state)));
SuggestedFix.replace(
tree, SourceCode.treeToString(tree.getArguments().get(0), state)));
default:
/* Handled below. */
}

View File

@@ -1,20 +1,19 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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.ALL;
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.isSameType;
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
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 com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
@@ -31,12 +30,11 @@ import com.sun.source.tree.Tree;
*/
@AutoService(BugChecker.class)
@BugPattern(
name = "RequestMappingAnnotation",
summary = "Make sure all `@RequestMapping` method parameters are annotated",
linkType = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.LIKELY_ERROR)
public final class RequestMappingAnnotationCheck extends BugChecker implements MethodTreeMatcher {
linkType = NONE,
severity = WARNING,
tags = LIKELY_ERROR)
public final class RequestMappingAnnotation extends BugChecker implements MethodTreeMatcher {
private static final long serialVersionUID = 1L;
private static final String ANN_PACKAGE_PREFIX = "org.springframework.web.bind.annotation.";
// XXX: Generalize this logic to fully support Spring meta-annotations, then update the class
@@ -51,8 +49,11 @@ public final class RequestMappingAnnotationCheck extends BugChecker implements M
isType(ANN_PACKAGE_PREFIX + "PostMapping"),
isType(ANN_PACKAGE_PREFIX + "PutMapping"),
isType(ANN_PACKAGE_PREFIX + "RequestMapping")));
// XXX: Add other parameters as necessary. See
// https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-arguments.
// XXX: Add other parameters as necessary. Also consider whether it makes sense to have WebMVC-
// and WebFlux-specific logic. See
// https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-arguments
// and
// https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-ann-arguments.
private static final Matcher<MethodTree> LACKS_PARAMETER_ANNOTATION =
not(
methodHasParameters(
@@ -66,10 +67,17 @@ public final class RequestMappingAnnotationCheck extends BugChecker implements M
isType(ANN_PACKAGE_PREFIX + "RequestHeader"),
isType(ANN_PACKAGE_PREFIX + "RequestParam"))),
isSameType("java.io.InputStream"),
isSameType("java.time.ZoneId"),
isSameType("java.util.Locale"),
isSameType("java.util.TimeZone"),
isSameType("javax.servlet.http.HttpServletRequest"),
isSameType("javax.servlet.http.HttpServletResponse"),
isSameType("org.springframework.http.HttpMethod"),
isSubtypeOf("org.springframework.web.context.request.WebRequest"))));
isSameType("org.springframework.web.context.request.NativeWebRequest"),
isSameType("org.springframework.web.context.request.WebRequest"),
isSameType("org.springframework.web.server.ServerWebExchange"),
isSameType("org.springframework.web.util.UriBuilder"),
isSameType("org.springframework.web.util.UriComponentsBuilder"))));
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {

View File

@@ -0,0 +1,44 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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.allOf;
import static com.google.errorprone.matchers.Matchers.annotations;
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 com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableMap;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.sun.source.tree.VariableTree;
/** A {@link BugChecker} which flags {@code @RequestParam} parameters with an unsupported type. */
@AutoService(BugChecker.class)
@BugPattern(
summary = "`@RequestParam` does not support `ImmutableCollection` and `ImmutableMap` subtypes",
linkType = NONE,
severity = ERROR,
tags = LIKELY_ERROR)
public final class RequestParamType extends BugChecker implements VariableTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<VariableTree> HAS_UNSUPPORTED_REQUEST_PARAM =
allOf(
annotations(AT_LEAST_ONE, isType("org.springframework.web.bind.annotation.RequestParam")),
anyOf(isSubtypeOf(ImmutableCollection.class), isSubtypeOf(ImmutableMap.class)));
@Override
public Description matchVariable(VariableTree tree, VisitorState state) {
return HAS_UNSUPPORTED_REQUEST_PARAM.matches(tree, state)
? describeMatch(tree)
: Description.NO_MATCH;
}
}

View File

@@ -0,0 +1,87 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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 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;
/**
* A {@link BugChecker} which 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",
linkType = NONE,
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));
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
if (!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

@@ -1,15 +1,15 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.base.Verify.verify;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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 com.google.auto.service.AutoService;
import com.google.common.base.Splitter;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
@@ -22,6 +22,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;
/** A {@link BugChecker} which flags SLF4J usages that are likely to be in error. */
// XXX: The special-casing of Throwable applies only to SLF4J 1.6.0+; see
@@ -31,13 +32,11 @@ import java.util.Optional;
// preconditions, ...
@AutoService(BugChecker.class)
@BugPattern(
name = "Slf4jLogStatement",
summary = "Make sure SLF4J log statements contain proper placeholders with matching arguments",
linkType = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.LIKELY_ERROR)
public final class Slf4jLogStatementCheck extends BugChecker
implements MethodInvocationTreeMatcher {
linkType = NONE,
severity = WARNING,
tags = LIKELY_ERROR)
public final class Slf4jLogStatement extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> MARKER = isSubtypeOf("org.slf4j.Marker");
private static final Matcher<ExpressionTree> THROWABLE = isSubtypeOf(Throwable.class);
@@ -114,7 +113,7 @@ public final class Slf4jLogStatementCheck extends BugChecker
* replaced at this usage site.
*/
description.addFix(
SuggestedFix.replace(tree, Util.treeToString(tree, state).replace("%s", "{}")));
SuggestedFix.replace(tree, SourceCode.treeToString(tree, state).replace("%s", "{}")));
}
return false;

View File

@@ -1,6 +1,9 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.base.Verify.verify;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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;
@@ -9,9 +12,6 @@ import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
@@ -25,6 +25,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;
/**
* A {@link BugChecker} which flags {@code @RequestMapping} annotations that can be written more
@@ -32,13 +34,12 @@ import java.util.Optional;
*/
@AutoService(BugChecker.class)
@BugPattern(
name = "SpringMvcAnnotation",
summary =
"Prefer the conciseness of `@{Get,Put,Post,Delete,Patch}Mapping` over `@RequestMapping`",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION)
public final class SpringMvcAnnotationCheck extends BugChecker implements AnnotationTreeMatcher {
linkType = NONE,
severity = SUGGESTION,
tags = SIMPLIFICATION)
public final class SpringMvcAnnotation extends BugChecker implements AnnotationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final String ANN_PACKAGE_PREFIX = "org.springframework.web.bind.annotation.";
private static final AnnotationAttributeMatcher ARGUMENT_SELECTOR =
@@ -92,7 +93,7 @@ public final class SpringMvcAnnotationCheck extends BugChecker implements Annota
private static String extractMethod(ExpressionTree expr, VisitorState state) {
switch (expr.getKind()) {
case IDENTIFIER:
return Util.treeToString(expr, state);
return SourceCode.treeToString(expr, state);
case MEMBER_SELECT:
return ((MemberSelectTree) expr).getIdentifier().toString();
default:
@@ -105,7 +106,7 @@ public final class SpringMvcAnnotationCheck extends BugChecker implements Annota
String newArguments =
tree.getArguments().stream()
.filter(not(argToRemove::equals))
.map(arg -> Util.treeToString(arg, state))
.map(arg -> SourceCode.treeToString(arg, state))
.collect(joining(", "));
return SuggestedFix.builder()

View File

@@ -1,5 +1,8 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static java.util.Objects.requireNonNull;
import com.google.auto.service.AutoService;
@@ -7,9 +10,6 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MemberSelectTreeMatcher;
@@ -19,14 +19,18 @@ 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.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.util.Optional;
/** A {@link BugChecker} which flags methods that can and should be statically imported. */
/**
* A {@link BugChecker} which flags methods and constants that can and should be statically
* imported.
*/
// XXX: Tricky cases:
// - `org.springframework.http.MediaType` (do except for `ALL`?)
// - `org.springframework.http.HttpStatus` (not always an improvement, and `valueOf` must
// certainly be excluded)
// - `com.google.common.collect.Tables`
@@ -41,21 +45,28 @@ import java.util.Optional;
// - Likely any of `*.{ZERO, ONE, MIX, MAX, MIN_VALUE, MAX_VALUE}`.
@AutoService(BugChecker.class)
@BugPattern(
name = "StaticImport",
summary = "Method should be statically imported",
linkType = LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.SIMPLIFICATION)
public final class StaticImportCheck extends BugChecker implements MemberSelectTreeMatcher {
summary = "Identifier should be statically imported",
linkType = NONE,
severity = SUGGESTION,
tags = SIMPLIFICATION)
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}.
*/
@VisibleForTesting
static final ImmutableSet<String> STATIC_IMPORT_CANDIDATE_CLASSES =
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.refaster.ImportPolicy",
"com.mongodb.client.model.Accumulators",
"com.mongodb.client.model.Aggregates",
"com.mongodb.client.model.Filters",
@@ -64,8 +75,10 @@ public final class StaticImportCheck extends BugChecker implements MemberSelectT
"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",
@@ -80,14 +93,17 @@ public final class StaticImportCheck extends BugChecker implements MemberSelectT
"org.mockito.Answers",
"org.mockito.ArgumentMatchers",
"org.mockito.Mockito",
"org.springframework.boot.test.context.SpringBootTest.WebEnvironment",
"org.springframework.format.annotation.DateTimeFormat.ISO",
"org.springframework.http.HttpHeaders",
"org.springframework.http.HttpMethod",
"org.springframework.http.MediaType",
"org.testng.Assert",
"reactor.function.TupleUtils");
/** Type members that should be statically imported. */
@VisibleForTesting
static final ImmutableSetMultimap<String, String> STATIC_IMPORT_CANDIDATE_METHODS =
static final ImmutableSetMultimap<String, String> STATIC_IMPORT_CANDIDATE_MEMBERS =
ImmutableSetMultimap.<String, String>builder()
.putAll(
"com.google.common.collect.ImmutableListMultimap",
@@ -108,8 +124,10 @@ public final class StaticImportCheck extends BugChecker implements MemberSelectT
.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")
.putAll(
"java.util.Objects",
@@ -122,9 +140,57 @@ public final class StaticImportCheck extends BugChecker implements MemberSelectT
.putAll("com.google.common.collect.Comparators", "emptiesFirst", "emptiesLast")
.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");
@Override
public Description matchMemberSelect(MemberSelectTree tree, VisitorState state) {
if (!isCandidate(state)) {
if (!isCandidateContext(state) || !isCandidate(tree)) {
return Description.NO_MATCH;
}
@@ -139,7 +205,7 @@ public final class StaticImportCheck extends BugChecker implements MemberSelectT
.orElse(Description.NO_MATCH);
}
private static boolean isCandidate(VisitorState state) {
private static boolean isCandidateContext(VisitorState state) {
Tree parentTree =
requireNonNull(state.getPath().getParentPath(), "MemberSelectTree lacks enclosing node")
.getLeaf();
@@ -154,6 +220,17 @@ public final class StaticImportCheck extends BugChecker implements MemberSelectT
}
}
private static boolean isCandidate(MemberSelectTree tree) {
String identifier = tree.getIdentifier().toString();
if (STATIC_IMPORT_EXEMPTED_IDENTIFIERS.contains(identifier)) {
return false;
}
Type type = ASTHelpers.getType(tree.getExpression());
return type != null
&& !STATIC_IMPORT_EXEMPTED_MEMBERS.containsEntry(type.toString(), identifier);
}
private static Optional<String> getCandidateSimpleName(StaticImportInfo importInfo) {
String canonicalName = importInfo.canonicalName();
return importInfo
@@ -161,8 +238,8 @@ public final class StaticImportCheck extends BugChecker implements MemberSelectT
.toJavaUtil()
.filter(
name ->
STATIC_IMPORT_CANDIDATE_CLASSES.contains(canonicalName)
|| STATIC_IMPORT_CANDIDATE_METHODS.containsEntry(canonicalName, name));
STATIC_IMPORT_CANDIDATE_TYPES.contains(canonicalName)
|| STATIC_IMPORT_CANDIDATE_MEMBERS.containsEntry(canonicalName, name));
}
private static Optional<Fix> tryStaticImport(

View File

@@ -1,42 +0,0 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType;
import static com.google.errorprone.BugPattern.SeverityLevel;
import static com.google.errorprone.BugPattern.StandardTags;
import static com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
import static com.sun.source.tree.Tree.Kind;
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.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.MethodInvocationTree;
@AutoService(BugChecker.class)
@BugPattern(
name = "StringIsEmpty",
summary = "Prefer `String#isEmpty` over `String#equals`",
severity = SeverityLevel.SUGGESTION,
tags = StandardTags.STYLE)
public final class StringIsEmptyCheck extends BugChecker implements MethodInvocationTreeMatcher {
private static final Matcher<ExpressionTree> STRING_EQUALS_INVOCATION =
instanceMethod().onDescendantOf("java.lang.String").named("equals");
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (STRING_EQUALS_INVOCATION.matches(tree, state)
&& tree.getArguments().get(0).getKind() == Kind.STRING_LITERAL
&& ((LiteralTree) tree.getArguments().get(0)).getValue().equals("")) {
return describeMatch(
tree, SuggestedFix.replace(tree, ASTHelpers.getReceiver(tree) + ".isEmpty()"));
}
return Description.NO_MATCH;
}
}

View File

@@ -1,5 +1,8 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.NONE;
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.anyOf;
import static com.google.errorprone.matchers.Matchers.enclosingClass;
@@ -10,9 +13,6 @@ import static com.google.errorprone.matchers.Matchers.staticMethod;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.LinkType;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.StandardTags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
@@ -29,13 +29,12 @@ import java.time.LocalTime;
/** A {@link BugChecker} which flags illegal time-zone related operations. */
@AutoService(BugChecker.class)
@BugPattern(
name = "TimeZoneUsage",
summary =
"Derive the current time from an existing `Clock` Spring bean, and don't rely on a `Clock`'s time zone",
linkType = LinkType.NONE,
severity = SeverityLevel.WARNING,
tags = StandardTags.FRAGILE_CODE)
public final class TimeZoneUsageCheck extends BugChecker implements MethodInvocationTreeMatcher {
linkType = NONE,
severity = WARNING,
tags = FRAGILE_CODE)
public final class TimeZoneUsage extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> BANNED_TIME_METHOD =
anyOf(
@@ -59,7 +58,7 @@ public final class TimeZoneUsageCheck extends BugChecker implements MethodInvoca
LocalDateTime.class.getName(),
LocalTime.class.getName())
.named("now"),
staticMethod().onClassAny(Instant.class.getName()).named("now").withParameters());
staticMethod().onClassAny(Instant.class.getName()).named("now").withNoParameters());
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.bugpatterns;
package tech.picnic.errorprone.bugpatterns.util;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.HashMultimap;
@@ -28,7 +28,7 @@ import java.util.stream.Stream;
* <p>This class allows one to define a whitelist or blacklist of annotations or their attributes.
* Annotations are identified by their fully qualified name.
*/
final class AnnotationAttributeMatcher implements Serializable {
public final class AnnotationAttributeMatcher implements Serializable {
private static final long serialVersionUID = 1L;
private final boolean complement;
@@ -59,7 +59,7 @@ final class AnnotationAttributeMatcher implements Serializable {
* @param exclusions The listed annotations or annotation attributes are not matched.
* @return A non-{@code null} {@link AnnotationAttributeMatcher}.
*/
static AnnotationAttributeMatcher create(
public static AnnotationAttributeMatcher create(
Optional<? extends List<String>> inclusions, Iterable<String> exclusions) {
Set<String> includedWholeTypes = new HashSet<>();
Set<String> excludedWholeTypes = new HashSet<>();
@@ -97,7 +97,13 @@ final class AnnotationAttributeMatcher implements Serializable {
}
}
Stream<? extends ExpressionTree> extractMatchingArguments(AnnotationTree tree) {
/**
* Returns the subset of arguments of the given {@link AnnotationTree} matched by this instance.
*
* @param tree The annotation AST node to be inspected.
* @return Any matching annotation arguments.
*/
public Stream<? extends ExpressionTree> extractMatchingArguments(AnnotationTree tree) {
Type type = ASTHelpers.getType(tree.getAnnotationType());
if (type == null) {
return Stream.empty();

View File

@@ -0,0 +1,129 @@
package tech.picnic.errorprone.bugpatterns.util;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
/** Utility class that can be used to identify reserved keywords of the Java language. */
public final class JavaKeywords {
/**
* List of all reserved keywords in the Java language.
*
* @see <a href="https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.9">JDK 17 JLS
* section 3.9: Keywords</a>
*/
private static final ImmutableSet<String> RESERVED_KEYWORDS =
ImmutableSet.of(
"_",
"abstract",
"assert",
"boolean",
"break",
"byte",
"case",
"catch",
"char",
"class",
"const",
"continue",
"default",
"do",
"double",
"else",
"enum",
"extends",
"final",
"finally",
"float",
"for",
"goto",
"if",
"implements",
"import",
"instanceof",
"int",
"interface",
"long",
"native",
"new",
"package",
"private",
"protected",
"public",
"return",
"short",
"static",
"strictfp",
"super",
"switch",
"synchronized",
"this",
"throw",
"throws",
"transient",
"try",
"void",
"volatile",
"while");
/**
* List of all contextual keywords in the Java language.
*
* @see <a href="https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.9">JDK 17 JLS
* section 3.9: Keywords</a>
*/
private static final ImmutableSet<String> CONTEXTUAL_KEYWORDS =
ImmutableSet.of(
"exports",
"module",
"non-sealed",
"open",
"opens",
"permits",
"provides",
"record",
"requires",
"sealed",
"to",
"transitive",
"uses",
"var",
"with",
"yield");
/** List of all keywords in the Java language. */
private static final ImmutableSet<String> ALL_KEYWORDS =
Sets.union(RESERVED_KEYWORDS, CONTEXTUAL_KEYWORDS).immutableCopy();
private JavaKeywords() {}
/**
* Tells whether the given string is a reserved keyword in the Java language.
*
* @param str The string of interest.
* @return {@code true} if the given string is a reserved keyword in the Java language.
*/
public static boolean isReservedKeyword(String str) {
return RESERVED_KEYWORDS.contains(str);
}
/**
* Tells whether the given string is a contextual keyword in the Java language.
*
* @param str The string of interest.
* @return {@code true} if the given string is a contextual keyword in the Java language.
*/
public static boolean isContextualKeyword(String str) {
return CONTEXTUAL_KEYWORDS.contains(str);
}
/**
* Tells whether the given string is a reserved or contextual keyword in the Java language.
*
* @param str The string of interest.
* @return {@code true} if the given string is a reserved or contextual keyword in the Java
* language.
*/
public static boolean isKeyword(String str) {
return ALL_KEYWORDS.contains(str);
}
}

View File

@@ -1,4 +1,4 @@
package tech.picnic.errorprone.bugpatterns;
package tech.picnic.errorprone.bugpatterns.util;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
@@ -15,13 +15,20 @@ import java.util.regex.Pattern;
/** A method invocation expression {@link Matcher} factory. */
// XXX: Document better. The expressions accepted here could also be defined using `MethodMatchers`.
// So explain why this class is still useful.
final class MethodMatcherFactory {
public final class MethodMatcherFactory {
private static final Splitter ARGUMENT_TYPE_SPLITTER =
Splitter.on(',').trimResults().omitEmptyStrings();
private static final Pattern METHOD_SIGNATURE =
Pattern.compile("([^\\s#(,)]+)#([^\\s#(,)]+)\\(((?:[^\\s#(,)]+(?:,[^\\s#(,)]+)*)?)\\)");
Matcher<ExpressionTree> create(Collection<String> signatures) {
/**
* Creates a {@link Matcher} of methods with any of the given signatures.
*
* @param signatures The method signatures of interest.
* @return A new {@link Matcher} which accepts invocation expressions of any method identified by
* the given signatures.
*/
public Matcher<ExpressionTree> create(Collection<String> signatures) {
return anyOf(
signatures.stream()
.map(MethodMatcherFactory::createMethodMatcher)

View File

@@ -1,19 +1,26 @@
package tech.picnic.errorprone.bugpatterns;
package tech.picnic.errorprone.bugpatterns.util;
import com.google.errorprone.VisitorState;
import com.sun.source.tree.Tree;
/**
* A collection of Error Prone utility methods for dealing with the source code representation of
* AST nodes.
*/
// XXX: Can we locate this code in a better place? Maybe contribute it upstream?
final class Util {
private Util() {}
public final class SourceCode {
private SourceCode() {}
/**
* Returns a string representation of the given {@link Tree}, preferring the original source code
* (if available) over its prettified representation.
*
* @param tree The AST node of interest.
* @param state A {@link VisitorState} describing the context in which the given {@link Tree} is
* found.
* @return A non-{@code null} string.
*/
static String treeToString(Tree tree, VisitorState state) {
public static String treeToString(Tree tree, VisitorState state) {
String src = state.getSourceForNode(tree);
return src != null ? src : tree.toString();
}

View File

@@ -0,0 +1,4 @@
/** Auxiliary utilities for use by Error Prone checks. */
@com.google.errorprone.annotations.CheckReturnValue
@javax.annotation.ParametersAreNonnullByDefault
package tech.picnic.errorprone.bugpatterns.util;

View File

@@ -8,13 +8,22 @@ import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.math.BigDecimal;
import org.assertj.core.api.AbstractBigDecimalAssert;
import org.assertj.core.api.BigDecimalAssert;
// XXX: If we add a rule which drops unnecessary `L` suffixes from literal longs, then the `0L`/`1L`
// cases below can go.
/**
* Refaster templates related to AssertJ assertions over {@link BigDecimal}s.
*
* <p>Note that, contrary to collections of Refaster templates for other {@link
* org.assertj.core.api.NumberAssert} subtypes, these templates do not rewrite to/from {@link
* BigDecimalAssert#isEqualTo(Object)} and {@link BigDecimalAssert#isNotEqualTo(Object)}. This is
* because {@link BigDecimal#equals(Object)} considers not only the numeric value of compared
* instances, but also their scale. As a result various seemingly straightforward transformations
* would actually subtly change the assertion's semantics.
*/
final class AssertJBigDecimalTemplates {
private AssertJBigDecimalTemplates() {}
static final class AbstractBigDecimalAssertIsEqualTo {
static final class AbstractBigDecimalAssertIsEqualByComparingTo {
@BeforeTemplate
AbstractBigDecimalAssert<?> before(AbstractBigDecimalAssert<?> bigDecimalAssert, BigDecimal n) {
return Refaster.anyOf(
@@ -24,11 +33,11 @@ final class AssertJBigDecimalTemplates {
@AfterTemplate
AbstractBigDecimalAssert<?> after(AbstractBigDecimalAssert<?> bigDecimalAssert, BigDecimal n) {
return bigDecimalAssert.isEqualTo(n);
return bigDecimalAssert.isEqualByComparingTo(n);
}
}
static final class AbstractBigDecimalAssertIsNotEqualTo {
static final class AbstractBigDecimalAssertIsNotEqualByComparingTo {
@BeforeTemplate
AbstractBigDecimalAssert<?> before(AbstractBigDecimalAssert<?> bigDecimalAssert, BigDecimal n) {
return Refaster.anyOf(
@@ -38,52 +47,7 @@ final class AssertJBigDecimalTemplates {
@AfterTemplate
AbstractBigDecimalAssert<?> after(AbstractBigDecimalAssert<?> bigDecimalAssert, BigDecimal n) {
return bigDecimalAssert.isNotEqualTo(n);
}
}
static final class AbstractBigDecimalAssertIsZero {
@BeforeTemplate
AbstractBigDecimalAssert<?> before(AbstractBigDecimalAssert<?> bigDecimalAssert) {
return Refaster.anyOf(
bigDecimalAssert.isZero(),
bigDecimalAssert.isEqualTo(0L),
bigDecimalAssert.isEqualTo(BigDecimal.ZERO));
}
@AfterTemplate
AbstractBigDecimalAssert<?> after(AbstractBigDecimalAssert<?> bigDecimalAssert) {
return bigDecimalAssert.isEqualTo(0);
}
}
static final class AbstractBigDecimalAssertIsNotZero {
@BeforeTemplate
AbstractBigDecimalAssert<?> before(AbstractBigDecimalAssert<?> bigDecimalAssert) {
return Refaster.anyOf(
bigDecimalAssert.isNotZero(),
bigDecimalAssert.isNotEqualTo(0L),
bigDecimalAssert.isNotEqualTo(BigDecimal.ZERO));
}
@AfterTemplate
AbstractBigDecimalAssert<?> after(AbstractBigDecimalAssert<?> bigDecimalAssert) {
return bigDecimalAssert.isNotEqualTo(0);
}
}
static final class AbstractBigDecimalAssertIsOne {
@BeforeTemplate
AbstractBigDecimalAssert<?> before(AbstractBigDecimalAssert<?> bigDecimalAssert) {
return Refaster.anyOf(
bigDecimalAssert.isOne(),
bigDecimalAssert.isEqualTo(1L),
bigDecimalAssert.isEqualTo(BigDecimal.ONE));
}
@AfterTemplate
AbstractBigDecimalAssert<?> after(AbstractBigDecimalAssert<?> bigDecimalAssert) {
return bigDecimalAssert.isEqualTo(1);
return bigDecimalAssert.isNotEqualByComparingTo(n);
}
}
}

View File

@@ -1,8 +1,8 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -59,7 +59,7 @@ final class AssertJBooleanTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractBooleanAssert<?> after(boolean b) {
return assertThat(b).isTrue();
}
@@ -88,7 +88,7 @@ final class AssertJBooleanTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractBooleanAssert<?> after(boolean b) {
return assertThat(b).isFalse();
}

View File

@@ -15,11 +15,7 @@ final class AssertJByteTemplates {
@BeforeTemplate
AbstractByteAssert<?> before(AbstractByteAssert<?> byteAssert, byte n) {
return Refaster.anyOf(
byteAssert.isCloseTo(n, offset((byte) 0)),
byteAssert.isCloseTo(Byte.valueOf(n), offset((byte) 0)),
byteAssert.isCloseTo(n, withPercentage(0)),
byteAssert.isCloseTo(Byte.valueOf(n), withPercentage(0)),
byteAssert.isEqualTo(Byte.valueOf(n)));
byteAssert.isCloseTo(n, offset((byte) 0)), byteAssert.isCloseTo(n, withPercentage(0)));
}
@AfterTemplate
@@ -33,10 +29,7 @@ final class AssertJByteTemplates {
AbstractByteAssert<?> before(AbstractByteAssert<?> byteAssert, byte n) {
return Refaster.anyOf(
byteAssert.isNotCloseTo(n, offset((byte) 0)),
byteAssert.isNotCloseTo(Byte.valueOf(n), offset((byte) 0)),
byteAssert.isNotCloseTo(n, withPercentage(0)),
byteAssert.isNotCloseTo(Byte.valueOf(n), withPercentage(0)),
byteAssert.isNotEqualTo(Byte.valueOf(n)));
byteAssert.isNotCloseTo(n, withPercentage(0)));
}
@AfterTemplate

View File

@@ -1,8 +1,8 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -21,7 +21,7 @@ final class AssertJCharSequenceTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(CharSequence charSequence) {
assertThat(charSequence).isEmpty();
}
@@ -36,7 +36,7 @@ final class AssertJCharSequenceTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractAssert<?, ?> after(CharSequence charSequence) {
return assertThat(charSequence).isNotEmpty();
}
@@ -49,7 +49,7 @@ final class AssertJCharSequenceTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractAssert<?, ?> after(CharSequence charSequence, int length) {
return assertThat(charSequence).hasSize(length);
}

View File

@@ -36,11 +36,7 @@ final class AssertJDoubleTemplates {
@BeforeTemplate
AbstractDoubleAssert<?> before(AbstractDoubleAssert<?> doubleAssert, double n) {
return Refaster.anyOf(
doubleAssert.isCloseTo(n, offset(0.0)),
doubleAssert.isCloseTo(Double.valueOf(n), offset(0.0)),
doubleAssert.isCloseTo(n, withPercentage(0.0)),
doubleAssert.isCloseTo(Double.valueOf(n), withPercentage(0.0)),
doubleAssert.isEqualTo(Double.valueOf(n)));
doubleAssert.isCloseTo(n, offset(0.0)), doubleAssert.isCloseTo(n, withPercentage(0.0)));
}
@AfterTemplate
@@ -54,10 +50,7 @@ final class AssertJDoubleTemplates {
AbstractDoubleAssert<?> before(AbstractDoubleAssert<?> doubleAssert, double n) {
return Refaster.anyOf(
doubleAssert.isNotCloseTo(n, offset(0.0)),
doubleAssert.isNotCloseTo(Double.valueOf(n), offset(0.0)),
doubleAssert.isNotCloseTo(n, withPercentage(0.0)),
doubleAssert.isNotCloseTo(Double.valueOf(n), withPercentage(0.0)),
doubleAssert.isNotEqualTo(Double.valueOf(n)));
doubleAssert.isNotCloseTo(n, withPercentage(0.0)));
}
@AfterTemplate

View File

@@ -36,11 +36,7 @@ final class AssertJFloatTemplates {
@BeforeTemplate
AbstractFloatAssert<?> before(AbstractFloatAssert<?> floatAssert, float n) {
return Refaster.anyOf(
floatAssert.isCloseTo(n, offset(0F)),
floatAssert.isCloseTo(Float.valueOf(n), offset(0F)),
floatAssert.isCloseTo(n, withPercentage(0)),
floatAssert.isCloseTo(Float.valueOf(n), withPercentage(0)),
floatAssert.isEqualTo(Float.valueOf(n)));
floatAssert.isCloseTo(n, offset(0F)), floatAssert.isCloseTo(n, withPercentage(0)));
}
@AfterTemplate
@@ -53,11 +49,7 @@ final class AssertJFloatTemplates {
@BeforeTemplate
AbstractFloatAssert<?> before(AbstractFloatAssert<?> floatAssert, float n) {
return Refaster.anyOf(
floatAssert.isNotCloseTo(n, offset(0F)),
floatAssert.isNotCloseTo(Float.valueOf(n), offset(0F)),
floatAssert.isNotCloseTo(n, withPercentage(0)),
floatAssert.isNotCloseTo(Float.valueOf(n), withPercentage(0)),
floatAssert.isNotEqualTo(Float.valueOf(n)));
floatAssert.isNotCloseTo(n, offset(0F)), floatAssert.isNotCloseTo(n, withPercentage(0)));
}
@AfterTemplate

View File

@@ -15,11 +15,7 @@ final class AssertJIntegerTemplates {
@BeforeTemplate
AbstractIntegerAssert<?> before(AbstractIntegerAssert<?> intAssert, int n) {
return Refaster.anyOf(
intAssert.isCloseTo(n, offset(0)),
intAssert.isCloseTo(Integer.valueOf(n), offset(0)),
intAssert.isCloseTo(n, withPercentage(0)),
intAssert.isCloseTo(Integer.valueOf(n), withPercentage(0)),
intAssert.isEqualTo(Integer.valueOf(n)));
intAssert.isCloseTo(n, offset(0)), intAssert.isCloseTo(n, withPercentage(0)));
}
@AfterTemplate
@@ -32,11 +28,7 @@ final class AssertJIntegerTemplates {
@BeforeTemplate
AbstractIntegerAssert<?> before(AbstractIntegerAssert<?> intAssert, int n) {
return Refaster.anyOf(
intAssert.isNotCloseTo(n, offset(0)),
intAssert.isNotCloseTo(Integer.valueOf(n), offset(0)),
intAssert.isNotCloseTo(n, withPercentage(0)),
intAssert.isNotCloseTo(Integer.valueOf(n), withPercentage(0)),
intAssert.isNotEqualTo(Integer.valueOf(n)));
intAssert.isNotCloseTo(n, offset(0)), intAssert.isNotCloseTo(n, withPercentage(0)));
}
@AfterTemplate

View File

@@ -15,11 +15,7 @@ final class AssertJLongTemplates {
@BeforeTemplate
AbstractLongAssert<?> before(AbstractLongAssert<?> longAssert, long n) {
return Refaster.anyOf(
longAssert.isCloseTo(n, offset(0L)),
longAssert.isCloseTo(Long.valueOf(n), offset(0L)),
longAssert.isCloseTo(n, withPercentage(0)),
longAssert.isCloseTo(Long.valueOf(n), withPercentage(0)),
longAssert.isEqualTo(Long.valueOf(n)));
longAssert.isCloseTo(n, offset(0L)), longAssert.isCloseTo(n, withPercentage(0)));
}
@AfterTemplate
@@ -32,11 +28,7 @@ final class AssertJLongTemplates {
@BeforeTemplate
AbstractLongAssert<?> before(AbstractLongAssert<?> longAssert, long n) {
return Refaster.anyOf(
longAssert.isNotCloseTo(n, offset(0L)),
longAssert.isNotCloseTo(Long.valueOf(n), offset(0L)),
longAssert.isNotCloseTo(n, withPercentage(0)),
longAssert.isNotCloseTo(Long.valueOf(n), withPercentage(0)),
longAssert.isNotEqualTo(Long.valueOf(n)));
longAssert.isNotCloseTo(n, offset(0L)), longAssert.isNotCloseTo(n, withPercentage(0)));
}
@AfterTemplate

View File

@@ -0,0 +1,35 @@
package tech.picnic.errorprone.refastertemplates;
import com.google.common.collect.ImmutableMap;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.Map;
import org.assertj.core.api.AbstractMapAssert;
final class AssertJMapTemplates {
private AssertJMapTemplates() {}
static final class AbstractMapAssertContainsExactlyInAnyOrderEntriesOf<K, V> {
@BeforeTemplate
AbstractMapAssert<?, ?, K, V> before(AbstractMapAssert<?, ?, K, V> mapAssert, Map<K, V> map) {
return mapAssert.isEqualTo(map);
}
@AfterTemplate
AbstractMapAssert<?, ?, K, V> after(AbstractMapAssert<?, ?, K, V> mapAssert, Map<K, V> map) {
return mapAssert.containsExactlyInAnyOrderEntriesOf(map);
}
}
static final class AbstractMapAssertContainsExactlyEntriesOf<K, V> {
@BeforeTemplate
AbstractMapAssert<?, ?, K, V> before(AbstractMapAssert<?, ?, K, V> mapAssert, K key, V value) {
return mapAssert.containsExactlyInAnyOrderEntriesOf(ImmutableMap.of(key, value));
}
@AfterTemplate
AbstractMapAssert<?, ?, K, V> after(AbstractMapAssert<?, ?, K, V> mapAssert, K key, V value) {
return mapAssert.containsExactlyEntriesOf(ImmutableMap.of(key, value));
}
}
}

View File

@@ -1,8 +1,12 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
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 java.math.BigDecimal;
import java.math.BigInteger;
import org.assertj.core.api.AbstractBigDecimalAssert;
@@ -18,7 +22,7 @@ import org.assertj.core.api.NumberAssert;
final class AssertJNumberTemplates {
private AssertJNumberTemplates() {}
static final class NumberIsPositive {
static final class NumberAssertIsPositive {
@BeforeTemplate
AbstractByteAssert<?> before(AbstractByteAssert<?> numberAssert) {
return Refaster.anyOf(
@@ -69,7 +73,7 @@ final class AssertJNumberTemplates {
}
}
static final class NumberIsNotPositive {
static final class NumberAssertIsNotPositive {
@BeforeTemplate
AbstractByteAssert<?> before(AbstractByteAssert<?> numberAssert) {
return Refaster.anyOf(
@@ -120,7 +124,7 @@ final class AssertJNumberTemplates {
}
}
static final class NumberIsNegative {
static final class NumberAssertIsNegative {
@BeforeTemplate
AbstractByteAssert<?> before(AbstractByteAssert<?> numberAssert) {
return Refaster.anyOf(
@@ -171,7 +175,7 @@ final class AssertJNumberTemplates {
}
}
static final class NumberIsNotNegative {
static final class NumberAssertIsNotNegative {
@BeforeTemplate
AbstractByteAssert<?> before(AbstractByteAssert<?> numberAssert) {
return Refaster.anyOf(
@@ -221,4 +225,40 @@ final class AssertJNumberTemplates {
return numberAssert.isNotNegative();
}
}
static final class AssertThatIsOdd {
@BeforeTemplate
AbstractIntegerAssert<?> before(int number) {
return assertThat(number % 2).isEqualTo(1);
}
@BeforeTemplate
AbstractLongAssert<?> before(long number) {
return assertThat(number % 2).isEqualTo(1);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
NumberAssert<?, ?> after(long number) {
return assertThat(number).isOdd();
}
}
static final class AssertThatIsEven {
@BeforeTemplate
AbstractIntegerAssert<?> before(int number) {
return assertThat(number % 2).isEqualTo(0);
}
@BeforeTemplate
AbstractLongAssert<?> before(long number) {
return assertThat(number % 2).isEqualTo(0);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
NumberAssert<?, ?> after(long number) {
return assertThat(number).isEven();
}
}
}

View File

@@ -1,8 +1,8 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -21,7 +21,7 @@ final class AssertJObjectTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ObjectAssert<S> after(S object) {
return assertThat(object).isInstanceOf(Refaster.<T>clazz());
}
@@ -34,7 +34,7 @@ final class AssertJObjectTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ObjectAssert<S> after(S object) {
return assertThat(object).isNotInstanceOf(Refaster.<T>clazz());
}
@@ -47,7 +47,7 @@ final class AssertJObjectTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ObjectAssert<S> after(S object1, T object2) {
return assertThat(object1).isEqualTo(object2);
}
@@ -60,7 +60,7 @@ final class AssertJObjectTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ObjectAssert<S> after(S object1, T object2) {
return assertThat(object1).isNotEqualTo(object2);
}
@@ -73,7 +73,7 @@ final class AssertJObjectTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ObjectAssert<T> after(T object, String str) {
return assertThat(object).hasToString(str);
}

View File

@@ -1,8 +1,8 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -26,7 +26,7 @@ final class AssertJOptionalTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, T> after(Optional<T> optional) {
return assertThat(optional).get();
}
@@ -53,7 +53,7 @@ final class AssertJOptionalTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
OptionalAssert<T> after(Optional<T> optional) {
return assertThat(optional).isPresent();
}
@@ -80,7 +80,7 @@ final class AssertJOptionalTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
OptionalAssert<T> after(Optional<T> optional) {
return assertThat(optional).isEmpty();
}
@@ -122,7 +122,7 @@ final class AssertJOptionalTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, T> after(Optional<T> optional, Predicate<? super T> predicate) {
return assertThat(optional).get().matches(predicate);
}

View File

@@ -15,11 +15,7 @@ final class AssertJShortTemplates {
@BeforeTemplate
AbstractShortAssert<?> before(AbstractShortAssert<?> shortAssert, short n) {
return Refaster.anyOf(
shortAssert.isCloseTo(n, offset((short) 0)),
shortAssert.isCloseTo(Short.valueOf(n), offset((short) 0)),
shortAssert.isCloseTo(n, withPercentage(0)),
shortAssert.isCloseTo(Short.valueOf(n), withPercentage(0)),
shortAssert.isEqualTo(Short.valueOf(n)));
shortAssert.isCloseTo(n, offset((short) 0)), shortAssert.isCloseTo(n, withPercentage(0)));
}
@AfterTemplate
@@ -33,10 +29,7 @@ final class AssertJShortTemplates {
AbstractShortAssert<?> before(AbstractShortAssert<?> shortAssert, short n) {
return Refaster.anyOf(
shortAssert.isNotCloseTo(n, offset((short) 0)),
shortAssert.isNotCloseTo(Short.valueOf(n), offset((short) 0)),
shortAssert.isNotCloseTo(n, withPercentage(0)),
shortAssert.isNotCloseTo(Short.valueOf(n), withPercentage(0)),
shortAssert.isNotEqualTo(Short.valueOf(n)));
shortAssert.isNotCloseTo(n, withPercentage(0)));
}
@AfterTemplate

View File

@@ -1,8 +1,8 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
@@ -31,7 +31,7 @@ final class AssertJStringTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(String string) {
assertThat(string).isEmpty();
}
@@ -56,9 +56,35 @@ final class AssertJStringTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractAssert<?, ?> after(String string) {
return assertThat(string).isNotEmpty();
}
}
static final class AssertThatMatches {
@BeforeTemplate
AbstractAssert<?, ?> before(String string, String regex) {
return assertThat(string.matches(regex)).isTrue();
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractAssert<?, ?> after(String string, String regex) {
return assertThat(string).matches(regex);
}
}
static final class AssertThatDoesNotMatch {
@BeforeTemplate
AbstractAssert<?, ?> before(String string, String regex) {
return assertThat(string.matches(regex)).isFalse();
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractAssert<?, ?> after(String string, String regex) {
return assertThat(string).doesNotMatch(regex);
}
}
}

View File

@@ -1,5 +1,6 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableBiMap;
@@ -12,7 +13,6 @@ 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.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -39,6 +39,7 @@ import java.util.stream.Collector;
import java.util.stream.Stream;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractBooleanAssert;
import org.assertj.core.api.AbstractCollectionAssert;
import org.assertj.core.api.AbstractComparableAssert;
import org.assertj.core.api.AbstractDoubleAssert;
import org.assertj.core.api.AbstractIntegerAssert;
@@ -96,7 +97,6 @@ import tech.picnic.errorprone.refaster.util.IsArray;
// XXX: Right now we use and import `Offset.offset` and `Percentage.withPercentage`. Use the AssertJ
// methods instead. (Also in the TestNG migration.)
// ^ Also for `Tuple`!
// XXX: Use `assertThatIllegalArgumentException` and variants.
// XXX: `assertThatCode(x).isInstanceOf(clazz)` -> `assertThatThrownBy(x).isInstanceOf(clazz)`
// (etc.)
// XXX: Look into using Assertions#contentOf(URL url, Charset charset) instead of our own test
@@ -136,7 +136,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
OptionalDoubleAssert after(OptionalDouble optional, double expected) {
return assertThat(optional).hasValue(expected);
}
@@ -155,7 +155,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
OptionalIntAssert after(OptionalInt optional, int expected) {
return assertThat(optional).hasValue(expected);
}
@@ -174,7 +174,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
OptionalLongAssert after(OptionalLong optional, long expected) {
return assertThat(optional).hasValue(expected);
}
@@ -364,6 +364,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ObjectEnumerableAssert<?, S> after(Set<S> set, T element) {
return assertThat(set).containsExactly(element);
}
@@ -428,7 +429,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Collection<E> iterable) {
assertThat(iterable).isEmpty();
}
@@ -452,7 +453,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
IterableAssert<E> after(Iterable<E> iterable) {
return assertThat(iterable).isNotEmpty();
}
@@ -470,7 +471,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
IterableAssert<E> after(Iterable<E> iterable, int length) {
return assertThat(iterable).hasSize(length);
}
@@ -483,7 +484,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
IterableAssert<S> after(Iterable<S> iterable, T element) {
return assertThat(iterable).containsExactly(element);
}
@@ -500,7 +501,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
IterableAssert<S> after(Iterable<S> iterable, T element) {
return assertThat(iterable).containsExactly(element);
}
@@ -517,7 +518,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(List<S> list1, List<T> list2) {
return assertThat(list1).containsExactlyElementsOf(list2);
}
@@ -529,15 +530,15 @@ final class AssertJTemplates {
static final class AssertThatSetsAreEqual<S, T extends S> {
@BeforeTemplate
IterableAssert<S> before(Set<S> set1, Set<T> set2) {
AbstractCollectionAssert<?, ?, S, ?> before(Set<S> set1, Set<T> set2) {
return Refaster.anyOf(
assertThat(set1).isEqualTo(set2),
assertThat(set1).containsExactlyInAnyOrderElementsOf(set2));
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
IterableAssert<S> after(Set<S> set1, Set<T> set2) {
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractCollectionAssert<?, ?, S, ?> after(Set<S> set1, Set<T> set2) {
return assertThat(set1).hasSameElementsAs(set2);
}
}
@@ -548,13 +549,13 @@ final class AssertJTemplates {
static final class AssertThatMultisetsAreEqual<S, T extends S> {
@BeforeTemplate
IterableAssert<S> before(Multiset<S> multiset1, Multiset<T> multiset2) {
AbstractCollectionAssert<?, ?, S, ?> before(Multiset<S> multiset1, Multiset<T> multiset2) {
return assertThat(multiset1).isEqualTo(multiset2);
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
IterableAssert<S> after(Multiset<S> multiset1, Multiset<T> multiset2) {
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractCollectionAssert<?, ?, S, ?> after(Multiset<S> multiset1, Multiset<T> multiset2) {
return assertThat(multiset1).containsExactlyInAnyOrderElementsOf(multiset2);
}
}
@@ -631,7 +632,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Map<K, V> map) {
assertThat(map).isEmpty();
}
@@ -668,7 +669,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
MapAssert<K, V> after(Map<K, V> map) {
return assertThat(map).isNotEmpty();
}
@@ -683,7 +684,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
MapAssert<K, V> after(Map<K, V> map, int length) {
return assertThat(map).hasSize(length);
}
@@ -697,7 +698,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
MapAssert<K, V> after(Map<K, V> map1, Map<K, V> map2) {
return assertThat(map1).hasSameSizeAs(map2);
}
@@ -711,7 +712,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
MapAssert<K, V> after(Map<K, V> map, K key) {
return assertThat(map).containsKey(key);
}
@@ -724,7 +725,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
MapAssert<K, V> after(Map<K, V> map, K key) {
return assertThat(map).doesNotContainKey(key);
}
@@ -737,7 +738,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
MapAssert<K, V> after(Map<K, V> map, K key, V value) {
return assertThat(map).containsEntry(key, value);
}
@@ -762,7 +763,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, Iterable<U> iterable) {
return assertThat(stream).containsAnyElementsOf(iterable);
}
@@ -783,7 +784,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, U[] array) {
return assertThat(stream).containsAnyOf(array);
}
@@ -807,7 +808,7 @@ final class AssertJTemplates {
@AfterTemplate
@SuppressWarnings("ObjectEnumerableContainsOneElement" /* Not a true singleton. */)
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).containsAnyOf(elements);
}
@@ -828,7 +829,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, Iterable<U> iterable) {
return assertThat(stream).containsAll(iterable);
}
@@ -849,7 +850,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, U[] array) {
return assertThat(stream).contains(array);
}
@@ -872,7 +873,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).contains(elements);
}
@@ -887,7 +888,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, Iterable<U> iterable) {
return assertThat(stream).containsExactlyElementsOf(iterable);
}
@@ -902,7 +903,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, U[] array) {
return assertThat(stream).containsExactly(array);
}
@@ -918,7 +919,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).containsExactly(elements);
}
@@ -934,13 +935,13 @@ final class AssertJTemplates {
}
@BeforeTemplate
IterableAssert<T> before2(
AbstractCollectionAssert<?, ?, T, ?> before2(
Stream<S> stream, Collector<S, ?, ? extends Multiset<T>> collector, Iterable<U> iterable) {
return assertThat(stream.collect(collector)).containsExactlyInAnyOrderElementsOf(iterable);
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, Iterable<U> iterable) {
return assertThat(stream).containsExactlyInAnyOrderElementsOf(iterable);
}
@@ -955,13 +956,13 @@ final class AssertJTemplates {
}
@BeforeTemplate
IterableAssert<T> before2(
AbstractCollectionAssert<?, ?, T, ?> before2(
Stream<S> stream, Collector<S, ?, ? extends Multiset<T>> collector, U[] array) {
return assertThat(stream.collect(collector)).containsExactlyInAnyOrder(array);
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, U[] array) {
return assertThat(stream).containsExactlyInAnyOrder(array);
}
@@ -979,7 +980,7 @@ final class AssertJTemplates {
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsExactlyInAnyOrder" /* Varargs converted to array. */)
IterableAssert<T> before2(
AbstractCollectionAssert<?, ?, T, ?> before2(
Stream<S> stream, Collector<S, ?, ? extends Multiset<T>> collector, @Repeated U elements) {
return assertThat(stream.collect(collector))
.containsExactlyInAnyOrder(Refaster.asVarargs(elements));
@@ -987,7 +988,7 @@ final class AssertJTemplates {
@AfterTemplate
@SuppressWarnings("ObjectEnumerableContainsExactlyOneElement" /* Not a true singleton. */)
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).containsExactlyInAnyOrder(elements);
}
@@ -1008,7 +1009,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, Iterable<U> iterable) {
return assertThat(stream).containsSequence(iterable);
}
@@ -1025,7 +1026,7 @@ final class AssertJTemplates {
@AfterTemplate
@SuppressWarnings("ObjectEnumerableContainsOneElement" /* Not a true singleton. */)
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).containsSequence(elements);
}
@@ -1046,7 +1047,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, Iterable<U> iterable) {
return assertThat(stream).containsSubsequence(iterable);
}
@@ -1064,7 +1065,7 @@ final class AssertJTemplates {
@AfterTemplate
@SuppressWarnings("ObjectEnumerableContainsOneElement" /* Not a true singleton. */)
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).containsSubsequence(elements);
}
@@ -1085,7 +1086,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, Iterable<U> iterable) {
return assertThat(stream).doesNotContainAnyElementsOf(iterable);
}
@@ -1106,7 +1107,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, U[] array) {
return assertThat(stream).doesNotContain(array);
}
@@ -1129,7 +1130,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).doesNotContain(elements);
}
@@ -1150,7 +1151,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, Iterable<U> iterable) {
return assertThat(stream).doesNotContainSequence(iterable);
}
@@ -1168,7 +1169,7 @@ final class AssertJTemplates {
@AfterTemplate
@SuppressWarnings("ObjectEnumerableDoesNotContainOneElement" /* Not a true singleton. */)
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).doesNotContainSequence(elements);
}
@@ -1189,7 +1190,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, Iterable<U> iterable) {
return assertThat(stream).hasSameElementsAs(iterable);
}
@@ -1210,7 +1211,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, U[] array) {
return assertThat(stream).containsOnly(array);
}
@@ -1233,7 +1234,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).containsOnly(elements);
}
@@ -1266,7 +1267,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, U[] iterable) {
return assertThat(stream).isSubsetOf(iterable);
}
@@ -1289,7 +1290,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ListAssert<S> after(Stream<S> stream, @Repeated U elements) {
return assertThat(stream).isSubsetOf(elements);
}
@@ -1308,7 +1309,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Stream<S> stream) {
assertThat(stream).isEmpty();
}
@@ -1327,7 +1328,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Stream<S> stream) {
assertThat(stream).isNotEmpty();
}
@@ -1340,7 +1341,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Stream<T> stream, int size) {
assertThat(stream).hasSize(size);
}
@@ -1357,7 +1358,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Predicate<T> predicate, T object) {
assertThat(predicate).accepts(object);
}
@@ -1370,7 +1371,7 @@ final class AssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Predicate<T> predicate, T object) {
assertThat(predicate).rejects(object);
}
@@ -2211,7 +2212,7 @@ final class AssertJTemplates {
// }
//
// @AfterTemplate
// @UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
// @UseImportPolicy(STATIC_IMPORT_ALWAYS)
// IterableAssert<E> after(Iterable<E> iterable, E expected) {
// return assertThat(iterable).containsExactly(expected);
// }

View File

@@ -0,0 +1,445 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIOException;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatNullPointerException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Repeated;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.io.IOException;
import org.assertj.core.api.AbstractObjectAssert;
import org.assertj.core.api.AbstractThrowableAssert;
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
/**
* Refaster templates related to AssertJ assertions over expressions that may throw a {@link
* Throwable} subtype.
*
* <p>For reasons of consistency we prefer {@link
* org.assertj.core.api.Assertions#assertThatThrownBy} over static methods for specific exception
* types. Note that only the most common assertion expressions are rewritten here; covering all
* cases would require the implementation of an Error Prone check instead.
*/
final class AssertJThrowingCallableTemplates {
private AssertJThrowingCallableTemplates() {}
static final class AssertThatThrownByIllegalArgumentException {
@BeforeTemplate
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable) {
return assertThatIllegalArgumentException().isThrownBy(throwingCallable);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable) {
return assertThatThrownBy(throwingCallable).isInstanceOf(IllegalArgumentException.class);
}
}
static final class AssertThatThrownByIllegalArgumentExceptionHasMessage {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalArgumentException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalArgumentException().isThrownBy(throwingCallable).withMessage(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(message);
}
}
static final class AssertThatThrownByIllegalArgumentExceptionHasMessageParameters {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalArgumentException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
return assertThatIllegalArgumentException()
.isThrownBy(throwingCallable)
.withMessage(message, parameters);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(message, parameters);
}
}
static final class AssertThatThrownByIllegalArgumentExceptionHasMessageStartingWith {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalArgumentException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalArgumentException()
.isThrownBy(throwingCallable)
.withMessageStartingWith(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IllegalArgumentException.class)
.hasMessageStartingWith(message);
}
}
static final class AssertThatThrownByIllegalArgumentExceptionHasMessageContaining {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalArgumentException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalArgumentException()
.isThrownBy(throwingCallable)
.withMessageContaining(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining(message);
}
}
static final class AssertThatThrownByIllegalArgumentExceptionHasMessageNotContainingAny {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalArgumentException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, @Repeated CharSequence values) {
return assertThatIllegalArgumentException()
.isThrownBy(throwingCallable)
.withMessageNotContainingAny(values);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
ThrowingCallable throwingCallable, @Repeated CharSequence values) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IllegalArgumentException.class)
.hasMessageNotContainingAny(values);
}
}
static final class AssertThatThrownByIllegalStateException {
@BeforeTemplate
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable) {
return assertThatIllegalStateException().isThrownBy(throwingCallable);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable) {
return assertThatThrownBy(throwingCallable).isInstanceOf(IllegalStateException.class);
}
}
static final class AssertThatThrownByIllegalStateExceptionHasMessage {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalStateException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalStateException().isThrownBy(throwingCallable).withMessage(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IllegalStateException.class)
.hasMessage(message);
}
}
static final class AssertThatThrownByIllegalStateExceptionHasMessageParameters {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalStateException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
return assertThatIllegalStateException()
.isThrownBy(throwingCallable)
.withMessage(message, parameters);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IllegalStateException.class)
.hasMessage(message, parameters);
}
}
static final class AssertThatThrownByIllegalStateExceptionHasMessageStartingWith {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalStateException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalStateException()
.isThrownBy(throwingCallable)
.withMessageStartingWith(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IllegalStateException.class)
.hasMessageStartingWith(message);
}
}
static final class AssertThatThrownByIllegalStateExceptionHasMessageContaining {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalStateException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalStateException()
.isThrownBy(throwingCallable)
.withMessageContaining(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining(message);
}
}
static final class AssertThatThrownByIllegalStateExceptionHasMessageNotContaining {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalStateException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalStateException()
.isThrownBy(throwingCallable)
.withMessageNotContaining(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IllegalStateException.class)
.hasMessageNotContaining(message);
}
}
static final class AssertThatThrownByNullPointerException {
@BeforeTemplate
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable) {
return assertThatNullPointerException().isThrownBy(throwingCallable);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable) {
return assertThatThrownBy(throwingCallable).isInstanceOf(NullPointerException.class);
}
}
static final class AssertThatThrownByNullPointerExceptionHasMessage {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByNullPointerException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatNullPointerException().isThrownBy(throwingCallable).withMessage(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(NullPointerException.class)
.hasMessage(message);
}
}
static final class AssertThatThrownByNullPointerExceptionHasMessageParameters {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByNullPointerException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
return assertThatNullPointerException()
.isThrownBy(throwingCallable)
.withMessage(message, parameters);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(NullPointerException.class)
.hasMessage(message, parameters);
}
}
static final class AssertThatThrownByNullPointerExceptionHasMessageStartingWith {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByNullPointerException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatNullPointerException()
.isThrownBy(throwingCallable)
.withMessageStartingWith(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(NullPointerException.class)
.hasMessageStartingWith(message);
}
}
static final class AssertThatThrownByIOException {
@BeforeTemplate
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable) {
return assertThatIOException().isThrownBy(throwingCallable);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable) {
return assertThatThrownBy(throwingCallable).isInstanceOf(IOException.class);
}
}
static final class AssertThatThrownByIOExceptionHasMessage {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIOException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIOException().isThrownBy(throwingCallable).withMessage(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IOException.class)
.hasMessage(message);
}
}
static final class AssertThatThrownByIOExceptionHasMessageParameters {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIOException" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
return assertThatIOException().isThrownBy(throwingCallable).withMessage(message, parameters);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IOException.class)
.hasMessage(message, parameters);
}
}
static final class AssertThatThrownBy {
@BeforeTemplate
AbstractObjectAssert<?, ?> before(
Class<? extends Throwable> exceptionType, ThrowingCallable throwingCallable) {
return assertThatExceptionOfType(exceptionType).isThrownBy(throwingCallable);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
Class<? extends Throwable> exceptionType, ThrowingCallable throwingCallable) {
return assertThatThrownBy(throwingCallable).isInstanceOf(exceptionType);
}
}
static final class AssertThatThrownByHasMessage {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* Matches strictly more specific expressions. */)
AbstractObjectAssert<?, ?> before(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
String message) {
return assertThatExceptionOfType(exceptionType)
.isThrownBy(throwingCallable)
.withMessage(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
String message) {
return assertThatThrownBy(throwingCallable).isInstanceOf(exceptionType).hasMessage(message);
}
}
// XXX: Drop this template in favour of a generic Error Prone check which flags
// `String.format(...)` arguments to a wide range of format methods.
static final class AbstractThrowableAssertHasMessage {
@BeforeTemplate
AbstractThrowableAssert<?, ? extends Throwable> before(
AbstractThrowableAssert<?, ? extends Throwable> abstractThrowableAssert,
String message,
@Repeated Object parameters) {
return abstractThrowableAssert.hasMessage(String.format(message, parameters));
}
@AfterTemplate
AbstractThrowableAssert<?, ? extends Throwable> after(
AbstractThrowableAssert<?, ? extends Throwable> abstractThrowableAssert,
String message,
@Repeated Object parameters) {
return abstractThrowableAssert.hasMessage(message, parameters);
}
}
// XXX: Drop this template in favour of a generic Error Prone check which flags
// `String.format(...)` arguments to a wide range of format methods.
static final class AbstractThrowableAssertWithFailMessage {
@BeforeTemplate
AbstractThrowableAssert<?, ? extends Throwable> before(
AbstractThrowableAssert<?, ? extends Throwable> abstractThrowableAssert,
String message,
@Repeated Object args) {
return abstractThrowableAssert.withFailMessage(String.format(message, args));
}
@AfterTemplate
AbstractThrowableAssert<?, ? extends Throwable> after(
AbstractThrowableAssert<?, ? extends Throwable> abstractThrowableAssert,
String message,
@Repeated Object args) {
return abstractThrowableAssert.withFailMessage(message, args);
}
}
}

View File

@@ -3,6 +3,8 @@ package tech.picnic.errorprone.refastertemplates;
import static com.google.common.base.Preconditions.checkElementIndex;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Sets.toImmutableEnumSet;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Collections.disjoint;
import static java.util.Objects.checkIndex;
import com.google.common.base.Splitter;
@@ -11,7 +13,6 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -92,7 +93,7 @@ final class AssortedTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ImmutableSet<T> after(Stream<T> stream) {
return stream.collect(toImmutableEnumSet());
}
@@ -162,7 +163,7 @@ final class AssortedTemplates {
@AfterTemplate
boolean after(Set<T> set1, Set<T> set2) {
return Collections.disjoint(set1, set2);
return disjoint(set1, set2);
}
}
@@ -177,15 +178,15 @@ final class AssortedTemplates {
@BeforeTemplate
boolean before(Collection<T> collection1, Collection<T> collection2) {
return Refaster.anyOf(
Collections.disjoint(ImmutableSet.copyOf(collection1), collection2),
Collections.disjoint(new HashSet<>(collection1), collection2),
Collections.disjoint(collection1, ImmutableSet.copyOf(collection2)),
Collections.disjoint(collection1, new HashSet<>(collection2)));
disjoint(ImmutableSet.copyOf(collection1), collection2),
disjoint(new HashSet<>(collection1), collection2),
disjoint(collection1, ImmutableSet.copyOf(collection2)),
disjoint(collection1, new HashSet<>(collection2)));
}
@AfterTemplate
boolean after(Collection<T> collection1, Collection<T> collection2) {
return Collections.disjoint(collection1, collection2);
return disjoint(collection1, collection2);
}
}

View File

@@ -15,6 +15,7 @@ import java.util.List;
import java.util.NavigableSet;
import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import java.util.SortedSet;
import java.util.function.IntFunction;
import java.util.stream.Stream;
@@ -129,31 +130,32 @@ final class CollectionTemplates {
}
}
static final class CollectionRemoveAllFromCollectionBlock<T, S extends T> {
static final class SetRemoveAllCollection<T, S extends T> {
@BeforeTemplate
void before(Collection<T> removeTo, Collection<S> elementsToRemove) {
elementsToRemove.forEach(removeTo::remove);
void before(Set<T> removeFrom, Collection<S> elementsToRemove) {
elementsToRemove.forEach(removeFrom::remove);
}
@BeforeTemplate
void before2(Collection<T> removeTo, Collection<S> elementsToRemove) {
void before2(Set<T> removeFrom, Collection<S> elementsToRemove) {
for (T element : elementsToRemove) {
removeTo.remove(element);
removeFrom.remove(element);
}
}
// XXX: This method is identical to `before2` except for the loop type. Make Refaster smarter so
// that this is supported out of the box.
// that this is supported out of the box. After doing so, also drop the `S extends T` type
// constraint; ideally this check applies to any `S`.
@BeforeTemplate
void before3(Collection<T> removeTo, Collection<S> elementsToRemove) {
void before3(Set<T> removeFrom, Collection<S> elementsToRemove) {
for (S element : elementsToRemove) {
removeTo.remove(element);
removeFrom.remove(element);
}
}
@AfterTemplate
void after(Collection<T> removeTo, Collection<S> elementsToRemove) {
removeTo.removeAll(elementsToRemove);
void after(Set<T> removeFrom, Collection<S> elementsToRemove) {
removeFrom.removeAll(elementsToRemove);
}
}
@@ -187,7 +189,7 @@ final class CollectionTemplates {
* Don't call {@link ImmutableCollection#asList()} if the result is going to be streamed; stream
* directly.
*/
static final class ImmutableCollectionAsListToStream<T> {
static final class ImmutableCollectionStream<T> {
@BeforeTemplate
Stream<T> before(ImmutableCollection<T> collection) {
return collection.asList().stream();

View File

@@ -1,5 +1,6 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Comparator.comparing;
import static java.util.Comparator.comparingDouble;
import static java.util.Comparator.comparingInt;
@@ -11,7 +12,6 @@ import static java.util.function.Function.identity;
import com.google.common.collect.Comparators;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -38,7 +38,7 @@ final class ComparatorTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Comparator<T> after() {
return naturalOrder();
}
@@ -52,7 +52,7 @@ final class ComparatorTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Comparator<T> after() {
return reverseOrder();
}
@@ -66,7 +66,7 @@ final class ComparatorTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Comparator<T> after(Comparator<T> cmp) {
return cmp;
}
@@ -93,7 +93,7 @@ final class ComparatorTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Comparator<S> after(Comparator<S> cmp, Function<? super S, ? extends T> function) {
return cmp.thenComparing(function, reverseOrder());
}
@@ -180,7 +180,7 @@ final class ComparatorTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Comparator<T> after(Comparator<T> cmp) {
return cmp.thenComparing(naturalOrder());
}

View File

@@ -20,7 +20,7 @@ final class EqualityTemplates {
* remaining reference-based equality checks.
*/
// XXX: This Refaster rule is the topic of https://github.com/google/error-prone/issues/559. We
// work around the issue by selecting the "largest replacements". See RefasterCheck.
// work around the issue by selecting the "largest replacements". See the `Refaster` check.
@BeforeTemplate
boolean before(T a, T b) {
return Refaster.anyOf(a.equals(b), Objects.equals(a, b));
@@ -34,9 +34,8 @@ final class EqualityTemplates {
}
/** Prefer {@link Object#equals(Object)} over the equivalent lambda function. */
// XXX: As it stands, this rule is a special case of what `MethodReferenceUsageCheck` tries to
// achieve. If/when `MethodReferenceUsageCheck` becomes production ready, we should simply drop
// this check.
// XXX: As it stands, this rule is a special case of what `MethodReferenceUsage` tries to achieve.
// If/when `MethodReferenceUsage` becomes production ready, we should simply drop this check.
// XXX: Alternatively, the rule should be replaced with a plugin which also identifies cases where
// the arguments are swapped but simplification is possible anyway, by virtue of `v` being
// non-null.

View File

@@ -2,6 +2,7 @@ package tech.picnic.errorprone.refastertemplates;
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;
@@ -12,7 +13,6 @@ import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.SortedSetMultimap;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -92,7 +92,7 @@ final class ImmutableListMultimapTemplates {
*/
static final class EntryToImmutableListMultimap<K, V> {
@BeforeTemplate
ImmutableMultimap<K, V> before(Map.Entry<? extends K, ? extends V> entry) {
ImmutableListMultimap<K, V> before(Map.Entry<? extends K, ? extends V> entry) {
return Refaster.anyOf(
ImmutableListMultimap.<K, V>builder().put(entry).build(),
Stream.of(entry)
@@ -161,7 +161,7 @@ final class ImmutableListMultimapTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ImmutableListMultimap<K, V> after(Stream<E> stream) {
return stream.collect(toImmutableListMultimap(e -> keyFunction(e), e -> valueFunction(e)));
}
@@ -272,17 +272,4 @@ final class ImmutableListMultimapTemplates {
return ImmutableListMultimap.copyOf(Multimaps.transformValues(multimap, transformation));
}
}
/** Don't unnecessarily copy an {@link ImmutableListMultimap}. */
static final class ImmutableListMultimapCopyOfImmutableListMultimap<K, V> {
@BeforeTemplate
ImmutableListMultimap<K, V> before(ImmutableListMultimap<K, V> multimap) {
return ImmutableListMultimap.copyOf(multimap);
}
@AfterTemplate
ImmutableListMultimap<K, V> after(ImmutableListMultimap<K, V> multimap) {
return multimap;
}
}
}

View File

@@ -2,21 +2,20 @@ package tech.picnic.errorprone.refastertemplates;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.Comparator.naturalOrder;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.ImportPolicy;
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 java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
@@ -41,37 +40,6 @@ final class ImmutableListTemplates {
}
}
/** Prefer {@link ImmutableList#of()} over more contrived alternatives. */
static final class EmptyImmutableList<T> {
@BeforeTemplate
ImmutableList<T> before() {
return Refaster.anyOf(
ImmutableList.<T>builder().build(), Stream.<T>empty().collect(toImmutableList()));
}
@AfterTemplate
ImmutableList<T> after() {
return ImmutableList.of();
}
}
/**
* Prefer {@link ImmutableList#of(Object)} over alternatives that don't communicate the
* immutability of the resulting list at the type level.
*/
// XXX: Note that this rewrite rule is incorrect for nullable elements.
static final class SingletonImmutableList<T> {
@BeforeTemplate
List<T> before(T element) {
return Collections.singletonList(element);
}
@AfterTemplate
ImmutableList<T> after(T element) {
return ImmutableList.of(element);
}
}
/**
* Prefer {@link ImmutableList#copyOf(Iterable)} and variants over more contrived alternatives.
*/
@@ -108,39 +76,20 @@ final class ImmutableListTemplates {
}
}
/** Prefer {@link ImmutableList#toImmutableList()} over the more verbose alternative. */
// XXX: Once the code base has been sufficiently cleaned up, we might want to also rewrite
// `Collectors.toList(`), with the caveat that it allows mutation (though this cannot be relied
// upon) as well as nulls. Another option is to explicitly rewrite those variants to
// `Collectors.toSet(ArrayList::new)`.
/** Prefer {@link ImmutableList#toImmutableList()} over less idiomatic alternatives. */
static final class StreamToImmutableList<T> {
@BeforeTemplate
ImmutableList<T> before(Stream<T> stream) {
return Refaster.anyOf(
ImmutableList.copyOf(stream.iterator()),
stream.collect(collectingAndThen(toList(), ImmutableList::copyOf)));
return ImmutableList.copyOf(stream.iterator());
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ImmutableList<T> after(Stream<T> stream) {
return stream.collect(toImmutableList());
}
}
/** Don't call {@link ImmutableList#asList()}; it is a no-op. */
static final class ImmutableListAsList<T> {
@BeforeTemplate
ImmutableList<T> before(ImmutableList<T> list) {
return list.asList();
}
@AfterTemplate
ImmutableList<T> after(ImmutableList<T> list) {
return list;
}
}
/** Prefer {@link ImmutableList#sortedCopyOf(Iterable)} over more contrived alternatives. */
static final class ImmutableListSortedCopyOf<T extends Comparable<? super T>> {
@BeforeTemplate
@@ -194,9 +143,122 @@ final class ImmutableListTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ImmutableList<T> after(Stream<T> stream) {
return stream.collect(toImmutableSet()).asList();
}
}
/**
* Prefer {@link ImmutableList#of()} over more contrived alternatives or alternatives that don't
* communicate the immutability of the resulting list at the type level.
*/
// XXX: The `Stream` variant may be too contrived to warrant inclusion. Review its usage if/when
// this and similar Refaster templates are replaced with an Error Prone check.
static final class ImmutableListOf<T> {
@BeforeTemplate
List<T> before() {
return Refaster.anyOf(
ImmutableList.<T>builder().build(),
Stream.<T>empty().collect(toImmutableList()),
emptyList(),
List.of());
}
@AfterTemplate
ImmutableList<T> after() {
return ImmutableList.of();
}
}
/**
* Prefer {@link ImmutableList#of(Object)} over more contrived alternatives or alternatives that
* don't communicate the immutability of the resulting list at the type level.
*/
// XXX: Note that the replacement of `Collections#singletonList` is incorrect for nullable
// elements.
static final class ImmutableListOf1<T> {
@BeforeTemplate
List<T> before(T e1) {
return Refaster.anyOf(
ImmutableList.<T>builder().add(e1).build(), singletonList(e1), List.of(e1));
}
@AfterTemplate
ImmutableList<T> after(T e1) {
return ImmutableList.of(e1);
}
}
/**
* Prefer {@link ImmutableList#of(Object, Object)} over alternatives that don't communicate the
* immutability of the resulting list at the type level.
*/
// XXX: Consider writing an Error Prone check which also flags straightforward
// `ImmutableList.builder()` usages.
static final class ImmutableListOf2<T> {
@BeforeTemplate
List<T> before(T e1, T e2) {
return List.of(e1, e2);
}
@AfterTemplate
ImmutableList<T> after(T e1, T e2) {
return ImmutableList.of(e1, e2);
}
}
/**
* Prefer {@link ImmutableList#of(Object, Object, Object)} over alternatives that don't
* communicate the immutability of the resulting list at the type level.
*/
// XXX: Consider writing an Error Prone check which also flags straightforward
// `ImmutableList.builder()` usages.
static final class ImmutableListOf3<T> {
@BeforeTemplate
List<T> before(T e1, T e2, T e3) {
return List.of(e1, e2, e3);
}
@AfterTemplate
ImmutableList<T> after(T e1, T e2, T e3) {
return ImmutableList.of(e1, e2, e3);
}
}
/**
* Prefer {@link ImmutableList#of(Object, Object, Object, Object)} over alternatives that don't
* communicate the immutability of the resulting list at the type level.
*/
// XXX: Consider writing an Error Prone check which also flags straightforward
// `ImmutableList.builder()` usages.
static final class ImmutableListOf4<T> {
@BeforeTemplate
List<T> before(T e1, T e2, T e3, T e4) {
return List.of(e1, e2, e3, e4);
}
@AfterTemplate
ImmutableList<T> after(T e1, T e2, T e3, T e4) {
return ImmutableList.of(e1, e2, e3, e4);
}
}
/**
* Prefer {@link ImmutableList#of(Object, Object, Object, Object, Object)} over alternatives that
* don't communicate the immutability of the resulting list at the type level.
*/
// XXX: Consider writing an Error Prone check which also flags straightforward
// `ImmutableList.builder()` usages.
static final class ImmutableListOf5<T> {
@BeforeTemplate
List<T> before(T e1, T e2, T e3, T e4, T e5) {
return List.of(e1, e2, e3, e4, e5);
}
@AfterTemplate
ImmutableList<T> after(T e1, T e2, T e3, T e4, T e5) {
return ImmutableList.of(e1, e2, e3, e4, e5);
}
}
}

View File

@@ -1,12 +1,14 @@
package tech.picnic.errorprone.refastertemplates;
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.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -14,7 +16,6 @@ import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
@@ -40,41 +41,6 @@ final class ImmutableMapTemplates {
}
}
/** Prefer {@link ImmutableMap#of()} over more contrived alternatives. */
static final class EmptyImmutableMap<K, V> {
@BeforeTemplate
ImmutableMap<K, V> before() {
return ImmutableMap.<K, V>builder().build();
}
@AfterTemplate
ImmutableMap<K, V> after() {
return ImmutableMap.of();
}
}
/**
* Prefer {@link ImmutableMap#of(Object, Object)} over more contrived alternatives and
* alternatives that don't communicate the immutability of the resulting map at the type level..
*/
// XXX: One can define variants for more than one key-value pair, but at some point the builder
// actually produces nicer code. So it's not clear we should add Refaster templates for those
// variants.
// XXX: Note that the `singletonMap` rewrite rule is incorrect for nullable elements.
static final class PairToImmutableMap<K, V> {
@BeforeTemplate
Map<K, V> before(K key, V value) {
return Refaster.anyOf(
ImmutableMap.<K, V>builder().put(key, value).build(),
Collections.singletonMap(key, value));
}
@AfterTemplate
ImmutableMap<K, V> after(K key, V value) {
return ImmutableMap.of(key, value);
}
}
/** Prefer {@link ImmutableMap#of(Object, Object)} over more contrived alternatives. */
static final class EntryToImmutableMap<K, V> {
@BeforeTemplate
@@ -178,7 +144,7 @@ final class ImmutableMapTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ImmutableMap<K, V> after(Stream<E> stream) {
return stream.collect(toImmutableMap(e -> keyFunction(e), e -> valueFunction(e)));
}
@@ -226,7 +192,7 @@ final class ImmutableMapTemplates {
// XXX: Instead of `Map.Entry::getKey` we could also match `e -> e.getKey()`. But for some
// reason Refaster doesn't handle that case. This doesn't matter if we roll out use of
// `MethodReferenceUsageCheck`. Same observation applies to a lot of other Refaster checks.
// `MethodReferenceUsage`. Same observation applies to a lot of other Refaster checks.
@BeforeTemplate
@SuppressWarnings("NullAway")
ImmutableMap<K, V2> before(Map<K, V1> map) {
@@ -242,16 +208,108 @@ final class ImmutableMapTemplates {
}
}
/** Don't unnecessarily copy an {@link ImmutableMap}. */
static final class ImmutableMapCopyOfImmutableMap<K, V> {
/**
* Prefer {@link ImmutableMap#of()} over more contrived alternatives or alternatives that don't
* communicate the immutability of the resulting map at the type level.
*/
static final class ImmutableMapOf<K, V> {
@BeforeTemplate
ImmutableMap<K, V> before(ImmutableMap<K, V> map) {
return ImmutableMap.copyOf(map);
Map<K, V> before() {
return Refaster.anyOf(ImmutableMap.<K, V>builder().build(), emptyMap(), Map.of());
}
@AfterTemplate
ImmutableMap<K, V> after(ImmutableMap<K, V> map) {
return map;
ImmutableMap<K, V> after() {
return ImmutableMap.of();
}
}
/**
* Prefer {@link ImmutableMap#of(Object, Object)} over more contrived alternatives or alternatives
* that don't communicate the immutability of the resulting map at the type level.
*/
// XXX: Note that the replacement of `Collections#singletonMap` is incorrect for nullable
// elements.
static final class ImmutableMapOf1<K, V> {
@BeforeTemplate
Map<K, V> before(K k1, V v1) {
return Refaster.anyOf(
ImmutableMap.<K, V>builder().put(k1, v1).build(), singletonMap(k1, v1), Map.of(k1, v1));
}
@AfterTemplate
ImmutableMap<K, V> after(K k1, V v1) {
return ImmutableMap.of(k1, v1);
}
}
/**
* Prefer {@link ImmutableMap#of(Object, Object, Object, Object)} over alternatives that don't
* communicate the immutability of the resulting map at the type level.
*/
// XXX: Also rewrite the `ImmutableMap.builder()` variant?
static final class ImmutableMapOf2<K, V> {
@BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2) {
return Map.of(k1, v1, k2, v2);
}
@AfterTemplate
ImmutableMap<K, V> after(K k1, V v1, K k2, V v2) {
return ImmutableMap.of(k1, v1, k2, v2);
}
}
/**
* Prefer {@link ImmutableMap#of(Object, Object, Object, Object, Object, Object)} over
* alternatives that don't communicate the immutability of the resulting map at the type level.
*/
// XXX: Also rewrite the `ImmutableMap.builder()` variant?
static final class ImmutableMapOf3<K, V> {
@BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3) {
return Map.of(k1, v1, k2, v2, k3, v3);
}
@AfterTemplate
ImmutableMap<K, V> after(K k1, V v1, K k2, V v2, K k3, V v3) {
return ImmutableMap.of(k1, v1, k2, v2, k3, v3);
}
}
/**
* Prefer {@link ImmutableMap#of(Object, Object, Object, Object, Object, Object, Object, Object)}
* over alternatives that don't communicate the immutability of the resulting map at the type
* level.
*/
// XXX: Also rewrite the `ImmutableMap.builder()` variant?
static final class ImmutableMapOf4<K, V> {
@BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
return Map.of(k1, v1, k2, v2, k3, v3, k4, v4);
}
@AfterTemplate
ImmutableMap<K, V> after(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
return ImmutableMap.of(k1, v1, k2, v2, k3, v3, k4, v4);
}
}
/**
* Prefer {@link ImmutableMap#of(Object, Object, Object, Object, Object, Object, Object, Object,
* Object, Object)} over alternatives that don't communicate the immutability of the resulting map
* at the type level.
*/
// XXX: Also rewrite the `ImmutableMap.builder()` variant?
static final class ImmutableMapOf5<K, V> {
@BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
return Map.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
}
@AfterTemplate
ImmutableMap<K, V> after(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
return ImmutableMap.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
}
}

View File

@@ -1,12 +1,10 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.common.collect.ImmutableMultiset.toImmutableMultiset;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -90,28 +88,13 @@ final class ImmutableMultisetTemplates {
static final class StreamToImmutableMultiset<T> {
@BeforeTemplate
ImmutableMultiset<T> before(Stream<T> stream) {
return Refaster.anyOf(
ImmutableMultiset.copyOf(stream.iterator()),
stream.collect(collectingAndThen(toList(), ImmutableMultiset::copyOf)));
return ImmutableMultiset.copyOf(stream.iterator());
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ImmutableMultiset<T> after(Stream<T> stream) {
return stream.collect(toImmutableMultiset());
}
}
/** Don't unnecessarily copy an {@link ImmutableMultiset}. */
static final class ImmutableMultisetCopyOfImmutableMultiset<T> {
@BeforeTemplate
ImmutableMultiset<T> before(ImmutableMultiset<T> multiset) {
return ImmutableMultiset.copyOf(multiset);
}
@AfterTemplate
ImmutableMultiset<T> after(ImmutableMultiset<T> multiset) {
return multiset;
}
}
}

View File

@@ -2,6 +2,7 @@ package tech.picnic.errorprone.refastertemplates;
import static com.google.common.collect.ImmutableSetMultimap.flatteningToImmutableSetMultimap;
import static com.google.common.collect.ImmutableSetMultimap.toImmutableSetMultimap;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ListMultimap;
@@ -10,7 +11,6 @@ import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.SortedSetMultimap;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -138,7 +138,7 @@ final class ImmutableSetMultimapTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ImmutableSetMultimap<K, V> after(Stream<E> stream) {
return stream.collect(toImmutableSetMultimap(e -> keyFunction(e), e -> valueFunction(e)));
}
@@ -162,7 +162,7 @@ final class ImmutableSetMultimapTemplates {
@AfterTemplate
ImmutableSetMultimap<K, V2> after(Multimap<K, V1> multimap) {
return ImmutableSetMultimap.copyOf(
Multimaps.transformValues(multimap, v -> valueTransformation(v)));
Multimaps.transformValues(multimap, e -> valueTransformation(e)));
}
}
@@ -215,17 +215,4 @@ final class ImmutableSetMultimapTemplates {
return ImmutableSetMultimap.copyOf(Multimaps.transformValues(multimap, transformation));
}
}
/** Don't unnecessarily copy an {@link ImmutableSetMultimap}. */
static final class ImmutableSetMultimapCopyOfImmutableSetMultimap<K, V> {
@BeforeTemplate
ImmutableSetMultimap<K, V> before(ImmutableSetMultimap<K, V> multimap) {
return ImmutableSetMultimap.copyOf(multimap);
}
@AfterTemplate
ImmutableSetMultimap<K, V> after(ImmutableSetMultimap<K, V> multimap) {
return multimap;
}
}
}

View File

@@ -1,21 +1,19 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Collections.emptySet;
import static java.util.Collections.singleton;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets.SetView;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.ImportPolicy;
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 java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import java.util.stream.Stream;
@@ -39,37 +37,6 @@ final class ImmutableSetTemplates {
}
}
/** Prefer {@link ImmutableSet#of()} over more contrived alternatives. */
static final class EmptyImmutableSet<T> {
@BeforeTemplate
ImmutableSet<T> before() {
return Refaster.anyOf(
ImmutableSet.<T>builder().build(), Stream.<T>empty().collect(toImmutableSet()));
}
@AfterTemplate
ImmutableSet<T> after() {
return ImmutableSet.of();
}
}
/**
* Prefer {@link ImmutableSet#of(Object)} over alternatives that don't communicate the
* immutability of the resulting set at the type level.
*/
// XXX: Note that this rewrite rule is incorrect for nullable elements.
static final class SingletonImmutableSet<T> {
@BeforeTemplate
Set<T> before(T element) {
return Collections.singleton(element);
}
@AfterTemplate
ImmutableSet<T> after(T element) {
return ImmutableSet.of(element);
}
}
/** Prefer {@link ImmutableSet#copyOf(Iterable)} and variants over more contrived alternatives. */
static final class IterableToImmutableSet<T> {
@BeforeTemplate
@@ -105,40 +72,20 @@ final class ImmutableSetTemplates {
}
/** Prefer {@link ImmutableSet#toImmutableSet()} over less idiomatic alternatives. */
// XXX: Once the code base has been sufficiently cleaned up, we might want to also rewrite
// `Collectors.toSet(`), with the caveat that it allows mutation (though this cannot be relied
// upon) as well as nulls. Another option is to explicitly rewrite those variants to
// `Collectors.toSet(HashSet::new)`.
static final class StreamToImmutableSet<T> {
@BeforeTemplate
ImmutableSet<T> before(Stream<T> stream) {
return Refaster.anyOf(
ImmutableSet.copyOf(stream.iterator()),
stream.distinct().collect(toImmutableSet()),
stream.collect(collectingAndThen(toList(), ImmutableSet::copyOf)),
stream.collect(collectingAndThen(toSet(), ImmutableSet::copyOf)));
ImmutableSet.copyOf(stream.iterator()), stream.distinct().collect(toImmutableSet()));
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ImmutableSet<T> after(Stream<T> stream) {
return stream.collect(toImmutableSet());
}
}
/** Don't unnecessarily copy an {@link ImmutableSet}. */
static final class ImmutableSetCopyOfImmutableSet<T> {
@BeforeTemplate
ImmutableSet<T> before(ImmutableSet<T> set) {
return ImmutableSet.copyOf(set);
}
@AfterTemplate
ImmutableSet<T> after(ImmutableSet<T> set) {
return set;
}
}
/** Prefer {@link SetView#immutableCopy()} over the more verbose alternative. */
static final class ImmutableSetCopyOfSetView<T> {
@BeforeTemplate
@@ -151,4 +98,115 @@ final class ImmutableSetTemplates {
return set.immutableCopy();
}
}
/**
* Prefer {@link ImmutableSet#of()} over more contrived alternatives or alternatives that don't
* communicate the immutability of the resulting set at the type level.
*/
// XXX: The `Stream` variant may be too contrived to warrant inclusion. Review its usage if/when
// this and similar Refaster templates are replaced with an Error Prone check.
static final class ImmutableSetOf<T> {
@BeforeTemplate
Set<T> before() {
return Refaster.anyOf(
ImmutableSet.<T>builder().build(),
Stream.<T>empty().collect(toImmutableSet()),
emptySet(),
Set.of());
}
@AfterTemplate
ImmutableSet<T> after() {
return ImmutableSet.of();
}
}
/**
* Prefer {@link ImmutableSet#of(Object)} over more contrived alternatives or alternatives that
* don't communicate the immutability of the resulting set at the type level.
*/
// XXX: Note that the replacement of `Collections#singleton` is incorrect for nullable elements.
static final class ImmutableSetOf1<T> {
@BeforeTemplate
Set<T> before(T e1) {
return Refaster.anyOf(ImmutableSet.<T>builder().add(e1).build(), singleton(e1), Set.of(e1));
}
@AfterTemplate
ImmutableSet<T> after(T e1) {
return ImmutableSet.of(e1);
}
}
/**
* Prefer {@link ImmutableSet#of(Object, Object)} over alternatives that don't communicate the
* immutability of the resulting set at the type level.
*/
// XXX: Consider writing an Error Prone check which also flags straightforward
// `ImmutableSet.builder()` usages.
static final class ImmutableSetOf2<T> {
@BeforeTemplate
Set<T> before(T e1, T e2) {
return Set.of(e1, e2);
}
@AfterTemplate
ImmutableSet<T> after(T e1, T e2) {
return ImmutableSet.of(e1, e2);
}
}
/**
* Prefer {@link ImmutableSet#of(Object, Object, Object)} over alternatives that don't communicate
* the immutability of the resulting set at the type level.
*/
// XXX: Consider writing an Error Prone check which also flags straightforward
// `ImmutableSet.builder()` usages.
static final class ImmutableSetOf3<T> {
@BeforeTemplate
Set<T> before(T e1, T e2, T e3) {
return Set.of(e1, e2, e3);
}
@AfterTemplate
ImmutableSet<T> after(T e1, T e2, T e3) {
return ImmutableSet.of(e1, e2, e3);
}
}
/**
* Prefer {@link ImmutableSet#of(Object, Object, Object, Object)} over alternatives that don't
* communicate the immutability of the resulting set at the type level.
*/
// XXX: Consider writing an Error Prone check which also flags straightforward
// `ImmutableSet.builder()` usages.
static final class ImmutableSetOf4<T> {
@BeforeTemplate
Set<T> before(T e1, T e2, T e3, T e4) {
return Set.of(e1, e2, e3, e4);
}
@AfterTemplate
ImmutableSet<T> after(T e1, T e2, T e3, T e4) {
return ImmutableSet.of(e1, e2, e3, e4);
}
}
/**
* Prefer {@link ImmutableSet#of(Object, Object, Object, Object, Object)} over alternatives that
* don't communicate the immutability of the resulting set at the type level.
*/
// XXX: Consider writing an Error Prone check which also flags straightforward
// `ImmutableSet.builder()` usages.
static final class ImmutableSetOf5<T> {
@BeforeTemplate
Set<T> before(T e1, T e2, T e3, T e4, T e5) {
return Set.of(e1, e2, e3, e4, e5);
}
@AfterTemplate
ImmutableSet<T> after(T e1, T e2, T e3, T e4, T e5) {
return ImmutableSet.of(e1, e2, e3, e4, e5);
}
}
}

View File

@@ -1,14 +1,11 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.common.collect.ImmutableSortedMultiset.toImmutableSortedMultiset;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Comparator.naturalOrder;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSortedMultiset;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -93,14 +90,14 @@ final class ImmutableSortedMultisetTemplates {
// `reverseOrder`.) Worth the hassle?
static final class IterableToImmutableSortedMultiset<T extends Comparable<? super T>> {
@BeforeTemplate
ImmutableMultiset<T> before(T[] iterable) {
ImmutableSortedMultiset<T> before(T[] iterable) {
return Refaster.anyOf(
ImmutableSortedMultiset.<T>naturalOrder().add(iterable).build(),
Arrays.stream(iterable).collect(toImmutableSortedMultiset(naturalOrder())));
}
@BeforeTemplate
ImmutableMultiset<T> before(Iterator<T> iterable) {
ImmutableSortedMultiset<T> before(Iterator<T> iterable) {
return Refaster.anyOf(
ImmutableSortedMultiset.copyOf(naturalOrder(), iterable),
ImmutableSortedMultiset.<T>naturalOrder().addAll(iterable).build(),
@@ -108,7 +105,7 @@ final class ImmutableSortedMultisetTemplates {
}
@BeforeTemplate
ImmutableMultiset<T> before(Iterable<T> iterable) {
ImmutableSortedMultiset<T> before(Iterable<T> iterable) {
return Refaster.anyOf(
ImmutableSortedMultiset.copyOf(naturalOrder(), iterable),
ImmutableSortedMultiset.<T>naturalOrder().addAll(iterable).build(),
@@ -134,13 +131,11 @@ final class ImmutableSortedMultisetTemplates {
static final class StreamToImmutableSortedMultiset<T extends Comparable<? super T>> {
@BeforeTemplate
ImmutableSortedMultiset<T> before(Stream<T> stream) {
return Refaster.anyOf(
ImmutableSortedMultiset.copyOf(stream.iterator()),
stream.collect(collectingAndThen(toList(), ImmutableSortedMultiset::copyOf)));
return ImmutableSortedMultiset.copyOf(stream.iterator());
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ImmutableSortedMultiset<T> after(Stream<T> stream) {
return stream.collect(toImmutableSortedMultiset(naturalOrder()));
}

View File

@@ -1,14 +1,11 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Comparator.naturalOrder;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -91,14 +88,14 @@ final class ImmutableSortedSetTemplates {
// `reverseOrder`.) Worth the hassle?
static final class IterableToImmutableSortedSet<T extends Comparable<? super T>> {
@BeforeTemplate
ImmutableSet<T> before(T[] iterable) {
ImmutableSortedSet<T> before(T[] iterable) {
return Refaster.anyOf(
ImmutableSortedSet.<T>naturalOrder().add(iterable).build(),
Arrays.stream(iterable).collect(toImmutableSortedSet(naturalOrder())));
}
@BeforeTemplate
ImmutableSet<T> before(Iterator<T> iterable) {
ImmutableSortedSet<T> before(Iterator<T> iterable) {
return Refaster.anyOf(
ImmutableSortedSet.copyOf(naturalOrder(), iterable),
ImmutableSortedSet.<T>naturalOrder().addAll(iterable).build(),
@@ -106,7 +103,7 @@ final class ImmutableSortedSetTemplates {
}
@BeforeTemplate
ImmutableSet<T> before(Iterable<T> iterable) {
ImmutableSortedSet<T> before(Iterable<T> iterable) {
return Refaster.anyOf(
ImmutableSortedSet.copyOf(naturalOrder(), iterable),
ImmutableSortedSet.<T>naturalOrder().addAll(iterable).build(),
@@ -134,13 +131,11 @@ final class ImmutableSortedSetTemplates {
static final class StreamToImmutableSortedSet<T extends Comparable<? super T>> {
@BeforeTemplate
ImmutableSortedSet<T> before(Stream<T> stream) {
return Refaster.anyOf(
ImmutableSortedSet.copyOf(stream.iterator()),
stream.collect(collectingAndThen(toList(), ImmutableSortedSet::copyOf)));
return ImmutableSortedSet.copyOf(stream.iterator());
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ImmutableSortedSet<T> after(Stream<T> stream) {
return stream.collect(toImmutableSortedSet(naturalOrder()));
}

View File

@@ -1,8 +1,8 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Repeated;
@@ -21,7 +21,7 @@ final class JUnitTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Arguments after(@Repeated T objects) {
return arguments(objects);
}

View File

@@ -1,12 +1,12 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Comparator.comparing;
import static java.util.Comparator.naturalOrder;
import static java.util.Map.Entry.comparingByKey;
import static java.util.Map.Entry.comparingByValue;
import com.google.common.collect.Maps;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -51,7 +51,7 @@ final class MapEntryTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Comparator<Map.Entry<K, V>> after() {
return comparingByKey();
}
@@ -65,7 +65,7 @@ final class MapEntryTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Comparator<Map.Entry<K, V>> after(Comparator<? super K> cmp) {
return comparingByKey(cmp);
}
@@ -80,7 +80,7 @@ final class MapEntryTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Comparator<Map.Entry<K, V>> after() {
return comparingByValue();
}
@@ -94,7 +94,7 @@ final class MapEntryTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Comparator<Map.Entry<K, V>> after(Comparator<? super V> cmp) {
return comparingByValue(cmp);
}

View File

@@ -1,10 +1,10 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
@@ -26,7 +26,7 @@ final class MockitoTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
VerificationMode after() {
return never();
}
@@ -43,7 +43,7 @@ final class MockitoTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
T after(T mock) {
return verify(mock);
}

View File

@@ -1,9 +1,9 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Objects.requireNonNullElse;
import com.google.common.base.MoreObjects;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
@@ -24,7 +24,7 @@ final class NullTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
T after(T first, T second) {
return requireNonNullElse(first, second);
}

View File

@@ -1,7 +1,8 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -14,6 +15,7 @@ import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.annotation.Nullable;
/** Refaster templates related to expressions dealing with {@link Optional}s. */
final class OptionalTemplates {
@@ -24,7 +26,7 @@ final class OptionalTemplates {
// parentheses around the null check, but that's currently not the case. Try to fix that.
@BeforeTemplate
@SuppressWarnings("TernaryOperatorOptionalNegativeFiltering" /* Special case. */)
Optional<T> before(T object) {
Optional<T> before(@Nullable T object) {
return object == null ? Optional.empty() : Optional.of(object);
}
@@ -91,19 +93,6 @@ final class OptionalTemplates {
}
}
/** Prefer {@link Optional#stream()} over the Guava alternative. */
static final class OptionalToStream<T> {
@BeforeTemplate
Stream<T> before(Optional<T> optional) {
return Streams.stream(optional);
}
@AfterTemplate
Stream<T> after(Optional<T> optional) {
return optional.stream();
}
}
/**
* Don't use the ternary operator to extract the first element of a possibly-empty {@link
* Iterator} as an {@link Optional}.
@@ -115,7 +104,7 @@ final class OptionalTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Optional<T> after(Iterator<T> it) {
return Streams.stream(it).findFirst();
}
@@ -124,7 +113,7 @@ final class OptionalTemplates {
/** 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 RefasterCheck should test `compilesWithFix`?
// Maybe our `Refaster` checker should test `compilesWithFix`?
abstract static class TernaryOperatorOptionalPositiveFiltering<T> {
@Placeholder
abstract boolean test(T value);
@@ -144,7 +133,7 @@ final class OptionalTemplates {
/** 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 RefasterCheck should test `compilesWithFix`?
// Maybe our `Refaster` checker should test `compilesWithFix`?
abstract static class TernaryOperatorOptionalNegativeFiltering<T> {
@Placeholder
abstract boolean test(T value);
@@ -177,6 +166,11 @@ final class OptionalTemplates {
}
}
/**
* Prefer {@link Optional#map} over a {@link Optional#flatMap} which wraps the result of a
* transformation in an {@link Optional}; the former operation transforms {@code null} to {@link
* Optional#empty()}.
*/
abstract static class MapToNullable<T, S> {
@Placeholder
abstract S toNullableFunction(@MayOptionallyUse T element);

View File

@@ -1,9 +1,10 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.common.collect.MoreCollectors.toOptional;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.MoreCollectors;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -142,6 +143,35 @@ final class ReactorTemplates {
}
}
/** Prefer {@link Flux#concatMap(Function)} over more contrived alternatives. */
static final class FluxConcatMap<T, S> {
@BeforeTemplate
Flux<S> before(Flux<T> flux, Function<? super T, ? extends Publisher<? extends S>> function) {
return Refaster.anyOf(flux.flatMap(function, 1), flux.flatMapSequential(function, 1));
}
@AfterTemplate
Flux<S> after(Flux<T> flux, Function<? super T, ? extends Publisher<? extends S>> function) {
return flux.concatMap(function);
}
}
/**
* 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> {
@BeforeTemplate
Flux<S> before(Flux<T> flux, Function<? super T, ? extends Iterable<? extends S>> function) {
return flux.flatMapIterable(function);
}
@AfterTemplate
Flux<S> after(Flux<T> flux, Function<? super T, ? extends Iterable<? extends S>> function) {
return flux.concatMapIterable(function);
}
}
/**
* Don't use {@link Mono#flatMapMany(Function)} to implicitly convert a {@link Mono} to a {@link
* Flux}.
@@ -161,6 +191,19 @@ final class ReactorTemplates {
}
}
/** Prefer {@link Mono#flux()}} over more contrived alternatives. */
static final class MonoFlux<T> {
@BeforeTemplate
Flux<T> before(Mono<T> mono) {
return Flux.concat(mono);
}
@AfterTemplate
Flux<T> after(Mono<T> mono) {
return mono.flux();
}
}
/**
* Prefer a collection using {@link MoreCollectors#toOptional()} over more contrived alternatives.
*/
@@ -175,12 +218,38 @@ final class ReactorTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Mono<Optional<T>> after(Mono<T> mono) {
return mono.flux().collect(toOptional());
}
}
/** Prefer {@link Mono#cast(Class)} over {@link Mono#map(Function)} with a cast. */
static final class MonoCast<T, S> {
@BeforeTemplate
Mono<S> before(Mono<T> mono) {
return mono.map(Refaster.<S>clazz()::cast);
}
@AfterTemplate
Mono<S> after(Mono<T> mono) {
return mono.cast(Refaster.<S>clazz());
}
}
/** Prefer {@link Flux#cast(Class)} over {@link Flux#map(Function)} with a cast. */
static final class FluxCast<T, S> {
@BeforeTemplate
Flux<S> before(Flux<T> flux) {
return flux.map(Refaster.<S>clazz()::cast);
}
@AfterTemplate
Flux<S> after(Flux<T> flux) {
return flux.cast(Refaster.<S>clazz());
}
}
/** Prefer {@link PublisherProbe#empty()}} over more verbose alternatives. */
static final class PublisherProbeEmpty<T> {
@BeforeTemplate
@@ -194,6 +263,32 @@ final class ReactorTemplates {
}
}
/** Prefer {@link Mono#as(Function)} when creating a {@link StepVerifier}. */
static final class StepVerifierFromMono<T> {
@BeforeTemplate
StepVerifier.FirstStep<? extends T> before(Mono<T> mono) {
return StepVerifier.create(mono);
}
@AfterTemplate
StepVerifier.FirstStep<? extends T> after(Mono<T> mono) {
return mono.as(StepVerifier::create);
}
}
/** Prefer {@link Flux#as(Function)} when creating a {@link StepVerifier}. */
static final class StepVerifierFromFlux<T> {
@BeforeTemplate
StepVerifier.FirstStep<? extends T> before(Flux<T> flux) {
return StepVerifier.create(flux);
}
@AfterTemplate
StepVerifier.FirstStep<? extends T> after(Flux<T> flux) {
return flux.as(StepVerifier::create);
}
}
/** Don't unnecessarily call {@link StepVerifier.Step#expectNext(Object[])}. */
static final class StepVerifierStepExpectNextEmpty<T> {
@BeforeTemplate
@@ -252,7 +347,9 @@ final class ReactorTemplates {
static final class StepVerifierLastStepVerifyErrorClass<T extends Throwable> {
@BeforeTemplate
Duration before(StepVerifier.LastStep step, Class<T> clazz) {
return step.expectError(clazz).verify();
return Refaster.anyOf(
step.expectError(clazz).verify(),
step.verifyErrorSatisfies(t -> assertThat(t).isInstanceOf(clazz)));
}
@AfterTemplate

View File

@@ -18,19 +18,6 @@ import reactor.core.publisher.Mono;
final class RxJava2AdapterTemplates {
private RxJava2AdapterTemplates() {}
/** Remove double conversion of ... */
static final class FluxToFlowableToFlux<T> {
@BeforeTemplate
Flux<T> before(Flux<T> flux) {
return RxJava2Adapter.flowableToFlux(RxJava2Adapter.fluxToFlowable(flux));
}
@AfterTemplate
Flux<T> after(Flux<T> flux) {
return flux;
}
}
/** Use the fluent API style when using {@link RxJava2Adapter#completableToMono}. */
static final class CompletableToMono {
@BeforeTemplate
@@ -54,11 +41,9 @@ final class RxJava2AdapterTemplates {
@BeforeTemplate
Publisher<T> before(Flowable<T> flowable) {
return Refaster.anyOf(
Flux.from(flowable),
flowable.compose(Flux::from),
flowable.to(Flux::from),
flowable.as(Flux::from),
RxJava2Adapter.flowableToFlux(flowable),
flowable.compose(RxJava2Adapter::flowableToFlux),
flowable.to(RxJava2Adapter::flowableToFlux));
}
@@ -80,7 +65,6 @@ final class RxJava2AdapterTemplates {
Flowable.fromPublisher(flux),
flux.transform(Flowable::fromPublisher),
flux.as(Flowable::fromPublisher),
RxJava2Adapter.fluxToFlowable(flux),
flux.transform(RxJava2Adapter::fluxToFlowable));
}
@@ -153,7 +137,6 @@ final class RxJava2AdapterTemplates {
Flowable.fromPublisher(mono),
mono.transform(Flowable::fromPublisher),
mono.as(Flowable::fromPublisher),
RxJava2Adapter.monoToFlowable(mono),
mono.transform(RxJava2Adapter::monoToFlowable));
}

View File

@@ -1,506 +0,0 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.ImportPolicy;
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 io.reactivex.Completable;
import io.reactivex.CompletableSource;
import io.reactivex.Flowable;
import io.reactivex.Maybe;
import io.reactivex.MaybeSource;
import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Predicate;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
import org.reactivestreams.Publisher;
import reactor.adapter.rxjava.RxJava2Adapter;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import tech.picnic.errorprone.migration.util.RxJavaReactorMigrationUtil;
/** The Refaster templates for the migration of the RxJava Completable type to Reactor */
final class RxJavaCompletableToReactorTemplates {
private RxJavaCompletableToReactorTemplates() {}
static final class CompletableAmb {
@BeforeTemplate
Completable before(Iterable<? extends Completable> sources) {
return Completable.amb(sources);
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.IMPORT_CLASS_DIRECTLY)
Completable after(Iterable<? extends Completable> sources) {
return RxJava2Adapter.monoToCompletable(
Mono.firstWithSignal(
Streams.stream(sources)
.map(RxJava2Adapter::completableToMono)
.collect(toImmutableList())));
}
}
// XXX: public static Completable ambArray(CompletableSource[])
static final class CompletableComplete {
@BeforeTemplate
Completable before() {
return Completable.complete();
}
@AfterTemplate
Completable after() {
return RxJava2Adapter.monoToCompletable(Mono.empty());
}
}
// XXX: public static Completable concat(Iterable)
// XXX: public static Completable concat(Publisher)
// XXX: public static Completable concat(Publisher,int)
// XXX: public static Completable concatArray(CompletableSource[])
// XXX: public static Completable create(CompletableOnSubscribe)
// XXX: The types of the @Before and @After are not matching
static final class CompletableDefer {
@BeforeTemplate
Completable before(Callable<? extends CompletableSource> supplier) {
return Completable.defer(supplier);
}
@AfterTemplate
Completable after(Callable<? extends Completable> supplier) {
return RxJava2Adapter.monoToCompletable(
Mono.defer(
() ->
RxJava2Adapter.completableToMono(
RxJavaReactorMigrationUtil.callableAsSupplier(supplier).get())));
}
}
static final class CompletableErrorCallable {
@BeforeTemplate
Completable before(Callable<? extends Throwable> throwable) {
return Completable.error(throwable);
}
@AfterTemplate
Completable after(Supplier<? extends Throwable> throwable) {
return RxJava2Adapter.monoToCompletable(Mono.error(throwable));
}
}
static final class CompletableErrorThrowable {
@BeforeTemplate
Completable before(Throwable throwable) {
return Completable.error(throwable);
}
@AfterTemplate
Completable after(Throwable throwable) {
return RxJava2Adapter.monoToCompletable(Mono.error(throwable));
}
}
static final class CompletableFromAction {
@BeforeTemplate
Completable before(Action action) {
return Completable.fromAction(action);
}
@AfterTemplate
Completable after(Action action) {
return RxJava2Adapter.monoToCompletable(
Mono.fromRunnable(RxJavaReactorMigrationUtil.toRunnable(action)));
}
}
static final class CompletableFromCallable {
@BeforeTemplate
Completable before(Callable<?> supplier) {
return Completable.fromCallable(supplier);
}
@AfterTemplate
Completable after(Callable<?> supplier) {
return RxJava2Adapter.monoToCompletable(Mono.fromCallable(supplier));
}
}
// XXX: public static Completable fromFuture(Future)
// XXX: public static Completable fromMaybe(MaybeSource)
// XXX: public static Completable fromObservable(ObservableSource)
static final class CompletableFromPublisher<T> {
@BeforeTemplate
Completable before(Publisher<T> source) {
return Completable.fromPublisher(source);
}
@AfterTemplate
Completable after(Publisher<T> source) {
return RxJava2Adapter.monoToCompletable(Mono.from(source));
}
}
static final class CompletableFromRunnable {
@BeforeTemplate
Completable before(Runnable runnable) {
return Completable.fromRunnable(runnable);
}
@AfterTemplate
Completable after(Runnable runnable) {
return RxJava2Adapter.monoToCompletable(Mono.fromRunnable(runnable));
}
}
// XXX: public static Completable fromSingle(SingleSource)
// XXX: public static Completable merge(Iterable)
// XXX: public static Completable merge(Publisher)
// XXX: public static Completable merge(Publisher,int)
// XXX: public static Completable mergeArray(CompletableSource[])
// XXX: public static Completable mergeArrayDelayError(CompletableSource[])
// XXX: public static Completable mergeDelayError(Iterable)
// XXX: public static Completable mergeDelayError(Publisher)
// XXX: public static Completable mergeDelayError(Publisher,int)
// XXX: public static Completable never()
// XXX: public static Completable timer(long,TimeUnit)
// XXX: public static Completable timer(long,TimeUnit,Scheduler)
// XXX: public static Completable unsafeCreate(CompletableSource)
// XXX: public static Completable using(Callable,Function,Consumer)
// XXX: public static Completable using(Callable,Function,Consumer,boolean)
static final class CompletableWrap {
@BeforeTemplate
Completable before(Completable source) {
return Completable.wrap(source);
}
@AfterTemplate
Completable after(Completable source) {
return source;
}
}
// XXX: public final Completable ambWith(CompletableSource)
static final class CompletableAndThenCompletable {
@BeforeTemplate
Completable before(Completable completable, CompletableSource source) {
return completable.andThen(source);
}
@AfterTemplate
Completable after(Completable completable, CompletableSource source) {
return RxJava2Adapter.monoToCompletable(
RxJava2Adapter.completableToMono(completable)
.then(RxJava2Adapter.completableToMono(Completable.wrap(source))));
}
}
static final class CompletableAndThenMaybe<T> {
@BeforeTemplate
Maybe<T> before(Completable completable, MaybeSource<T> source) {
return completable.andThen(source);
}
@AfterTemplate
Maybe<T> after(Completable completable, MaybeSource<T> source) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.completableToMono(completable)
.then(RxJava2Adapter.maybeToMono(Maybe.wrap(source))));
}
}
// XXX: public final Observable andThen(ObservableSource)
static final class CompletableAndThenPublisher<T> {
@BeforeTemplate
Flowable<T> before(Completable completable, Publisher<T> source) {
return completable.andThen(source);
}
@AfterTemplate
Flowable<T> after(Completable completable, Publisher<T> source) {
return RxJava2Adapter.fluxToFlowable(
RxJava2Adapter.completableToMono(completable).thenMany(source));
}
}
static final class CompletableAndThenSingle<T> {
@BeforeTemplate
Single<T> before(Completable completable, SingleSource<T> source) {
return completable.andThen(source);
}
@AfterTemplate
Single<T> after(Completable completable, SingleSource<T> source) {
return RxJava2Adapter.monoToSingle(
RxJava2Adapter.completableToMono(completable)
.then(RxJava2Adapter.singleToMono(Single.wrap(source))));
}
}
// XXX: public final Object as(CompletableConverter)
static final class CompletableBlockingAwait {
@BeforeTemplate
void before(Completable completable) {
completable.blockingAwait();
}
@AfterTemplate
void after(Completable completable) {
RxJava2Adapter.completableToMono(completable).block();
}
}
// XXX: public final boolean blockingAwait(long,TimeUnit)
// XXX: public final Throwable blockingGet()
// XXX: public final Throwable blockingGet(long,TimeUnit)
// XXX: public final Completable cache()
// XXX: public final Completable compose(CompletableTransformer)
// XXX: public final Completable concatWith(CompletableSource)
// XXX: public final Completable delay(long,TimeUnit)
// XXX: public final Completable delay(long,TimeUnit,Scheduler)
// XXX: public final Completable delay(long,TimeUnit,Scheduler,boolean)
// XXX: public final Completable delaySubscription(long,TimeUnit)
// XXX: public final Completable delaySubscription(long,TimeUnit,Scheduler)
// XXX: public final Completable doAfterTerminate(Action)
// XXX: public final Completable doFinally(Action)
// XXX: public final Completable doOnComplete(Action)
// XXX: public final Completable doOnDispose(Action)
// XXX: public final Completable doOnError(Consumer)
// XXX: public final Completable doOnEvent(Consumer)
// XXX: public final Completable doOnSubscribe(Consumer)
static final class CompletableDoOnError {
@BeforeTemplate
Completable before(Completable completable, Consumer<? super Throwable> consumer) {
return completable.doOnError(consumer);
}
@AfterTemplate
Completable after(Completable completable, Consumer<? super Throwable> consumer) {
return RxJava2Adapter.monoToCompletable(
RxJava2Adapter.completableToMono(completable)
.doOnError(RxJavaReactorMigrationUtil.toJdkConsumer(consumer)));
}
}
// XXX: public final Completable doOnTerminate(Action)
// XXX: public final Completable hide()
// XXX: public final Completable lift(CompletableOperator)
// XXX: public final Single materialize()
// XXX: public final Completable mergeWith(CompletableSource)
// XXX: public final Completable observeOn(Scheduler)
// XXX: Verify whether this is the correct equivalent.
static final class CompletableOnErrorComplete {
Completable before(Completable completable) {
return completable.onErrorComplete();
}
Completable after(Completable completable) {
return RxJava2Adapter.monoToCompletable(
RxJava2Adapter.completableToMono(completable).onErrorStop());
}
}
static final class CompletableOnErrorCompletePredicate {
Completable before(Completable completable, Predicate<? super Throwable> predicate) {
return completable.onErrorComplete(predicate);
}
Completable after(Completable completable, Predicate<? super Throwable> predicate) {
return RxJava2Adapter.monoToCompletable(
RxJava2Adapter.completableToMono(completable)
.onErrorResume(
RxJavaReactorMigrationUtil.toJdkPredicate(predicate), t -> Mono.empty()));
}
}
// XXX: public final Completable onErrorComplete(Predicate)
// XXX: public final Completable onErrorResumeNext(Function)
// XXX: public final Completable onTerminateDetach()
// XXX: public final Completable repeat()
// XXX: public final Completable repeat(long)
// XXX: public final Completable repeatUntil(BooleanSupplier)
// XXX: public final Completable repeatWhen(Function)
// XXX: public final Completable retry()
// XXX: public final Completable retry(BiPredicate)
// XXX: public final Completable retry(long)
// XXX: public final Completable retry(long,Predicate)
// XXX: public final Completable retry(Predicate)
// XXX: public final Completable retryWhen(Function)
// XXX: public final Completable startWith(CompletableSource)
// XXX: public final Observable startWith(Observable)
// XXX: public final Flowable startWith(Publisher)
// XXX: public final Disposable subscribe()
// XXX: public final Disposable subscribe(Action)
// XXX: public final Disposable subscribe(Action,Consumer)
// XXX: public final void subscribe(CompletableObserver)
// XXX: public final Completable subscribeOn(Scheduler)
// XXX: public final CompletableObserver subscribeWith(CompletableObserver)
// XXX: public final Completable takeUntil(CompletableSource)
// XXX: public final Completable timeout(long,TimeUnit)
// XXX: public final Completable timeout(long,TimeUnit,CompletableSource)
// XXX: public final Completable timeout(long,TimeUnit,Scheduler)
// XXX: public final Completable timeout(long,TimeUnit,Scheduler,CompletableSource)
// XXX: public final Object to(Function)
static final class CompletableToFlowable {
@BeforeTemplate
Flowable<Void> before(Completable completable) {
return completable.toFlowable();
}
@AfterTemplate
Flowable<Void> after(Completable completable) {
return RxJava2Adapter.fluxToFlowable(RxJava2Adapter.completableToMono(completable).flux());
}
}
// XXX: Requires investigation. Should not be Void...
static final class CompletableToMaybe {
@BeforeTemplate
Maybe<Void> before(Completable completable) {
return completable.toMaybe();
}
@AfterTemplate
Maybe<Void> after(Completable completable) {
return RxJava2Adapter.monoToMaybe(RxJava2Adapter.completableToMono(completable));
}
}
// XXX: public final Observable toObservable()
// XXX: public final Single toSingle(Callable)
// XXX: public final Single toSingleDefault(Object)
// XXX: public final Completable unsubscribeOn(Scheduler)
static final class CompletableTestAssertResult {
@BeforeTemplate
void before(Completable completable) throws InterruptedException {
Refaster.anyOf(
completable.test().await().assertResult(),
completable.test().assertResult(),
completable.test().await());
}
@AfterTemplate
void after(Completable completable) {
RxJava2Adapter.completableToMono(completable).as(StepVerifier::create).verifyComplete();
}
}
static final class CompletableTestAssertComplete {
@BeforeTemplate
void before(Completable completable) throws InterruptedException {
Refaster.anyOf(
completable.test().await().assertComplete(), completable.test().assertComplete());
}
@AfterTemplate
void after(Completable completable) {
RxJava2Adapter.completableToMono(completable).as(StepVerifier::create).verifyComplete();
}
}
static final class CompletableTestAssertErrorClass {
@BeforeTemplate
void before(Completable completable, Class<? extends Throwable> errorClass)
throws InterruptedException {
Refaster.anyOf(
completable.test().await().assertError(errorClass),
completable.test().assertError(errorClass));
}
@AfterTemplate
void after(Completable completable, Class<? extends Throwable> errorClass) {
RxJava2Adapter.completableToMono(completable)
.as(StepVerifier::create)
.verifyError(errorClass);
}
}
static final class CompletableTestAssertNoErrors {
@BeforeTemplate
void before(Completable completable) throws InterruptedException {
completable.test().await().assertNoErrors();
}
@AfterTemplate
void after(Completable completable) {
RxJava2Adapter.completableToMono(completable).as(StepVerifier::create).verifyComplete();
}
}
static final class CompletableTestAssertValueCount {
@BeforeTemplate
void before(Completable completable, int count) throws InterruptedException {
completable.test().await().assertValueCount(count);
}
@AfterTemplate
void after(Completable completable, int count) {
RxJava2Adapter.completableToMono(completable)
.as(StepVerifier::create)
.expectNextCount(count)
.verifyComplete();
}
}
static final class CompletableTestAssertFailure {
@BeforeTemplate
void before(Completable completable, Class<? extends Throwable> error)
throws InterruptedException {
completable.test().await().assertFailure(error);
}
@AfterTemplate
void after(Completable completable, Class<? extends Throwable> error) {
RxJava2Adapter.completableToMono(completable).as(StepVerifier::create).verifyError(error);
}
}
static final class CompletableTestAssertNoValues {
@BeforeTemplate
void before(Completable completable) throws InterruptedException {
completable.test().await().assertNoValues();
}
@AfterTemplate
void after(Completable completable) {
RxJava2Adapter.completableToMono(completable).as(StepVerifier::create).verifyComplete();
}
}
static final class CompletableTestAssertFailureAndMessage {
@BeforeTemplate
void before(Completable completable, Class<? extends Throwable> error, String message)
throws InterruptedException {
completable.test().await().assertFailureAndMessage(error, message);
}
@AfterTemplate
void after(Completable completable, Class<? extends Throwable> error, String message) {
RxJava2Adapter.completableToMono(completable)
.as(StepVerifier::create)
.expectErrorSatisfies(
t -> assertThat(t).isInstanceOf(error).hasMessageContaining(message))
.verify();
}
}
// XXX: public final TestObserver test(boolean)
}

View File

@@ -1,959 +0,0 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.Repeated;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import io.reactivex.Completable;
import io.reactivex.CompletableSource;
import io.reactivex.Flowable;
import io.reactivex.Maybe;
import io.reactivex.MaybeSource;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.BiFunction;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import org.reactivestreams.Publisher;
import reactor.adapter.rxjava.RxJava2Adapter;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import tech.picnic.errorprone.migration.util.RxJavaReactorMigrationUtil;
/** The Refaster templates for the migration of the RxJava Maybe type to Reactor */
final class RxJavaMaybeToReactorTemplates {
private RxJavaMaybeToReactorTemplates() {}
static final class MaybeAmb<T> {
@BeforeTemplate
Maybe<T> before(Iterable<? extends Maybe<? extends T>> iterable) {
return Maybe.amb(iterable);
}
@AfterTemplate
Maybe<T> after(Iterable<? extends Maybe<? extends T>> iterable) {
return RxJava2Adapter.monoToMaybe(
Mono.firstWithSignal(
Streams.stream(iterable)
.map(RxJava2Adapter::maybeToMono)
.collect(toImmutableList())));
}
}
// XXX: public static Maybe ambArray(MaybeSource... sources)
// XXX: public static Flowable concat(Iterable)
// XXX: public static Flowable concat(MaybeSource,MaybeSource)
// XXX: public static Flowable concat(MaybeSource,MaybeSource,MaybeSource)
// XXX: public static Flowable concat(MaybeSource,MaybeSource,MaybeSource,MaybeSource)
// XXX: public static Flowable concat(Publisher)
// XXX: public static Flowable concat(Publisher,int)
// XXX: How to make this conversion correct? Turned off test for now.
static final class MaybeConcatArray<T> {
@BeforeTemplate
Flowable<T> before(@Repeated Maybe<T> sources) {
return Maybe.concatArray(Refaster.asVarargs(sources));
}
@AfterTemplate
Flowable<T> after(@Repeated Maybe<T> sources) {
return RxJava2Adapter.fluxToFlowable(
Flux.concat(
Arrays.stream(Refaster.asVarargs(sources))
.map(RxJava2Adapter::maybeToMono)
.collect(toImmutableList())));
}
}
// XXX: public static Flowable concatArrayDelayError(MaybeSource[])
// XXX: public static Flowable concatArrayEager(MaybeSource[])
// XXX: public static Flowable concatDelayError(Iterable)
// XXX: public static Flowable concatDelayError(Publisher)
// XXX: public static Flowable concatEager(Iterable)
// XXX: public static Flowable concatEager(Publisher)
// XXX: public static Maybe create(MaybeOnSubscribe)
/// XXX: Add test
abstract static class MaybeDeferFirst<T> {
@Placeholder
abstract Maybe<T> maybeProducer();
@BeforeTemplate
Maybe<T> before() {
return Maybe.defer(() -> maybeProducer());
}
@AfterTemplate
Maybe<T> after() {
return RxJava2Adapter.monoToMaybe(
Mono.defer(() -> RxJava2Adapter.maybeToMono(maybeProducer())));
}
}
abstract static class MaybeDefer<T> {
@Placeholder
abstract Maybe<T> maybeProducer();
@BeforeTemplate
Mono<T> before() {
return Maybe.defer(() -> maybeProducer()).as(RxJava2Adapter::maybeToMono);
}
@AfterTemplate
Mono<T> after() {
return Mono.defer(() -> RxJava2Adapter.maybeToMono(maybeProducer()));
}
}
static final class MaybeEmpty<T> {
@BeforeTemplate
Maybe<T> before() {
return Maybe.empty();
}
@AfterTemplate
Maybe<T> after() {
return RxJava2Adapter.monoToMaybe(Mono.empty());
}
}
static final class MaybeErrorCallable<T> {
@BeforeTemplate
Maybe<T> before(Callable<? extends Throwable> throwable) {
return Maybe.error(throwable);
}
@AfterTemplate
Maybe<T> after(Callable<? extends Throwable> throwable) {
return RxJava2Adapter.monoToMaybe(
Mono.error(RxJavaReactorMigrationUtil.callableAsSupplier(throwable)));
}
}
static final class MaybeErrorThrowable<T> {
@BeforeTemplate
Maybe<T> before(Throwable throwable) {
return Maybe.error(throwable);
}
@AfterTemplate
Maybe<T> after(Throwable throwable) {
return RxJava2Adapter.monoToMaybe(Mono.error(throwable));
}
}
static final class MaybeFromAction<T> {
@BeforeTemplate
Maybe<T> before(Action action) {
return Maybe.fromAction(action);
}
@AfterTemplate
Maybe<T> after(Action action) {
return RxJava2Adapter.monoToMaybe(
Mono.fromRunnable(RxJavaReactorMigrationUtil.toRunnable(action)));
}
}
static final class MaybeFromCallable<T> {
@BeforeTemplate
Maybe<T> before(Callable<? extends T> callable) {
return Maybe.fromCallable(callable);
}
@AfterTemplate
Maybe<T> after(Callable<? extends T> callable) {
return RxJava2Adapter.monoToMaybe(
Mono.fromSupplier(RxJavaReactorMigrationUtil.callableAsSupplier(callable)));
}
}
// XXX: public static Maybe fromCompletable(CompletableSource)
// XXX: Also handle `Future`s that don't extend `CompletableFuture`.
static final class MaybeFromFuture<T> {
@BeforeTemplate
Maybe<T> before(CompletableFuture<? extends T> future) {
return Maybe.fromFuture(future);
}
@AfterTemplate
Maybe<T> after(CompletableFuture<? extends T> future) {
return RxJava2Adapter.monoToMaybe(Mono.fromFuture(future));
}
}
// XXX: public static Maybe fromFuture(Future,long,TimeUnit)
static final class MaybeFromRunnable<T> {
@BeforeTemplate
Maybe<T> before(Runnable runnable) {
return Maybe.fromRunnable(runnable);
}
@AfterTemplate
Maybe<T> after(Runnable runnable) {
return RxJava2Adapter.monoToMaybe(Mono.fromRunnable(runnable));
}
}
static final class MaybeFromSingle<T> {
@BeforeTemplate
Maybe<T> before(SingleSource<T> source) {
return Maybe.fromSingle(source);
}
@AfterTemplate
Maybe<T> after(SingleSource<T> source) {
return RxJava2Adapter.monoToMaybe(
Mono.from(RxJava2Adapter.singleToMono(Single.wrap(source))));
}
}
static final class MaybeJust<T> {
@BeforeTemplate
Maybe<T> before(T item) {
return Maybe.just(item);
}
@AfterTemplate
Maybe<T> after(T item) {
return RxJava2Adapter.monoToMaybe(Mono.just(item));
}
}
// XXX: public static Flowable merge(Iterable)
// XXX: public static Maybe merge(MaybeSource)
// XXX: public static Flowable merge(MaybeSource,MaybeSource)
// XXX: public static Flowable merge(MaybeSource,MaybeSource,MaybeSource)
// XXX: public static Flowable merge(MaybeSource,MaybeSource,MaybeSource,MaybeSource)
// XXX: public static Flowable merge(Publisher)
// XXX: public static Flowable merge(Publisher,int)
// XXX: public static Flowable mergeArray(MaybeSource[])
// XXX: public static Flowable mergeArrayDelayError(MaybeSource[])
// XXX: public static Flowable mergeDelayError(Iterable)
// XXX: public static Flowable mergeDelayError(MaybeSource,MaybeSource)
// XXX: public static Flowable mergeDelayError(MaybeSource,MaybeSource,MaybeSource)
// XXX: public static Flowable mergeDelayError(MaybeSource,MaybeSource,MaybeSource,MaybeSource)
// XXX: public static Flowable mergeDelayError(Publisher)
// XXX: public static Flowable mergeDelayError(Publisher,int)
// XXX: public static Maybe never()
// XXX: public static Single sequenceEqual(MaybeSource,MaybeSource)
// XXX: public static Single sequenceEqual(MaybeSource,MaybeSource,BiPredicate)
// XXX: public static Maybe timer(long,TimeUnit)
// XXX: public static Maybe timer(long,TimeUnit,Scheduler)
// XXX: public static Maybe unsafeCreate(MaybeSource)
// XXX: public static Maybe using(Callable,Function,Consumer)
// XXX: public static Maybe using(Callable,Function,Consumer,boolean)
static final class MaybeWrap<T> {
@BeforeTemplate
Maybe<T> before(Maybe<T> maybe) {
return Maybe.wrap(maybe);
}
@AfterTemplate
Maybe<T> after(Maybe<T> maybe) {
return maybe;
}
}
// XXX: public static Maybe zip(Iterable,Function)
// XXX: public static Maybe zip(MaybeSource,MaybeSource,BiFunction)
// XXX: public static Maybe zip(MaybeSource,MaybeSource,MaybeSource,Function3)
// XXX: public static Maybe zip(MaybeSource,MaybeSource,MaybeSource,MaybeSource,Function4)
// XXX: public static Maybe
// zip(MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,Function5)
// XXX: public static Maybe
// zip(MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,Function6)
// XXX: public static Maybe
// zip(MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,Function7)
// XXX: public static Maybe
// zip(MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,Function8)
// XXX: public static Maybe
// zip(MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,MaybeSource,Function9)
// XXX: public static Maybe zipArray(Function,MaybeSource[])
static final class MaybeAmbWith<T> {
@BeforeTemplate
Maybe<T> before(Maybe<T> maybe, Maybe<? extends T> otherMaybe) {
return maybe.ambWith(otherMaybe);
}
@AfterTemplate
Maybe<T> after(Maybe<T> maybe, Maybe<? extends T> otherMaybe) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.maybeToMono(maybe).or(RxJava2Adapter.maybeToMono(otherMaybe)));
}
}
// XXX: public final Object as(MaybeConverter)
static final class MaybeBlockingGet<T> {
@BeforeTemplate
Object before(Maybe<T> maybe) {
return maybe.blockingGet();
}
@AfterTemplate
Object after(Maybe<T> maybe) {
return RxJava2Adapter.maybeToMono(maybe).block();
}
}
// XXX: public final Object blockingGet(Object)
// XXX: public final Maybe cache()
static final class MaybeCast<T> {
@BeforeTemplate
Maybe<T> before(Maybe<T> maybe) {
return maybe.cast(Refaster.<T>clazz());
}
@AfterTemplate
Maybe<T> after(Maybe<T> maybe) {
return maybe;
}
}
// XXX: public final Maybe compose(MaybeTransformer)
// XXX: public final Maybe concatMap(Function)
// XXX: public final Flowable concatWith(MaybeSource)
// XXX: public final Single contains(Object)
// XXX: public final Single count()
static final class MaybeDefaultIfEmpty<T> {
@BeforeTemplate
Maybe<T> before(Maybe<T> maybe, T item) {
return maybe.defaultIfEmpty(item);
}
@AfterTemplate
Maybe<T> after(Maybe<T> maybe, T item) {
return RxJava2Adapter.monoToMaybe(RxJava2Adapter.maybeToMono(maybe).defaultIfEmpty(item));
}
}
// XXX: public final Maybe delay(long,TimeUnit)
// XXX: public final Maybe delay(long,TimeUnit,Scheduler)
// XXX: public final Maybe delay(Publisher)
// XXX: public final Maybe delaySubscription(long,TimeUnit)
// XXX: public final Maybe delaySubscription(long,TimeUnit,Scheduler)
// XXX: public final Maybe delaySubscription(Publisher)
// XXX: public final Maybe doAfterSuccess(Consumer)
// XXX: public final Maybe doAfterTerminate(Action)
// XXX: public final Maybe doFinally(Action)
// XXX: public final Maybe doOnComplete(Action)
// XXX: public final Maybe doOnDispose(Action)
static final class MaybeDoOnError<T> {
@BeforeTemplate
Maybe<T> before(Maybe<T> maybe, Consumer<? super Throwable> consumer) {
return maybe.doOnError(consumer);
}
@AfterTemplate
Maybe<T> after(Maybe<T> maybe, Consumer<? super Throwable> consumer) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.maybeToMono(maybe)
.doOnError(RxJavaReactorMigrationUtil.toJdkConsumer(consumer)));
}
}
// XXX: public final Maybe doOnEvent(BiConsumer)
// XXX: public final Maybe doOnSubscribe(Consumer)
static final class MaybeDoOnSuccess<T> {
@BeforeTemplate
Maybe<T> before(Maybe<T> maybe, Consumer<T> consumer) {
return maybe.doOnSuccess(consumer);
}
@AfterTemplate
Maybe<T> after(Maybe<T> maybe, Consumer<T> consumer) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.maybeToMono(maybe)
.doOnSuccess(RxJavaReactorMigrationUtil.toJdkConsumer(consumer)));
}
}
// XXX: public final Maybe doOnTerminate(Action)
static final class MaybeFilter<T> {
@BeforeTemplate
Maybe<T> before(Maybe<T> maybe, Predicate<T> predicate) {
return maybe.filter(predicate);
}
@AfterTemplate
Maybe<T> after(Maybe<T> maybe, Predicate<T> predicate) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.maybeToMono(maybe)
.filter(RxJavaReactorMigrationUtil.toJdkPredicate(predicate)));
}
}
static final class MaybeFlatMapFunction<
I, T extends I, O, X extends O, M extends MaybeSource<X>> {
@BeforeTemplate
Maybe<O> before(
Maybe<T> maybe, Function<? super T, ? extends MaybeSource<? extends O>> function) {
return maybe.flatMap(function);
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.IMPORT_CLASS_DIRECTLY)
Maybe<O> after(Maybe<T> maybe, Function<I, M> function) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.maybeToMono(maybe)
.flatMap(
v ->
RxJava2Adapter.maybeToMono(
Maybe.wrap(
RxJavaReactorMigrationUtil.<I, M>toJdkFunction(function).apply(v)))));
}
}
// XXX: There is no link to an original public method for this, but it is important.
abstract static class MaybeFlatMapLambda<S, T> {
@Placeholder
abstract Maybe<T> toMaybeFunction(@MayOptionallyUse S element);
@BeforeTemplate
Maybe<T> before(Maybe<S> maybe) {
return maybe.flatMap(v -> toMaybeFunction(v));
}
@AfterTemplate
Maybe<T> after(Maybe<S> maybe) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.maybeToMono(maybe)
.flatMap(z -> toMaybeFunction(z).as(RxJava2Adapter::maybeToMono)));
}
}
// XXX: public final Maybe flatMap(Function,BiFunction)
// XXX: public final Maybe flatMap(Function,Function,Callable)
// XXX: Add test
static final class MaybeFlatMapCompletable<T, R extends CompletableSource> {
@BeforeTemplate
Completable before(Maybe<T> maybe, Function<T, R> function) {
return maybe.flatMapCompletable(function);
}
@AfterTemplate
Completable after(Maybe<T> maybe, Function<T, R> function) {
return RxJava2Adapter.monoToCompletable(
RxJava2Adapter.maybeToMono(maybe)
.flatMap(
y ->
RxJava2Adapter.completableToMono(
Completable.wrap(
RxJavaReactorMigrationUtil.toJdkFunction((Function<T, R>) function)
.apply(y))))
.then());
}
}
// XXX: public final Observable flatMapObservable(Function)
static final class MaybeFlatMapPublisher<T, O extends T, R extends Publisher<O>> {
@BeforeTemplate
Flowable<O> before(
Maybe<T> maybe, Function<? super T, ? extends Publisher<? extends O>> function) {
return maybe.flatMapPublisher(function);
}
@AfterTemplate
Flowable<O> after(Maybe<T> maybe, Function<T, R> function) {
return RxJava2Adapter.monoToFlowable(
RxJava2Adapter.maybeToMono(maybe)
.flatMap(
y ->
Mono.from(
RxJavaReactorMigrationUtil.<T, R>toJdkFunction(function).apply(y))));
}
}
static final class MaybeFlatMapSingle<T, O extends T, R extends SingleSource<O>> {
@BeforeTemplate
Single<O> before(
Maybe<T> maybe, Function<? super T, ? extends SingleSource<? extends O>> function) {
return maybe.flatMapSingle(function);
}
@AfterTemplate
Single<O> after(Maybe<T> maybe, Function<T, R> function) {
return RxJava2Adapter.monoToSingle(
RxJava2Adapter.maybeToMono(maybe)
.flatMap(
y ->
RxJava2Adapter.singleToMono(
Single.wrap(
RxJavaReactorMigrationUtil.<T, R>toJdkFunction(function).apply(y)))));
}
}
// XXX: Improve the @AfterTemplate to not have a cast
@SuppressWarnings("unchecked")
static final class MaybeFlatMapSingleElement<T, O> {
@BeforeTemplate
Maybe<O> before(
Maybe<T> maybe, Function<? super T, ? extends SingleSource<? extends O>> function) {
return maybe.flatMapSingleElement(function);
}
@AfterTemplate
Maybe<O> after(
Maybe<T> maybe, Function<? super T, ? extends SingleSource<? extends O>> function) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.maybeToMono(maybe)
.flatMap(
e ->
RxJava2Adapter.singleToMono(
Single.wrap(
RxJavaReactorMigrationUtil.toJdkFunction(
(Function<T, SingleSource<O>>) function)
.apply(e)))));
}
}
// XXX: public final Flowable flattenAsFlowable(Function)
// XXX: public final Observable flattenAsObservable(Function)
// XXX: public final Maybe hide()
static final class MaybeIgnoreElement<T> {
@BeforeTemplate
Completable before(Maybe<T> maybe) {
return maybe.ignoreElement();
}
@AfterTemplate
Completable after(Maybe<T> maybe) {
return RxJava2Adapter.monoToCompletable(RxJava2Adapter.maybeToMono(maybe).then());
}
}
// XXX: Add test
static final class MaybeIsEmpty<T> {
@BeforeTemplate
Single<Boolean> before(Maybe<T> maybe) {
return maybe.isEmpty();
}
@AfterTemplate
Single<Boolean> after(Maybe<T> maybe) {
return RxJava2Adapter.monoToSingle(RxJava2Adapter.maybeToMono(maybe).hasElement());
}
}
// XXX: public final Maybe lift(MaybeOperator)
// XXX: public final Maybe map(Function)
static final class MaybeMap<T, R> {
@BeforeTemplate
Maybe<R> before(Maybe<T> maybe, Function<T, R> mapper) {
return maybe.map(mapper);
}
@AfterTemplate
Maybe<R> after(Maybe<T> maybe, Function<T, R> mapper) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.maybeToMono(maybe).map(RxJavaReactorMigrationUtil.toJdkFunction(mapper)));
}
}
// XXX: public final Single materialize()
// XXX: public final Flowable mergeWith(MaybeSource)
// XXX: public final Maybe observeOn(Scheduler)
// XXX: public final Maybe ofType(Class)
// XXX: public final Maybe onErrorComplete()
// XXX: public final Maybe onErrorComplete(Predicate)
// XXX: public final Maybe onErrorResumeNext(Function)
// XXX: public final Maybe onErrorResumeNext(MaybeSource)
// XXX: public final Maybe onErrorReturn(Function)
abstract static class MaybeOnErrorReturn<T, R> {
@Placeholder
abstract T placeholder(@MayOptionallyUse Throwable throwable);
@BeforeTemplate
Maybe<T> before(Maybe<T> maybe) {
return maybe.onErrorReturn(t -> placeholder(t));
}
@AfterTemplate
Maybe<T> after(Maybe<T> maybe) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.maybeToMono(maybe).onErrorResume(t -> Mono.just(placeholder(t))));
}
}
// XXX: public final Maybe onErrorReturnItem(Object)
// XXX: public final Maybe onExceptionResumeNext(MaybeSource)
// XXX: public final Maybe onTerminateDetach()
// XXX: public final Flowable repeat()
// XXX: public final Flowable repeat(long)
// XXX: public final Flowable repeatUntil(BooleanSupplier)
// XXX: public final Flowable repeatWhen(Function)
// XXX: public final Maybe retry()
// XXX: public final Maybe retry(BiPredicate)
// XXX: public final Maybe retry(long)
// XXX: public final Maybe retry(long,Predicate)
// XXX: public final Maybe retry(Predicate)
// XXX: public final Maybe retryUntil(BooleanSupplier)
// XXX: public final Maybe retryWhen(Function)
// XXX: Add test
static final class MaybeSubscribe<T> {
@BeforeTemplate
Disposable before(Maybe<T> maybe) {
return maybe.subscribe();
}
@AfterTemplate
reactor.core.Disposable after(Maybe<T> maybe) {
return RxJava2Adapter.maybeToMono(maybe).subscribe();
}
}
// XXX: Add test
static final class MaybeSubscribeConsumer<T> {
@BeforeTemplate
Disposable before(Maybe<T> maybe, Consumer<? super T> consumer) {
return maybe.subscribe(consumer);
}
@AfterTemplate
reactor.core.Disposable after(Maybe<T> maybe, Consumer<? super T> consumer) {
return RxJava2Adapter.maybeToMono(maybe)
.subscribe(RxJavaReactorMigrationUtil.toJdkConsumer(consumer));
}
}
// XXX: Add test
static final class MaybeSubscribeTwoConsumers<T> {
@BeforeTemplate
Disposable before(
Maybe<T> maybe, Consumer<? super T> consumer1, Consumer<? super Throwable> consumer2) {
return maybe.subscribe(consumer1, consumer2);
}
@AfterTemplate
reactor.core.Disposable after(
Maybe<T> maybe, Consumer<? super T> consumer1, Consumer<? super Throwable> consumer2) {
return RxJava2Adapter.maybeToMono(maybe)
.subscribe(
RxJavaReactorMigrationUtil.toJdkConsumer(consumer1),
RxJavaReactorMigrationUtil.toJdkConsumer(consumer2));
}
}
// XXX: Add test
static final class MaybeSubscribeTwoConsumersWithAction<T> {
@BeforeTemplate
Disposable before(
Maybe<T> maybe,
Consumer<? super T> consumer1,
Consumer<? super Throwable> consumer2,
Action action) {
return maybe.subscribe(consumer1, consumer2, action);
}
@AfterTemplate
reactor.core.Disposable after(
Maybe<T> maybe,
Consumer<? super T> consumer1,
Consumer<? super Throwable> consumer2,
Action action) {
return RxJava2Adapter.maybeToMono(maybe)
.subscribe(
RxJavaReactorMigrationUtil.toJdkConsumer(consumer1),
RxJavaReactorMigrationUtil.toJdkConsumer(consumer2),
RxJavaReactorMigrationUtil.toRunnable(action));
}
}
// XXX: public final void subscribe(MaybeObserver)
// XXX: public final Maybe subscribeOn(Scheduler)
// XXX: public final MaybeObserver subscribeWith(MaybeObserver)
// XXX: Add test
static final class MaybeSourceSwitchIfEmpty<S, T extends S> {
@BeforeTemplate
Maybe<S> before(Maybe<S> maybe, MaybeSource<T> maybeSource) {
return maybe.switchIfEmpty(maybeSource);
}
@AfterTemplate
Maybe<S> after(Maybe<S> maybe, MaybeSource<T> maybeSource) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.maybeToMono(maybe)
.switchIfEmpty(RxJava2Adapter.maybeToMono(Maybe.wrap(maybeSource))));
}
}
static final class MaybeSwitchIfEmpty<S, T extends S> {
@BeforeTemplate
Single<S> before(Maybe<S> maybe, SingleSource<T> single) {
return maybe.switchIfEmpty(single);
}
@AfterTemplate
Single<S> after(Maybe<S> maybe, SingleSource<T> single) {
return RxJava2Adapter.monoToSingle(
RxJava2Adapter.maybeToMono(maybe)
.switchIfEmpty(RxJava2Adapter.singleToMono(Single.wrap(single))));
}
}
// XXX: public final Maybe takeUntil(MaybeSource)
// XXX: public final Maybe takeUntil(Publisher)
// XXX: public final Maybe timeout(long,TimeUnit)
// XXX: public final Maybe timeout(long,TimeUnit,MaybeSource)
// XXX: public final Maybe timeout(long,TimeUnit,Scheduler)
// XXX: public final Maybe timeout(long,TimeUnit,Scheduler,MaybeSource)
// XXX: public final Maybe timeout(MaybeSource)
// XXX: public final Maybe timeout(MaybeSource,MaybeSource)
// XXX: public final Maybe timeout(Publisher)
// XXX: public final Maybe timeout(Publisher,MaybeSource)
// XXX: public final Object to(Function)
static final class MaybeToFlowable<T> {
@BeforeTemplate
Flowable<T> before(Maybe<T> maybe) {
return maybe.toFlowable();
}
@AfterTemplate
Flowable<T> after(Maybe<T> maybe) {
return RxJava2Adapter.fluxToFlowable(RxJava2Adapter.maybeToMono(maybe).flux());
}
}
static final class MaybeToObservable<T> {
@BeforeTemplate
Observable<T> before(Maybe<T> maybe) {
return maybe.toObservable();
}
@AfterTemplate
Observable<T> after(Maybe<T> maybe) {
return RxJava2Adapter.fluxToObservable(RxJava2Adapter.maybeToMono(maybe).flux());
}
}
// XXX: Add test
static final class MaybeToSingle<T> {
@BeforeTemplate
Single<T> before(Maybe<T> maybe) {
return maybe.toSingle();
}
@AfterTemplate
Single<T> after(Maybe<T> maybe) {
return RxJava2Adapter.monoToSingle(RxJava2Adapter.maybeToMono(maybe).single());
}
}
// XXX: public final Single toSingle(Object)
// XXX: public final Maybe unsubscribeOn(Scheduler)
// XXX: Add test
static final class MaybeZipWith<T, R, U> {
@BeforeTemplate
Maybe<R> before(
Maybe<T> maybe,
MaybeSource<U> source,
BiFunction<? super T, ? super U, ? extends R> biFunction) {
return maybe.zipWith(source, biFunction);
}
@AfterTemplate
Maybe<R> after(
Maybe<T> maybe,
MaybeSource<U> source,
BiFunction<? super T, ? super U, ? extends R> biFunction) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.maybeToMono(maybe)
.zipWith(
RxJava2Adapter.maybeToMono(Maybe.wrap(source)),
RxJavaReactorMigrationUtil.toJdkBiFunction(biFunction)));
}
}
@SuppressWarnings("unchecked")
static final class MaybeTestAssertResultItem<T> {
@BeforeTemplate
void before(Maybe<T> maybe, T item) throws InterruptedException {
Refaster.anyOf(
maybe.test().await().assertResult(item),
maybe.test().await().assertResult(item).assertComplete(),
maybe.test().await().assertComplete().assertResult(item),
maybe.test().await().assertValue(item),
maybe.test().await().assertValue(item).assertComplete(),
maybe.test().await().assertComplete().assertValue(item),
// XXX: Move this to correct method
maybe.test().await().assertValues(item));
}
@AfterTemplate
void after(Maybe<T> maybe, T item) {
RxJava2Adapter.maybeToMono(maybe).as(StepVerifier::create).expectNext(item).verifyComplete();
}
}
@SuppressWarnings("unchecked")
static final class MaybeTestAssertResult<T> {
@BeforeTemplate
void before(Maybe<T> maybe) throws InterruptedException {
maybe.test().await().assertResult();
}
@AfterTemplate
void after(Maybe<T> maybe) {
RxJava2Adapter.maybeToMono(maybe).as(StepVerifier::create).verifyComplete();
}
}
static final class MaybeTestAssertValue<T> {
@BeforeTemplate
void before(Maybe<T> maybe, Predicate<T> predicate) throws InterruptedException {
Refaster.anyOf(
maybe.test().await().assertValue(predicate),
maybe.test().await().assertValue(predicate).assertComplete(),
maybe.test().await().assertValue(predicate).assertNoErrors().assertComplete(),
maybe.test().await().assertComplete().assertValue(predicate));
}
@AfterTemplate
void after(Maybe<T> maybe, Predicate<T> predicate) {
RxJava2Adapter.maybeToMono(maybe)
.as(StepVerifier::create)
.expectNextMatches(RxJavaReactorMigrationUtil.toJdkPredicate(predicate))
.verifyComplete();
}
}
static final class MaybeTestAssertComplete<T> {
@BeforeTemplate
void before(Maybe<T> maybe) throws InterruptedException {
maybe.test().await().assertComplete();
}
@AfterTemplate
void after(Maybe<T> maybe) {
RxJava2Adapter.maybeToMono(maybe).as(StepVerifier::create).verifyComplete();
}
}
static final class MaybeTestAssertErrorClass<T> {
@BeforeTemplate
void before(Maybe<T> maybe, Class<? extends Throwable> errorClass) throws InterruptedException {
maybe.test().await().assertError(errorClass);
}
@AfterTemplate
void after(Maybe<T> maybe, Class<? extends Throwable> errorClass) {
RxJava2Adapter.maybeToMono(maybe).as(StepVerifier::create).verifyError(errorClass);
}
}
static final class MaybeTestAssertNoErrors<T> {
@BeforeTemplate
void before(Maybe<T> maybe) throws InterruptedException {
maybe.test().await().assertNoErrors();
}
@AfterTemplate
void after(Maybe<T> maybe) {
RxJava2Adapter.maybeToMono(maybe).as(StepVerifier::create).verifyComplete();
}
}
static final class MaybeTestAssertValueCount<T> {
@BeforeTemplate
void before(Maybe<T> maybe, int count) throws InterruptedException {
maybe.test().await().assertValueCount(count);
}
@AfterTemplate
void after(Maybe<T> maybe, int count) {
RxJava2Adapter.maybeToMono(maybe)
.as(StepVerifier::create)
.expectNextCount(count)
.verifyComplete();
}
}
// XXX: Add test
@SuppressWarnings("unchecked")
static final class MaybeTestAssertFailure<T> {
@BeforeTemplate
void before(Maybe<T> maybe, Class<? extends Throwable> error) throws InterruptedException {
maybe.test().await().assertFailure(error);
}
@AfterTemplate
void after(Maybe<T> maybe, Class<? extends Throwable> error) {
RxJava2Adapter.maybeToMono(maybe).as(StepVerifier::create).verifyError(error);
}
}
// XXX: Add test
static final class MaybeTestAssertNoValues<T> {
@BeforeTemplate
void before(Maybe<T> maybe) throws InterruptedException {
Refaster.anyOf(
maybe.test().await().assertNoValues(),
maybe.test().assertNoValues(),
maybe.test().assertNoValues().assertComplete(),
maybe.test().await().assertNoValues().assertComplete(),
maybe.test().await().assertComplete().assertNoValues());
}
@AfterTemplate
void after(Maybe<T> maybe) {
RxJava2Adapter.maybeToMono(maybe).as(StepVerifier::create).verifyComplete();
}
}
// XXX: Add test
// XXX: This introduces AssertJ dependency
@SuppressWarnings("unchecked")
static final class MaybeTestAssertFailureAndMessage<T> {
@BeforeTemplate
void before(Maybe<T> maybe, Class<? extends Throwable> error, String message)
throws InterruptedException {
maybe.test().await().assertFailureAndMessage(error, message);
}
@AfterTemplate
void after(Maybe<T> maybe, Class<? extends Throwable> error, String message) {
RxJava2Adapter.maybeToMono(maybe)
.as(StepVerifier::create)
.expectErrorSatisfies(
t -> assertThat(t).isInstanceOf(error).hasMessageContaining(message))
.verify();
}
}
// XXX: public final TestObserver test(boolean)
}

View File

@@ -1,927 +0,0 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Repeated;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Completable;
import io.reactivex.Flowable;
import io.reactivex.Maybe;
import io.reactivex.MaybeSource;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import java.util.concurrent.Callable;
import org.reactivestreams.Publisher;
import reactor.adapter.rxjava.RxJava2Adapter;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import tech.picnic.errorprone.migration.util.RxJavaReactorMigrationUtil;
/** The Refaster templates for the migration of the RxJava Observable type to Reactor */
final class RxJavaObservableToReactorTemplates {
private RxJavaObservableToReactorTemplates() {}
static final class ObservableAmb<T> {
@BeforeTemplate
Observable<T> before(Iterable<? extends Observable<T>> sources) {
return Observable.amb(sources);
}
@AfterTemplate
Observable<T> after(Iterable<? extends Observable<T>> sources) {
return RxJava2Adapter.fluxToObservable(
Flux.<T>firstWithSignal(
Streams.stream(sources)
.map(e -> e.toFlowable(BackpressureStrategy.BUFFER))
.map(RxJava2Adapter::flowableToFlux)
.collect(toImmutableList())));
}
}
// XXX: public static Observable ambArray(ObservableSource[])
// XXX: public static int bufferSize()
// XXX: public static Observable combineLatest(Function,int,ObservableSource[])
// XXX: public static Observable combineLatest(Iterable,Function)
// XXX: public static Observable combineLatest(Iterable,Function,int)
// XXX: public static Observable combineLatest(ObservableSource[],Function)
// XXX: public static Observable combineLatest(ObservableSource[],Function,int)
// XXX: public static Observable combineLatest(ObservableSource,ObservableSource,BiFunction)
// XXX: public static Observable
// combineLatest(ObservableSource,ObservableSource,ObservableSource,Function3)
// XXX: public static Observable
// combineLatest(ObservableSource,ObservableSource,ObservableSource,ObservableSource,Function4)
// XXX: public static Observable
// combineLatest(ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,Function5)
// XXX: public static Observable
// combineLatest(ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,Function6)
// XXX: public static Observable
// combineLatest(ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,Function7)
// XXX: public static Observable
// combineLatest(ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,Function8)
// XXX: public static Observable
// combineLatest(ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,Function9)
// XXX: public static Observable combineLatestDelayError(Function,int,ObservableSource[])
// XXX: public static Observable combineLatestDelayError(Iterable,Function)
// XXX: public static Observable combineLatestDelayError(Iterable,Function,int)
// XXX: public static Observable combineLatestDelayError(ObservableSource[],Function)
// XXX: public static Observable combineLatestDelayError(ObservableSource[],Function,int)
// XXX: public static Observable concat(Iterable)
// XXX: public static Observable concat(ObservableSource)
// XXX: public static Observable concat(ObservableSource,int)
// XXX: public static Observable concat(ObservableSource,ObservableSource)
// XXX: public static Observable concat(ObservableSource,ObservableSource,ObservableSource)
// XXX: public static Observable
// concat(ObservableSource,ObservableSource,ObservableSource,ObservableSource)
// XXX: public static Observable concatArray(ObservableSource[])
// XXX: public static Observable concatArrayDelayError(ObservableSource[])
// XXX: public static Observable concatArrayEager(int,int,ObservableSource[])
// XXX: public static Observable concatArrayEager(ObservableSource[])
// XXX: public static Observable concatArrayEagerDelayError(int,int,ObservableSource[])
// XXX: public static Observable concatArrayEagerDelayError(ObservableSource[])
// XXX: public static Observable concatDelayError(Iterable)
// XXX: public static Observable concatDelayError(ObservableSource)
// XXX: public static Observable concatDelayError(ObservableSource,int,boolean)
// XXX: public static Observable concatEager(Iterable)
// XXX: public static Observable concatEager(Iterable,int,int)
// XXX: public static Observable concatEager(ObservableSource)
// XXX: public static Observable concatEager(ObservableSource,int,int)
// XXX: public static Observable create(ObservableOnSubscribe)
// XXX: public static Observable defer(Callable)
static final class ObservableEmpty<T> {
@BeforeTemplate
Observable<T> before() {
return Observable.empty();
}
@AfterTemplate
Observable<T> after() {
return RxJava2Adapter.fluxToObservable(Flux.empty());
}
}
// XXX: public static Observable error(Callable)
// XXX: public static Observable error(Throwable)
// XXX: public static Observable fromArray(Object[])
static final class ObservableFromCallable<T> {
@BeforeTemplate
Observable<? extends T> before(Callable<? extends T> callable) {
return Observable.fromCallable(callable);
}
@AfterTemplate
Observable<? extends T> after(Callable<? extends T> callable) {
return RxJava2Adapter.fluxToObservable(
Mono.fromSupplier(RxJavaReactorMigrationUtil.callableAsSupplier(callable)).flux());
}
}
// XXX: public static Observable fromFuture(Future)
// XXX: public static Observable fromFuture(Future,long,TimeUnit)
// XXX: public static Observable fromFuture(Future,long,TimeUnit,Scheduler)
// XXX: public static Observable fromFuture(Future,Scheduler)
// XXX: public static Observable fromIterable(Iterable)
static final class ObservableFromPublisher<T> {
@BeforeTemplate
Observable<T> before(Publisher<? extends T> source) {
return Observable.fromPublisher(source);
}
@AfterTemplate
Observable<T> after(Publisher<? extends T> source) {
return RxJava2Adapter.fluxToObservable(Flux.from(source));
}
}
// XXX: public static Observable generate(Callable,BiConsumer)
// XXX: public static Observable generate(Callable,BiConsumer,Consumer)
// XXX: public static Observable generate(Callable,BiFunction)
// XXX: public static Observable generate(Callable,BiFunction,Consumer)
// XXX: public static Observable generate(Consumer)
// XXX: public static Observable interval(long,long,TimeUnit)
// XXX: public static Observable interval(long,long,TimeUnit,Scheduler)
// XXX: public static Observable interval(long,TimeUnit)
// XXX: public static Observable interval(long,TimeUnit,Scheduler)
// XXX: public static Observable intervalRange(long,long,long,long,TimeUnit)
// XXX: public static Observable intervalRange(long,long,long,long,TimeUnit,Scheduler)
static final class ObservableJust<T> {
@BeforeTemplate
Observable<T> before(T t) {
return Observable.just(t);
}
@AfterTemplate
Observable<T> after(T t) {
return RxJava2Adapter.fluxToObservable(Flux.just(t));
}
}
static final class ObservableJustTwo<T> {
@BeforeTemplate
Observable<T> before(T t, T t2) {
return Observable.just(t, t2);
}
@AfterTemplate
Observable<T> after(T t, T t2) {
return RxJava2Adapter.fluxToObservable(Flux.just(t, t2));
}
}
static final class ObservableJustThree<T> {
@BeforeTemplate
Observable<T> before(T t, T t2, T t3) {
return Observable.just(t, t2, t3);
}
@AfterTemplate
Observable<T> after(T t, T t2, T t3) {
return RxJava2Adapter.fluxToObservable(Flux.just(t, t2, t3));
}
}
// XXX: public static Observable just(Object,Object,Object,Object)
// XXX: public static Observable just(Object,Object,Object,Object,Object)
// XXX: public static Observable just(Object,Object,Object,Object,Object,Object)
// XXX: public static Observable just(Object,Object,Object,Object,Object,Object,Object)
// XXX: public static Observable just(Object,Object,Object,Object,Object,Object,Object,Object)
// XXX: public static Observable
// just(Object,Object,Object,Object,Object,Object,Object,Object,Object)
// XXX: public static Observable
// just(Object,Object,Object,Object,Object,Object,Object,Object,Object,Object)
// XXX: public static Observable merge(Iterable)
// XXX: public static Observable merge(Iterable,int)
// XXX: public static Observable merge(Iterable,int,int)
// XXX: public static Observable merge(ObservableSource)
// XXX: public static Observable merge(ObservableSource,int)
// XXX: public static Observable merge(ObservableSource,ObservableSource)
// XXX: public static Observable merge(ObservableSource,ObservableSource,ObservableSource)
// XXX: public static Observable
// merge(ObservableSource,ObservableSource,ObservableSource,ObservableSource)
// XXX: public static Observable mergeArray(int,int,ObservableSource[])
// XXX: public static Observable mergeArray(ObservableSource[])
// XXX: public static Observable mergeArrayDelayError(int,int,ObservableSource[])
// XXX: public static Observable mergeArrayDelayError(ObservableSource[])
// XXX: public static Observable mergeDelayError(Iterable)
// XXX: public static Observable mergeDelayError(Iterable,int)
// XXX: public static Observable mergeDelayError(Iterable,int,int)
// XXX: public static Observable mergeDelayError(ObservableSource)
// XXX: public static Observable mergeDelayError(ObservableSource,int)
// XXX: public static Observable mergeDelayError(ObservableSource,ObservableSource)
// XXX: public static Observable
// mergeDelayError(ObservableSource,ObservableSource,ObservableSource)
// XXX: public static Observable
// mergeDelayError(ObservableSource,ObservableSource,ObservableSource,ObservableSource)
// XXX: public static Observable never()
// XXX: public static Observable range(int,int)
// XXX: public static Observable rangeLong(long,long)
// XXX: public static Single sequenceEqual(ObservableSource,ObservableSource)
// XXX: public static Single sequenceEqual(ObservableSource,ObservableSource,BiPredicate)
// XXX: public static Single sequenceEqual(ObservableSource,ObservableSource,BiPredicate,int)
// XXX: public static Single sequenceEqual(ObservableSource,ObservableSource,int)
// XXX: public static Observable switchOnNext(ObservableSource)
// XXX: public static Observable switchOnNext(ObservableSource,int)
// XXX: public static Observable switchOnNextDelayError(ObservableSource)
// XXX: public static Observable switchOnNextDelayError(ObservableSource,int)
// XXX: public static Observable timer(long,TimeUnit)
// XXX: public static Observable timer(long,TimeUnit,Scheduler)
// XXX: public static Observable unsafeCreate(ObservableSource)
// XXX: public static Observable using(Callable,Function,Consumer)
// XXX: public static Observable using(Callable,Function,Consumer,boolean)
// XXX: public static Observable wrap(ObservableSource)
// XXX: public static Observable zip(Iterable,Function)
// XXX: public static Observable zip(ObservableSource,Function)
// XXX: public static Observable zip(ObservableSource,ObservableSource,BiFunction)
// XXX: public static Observable zip(ObservableSource,ObservableSource,BiFunction,boolean)
// XXX: public static Observable zip(ObservableSource,ObservableSource,BiFunction,boolean,int)
// XXX: public static Observable zip(ObservableSource,ObservableSource,ObservableSource,Function3)
// XXX: public static Observable
// zip(ObservableSource,ObservableSource,ObservableSource,ObservableSource,Function4)
// XXX: public static Observable
// zip(ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,Function5)
// XXX: public static Observable
// zip(ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,Function6)
// XXX: public static Observable
// zip(ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,Function7)
// XXX: public static Observable
// zip(ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,Function8)
// XXX: public static Observable
// zip(ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,ObservableSource,Function9)
// XXX: public static Observable zipArray(Function,boolean,int,ObservableSource[])
// XXX: public static Observable zipIterable(Iterable,Function,boolean,int)
// XXX: public final Single all(Predicate)
// XXX: public final Observable ambWith(ObservableSource)
// XXX: public final Single any(Predicate)
// XXX: public final Object as(ObservableConverter)
// XXX: public final Object blockingFirst()
// XXX: public final Object blockingFirst(Object)
// XXX: public final void blockingForEach(Consumer)
// XXX: public final Iterable blockingIterable()
// XXX: public final Iterable blockingIterable(int)
// XXX: public final Object blockingLast()
// XXX: public final Object blockingLast(Object)
// XXX: public final Iterable blockingLatest()
// XXX: public final Iterable blockingMostRecent(Object)
// XXX: public final Iterable blockingNext()
// XXX: public final Object blockingSingle()
// XXX: public final Object blockingSingle(Object)
// XXX: public final void blockingSubscribe()
// XXX: public final void blockingSubscribe(Consumer)
// XXX: public final void blockingSubscribe(Consumer,Consumer)
// XXX: public final void blockingSubscribe(Consumer,Consumer,Action)
// XXX: public final void blockingSubscribe(Observer)
// XXX: public final Observable buffer(Callable)
// XXX: public final Observable buffer(Callable,Callable)
// XXX: public final Observable buffer(int)
// XXX: public final Observable buffer(int,Callable)
// XXX: public final Observable buffer(int,int)
// XXX: public final Observable buffer(int,int,Callable)
// XXX: public final Observable buffer(long,long,TimeUnit)
// XXX: public final Observable buffer(long,long,TimeUnit,Scheduler)
// XXX: public final Observable buffer(long,long,TimeUnit,Scheduler,Callable)
// XXX: public final Observable buffer(long,TimeUnit)
// XXX: public final Observable buffer(long,TimeUnit,int)
// XXX: public final Observable buffer(long,TimeUnit,Scheduler)
// XXX: public final Observable buffer(long,TimeUnit,Scheduler,int)
// XXX: public final Observable buffer(long,TimeUnit,Scheduler,int,Callable,boolean)
// XXX: public final Observable buffer(ObservableSource)
// XXX: public final Observable buffer(ObservableSource,Callable)
// XXX: public final Observable buffer(ObservableSource,Function)
// XXX: public final Observable buffer(ObservableSource,Function,Callable)
// XXX: public final Observable buffer(ObservableSource,int)
// XXX: public final Observable cache()
// XXX: public final Observable cacheWithInitialCapacity(int)
// XXX: public final Observable cast(Class)
// XXX: public final Single collect(Callable,BiConsumer)
// XXX: public final Single collectInto(Object,BiConsumer)
// XXX: public final Observable compose(ObservableTransformer)
// XXX: public final Observable concatMap(Function)
// XXX: public final Observable concatMap(Function,int)
// XXX: public final Completable concatMapCompletable(Function)
// XXX: public final Completable concatMapCompletable(Function,int)
// XXX: public final Completable concatMapCompletableDelayError(Function)
// XXX: public final Completable concatMapCompletableDelayError(Function,boolean)
// XXX: public final Completable concatMapCompletableDelayError(Function,boolean,int)
// XXX: public final Observable concatMapDelayError(Function)
// XXX: public final Observable concatMapDelayError(Function,int,boolean)
// XXX: public final Observable concatMapEager(Function)
// XXX: public final Observable concatMapEager(Function,int,int)
// XXX: public final Observable concatMapEagerDelayError(Function,boolean)
// XXX: public final Observable concatMapEagerDelayError(Function,int,int,boolean)
// XXX: public final Observable concatMapIterable(Function)
// XXX: public final Observable concatMapIterable(Function,int)
// XXX: public final Observable concatMapMaybe(Function)
// XXX: public final Observable concatMapMaybe(Function,int)
// XXX: public final Observable concatMapMaybeDelayError(Function)
// XXX: public final Observable concatMapMaybeDelayError(Function,boolean)
// XXX: public final Observable concatMapMaybeDelayError(Function,boolean,int)
// XXX: public final Observable concatMapSingle(Function)
// XXX: public final Observable concatMapSingle(Function,int)
// XXX: public final Observable concatMapSingleDelayError(Function)
// XXX: public final Observable concatMapSingleDelayError(Function,boolean)
// XXX: public final Observable concatMapSingleDelayError(Function,boolean,int)
// XXX: public final Observable concatWith(CompletableSource)
// XXX: public final Observable concatWith(MaybeSource)
// XXX: public final Observable concatWith(ObservableSource)
// XXX: public final Observable concatWith(SingleSource)
// XXX: public final Single contains(Object)
// XXX: public final Single count()
// XXX: public final Observable debounce(Function)
// XXX: public final Observable debounce(long,TimeUnit)
// XXX: public final Observable debounce(long,TimeUnit,Scheduler)
// XXX: public final Observable defaultIfEmpty(Object)
// XXX: public final Observable delay(Function)
// XXX: public final Observable delay(long,TimeUnit)
// XXX: public final Observable delay(long,TimeUnit,boolean)
// XXX: public final Observable delay(long,TimeUnit,Scheduler)
// XXX: public final Observable delay(long,TimeUnit,Scheduler,boolean)
// XXX: public final Observable delay(ObservableSource,Function)
// XXX: public final Observable delaySubscription(long,TimeUnit)
// XXX: public final Observable delaySubscription(long,TimeUnit,Scheduler)
// XXX: public final Observable delaySubscription(ObservableSource)
// XXX: public final Observable dematerialize()
// XXX: public final Observable dematerialize(Function)
// XXX: public final Observable distinct()
// XXX: public final Observable distinct(Function)
// XXX: public final Observable distinct(Function,Callable)
// XXX: public final Observable distinctUntilChanged()
// XXX: public final Observable distinctUntilChanged(BiPredicate)
// XXX: public final Observable distinctUntilChanged(Function)
// XXX: public final Observable doAfterNext(Consumer)
// XXX: public final Observable doAfterTerminate(Action)
// XXX: public final Observable doFinally(Action)
// XXX: public final Observable doOnComplete(Action)
// XXX: public final Observable doOnDispose(Action)
// XXX: public final Observable doOnEach(Consumer)
// XXX: public final Observable doOnEach(Observer)
// XXX: public final Observable doOnError(Consumer)
// XXX: public final Observable doOnLifecycle(Consumer,Action)
// XXX: public final Observable doOnNext(Consumer)
// XXX: public final Observable doOnSubscribe(Consumer)
// XXX: public final Observable doOnTerminate(Action)
// XXX: public final Maybe elementAt(long)
// XXX: public final Single elementAt(long,Object)
// XXX: public final Single elementAtOrError(long)
// XXX: Default BackPressureStrategy.BUFFER is set.
static final class ObservableFilter<T> {
@BeforeTemplate
Observable<T> before(Observable<T> observable, Predicate<T> predicate) {
return observable.filter(predicate);
}
@AfterTemplate
Observable<T> after(Observable<T> observable, Predicate<T> predicate) {
return RxJava2Adapter.fluxToObservable(
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.filter(RxJavaReactorMigrationUtil.toJdkPredicate(predicate)));
}
}
// XXX: public final Single first(Object)
// XXX: Default BUFFER is chosen here.
static final class MaybeFirstElement<T> {
@BeforeTemplate
Maybe<T> before(Observable<T> observable) {
return observable.firstElement();
}
@AfterTemplate
Maybe<T> after(Observable<T> observable) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER).next());
}
}
// XXX: public final Single firstOrError()
// XXX: public final Observable flatMap(Function)
// XXX: Add test
// XXX: Default BUFFER is set here.
static final class ObservableFlatMap<I, T extends I, O, P extends ObservableSource<O>> {
@BeforeTemplate
Observable<O> before(
Observable<T> observable,
Function<? super T, ? extends ObservableSource<? extends O>> function) {
return observable.flatMap(function);
}
@UseImportPolicy(ImportPolicy.IMPORT_CLASS_DIRECTLY)
@AfterTemplate
Observable<O> after(Observable<T> observable, Function<I, P> function) {
return RxJava2Adapter.fluxToObservable(
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.flatMap(
z ->
RxJava2Adapter.observableToFlux(
Observable.wrap(
RxJavaReactorMigrationUtil.<I, P>toJdkFunction(function).apply(z)),
BackpressureStrategy.BUFFER)));
}
}
// XXX: public final Observable flatMap(Function,BiFunction)
// XXX: public final Observable flatMap(Function,BiFunction,boolean)
// XXX: public final Observable flatMap(Function,BiFunction,boolean,int)
// XXX: public final Observable flatMap(Function,BiFunction,boolean,int,int)
// XXX: public final Observable flatMap(Function,BiFunction,int)
// XXX: public final Observable flatMap(Function,boolean)
// XXX: public final Observable flatMap(Function,boolean,int)
// XXX: public final Observable flatMap(Function,boolean,int,int)
// XXX: public final Observable flatMap(Function,Function,Callable)
// XXX: public final Observable flatMap(Function,Function,Callable,int)
// XXX: public final Observable flatMap(Function,int)
// XXX: public final Completable flatMapCompletable(Function)
// XXX: public final Completable flatMapCompletable(Function,boolean)
static final class ObservableFromIterable<T> {
@BeforeTemplate
Observable<T> before(Iterable<? extends T> iterable) {
return Observable.fromIterable(iterable);
}
@AfterTemplate
Observable<T> after(Iterable<? extends T> iterable) {
return RxJava2Adapter.fluxToObservable(Flux.fromIterable(iterable));
}
}
// XXX: public final Observable flatMapIterable(Function,BiFunction)
static final class ObservableFlatMapMaybe<T, R, O extends R, M extends MaybeSource<O>> {
Observable<O> before(
Observable<T> observable, Function<? super T, ? extends MaybeSource<? extends O>> mapper) {
return observable.flatMapMaybe(mapper);
}
Observable<O> after(Observable<T> observable, Function<T, M> mapper) {
return RxJava2Adapter.fluxToObservable(
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.flatMap(
t ->
RxJava2Adapter.maybeToMono(
Maybe.wrap(
RxJavaReactorMigrationUtil.<T, M>toJdkFunction(mapper).apply(t)))));
}
} // XXX: public final Observable flatMapMaybe(Function,boolean)
// XXX: public final Observable flatMapSingle(Function)
// XXX: public final Observable flatMapSingle(Function,boolean)
// XXX: public final Disposable forEach(Consumer)
// XXX: public final Disposable forEachWhile(Predicate)
// XXX: public final Disposable forEachWhile(Predicate,Consumer)
// XXX: public final Disposable forEachWhile(Predicate,Consumer,Action)
// XXX: public final Observable groupBy(Function)
// XXX: public final Observable groupBy(Function,boolean)
// XXX: public final Observable groupBy(Function,Function)
// XXX: public final Observable groupBy(Function,Function,boolean)
// XXX: public final Observable groupBy(Function,Function,boolean,int)
// XXX: public final Observable groupJoin(ObservableSource,Function,Function,BiFunction)
// XXX: public final Observable hide()
static final class ObservableIgnoreElements<T> {
@BeforeTemplate
Completable before(Observable<T> observable) {
return observable.ignoreElements();
}
@AfterTemplate
Completable after(Observable<T> observable) {
return RxJava2Adapter.monoToCompletable(
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.ignoreElements()
.then());
}
}
// XXX: public final Single isEmpty()
// XXX: public final Observable join(ObservableSource,Function,Function,BiFunction)
// XXX: public final Single last(Object)
// XXX: public final Maybe lastElement()
// XXX: public final Single lastOrError()
// XXX: public final Observable lift(ObservableOperator)
// XXX: public final Observable map(Function)
// XXX: public final Observable materialize()
// XXX: public final Observable mergeWith(CompletableSource)
// XXX: public final Observable mergeWith(MaybeSource)
// XXX: public final Observable mergeWith(ObservableSource)
// XXX: public final Observable mergeWith(SingleSource)
// XXX: public final Observable observeOn(Scheduler)
// XXX: public final Observable observeOn(Scheduler,boolean)
// XXX: public final Observable observeOn(Scheduler,boolean,int)
// XXX: public final Observable ofType(Class)
// XXX: public final Observable onErrorResumeNext(Function)
// XXX: public final Observable onErrorResumeNext(ObservableSource)
// XXX: public final Observable onErrorReturn(Function)
// XXX: public final Observable onErrorReturnItem(Object)
// XXX: public final Observable onExceptionResumeNext(ObservableSource)
// XXX: public final Observable onTerminateDetach()
// XXX: public final ConnectableObservable publish()
// XXX: public final Observable publish(Function)
// XXX: public final Maybe reduce(BiFunction)
// XXX: public final Single reduce(Object,BiFunction)
// XXX: public final Single reduceWith(Callable,BiFunction)
// XXX: public final Observable repeat()
// XXX: public final Observable repeat(long)
// XXX: public final Observable repeatUntil(BooleanSupplier)
// XXX: public final Observable repeatWhen(Function)
// XXX: public final ConnectableObservable replay()
// XXX: public final Observable replay(Function)
// XXX: public final Observable replay(Function,int)
// XXX: public final Observable replay(Function,int,long,TimeUnit)
// XXX: public final Observable replay(Function,int,long,TimeUnit,Scheduler)
// XXX: public final Observable replay(Function,int,Scheduler)
// XXX: public final Observable replay(Function,long,TimeUnit)
// XXX: public final Observable replay(Function,long,TimeUnit,Scheduler)
// XXX: public final Observable replay(Function,Scheduler)
// XXX: public final ConnectableObservable replay(int)
// XXX: public final ConnectableObservable replay(int,long,TimeUnit)
// XXX: public final ConnectableObservable replay(int,long,TimeUnit,Scheduler)
// XXX: public final ConnectableObservable replay(int,Scheduler)
// XXX: public final ConnectableObservable replay(long,TimeUnit)
// XXX: public final ConnectableObservable replay(long,TimeUnit,Scheduler)
// XXX: public final ConnectableObservable replay(Scheduler)
// XXX: public final Observable retry()
// XXX: public final Observable retry(BiPredicate)
// XXX: public final Observable retry(long)
// XXX: public final Observable retry(long,Predicate)
// XXX: public final Observable retry(Predicate)
// XXX: public final Observable retryUntil(BooleanSupplier)
// XXX: public final Observable retryWhen(Function)
// XXX: public final void safeSubscribe(Observer)
// XXX: public final Observable sample(long,TimeUnit)
// XXX: public final Observable sample(long,TimeUnit,boolean)
// XXX: public final Observable sample(long,TimeUnit,Scheduler)
// XXX: public final Observable sample(long,TimeUnit,Scheduler,boolean)
// XXX: public final Observable sample(ObservableSource)
// XXX: public final Observable sample(ObservableSource,boolean)
// XXX: public final Observable scan(BiFunction)
// XXX: public final Observable scan(Object,BiFunction)
// XXX: public final Observable scanWith(Callable,BiFunction)
// XXX: public final Observable serialize()
// XXX: public final Observable share()
// XXX: public final Single single(Object)
// XXX: public final Maybe singleElement()
// XXX: public final Single singleOrError()
// XXX: public final Observable skip(long)
// XXX: public final Observable skip(long,TimeUnit)
// XXX: public final Observable skip(long,TimeUnit,Scheduler)
// XXX: public final Observable skipLast(int)
// XXX: public final Observable skipLast(long,TimeUnit)
// XXX: public final Observable skipLast(long,TimeUnit,boolean)
// XXX: public final Observable skipLast(long,TimeUnit,Scheduler)
// XXX: public final Observable skipLast(long,TimeUnit,Scheduler,boolean)
// XXX: public final Observable skipLast(long,TimeUnit,Scheduler,boolean,int)
// XXX: public final Observable skipUntil(ObservableSource)
// XXX: public final Observable skipWhile(Predicate)
// XXX: public final Observable sorted()
// XXX: public final Observable sorted(Comparator)
// XXX: public final Observable startWith(Iterable)
// XXX: public final Observable startWith(Object)
// XXX: public final Observable startWith(ObservableSource)
// XXX: public final Observable startWithArray(Object[])
// XXX: public final Disposable subscribe()
// XXX: public final Disposable subscribe(Consumer)
// XXX: public final Disposable subscribe(Consumer,Consumer)
// XXX: public final Disposable subscribe(Consumer,Consumer,Action)
// XXX: public final Disposable subscribe(Consumer,Consumer,Action,Consumer)
// XXX: public final void subscribe(Observer)
// XXX: public final Observable subscribeOn(Scheduler)
// XXX: public final Observer subscribeWith(Observer)
// XXX: public final Observable switchIfEmpty(ObservableSource)
// XXX: public final Observable switchMap(Function)
// XXX: public final Observable switchMap(Function,int)
// XXX: public final Completable switchMapCompletable(Function)
// XXX: public final Completable switchMapCompletableDelayError(Function)
// XXX: public final Observable switchMapDelayError(Function)
// XXX: public final Observable switchMapDelayError(Function,int)
// XXX: public final Observable switchMapMaybe(Function)
// XXX: public final Observable switchMapMaybeDelayError(Function)
// XXX: public final Observable switchMapSingle(Function)
// XXX: public final Observable switchMapSingleDelayError(Function)
// XXX: public final Observable take(long)
// XXX: public final Observable take(long,TimeUnit)
// XXX: public final Observable take(long,TimeUnit,Scheduler)
// XXX: public final Observable takeLast(int)
// XXX: public final Observable takeLast(long,long,TimeUnit)
// XXX: public final Observable takeLast(long,long,TimeUnit,Scheduler)
// XXX: public final Observable takeLast(long,long,TimeUnit,Scheduler,boolean,int)
// XXX: public final Observable takeLast(long,TimeUnit)
// XXX: public final Observable takeLast(long,TimeUnit,boolean)
// XXX: public final Observable takeLast(long,TimeUnit,Scheduler)
// XXX: public final Observable takeLast(long,TimeUnit,Scheduler,boolean)
// XXX: public final Observable takeLast(long,TimeUnit,Scheduler,boolean,int)
// XXX: public final Observable takeUntil(ObservableSource)
// XXX: public final Observable takeUntil(Predicate)
// XXX: public final Observable takeWhile(Predicate)
// XXX: public final Observable throttleFirst(long,TimeUnit)
// XXX: public final Observable throttleFirst(long,TimeUnit,Scheduler)
// XXX: public final Observable throttleLast(long,TimeUnit)
// XXX: public final Observable throttleLast(long,TimeUnit,Scheduler)
// XXX: public final Observable throttleLatest(long,TimeUnit)
// XXX: public final Observable throttleLatest(long,TimeUnit,boolean)
// XXX: public final Observable throttleLatest(long,TimeUnit,Scheduler)
// XXX: public final Observable throttleLatest(long,TimeUnit,Scheduler,boolean)
// XXX: public final Observable throttleWithTimeout(long,TimeUnit)
// XXX: public final Observable throttleWithTimeout(long,TimeUnit,Scheduler)
// XXX: public final Observable timeInterval()
// XXX: public final Observable timeInterval(Scheduler)
// XXX: public final Observable timeInterval(TimeUnit)
// XXX: public final Observable timeInterval(TimeUnit,Scheduler)
// XXX: public final Observable timeout(Function)
// XXX: public final Observable timeout(Function,ObservableSource)
// XXX: public final Observable timeout(long,TimeUnit)
// XXX: public final Observable timeout(long,TimeUnit,ObservableSource)
// XXX: public final Observable timeout(long,TimeUnit,Scheduler)
// XXX: public final Observable timeout(long,TimeUnit,Scheduler,ObservableSource)
// XXX: public final Observable timeout(ObservableSource,Function)
// XXX: public final Observable timeout(ObservableSource,Function,ObservableSource)
// XXX: public final Observable timestamp()
// XXX: public final Observable timestamp(Scheduler)
// XXX: public final Observable timestamp(TimeUnit)
// XXX: public final Observable timestamp(TimeUnit,Scheduler)
// XXX: public final Object to(Function)
static final class CompletableToFlowable<T> {
@BeforeTemplate
Flowable<T> before(Observable<T> observable, BackpressureStrategy strategy) {
return observable.toFlowable(strategy);
}
@AfterTemplate
Flowable<T> after(Observable<T> observable, BackpressureStrategy strategy) {
return RxJava2Adapter.fluxToFlowable(RxJava2Adapter.observableToFlux(observable, strategy));
}
}
// XXX: public final Future toFuture()
// XXX: public final Single toList()
// XXX: public final Single toList(Callable)
// XXX: public final Single toList(int)
// XXX: public final Single toMap(Function)
// XXX: public final Single toMap(Function,Function)
// XXX: public final Single toMap(Function,Function,Callable)
// XXX: public final Single toMultimap(Function)
// XXX: public final Single toMultimap(Function,Function)
// XXX: public final Single toMultimap(Function,Function,Callable)
// XXX: public final Single toMultimap(Function,Function,Callable,Function)
// XXX: public final Single toSortedList()
// XXX: public final Single toSortedList(Comparator)
// XXX: public final Single toSortedList(Comparator,int)
// XXX: public final Single toSortedList(int)
// XXX: public final Observable unsubscribeOn(Scheduler)
// XXX: public final Observable window(Callable)
// XXX: public final Observable window(Callable,int)
// XXX: public final Observable window(long)
// XXX: public final Observable window(long,long)
// XXX: public final Observable window(long,long,int)
// XXX: public final Observable window(long,long,TimeUnit)
// XXX: public final Observable window(long,long,TimeUnit,Scheduler)
// XXX: public final Observable window(long,long,TimeUnit,Scheduler,int)
// XXX: public final Observable window(long,TimeUnit)
// XXX: public final Observable window(long,TimeUnit,long)
// XXX: public final Observable window(long,TimeUnit,long,boolean)
// XXX: public final Observable window(long,TimeUnit,Scheduler)
// XXX: public final Observable window(long,TimeUnit,Scheduler,long)
// XXX: public final Observable window(long,TimeUnit,Scheduler,long,boolean)
// XXX: public final Observable window(long,TimeUnit,Scheduler,long,boolean,int)
// XXX: public final Observable window(ObservableSource)
// XXX: public final Observable window(ObservableSource,Function)
// XXX: public final Observable window(ObservableSource,Function,int)
// XXX: public final Observable window(ObservableSource,int)
// XXX: public final Observable withLatestFrom(Iterable,Function)
// XXX: public final Observable withLatestFrom(ObservableSource,BiFunction)
// XXX: public final Observable withLatestFrom(ObservableSource[],Function)
// XXX: public final Observable withLatestFrom(ObservableSource,ObservableSource,Function3)
// XXX: public final Observable
// withLatestFrom(ObservableSource,ObservableSource,ObservableSource,Function4)
// XXX: public final Observable
// withLatestFrom(ObservableSource,ObservableSource,ObservableSource,ObservableSource,Function5)
// XXX: public final Observable zipWith(Iterable,BiFunction)
// XXX: public final Observable zipWith(ObservableSource,BiFunction)
// XXX: public final Observable zipWith(ObservableSource,BiFunction,boolean)
// XXX: public final Observable zipWith(ObservableSource,BiFunction,boolean,int)
// XXX: Default BackpressureStrategy.BUFFER is set
static final class ObservableTestAssertResultItem<T> {
@BeforeTemplate
void before(Observable<T> observable, T item) throws InterruptedException {
Refaster.anyOf(
observable.test().await().assertResult(item),
observable.test().await().assertValue(item));
}
@AfterTemplate
void after(Observable<T> observable, T item) {
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.as(StepVerifier::create)
.expectNext(item)
.verifyComplete();
}
}
// XXX: Default BackpressureStrategy.BUFFER is set
@SuppressWarnings("unchecked")
static final class ObservableTestAssertResult<T> {
@BeforeTemplate
void before(Observable<T> observable) throws InterruptedException {
Refaster.anyOf(observable.test().await().assertResult(), observable.test().await());
}
@AfterTemplate
void after(Observable<T> observable) {
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.as(StepVerifier::create)
.verifyComplete();
}
}
@SuppressWarnings("unchecked")
static final class ObservableTestAssertResultTwoItems<T> {
@BeforeTemplate
void before(Observable<T> observable, T t1, T t2) throws InterruptedException {
observable.test().await().assertResult(t1, t2);
}
@AfterTemplate
void after(Observable<T> observable, T t1, T t2) {
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.as(StepVerifier::create)
.expectNext(t1, t2)
.verifyComplete();
}
}
// XXX: Default BackpressureStrategy.BUFFER is set
static final class ObservableTestAssertValue<T> {
@BeforeTemplate
void before(Observable<T> observable, Predicate<T> predicate) throws InterruptedException {
Refaster.anyOf(
observable.test().await().assertValue(predicate),
observable.test().await().assertValue(predicate).assertNoErrors().assertComplete(),
observable.test().await().assertComplete().assertValue(predicate),
observable.test().await().assertValue(predicate).assertComplete());
}
@AfterTemplate
void after(Observable<T> observable, Predicate<T> predicate) {
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.as(StepVerifier::create)
.expectNextMatches(RxJavaReactorMigrationUtil.toJdkPredicate(predicate))
.verifyComplete();
}
}
// XXX: Default BackpressureStrategy.BUFFER is set
static final class ObservableTestAssertResultValues<T> {
@BeforeTemplate
void before(Observable<T> observable, @Repeated T item) throws InterruptedException {
Refaster.anyOf(
observable.test().await().assertResult(Refaster.asVarargs(item)),
observable.test().await().assertValues(Refaster.asVarargs(item)));
}
@AfterTemplate
void after(Observable<T> observable, @Repeated T item) {
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.as(StepVerifier::create)
.expectNext(item)
.verifyComplete();
}
}
// XXX: Default BackpressureStrategy.BUFFER is set
static final class ObservableTestAssertComplete<T> {
@BeforeTemplate
void before(Observable<T> observable) throws InterruptedException {
observable.test().await().assertComplete();
}
@AfterTemplate
void after(Observable<T> observable) {
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.as(StepVerifier::create)
.verifyComplete();
}
}
// XXX: Default BackpressureStrategy.BUFFER is set
static final class ObservableTestAssertErrorClass<T> {
@BeforeTemplate
void before(Observable<T> observable, Class<? extends Throwable> errorClass)
throws InterruptedException {
observable.test().await().assertError(errorClass);
}
@AfterTemplate
void after(Observable<T> observable, Class<? extends Throwable> errorClass) {
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.as(StepVerifier::create)
.verifyError(errorClass);
}
}
// XXX: Default BackpressureStrategy.BUFFER is set
static final class ObservableTestAssertNoErrors<T> {
@BeforeTemplate
void before(Observable<T> observable) throws InterruptedException {
observable.test().await().assertNoErrors();
}
@AfterTemplate
void after(Observable<T> observable) {
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.as(StepVerifier::create)
.verifyComplete();
}
}
// XXX: Default BackpressureStrategy.BUFFER is set
static final class ObservableTestAssertValueCount<T> {
@BeforeTemplate
void before(Observable<T> observable, int count) throws InterruptedException {
observable.test().await().assertValueCount(count);
}
@AfterTemplate
void after(Observable<T> observable, int count) {
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.as(StepVerifier::create)
.expectNextCount(count)
.verifyComplete();
}
}
// XXX: Add test
// XXX: Default BackpressureStrategy.BUFFER is set
@SuppressWarnings("unchecked")
static final class ObservableTestAssertFailure<T> {
@BeforeTemplate
void before(Observable<T> observable, Class<? extends Throwable> error)
throws InterruptedException {
observable.test().await().assertFailure(error);
}
@AfterTemplate
void after(Observable<T> observable, Class<? extends Throwable> error) {
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.as(StepVerifier::create)
.verifyError(error);
}
}
// XXX: Add test
// XXX: Default BackpressureStrategy.BUFFER is set
static final class ObservableTestAssertNoValues<T> {
@BeforeTemplate
void before(Observable<T> observable) throws InterruptedException {
Refaster.anyOf(
observable.test().await().assertNoValues(),
observable.test().await().assertNoValues().assertComplete());
}
@AfterTemplate
void after(Observable<T> observable) {
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.as(StepVerifier::create)
.verifyComplete();
}
}
// XXX: Add test
// XXX: This introduces AssertJ dependency
@SuppressWarnings("unchecked")
static final class ObservableTestAssertFailureAndMessage<T> {
@BeforeTemplate
void before(Observable<T> observable, Class<? extends Throwable> error, String message)
throws InterruptedException {
observable.test().await().assertFailureAndMessage(error, message);
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.IMPORT_CLASS_DIRECTLY)
void after(Observable<T> observable, Class<? extends Throwable> error, String message) {
RxJava2Adapter.observableToFlux(observable, BackpressureStrategy.BUFFER)
.as(StepVerifier::create)
.expectErrorSatisfies(
t -> assertThat(t).isInstanceOf(error).hasMessageContaining(message))
.verify();
}
}
// XXX: public final TestObserver test(boolean)
}

View File

@@ -1,764 +0,0 @@
package tech.picnic.errorprone.refastertemplates;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import io.reactivex.Completable;
import io.reactivex.CompletableSource;
import io.reactivex.Flowable;
import io.reactivex.Maybe;
import io.reactivex.MaybeSource;
import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.BiFunction;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import io.reactivex.schedulers.Schedulers;
import java.util.concurrent.Callable;
import org.reactivestreams.Publisher;
import reactor.adapter.rxjava.RxJava2Adapter;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import tech.picnic.errorprone.migration.util.RxJavaReactorMigrationUtil;
/** The Refaster templates for the migration of the RxJava Single type to Reactor */
final class RxJavaSingleToReactorTemplates {
private RxJavaSingleToReactorTemplates() {}
// XXX: public static Single amb(Iterable)
// XXX: public static Single ambArray(SingleSource[])
// XXX: public static Flowable concat(Iterable)
// XXX: public static Observable concat(ObservableSource)
// XXX: public static Flowable concat(Publisher)
// XXX: public static Flowable concat(Publisher,int)
// XXX: public static Flowable concat(SingleSource,SingleSource)
// XXX: public static Flowable concat(SingleSource,SingleSource,SingleSource)
// XXX: public static Flowable concat(SingleSource,SingleSource,SingleSource,SingleSource)
// XXX: public static Flowable concatArray(SingleSource[])
// XXX: public static Flowable concatArrayEager(SingleSource[])
// XXX: public static Flowable concatEager(Iterable)
// XXX: public static Flowable concatEager(Publisher)
// XXX: public static Single create(SingleOnSubscribe)
abstract static class SingleDeferFirst<T> {
@Placeholder
abstract Single<? extends T> singleProducer();
@BeforeTemplate
Single<T> before() {
return Single.defer(() -> singleProducer());
}
@AfterTemplate
Single<? extends T> after() {
return RxJava2Adapter.monoToSingle(
Mono.defer(() -> RxJava2Adapter.singleToMono(singleProducer())));
}
}
// XXX: public static Single equals(SingleSource,SingleSource)
static final class SingleErrorCallable<T> {
@BeforeTemplate
Single<T> before(Callable<? extends Throwable> throwable) {
return Single.error(throwable);
}
@UseImportPolicy(ImportPolicy.IMPORT_CLASS_DIRECTLY)
@AfterTemplate
Single<T> after(Callable<? extends Throwable> throwable) {
return RxJava2Adapter.monoToSingle(
Mono.error(RxJavaReactorMigrationUtil.callableAsSupplier(throwable)));
}
}
static final class SingleErrorThrowable<T> {
@BeforeTemplate
Single<T> before(Throwable throwable) {
return Single.error(throwable);
}
@AfterTemplate
Single<T> after(Throwable throwable) {
return RxJava2Adapter.monoToSingle(Mono.error(throwable));
}
}
static final class SingleFromCallable<T> {
@BeforeTemplate
Single<T> before(Callable<? extends T> callable) {
return Single.fromCallable(callable);
}
@UseImportPolicy(ImportPolicy.IMPORT_CLASS_DIRECTLY)
@AfterTemplate
Single<T> after(Callable<? extends T> callable) {
return RxJava2Adapter.monoToSingle(
Mono.fromSupplier(RxJavaReactorMigrationUtil.callableAsSupplier(callable)));
}
}
// XXX: public static Single fromFuture(Future)
// XXX: public static Single fromFuture(Future,long,TimeUnit)
// XXX: public static Single fromFuture(Future,long,TimeUnit,Scheduler)
// XXX: public static Single fromFuture(Future,Scheduler)
// XXX: public static Single fromObservable(ObservableSource)
static final class SingleFromPublisher<T> {
@BeforeTemplate
Single<T> before(Publisher<? extends T> source) {
return Single.fromPublisher(source);
}
@AfterTemplate
Single<T> after(Publisher<? extends T> source) {
return RxJava2Adapter.monoToSingle(Mono.from(source));
}
}
static final class SingleJust<T> {
@BeforeTemplate
Single<T> before(T item) {
return Single.just(item);
}
@AfterTemplate
Single<T> after(T item) {
return RxJava2Adapter.monoToSingle(Mono.just(item));
}
}
// XXX: public static Flowable merge(Iterable)
// XXX: public static Flowable merge(Publisher)
// XXX: public static Single merge(SingleSource)
// XXX: public static Flowable merge(SingleSource,SingleSource)
// XXX: public static Flowable merge(SingleSource,SingleSource,SingleSource)
// XXX: public static Flowable merge(SingleSource,SingleSource,SingleSource,SingleSource)
// XXX: public static Flowable mergeDelayError(Iterable)
// XXX: public static Flowable mergeDelayError(Publisher)
// XXX: public static Flowable mergeDelayError(SingleSource,SingleSource)
// XXX: public static Flowable mergeDelayError(SingleSource,SingleSource,SingleSource)
// XXX: public static Flowable
// mergeDelayError(SingleSource,SingleSource,SingleSource,SingleSource)
// XXX: public static Single never()
static final class SingleNever {
@BeforeTemplate
<T> Single<T> before() {
return Single.never();
}
@AfterTemplate
<T> Single<T> after() {
return RxJava2Adapter.monoToSingle(Mono.never());
}
}
// XXX: public static Single timer(long,TimeUnit)
// XXX: public static Single timer(long,TimeUnit,Scheduler)
// XXX: public static Single unsafeCreate(SingleSource)
// XXX: public static Single using(Callable,Function,Consumer)
// XXX: public static Single using(Callable,Function,Consumer,boolean)
static final class SingleWrap<T> {
@BeforeTemplate
Single<T> before(Single<T> single) {
return Single.wrap(single);
}
@AfterTemplate
Single<T> after(Single<T> single) {
return single;
}
}
// XXX: public static Single zip(Iterable,Function)
// XXX: public static Single zip(SingleSource,SingleSource,BiFunction)
// XXX: public static Single zip(SingleSource,SingleSource,SingleSource,Function3)
// XXX: public static Single zip(SingleSource,SingleSource,SingleSource,SingleSource,Function4)
// XXX: public static Single
// zip(SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,Function5)
// XXX: public static Single
// zip(SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,Function6)
// XXX: public static Single
// zip(SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,Function7)
// XXX: public static Single
// zip(SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,Function8)
// XXX: public static Single
// zip(SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,SingleSource,Function9)
// XXX: public static Single zipArray(Function,SingleSource[])
// XXX: public final Single ambWith(SingleSource)
// XXX: public final Object as(SingleConverter)
static final class SingleBlockingGet<T> {
@BeforeTemplate
Object before(Single<T> single) {
return single.blockingGet();
}
@AfterTemplate
Object after(Single<T> single) {
return RxJava2Adapter.singleToMono(single).block();
}
}
// XXX: public final Single cache()
// XXX: public final Single cast(Class)
// XXX: public final Single compose(SingleTransformer)
static final class SingleConcatWith<T> {
@BeforeTemplate
Flowable<T> before(Single<T> single, SingleSource<? extends T> source) {
return single.concatWith(source);
}
@AfterTemplate
Flowable<T> after(Single<T> single, SingleSource<? extends T> source) {
return RxJava2Adapter.fluxToFlowable(
RxJava2Adapter.singleToMono(single)
.concatWith(RxJava2Adapter.singleToMono(Single.wrap(source))));
}
}
// XXX: public final Single contains(Object)
// XXX: public final Single contains(Object,BiPredicate)
// XXX: public final Single delay(long,TimeUnit)
// XXX: public final Single delay(long,TimeUnit,boolean)
// XXX: public final Single delay(long,TimeUnit,Scheduler)
// XXX: public final Single delay(long,TimeUnit,Scheduler,boolean)
// XXX: public final Single delaySubscription(CompletableSource)
// XXX: public final Single delaySubscription(long,TimeUnit)
// XXX: public final Single delaySubscription(long,TimeUnit,Scheduler)
// XXX: public final Single delaySubscription(ObservableSource)
// XXX: public final Single delaySubscription(Publisher)
// XXX: public final Single delaySubscription(SingleSource)
// XXX: public final Maybe dematerialize(Function)
// XXX: public final Single doAfterSuccess(Consumer)
// XXX: public final Single doAfterTerminate(Action)
// XXX: public final Single doFinally(Action)
// XXX: public final Single doOnDispose(Action)
static final class SingleDoOnError<T> {
@BeforeTemplate
Single<T> before(Single<T> single, Consumer<? super Throwable> consumer) {
return single.doOnError(consumer);
}
@AfterTemplate
Single<T> after(Single<T> single, Consumer<? super Throwable> consumer) {
return RxJava2Adapter.monoToSingle(
RxJava2Adapter.singleToMono(single)
.doOnError(RxJavaReactorMigrationUtil.toJdkConsumer(consumer)));
}
}
// XXX: public final Single doOnEvent(BiConsumer)
// XXX: public final Single doOnSubscribe(Consumer)
static final class SingleDoOnSuccess<T> {
@BeforeTemplate
Single<T> before(Single<T> single, Consumer<T> consumer) {
return single.doOnSuccess(consumer);
}
@AfterTemplate
Single<T> after(Single<T> single, Consumer<T> consumer) {
return RxJava2Adapter.monoToSingle(
RxJava2Adapter.singleToMono(single)
.doOnSuccess(RxJavaReactorMigrationUtil.toJdkConsumer(consumer)));
}
}
// XXX: public final Single doOnTerminate(Action)
static final class SingleFilter<S, T extends S> {
@BeforeTemplate
Maybe<T> before(Single<T> single, Predicate<S> predicate) {
return single.filter(predicate);
}
@AfterTemplate
Maybe<T> after(Single<T> single, Predicate<S> predicate) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.singleToMono(single)
.filter(RxJavaReactorMigrationUtil.toJdkPredicate(predicate)));
}
}
// XXX: Add test
static final class SingleFlatMapFunction<I, T extends I, O, M extends SingleSource<O>> {
@BeforeTemplate
Single<O> before(
Single<T> single, Function<? super I, ? extends SingleSource<? extends O>> function) {
return single.flatMap(function);
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.IMPORT_CLASS_DIRECTLY)
Single<O> after(Single<T> single, Function<I, M> function) {
return RxJava2Adapter.monoToSingle(
RxJava2Adapter.singleToMono(single)
.flatMap(
v ->
RxJava2Adapter.singleToMono(
Single.wrap(
RxJavaReactorMigrationUtil.<I, M>toJdkFunction(function).apply(v)))));
}
}
abstract static class SingleFlatMapLambda<S, T> {
@Placeholder
abstract Single<T> toSingleFunction(@MayOptionallyUse S element);
@BeforeTemplate
Single<T> before(Single<S> single) {
return Refaster.anyOf(
single.flatMap(v -> toSingleFunction(v)), single.flatMap((S v) -> toSingleFunction(v)));
}
@AfterTemplate
Single<T> after(Single<S> single) {
return RxJava2Adapter.monoToSingle(
RxJava2Adapter.singleToMono(single)
.flatMap(v -> RxJava2Adapter.singleToMono(toSingleFunction(v))));
}
}
static final class SingleFlatMapCompletable<T, R extends CompletableSource> {
@BeforeTemplate
Completable before(
Single<T> single, Function<? super T, ? extends CompletableSource> function) {
return single.flatMapCompletable(function);
}
@AfterTemplate
Completable after(Single<T> single, Function<T, R> function) {
return RxJava2Adapter.monoToCompletable(
RxJava2Adapter.singleToMono(single)
.flatMap(
z ->
RxJava2Adapter.completableToMono(
Completable.wrap(
RxJavaReactorMigrationUtil.<T, R>toJdkFunction(function).apply(z))))
.then());
}
}
// XXX: Add test
static final class SingleFlatMapMaybe<T, R, M extends MaybeSource<R>> {
@BeforeTemplate
Maybe<R> before(
Single<T> single, Function<? super T, ? extends MaybeSource<? extends R>> mapper) {
return single.flatMapMaybe(mapper);
}
@AfterTemplate
Maybe<R> after(Single<T> single, Function<T, M> mapper) {
return RxJava2Adapter.monoToMaybe(
RxJava2Adapter.singleToMono(single)
.flatMap(
e ->
RxJava2Adapter.maybeToMono(
Maybe.wrap(
RxJavaReactorMigrationUtil.<T, M>toJdkFunction(mapper).apply(e)))));
}
}
// XXX: public final Observable flatMapObservable(Function)
static final class SingleFlatMapPublisher<T, R> {
@BeforeTemplate
Flowable<R> before(
Single<T> single, Function<? super T, ? extends Publisher<? extends R>> mapper) {
return single.flatMapPublisher(mapper);
}
@AfterTemplate
Flowable<R> after(
Single<T> single, Function<? super T, ? extends Publisher<? extends R>> mapper) {
return RxJava2Adapter.fluxToFlowable(
RxJava2Adapter.singleToMono(single)
.flatMapMany(RxJavaReactorMigrationUtil.toJdkFunction(mapper)));
}
}
// XXX: public final Flowable flattenAsFlowable(Function)
// XXX: public final Observable flattenAsObservable(Function)
// XXX: public final Single hide()
static final class CompletableIgnoreElement<T> {
@BeforeTemplate
Completable before(Single<T> single) {
return single.ignoreElement();
}
@AfterTemplate
Completable after(Single<T> single) {
return RxJava2Adapter.monoToCompletable(RxJava2Adapter.singleToMono(single).then());
}
}
// XXX: public final Single lift(SingleOperator)
static final class SingleMap<I, T extends I, O> {
@BeforeTemplate
Single<O> before(Single<T> single, Function<? super I, ? extends O> function) {
return single.map(function);
}
@AfterTemplate
Single<O> after(Single<T> single, Function<I, O> function) {
return RxJava2Adapter.monoToSingle(
RxJava2Adapter.singleToMono(single)
.map(RxJavaReactorMigrationUtil.toJdkFunction(function)));
}
}
// XXX: public final Single materialize()
// XXX: public final Flowable mergeWith(SingleSource)
// XXX: public final Single observeOn(Scheduler)
static final class SingleOnErrorResumeNext<
S, T extends S, R, P extends Throwable, Q extends Single<T>> {
@BeforeTemplate
Single<T> before(
Single<T> single,
Function<? super Throwable, ? extends SingleSource<? extends T>> function) {
return single.onErrorResumeNext(function);
}
@AfterTemplate
Single<T> after(Single<T> single, Function<Throwable, Q> function) {
return RxJava2Adapter.monoToSingle(
RxJava2Adapter.singleToMono(single)
.onErrorResume(
err ->
RxJava2Adapter.singleToMono(
RxJavaReactorMigrationUtil.<Throwable, Q>toJdkFunction(function)
.apply(err))));
}
}
// XXX: public final Single onErrorResumeNext(Single)
// XXX: public final Single onErrorReturn(Function)
// XXX: public final Single onErrorReturnItem(Object)
// XXX: public final Single onTerminateDetach()
// XXX: public final Flowable repeat()
// XXX: public final Flowable repeat(long)
// XXX: public final Flowable repeatUntil(BooleanSupplier)
// XXX: public final Flowable repeatWhen(Function)
// XXX: public final Single retry()
// XXX: public final Single retry(BiPredicate)
// XXX: public final Single retry(long)
// XXX: public final Single retry(long,Predicate)
// XXX: public final Single retry(Predicate)
// XXX: public final Single retryWhen(Function)
// XXX: Add test
static final class SingleSubscribe<T> {
@BeforeTemplate
Disposable before(Single<T> single) {
return single.subscribe();
}
@AfterTemplate
reactor.core.Disposable after(Single<T> single) {
return RxJava2Adapter.singleToMono(single).subscribe();
}
}
// XXX: public final Disposable subscribe(BiConsumer)
// XXX: Add test
static final class SingleSubscribeConsumer<T> {
@BeforeTemplate
Disposable before(Single<T> single, Consumer<? super T> consumer) {
return single.subscribe(consumer);
}
@AfterTemplate
reactor.core.Disposable after(Single<T> single, Consumer<? super T> consumer) {
return RxJava2Adapter.singleToMono(single)
.subscribe(RxJavaReactorMigrationUtil.toJdkConsumer(consumer));
}
}
// XXX: Add test
static final class SingleSubscribeTwoConsumers<T> {
@BeforeTemplate
Disposable before(
Single<T> single, Consumer<? super T> consumer1, Consumer<? super Throwable> consumer2) {
return single.subscribe(consumer1, consumer2);
}
@AfterTemplate
reactor.core.Disposable after(
Single<T> single, Consumer<? super T> consumer1, Consumer<? super Throwable> consumer2) {
return RxJava2Adapter.singleToMono(single)
.subscribe(
RxJavaReactorMigrationUtil.toJdkConsumer(consumer1),
RxJavaReactorMigrationUtil.toJdkConsumer(consumer2));
}
}
// XXX: public final void subscribe(SingleObserver)
// XXX: We are currently not accounting for the Schedulers.computation()
static final class SingleSubscribeOn<T> {
@BeforeTemplate
Single<T> before(Single<T> single) {
return single.subscribeOn(Schedulers.io());
}
@AfterTemplate
Single<T> after(Single<T> single) {
return RxJava2Adapter.monoToSingle(
RxJava2Adapter.singleToMono(single)
.subscribeOn(reactor.core.scheduler.Schedulers.boundedElastic()));
}
}
// XXX: public final SingleObserver subscribeWith(SingleObserver)
// XXX: public final Single takeUntil(CompletableSource)
// XXX: public final Single takeUntil(Publisher)
// XXX: public final Single takeUntil(SingleSource)
// XXX: public final Single timeout(long,TimeUnit)
// XXX: public final Single timeout(long,TimeUnit,Scheduler)
// XXX: public final Single timeout(long,TimeUnit,Scheduler,SingleSource)
// XXX: public final Single timeout(long,TimeUnit,SingleSource)
// XXX: public final Object to(Function)
// XXX: public final Completable toCompletable()
static final class SingleToFlowable<T> {
@BeforeTemplate
Flowable<T> before(Single<T> single) {
return single.toFlowable();
}
@AfterTemplate
Flowable<T> after(Single<T> single) {
return RxJava2Adapter.fluxToFlowable(RxJava2Adapter.singleToMono(single).flux());
}
}
// XXX: public final Future toFuture()
static final class SingleToMaybe<T> {
@BeforeTemplate
Maybe<T> before(Single<T> single) {
return single.toMaybe();
}
@AfterTemplate
Maybe<T> after(Single<T> single) {
return RxJava2Adapter.monoToMaybe(RxJava2Adapter.singleToMono(single));
}
}
// XXX: public final Observable toObservable()
// XXX: public final Single unsubscribeOn(Scheduler)
static final class SingleZipWith<T, R, U> {
@BeforeTemplate
Single<R> before(
Single<T> single,
SingleSource<U> source,
BiFunction<? super T, ? super U, ? extends R> biFunction) {
return single.zipWith(source, biFunction);
}
@AfterTemplate
Single<R> after(
Single<T> single,
SingleSource<U> source,
BiFunction<? super T, ? super U, ? extends R> biFunction) {
return RxJava2Adapter.monoToSingle(
RxJava2Adapter.singleToMono(single)
.zipWith(
RxJava2Adapter.singleToMono(Single.wrap(source)),
RxJavaReactorMigrationUtil.toJdkBiFunction(biFunction)));
}
}
@SuppressWarnings("unchecked")
static final class SingleTestAssertResultItem<T> {
@BeforeTemplate
void before(Single<T> single, T item) throws InterruptedException {
Refaster.anyOf(
single.test().assertResult(item),
single.test().await().assertResult(item),
single.test().await().assertComplete().assertResult(item),
single.test().await().assertResult(item).assertComplete(),
single.test().await().assertValue(item),
single.test().await().assertComplete().assertValue(item),
single.test().assertValue(item),
single.test().await().assertValue(item).assertComplete());
}
@AfterTemplate
void after(Single<T> single, T item) {
RxJava2Adapter.singleToMono(single)
.as(StepVerifier::create)
.expectNext(item)
.verifyComplete();
}
}
static final class SingleAssertValueSet<T> {
@BeforeTemplate
void before(Single<T> single, ImmutableSet<? extends T> set) throws InterruptedException {
single.test().await().assertNoErrors().assertValueSet(set).assertComplete();
}
@AfterTemplate
void after(Single<T> single, ImmutableSet<? extends T> set) {
RxJava2Adapter.singleToMono(single)
.map(ImmutableSet::of)
.as(StepVerifier::create)
.expectNext(ImmutableSet.copyOf(set))
.verifyComplete();
}
}
@SuppressWarnings("unchecked")
static final class SingleTestAssertResult<T> {
@BeforeTemplate
void before(Single<T> single) throws InterruptedException {
single.test().await().assertResult();
}
@AfterTemplate
void after(Single<T> single) {
RxJava2Adapter.singleToMono(single).as(StepVerifier::create).verifyComplete();
}
}
static final class SingleTestAssertValue<T> {
@BeforeTemplate
void before(Single<T> single, Predicate<T> predicate) throws InterruptedException {
Refaster.anyOf(
single.test().await().assertValue(predicate),
single.test().await().assertValue(predicate).assertComplete(),
single.test().await().assertValue(predicate).assertNoErrors().assertComplete(),
single.test().await().assertComplete().assertValue(predicate));
}
@AfterTemplate
void after(Single<T> single, Predicate<T> predicate) {
RxJava2Adapter.singleToMono(single)
.as(StepVerifier::create)
.expectNextMatches(RxJavaReactorMigrationUtil.toJdkPredicate(predicate))
.verifyComplete();
}
}
static final class SingleTestAssertComplete<T> {
@BeforeTemplate
void before(Single<T> single) throws InterruptedException {
single.test().await().assertComplete();
}
@AfterTemplate
void after(Single<T> single) {
RxJava2Adapter.singleToMono(single).as(StepVerifier::create).verifyComplete();
}
}
static final class SingleTestAssertErrorClass<T> {
@BeforeTemplate
void before(Single<T> single, Class<? extends Throwable> errorClass)
throws InterruptedException {
single.test().await().assertError(errorClass);
}
@AfterTemplate
void after(Single<T> single, Class<? extends Throwable> errorClass) {
RxJava2Adapter.singleToMono(single).as(StepVerifier::create).verifyError(errorClass);
}
}
static final class SingleTestAssertNoErrors<T> {
@BeforeTemplate
void before(Single<T> single) throws InterruptedException {
single.test().await().assertNoErrors();
}
@AfterTemplate
void after(Single<T> single) {
RxJava2Adapter.singleToMono(single).as(StepVerifier::create).verifyComplete();
}
}
static final class SingleTestAssertValueCount<T> {
@BeforeTemplate
void before(Single<T> single, int count) throws InterruptedException {
single.test().await().assertValueCount(count);
}
@AfterTemplate
void after(Single<T> single, int count) {
RxJava2Adapter.singleToMono(single)
.as(StepVerifier::create)
.expectNextCount(count)
.verifyComplete();
}
}
// XXX: Add test
@SuppressWarnings("unchecked")
static final class SingleTestAssertFailure<T> {
@BeforeTemplate
void before(Single<T> single, Class<? extends Throwable> error) throws InterruptedException {
single.test().await().assertFailure(error);
}
@AfterTemplate
void after(Single<T> single, Class<? extends Throwable> error) {
RxJava2Adapter.singleToMono(single).as(StepVerifier::create).verifyError(error);
}
}
// XXX: Add test
static final class SingleTestAssertNoValues<T> {
@BeforeTemplate
void before(Single<T> single) throws InterruptedException {
Refaster.anyOf(
single.test().await().assertNoValues(),
single.test().await().assertNoValues().assertComplete());
}
@AfterTemplate
void after(Single<T> single) {
RxJava2Adapter.singleToMono(single).as(StepVerifier::create).verifyComplete();
}
}
// XXX: Add test
// XXX: This introduces AssertJ dependency
static final class SingleTestAssertFailureAndMessage<T> {
@BeforeTemplate
void before(Single<T> single, Class<? extends Throwable> error, String message)
throws InterruptedException {
single.test().await().assertFailureAndMessage(error, message);
}
@AfterTemplate
void after(Single<T> single, Class<? extends Throwable> error, String message) {
RxJava2Adapter.singleToMono(single)
.as(StepVerifier::create)
.expectErrorSatisfies(
t -> assertThat(t).isInstanceOf(error).hasMessageContaining(message))
.verify();
}
}
// XXX: public final TestObserver test(boolean)
}

View File

@@ -1,290 +0,0 @@
package tech.picnic.errorprone.refastertemplates;
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.CanTransformToTargetType;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.functions.Action;
import io.reactivex.functions.BiFunction;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
import org.reactivestreams.Publisher;
import reactor.adapter.rxjava.RxJava2Adapter;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import tech.picnic.errorprone.migration.util.RxJavaReactorMigrationUtil;
/** Assorted Refaster templates for the migration of RxJava to Reactor */
public final class RxJavaToReactorTemplates {
private RxJavaToReactorTemplates() {}
static final class FluxToFlowableToFlux<T> {
@BeforeTemplate
Flux<T> before(Flux<T> flux, BackpressureStrategy strategy) {
return Refaster.anyOf(
RxJava2Adapter.fluxToFlowable(flux).as(RxJava2Adapter::flowableToFlux),
RxJava2Adapter.flowableToFlux(RxJava2Adapter.fluxToFlowable(flux)),
RxJava2Adapter.flowableToFlux(flux.as(RxJava2Adapter::fluxToFlowable)),
RxJava2Adapter.observableToFlux(flux.as(RxJava2Adapter::fluxToObservable), strategy),
flux.as(RxJava2Adapter::fluxToObservable)
.toFlowable(strategy)
.as(RxJava2Adapter::flowableToFlux),
RxJava2Adapter.observableToFlux(RxJava2Adapter.fluxToObservable(flux), strategy),
flux.as(RxJava2Adapter::fluxToFlowable).as(RxJava2Adapter::flowableToFlux));
}
@AfterTemplate
Flux<T> after(Flux<T> flux) {
return flux;
}
}
static final class MonoToFlowableToMono<T> {
@BeforeTemplate
Mono<Void> before(Mono<Void> mono) {
return Refaster.anyOf(
RxJava2Adapter.monoToCompletable(mono).as(RxJava2Adapter::completableToMono),
mono.as(RxJava2Adapter::monoToCompletable).as(RxJava2Adapter::completableToMono),
RxJava2Adapter.completableToMono(RxJava2Adapter.monoToCompletable(mono)),
RxJava2Adapter.completableToMono(mono.as(RxJava2Adapter::monoToCompletable)));
}
@BeforeTemplate
Mono<T> before2(Mono<T> mono) {
return Refaster.anyOf(
RxJava2Adapter.monoToMaybe(mono).as(RxJava2Adapter::maybeToMono),
RxJava2Adapter.maybeToMono(RxJava2Adapter.monoToMaybe(mono)),
RxJava2Adapter.maybeToMono(mono.as(RxJava2Adapter::monoToMaybe)),
mono.as(RxJava2Adapter::monoToMaybe).as(RxJava2Adapter::maybeToMono),
RxJava2Adapter.monoToSingle(mono).as(RxJava2Adapter::singleToMono),
RxJava2Adapter.singleToMono(RxJava2Adapter.monoToSingle(mono)),
RxJava2Adapter.singleToMono(mono.as(RxJava2Adapter::monoToSingle)),
mono.as(RxJava2Adapter::monoToSingle).as(RxJava2Adapter::singleToMono));
}
@BeforeTemplate
Mono<Void> before3(Mono<T> mono) {
return Refaster.anyOf(
RxJava2Adapter.completableToMono(RxJava2Adapter.monoToCompletable(mono)),
RxJava2Adapter.completableToMono(mono.as(RxJava2Adapter::monoToCompletable)),
RxJava2Adapter.monoToCompletable(mono).as(RxJava2Adapter::completableToMono));
}
@AfterTemplate
Mono<T> after(Mono<T> mono) {
return mono;
}
}
// XXX: Add test cases
static final class MonoToFlowableToFlux<T> {
@BeforeTemplate
Flux<T> before(Mono<T> mono) {
return mono.as(RxJava2Adapter::monoToFlowable).as(RxJava2Adapter::flowableToFlux);
}
@AfterTemplate
Flux<T> after(Mono<T> mono) {
return mono.flux();
}
}
static final class MonoErrorCallableSupplierUtil<T> {
@BeforeTemplate
Mono<T> before(@CanTransformToTargetType Callable<? extends Throwable> callable) {
return Mono.error(RxJavaReactorMigrationUtil.callableAsSupplier(callable));
}
@AfterTemplate
Mono<T> after(Supplier<? extends Throwable> callable) {
return Mono.error(callable);
}
}
@SuppressWarnings({"NoFunctionalReturnType", "FunctionalInterfaceClash"})
static final class RemoveUtilCallable<T> {
@BeforeTemplate
Supplier<T> before(@CanTransformToTargetType Callable<T> callable) {
return RxJavaReactorMigrationUtil.callableAsSupplier(callable);
}
@AfterTemplate
Supplier<T> before(Supplier<T> callable) {
return callable;
}
}
@SuppressWarnings("NoFunctionalReturnType")
static final class UnnecessaryFunctionConversion<I, O> {
@BeforeTemplate
java.util.function.Function<I, O> before(@CanTransformToTargetType Function<I, O> function) {
return RxJavaReactorMigrationUtil.toJdkFunction(function);
}
@AfterTemplate
java.util.function.Function<I, O> after(java.util.function.Function<I, O> function) {
return function;
}
}
@SuppressWarnings("NoFunctionalReturnType")
static final class UnnecessaryBiFunctionConversion<T, U, R> {
@BeforeTemplate
java.util.function.BiFunction<? super T, ? super U, ? extends R> before(
@CanTransformToTargetType BiFunction<? super T, ? super U, ? extends R> zipper) {
return RxJavaReactorMigrationUtil.toJdkBiFunction(zipper);
}
@AfterTemplate
java.util.function.BiFunction<? super T, ? super U, ? extends R> after(
java.util.function.BiFunction<? super T, ? super U, ? extends R> zipper) {
return zipper;
}
}
@SuppressWarnings("NoFunctionalReturnType")
static final class UnnecessaryConsumerConversion<T> {
@BeforeTemplate
java.util.function.Consumer<? extends T> before(
@CanTransformToTargetType Consumer<? extends T> consumer) {
return RxJavaReactorMigrationUtil.toJdkConsumer(consumer);
}
@AfterTemplate
java.util.function.Consumer<? extends T> after(
java.util.function.Consumer<? extends T> consumer) {
return consumer;
}
}
static final class UnnecessaryRunnableConversion {
@BeforeTemplate
Runnable before(@CanTransformToTargetType Action action) {
return RxJavaReactorMigrationUtil.toRunnable(action);
}
@AfterTemplate
Runnable after(Runnable action) {
return action;
}
}
@SuppressWarnings("NoFunctionalReturnType")
static final class UnnecessaryPredicateConversion<T> {
@BeforeTemplate
java.util.function.Predicate<? extends T> before(
@CanTransformToTargetType Predicate<? extends T> predicate) {
return RxJavaReactorMigrationUtil.toJdkPredicate(predicate);
}
@AfterTemplate
java.util.function.Predicate<? extends T> after(
java.util.function.Predicate<? extends T> predicate) {
return predicate;
}
}
static final class FlowableBiFunctionRemoveUtil<T, U, R> {
@BeforeTemplate
Flowable<R> before(
Publisher<? extends T> source1,
Publisher<? extends U> source2,
@CanTransformToTargetType BiFunction<? super T, ? super U, ? extends R> zipper) {
return RxJava2Adapter.fluxToFlowable(
Flux.<T, U, R>zip(source1, source2, RxJavaReactorMigrationUtil.toJdkBiFunction(zipper)));
}
@AfterTemplate
Flowable<R> after(
Publisher<? extends T> source1,
Publisher<? extends U> source2,
java.util.function.BiFunction<? super T, ? super U, ? extends R> zipper) {
return RxJava2Adapter.fluxToFlowable(Flux.<T, U, R>zip(source1, source2, zipper));
}
}
///////////////////////////////////////////
//////////// ASSORTED TEMPLATES ///////////
///////////////////////////////////////////
static final class MonoFromNestedPublisher<T> {
@BeforeTemplate
Mono<T> before(Flux<T> flux) {
return Mono.from(RxJava2Adapter.fluxToFlowable(flux));
}
@AfterTemplate
Mono<T> after(Flux<T> flux) {
return Mono.from(flux);
}
}
static final class FlowableToFluxWithFilter<T> {
@BeforeTemplate
Flux<T> before(Flux<T> flux, Predicate<T> predicate) {
return RxJava2Adapter.flowableToFlux(
flux.filter(RxJavaReactorMigrationUtil.toJdkPredicate(predicate))
.as(RxJava2Adapter::fluxToFlowable));
}
@AfterTemplate
Flux<T> after(Flux<T> flux, Predicate<T> predicate) {
return flux.filter(RxJavaReactorMigrationUtil.toJdkPredicate(predicate));
}
}
static final class ObservableToFlux<T> {
@BeforeTemplate
Flux<T> before(Flux<T> flux, Predicate<T> predicate, BackpressureStrategy strategy) {
return RxJava2Adapter.observableToFlux(
RxJava2Adapter.fluxToObservable(flux).filter(predicate), strategy);
}
@AfterTemplate
Flux<T> after(Flux<T> flux, Predicate<T> predicate, BackpressureStrategy strategy) {
return flux.filter(RxJavaReactorMigrationUtil.toJdkPredicate(predicate));
}
}
static final class MonoFromToFlowableToFlux<T> {
@BeforeTemplate
Flux<T> before(Mono<T> mono) {
return RxJava2Adapter.flowableToFlux(mono.as(RxJava2Adapter::monoToFlowable));
}
@AfterTemplate
Flux<T> after(Mono<T> mono) {
return mono.flux();
}
}
static final class MonoThenThen<T> {
@BeforeTemplate
Mono<T> before(Mono<T> mono, Mono<T> other) {
return mono.then().then(other);
}
@AfterTemplate
Mono<T> after(Mono<T> mono, Mono<T> other) {
return mono.then(other);
}
}
// XXX: Find out how we can use this in the future.
// static final class RemoveRedundantCast<T> {
// @BeforeTemplate
// T before(T object) {
// return (T) object;
// }
//
// @AfterTemplate
// T after(T object) {
// return object;
// }
// }
}

View File

@@ -1,404 +0,0 @@
package tech.picnic.errorprone.refastertemplates;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.Placeholder;
import io.reactivex.Completable;
import io.reactivex.CompletableSource;
import io.reactivex.Maybe;
import io.reactivex.MaybeSource;
import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.functions.Function;
import org.reactivestreams.Publisher;
import reactor.adapter.rxjava.RxJava2Adapter;
import reactor.core.publisher.Mono;
import tech.picnic.errorprone.migration.util.RxJavaReactorMigrationUtil;
public final class RxJavaUnwrapTemplates {
private RxJavaUnwrapTemplates() {}
// XXX: Add test
@SuppressWarnings("NoFunctionalReturnType")
abstract static class FlowableConcatMapCompletableUnwrapLambda<T> {
@Placeholder
abstract Mono<?> placeholder(@MayOptionallyUse T input);
@BeforeTemplate
java.util.function.Function<? super T, ? extends Publisher<?>> before() {
return e ->
RxJava2Adapter.completableToMono(
RxJavaReactorMigrationUtil.toJdkFunction(
(T ident) -> RxJava2Adapter.monoToCompletable(placeholder(ident)))
.apply(e));
}
@AfterTemplate
java.util.function.Function<T, ? extends Publisher<?>> after() {
return v -> placeholder(v);
}
}
// XXX: Add test
@SuppressWarnings("NoFunctionalReturnType")
abstract static class MaybeFlatMapUnwrapLambda<I, T extends I, O> {
@Placeholder
abstract Mono<? extends O> placeholder(@MayOptionallyUse T input);
@BeforeTemplate
@SuppressWarnings("unchecked")
java.util.function.Function<? super T, ? extends Mono<? extends O>> before() {
return Refaster.anyOf(
v ->
RxJava2Adapter.maybeToMono(
(Maybe<O>)
RxJavaReactorMigrationUtil.toJdkFunction(
(T ident) -> RxJava2Adapter.monoToMaybe(placeholder(ident)))
.apply(v)),
v ->
RxJava2Adapter.maybeToMono(
RxJavaReactorMigrationUtil.toJdkFunction(
(T ident) -> RxJava2Adapter.monoToMaybe(placeholder(ident)))
.apply(v)));
}
@AfterTemplate
java.util.function.Function<? super T, ? extends Mono<? extends O>> after() {
return v -> placeholder(v);
}
}
// XXX: Add test
@SuppressWarnings("NoFunctionalReturnType")
abstract static class MaybeFlatMapSingleElementUnwrapLambda<T, R> {
@Placeholder
abstract Mono<R> placeholder(@MayOptionallyUse T input);
@BeforeTemplate
java.util.function.Function<T, ? extends Mono<? extends R>> before() {
return Refaster.anyOf(
e ->
RxJava2Adapter.singleToMono(
Single.wrap(
RxJavaReactorMigrationUtil.toJdkFunction(
(Function<T, SingleSource<R>>)
(T ident) -> RxJava2Adapter.monoToSingle(placeholder(ident)))
.apply(e))),
e ->
RxJava2Adapter.singleToMono(
Single.wrap(
RxJavaReactorMigrationUtil.<T, SingleSource<R>>toJdkFunction(
(T ident) -> RxJava2Adapter.monoToSingle(placeholder(ident)))
.apply(e))));
}
@AfterTemplate
java.util.function.Function<T, ? extends Mono<? extends R>> after() {
return e -> placeholder(e);
}
}
// XXX: Add test
@SuppressWarnings("NoFunctionalReturnType")
abstract static class SingleFlatMapMaybeUnwrapLambda<T, R> {
@Placeholder
abstract Mono<R> placeholder(@MayOptionallyUse T input);
@BeforeTemplate
java.util.function.Function<? super T, ? extends Mono<? extends R>> before() {
return Refaster.anyOf(
e ->
RxJava2Adapter.maybeToMono(
Maybe.wrap(
RxJavaReactorMigrationUtil.toJdkFunction(
(Function<T, MaybeSource<R>>)
(T ident) -> RxJava2Adapter.monoToMaybe(placeholder(ident)))
.apply(e))),
e ->
RxJava2Adapter.maybeToMono(
Maybe.wrap(
RxJavaReactorMigrationUtil.toJdkFunction(
(Function<T, MaybeSource<R>>)
ident -> RxJava2Adapter.monoToMaybe(placeholder(ident)))
.apply(e))),
e ->
RxJava2Adapter.maybeToMono(
Maybe.wrap(
RxJavaReactorMigrationUtil.<T, MaybeSource<R>>toJdkFunction(
ident -> RxJava2Adapter.monoToMaybe(placeholder(ident)))
.apply(e))));
}
@AfterTemplate
java.util.function.Function<? super T, ? extends Mono<? extends R>> after() {
return e -> placeholder(e);
}
}
// XXX: Add test
@SuppressWarnings({"NoFunctionalReturnType", "unchecked"})
abstract static class SingleOnResumeUnwrapLambda<T, R> {
@Placeholder
abstract Mono<? extends R> placeholder(@MayOptionallyUse Throwable input);
@BeforeTemplate
java.util.function.Function<? extends Throwable, ? extends Mono<? extends R>> before() {
return Refaster.anyOf(
e ->
RxJava2Adapter.singleToMono(
RxJavaReactorMigrationUtil.toJdkFunction(
ident -> RxJava2Adapter.monoToSingle(placeholder(e)))
.apply(e)),
e ->
RxJava2Adapter.singleToMono(
Single.wrap(
RxJavaReactorMigrationUtil.toJdkFunction(
(Function<Throwable, ? extends SingleSource<? extends R>>)
placeholder(e))
.apply(e))),
e ->
RxJava2Adapter.singleToMono(
Single.wrap(
RxJavaReactorMigrationUtil.<Throwable, SingleSource<R>>toJdkFunction(
(Function<Throwable, SingleSource<R>>) placeholder(e))
.apply(e))));
}
@AfterTemplate
java.util.function.Function<Throwable, ? extends Mono<? extends R>> after() {
return v -> placeholder(v);
}
}
// XXX: Add test
@SuppressWarnings("NoFunctionalReturnType")
abstract static class FlowableConcatMapMaybeDelayErrorUnwrapLambda<T, R> {
@Placeholder
abstract Mono<R> placeholder(@MayOptionallyUse T input);
@BeforeTemplate
java.util.function.Function<? super T, ? extends Publisher<? extends R>> after() {
return Refaster.anyOf(
e ->
Maybe.wrap(
RxJavaReactorMigrationUtil.toJdkFunction(
(Function<T, MaybeSource<R>>)
ident -> RxJava2Adapter.monoToMaybe(placeholder(ident)))
.apply(e))
.toFlowable(),
e ->
Maybe.wrap(
RxJavaReactorMigrationUtil.<T, MaybeSource<R>>toJdkFunction(
ident -> RxJava2Adapter.monoToMaybe(placeholder(ident)))
.apply(e))
.toFlowable());
}
@AfterTemplate
java.util.function.Function<? super T, ? extends Publisher<? extends R>> before() {
return e -> placeholder(e);
}
}
// XXX: Add test
@SuppressWarnings("NoFunctionalReturnType")
abstract static class FlowableFlatMapCompletableUnwrapLambda<T> {
@Placeholder
abstract Mono<?> placeholder(@MayOptionallyUse T input);
@BeforeTemplate
java.util.function.Function<T, ? extends Publisher<? extends Void>> before() {
return Refaster.anyOf(
e ->
RxJava2Adapter.completableToMono(
Completable.wrap(
RxJavaReactorMigrationUtil.<T, Completable>toJdkFunction(
(Function<T, Completable>)
(T ident) -> RxJava2Adapter.monoToCompletable(placeholder(ident)))
.apply(e))),
e ->
RxJava2Adapter.completableToMono(
RxJavaReactorMigrationUtil.<T, Completable>toJdkFunction(
(Function<T, Completable>)
(T ident) -> RxJava2Adapter.monoToCompletable(placeholder(ident)))
.apply(e)),
e ->
RxJava2Adapter.completableToMono(
Completable.wrap(
RxJavaReactorMigrationUtil.<T, Completable>toJdkFunction(
(T ident) -> RxJava2Adapter.monoToCompletable(placeholder(ident)))
.apply(e))),
e ->
RxJava2Adapter.completableToMono(
RxJavaReactorMigrationUtil.<T, Completable>toJdkFunction(
(T ident) -> RxJava2Adapter.monoToCompletable(placeholder(ident)))
.apply(e)));
}
@AfterTemplate
java.util.function.Function<T, Mono<?>> after() {
return v -> placeholder(v);
}
}
// XXX: Improve naming and add test case
@SuppressWarnings("NoFunctionalReturnType")
abstract static class FlowableUnwrapLambda<T> {
@Placeholder
abstract Completable placeholder(@MayOptionallyUse T input);
@BeforeTemplate
java.util.function.Function<T, Publisher<? extends Void>> before() {
return Refaster.anyOf(
e ->
RxJava2Adapter.completableToMono(
Completable.wrap(
RxJavaReactorMigrationUtil.<T, CompletableSource>toJdkFunction(
(Function<T, CompletableSource>) v -> placeholder(v))
.apply(e))),
e ->
RxJava2Adapter.completableToMono(
Completable.wrap(
RxJavaReactorMigrationUtil.<T, CompletableSource>toJdkFunction(
v -> placeholder(v))
.apply(e))));
}
@AfterTemplate
java.util.function.Function<T, Mono<? extends Void>> after() {
return v -> RxJava2Adapter.completableToMono(Completable.wrap(placeholder(v)));
}
}
@SuppressWarnings("NoFunctionalReturnType")
abstract static class FlowableFlatMapUnwrapLambda<T> {
@Placeholder
abstract CompletableSource placeholder(@MayOptionallyUse T input);
@BeforeTemplate
java.util.function.Function<T, ? extends Publisher<? extends Void>> before() {
return e ->
RxJava2Adapter.completableToMono(
Completable.wrap(
RxJavaReactorMigrationUtil.<T, CompletableSource>toJdkFunction(
(Function<T, CompletableSource>) v -> placeholder(v))
.apply(e)));
}
@AfterTemplate
java.util.function.Function<T, Mono<? extends Void>> after() {
return v -> RxJava2Adapter.completableToMono(Completable.wrap(placeholder(v)));
}
}
// XXX: Add test
@SuppressWarnings("NoFunctionalReturnType")
abstract static class SingleFlatMapUnwrapLambda<T, R> {
@Placeholder
abstract Mono<? extends R> placeholder(@MayOptionallyUse T input);
@BeforeTemplate
java.util.function.Function<T, ? extends Mono<? extends R>> before() {
return v ->
RxJava2Adapter.singleToMono(
(Single<? extends R>)
RxJavaReactorMigrationUtil.toJdkFunction(
(T ident) -> RxJava2Adapter.monoToSingle(placeholder(ident)))
.apply(v));
}
@AfterTemplate
java.util.function.Function<T, ? extends Mono<? extends R>> after() {
return v -> placeholder(v);
}
}
// XXX: Add test
@SuppressWarnings("NoFunctionalReturnType")
abstract static class SingleRemoveLambdaWithCast<T> {
@Placeholder
abstract Mono<?> placeholder(@MayOptionallyUse T input);
@BeforeTemplate
java.util.function.Function<? super T, ? extends Publisher<? extends Void>> before() {
return Refaster.anyOf(
e ->
RxJava2Adapter.completableToMono(
Completable.wrap(
RxJavaReactorMigrationUtil.<T, Completable>toJdkFunction(
(Function<T, Completable>)
v -> placeholder(v).as(RxJava2Adapter::monoToCompletable))
.apply(e))),
e ->
RxJava2Adapter.completableToMono(
Completable.wrap(
RxJavaReactorMigrationUtil.<T, Completable>toJdkFunction(
(Function<T, Completable>)
v -> RxJava2Adapter.monoToCompletable(placeholder(v)))
.apply(e))),
e ->
RxJava2Adapter.completableToMono(
Completable.wrap(
RxJavaReactorMigrationUtil.<T, Completable>toJdkFunction(
v -> RxJava2Adapter.monoToCompletable(placeholder(v)))
.apply(e))));
}
@AfterTemplate
java.util.function.Function<? super T, ? extends Mono<?>> after() {
return v -> placeholder(v);
}
}
// XXX: Add test
@SuppressWarnings("NoFunctionalReturnType")
abstract static class SingleRemoveLambdaWithCompletable<T> {
@BeforeTemplate
java.util.function.Function<? super T, ? extends Mono<? extends Void>> before(
Completable completable) {
return Refaster.anyOf(
e ->
RxJava2Adapter.completableToMono(
Completable.wrap(
RxJavaReactorMigrationUtil.<T, CompletableSource>toJdkFunction(
(Function<T, CompletableSource>) v -> completable)
.apply(e))),
e ->
RxJava2Adapter.completableToMono(
Completable.wrap(
RxJavaReactorMigrationUtil.<T, CompletableSource>toJdkFunction(
v -> completable)
.apply(e))));
}
@AfterTemplate
java.util.function.Function<? super T, ? extends Mono<? extends Void>> after(
Completable completable) {
return v -> RxJava2Adapter.completableToMono(completable);
}
}
// XXX: Verify if this template still flags other cases than the one above.
@SuppressWarnings("NoFunctionalReturnType")
abstract static class SingleRemoveLambdaWithCompletableExtra<T> {
@Placeholder
abstract Completable placeholder(@MayOptionallyUse T input);
@BeforeTemplate
java.util.function.Function<? super T, ? extends Mono<? extends Void>> before() {
return e ->
RxJava2Adapter.completableToMono(
Completable.wrap(
RxJavaReactorMigrationUtil.<T, CompletableSource>toJdkFunction(
(Function<T, CompletableSource>) v -> placeholder(v))
.apply(e)));
}
@AfterTemplate
java.util.function.Function<? super T, ? extends Mono<? extends Void>> after() {
return v -> RxJava2Adapter.completableToMono(placeholder(v));
}
}
}

View File

@@ -1,11 +1,12 @@
package tech.picnic.errorprone.refastertemplates;
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.Predicate.not;
import static java.util.stream.Collectors.joining;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -18,12 +19,31 @@ import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** Refaster templates related to expressions dealing with {@link Stream}s. */
final class StreamTemplates {
private StreamTemplates() {}
/**
* Prefer {@link Collectors#joining()} over {@link Collectors#joining(CharSequence)} with an empty
* delimiter string.
*/
static final class Joining {
@BeforeTemplate
Collector<CharSequence, ?, String> before() {
return joining("");
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Collector<CharSequence, ?, String> after() {
return joining();
}
}
/** Prefer {@link Stream#empty()} over less clear alternatives. */
static final class EmptyStream<T> {
@BeforeTemplate
@@ -216,7 +236,7 @@ final class StreamTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Optional<T> after(Stream<T> stream) {
return stream.min(naturalOrder());
}
@@ -242,7 +262,7 @@ final class StreamTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Optional<T> after(Stream<T> stream) {
return stream.max(naturalOrder());
}

View File

@@ -14,6 +14,7 @@ import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.Arrays;
import java.util.Collection;
import java.util.Optional;
import javax.annotation.Nullable;
/** Refaster templates related to expressions dealing with {@link String}s. */
// XXX: Should we prefer `s -> !s.isEmpty()` or `not(String::isEmpty)`?
@@ -37,7 +38,7 @@ final class StringTemplates {
/** Prefer {@link Strings#isNullOrEmpty(String)} over the more verbose alternative. */
static final class StringIsNullOrEmpty {
@BeforeTemplate
boolean before(String str) {
boolean before(@Nullable String str) {
return str == null || str.isEmpty();
}

View File

@@ -1,5 +1,6 @@
package tech.picnic.errorprone.refastertemplates;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.fail;
@@ -17,7 +18,6 @@ import static org.testng.Assert.assertTrue;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.DoNotCall;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
@@ -96,7 +96,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(String message) {
fail(message);
}
@@ -110,7 +110,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(String message, Throwable throwable) {
fail(message, throwable);
}
@@ -123,7 +123,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(boolean condition) {
assertThat(condition).isTrue();
}
@@ -136,7 +136,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(boolean condition, String message) {
assertThat(condition).withFailMessage(message).isTrue();
}
@@ -149,7 +149,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(boolean condition) {
assertThat(condition).isFalse();
}
@@ -162,7 +162,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(boolean condition, String message) {
assertThat(condition).withFailMessage(message).isFalse();
}
@@ -175,7 +175,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object object) {
assertThat(object).isNull();
}
@@ -188,7 +188,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object object, String message) {
assertThat(object).withFailMessage(message).isNull();
}
@@ -201,7 +201,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object object) {
assertThat(object).isNotNull();
}
@@ -214,7 +214,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object object, String message) {
assertThat(object).withFailMessage(message).isNotNull();
}
@@ -227,7 +227,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected) {
assertThat(actual).isSameAs(expected);
}
@@ -240,7 +240,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected, String message) {
assertThat(actual).withFailMessage(message).isSameAs(expected);
}
@@ -253,7 +253,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected) {
assertThat(actual).isNotSameAs(expected);
}
@@ -266,7 +266,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected, String message) {
assertThat(actual).withFailMessage(message).isNotSameAs(expected);
}
@@ -329,7 +329,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected) {
assertThat(actual).isEqualTo(expected);
}
@@ -392,7 +392,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected, String message) {
assertThat(actual).withFailMessage(message).isEqualTo(expected);
}
@@ -405,7 +405,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float actual, float expected, float delta) {
assertThat(actual).isCloseTo(expected, offset(delta));
}
@@ -418,7 +418,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float actual, float expected, float delta, String message) {
assertThat(actual).withFailMessage(message).isCloseTo(expected, offset(delta));
}
@@ -431,7 +431,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double actual, double expected, double delta) {
assertThat(actual).isCloseTo(expected, offset(delta));
}
@@ -444,7 +444,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double actual, double expected, double delta, String message) {
assertThat(actual).withFailMessage(message).isCloseTo(expected, offset(delta));
}
@@ -497,7 +497,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object[] actual, Object[] expected) {
assertThat(actual).containsExactly(expected);
}
@@ -550,7 +550,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object[] actual, Object[] expected, String message) {
assertThat(actual).withFailMessage(message).containsExactly(expected);
}
@@ -563,7 +563,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object[] actual, Object[] expected) {
assertThat(actual).containsExactlyInAnyOrder(expected);
}
@@ -576,7 +576,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object[] actual, Object[] expected, String message) {
assertThat(actual).withFailMessage(message).containsExactlyInAnyOrder(expected);
}
@@ -589,7 +589,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
<S, T extends S> void after(Iterator<S> actual, Iterator<T> expected) {
// XXX: This is not `null`-safe.
// XXX: The `ImmutableList.copyOf` should actually *not* be imported statically.
@@ -604,7 +604,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
<S, T extends S> void after(Iterator<S> actual, Iterator<T> expected, String message) {
// XXX: This is not `null`-safe.
// XXX: The `ImmutableList.copyOf` should actually *not* be imported statically.
@@ -629,7 +629,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
<S, T extends S> void after(Iterable<S> actual, Iterable<T> expected) {
assertThat(actual).containsExactlyElementsOf(expected);
}
@@ -647,7 +647,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
<S, T extends S> void after(Iterable<S> actual, Iterable<T> expected, String message) {
assertThat(actual).withFailMessage(message).containsExactlyElementsOf(expected);
}
@@ -660,7 +660,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
<S, T extends S> void after(Set<S> actual, Set<T> expected) {
assertThat(actual).hasSameElementsAs(expected);
}
@@ -673,7 +673,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
<S, T extends S> void after(Set<S> actual, Set<T> expected, String message) {
assertThat(actual).withFailMessage(message).hasSameElementsAs(expected);
}
@@ -741,7 +741,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected) {
assertThat(actual).isNotEqualTo(expected);
}
@@ -809,7 +809,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(Object actual, Object expected, String message) {
assertThat(actual).withFailMessage(message).isNotEqualTo(expected);
}
@@ -822,7 +822,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float actual, float expected, float delta) {
assertThat(actual).isNotCloseTo(expected, offset(delta));
}
@@ -835,7 +835,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float actual, float expected, float delta, String message) {
assertThat(actual).withFailMessage(message).isNotCloseTo(expected, offset(delta));
}
@@ -848,7 +848,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double actual, double expected, double delta) {
assertThat(actual).isNotCloseTo(expected, offset(delta));
}
@@ -861,7 +861,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double actual, double expected, double delta, String message) {
assertThat(actual).withFailMessage(message).isNotCloseTo(expected, offset(delta));
}
@@ -874,7 +874,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(ThrowingCallable runnable) {
assertThatThrownBy(runnable);
}
@@ -887,7 +887,7 @@ final class TestNGToAssertJTemplates {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(ThrowingCallable runnable, Class<T> clazz) {
assertThatThrownBy(runnable).isInstanceOf(clazz);
}

View File

@@ -1,5 +1,7 @@
package tech.picnic.errorprone.refastertemplates;
import static java.time.ZoneOffset.UTC;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation;
@@ -17,6 +19,7 @@ import java.time.ZoneOffset;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.ChronoLocalDateTime;
import java.time.chrono.ChronoZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
/** Refaster templates related to expressions dealing with time. */
@@ -49,13 +52,26 @@ final class TimeTemplates {
ZoneId.of("UTC"),
ZoneId.of("+0"),
ZoneId.of("-0"),
ZoneOffset.UTC.normalized(),
ZoneId.from(ZoneOffset.UTC));
UTC.normalized(),
ZoneId.from(UTC));
}
@AfterTemplate
ZoneOffset after() {
return ZoneOffset.UTC;
return UTC;
}
}
/** Prefer {@link Instant#atOffset(ZoneOffset)} over the more verbose alternative. */
static final class InstantAtOffset {
@BeforeTemplate
OffsetDateTime before(Instant instant, ZoneOffset zoneOffset) {
return OffsetDateTime.ofInstant(instant, zoneOffset);
}
@AfterTemplate
OffsetDateTime after(Instant instant, ZoneOffset zoneOffset) {
return instant.atOffset(zoneOffset);
}
}
@@ -64,7 +80,7 @@ final class TimeTemplates {
@BeforeTemplate
@SuppressWarnings("TimeZoneUsage")
Clock before() {
return Clock.system(ZoneOffset.UTC);
return Clock.system(UTC);
}
@AfterTemplate
@@ -310,8 +326,86 @@ final class TimeTemplates {
}
}
/** Prefer {@link Duration#ofDays(long)} over alternative representations. */
static final class DurationOfDays {
@BeforeTemplate
Duration before(long amount) {
return Duration.of(amount, ChronoUnit.DAYS);
}
@AfterTemplate
Duration after(long amount) {
return Duration.ofDays(amount);
}
}
/** Prefer {@link Duration#ofHours(long)} over alternative representations. */
static final class DurationOfHours {
@BeforeTemplate
Duration before(long amount) {
return Duration.of(amount, ChronoUnit.HOURS);
}
@AfterTemplate
Duration after(long amount) {
return Duration.ofHours(amount);
}
}
/** Prefer {@link Duration#ofMillis(long)} over alternative representations. */
static final class DurationOfMillis {
@BeforeTemplate
Duration before(long amount) {
return Duration.of(amount, ChronoUnit.MILLIS);
}
@AfterTemplate
Duration after(long amount) {
return Duration.ofMillis(amount);
}
}
/** Prefer {@link Duration#ofMinutes(long)} over alternative representations. */
static final class DurationOfMinutes {
@BeforeTemplate
Duration before(long amount) {
return Duration.of(amount, ChronoUnit.MINUTES);
}
@AfterTemplate
Duration after(long amount) {
return Duration.ofMinutes(amount);
}
}
/** Prefer {@link Duration#ofNanos(long)} over alternative representations. */
static final class DurationOfNanos {
@BeforeTemplate
Duration before(long amount) {
return Duration.of(amount, ChronoUnit.NANOS);
}
@AfterTemplate
Duration after(long amount) {
return Duration.ofNanos(amount);
}
}
/** Prefer {@link Duration#ofSeconds(long)} over alternative representations. */
static final class DurationOfSeconds {
@BeforeTemplate
Duration before(long amount) {
return Duration.of(amount, ChronoUnit.SECONDS);
}
@AfterTemplate
Duration after(long amount) {
return Duration.ofSeconds(amount);
}
}
/**
* Don't unnecessarily convert two and from milliseconds. (This way nanosecond precision is
* Don't unnecessarily convert to and from milliseconds. (This way nanosecond precision is
* retained.)
*
* <p><strong>Warning:</strong> this rewrite rule increases precision!
@@ -329,7 +423,7 @@ final class TimeTemplates {
}
/**
* Don't unnecessarily convert two and from milliseconds. (This way nanosecond precision is
* Don't unnecessarily convert to and from milliseconds. (This way nanosecond precision is
* retained.)
*
* <p><strong>Warning:</strong> this rewrite rule increases precision!

View File

@@ -1,12 +1,25 @@
package tech.picnic.errorprone.refastertemplates;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.HEAD;
import static org.springframework.http.HttpMethod.OPTIONS;
import static org.springframework.http.HttpMethod.PATCH;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.http.HttpMethod.PUT;
import static org.springframework.web.reactive.function.BodyInserters.fromValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Repeated;
import java.util.function.Function;
import org.springframework.http.HttpMethod;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec;
import org.springframework.web.reactive.function.client.WebClient.RequestBodyUriSpec;
import org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec;
import org.springframework.web.reactive.function.client.WebClient.RequestHeadersUriSpec;
/**
* Refaster templates related to expressions dealing with {@link
@@ -23,7 +36,7 @@ final class WebClientTemplates {
}
@BeforeTemplate
WebTestClient.RequestHeadersSpec<?> before2(
WebTestClient.RequestHeadersSpec<?> before(
WebTestClient.RequestBodySpec requestBodySpec, T value) {
return requestBodySpec.body(fromValue(value));
}
@@ -33,4 +46,159 @@ final class WebClientTemplates {
return requestBodySpec.bodyValue(value);
}
}
/**
* Prefer {@link WebClient#get()} over {@link WebClient#method(HttpMethod)} with {@link
* HttpMethod#GET}.
*/
static final class WebClientGet {
@BeforeTemplate
RequestHeadersSpec<?> before(WebClient webClient) {
return webClient.method(GET);
}
@BeforeTemplate
WebTestClient.RequestHeadersSpec<?> before(WebTestClient webClient) {
return webClient.method(GET);
}
@AfterTemplate
RequestHeadersSpec<?> after(WebClient webClient) {
return webClient.get();
}
}
/**
* Prefer {@link WebClient#head()} over {@link WebClient#method(HttpMethod)} with {@link
* HttpMethod#HEAD}.
*/
static final class WebClientHead {
@BeforeTemplate
RequestHeadersSpec<?> before(WebClient webClient) {
return webClient.method(HEAD);
}
@BeforeTemplate
WebTestClient.RequestHeadersSpec<?> before(WebTestClient webClient) {
return webClient.method(HEAD);
}
@AfterTemplate
RequestHeadersSpec<?> after(WebClient webClient) {
return webClient.head();
}
}
/**
* Prefer {@link WebClient#options()} over {@link WebClient#method(HttpMethod)} with {@link
* HttpMethod#OPTIONS}.
*/
static final class WebClientOptions {
@BeforeTemplate
RequestHeadersSpec<?> before(WebClient webClient) {
return webClient.method(OPTIONS);
}
@BeforeTemplate
WebTestClient.RequestHeadersSpec<?> before(WebTestClient webClient) {
return webClient.method(OPTIONS);
}
@AfterTemplate
RequestHeadersSpec<?> after(WebClient webClient) {
return webClient.options();
}
}
/**
* Prefer {@link WebClient#patch()} over {@link WebClient#method(HttpMethod)} with {@link
* HttpMethod#PATCH}.
*/
static final class WebClientPatch {
@BeforeTemplate
RequestBodyUriSpec before(WebClient webClient) {
return webClient.method(PATCH);
}
@BeforeTemplate
WebTestClient.RequestBodyUriSpec before(WebTestClient webClient) {
return webClient.method(PATCH);
}
@AfterTemplate
RequestBodyUriSpec after(WebClient webClient) {
return webClient.patch();
}
}
/**
* Prefer {@link WebClient#post()} over {@link WebClient#method(HttpMethod)} with {@link
* HttpMethod#POST}.
*/
static final class WebClientPost {
@BeforeTemplate
RequestBodyUriSpec before(WebClient webClient) {
return webClient.method(POST);
}
@BeforeTemplate
WebTestClient.RequestBodyUriSpec before(WebTestClient webClient) {
return webClient.method(POST);
}
@AfterTemplate
RequestBodyUriSpec after(WebClient webClient) {
return webClient.post();
}
}
/**
* Prefer {@link WebClient#put()} over {@link WebClient#method(HttpMethod)} with {@link
* HttpMethod#PUT}.
*/
static final class WebClientPut {
@BeforeTemplate
RequestBodyUriSpec before(WebClient webClient) {
return webClient.method(PUT);
}
@BeforeTemplate
WebTestClient.RequestBodyUriSpec before(WebTestClient webClient) {
return webClient.method(PUT);
}
@AfterTemplate
RequestBodyUriSpec after(WebClient webClient) {
return webClient.put();
}
}
/** Don't unnecessarily use {@link RequestHeadersUriSpec#uri(Function)}. */
abstract static class RequestHeadersUriSpecUri {
@BeforeTemplate
RequestHeadersSpec<?> before(
RequestHeadersUriSpec<?> requestHeadersUriSpec,
String path,
@Repeated Object uriVariables) {
return requestHeadersUriSpec.uri(
uriBuilder -> uriBuilder.path(path).build(Refaster.asVarargs(uriVariables)));
}
@BeforeTemplate
WebTestClient.RequestHeadersSpec<?> before(
WebTestClient.RequestHeadersUriSpec<?> requestHeadersUriSpec,
String path,
@Repeated Object uriVariables) {
return requestHeadersUriSpec.uri(
uriBuilder -> uriBuilder.path(path).build(Refaster.asVarargs(uriVariables)));
}
@AfterTemplate
RequestHeadersSpec<?> after(
RequestHeadersUriSpec<?> requestHeadersUriSpec,
String path,
@Repeated Object uriVariables) {
return requestHeadersUriSpec.uri(path, Refaster.asVarargs(uriVariables));
}
}
}

View File

@@ -6,14 +6,14 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class AmbiguousJsonCreatorCheckTest {
final class AmbiguousJsonCreatorTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(AmbiguousJsonCreatorCheck.class, getClass())
CompilationTestHelper.newInstance(AmbiguousJsonCreator.class, getClass())
.expectErrorMessage(
"X",
containsPattern("`JsonCreator.Mode` should be set for single-argument creators"));
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(AmbiguousJsonCreatorCheck.class, getClass());
BugCheckerRefactoringTestHelper.newInstance(AmbiguousJsonCreator.class, getClass());
@Test
void identification() {
@@ -112,7 +112,6 @@ final class AmbiguousJsonCreatorCheckTest {
" return new F(s);",
" }",
" }",
"",
"}")
.doTest();
}

View File

@@ -0,0 +1,64 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode.TEXT_MATCH;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class AssertJIsNullTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(AssertJIsNull.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(AssertJIsNull.class, getClass());
@Test
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import static org.assertj.core.api.Assertions.assertThat;",
"",
"class A {",
" void m() {",
" assertThat(1).isEqualTo(1);",
" // BUG: Diagnostic contains:",
" assertThat(1).isEqualTo(null);",
" // BUG: Diagnostic contains:",
" assertThat(\"foo\").isEqualTo(null);",
" isEqualTo(null);",
" }",
"",
" private boolean isEqualTo(Object value) {",
" return value.equals(\"bar\");",
" }",
"}")
.doTest();
}
@Test
void replacement() {
refactoringTestHelper
.addInputLines(
"A.java",
"import static org.assertj.core.api.Assertions.assertThat;",
"",
"class A {",
" void m() {",
" assertThat(1).isEqualTo(null);",
" assertThat(\"foo\").isEqualTo(null);",
" }",
"}")
.addOutputLines(
"A.java",
"import static org.assertj.core.api.Assertions.assertThat;",
"",
"class A {",
" void m() {",
" assertThat(1).isNull();",
" assertThat(\"foo\").isNull();",
" }",
"}")
.doTest(TEXT_MATCH);
}
}

View File

@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
public final class AutowiredConstructorCheckTest {
final class AutowiredConstructorTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(AutowiredConstructorCheck.class, getClass());
CompilationTestHelper.newInstance(AutowiredConstructor.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(AutowiredConstructorCheck.class, getClass());
BugCheckerRefactoringTestHelper.newInstance(AutowiredConstructor.class, getClass());
@Test
void identification() {
@@ -27,27 +27,34 @@ public final class AutowiredConstructorCheckTest {
" }",
"",
" class B {",
" @Autowired void setProperty(Object o) {}",
" @Autowired",
" void setProperty(Object o) {}",
" }",
"",
" class C {",
" // BUG: Diagnostic contains:",
" @Autowired C() {}",
" @Autowired",
" C() {}",
" }",
"",
" class D {",
" // BUG: Diagnostic contains:",
" @Autowired D(String x) {}",
" @Autowired",
" D(String x) {}",
" }",
"",
" class E {",
" @Autowired E() {}",
" @Autowired",
" E() {}",
"",
" E(String x) {}",
" }",
"",
" class F {",
" F() {}",
" @Autowired F(String x) {}",
"",
" @Autowired",
" F(String x) {}",
" }",
"",
" class G {",
@@ -55,7 +62,8 @@ public final class AutowiredConstructorCheckTest {
" }",
"",
" class H {",
" @SafeVarargs H(List<String>... lists) {}",
" @SafeVarargs",
" H(List<String>... lists) {}",
" }",
"}")
.doTest();
@@ -70,11 +78,14 @@ public final class AutowiredConstructorCheckTest {
"",
"interface Container {",
" class A {",
" @Autowired @Deprecated A() {}",
" @Autowired",
" @Deprecated",
" A() {}",
" }",
"",
" class B {",
" @Autowired B(String x) {}",
" @Autowired",
" B(String x) {}",
" }",
"}")
.addOutputLines(
@@ -83,10 +94,13 @@ public final class AutowiredConstructorCheckTest {
"",
"interface Container {",
" class A {",
" @Deprecated A() {}",
"",
" @Deprecated",
" A() {}",
" }",
"",
" class B {",
"",
" B(String x) {}",
" }",
"}")

View File

@@ -1,156 +0,0 @@
package tech.picnic.errorprone.bugpatterns;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
public final class CanonicalAnnotationSyntaxCheckTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(CanonicalAnnotationSyntaxCheck.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(CanonicalAnnotationSyntaxCheck.class, getClass());
@Test
void identification() {
compilationTestHelper
.addSourceLines(
"pkg/A.java",
"package pkg;",
"",
"import pkg.A.Foo;",
"",
"interface A {",
" @interface Foo {",
" int[] value() default {};",
" int[] value2() default {};",
" }",
"",
" @pkg.A.Foo A minimal1();",
" @A.Foo A minimal2();",
" @Foo A minimal3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo() A functional1();",
" // BUG: Diagnostic contains:",
" @A.Foo() A functional2();",
" // BUG: Diagnostic contains:",
" @Foo() A functional3();",
"",
" @pkg.A.Foo(1) A simple1();",
" @A.Foo(1) A simple2();",
" @Foo(1) A simple3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo({1}) A singleton1();",
" // BUG: Diagnostic contains:",
" @A.Foo({1}) A singleton2();",
" // BUG: Diagnostic contains:",
" @Foo({1}) A singleton3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo(value = 1) A verbose1();",
" // BUG: Diagnostic contains:",
" @A.Foo(value = 1) A verbose2();",
" // BUG: Diagnostic contains:",
" @Foo(value = 1) A verbose3();",
"",
" @pkg.A.Foo(value2 = 2) A custom1();",
" @A.Foo(value2 = 2) A custom2();",
" @Foo(value2 = 2) A custom3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo(value2 = {2}) A customSingleton1();",
" // BUG: Diagnostic contains:",
" @A.Foo(value2 = {2}) A customSingleton2();",
" // BUG: Diagnostic contains:",
" @Foo(value2 = {2}) A customSingleton3();",
"",
" @pkg.A.Foo(value2 = {2, 2}) A customPair1();",
" @A.Foo(value2 = {2, 2}) A customPair2();",
" @Foo(value2 = {2, 2}) A customPair3();",
"",
" @pkg.A.Foo(value = 1, value2 = 2) A extended1();",
" @A.Foo(value = 1, value2 = 2) A extended2();",
" @Foo(value = 1, value2 = 2) A extended3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo({1, 1,}) A trailingComma1();",
" // BUG: Diagnostic contains:",
" @A.Foo({1, 1,}) A trailingComma2();",
" // BUG: Diagnostic contains:",
" @Foo({1, 1,}) A trailingComma3();",
"}")
.doTest();
}
@Test
void replacement() {
refactoringTestHelper
.addInputLines(
"in/pkg/A.java",
"package pkg;",
"",
"import pkg.A.Foo;",
"",
"interface A {",
" @interface Foo {",
" String[] value() default {};",
" int[] value2() default {};",
" }",
"",
" @pkg.A.Foo() A functional1();",
" @A.Foo() A functional2();",
" @Foo() A functional3();",
"",
" @pkg.A.Foo(value = \"foo\") A verbose1();",
" @A.Foo(value = \"a'b\") A verbose2();",
" @Foo(value = \"a\" + \"\\nb\") A verbose3();",
"",
" @pkg.A.Foo(value = {\"foo\"}) A moreVerbose1();",
" @A.Foo(value = {\"a'b\"}) A moreVerbose2();",
" @Foo(value = {\"a\" + \"\\nb\"}) A moreVerbose3();",
"",
" @pkg.A.Foo(value = {\"foo\", \"bar\"}, value2 = {2}) A extended1();",
" @A.Foo(value = {\"a'b\", \"c'd\"}, value2 = {2}) A extended2();",
" @Foo(value = {\"a\" + \"\\nb\", \"c\" + \"\\nd\"}, value2 = {2}) A extended3();",
"",
" @pkg.A.Foo({\"foo\", \"bar\",}) A trailingComma1();",
" @A.Foo({\"a'b\", \"c'd\",}) A trailingComma2();",
" @Foo({\"a\" + \"\\nb\", \"c\" + \"\\nd\",}) A trailingComma3();",
"}")
.addOutputLines(
"out/pkg/A.java",
"package pkg;",
"",
"import pkg.A.Foo;",
"",
"interface A {",
" @interface Foo {",
" String[] value() default {};",
" int[] value2() default {};",
" }",
"",
" @pkg.A.Foo A functional1();",
" @A.Foo A functional2();",
" @Foo A functional3();",
"",
" @pkg.A.Foo(\"foo\") A verbose1();",
" @A.Foo(\"a'b\") A verbose2();",
" @Foo(\"a\" + \"\\nb\") A verbose3();",
"",
" @pkg.A.Foo(\"foo\") A moreVerbose1();",
" @A.Foo(\"a'b\") A moreVerbose2();",
" @Foo(\"a\" + \"\\nb\") A moreVerbose3();",
"",
" @pkg.A.Foo(value = {\"foo\", \"bar\"}, value2 = 2) A extended1();",
" @A.Foo(value = {\"a'b\", \"c'd\"}, value2 = 2) A extended2();",
" @Foo(value = {\"a\" + \"\\nb\", \"c\" + \"\\nd\"}, value2 = 2) A extended3();",
"",
" @pkg.A.Foo({\"foo\", \"bar\"}) A trailingComma1();",
" @A.Foo({\"a'b\", \"c'd\"}) A trailingComma2();",
" @Foo({\"a\" + \"\\nb\", \"c\" + \"\\nd\"}) A trailingComma3();",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -0,0 +1,274 @@
package tech.picnic.errorprone.bugpatterns;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class CanonicalAnnotationSyntaxTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(CanonicalAnnotationSyntax.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(CanonicalAnnotationSyntax.class, getClass());
@Test
void identification() {
compilationTestHelper
.addSourceLines(
"pkg/A.java",
"package pkg;",
"",
"import pkg.A.Foo;",
"",
"interface A {",
" @interface Foo {",
" int[] value() default {};",
"",
" int[] value2() default {};",
" }",
"",
" @pkg.A.Foo",
" A minimal1();",
"",
" @A.Foo",
" A minimal2();",
"",
" @Foo",
" A minimal3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo()",
" A functional1();",
" // BUG: Diagnostic contains:",
" @A.Foo()",
" A functional2();",
" // BUG: Diagnostic contains:",
" @Foo()",
" A functional3();",
"",
" @pkg.A.Foo(1)",
" A simple1();",
"",
" @A.Foo(1)",
" A simple2();",
"",
" @Foo(1)",
" A simple3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo({1})",
" A singleton1();",
" // BUG: Diagnostic contains:",
" @A.Foo({1})",
" A singleton2();",
" // BUG: Diagnostic contains:",
" @Foo({1})",
" A singleton3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo(value = 1)",
" A verbose1();",
" // BUG: Diagnostic contains:",
" @A.Foo(value = 1)",
" A verbose2();",
" // BUG: Diagnostic contains:",
" @Foo(value = 1)",
" A verbose3();",
"",
" @pkg.A.Foo(value2 = 2)",
" A custom1();",
"",
" @A.Foo(value2 = 2)",
" A custom2();",
"",
" @Foo(value2 = 2)",
" A custom3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo(value2 = {2})",
" A customSingleton1();",
" // BUG: Diagnostic contains:",
" @A.Foo(value2 = {2})",
" A customSingleton2();",
" // BUG: Diagnostic contains:",
" @Foo(value2 = {2})",
" A customSingleton3();",
"",
" @pkg.A.Foo(value2 = {2, 2})",
" A customPair1();",
"",
" @A.Foo(value2 = {2, 2})",
" A customPair2();",
"",
" @Foo(value2 = {2, 2})",
" A customPair3();",
"",
" @pkg.A.Foo(value = 1, value2 = 2)",
" A extended1();",
"",
" @A.Foo(value = 1, value2 = 2)",
" A extended2();",
"",
" @Foo(value = 1, value2 = 2)",
" A extended3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo({",
" 1, 1,",
" })",
" A trailingComma1();",
" // BUG: Diagnostic contains:",
" @A.Foo({",
" 1, 1,",
" })",
" A trailingComma2();",
" // BUG: Diagnostic contains:",
" @Foo({",
" 1, 1,",
" })",
" A trailingComma3();",
"}")
.doTest();
}
@Test
void replacement() {
refactoringTestHelper
.addInputLines(
"in/pkg/A.java",
"package pkg;",
"",
"import pkg.A.Foo;",
"",
"interface A {",
" @interface Foo {",
" String[] value() default {};",
"",
" int[] value2() default {};",
" }",
"",
" @pkg.A.Foo()",
" A functional1();",
"",
" @A.Foo()",
" A functional2();",
"",
" @Foo()",
" A functional3();",
"",
" @pkg.A.Foo(value = \"foo\")",
" A verbose1();",
"",
" @A.Foo(value = \"a'b\")",
" A verbose2();",
"",
" @Foo(value = \"a\" + \"\\nb\")",
" A verbose3();",
"",
" @pkg.A.Foo(value = {\"foo\"})",
" A moreVerbose1();",
"",
" @A.Foo(value = {\"a'b\"})",
" A moreVerbose2();",
"",
" @Foo(value = {\"a\" + \"\\nb\"})",
" A moreVerbose3();",
"",
" @pkg.A.Foo(",
" value = {\"foo\", \"bar\"},",
" value2 = {2})",
" A extended1();",
"",
" @A.Foo(",
" value = {\"a'b\", \"c'd\"},",
" value2 = {2})",
" A extended2();",
"",
" @Foo(",
" value = {\"a\" + \"\\nb\", \"c\" + \"\\nd\"},",
" value2 = {2})",
" A extended3();",
"",
" @pkg.A.Foo({",
" \"foo\", \"bar\",",
" })",
" A trailingComma1();",
"",
" @A.Foo({",
" \"a'b\", \"c'd\",",
" })",
" A trailingComma2();",
"",
" @Foo({",
" \"a\" + \"\\nb\",",
" \"c\" + \"\\nd\",",
" })",
" A trailingComma3();",
"}")
.addOutputLines(
"out/pkg/A.java",
"package pkg;",
"",
"import pkg.A.Foo;",
"",
"interface A {",
" @interface Foo {",
" String[] value() default {};",
"",
" int[] value2() default {};",
" }",
"",
" @pkg.A.Foo",
" A functional1();",
"",
" @A.Foo",
" A functional2();",
"",
" @Foo",
" A functional3();",
"",
" @pkg.A.Foo(\"foo\")",
" A verbose1();",
"",
" @A.Foo(\"a'b\")",
" A verbose2();",
"",
" @Foo(\"a\" + \"\\nb\")",
" A verbose3();",
"",
" @pkg.A.Foo(\"foo\")",
" A moreVerbose1();",
"",
" @A.Foo(\"a'b\")",
" A moreVerbose2();",
"",
" @Foo(\"a\" + \"\\nb\")",
" A moreVerbose3();",
"",
" @pkg.A.Foo(",
" value = {\"foo\", \"bar\"},",
" value2 = 2)",
" A extended1();",
"",
" @A.Foo(",
" value = {\"a'b\", \"c'd\"},",
" value2 = 2)",
" A extended2();",
"",
" @Foo(",
" value = {\"a\" + \"\\nb\", \"c\" + \"\\nd\"},",
" value2 = 2)",
" A extended3();",
"",
" @pkg.A.Foo({\"foo\", \"bar\"})",
" A trailingComma1();",
"",
" @A.Foo({\"a'b\", \"c'd\"})",
" A trailingComma2();",
"",
" @Foo({\"a\" + \"\\nb\", \"c\" + \"\\nd\"})",
" A trailingComma3();",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -0,0 +1,200 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers.SECOND;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class CollectorMutabilityTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(CollectorMutability.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(CollectorMutability.class, getClass());
@Test
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import static com.google.common.collect.ImmutableList.toImmutableList;",
"import static com.google.common.collect.ImmutableMap.toImmutableMap;",
"import static com.google.common.collect.ImmutableSet.toImmutableSet;",
"import static java.util.stream.Collectors.toCollection;",
"import static java.util.stream.Collectors.toList;",
"import static java.util.stream.Collectors.toMap;",
"import static java.util.stream.Collectors.toSet;",
"",
"import java.util.ArrayList;",
"import java.util.HashMap;",
"import java.util.HashSet;",
"import java.util.stream.Collectors;",
"import java.util.stream.Stream;",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" // BUG: Diagnostic contains:",
" Flux.just(1).collect(Collectors.toList());",
" // BUG: Diagnostic contains:",
" Flux.just(2).collect(toList());",
" Flux.just(3).collect(toImmutableList());",
" Flux.just(4).collect(toCollection(ArrayList::new));",
"",
" // BUG: Diagnostic contains:",
" Flux.just(\"foo\").collect(Collectors.toMap(String::getBytes, String::length));",
" // BUG: Diagnostic contains:",
" Flux.just(\"bar\").collect(toMap(String::getBytes, String::length));",
" Flux.just(\"baz\").collect(toImmutableMap(String::getBytes, String::length));",
" // BUG: Diagnostic contains:",
" Flux.just(\"qux\").collect(toMap(String::getBytes, String::length, (a, b) -> a));",
" Flux.just(\"quux\").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> a));",
" Flux.just(\"quuz\").collect(toMap(String::getBytes, String::length, (a, b) -> a, HashMap::new));",
"",
" // BUG: Diagnostic contains:",
" Stream.of(1).collect(Collectors.toSet());",
" // BUG: Diagnostic contains:",
" Stream.of(2).collect(toSet());",
" Stream.of(3).collect(toImmutableSet());",
" Stream.of(4).collect(toCollection(HashSet::new));",
"",
" Flux.just(\"foo\").collect(Collectors.joining());",
" }",
"}")
.doTest();
}
@Test
void replacementFirstSuggestedFix() {
refactoringTestHelper
.addInputLines(
"A.java",
"import static java.util.stream.Collectors.toList;",
"import static java.util.stream.Collectors.toMap;",
"import static java.util.stream.Collectors.toSet;",
"",
"import java.util.stream.Collectors;",
"import java.util.stream.Stream;",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).collect(Collectors.toList());",
" Flux.just(2).collect(toList());",
"",
" Stream.of(\"foo\").collect(Collectors.toMap(String::getBytes, String::length));",
" Stream.of(\"bar\").collect(toMap(String::getBytes, String::length));",
" Flux.just(\"baz\").collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b));",
" Flux.just(\"qux\").collect(toMap(String::getBytes, String::length, (a, b) -> b));",
"",
" Stream.of(1).collect(Collectors.toSet());",
" Stream.of(2).collect(toSet());",
" }",
"}")
.addOutputLines(
"A.java",
"import static com.google.common.collect.ImmutableList.toImmutableList;",
"import static com.google.common.collect.ImmutableMap.toImmutableMap;",
"import static com.google.common.collect.ImmutableSet.toImmutableSet;",
"import static java.util.stream.Collectors.toList;",
"import static java.util.stream.Collectors.toMap;",
"import static java.util.stream.Collectors.toSet;",
"",
"import java.util.stream.Collectors;",
"import java.util.stream.Stream;",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).collect(toImmutableList());",
" Flux.just(2).collect(toImmutableList());",
"",
" Stream.of(\"foo\").collect(toImmutableMap(String::getBytes, String::length));",
" Stream.of(\"bar\").collect(toImmutableMap(String::getBytes, String::length));",
" Flux.just(\"baz\").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> b));",
" Flux.just(\"qux\").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> b));",
"",
" Stream.of(1).collect(toImmutableSet());",
" Stream.of(2).collect(toImmutableSet());",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
@Test
void replacementSecondSuggestedFix() {
refactoringTestHelper
.setFixChooser(SECOND)
.addInputLines(
"A.java",
"import static java.util.stream.Collectors.toList;",
"import static java.util.stream.Collectors.toMap;",
"import static java.util.stream.Collectors.toSet;",
"",
"import java.util.stream.Collectors;",
"import java.util.stream.Stream;",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).collect(Collectors.toList());",
" Flux.just(2).collect(toList());",
"",
" Stream.of(\"foo\").collect(Collectors.toMap(String::getBytes, String::length));",
" Stream.of(\"bar\").collect(toMap(String::getBytes, String::length));",
" Flux.just(\"baz\").collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b));",
" Flux.just(\"qux\").collect(toMap(String::getBytes, String::length, (a, b) -> b));",
"",
" Stream.of(1).collect(Collectors.toSet());",
" Stream.of(2).collect(toSet());",
" }",
"}")
.addOutputLines(
"A.java",
"import static java.util.stream.Collectors.toCollection;",
"import static java.util.stream.Collectors.toList;",
"import static java.util.stream.Collectors.toMap;",
"import static java.util.stream.Collectors.toSet;",
"",
"import java.util.ArrayList;",
"import java.util.HashMap;",
"import java.util.HashSet;",
"import java.util.stream.Collectors;",
"import java.util.stream.Stream;",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).collect(toCollection(ArrayList::new));",
" Flux.just(2).collect(toCollection(ArrayList::new));",
"",
" Stream.of(\"foo\")",
" .collect(",
" Collectors.toMap(",
" String::getBytes,",
" String::length,",
" (a, b) -> {",
" throw new IllegalStateException();",
" },",
" HashMap::new));",
" Stream.of(\"bar\")",
" .collect(",
" toMap(",
" String::getBytes,",
" String::length,",
" (a, b) -> {",
" throw new IllegalStateException();",
" },",
" HashMap::new));",
" Flux.just(\"baz\")",
" .collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b, HashMap::new));",
" Flux.just(\"qux\").collect(toMap(String::getBytes, String::length, (a, b) -> b, HashMap::new));",
"",
" Stream.of(1).collect(toCollection(HashSet::new));",
" Stream.of(2).collect(toCollection(HashSet::new));",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
public final class EmptyMethodCheckTest {
final class EmptyMethodTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(EmptyMethodCheck.class, getClass());
CompilationTestHelper.newInstance(EmptyMethod.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(EmptyMethodCheck.class, getClass());
BugCheckerRefactoringTestHelper.newInstance(EmptyMethod.class, getClass());
@Test
void identification() {

View File

@@ -0,0 +1,151 @@
package tech.picnic.errorprone.bugpatterns;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class ErrorProneTestHelperSourceFormatTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(ErrorProneTestHelperSourceFormat.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(
ErrorProneTestHelperSourceFormat.class, getClass());
@Test
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;",
"import com.google.errorprone.CompilationTestHelper;",
"import tech.picnic.errorprone.bugpatterns.EmptyMethod;",
"",
"class A {",
" private final CompilationTestHelper compilationTestHelper =",
" CompilationTestHelper.newInstance(EmptyMethod.class, getClass());",
" private final BugCheckerRefactoringTestHelper refactoringTestHelper =",
" BugCheckerRefactoringTestHelper.newInstance(EmptyMethod.class, getClass());",
"",
" void m() {",
" compilationTestHelper",
" // BUG: Diagnostic contains: No source code provided",
" .addSourceLines(\"A.java\")",
" // BUG: Diagnostic contains: Source code is malformed:",
" .addSourceLines(\"B.java\", \"class B {\")",
" // Well-formed code, so not flagged.",
" .addSourceLines(\"C.java\", \"class C {}\")",
" // Malformed code, but not compile-time constant, so not flagged.",
" .addSourceLines(\"D.java\", \"class D {\" + getClass())",
" // BUG: Diagnostic contains: Test code should follow the Google Java style",
" .addSourceLines(\"E.java\", \"class E { }\")",
" .doTest();",
"",
" refactoringTestHelper",
" // BUG: Diagnostic contains: Test code should follow the Google Java style",
" .addInputLines(\"in/A.java\", \"class A { }\")",
" // BUG: Diagnostic contains: Test code should follow the Google Java style",
" .addOutputLines(\"out/A.java\", \"class A { }\")",
" // BUG: Diagnostic contains: Test code should follow the Google Java style",
" .addInputLines(\"in/B.java\", \"import java.util.Map;\", \"\", \"class B {}\")",
" // Unused import, but in an output file, so not flagged.",
" .addOutputLines(\"out/B.java\", \"import java.util.Map;\", \"\", \"class B {}\")",
" .doTest(TestMode.TEXT_MATCH);",
" }",
"}")
.doTest();
}
@Test
void replacement() {
/*
* Verifies that import sorting and code formatting is performed unconditionally, while unused
* imports are removed unless part of a `BugCheckerRefactoringTestHelper` expected output file.
*/
refactoringTestHelper
.addInputLines(
"in/A.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;",
"import com.google.errorprone.CompilationTestHelper;",
"import tech.picnic.errorprone.bugpatterns.EmptyMethod;",
"",
"class A {",
" private final CompilationTestHelper compilationTestHelper =",
" CompilationTestHelper.newInstance(EmptyMethod.class, getClass());",
" private final BugCheckerRefactoringTestHelper refactoringTestHelper =",
" BugCheckerRefactoringTestHelper.newInstance(EmptyMethod.class, getClass());",
"",
" void m() {",
" compilationTestHelper",
" .addSourceLines(",
" \"A.java\",",
" \"import java.util.Map;\",",
" \"import java.util.Collection;\",",
" \"import java.util.List;\",",
" \"\",",
" \"interface A extends List<A>, Map<A,A> { }\")",
" .doTest();",
"",
" refactoringTestHelper",
" .addInputLines(",
" \"in/A.java\",",
" \"import java.util.Map;\",",
" \"import java.util.Collection;\",",
" \"import java.util.List;\",",
" \"\",",
" \"interface A extends List<A>, Map<A,A> { }\")",
" .addOutputLines(",
" \"out/A.java\",",
" \"import java.util.Map;\",",
" \"import java.util.Collection;\",",
" \"import java.util.List;\",",
" \"\",",
" \"interface A extends List<A>, Map<A,A> { }\")",
" .doTest(TestMode.TEXT_MATCH);",
" }",
"}")
.addOutputLines(
"out/A.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;",
"import com.google.errorprone.CompilationTestHelper;",
"import tech.picnic.errorprone.bugpatterns.EmptyMethod;",
"",
"class A {",
" private final CompilationTestHelper compilationTestHelper =",
" CompilationTestHelper.newInstance(EmptyMethod.class, getClass());",
" private final BugCheckerRefactoringTestHelper refactoringTestHelper =",
" BugCheckerRefactoringTestHelper.newInstance(EmptyMethod.class, getClass());",
"",
" void m() {",
" compilationTestHelper",
" .addSourceLines(",
" \"A.java\",",
" \"import java.util.List;\",",
" \"import java.util.Map;\",",
" \"\",",
" \"interface A extends List<A>, Map<A, A> {}\")",
" .doTest();",
"",
" refactoringTestHelper",
" .addInputLines(",
" \"in/A.java\",",
" \"import java.util.List;\",",
" \"import java.util.Map;\",",
" \"\",",
" \"interface A extends List<A>, Map<A, A> {}\")",
" .addOutputLines(",
" \"out/A.java\",",
" \"import java.util.Collection;\",",
" \"import java.util.List;\",",
" \"import java.util.Map;\",",
" \"\",",
" \"interface A extends List<A>, Map<A, A> {}\")",
" .doTest(TestMode.TEXT_MATCH);",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -3,23 +3,23 @@ package tech.picnic.errorprone.bugpatterns;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class ExplicitEnumOrderingCheckTest {
final class ExplicitEnumOrderingTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(ExplicitEnumOrderingCheck.class, getClass());
CompilationTestHelper.newInstance(ExplicitEnumOrdering.class, getClass());
@Test
void Identification() {
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import static java.lang.annotation.RetentionPolicy.SOURCE;",
"import static java.lang.annotation.RetentionPolicy.CLASS;",
"import static java.lang.annotation.RetentionPolicy.RUNTIME;",
"import static java.lang.annotation.RetentionPolicy.SOURCE;",
"import static java.time.chrono.IsoEra.BCE;",
"import static java.time.chrono.IsoEra.CE;",
"",
"import com.google.common.collect.Ordering;",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.Ordering;",
"import java.lang.annotation.RetentionPolicy;",
"import java.time.chrono.IsoEra;",
"",

View File

@@ -0,0 +1,122 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugCheckerRefactoringTestHelper.newInstance;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class FluxFlatMapUsageTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(FluxFlatMapUsage.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
newInstance(FluxFlatMapUsage.class, getClass());
@Test
void identification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import java.util.function.BiFunction;",
"import java.util.function.Function;",
"import reactor.core.publisher.Flux;",
"import reactor.core.publisher.Mono;",
"",
"class A {",
" void m() {",
" // BUG: Diagnostic contains:",
" Flux.just(1).flatMap(Flux::just);",
" // BUG: Diagnostic contains:",
" Flux.just(1).<String>flatMap(i -> Flux.just(String.valueOf(i)));",
" // BUG: Diagnostic contains:",
" Flux.just(1).flatMapSequential(Flux::just);",
" // BUG: Diagnostic contains:",
" Flux.just(1).<String>flatMapSequential(i -> Flux.just(String.valueOf(i)));",
"",
" Mono.just(1).flatMap(Mono::just);",
" Flux.just(1).concatMap(Flux::just);",
"",
" Flux.just(1).flatMap(Flux::just, 1);",
" Flux.just(1).flatMap(Flux::just, 1, 1);",
" Flux.just(1).flatMap(Flux::just, throwable -> Flux.empty(), Flux::empty);",
"",
" Flux.just(1).flatMapSequential(Flux::just, 1);",
" Flux.just(1).flatMapSequential(Flux::just, 1, 1);",
"",
" // BUG: Diagnostic contains:",
" this.<String, Flux<String>>sink(Flux::flatMap);",
" // BUG: Diagnostic contains:",
" this.<Integer, Flux<Integer>>sink(Flux::<Integer>flatMap);",
"",
" // BUG: Diagnostic contains:",
" this.<String, Flux<String>>sink(Flux::flatMapSequential);",
" // BUG: Diagnostic contains:",
" this.<Integer, Flux<Integer>>sink(Flux::<Integer>flatMapSequential);",
"",
" this.<String, Mono<String>>sink(Mono::flatMap);",
" }",
"",
" private <T, P> void sink(BiFunction<P, Function<T, P>, P> fun) {}",
"}")
.doTest();
}
@Test
void replacementFirstSuggestedFix() {
refactoringTestHelper
.setFixChooser(FixChoosers.FIRST)
.addInputLines(
"in/A.java",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).flatMap(Flux::just);",
" Flux.just(1).flatMapSequential(Flux::just);",
" }",
"}")
.addOutputLines(
"out/A.java",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).concatMap(Flux::just);",
" Flux.just(1).concatMap(Flux::just);",
" }",
"}")
.doTest();
}
@Test
void replacementSecondSuggestedFix() {
refactoringTestHelper
.setFixChooser(FixChoosers.SECOND)
.addInputLines(
"in/A.java",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" private static final int MAX_CONCURRENCY = 8;",
"",
" void m() {",
" Flux.just(1).flatMap(Flux::just);",
" Flux.just(1).flatMapSequential(Flux::just);",
" }",
"}")
.addOutputLines(
"out/A.java",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" private static final int MAX_CONCURRENCY = 8;",
"",
" void m() {",
" Flux.just(1).flatMap(Flux::just, MAX_CONCURRENCY);",
" Flux.just(1).flatMapSequential(Flux::just, MAX_CONCURRENCY);",
" }",
"}")
.doTest();
}
}

View File

@@ -5,11 +5,11 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
public final class FormatStringConcatenationCheckTest {
final class FormatStringConcatenationTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(FormatStringConcatenationCheck.class, getClass());
CompilationTestHelper.newInstance(FormatStringConcatenation.class, getClass());
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(FormatStringConcatenationCheck.class, getClass());
BugCheckerRefactoringTestHelper.newInstance(FormatStringConcatenation.class, getClass());
@Test
void identification() {
@@ -23,8 +23,8 @@ public final class FormatStringConcatenationCheckTest {
"import static org.assertj.core.api.Assertions.assertThat;",
"import static org.assertj.core.api.SoftAssertions.assertSoftly;",
"",
"import java.util.Locale;",
"import java.util.Formatter;",
"import java.util.Locale;",
"import org.assertj.core.api.Assertions;",
"import org.assertj.core.api.BDDAssertions;",
"import org.assertj.core.api.Fail;",
@@ -269,9 +269,9 @@ public final class FormatStringConcatenationCheckTest {
" LOG.error(\"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.error((Marker) null,\"str \" + toString());",
" LOG.error((Marker) null, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" LOG.error((Marker) null,\"{} \" + toString(), \"arg\");",
" LOG.error((Marker) null, \"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.info(\"str \" + toString());",
@@ -279,9 +279,9 @@ public final class FormatStringConcatenationCheckTest {
" LOG.info(\"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.info((Marker) null,\"str \" + toString());",
" LOG.info((Marker) null, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" LOG.info((Marker) null,\"{} \" + toString(), \"arg\");",
" LOG.info((Marker) null, \"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.trace(\"str \" + toString());",
@@ -289,9 +289,9 @@ public final class FormatStringConcatenationCheckTest {
" LOG.trace(\"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.trace((Marker) null,\"str \" + toString());",
" LOG.trace((Marker) null, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" LOG.trace((Marker) null,\"{} \" + toString(), \"arg\");",
" LOG.trace((Marker) null, \"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.warn(\"str \" + toString());",
@@ -299,9 +299,9 @@ public final class FormatStringConcatenationCheckTest {
" LOG.warn(\"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.warn((Marker) null,\"str \" + toString());",
" LOG.warn((Marker) null, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" LOG.warn((Marker) null,\"{} \" + toString(), \"arg\");",
" LOG.warn((Marker) null, \"{} \" + toString(), \"arg\");",
" }",
"}")
.doTest();
@@ -316,7 +316,6 @@ public final class FormatStringConcatenationCheckTest {
"import static org.assertj.core.api.Assertions.assertThat;",
"",
"import java.util.Locale;",
"import java.util.Formatter;",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"import org.slf4j.Marker;",
@@ -366,7 +365,6 @@ public final class FormatStringConcatenationCheckTest {
"import static org.assertj.core.api.Assertions.assertThat;",
"",
"import java.util.Locale;",
"import java.util.Formatter;",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"import org.slf4j.Marker;",
@@ -400,6 +398,7 @@ public final class FormatStringConcatenationCheckTest {
" String.format(\"{} \" + toString(), \"arg\");",
" String.format(Locale.ROOT, \"{} \" + toString(), \"arg\");",
" }",
"",
" void slf4j() {",
" LOG.debug(\"str {}\", toString());",
" LOG.debug((Marker) null, \"str {}\", toString());",

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