Compare commits

..

166 Commits

Author SHA1 Message Date
jetbrains-junie[bot]
03b36a01c7 feat(junie): added .devcontainer.json 2025-06-02 21:53:18 +00:00
jetbrains-junie[bot]
401b7f5f67 feat(junie): added .junie workflow 2025-06-02 21:53:17 +00:00
Picnic-DevPla-Bot
411066bedb Upgrade Project Reactor 2024.0.4 -> 2024.0.5 (#1643)
See:
- https://github.com/reactor/reactor/releases/tag/2024.0.5
- https://github.com/reactor/reactor/compare/2024.0.4...2024.0.5
2025-04-16 15:40:44 +02:00
Picnic-DevPla-Bot
bedf588e2a Upgrade Micrometer 1.14.5 -> 1.14.6 (#1641)
See:
- https://github.com/micrometer-metrics/micrometer/releases/tag/v1.14.6
- https://github.com/micrometer-metrics/micrometer/compare/v1.14.5...v1.14.6
2025-04-16 09:24:00 +02:00
Stephan Schroevers
3a629b11ec Update Error Prone compatibility matrix (#1642) 2025-04-16 08:23:54 +02:00
Stephan Schroevers
fc2eb57b40 [maven-release-plugin] prepare for next development iteration 2025-04-14 11:36:15 +02:00
Stephan Schroevers
1c429f0d1c [maven-release-plugin] prepare release v0.22.0 2025-04-14 11:36:15 +02:00
Mohamed Sameh
ac6ffc72e9 Avoid invalid ExplicitArgumentEnumeration suggestions (#1637)
While still imperfect, this change improves the heuristics that 
determine whether an explicit `Iterable` creator invocation can be 
unwrapped, such that the enumerated values will be passed to a 
compatible varargs overload instead. The new logic validates that the
overload accepts values of the appropriate type.
2025-04-14 11:33:20 +02:00
Picnic-DevPla-Bot
07399bb4ef Upgrade Guava 33.4.0-jre -> 33.4.7-jre (#1598)
See:
- https://guava.dev/releases/33.4.7-jre/api/diffs/
- https://github.com/google/guava/releases/tag/v33.4.1
- https://github.com/google/guava/releases/tag/v33.4.2
- https://github.com/google/guava/releases/tag/v33.4.3
- https://github.com/google/guava/releases/tag/v33.4.4
- https://github.com/google/guava/releases/tag/v33.4.5
- https://github.com/google/guava/releases/tag/v33.4.6
- https://github.com/google/guava/releases/tag/v33.4.7
- https://github.com/google/guava/compare/v33.4.0...v33.4.7
2025-04-14 10:22:02 +02:00
Stephan Schroevers
aa988ef2b0 Run NullAway in JSpecify mode (#1608) 2025-04-14 09:42:16 +02:00
Picnic-DevPla-Bot
b58be2b89b Upgrade NullAway 0.12.5 -> 0.12.6 (#1616)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.12.6
- https://github.com/uber/NullAway/compare/v0.12.5...v0.12.6
2025-04-14 09:42:16 +02:00
Picnic-DevPla-Bot
8fa90f6121 Upgrade Swagger 2.2.29 -> 2.2.30 (#1633)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.30
- https://github.com/swagger-api/swagger-core/compare/v2.2.29...v2.2.30
2025-04-14 08:02:35 +02:00
Picnic-DevPla-Bot
6ba03c6352 Upgrade AspectJ 1.9.23 -> 1.9.24 (#1638)
See:
- https://github.com/eclipse-aspectj/aspectj/releases/tag/V1_9_24
- https://github.com/eclipse/org.aspectj/compare/V1_9_23...V1_9_24
2025-04-13 23:48:40 +02:00
Picnic-DevPla-Bot
912e06885d Upgrade JUnit 5 5.12.1 -> 5.12.2 (#1639)
See:
- https://junit.org/junit5/docs/current/release-notes/
- https://github.com/junit-team/junit5/releases/tag/r5.12.2
- https://github.com/junit-team/junit5/compare/r5.12.1...r5.12.2
2025-04-13 21:09:28 +02:00
Picnic-DevPla-Bot
e803a5d333 Upgrade OpenRewrite Templating 1.24.2 -> 1.25.1 (#1636)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.25.0
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.25.1
- https://github.com/openrewrite/rewrite-templating/compare/v1.24.2...v1.25.1
2025-04-12 10:41:29 +02:00
Picnic-DevPla-Bot
4a1ad1b991 Upgrade OpenRewrite 3.5.0 -> 3.6.1 (#1635)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v3.6.0
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v3.6.1
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v3.5.0...v3.6.1
2025-04-12 10:19:46 +02:00
Picnic-DevPla-Bot
80d433f051 Upgrade pitest-maven-plugin 1.19.0 -> 1.19.1 (#1634)
See:
- https://github.com/hcoles/pitest/releases/tag/1.19.1
- https://github.com/hcoles/pitest/compare/1.19.0...1.19.1
2025-04-10 10:37:37 +02:00
Stephan Schroevers
afd9703ce6 Extend EnumerableAssertHasSameSizeAs Refaster rule (#1632) 2025-04-07 12:48:46 +02:00
Picnic-DevPla-Bot
f9d310bc4b Upgrade Pitest Git plugins 2.2.0 -> 2.2.1 (#1618) 2025-04-07 10:16:56 +02:00
Picnic-DevPla-Bot
a3a9ca0bf0 Upgrade step-security/harden-runner v2.11.0 -> v2.11.1 (#1625)
See:
- https://github.com/step-security/harden-runner/releases/tag/v2.11.1
2025-04-07 09:57:11 +02:00
Picnic-DevPla-Bot
0e609aeb1c Upgrade Checker Framework Annotations 3.49.1 -> 3.49.2 (#1627)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.49.2
- https://github.com/typetools/checker-framework/compare/checker-framework-3.49.1...checker-framework-3.49.2
2025-04-07 09:16:29 +02:00
Picnic-DevPla-Bot
e9dae1d66c Upgrade Checkstyle 10.22.0 -> 10.23.0 (#1629)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.23.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.22.0...checkstyle-10.23.0
2025-04-07 09:02:09 +02:00
Picnic-DevPla-Bot
f0ad9d21e6 Upgrade Google Java Format 1.25.2 -> 1.26.0 (#1619)
See:
- https://github.com/google/google-java-format/releases/tag/v1.26.0
- https://github.com/google/google-java-format/compare/v1.25.2...v1.26.0
2025-04-07 08:02:37 +02:00
Picnic-DevPla-Bot
7138aa2100 Upgrade extra-enforcer-rules 1.9.0 -> 1.10.0 (#1626)
See:
- https://github.com/mojohaus/extra-enforcer-rules/releases/tag/extra-enforcer-rules-1.10.0
- https://github.com/mojohaus/extra-enforcer-rules/compare/1.9.0...extra-enforcer-rules-1.10.0
2025-04-06 21:59:19 +02:00
Picnic-DevPla-Bot
de4667628f Upgrade OpenRewrite 3.4.0 -> 3.5.0 (#1620)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v3.5.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v3.4.0...v3.5.0
2025-04-06 18:21:40 +02:00
Picnic-DevPla-Bot
5e958fe20b Upgrade Forbidden APIs plugin 3.8 -> 3.9 (#1630)
See:
- https://github.com/policeman-tools/forbidden-apis/wiki/Changes
- https://github.com/policeman-tools/forbidden-apis/compare/3.8...3.9
2025-04-06 17:28:38 +02:00
Picnic-DevPla-Bot
baa921caac Upgrade Mockito 5.16.1 -> 5.17.0 (#1631)
See:
- https://github.com/mockito/mockito/releases/tag/v5.17.0
- https://github.com/mockito/mockito/compare/v5.16.1...v5.17.0
2025-04-06 16:55:07 +02:00
Picnic-DevPla-Bot
ba040bd191 Upgrade Byte Buddy 1.17.4 -> 1.17.5 (#1624)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.17.5
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.17.4...byte-buddy-1.17.5
2025-04-06 11:22:24 +02:00
Picnic-DevPla-Bot
a3a20b52e5 Upgrade jacoco-maven-plugin 0.8.12 -> 0.8.13 (#1628)
See:
- https://github.com/jacoco/jacoco/releases/tag/v0.8.13
- https://github.com/jacoco/jacoco/compare/v0.8.12...v0.8.13
2025-04-04 13:58:35 +02:00
Picnic-DevPla-Bot
5d8d27176b Upgrade sonar-maven-plugin 5.0.0.4389 -> 5.1.0.4751 (#1614)
See:
- https://github.com/SonarSource/sonar-scanner-maven/releases/tag/5.1.0.4751
- https://github.com/SonarSource/sonar-scanner-maven/compare/5.0.0.4389...5.1.0.4751
2025-04-02 14:25:42 +02:00
Picnic-DevPla-Bot
d878a57a8e Upgrade OpenRewrite Templating 1.24.1 -> 1.24.2 (#1617)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.24.2
- https://github.com/openrewrite/rewrite-templating/compare/v1.24.1...v1.24.2
2025-04-01 09:12:07 +02:00
Picnic-DevPla-Bot
eaec12f460 Upgrade Checkstyle 10.21.4 -> 10.22.0 (#1623)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.22.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.21.4...checkstyle-10.22.0
2025-03-31 21:17:40 +02:00
Picnic-DevPla-Bot
da7dafb6e7 Upgrade Surefire 3.5.2 -> 3.5.3 (#1622)
See:
- https://github.com/apache/maven-surefire/releases/tag/maven-surefire-3.5.3
- https://github.com/apache/maven-surefire/compare/surefire-3.5.2...maven-surefire-3.5.3
2025-03-31 11:38:52 +02:00
Picnic-DevPla-Bot
5a7aaf12d6 Upgrade NullAway 0.12.4 -> 0.12.5 (#1615)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.12.5
- https://github.com/uber/NullAway/compare/v0.12.4...v0.12.5
2025-03-27 14:08:05 +01:00
Stephan Schroevers
92e4d74e4b Update Error Prone compatibility matrix (#1613) 2025-03-25 18:56:11 +01:00
Stephan Schroevers
4a0bc0c210 [maven-release-plugin] prepare for next development iteration 2025-03-24 11:41:07 +01:00
Stephan Schroevers
53152499d6 [maven-release-plugin] prepare release v0.21.0 2025-03-24 11:41:07 +01:00
Picnic-DevPla-Bot
61d92fb33f Upgrade CodeQL v3.28.10 -> v3.28.12 (#1611)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/releases/tag/v3.28.11
- https://github.com/github/codeql-action/releases/tag/v3.28.12
- https://github.com/github/codeql-action/compare/v3.28.10...v3.28.12
2025-03-24 10:44:45 +01:00
Picnic-DevPla-Bot
8690f49c35 Upgrade Byte Buddy 1.17.3 -> 1.17.4 (#1610)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.17.4
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.17.3...byte-buddy-1.17.4
2025-03-24 10:30:40 +01:00
Picnic-DevPla-Bot
d808f664ec Upgrade ruby/setup-ruby v1.221.0 -> v1.227.0 (#1612)
See:
- https://github.com/ruby/setup-ruby/releases/tag/v1.227.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.226.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.225.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.224.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.223.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.222.0
2025-03-24 09:39:01 +01:00
Picnic-DevPla-Bot
7f5f4820e9 Upgrade Pitest Git plugins 2.1.0 -> 2.2.0 (#1607) 2025-03-23 17:54:05 +01:00
Picnic-DevPla-Bot
f7a4427852 Upgrade Arcmutate 1.3.2 -> 1.4.0 (#1606) 2025-03-23 17:24:51 +01:00
Picnic-DevPla-Bot
0e956bcd44 Upgrade MongoDB driver 5.3.1 -> 5.4.0 (#1605)
See:
- https://jira.mongodb.org/issues/?jql=project%20%3D%20JAVA%20AND%20fixVersion%20%3E%205.3.1%20AND%20fixVersion%20%3C%3D%205.4.0
- https://github.com/mongodb/mongo-java-driver/releases/tag/r5.4.0-alpha0
- https://github.com/mongodb/mongo-java-driver/releases/tag/r5.4.0
- https://github.com/mongodb/mongo-java-driver/compare/r5.3.1...r5.4.0
2025-03-23 15:53:47 +01:00
Picnic-DevPla-Bot
5395fc60e1 Upgrade Spring Boot 3.4.3 -> 3.4.4 (#1604)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v3.4.4
- https://github.com/spring-projects/spring-boot/compare/v3.4.3...v3.4.4
2025-03-23 15:13:32 +01:00
Picnic-DevPla-Bot
d8cae04a98 Upgrade Byte Buddy 1.17.2 -> 1.17.3 (#1603)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.17.3
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.17.2...byte-buddy-1.17.3
2025-03-23 11:59:48 +01:00
Julian Broudy
7b14711ecf Extend FluxJust Refaster rule (#1581) 2025-03-23 11:26:19 +01:00
Tim te Beek
c3351b9ee1 Introduce two FileRules Refaster rules (#1596)
Invoking `File#mkdirs` before testing for existence of the specified
path, rather than the other way around, avoids a subtle concurrency
issue.

See also openrewrite/rewrite#5189.
2025-03-23 11:13:24 +01:00
Picnic-DevPla-Bot
40b3c87b72 Upgrade Spring 6.2.4 -> 6.2.5 (#1602)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.5
- https://github.com/spring-projects/spring-framework/compare/v6.2.4...v6.2.5
2025-03-22 12:54:04 +01:00
Picnic-DevPla-Bot
726db5ce5b Upgrade Error Prone 2.36.0 -> 2.37.0 (#1601)
Resolves #1597.

See:
- https://github.com/google/error-prone/releases/tag/v2.37.0
- https://github.com/google/error-prone/compare/v2.36.0...v2.37.0
- https://github.com/PicnicSupermarket/error-prone/compare/v2.36.0-picnic-4...v2.37.0-picnic-1
2025-03-21 09:47:13 +01:00
Picnic-DevPla-Bot
99d359c548 Upgrade OpenRewrite Templating 1.24.0 -> 1.24.1 (#1599)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.24.1
- https://github.com/openrewrite/rewrite-templating/compare/v1.24.0...v1.24.1
2025-03-20 16:42:24 +01:00
Picnic-DevPla-Bot
4744113411 Upgrade actions/upload-artifact v4.6.1 -> v4.6.2 (#1600)
See:
- https://github.com/actions/upload-artifact/releases/tag/v4.6.2
2025-03-20 12:40:33 +01:00
Picnic-DevPla-Bot
ae8f940f55 Upgrade AspectJ 1.9.22.1 -> 1.9.23 (#1587)
See:
- https://github.com/eclipse-aspectj/aspectj/releases/tag/V1_9_23
- https://github.com/eclipse-aspectj/aspectj/compare/V1_9_22_1...V1_9_23
2025-03-19 21:28:29 +01:00
Picnic-DevPla-Bot
8d7633df2d Upgrade pitest-maven-plugin 1.18.2 -> 1.19.0 (#1593)
See:
- https://github.com/hcoles/pitest/releases/tag/1.19.0
- https://github.com/hcoles/pitest/compare/1.18.2...1.19.0
2025-03-19 21:16:34 +01:00
Picnic-DevPla-Bot
4a351cfbe3 Upgrade JUnit 5 5.12.0 -> 5.12.1 (#1589)
See:
- https://junit.org/junit5/docs/current/release-notes/
- https://github.com/junit-team/junit5/releases/tag/r5.12.1
- https://github.com/junit-team/junit5/compare/r5.12.0...r5.12.1
2025-03-19 09:30:32 +01:00
Stephan Schroevers
bb01447760 Relocate Arcmutate license file (#1594)
This former location is deprecated.
2025-03-18 15:31:18 +01:00
Picnic-DevPla-Bot
f12ed17b96 Upgrade Spring Security 6.4.3 -> 6.4.4 (#1592)
See:
- https://github.com/spring-projects/spring-security/releases/tag/6.4.4
- https://github.com/spring-projects/spring-security/compare/6.4.3...6.4.4
2025-03-18 12:06:47 +01:00
Stephan Schroevers
854e05f044 Upgrade Arcmutate plugins (#1586)
These upgrades were not picked up automatically due to a groupId change.

Summary of changes:
- Upgrade Pitest Git plugins 1.1.4 -> 2.1.0
- Upgrade Arcmutate 1.2.2 -> 1.3.2
- Upgrade pitest-accelerator-junit5 1.0.6 -> 1.2.0
2025-03-18 11:47:21 +01:00
Picnic-DevPla-Bot
82c22682c0 Upgrade Mockito 5.16.0 -> 5.16.1 (#1590)
See:
- https://github.com/mockito/mockito/releases/tag/v5.16.1
- https://github.com/mockito/mockito/compare/v5.16.0...v5.16.1
2025-03-18 11:16:24 +01:00
Stephan Schroevers
25b3817876 Upgrade Error Prone fork 2.36.0-picnic-2 -> 2.36.0-picnic-4 (#1591)
See:
- https://github.com/PicnicSupermarket/error-prone/releases/tag/v2.36.0-picnic-3
- https://github.com/PicnicSupermarket/error-prone/releases/tag/v2.36.0-picnic-4
- https://github.com/PicnicSupermarket/error-prone/compare/v2.36.0-picnic-2...v2.36.0-picnic-4
2025-03-18 09:10:40 +01:00
Picnic-DevPla-Bot
e2a2b086ad Upgrade Spring 6.2.3 -> 6.2.4 (#1588)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.4
- https://github.com/spring-projects/spring-framework/compare/v6.2.3...v6.2.4
2025-03-15 13:39:30 +01:00
Picnic-DevPla-Bot
5f9a0c5e17 Upgrade Project Reactor 2024.0.3 -> 2024.0.4 (#1583)
See:
- https://github.com/reactor/reactor/releases/tag/2024.0.4
- https://github.com/reactor/reactor/compare/2024.0.3...2024.0.4
2025-03-15 11:37:49 +01:00
Picnic-DevPla-Bot
2a0ae0af13 Upgrade OpenRewrite Templating 1.23.0 -> 1.24.0 (#1585)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.24.0
- https://github.com/openrewrite/rewrite-templating/compare/v1.23.0...v1.24.0
2025-03-14 17:35:28 +01:00
Picnic-DevPla-Bot
7a051146b6 Upgrade Micrometer 1.14.4 -> 1.14.5 (#1582)
See:
- https://github.com/micrometer-metrics/micrometer/releases/tag/v1.14.5
- https://github.com/micrometer-metrics/micrometer/compare/v1.14.4...v1.14.5
2025-03-13 08:49:57 +01:00
Picnic-DevPla-Bot
d9398001cb Upgrade OpenRewrite 3.2.0 -> 3.4.0 (#1557)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v3.3.0
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v3.4.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v3.2.0...v3.4.0
2025-03-12 15:06:25 +01:00
Picnic-DevPla-Bot
0be99cb12a Upgrade Swagger 2.2.28 -> 2.2.29 (#1584)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.29
- https://github.com/swagger-api/swagger-core/compare/v2.2.28...v2.2.29
2025-03-12 13:07:45 +01:00
Picnic-DevPla-Bot
70e2d3d43f Upgrade tidy-maven-plugin 1.3.0 -> 1.4.0 (#1580)
See:
- https://github.com/mojohaus/tidy-maven-plugin/releases/tag/1.4.0
- https://github.com/mojohaus/tidy-maven-plugin/compare/tidy-maven-plugin-1.3.0...1.4.0
2025-03-12 09:30:27 +01:00
Picnic-DevPla-Bot
441258f9f2 Upgrade maven-deploy-plugin 3.1.3 -> 3.1.4 (#1573)
See:
- https://github.com/apache/maven-deploy-plugin/releases/tag/maven-deploy-plugin-3.1.4
2025-03-10 14:37:20 +01:00
Picnic-DevPla-Bot
b96efb533c Upgrade Checkstyle 10.21.3 -> 10.21.4 (#1579)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.21.4
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.21.3...checkstyle-10.21.4
2025-03-09 12:35:28 +01:00
Picnic-DevPla-Bot
5af067cc23 Upgrade Mockito 5.15.2 -> 5.16.0 (#1578)
See:
- https://github.com/mockito/mockito/releases/tag/v5.16.0
- https://github.com/mockito/mockito/compare/v5.15.2...v5.16.0
2025-03-09 12:05:58 +01:00
Picnic-DevPla-Bot
0c84665e38 Upgrade maven-install-plugin 3.1.3 -> 3.1.4 (#1574)
See:
- https://github.com/apache/maven-install-plugin/releases/tag/maven-install-plugin-3.1.4
- https://github.com/apache/maven-install-plugin/compare/maven-install-plugin-3.1.3...maven-install-plugin-3.1.4
2025-03-09 11:52:58 +01:00
Picnic-DevPla-Bot
9316d81fe3 Upgrade Jackson 2.18.2 -> 2.18.3 (#1575)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.18.3
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.18.2...jackson-bom-2.18.3
2025-03-09 11:43:33 +01:00
Picnic-DevPla-Bot
ec96c044d5 Upgrade NullAway 0.12.3 -> 0.12.4 (#1572)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.12.4
- https://github.com/uber/NullAway/compare/v0.12.3...v0.12.4
2025-03-09 11:33:22 +01:00
Picnic-DevPla-Bot
ae4ed9273f Upgrade Checker Framework Annotations 3.49.0 -> 3.49.1 (#1577)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.49.1
- https://github.com/typetools/checker-framework/compare/checker-framework-3.49.0...checker-framework-3.49.1
2025-03-09 11:24:08 +01:00
Picnic-DevPla-Bot
0ec882e62e Upgrade Byte Buddy 1.17.1 -> 1.17.2 (#1576)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.17.2
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.17.1...byte-buddy-1.17.2
2025-03-09 09:47:31 +01:00
Picnic-DevPla-Bot
fef9ba23f4 Upgrade org.pitest:pitest-junit5-plugin 1.2.1 -> 1.2.2 (#1570)
See:
- https://github.com/pitest/pitest-junit5-plugin/releases/tag/1.2.2
- https://github.com/pitest/pitest-junit5-plugin/compare/1.2.1...1.2.2
2025-03-04 09:25:13 +01:00
Picnic-DevPla-Bot
3bd415b910 Upgrade SLF4J 2.0.16 -> 2.0.17 (#1571)
See:
- https://www.slf4j.org/news.html
- https://github.com/qos-ch/slf4j/compare/v_2.0.16...v_2.0.17
2025-02-27 10:12:40 +01:00
Picnic-DevPla-Bot
2128624261 Upgrade ruby/setup-ruby v1.213.0 -> v1.221.0 (#1568)
See:
- https://github.com/ruby/setup-ruby/releases/tag/v1.221.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.220.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.219.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.218.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.217.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.216.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.215.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.214.0
2025-02-24 12:53:58 +01:00
Picnic-DevPla-Bot
c53fcace76 Upgrade CodeQL v3.28.5 -> v3.28.10 (#1567)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/releases/tag/v3.28.6
- https://github.com/github/codeql-action/releases/tag/v3.28.7
- https://github.com/github/codeql-action/releases/tag/v3.28.8
- https://github.com/github/codeql-action/releases/tag/v3.28.9
- https://github.com/github/codeql-action/releases/tag/v3.28.10
- https://github.com/github/codeql-action/compare/v3.28.5...v3.28.10
2025-02-24 10:56:49 +01:00
Picnic-DevPla-Bot
ff3759984c Upgrade Checkstyle 10.21.2 -> 10.21.3 (#1566)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.21.3
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.21.2...checkstyle-10.21.3
2025-02-24 09:58:19 +01:00
Phil Werli
6358d1e2e1 Extend MonoSingleOptional Refaster rule (#1553) 2025-02-24 09:25:30 +01:00
Mohamed Sameh
db53631e76 Extend MonoThen Refaster rule (#1556) 2025-02-24 09:09:27 +01:00
Picnic-DevPla-Bot
86b2d929ab Upgrade OpenRewrite Templating 1.22.1 -> 1.23.0 (#1558)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.23.0
- https://github.com/openrewrite/rewrite-templating/compare/v1.22.1...v1.23.0
2025-02-23 22:22:38 +01:00
Picnic-DevPla-Bot
0db4462a64 Upgrade ossf/scorecard-action v2.4.0 -> v2.4.1 (#1563)
See:
- https://github.com/ossf/scorecard-action/releases/tag/v2.4.1
2025-02-23 22:12:53 +01:00
Picnic-DevPla-Bot
f8667fc655 Upgrade pitest-maven-plugin 1.18.1 -> 1.18.2 (#1552)
See:
- https://github.com/hcoles/pitest/releases/tag/1.18.2
- https://github.com/hcoles/pitest/compare/1.18.1...1.18.2
2025-02-23 18:06:49 +01:00
Picnic-DevPla-Bot
d91f94e879 Upgrade actions/upload-artifact v4.6.0 -> v4.6.1 (#1562)
See:
- https://github.com/actions/upload-artifact/releases/tag/v4.6.1
2025-02-23 17:43:58 +01:00
Picnic-DevPla-Bot
ad6c8593f2 Upgrade JUnit 5 5.11.4 -> 5.12.0 (#1564)
See:
- https://junit.org/junit5/docs/current/release-notes/
- https://github.com/junit-team/junit5/releases/tag/r5.12.0-M1
- https://github.com/junit-team/junit5/releases/tag/r5.12.0-RC1
- https://github.com/junit-team/junit5/releases/tag/r5.12.0-RC2
- https://github.com/junit-team/junit5/releases/tag/r5.12.0
- https://github.com/junit-team/junit5/compare/r5.11.4...r5.12.0
2025-02-23 17:30:14 +01:00
Picnic-DevPla-Bot
873ee47e8d Upgrade maven-compiler-plugin 3.13.0 -> 3.14.0 (#1565)
See:
- https://github.com/apache/maven-compiler-plugin/releases/tag/maven-compiler-plugin-3.14.0
- https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.13.0...maven-compiler-plugin-3.14.0
2025-02-23 17:13:46 +01:00
Picnic-DevPla-Bot
fed281dc2b Upgrade Spring Boot 3.4.2 -> 3.4.3 (#1561)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v3.4.3
- https://github.com/spring-projects/spring-boot/compare/v3.4.2...v3.4.3
2025-02-22 13:36:10 +01:00
Picnic-DevPla-Bot
277d30467d Upgrade Spring Security 6.4.2 -> 6.4.3 (#1554)
See:
- https://github.com/spring-projects/spring-security/releases/tag/6.4.3
- https://github.com/spring-projects/spring-security/compare/6.4.2...6.4.3
2025-02-21 14:55:42 +01:00
Picnic-DevPla-Bot
064e0bbc8c Upgrade maven-clean-plugin 3.4.0 -> 3.4.1 (#1555)
See:
- https://github.com/apache/maven-clean-plugin/releases/tag/maven-clean-plugin-3.4.1
- https://github.com/apache/maven-clean-plugin/compare/maven-clean-plugin-3.4.0...maven-clean-plugin-3.4.1
2025-02-20 11:29:43 +01:00
Stephan Schroevers
3beadeec50 Introduce ArraysCompareUnsigned{Byte,Int,Long}s Refaster rules (#1542)
While there, document possible `StreamFlatMapOptional` improvement.
2025-02-18 19:24:21 +01:00
Phil Werli
c2a26ed12f Introduce MonoFromFutureAsyncLoadingCacheGetAll Refaster rule (#1551) 2025-02-18 19:04:11 +01:00
Picnic-DevPla-Bot
2419dad433 Upgrade step-security/harden-runner v2.10.4 -> v2.11.0 (#1550)
See:
- https://github.com/step-security/harden-runner/releases/tag/v2.11.0
2025-02-17 09:48:16 +01:00
Picnic-DevPla-Bot
900d6eaf78 Upgrade TestNG 7.10.2 -> 7.11.0 (#1546)
See:
- https://github.com/testng-team/testng/releases/tag/7.11.0
- https://github.com/testng-team/testng/compare/7.10.2...7.11.0
2025-02-17 08:57:36 +01:00
Picnic-DevPla-Bot
33d205e11f Upgrade Byte Buddy 1.17.0 -> 1.17.1 (#1549)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.17.1
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.17.0...byte-buddy-1.17.1
2025-02-16 13:47:53 +01:00
Picnic-DevPla-Bot
ee0651d9d3 Upgrade pitest-maven-plugin 1.18.0 -> 1.18.1 (#1545)
See:
- https://github.com/hcoles/pitest/releases/tag/1.18.1
- https://github.com/hcoles/pitest/compare/1.18.0...1.18.1
2025-02-15 19:12:33 +01:00
Picnic-DevPla-Bot
fb22039fd3 Upgrade Spring 6.2.2 -> 6.2.3 (#1548)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.3
- https://github.com/spring-projects/spring-framework/compare/v6.2.2...v6.2.3
2025-02-15 17:08:11 +01:00
Picnic-DevPla-Bot
cf294b8964 Upgrade Project Reactor 2024.0.2 -> 2024.0.3 (#1544)
See:
- https://github.com/reactor/reactor/releases/tag/2024.0.3
- https://github.com/reactor/reactor/compare/2024.0.2...2024.0.3
2025-02-13 14:04:35 +01:00
Picnic-DevPla-Bot
0004c8bc44 Upgrade Micrometer 1.14.3 -> 1.14.4 (#1543)
See:
- https://github.com/micrometer-metrics/micrometer/releases/tag/v1.14.4
- https://github.com/micrometer-metrics/micrometer/compare/v1.14.3...v1.14.4
2025-02-13 09:02:32 +01:00
Stephan Schroevers
aedeeb0943 Fix integration test step-security/harden-runner configuration (#1541)
Resolves #1534.
2025-02-09 20:54:57 +01:00
Picnic-DevPla-Bot
a68e5ae150 Upgrade OpenRewrite 3.1.0 -> 3.2.0 (#1540)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v3.2.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v3.1.0...v3.2.0
2025-02-08 15:52:40 +01:00
Picnic-DevPla-Bot
6a6354eb55 Upgrade OpenRewrite Templating 1.22.0 -> 1.22.1 (#1539)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.22.1
- https://github.com/openrewrite/rewrite-templating/compare/v1.22.0...v1.22.1
2025-02-08 15:18:39 +01:00
Picnic-DevPla-Bot
ab0a844f26 Upgrade pitest-maven-plugin 1.17.4 -> 1.18.0 (#1538)
See:
- https://github.com/hcoles/pitest/releases/tag/1.18.0
- https://github.com/hcoles/pitest/compare/1.17.4...1.18.0
2025-02-08 14:59:53 +01:00
Picnic-DevPla-Bot
5105cb684f Upgrade Checker Framework Annotations 3.48.4 -> 3.49.0 (#1537)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.49.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.48.4...checker-framework-3.49.0
2025-02-08 13:38:40 +01:00
Stephan Schroevers
f128a7975f Update Error Prone compatibility matrix (#1536) 2025-02-03 09:04:46 +01:00
Stephan Schroevers
e572a3641d [maven-release-plugin] prepare for next development iteration 2025-02-02 13:19:40 +01:00
Stephan Schroevers
2b467832fb [maven-release-plugin] prepare release v0.20.0 2025-02-02 13:19:40 +01:00
Rick Ossendrijver
77557c80b1 Extend size-related AssertJEnumerableRules Refaster rules (#1512)
By also matching expressions ending in `.returnToIterable()`.
2025-02-02 12:46:39 +01:00
Picnic-DevPla-Bot
9088369f89 Upgrade Byte Buddy 1.16.1 -> 1.17.0 (#1535)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.17.0
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.16.1...byte-buddy-1.17.0
2025-02-01 16:41:07 +01:00
Picnic-DevPla-Bot
36ef967f0e Upgrade Checkstyle 10.21.1 -> 10.21.2 (#1531)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.21.2
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.21.1...checkstyle-10.21.2
2025-01-27 14:07:12 +01:00
Picnic-DevPla-Bot
dd190ee056 Upgrade CodeQL v3.28.0 -> v3.28.5 (#1532)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/releases/tag/v3.28.1
- https://github.com/github/codeql-action/releases/tag/v3.28.2
- https://github.com/github/codeql-action/releases/tag/v3.28.3
- https://github.com/github/codeql-action/releases/tag/v3.28.4
- https://github.com/github/codeql-action/releases/tag/v3.28.5
- https://github.com/github/codeql-action/compare/v3.28.0...v3.28.5
2025-01-27 13:40:57 +01:00
Picnic-DevPla-Bot
4c32d3ce7a Upgrade ruby/setup-ruby v1.206.0 -> v1.213.0 (#1533)
See:
- https://github.com/ruby/setup-ruby/releases/tag/v1.213.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.212.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.211.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.210.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.209.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.208.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.207.0
2025-01-27 10:13:25 +01:00
Picnic-DevPla-Bot
4608c00140 Upgrade OpenRewrite 3.0.2 -> 3.1.0 (#1529)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v3.1.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v3.0.2...v3.1.0
2025-01-25 13:50:19 +01:00
Picnic-DevPla-Bot
708317f314 Upgrade Spring Boot 3.4.1 -> 3.4.2 (#1528)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v3.4.2
- https://github.com/spring-projects/spring-boot/compare/v3.4.1...v3.4.2
2025-01-25 13:22:19 +01:00
Picnic-DevPla-Bot
636c1993d5 Upgrade OpenRewrite Templating 1.21.0 -> 1.22.0 (#1530)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.22.0
- https://github.com/openrewrite/rewrite-templating/compare/v1.21.0...v1.22.0
2025-01-25 13:11:33 +01:00
Picnic-DevPla-Bot
895875c849 Upgrade MongoDB driver 5.3.0 -> 5.3.1 (#1527)
See:
- https://github.com/mongodb/mongo-java-driver/releases/tag/r5.3.1
- https://github.com/mongodb/mongo-java-driver/compare/r5.3.0...r5.3.1
2025-01-24 10:11:42 +01:00
Picnic-DevPla-Bot
1aea710c53 Upgrade OpenRewrite 3.0.1 -> 3.0.2 (#1519)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v3.0.2
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v3.0.1...v3.0.2
2025-01-21 19:41:23 +01:00
Picnic-DevPla-Bot
5085eb2f25 Upgrade AssertJ 3.27.2 -> 3.27.3 (#1523)
See:
- https://github.com/assertj/assertj/releases/tag/assertj-build-3.27.3
- https://github.com/assertj/assertj/compare/assertj-build-3.27.2...assertj-build-3.27.3
2025-01-21 07:38:00 +01:00
Picnic-DevPla-Bot
ad5b1c9917 Upgrade Modernizer Maven Plugin 3.0.0 -> 3.1.0 (#1526)
See:
- https://github.com/gaul/modernizer-maven-plugin/releases/tag/modernizer-maven-plugin-3.1.0
- https://github.com/gaul/modernizer-maven-plugin/compare/modernizer-maven-plugin-3.0.0...modernizer-maven-plugin-3.1.0
2025-01-20 12:41:38 +01:00
Picnic-DevPla-Bot
34cab33b76 Upgrade step-security/harden-runner v2.10.3 -> v2.10.4 (#1525)
See:
- https://github.com/step-security/harden-runner/releases/tag/v2.10.4
2025-01-20 09:50:54 +01:00
Picnic-DevPla-Bot
c836f1147f Upgrade Byte Buddy 1.16.0 -> 1.16.1 (#1524)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.16.1
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.16.0...byte-buddy-1.16.1
2025-01-20 09:28:43 +01:00
Picnic-DevPla-Bot
f43921f344 Upgrade Caffeine 3.1.8 -> 3.2.0 (#1522)
See:
- https://github.com/ben-manes/caffeine/releases/tag/v3.2.0
- https://github.com/ben-manes/caffeine/compare/v3.1.8...v3.2.0
2025-01-19 21:19:32 +01:00
Picnic-DevPla-Bot
811e70ae3a Upgrade Swagger 2.2.27 -> 2.2.28 (#1520)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.28
- https://github.com/swagger-api/swagger-core/compare/v2.2.27...v2.2.28
2025-01-19 21:09:43 +01:00
Picnic-DevPla-Bot
5fd50e6181 Upgrade Byte Buddy 1.15.11 -> 1.16.0 (#1521)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.16.0
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.15.11...byte-buddy-1.16.0
2025-01-18 11:08:24 +01:00
Picnic-DevPla-Bot
3767341605 Upgrade swagger-annotations 1.6.14 -> 1.6.15 (#1517)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v1.6.15
- https://github.com/swagger-api/swagger-core/compare/v1.6.14...v1.6.15
2025-01-17 13:05:37 +01:00
Picnic-DevPla-Bot
9f83eec36b Upgrade jOOQ 3.19.17 -> 3.19.18 (#1518)
See:
- https://www.jooq.org/notes
- https://github.com/jOOQ/jOOQ/releases/tag/version-3.19.18
- https://github.com/jOOQ/jOOQ/compare/version-3.19.17...version-3.19.18
2025-01-17 12:40:07 +01:00
Picnic-DevPla-Bot
126159878c Upgrade Spring 6.2.1 -> 6.2.2 (#1516)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.2
- https://github.com/spring-projects/spring-framework/compare/v6.2.1...v6.2.2
2025-01-17 11:33:55 +01:00
Picnic-DevPla-Bot
78141b2528 Upgrade Project Reactor 2024.0.1 -> 2024.0.2 (#1515)
See:
- https://github.com/reactor/reactor/releases/tag/2024.0.2
- https://github.com/reactor/reactor/compare/2024.0.1...2024.0.2
2025-01-16 18:40:35 +01:00
Picnic-DevPla-Bot
56db8adb5a Upgrade OpenRewrite 3.0.0 -> 3.0.1 (#1514)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v3.0.1
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v3.0.0...v3.0.1
2025-01-15 16:44:33 +01:00
Picnic-DevPla-Bot
90b4baba12 Upgrade Micrometer 1.14.2 -> 1.14.3 (#1513)
See:
- https://github.com/micrometer-metrics/micrometer/releases/tag/v1.14.3
- https://github.com/micrometer-metrics/micrometer/compare/v1.14.2...v1.14.3
2025-01-15 16:20:12 +01:00
Picnic-DevPla-Bot
54c56a4cc8 Upgrade OpenRewrite 2.23.2 -> 3.0.0 (#1511)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v3.0.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.23.2...v3.0.0
2025-01-13 14:17:40 +01:00
Picnic-DevPla-Bot
b123282778 Upgrade OpenRewrite Templating 1.20.2 -> 1.21.0 (#1510)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.21.0
- https://github.com/openrewrite/rewrite-templating/compare/v1.20.2...v1.21.0
2025-01-13 09:51:58 +01:00
Picnic-DevPla-Bot
f4562c7106 Upgrade MongoDB driver 5.2.1 -> 5.3.0 (#1509)
See:
- https://jira.mongodb.org/issues/?jql=project%20%3D%20JAVA%20AND%20fixVersion%20%3E%205.2.1%20AND%20fixVersion%20%3C%3D%205.3.0
- https://github.com/mongodb/mongo-java-driver/releases/tag/r5.3.0-beta0
- https://github.com/mongodb/mongo-java-driver/releases/tag/r5.3.0
- https://github.com/mongodb/mongo-java-driver/compare/r5.2.1...r5.3.0
2025-01-12 12:31:32 +01:00
Picnic-DevPla-Bot
6211e7e651 Upgrade pitest-maven-plugin 1.17.3 -> 1.17.4 (#1508)
See:
- https://github.com/hcoles/pitest/releases/tag/1.17.4
- https://github.com/hcoles/pitest/compare/1.17.3...1.17.4
2025-01-12 11:54:41 +01:00
Stephan Schroevers
3e4a01a673 Have TimeZoneUsage check also flag illegal method references (#1507)
While there, reorder a few things.
2025-01-11 14:54:28 +01:00
Stephan Schroevers
a42353b41a Introduce EagerStringFormatting check (#1139)
This new check flags code that can be simplified and/or optimized by
deferring certain string formatting operations.
2025-01-11 14:42:22 +01:00
Picnic-DevPla-Bot
d2ce18e33e Upgrade actions/upload-artifact v4.5.0 -> v4.6.0 (#1506)
See:
- https://github.com/actions/upload-artifact/releases/tag/v4.6.0
2025-01-11 12:36:15 +01:00
Stephan Schroevers
7b81dc44e5 Upgrade Error Prone fork 2.36.0-picnic-1 -> 2.36.0-picnic-2 (#1499)
This new release is published using GitHub Packages rather than
JitPack. This comes with a simpler release setup and a (hopefully) more
stable package repository. A minor downside is that GitHub Packages
require authenticated access, even for read access. The documentation
has been updated accordingly.

The new release is no longer published using a custom groupId, enabling
some build simplifications.

While there, some obsolete fork-related documentation and configuration
is dropped.

See:
- https://github.com/PicnicSupermarket/error-prone/releases/tag/v2.36.0-picnic-2
- https://github.com/PicnicSupermarket/error-prone/compare/v2.36.0-picnic-1...v2.36.0-picnic-2
2025-01-10 16:40:59 +01:00
Phil Werli
5e81719cea Disallow static imports for InstantSource class and EPOCH constants (#1503) 2025-01-10 15:06:24 +01:00
Picnic-DevPla-Bot
2f3788fc63 Upgrade jOOQ 3.19.16 -> 3.19.17 (#1504)
See:
- https://www.jooq.org/notes
- https://github.com/jOOQ/jOOQ/releases/tag/version-3.19.17
- https://github.com/jOOQ/jOOQ/compare/version-3.19.16...version-3.19.17
2025-01-10 13:12:35 +01:00
Picnic-DevPla-Bot
a98780cef2 Upgrade step-security/harden-runner v2.10.2 -> v2.10.3 (#1505)
See:
- https://github.com/step-security/harden-runner/releases/tag/v2.10.3
2025-01-10 11:51:58 +01:00
Stephan Schroevers
ff0e30c885 Make Mockito setup IntelliJ IDEA-compatible (#1500)
See https://github.com/mockito/mockito/issues/3037#issuecomment-2569680756
2025-01-09 09:20:39 +01:00
Stephan Schroevers
4aacc58382 Extend JUnitToAssertJRules Refaster rule collection (#1484)
By migrating all remaining `assertArrayEquals` methods.
2025-01-08 09:35:09 +01:00
Stephan Schroevers
dec22b8633 Introduce assorted Iterator and Iterable Refaster rules (#1487) 2025-01-07 19:15:54 +01:00
Picnic-DevPla-Bot
37d8ea92c6 Upgrade NullAway 0.12.2 -> 0.12.3 (#1502)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.12.3
- https://github.com/uber/NullAway/compare/v0.12.2...v0.12.3
2025-01-07 18:01:31 +01:00
Picnic-DevPla-Bot
7eb46dd218 Upgrade Checker Framework Annotations 3.48.3 -> 3.48.4 (#1497)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.48.4
- https://github.com/typetools/checker-framework/compare/checker-framework-3.48.3...checker-framework-3.48.4
2025-01-06 08:54:01 +01:00
Picnic-DevPla-Bot
623bdd7344 Upgrade Mockito 5.14.2 -> 5.15.2 (#1498)
See:
- https://github.com/mockito/mockito/releases/tag/v5.15.0
- https://github.com/mockito/mockito/releases/tag/v5.15.1
- https://github.com/mockito/mockito/releases/tag/v5.15.2
- https://github.com/mockito/mockito/compare/v5.14.2...v5.15.2
2025-01-05 17:27:38 +01:00
Picnic-DevPla-Bot
c3ae1b5b92 Upgrade AssertJ 3.27.1 -> 3.27.2 (#1501)
See:
- https://github.com/assertj/assertj/releases/tag/assertj-build-3.27.2
- https://github.com/assertj/assertj/compare/assertj-build-3.27.1...assertj-build-3.27.2
2025-01-05 13:28:00 +01:00
Stephan Schroevers
19d3ba0505 Extend ImmutableMapRules Refaster rule collection (#1488)
Resolves #1223.
2025-01-03 11:53:24 +01:00
Stephan Schroevers
9493f2d59a Introduce ImmutableTableRules Refaster rule collection (#1489) 2025-01-03 11:18:47 +01:00
Picnic-DevPla-Bot
68ecd652f7 Upgrade AssertJ 3.27.0 -> 3.27.1 (#1496)
See:
- https://github.com/assertj/assertj/releases/tag/assertj-build-3.27.1
- https://github.com/assertj/assertj/compare/assertj-build-3.27.0...assertj-build-3.27.1
2025-01-03 08:53:48 +01:00
Phil Werli
e67800e4e2 Introduce FluxMapNotNull{,Transformation}OrElse Refaster rules (#1493) 2025-01-02 12:42:25 +01:00
Picnic-DevPla-Bot
7f90f26830 Upgrade s4u/setup-maven-action v1.17.0 -> v1.18.0 (#1495)
See:
- https://github.com/s4u/setup-maven-action/releases/tag/v1.18.0
2025-01-02 07:40:34 +01:00
Stephan Schroevers
6477c1899d Extend TestNGToAssertJRules Refaster rule collection (#1483)
By migrating all remaining `assertEquals` methods.
2025-01-01 11:39:30 +01:00
Stephan Schroevers
03514f9f6a Generalize assorted Refaster rules (#1481) 2025-01-01 01:27:07 +01:00
Phil Werli
d11ac09bda Extend {Is,Non}NullFunction Refaster rules (#1494)
While there, simplify the associated tests.
2024-12-31 16:30:17 +01:00
Stephan Schroevers
667f83fd2f Run GitHub Actions workflows on macos-15 and windows-2025 (#1490)
See:
- https://github.com/actions/runner-images/blob/main/README.md#available-images
- https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md
- https://github.com/actions/runner-images/blob/main/images/windows/Windows2025-Readme.md
2024-12-31 09:49:40 +01:00
Picnic-DevPla-Bot
15ba59a9aa Upgrade CodeQL v3.27.5 -> v3.28.0 (#1491)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/releases/tag/v3.27.6
- https://github.com/github/codeql-action/releases/tag/v3.27.7
- https://github.com/github/codeql-action/releases/tag/v3.27.9
- https://github.com/github/codeql-action/releases/tag/v3.28.0
- https://github.com/github/codeql-action/compare/v3.27.5...v3.28.0
2024-12-31 08:38:03 +01:00
Picnic-DevPla-Bot
a46d6dc146 Upgrade ruby/setup-ruby v1.202.0 -> v1.206.0 (#1492)
See:
- https://github.com/ruby/setup-ruby/releases/tag/v1.206.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.205.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.204.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.203.0
2024-12-30 08:16:01 +01:00
Picnic-DevPla-Bot
cf523bc811 Upgrade Checkstyle 10.21.0 -> 10.21.1 (#1485)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.21.1
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.21.0...checkstyle-10.21.1
2024-12-29 21:41:34 +01:00
Stephan Schroevers
9bd8095e0b Sync Dropwizard Metrics integration test (#1482) 2024-12-29 20:30:59 +01:00
Picnic-DevPla-Bot
6cfa9a0dfe Upgrade Modernizer Maven Plugin 2.9.0 -> 3.0.0 (#1486)
See:
- https://github.com/gaul/modernizer-maven-plugin/releases/tag/modernizer-maven-plugin-3.0.0
- https://github.com/gaul/modernizer-maven-plugin/compare/modernizer-maven-plugin-2.9.0...modernizer-maven-plugin-3.0.0
2024-12-29 20:05:43 +01:00
Rick Ossendrijver
7daa39a0b5 Update comments referencing Refaster rule limitation (#46)
Issue google/error-prone#2706 has been resolved; we have yet to decide
how to proceed.
2024-12-27 05:30:30 +01:00
Rick Ossendrijver
5fc7bc29ee Introduce CharSequenceRules Refaster rule collection (#1480)
Resolves #1394.
2024-12-26 17:47:57 +01:00
Stephan Schroevers
83f3f8bedc Introduce AssertThatString{Contains,DoesNotContain} Refaster rules (#1479)
While there, extend `AssertThatIterableIsEmpty`.
2024-12-25 13:40:22 +01:00
Picnic-DevPla-Bot
12585a8969 Upgrade AssertJ 3.26.3 -> 3.27.0 (#1472)
See:
- https://github.com/assertj/assertj/releases/tag/assertj-build-3.27.0
- https://github.com/assertj/assertj/compare/assertj-build-3.26.3...assertj-build-3.27.0
2024-12-25 11:29:40 +01:00
121 changed files with 4028 additions and 1478 deletions

View File

@@ -0,0 +1,12 @@
{
"name": "Java",
"image": "mcr.microsoft.com/devcontainers/java:1-21",
"features": {
"ghcr.io/devcontainers/features/java:1": {
"version": "none",
"installMaven": "true",
"mavenVersion": "3.8.6",
"installGradle": "true"
}
}
}

View File

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

View File

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

View File

@@ -1,58 +0,0 @@
# Description: This workflow is triggered when the `receive-pr` workflow completes to post suggestions on the PR.
# Since this pull request has write permissions on the target repo, we should **NOT** execute any untrusted code.
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
---
name: comment-pr
on:
workflow_run:
workflows: ["receive-pr"]
types:
- completed
permissions:
actions: read
jobs:
post-suggestions:
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#running-a-workflow-based-on-the-conclusion-of-another-workflow
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
env:
# https://docs.github.com/en/actions/reference/authentication-in-a-workflow#permissions-for-the-github_token
ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{github.event.workflow_run.head_branch}}
repository: ${{github.event.workflow_run.head_repository.full_name}}
- name: Download the patch.
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
with:
name: patch
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
- name: Apply patch
run: |
git apply git-diff.patch --allow-empty
rm git-diff.patch
- name: Download the PR number.
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
with:
name: pr_number
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
- name: Read pr_number.txt
run: |
PR_NUMBER=$(cat pr_number.txt)
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
rm pr_number.txt
- name: Post suggestions as a comment on the PR.
uses: googleapis/code-suggester@589b3ac11ac2575fd561afa45034907f301a375b # v3.4.4
with:
command: review
pull_number: ${{ env.PR_NUMBER }}
git_dir: '.'

View File

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

22
.github/workflows/junie.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: Junie
run-name: Junie run ${{ inputs.run_id }}
permissions:
contents: write
pull-requests: write
on:
workflow_dispatch:
inputs:
run_id:
description: "id of workflow process"
required: true
workflow_params:
description: "stringified params"
required: true
jobs:
call-workflow-passing-data:
uses: jetbrains-junie/junie-workflows/.github/workflows/ej-issue.yml@main
with:
workflow_params: ${{ inputs.workflow_params }}

View File

@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with:
disable-sudo: true
egress-policy: block
@@ -42,12 +42,12 @@ jobs:
with:
persist-credentials: false
- name: Run OpenSSF Scorecard analysis
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
with:
results_file: results.sarif
results_format: sarif
publish_results: ${{ github.ref == 'refs/heads/master' }}
- name: Update GitHub's code scanning dashboard
uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
uses: github/codeql-action/upload-sarif@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12
with:
sarif_file: results.sarif

View File

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

View File

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

View File

@@ -1,56 +0,0 @@
# Description: This workflow runs OpenRewrite recipes against opened pull request and upload the patch.
# Since this pull request receives untrusted code, we should **NOT** have any secrets in the environment.
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
---
name: receive-pr
on:
pull_request:
types: [opened, synchronize]
branches:
- master
permissions:
actions: read
concurrency:
group: '${{ github.workflow }} @ ${{ github.ref }}'
cancel-in-progress: true
jobs:
upload-patch:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: XXX add name.
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
with:
java-version: 17.0.10
java-distribution: temurin
maven-version: 3.9.9
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow
- name: Capture the PR number.
run: echo "${{ github.event.number }}" > pr_number.txt
- name: Upload `pr_number.txt`.
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: pr_number
path: pr_number.txt
- name: Remove pr_number.txt
run: rm -f pr_number.txt
- name: Run Error Prone and Error Prone Support.
run: ./apply-error-prone-suggestions.sh
- name: Capture the diff and create the patch.
run: |
git diff | tee git-diff.patch
- name: Upload the diff.
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: patch
path: git-diff.patch

View File

@@ -22,14 +22,14 @@ jobs:
integration-test: [ "checkstyle", "metrics", "prometheus-java-client" ]
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with:
disable-sudo: true
egress-policy: block
# XXX: After updating the validation build flags in
# `integration-tests/prometheus-java-client.sh`, review whether the
# Docker domains specified here can be dropped.
allowed-endpoints: >
# XXX: After updating the validation build flags in
# `integration-tests/prometheus-java-client.sh`, review whether the
# Docker domains specified here can be dropped.
api.adoptium.net:443
auth.docker.io:443
checkstyle.org:443
@@ -43,7 +43,7 @@ jobs:
repo.maven.apache.org:443
repository.sonatype.org:443
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
with:
checkout-ref: "refs/pull/${{ github.event.issue.number }}/head"
java-version: 17.0.13
@@ -55,7 +55,7 @@ jobs:
run: xvfb-run "./integration-tests/${{ matrix.integration-test }}.sh" "${{ runner.temp }}/artifacts"
- name: Upload artifacts on failure
if: ${{ failure() }}
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: "integration-test-${{ matrix.integration-test }}"
path: "${{ runner.temp }}/artifacts"

View File

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

View File

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

View File

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

View File

@@ -2,6 +2,7 @@ package tech.picnic.errorprone.documentation;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import static java.util.Objects.requireNonNull;
import static java.util.function.Predicate.not;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@@ -167,7 +168,10 @@ public final class BugPatternTestExtractor implements Extractor<BugPatternTestCa
* is safe, because this code is guarded by an earlier call to `#getClassUnderTest(..)`,
* which ensures that `tree` is part of a longer method invocation chain.
*/
MethodInvocationTree inputTree = (MethodInvocationTree) ASTHelpers.getReceiver(tree);
MethodInvocationTree inputTree =
(MethodInvocationTree)
requireNonNull(
ASTHelpers.getReceiver(tree), "Instance method invocation must have receiver");
String path = ASTHelpers.constValue(inputTree.getArguments().get(0), String.class);
Optional<String> inputCode = getSourceCode(inputTree);

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.19.2-SNAPSHOT</version>
<version>0.22.1-SNAPSHOT</version>
</parent>
<artifactId>error-prone-contrib</artifactId>
@@ -15,31 +15,6 @@
<url>https://error-prone.picnic.tech</url>
<dependencies>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>documentation-support</artifactId>
@@ -87,6 +62,41 @@
<artifactId>auto-value-annotations</artifactId>
<scope>provided</scope>
</dependency>
<!-- XXX: JSR-305 (meta-)annotation usage by some dependencies triggers
NullAway to attempt to load said annotations. As such some modules
require these annotations to be on the classpath. Periodically review
whether we can drop this dependeny declaration. See
https://github.com/uber/NullAway/issues/1171. -->
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>

View File

@@ -11,6 +11,7 @@ import static com.google.errorprone.matchers.Matchers.not;
import static com.google.errorprone.matchers.Matchers.returnStatement;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.matchers.Matchers.toType;
import static java.util.Objects.requireNonNull;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
@@ -79,7 +80,10 @@ public final class DirectReturn extends BugChecker implements BlockTreeMatcher {
return Description.NO_MATCH;
}
Symbol variableSymbol = ASTHelpers.getSymbol(((ReturnTree) finalStatement).getExpression());
Symbol variableSymbol =
requireNonNull(
ASTHelpers.getSymbol(((ReturnTree) finalStatement).getExpression()),
"Missing symbol for returned variable");
StatementTree precedingStatement = statements.get(statements.size() - 2);
return tryMatchAssignment(variableSymbol, precedingStatement)

View File

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

View File

@@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Iterables;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
@@ -33,6 +34,8 @@ import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -113,7 +116,7 @@ public final class ExplicitArgumentEnumeration extends BugChecker
.put(OBJECT_ENUMERABLE_ASSERT, "doesNotContainAnyElementsOf", "doesNotContain")
.put(OBJECT_ENUMERABLE_ASSERT, "hasSameElementsAs", "containsOnly")
.put(STEP_VERIFIER_STEP, "expectNextSequence", "expectNext")
.build();
.buildOrThrow();
/** Instantiates a new {@link ExplicitArgumentEnumeration} instance. */
public ExplicitArgumentEnumeration() {}
@@ -178,30 +181,45 @@ public final class ExplicitArgumentEnumeration extends BugChecker
state.getTypes())
.collect(toImmutableList());
/*
* If all overloads have a single parameter, and at least one of them is a varargs method, then
* we assume that unwrapping the iterable argument will cause a suitable overload to be invoked.
* (Note that there may be multiple varargs overloads, either with different parameter types, or
* due to method overriding; this check does not attempt to determine which exact method or
* overload will be invoked as a result of the suggested simplification.)
*
* Note that this is a (highly!) imperfect heuristic, but it is sufficient to prevent e.g.
* unwrapping of arguments to `org.jooq.impl.DSL#row`, which can cause the expression's return
* type to change from `RowN` to (e.g.) `Row2`.
*/
// XXX: There are certainly cases where it _would_ be nice to unwrap the arguments to
// `org.jooq.impl.DSL#row(Collection<?>)`. Look into this.
// XXX: Ideally we do check that one of the overloads accepts the unwrapped arguments.
// XXX: Ideally we validate that eligible overloads have compatible return types.
boolean hasLikelySuitableVarargsOverload =
overloads.stream().allMatch(m -> m.params().size() == 1)
&& overloads.stream().anyMatch(MethodSymbol::isVarArgs);
return hasLikelySuitableVarargsOverload
return hasLikelySuitableVarargsOverload(method, overloads, state)
? Optional.of(SourceCode.unwrapMethodInvocation(argument, state))
: Optional.empty();
}
/**
* Tells whether it is likely that, if the argument to the given method is unwrapped, a suitable
* varargs overload will be invoked instead.
*
* <p>If all overloads have a single parameter, and at least one of them is a suitably-typed
* varargs method, then we assume that unwrapping the iterable argument will cause a suitable
* overload to be invoked. (Note that there may be multiple varargs overloads due to method
* overriding; this check does not attempt to determine which exact method or overload will be
* invoked as a result of the suggested simplification.)
*
* <p>Note that this is a (highly!) imperfect heuristic, but it is sufficient to prevent e.g.
* unwrapping of arguments to `org.jooq.impl.DSL#row`, which can cause the expression's return
* type to change from `RowN` to (e.g.) `Row2`.
*/
// XXX: There are certainly cases where it _would_ be nice to unwrap the arguments to
// `org.jooq.impl.DSL#row(Collection<?>)`. Look into this.
// XXX: Ideally we validate that eligible overloads have compatible return types.
private static boolean hasLikelySuitableVarargsOverload(
MethodSymbol method, ImmutableList<MethodSymbol> overloads, VisitorState state) {
Types types = state.getTypes();
// XXX: This logic is fragile, as it assumes that the method parameter's type is of the form
// `X<T>`, where `T` is the type of the explicitly enumerated values passed to the expression to
// be unwrapped. This should generally hold, given the types returned by the
// `EXPLICIT_ITERABLE_CREATOR` expressions: `Iterable<T>`, `List<T>`, `Set<T>`, etc.
Type parameterType =
Iterables.getOnlyElement(
Iterables.getOnlyElement(method.getParameters()).type.getTypeArguments());
return overloads.stream().allMatch(m -> m.params().size() == 1)
&& overloads.stream()
.filter(MethodSymbol::isVarArgs)
.map(m -> types.elemtype(Iterables.getOnlyElement(m.getParameters()).type))
.anyMatch(varArgsType -> types.containsType(parameterType, varArgsType));
}
private static Optional<SuggestedFix> trySuggestCallingCustomAlternative(
MethodInvocationTree tree, MethodInvocationTree argument, VisitorState state) {
return ALTERNATIVE_METHODS.rowMap().entrySet().stream()

View File

@@ -17,6 +17,7 @@ import static com.google.errorprone.matchers.Matchers.isSameType;
import static com.google.errorprone.matchers.Matchers.methodHasParameters;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.matchers.Matchers.toType;
import static java.util.Objects.requireNonNull;
import static java.util.function.Predicate.not;
import static java.util.stream.Collectors.joining;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
@@ -129,7 +130,10 @@ public final class JUnitValueSource extends BugChecker implements MethodTreeMatc
return Description.NO_MATCH;
}
Type parameterType = ASTHelpers.getType(Iterables.getOnlyElement(tree.getParameters()));
Type parameterType =
requireNonNull(
ASTHelpers.getType(Iterables.getOnlyElement(tree.getParameters())),
"Missing type for method parameter");
return findMethodSourceAnnotation(tree, state)
.flatMap(
@@ -173,7 +177,9 @@ public final class JUnitValueSource extends BugChecker implements MethodTreeMatc
private static Optional<MethodTree> findMatchingSibling(
MethodTree tree, Predicate<? super MethodTree> predicate, VisitorState state) {
return state.findEnclosing(ClassTree.class).getMembers().stream()
return requireNonNull(state.findEnclosing(ClassTree.class), "No class enclosing method")
.getMembers()
.stream()
.filter(MethodTree.class::isInstance)
.map(MethodTree.class::cast)
.filter(not(tree::equals))

View File

@@ -5,6 +5,7 @@ import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static java.util.Objects.requireNonNull;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
@@ -86,7 +87,9 @@ public final class NonEmptyMono extends BugChecker implements MethodInvocationTr
return Description.NO_MATCH;
}
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
ExpressionTree receiver =
requireNonNull(
ASTHelpers.getReceiver(tree), "Instance method invocation must have receiver");
if (!NON_EMPTY_MONO.matches(receiver, state)) {
return Description.NO_MATCH;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,6 +5,9 @@ import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.Collection;
import org.assertj.core.api.AbstractIntegerAssert;
import org.assertj.core.api.AbstractIterableAssert;
import org.assertj.core.api.AbstractIterableSizeAssert;
import org.assertj.core.api.EnumerableAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@@ -21,6 +24,11 @@ final class AssertJEnumerableRules {
enumAssert.hasSizeLessThan(1));
}
@BeforeTemplate
void before(AbstractIterableAssert<?, ?, E, ?> enumAssert) {
enumAssert.size().isNotPositive();
}
@AfterTemplate
void after(EnumerableAssert<?, E> enumAssert) {
enumAssert.isEmpty();
@@ -34,30 +42,175 @@ final class AssertJEnumerableRules {
enumAssert.hasSizeGreaterThan(0), enumAssert.hasSizeGreaterThanOrEqualTo(1));
}
@BeforeTemplate
AbstractIterableAssert<?, ?, E, ?> before(AbstractIterableAssert<?, ?, E, ?> enumAssert) {
return Refaster.anyOf(
enumAssert.size().isNotEqualTo(0).returnToIterable(),
enumAssert.size().isPositive().returnToIterable());
}
// XXX: If this template matches, then the expression's return type changes incompatibly.
// Consider moving this template to a separate block (statement) rule.
@BeforeTemplate
AbstractIntegerAssert<?> before2(AbstractIterableAssert<?, ?, E, ?> enumAssert) {
return Refaster.anyOf(enumAssert.size().isNotEqualTo(0), enumAssert.size().isPositive());
}
@AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert) {
return enumAssert.isNotEmpty();
}
}
static final class EnumerableAssertHasSameSizeAs<S, T> {
static final class EnumerableAssertHasSize<E> {
@BeforeTemplate
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, Iterable<T> iterable) {
AbstractIterableAssert<?, ?, E, ?> before(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isEqualTo(size).returnToIterable();
}
// XXX: If this template matches, then the expression's return type changes incompatibly.
// Consider moving this template to a separate block (statement) rule.
@BeforeTemplate
AbstractIterableSizeAssert<?, ?, E, ?> before2(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isEqualTo(size);
}
@AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
return enumAssert.hasSize(size);
}
}
static final class EnumerableAssertHasSizeLessThan<E> {
@BeforeTemplate
AbstractIterableAssert<?, ?, E, ?> before(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isLessThan(size).returnToIterable();
}
// XXX: If this template matches, then the expression's return type changes incompatibly.
// Consider moving this template to a separate block (statement) rule.
@BeforeTemplate
AbstractIterableSizeAssert<?, ?, E, ?> before2(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isLessThan(size);
}
@AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
return enumAssert.hasSizeLessThan(size);
}
}
static final class EnumerableAssertHasSizeLessThanOrEqualTo<E> {
@BeforeTemplate
AbstractIterableAssert<?, ?, E, ?> before(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isLessThanOrEqualTo(size).returnToIterable();
}
// XXX: If this template matches, then the expression's return type changes incompatibly.
// Consider moving this template to a separate block (statement) rule.
@BeforeTemplate
AbstractIterableSizeAssert<?, ?, E, ?> before2(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isLessThanOrEqualTo(size);
}
@AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
return enumAssert.hasSizeLessThanOrEqualTo(size);
}
}
static final class EnumerableAssertHasSizeGreaterThan<E> {
@BeforeTemplate
AbstractIterableAssert<?, ?, E, ?> before(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isGreaterThan(size).returnToIterable();
}
// XXX: If this template matches, then the expression's return type changes incompatibly.
// Consider moving this template to a separate block (statement) rule.
@BeforeTemplate
AbstractIterableSizeAssert<?, ?, E, ?> before2(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isGreaterThan(size);
}
@AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
return enumAssert.hasSizeGreaterThan(size);
}
}
static final class EnumerableAssertHasSizeGreaterThanOrEqualTo<E> {
@BeforeTemplate
AbstractIterableAssert<?, ?, E, ?> before(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isGreaterThanOrEqualTo(size).returnToIterable();
}
// XXX: If this template matches, then the expression's return type changes incompatibly.
// Consider moving this template to a separate block (statement) rule.
@BeforeTemplate
AbstractIterableSizeAssert<?, ?, E, ?> before2(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int size) {
return enumAssert.size().isGreaterThanOrEqualTo(size);
}
@AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int size) {
return enumAssert.hasSizeGreaterThanOrEqualTo(size);
}
}
static final class EnumerableAssertHasSizeBetween<E> {
@BeforeTemplate
AbstractIterableAssert<?, ?, E, ?> before(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int lower, int upper) {
return enumAssert.size().isBetween(lower, upper).returnToIterable();
}
// XXX: If this template matches, then the expression's return type changes incompatibly.
// Consider moving this template to a separate block (statement) rule.
@BeforeTemplate
AbstractIterableSizeAssert<?, ?, E, ?> before2(
AbstractIterableAssert<?, ?, E, ?> enumAssert, int lower, int upper) {
return enumAssert.size().isBetween(lower, upper);
}
@AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert, int lower, int upper) {
return enumAssert.hasSizeBetween(lower, upper);
}
}
static final class EnumerableAssertHasSameSizeAs<S, E> {
@BeforeTemplate
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, Iterable<E> iterable) {
return enumAssert.hasSize(Iterables.size(iterable));
}
@BeforeTemplate
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, Collection<T> iterable) {
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, Collection<E> iterable) {
return enumAssert.hasSize(iterable.size());
}
@BeforeTemplate
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, T[] iterable) {
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, E[] iterable) {
return enumAssert.hasSize(iterable.length);
}
@BeforeTemplate
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, CharSequence iterable) {
return enumAssert.hasSize(iterable.length());
}
@AfterTemplate
EnumerableAssert<?, S> after(EnumerableAssert<?, S> enumAssert, Iterable<T> iterable) {
EnumerableAssert<?, S> after(EnumerableAssert<?, S> enumAssert, Iterable<E> iterable) {
return enumAssert.hasSameSizeAs(iterable);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,6 +4,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Repeated;
import java.io.File;
@@ -11,6 +12,7 @@ import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileAttribute;
@@ -141,4 +143,35 @@ final class FileRules {
return Files.createTempFile(directory.toPath(), prefix, suffix).toFile();
}
}
/**
* Invoke {@link File#mkdirs()} before {@link Files#exists(Path, LinkOption...)} to avoid
* concurrency issues.
*/
static final class PathToFileMkDirsFilesExists {
@BeforeTemplate
boolean before(Path path) {
return Files.exists(path) || path.toFile().mkdirs();
}
@AfterTemplate
@AlsoNegation
boolean after(Path path) {
return path.toFile().mkdirs() || Files.exists(path);
}
}
/** Invoke {@link File#mkdirs()} before {@link File#exists()} to avoid concurrency issues. */
static final class FileMkDirsFileExists {
@BeforeTemplate
boolean before(File file) {
return file.exists() || file.mkdirs();
}
@AfterTemplate
@AlsoNegation
boolean after(File file) {
return file.mkdirs() || file.exists();
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -282,6 +282,8 @@ final class OptionalRules {
// XXX: The rewritten `filter`/`map` expression may be more performant than its replacement. See
// https://github.com/palantir/gradle-baseline/pull/2946. (There are plans to pair Refaster rules
// with JMH benchmarks; this would be a great use case.)
// XXX: Perhaps `stream.mapMulti(Optional::ifPresent)` is what we should use. See
// https://github.com/palantir/gradle-baseline/pull/2996.
static final class StreamFlatMapOptional<T> {
@BeforeTemplate
Stream<T> before(Stream<Optional<T>> stream) {

View File

@@ -9,7 +9,6 @@ import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Objects.requireNonNull;
import com.google.common.base.Preconditions;
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 +30,7 @@ final class PreconditionsRules {
}
@AfterTemplate
@UseImportPolicy(ImportPolicy.STATIC_IMPORT_ALWAYS)
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(boolean condition) {
checkArgument(!condition);
}

View File

@@ -8,12 +8,15 @@ import com.google.common.primitives.Floats;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts;
import com.google.common.primitives.UnsignedBytes;
import com.google.common.primitives.UnsignedInts;
import com.google.common.primitives.UnsignedLongs;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.Arrays;
import java.util.Comparator;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster rules related to expressions dealing with primitives. */
@@ -525,10 +528,7 @@ final class PrimitiveRules {
}
}
/**
* Prefer JDK's {@link Integer#toUnsignedString(int,int)} over third-party or more verbose
* alternatives.
*/
/** Prefer JDK's {@link Integer#toUnsignedString(int,int)} over third-party alternatives. */
static final class IntegerToUnsignedStringWithRadix {
@BeforeTemplate
String before(int i, int radix) {
@@ -541,10 +541,7 @@ final class PrimitiveRules {
}
}
/**
* Prefer JDK's {@link Long#toUnsignedString(long,int)} over third-party or more verbose
* alternatives.
*/
/** Prefer JDK's {@link Long#toUnsignedString(long,int)} over third-party alternatives. */
static final class LongToUnsignedStringWithRadix {
@BeforeTemplate
String before(long i, int radix) {
@@ -556,4 +553,49 @@ final class PrimitiveRules {
return Long.toUnsignedString(i, radix);
}
}
/** Prefer JDK's {@link Arrays#compareUnsigned(byte[], byte[])} over third-party alternatives. */
// XXX: This rule will yield non-compilable code if the result of the replaced expression is
// dereferenced. Investigate how to make this safe.
static final class ArraysCompareUnsignedBytes {
@BeforeTemplate
Comparator<byte[]> before() {
return UnsignedBytes.lexicographicalComparator();
}
@AfterTemplate
Comparator<byte[]> after() {
return Arrays::compareUnsigned;
}
}
/** Prefer JDK's {@link Arrays#compareUnsigned(int[], int[])} over third-party alternatives. */
// XXX: This rule will yield non-compilable code if the result of the replaced expression is
// dereferenced. Investigate how to make this safe.
static final class ArraysCompareUnsignedInts {
@BeforeTemplate
Comparator<int[]> before() {
return UnsignedInts.lexicographicalComparator();
}
@AfterTemplate
Comparator<int[]> after() {
return Arrays::compareUnsigned;
}
}
/** Prefer JDK's {@link Arrays#compareUnsigned(long[], long[])} over third-party alternatives. */
// XXX: This rule will yield non-compilable code if the result of the replaced expression is
// dereferenced. Investigate how to make this safe.
static final class ArraysCompareUnsignedLongs {
@BeforeTemplate
Comparator<long[]> before() {
return UnsignedLongs.lexicographicalComparator();
}
@AfterTemplate
Comparator<long[]> after() {
return Arrays::compareUnsigned;
}
}
}

View File

@@ -489,9 +489,16 @@ final class ReactorRules {
return Flux.range(value, 1);
}
// XXX: Consider generalizing part of this template using an Error Prone check that covers any
// sequence of explicitly enumerated values passed to an iteration order-preserving collection
// factory method.
@BeforeTemplate
Flux<T> before(T value) {
return Mono.just(value).repeat().take(1);
return Refaster.anyOf(
Mono.just(value).flux(),
Mono.just(value).repeat().take(1),
Flux.fromIterable(ImmutableList.of(value)),
Flux.fromIterable(ImmutableSet.of(value)));
}
@AfterTemplate
@@ -508,8 +515,14 @@ final class ReactorRules {
mono.switchIfEmpty(Mono.empty()), mono.flux().next(), mono.flux().singleOrEmpty());
}
// XXX: Consider filing a SonarCloud issue for the S2637 false positive.
@BeforeTemplate
Mono<@Nullable Void> before2(Mono<@Nullable Void> mono) {
@SuppressWarnings({
"java:S2637" /* False positive: result is never `null`. */,
"java:S4968" /* Result may be `Mono<Void>`. */,
"key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict"
})
Mono<? extends @Nullable Void> before2(Mono<@Nullable Void> mono) {
return Refaster.anyOf(mono.ignoreElement(), mono.then());
}
@@ -889,6 +902,38 @@ final class ReactorRules {
}
}
/**
* Prefer immediately unwrapping {@link Optional} transformation results inside {@link
* Flux#mapNotNull(Function)} over more contrived alternatives.
*/
abstract static class FluxMapNotNullTransformationOrElse<T, S> {
@Placeholder(allowsIdentity = true)
abstract Optional<S> transformation(@MayOptionallyUse T value);
@BeforeTemplate
Flux<S> before(Flux<T> flux) {
return flux.map(v -> transformation(v)).mapNotNull(o -> o.orElse(null));
}
@AfterTemplate
Flux<S> after(Flux<T> flux) {
return flux.mapNotNull(x -> transformation(x).orElse(null));
}
}
/** Prefer {@link Flux#mapNotNull(Function)} over more contrived alternatives. */
static final class FluxMapNotNullOrElse<T> {
@BeforeTemplate
Flux<T> before(Flux<Optional<T>> flux) {
return flux.filter(Optional::isPresent).map(Optional::orElseThrow);
}
@AfterTemplate
Flux<T> after(Flux<Optional<T>> flux) {
return flux.mapNotNull(x -> x.orElse(null));
}
}
/** Prefer {@link Mono#flux()}} over more contrived alternatives. */
static final class MonoFlux<T> {
@BeforeTemplate
@@ -906,12 +951,18 @@ final class ReactorRules {
/** Prefer direct invocation of {@link Mono#then()}} over more contrived alternatives. */
static final class MonoThen<T> {
@BeforeTemplate
Mono<@Nullable Void> before(Mono<T> mono) {
return Refaster.anyOf(mono.ignoreElement().then(), mono.flux().then());
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> before(Mono<T> mono) {
return Refaster.anyOf(
mono.ignoreElement().then(),
mono.flux().then(),
Mono.when(mono),
Mono.whenDelayError(mono));
}
@AfterTemplate
Mono<@Nullable Void> after(Mono<T> mono) {
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> after(Mono<T> mono) {
return mono.then();
}
}
@@ -919,17 +970,25 @@ final class ReactorRules {
/** Avoid vacuous invocations of {@link Flux#ignoreElements()}. */
static final class FluxThen<T> {
@BeforeTemplate
Mono<@Nullable Void> before(Flux<T> flux) {
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> before(Flux<T> flux) {
return flux.ignoreElements().then();
}
// XXX: Consider filing a SonarCloud issue for the S2637 false positive.
@BeforeTemplate
Mono<@Nullable Void> before2(Flux<@Nullable Void> flux) {
@SuppressWarnings({
"java:S2637" /* False positive: result is never `null`. */,
"java:S4968" /* Result may be `Mono<Void>`. */,
"key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict"
})
Mono<? extends @Nullable Void> before2(Flux<@Nullable Void> flux) {
return flux.ignoreElements();
}
@AfterTemplate
Mono<@Nullable Void> after(Flux<T> flux) {
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> after(Flux<T> flux) {
return flux.then();
}
}
@@ -937,12 +996,14 @@ final class ReactorRules {
/** Avoid vacuous invocations of {@link Mono#ignoreElement()}. */
static final class MonoThenEmpty<T> {
@BeforeTemplate
Mono<@Nullable Void> before(Mono<T> mono, Publisher<@Nullable Void> publisher) {
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> before(Mono<T> mono, Publisher<@Nullable Void> publisher) {
return mono.ignoreElement().thenEmpty(publisher);
}
@AfterTemplate
Mono<@Nullable Void> after(Mono<T> mono, Publisher<@Nullable Void> publisher) {
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> after(Mono<T> mono, Publisher<@Nullable Void> publisher) {
return mono.thenEmpty(publisher);
}
}
@@ -950,12 +1011,14 @@ final class ReactorRules {
/** Avoid vacuous invocations of {@link Flux#ignoreElements()}. */
static final class FluxThenEmpty<T> {
@BeforeTemplate
Mono<@Nullable Void> before(Flux<T> flux, Publisher<@Nullable Void> publisher) {
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> before(Flux<T> flux, Publisher<@Nullable Void> publisher) {
return flux.ignoreElements().thenEmpty(publisher);
}
@AfterTemplate
Mono<@Nullable Void> after(Flux<T> flux, Publisher<@Nullable Void> publisher) {
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> after(Flux<T> flux, Publisher<@Nullable Void> publisher) {
return flux.thenEmpty(publisher);
}
}
@@ -1011,7 +1074,8 @@ final class ReactorRules {
}
@BeforeTemplate
Mono<@Nullable Void> before2(Mono<T> mono1, Mono<@Nullable Void> mono2) {
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> before2(Mono<T> mono1, Mono<@Nullable Void> mono2) {
return mono1.thenEmpty(mono2);
}
@@ -1029,7 +1093,8 @@ final class ReactorRules {
}
@BeforeTemplate
Mono<@Nullable Void> before2(Flux<T> flux, Mono<@Nullable Void> mono) {
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> before2(Flux<T> flux, Mono<@Nullable Void> mono) {
return flux.thenEmpty(mono);
}
@@ -1046,10 +1111,12 @@ final class ReactorRules {
// rule. Consider introducing an Error Prone check for this.
static final class MonoSingleOptional<T> {
@BeforeTemplate
Mono<Optional<T>> before(Mono<T> mono) {
Mono<Optional<T>> before(Mono<T> mono, Optional<T> optional, Mono<Optional<T>> alternate) {
return Refaster.anyOf(
mono.flux().collect(toOptional()),
mono.map(Optional::of).defaultIfEmpty(Optional.empty()),
mono.map(Optional::of),
mono.singleOptional().defaultIfEmpty(optional),
mono.singleOptional().switchIfEmpty(alternate),
mono.transform(Mono::singleOptional));
}
@@ -2142,6 +2209,22 @@ final class ReactorRules {
}
}
/**
* Don't propagate {@link Mono} cancellations to upstream cache value computations, as completion
* of such computations may benefit concurrent or subsequent cache usages.
*/
static final class MonoFromFutureAsyncLoadingCacheGetAll<K1, K2 extends K1, V> {
@BeforeTemplate
Mono<Map<K1, V>> before(AsyncLoadingCache<K1, V> cache, Iterable<K2> keys) {
return Mono.fromFuture(() -> cache.getAll(keys));
}
@AfterTemplate
Mono<Map<K1, V>> after(AsyncLoadingCache<K1, V> cache, Iterable<K2> keys) {
return Mono.fromFuture(() -> cache.getAll(keys), /* suppressCancel= */ true);
}
}
/**
* Prefer {@link Flux#fromStream(Supplier)} over {@link Flux#fromStream(Stream)}, as the former
* yields a {@link Flux} that is more likely to behave as expected when subscribed to more than

View File

@@ -23,14 +23,16 @@ final class RxJava2AdapterRules {
/** Use the fluent API style when using {@link RxJava2Adapter#completableToMono}. */
static final class CompletableToMono {
@BeforeTemplate
Mono<@Nullable Void> before(Completable completable) {
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> before(Completable completable) {
return Refaster.anyOf(
RxJava2Adapter.completableToMono(completable),
completable.to(RxJava2Adapter::completableToMono));
}
@AfterTemplate
Mono<@Nullable Void> after(Completable completable) {
@SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
Mono<? extends @Nullable Void> after(Completable completable) {
return completable.as(RxJava2Adapter::completableToMono);
}
}

View File

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

View File

@@ -1,5 +1,6 @@
package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.VisitorState;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -65,16 +66,18 @@ final class SuggestedFixRules {
}
}
/** Prefer {@link SuggestedFix#swap(Tree, Tree)} over more contrived alternatives. */
/**
* Prefer {@link SuggestedFix#swap(Tree, Tree, VisitorState)} over more contrived alternatives.
*/
static final class SuggestedFixSwap {
@BeforeTemplate
SuggestedFix before(Tree tree1, Tree tree2) {
return SuggestedFix.builder().swap(tree1, tree2).build();
SuggestedFix before(Tree tree1, Tree tree2, VisitorState state) {
return SuggestedFix.builder().swap(tree1, tree2, state).build();
}
@AfterTemplate
SuggestedFix after(Tree tree1, Tree tree2) {
return SuggestedFix.swap(tree1, tree2);
SuggestedFix after(Tree tree1, Tree tree2, VisitorState state) {
return SuggestedFix.swap(tree1, tree2, state);
}
}

View File

@@ -53,71 +53,20 @@ import tech.picnic.errorprone.refaster.annotation.TypeMigration;
// XXX: As-is these rules do not result in a complete migration:
// - Expressions containing comments are skipped due to a limitation of Refaster.
// - Assertions inside lambda expressions are also skipped. Unclear why.
// XXX: The `assertEquals` tests for this class generally use the same expression for `expected` and
// XXX: Many of the test expressions for these rules use the same expression for `expected` and
// `actual`, which makes the validation weaker than necessary; fix this. (And investigate whether we
// can introduce validation for this.)
@OnlineDocumentation
@TypeMigration(
of = Assert.class,
unmigratedMethods = {
// XXX: Add migrations for the methods below.
"assertEquals(Boolean, Boolean)",
"assertEquals(Boolean, boolean)",
"assertEquals(boolean, Boolean)",
"assertEquals(Boolean, Boolean, String)",
"assertEquals(Boolean, boolean, String)",
"assertEquals(boolean, Boolean, String)",
"assertEquals(Byte, Byte)",
"assertEquals(Byte, byte)",
"assertEquals(byte, Byte)",
"assertEquals(Byte, Byte, String)",
"assertEquals(Byte, byte, String)",
"assertEquals(byte, Byte, String)",
"assertEquals(char, Character)",
"assertEquals(char, Character, String)",
"assertEquals(Character, char)",
"assertEquals(Character, char, String)",
"assertEquals(Character, Character)",
"assertEquals(Character, Character, String)",
"assertEquals(Double, Double)",
"assertEquals(Double, double)",
"assertEquals(double, Double)",
"assertEquals(Double, Double, String)",
"assertEquals(Double, double, String)",
"assertEquals(double, Double, String)",
"assertEquals(double[], double[], double)",
"assertEquals(double[], double[], double, String)",
"assertEquals(Float, Float)",
"assertEquals(Float, float)",
"assertEquals(float, Float)",
"assertEquals(Float, Float, String)",
"assertEquals(Float, float, String)",
"assertEquals(float, Float, String)",
"assertEquals(float[], float[], float)",
"assertEquals(float[], float[], float, String)",
"assertEquals(int, Integer)",
"assertEquals(int, Integer, String)",
"assertEquals(Integer, int)",
"assertEquals(Integer, int, String)",
"assertEquals(Integer, Integer)",
"assertEquals(Integer, Integer, String)",
"assertEquals(Long, Long)",
"assertEquals(Long, long)",
"assertEquals(long, Long)",
"assertEquals(Long, Long, String)",
"assertEquals(Long, long, String)",
"assertEquals(Short, Short)",
"assertEquals(Short, short)",
"assertEquals(short, Short)",
"assertEquals(Short, Short, String)",
"assertEquals(Short, short, String)",
"assertEquals(short, Short, String)",
/*
* These `assertEqualsDeep` methods cannot (easily) be expressed using AssertJ because they
* mix regular equality and array equality:
*/
"assertEqualsDeep(Map<?, ?>, Map<?, ?>)",
"assertEqualsDeep(Map<?, ?>, Map<?, ?>, String)",
"assertEqualsDeep(Set<?>, Set<?>)",
"assertEqualsDeep(Set<?>, Set<?>, String)",
// XXX: Add migrations for the methods below.
"assertEqualsNoOrder(Collection<?>, Collection<?>)",
@@ -351,47 +300,168 @@ final class TestNGToAssertJRules {
}
}
@SuppressWarnings("java:S1448" /* Each variant requires a separate `@BeforeTemplate` method. */)
static final class AssertEqual {
@BeforeTemplate
void before(boolean actual, boolean expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(boolean actual, Boolean expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Boolean actual, boolean expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Boolean actual, Boolean expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(byte actual, byte expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(byte actual, Byte expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Byte actual, byte expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Byte actual, Byte expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(char actual, char expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(char actual, Character expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Character actual, char expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Character actual, Character expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(short actual, short expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(short actual, Short expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Short actual, short expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Short actual, Short expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(int actual, int expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(int actual, Integer expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Integer actual, int expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Integer actual, Integer expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(long actual, long expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(long actual, Long expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Long actual, long expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Long actual, Long expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(float actual, float expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(float actual, Float expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Float actual, float expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Float actual, Float expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(double actual, double expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(double actual, Double expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Double actual, double expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Double actual, Double expected) {
assertEquals(actual, expected);
}
@BeforeTemplate
void before(Object actual, Object expected) {
assertEquals(actual, expected);
@@ -414,47 +484,168 @@ final class TestNGToAssertJRules {
}
}
@SuppressWarnings("java:S1448" /* Each variant requires a separate `@BeforeTemplate` method. */)
static final class AssertEqualWithMessage {
@BeforeTemplate
void before(boolean actual, String message, boolean expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(boolean actual, String message, Boolean expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Boolean actual, String message, boolean expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Boolean actual, String message, Boolean expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(byte actual, String message, byte expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(byte actual, String message, Byte expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Byte actual, String message, byte expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Byte actual, String message, Byte expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(char actual, String message, char expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(char actual, String message, Character expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Character actual, String message, char expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Character actual, String message, Character expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(short actual, String message, short expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(short actual, String message, Short expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Short actual, String message, short expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Short actual, String message, Short expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(int actual, String message, int expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(int actual, String message, Integer expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Integer actual, String message, int expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Integer actual, String message, Integer expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(long actual, String message, long expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(long actual, String message, Long expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Long actual, String message, long expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Long actual, String message, Long expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(float actual, String message, float expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(float actual, String message, Float expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Float actual, String message, float expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Float actual, String message, Float expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(double actual, String message, double expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(double actual, String message, Double expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Double actual, String message, double expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Double actual, String message, Double expected) {
assertEquals(actual, expected, message);
}
@BeforeTemplate
void before(Object actual, String message, Object expected) {
assertEquals(actual, expected, message);
@@ -485,7 +676,7 @@ final class TestNGToAssertJRules {
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float actual, float expected, float delta) {
void after(Float actual, float expected, float delta) {
assertThat(actual).isCloseTo(expected, offset(delta));
}
}
@@ -635,6 +826,58 @@ final class TestNGToAssertJRules {
}
}
static final class AssertEqualFloatArraysWithDelta {
@BeforeTemplate
void before(float[] actual, float[] expected, float delta) {
assertEquals(actual, expected, delta);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float[] actual, float[] expected, float delta) {
assertThat(actual).containsExactly(expected, offset(delta));
}
}
static final class AssertEqualFloatArraysWithDeltaWithMessage {
@BeforeTemplate
void before(float[] actual, String message, float[] expected, float delta) {
assertEquals(actual, expected, delta, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(float[] actual, String message, float[] expected, float delta) {
assertThat(actual).withFailMessage(message).containsExactly(expected, offset(delta));
}
}
static final class AssertEqualDoubleArraysWithDelta {
@BeforeTemplate
void before(double[] actual, double[] expected, double delta) {
assertEquals(actual, expected, delta);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double[] actual, double[] expected, double delta) {
assertThat(actual).containsExactly(expected, offset(delta));
}
}
static final class AssertEqualDoubleArraysWithDeltaWithMessage {
@BeforeTemplate
void before(double[] actual, String message, double[] expected, double delta) {
assertEquals(actual, expected, delta, message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(double[] actual, String message, double[] expected, double delta) {
assertThat(actual).withFailMessage(message).containsExactly(expected, offset(delta));
}
}
static final class AssertEqualArraysIrrespectiveOfOrder {
@BeforeTemplate
void before(Object[] actual, Object[] expected) {

View File

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

View File

@@ -16,6 +16,8 @@ final class ExplicitArgumentEnumerationTest {
"import com.google.common.collect.ImmutableList;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"import io.micrometer.core.instrument.Counter;",
"import io.micrometer.core.instrument.Tag;",
"import org.jooq.impl.DSL;",
"import reactor.core.publisher.Flux;",
"import reactor.test.StepVerifier;",
@@ -32,6 +34,8 @@ final class ExplicitArgumentEnumerationTest {
"",
" DSL.row(ImmutableList.of(1, 2));",
"",
" Counter.builder(\"foo\").tags(ImmutableList.of(Tag.of(\"bar\", \"baz\")));",
"",
" // BUG: Diagnostic contains:",
" unaryMethod(ImmutableList.of(1, 2));",
" unaryMethodWithLessVisibleOverload(ImmutableList.of(1, 2));",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -39,4 +39,16 @@ final class FileRulesTest implements RefasterRuleCollectionTestCase {
File testFilesCreateTempFileInCustomDirectoryToFile() throws IOException {
return File.createTempFile("foo", "bar", new File("baz"));
}
ImmutableSet<Boolean> testPathToFileMkDirsFilesExists() {
return ImmutableSet.of(
Files.exists(Path.of("foo")) || Path.of("foo").toFile().mkdirs(),
!Files.exists(Path.of("bar")) && !Path.of("bar").toFile().mkdirs());
}
ImmutableSet<Boolean> testFileMkDirsFileExists() {
return ImmutableSet.of(
new File("foo").exists() || new File("foo").mkdirs(),
!new File("bar").exists() && !new File("bar").mkdirs());
}
}

View File

@@ -39,4 +39,16 @@ final class FileRulesTest implements RefasterRuleCollectionTestCase {
File testFilesCreateTempFileInCustomDirectoryToFile() throws IOException {
return Files.createTempFile(new File("baz").toPath(), "foo", "bar").toFile();
}
ImmutableSet<Boolean> testPathToFileMkDirsFilesExists() {
return ImmutableSet.of(
Path.of("foo").toFile().mkdirs() || Files.exists(Path.of("foo")),
!Path.of("bar").toFile().mkdirs() && !Files.exists(Path.of("bar")));
}
ImmutableSet<Boolean> testFileMkDirsFileExists() {
return ImmutableSet.of(
new File("foo").mkdirs() || new File("foo").exists(),
!new File("bar").mkdirs() && !new File("bar").exists());
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,8 +9,10 @@ import com.google.common.primitives.Floats;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts;
import com.google.common.primitives.UnsignedBytes;
import com.google.common.primitives.UnsignedInts;
import com.google.common.primitives.UnsignedLongs;
import java.util.Comparator;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
@@ -25,6 +27,7 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
Ints.class,
Longs.class,
Shorts.class,
UnsignedBytes.class,
UnsignedInts.class,
UnsignedLongs.class);
}
@@ -222,4 +225,16 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
String testLongToUnsignedStringWithRadix() {
return UnsignedLongs.toString(1, 2);
}
Comparator<byte[]> testArraysCompareUnsignedBytes() {
return UnsignedBytes.lexicographicalComparator();
}
Comparator<int[]> testArraysCompareUnsignedInts() {
return UnsignedInts.lexicographicalComparator();
}
Comparator<long[]> testArraysCompareUnsignedLongs() {
return UnsignedLongs.lexicographicalComparator();
}
}

View File

@@ -9,8 +9,11 @@ import com.google.common.primitives.Floats;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts;
import com.google.common.primitives.UnsignedBytes;
import com.google.common.primitives.UnsignedInts;
import com.google.common.primitives.UnsignedLongs;
import java.util.Arrays;
import java.util.Comparator;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
@@ -25,6 +28,7 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
Ints.class,
Longs.class,
Shorts.class,
UnsignedBytes.class,
UnsignedInts.class,
UnsignedLongs.class);
}
@@ -222,4 +226,16 @@ final class PrimitiveRulesTest implements RefasterRuleCollectionTestCase {
String testLongToUnsignedStringWithRadix() {
return Long.toUnsignedString(1, 2);
}
Comparator<byte[]> testArraysCompareUnsignedBytes() {
return Arrays::compareUnsigned;
}
Comparator<int[]> testArraysCompareUnsignedInts() {
return Arrays::compareUnsigned;
}
Comparator<long[]> testArraysCompareUnsignedLongs() {
return Arrays::compareUnsigned;
}
}

View File

@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
@@ -187,7 +188,12 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
}
ImmutableSet<Flux<Integer>> testFluxJust() {
return ImmutableSet.of(Flux.range(0, 1), Mono.just(2).repeat().take(1));
return ImmutableSet.of(
Flux.range(0, 1),
Mono.just(2).flux(),
Mono.just(3).repeat().take(1),
Flux.fromIterable(ImmutableList.of(4)),
Flux.fromIterable(ImmutableSet.of(5)));
}
ImmutableSet<Mono<?>> testMonoIdentity() {
@@ -325,6 +331,14 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
Flux.just(1).switchMap(n -> Mono.fromSupplier(() -> n * 2)));
}
Flux<String> testFluxMapNotNullTransformationOrElse() {
return Flux.just(1).map(x -> Optional.of(x.toString())).mapNotNull(x -> x.orElse(null));
}
Flux<Integer> testFluxMapNotNullOrElse() {
return Flux.just(Optional.of(1)).filter(Optional::isPresent).map(Optional::orElseThrow);
}
ImmutableSet<Flux<String>> testMonoFlux() {
return ImmutableSet.of(
Mono.just("foo").flatMapMany(Mono::just),
@@ -333,7 +347,11 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
}
ImmutableSet<Mono<Void>> testMonoThen() {
return ImmutableSet.of(Mono.just("foo").ignoreElement().then(), Mono.just("bar").flux().then());
return ImmutableSet.of(
Mono.just("foo").ignoreElement().then(),
Mono.just("bar").flux().then(),
Mono.when(Mono.just("baz")),
Mono.whenDelayError(Mono.just("qux")));
}
ImmutableSet<Mono<Void>> testFluxThen() {
@@ -379,8 +397,10 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
ImmutableSet<Mono<Optional<String>>> testMonoSingleOptional() {
return ImmutableSet.of(
Mono.just("foo").flux().collect(toOptional()),
Mono.just("bar").map(Optional::of).defaultIfEmpty(Optional.empty()),
Mono.just("baz").transform(Mono::singleOptional));
Mono.just("bar").map(Optional::of),
Mono.just("baz").singleOptional().defaultIfEmpty(Optional.empty()),
Mono.just("quux").singleOptional().switchIfEmpty(Mono.just(Optional.empty())),
Mono.just("quuz").transform(Mono::singleOptional));
}
Mono<Number> testMonoCast() {
@@ -737,6 +757,11 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return Mono.fromFuture(() -> ((AsyncLoadingCache<Integer, String>) null).get(0));
}
Mono<Map<Integer, String>> testMonoFromFutureAsyncLoadingCacheGetAll() {
return Mono.fromFuture(
() -> ((AsyncLoadingCache<Integer, String>) null).getAll(ImmutableSet.of()));
}
Flux<Integer> testFluxFromStreamSupplier() {
return Flux.fromStream(Stream.of(1));
}

View File

@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
@@ -191,7 +192,7 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
}
ImmutableSet<Flux<Integer>> testFluxJust() {
return ImmutableSet.of(Flux.just(0), Flux.just(2));
return ImmutableSet.of(Flux.just(0), Flux.just(2), Flux.just(3), Flux.just(4), Flux.just(5));
}
ImmutableSet<Mono<?>> testMonoIdentity() {
@@ -325,13 +326,25 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
Flux.just(1).mapNotNull(n -> n * 2));
}
Flux<String> testFluxMapNotNullTransformationOrElse() {
return Flux.just(1).mapNotNull(x -> Optional.of(x.toString()).orElse(null));
}
Flux<Integer> testFluxMapNotNullOrElse() {
return Flux.just(Optional.of(1)).mapNotNull(x -> x.orElse(null));
}
ImmutableSet<Flux<String>> testMonoFlux() {
return ImmutableSet.of(
Mono.just("foo").flux(), Mono.just("bar").flux(), Mono.just("baz").flux());
}
ImmutableSet<Mono<Void>> testMonoThen() {
return ImmutableSet.of(Mono.just("foo").then(), Mono.just("bar").then());
return ImmutableSet.of(
Mono.just("foo").then(),
Mono.just("bar").then(),
Mono.just("baz").then(),
Mono.just("qux").then());
}
ImmutableSet<Mono<Void>> testFluxThen() {
@@ -375,7 +388,9 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableSet.of(
Mono.just("foo").singleOptional(),
Mono.just("bar").singleOptional(),
Mono.just("baz").singleOptional());
Mono.just("baz").singleOptional(),
Mono.just("quux").singleOptional(),
Mono.just("quuz").singleOptional());
}
Mono<Number> testMonoCast() {
@@ -711,6 +726,11 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return Mono.fromFuture(() -> ((AsyncLoadingCache<Integer, String>) null).get(0), true);
}
Mono<Map<Integer, String>> testMonoFromFutureAsyncLoadingCacheGetAll() {
return Mono.fromFuture(
() -> ((AsyncLoadingCache<Integer, String>) null).getAll(ImmutableSet.of()), true);
}
Flux<Integer> testFluxFromStreamSupplier() {
return Flux.fromStream(() -> Stream.of(1));
}

View File

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

View File

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

View File

@@ -1,5 +1,6 @@
package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.VisitorState;
import com.google.errorprone.fixes.SuggestedFix;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.Tree;
@@ -23,7 +24,9 @@ final class SuggestedFixRulesTest implements RefasterRuleCollectionTestCase {
}
SuggestedFix testSuggestedFixSwap() {
return SuggestedFix.builder().swap((Tree) null, (ExpressionTree) null).build();
return SuggestedFix.builder()
.swap((Tree) null, (ExpressionTree) null, (VisitorState) null)
.build();
}
SuggestedFix testSuggestedFixPrefixWith() {

View File

@@ -1,5 +1,6 @@
package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.VisitorState;
import com.google.errorprone.fixes.SuggestedFix;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.Tree;
@@ -23,7 +24,7 @@ final class SuggestedFixRulesTest implements RefasterRuleCollectionTestCase {
}
SuggestedFix testSuggestedFixSwap() {
return SuggestedFix.swap((Tree) null, (ExpressionTree) null);
return SuggestedFix.swap((Tree) null, (ExpressionTree) null, (VisitorState) null);
}
SuggestedFix testSuggestedFixPrefixWith() {

View File

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

View File

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

View File

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

View File

@@ -29,6 +29,7 @@ import com.sun.source.tree.ReturnTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Type;
import java.util.List;
import java.util.Optional;
@@ -126,7 +127,7 @@ public final class MethodReferenceUsage extends BugChecker implements LambdaExpr
return Optional.empty();
}
Symbol sym = ASTHelpers.getSymbol(methodSelect);
Symbol sym = ASTHelpers.getSymbol(subTree);
return ASTHelpers.isStatic(sym)
? constructFix(lambdaExpr, sym.owner, methodSelect)
: constructFix(lambdaExpr, "this", methodSelect);
@@ -200,7 +201,8 @@ public final class MethodReferenceUsage extends BugChecker implements LambdaExpr
Name sName = target.getSimpleName();
Optional<SuggestedFix.Builder> fix = constructFix(lambdaExpr, sName, methodName);
if (!"java.lang".equals(ASTHelpers.enclosingPackage(target).toString())) {
PackageSymbol pkg = ASTHelpers.enclosingPackage(target);
if (pkg != null && !"java.lang".equals(pkg.toString())) {
Name fqName = target.getQualifiedName();
if (!sName.equals(fqName)) {
return fix.map(b -> b.addImport(fqName.toString()));

View File

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

View File

@@ -46,7 +46,6 @@ import java.util.Set;
import java.util.function.Consumer;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Modifier;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.utils.SourceCode;
@@ -102,7 +101,8 @@ public final class ExhaustiveRefasterTypeMigration extends BugChecker implements
AnnotationTree migrationAnnotation = migrationAnnotations.onlyMatchingNode();
AnnotationMirror annotationMirror = ASTHelpers.getAnnotationMirror(migrationAnnotation);
TypeSymbol migratedType = getMigratedType(annotationMirror);
if (migratedType.asType().isPrimitive() || !(migratedType instanceof ClassSymbol)) {
if (migratedType.asType().isPrimitive()
|| !(migratedType instanceof ClassSymbol migratedClass)) {
return buildDescription(migrationAnnotation)
.setMessage(String.format("Migration of type '%s' is unsupported", migratedType))
.build();
@@ -111,7 +111,7 @@ public final class ExhaustiveRefasterTypeMigration extends BugChecker implements
ImmutableList<String> methodsClaimedUnmigrated = getMethodsClaimedUnmigrated(annotationMirror);
ImmutableList<String> unmigratedMethods =
getMethodsDefinitelyUnmigrated(
tree, (ClassSymbol) migratedType, signatureOrder(methodsClaimedUnmigrated), state);
tree, migratedClass, signatureOrder(methodsClaimedUnmigrated), state);
if (unmigratedMethods.equals(methodsClaimedUnmigrated)) {
return Description.NO_MATCH;
@@ -160,17 +160,11 @@ public final class ExhaustiveRefasterTypeMigration extends BugChecker implements
.getValue().stream().map(a -> a.getValue().toString()).collect(toImmutableList());
}
// XXX: Once only JDK 14 and above are supported, change the
// `m.getModifiers().contains(Modifier.PUBLIC)` check to just `m.isPublic()`.
private static ImmutableList<String> getMethodsDefinitelyUnmigrated(
ClassTree tree, ClassSymbol migratedType, Comparator<String> comparator, VisitorState state) {
Set<MethodSymbol> publicMethods =
Streams.stream(
ASTHelpers.scope(migratedType.members())
.getSymbols(
m ->
m.getModifiers().contains(Modifier.PUBLIC)
&& m instanceof MethodSymbol))
migratedType.members().getSymbols(m -> m.isPublic() && m instanceof MethodSymbol))
.map(MethodSymbol.class::cast)
.collect(toCollection(HashSet::new));

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.19.2-SNAPSHOT</version>
<version>0.22.1-SNAPSHOT</version>
</parent>
<artifactId>error-prone-utils</artifactId>
@@ -16,22 +16,22 @@
<dependencies>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_test_helpers</artifactId>
<scope>provided</scope>
</dependency>

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