Compare commits

...

250 Commits

Author SHA1 Message Date
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
Picnic-DevPla-Bot
72b701cae3 Upgrade OpenRewrite Templating 1.20.1 -> 1.20.2 (#1478)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.20.2
- https://github.com/openrewrite/rewrite-templating/compare/v1.20.1...v1.20.2
2024-12-24 13:48:48 +01:00
Rick Ossendrijver
24e3251eb0 Introduce Prometheus Java Client integration test (#1468)
And document some possible future improvements.
2024-12-24 10:36:23 +01:00
Stephan Schroevers
f124749a4f Generalize AssertThatThrownBy Refaster rule (#1477)
By replacing it with the `AssertThatThrownByAsInstanceOfThrowable` and
`AssertThatThrownByIsInstanceOf` rules that are slightly more type-safe.
2024-12-23 17:33:42 +01:00
Stephan Schroevers
2a3d9c8dd5 Improve ExplicitArgumentEnumeration check (#1475)
Summary of changes:
- Also drop unnecessary `Immutable{List,Multiset,Set}#copyOf(E[])`
  invocations.
- Don't suggest simplifications that are likely to introduce unbounded
  recursion.
2024-12-23 10:15:27 +01:00
Philipp Zeipert
0fa59a5cec Introduce StreamMapFilter Refaster rule (#1467) 2024-12-23 09:38:43 +01:00
Stephan Schroevers
d316e8ac70 Improve JUnitMethodDeclaration method rename heuristics (#1476)
These changes make it less likely that the check suggests a method
rename that would yield invalid code.
2024-12-23 09:17:45 +01:00
Picnic-DevPla-Bot
53fe15c356 Upgrade OpenRewrite Templating 1.20.0 -> 1.20.1 (#1474)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.20.1
- https://github.com/openrewrite/rewrite-templating/compare/v1.20.0...v1.20.1
2024-12-22 13:35:25 +01:00
Rick Ossendrijver
acb8b651b7 Introduce AssertThatThrownBy*ExceptionRootCauseHasMessage Refaster rules (#1471) 2024-12-22 12:36:52 +01:00
Picnic-DevPla-Bot
ace6bc2813 Upgrade Spring Boot 3.4.0 -> 3.4.1 (#1473)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v3.4.1
- https://github.com/spring-projects/spring-boot/compare/v3.4.0...v3.4.1
2024-12-21 11:24:35 +01:00
Picnic-DevPla-Bot
f69fef2f52 Upgrade OpenRewrite 2.23.1 -> 2.23.2 (#1469)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.23.2
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.23.1...v2.23.2
2024-12-20 14:10:44 +01:00
Picnic-DevPla-Bot
d033b84b5b Upgrade Spring 6.2.0 -> 6.2.1 (#1459)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.1
- https://github.com/spring-projects/spring-framework/compare/v6.2.0...v6.2.1
2024-12-20 08:49:06 +01:00
Picnic-DevPla-Bot
3e702733bc Upgrade OpenRewrite Templating 1.19.1 -> 1.20.0 (#1470)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.20.0
- https://github.com/openrewrite/rewrite-templating/compare/v1.19.1...v1.20.0
2024-12-20 08:23:37 +01:00
Picnic-DevPla-Bot
f212e9476d Upgrade Guava 33.3.1-jre -> 33.4.0-jre (#1462)
See:
- https://guava.dev/releases/33.4.0-jre/api/diffs/
- https://github.com/google/guava/releases/tag/v33.4.0
- https://github.com/google/guava/compare/v33.3.1...v33.4.0
2024-12-19 12:46:23 +01:00
Picnic-DevPla-Bot
da00863e34 Upgrade pitest-maven-plugin 1.17.2 -> 1.17.3 (#1465)
See:
- https://github.com/hcoles/pitest/releases/tag/1.17.3
- https://github.com/hcoles/pitest/compare/1.17.2...1.17.3
2024-12-18 10:13:18 +01:00
Picnic-DevPla-Bot
476916f381 Upgrade JUnit 5 5.11.3 -> 5.11.4 (#1463)
See:
- https://junit.org/junit5/docs/current/release-notes/
- https://github.com/junit-team/junit5/releases/tag/r5.11.4
- https://github.com/junit-team/junit5/compare/r5.11.3...r5.11.4
2024-12-18 09:51:10 +01:00
Picnic-DevPla-Bot
67bf5b98a8 Upgrade actions/upload-artifact v4.4.3 -> v4.5.0 (#1466)
See:
- https://github.com/actions/upload-artifact/releases/tag/v4.5.0
2024-12-18 09:14:26 +01:00
Picnic-DevPla-Bot
db7757c556 Upgrade Spring Security 6.4.1 -> 6.4.2 (#1464)
See:
- https://github.com/spring-projects/spring-security/releases/tag/6.4.2
- https://github.com/spring-projects/spring-security/compare/6.4.1...6.4.2
2024-12-18 08:51:49 +01:00
Picnic-DevPla-Bot
bfd309800b Upgrade Checkstyle 10.20.2 -> 10.21.0 (#1460)
While there, also update the integration test.

See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.21.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.20.2...checkstyle-10.21.0
2024-12-18 08:41:28 +01:00
Picnic-DevPla-Bot
0121f7b33c Upgrade NullAway 0.12.1 -> 0.12.2 (#1458)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.12.2
- https://github.com/uber/NullAway/compare/v0.12.1...v0.12.2
2024-12-17 09:12:46 +01:00
Mohamed Sameh
8dbff50a8b Ignore type variable casts in ClassCastLambdaUsage check (#1449) 2024-12-16 15:47:36 +01:00
Picnic-DevPla-Bot
aec56ce025 Upgrade Byte Buddy 1.15.10 -> 1.15.11 (#1461)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.15.11
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.15.10...byte-buddy-1.15.11
2024-12-16 14:37:00 +01:00
Stephan Schroevers
1b8ffd86b9 Introduce ExplicitArgumentEnumeration check (#985) 2024-12-16 09:15:30 +01:00
Picnic-DevPla-Bot
ee7be7e3b2 Upgrade Swagger 2.2.26 -> 2.2.27 (#1457)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.27
- https://github.com/swagger-api/swagger-core/compare/v2.2.26...v2.2.27
2024-12-13 09:49:29 +01:00
Picnic-DevPla-Bot
57825decf0 Upgrade Google Java Format 1.25.1 -> 1.25.2 (#1456)
See:
- https://github.com/google/google-java-format/releases/tag/v1.25.2
- https://github.com/google/google-java-format/compare/v1.25.1...v1.25.2
2024-12-13 09:34:46 +01:00
Stephan Schroevers
2b3e11bd24 Make integration tests Error Prone 2.36.0-compatible (#1455) 2024-12-12 09:12:23 +01:00
Picnic-DevPla-Bot
23cb29b6fc Upgrade Project Reactor 2024.0.0 -> 2024.0.1 (#1454)
See:
- https://github.com/reactor/reactor/releases/tag/2024.0.1
- https://github.com/reactor/reactor/compare/2024.0.0...2024.0.1
2024-12-11 14:46:21 +01:00
Picnic-DevPla-Bot
ba1dd2cd08 Upgrade Micrometer 1.14.1 -> 1.14.2 (#1453)
See:
- https://github.com/micrometer-metrics/micrometer/releases/tag/v1.14.2
- https://github.com/micrometer-metrics/micrometer/compare/v1.14.1...v1.14.2
2024-12-11 11:58:48 +01:00
Picnic-DevPla-Bot
75a9786f8f Upgrade Google Java Format 1.25.0 -> 1.25.1 (#1452)
See:
- https://github.com/google/google-java-format/releases/tag/v1.25.1
- https://github.com/google/google-java-format/compare/v1.25.0...v1.25.1
2024-12-10 14:16:55 +01:00
Picnic-DevPla-Bot
0b4fd8ddd1 Upgrade org.codehaus.mojo:license-maven-plugin 2.4.0 -> 2.5.0 (#1445)
See:
- https://github.com/mojohaus/license-maven-plugin/releases/tag/2.5.0
- https://github.com/mojohaus/license-maven-plugin/compare/2.4.0...2.5.0
2024-12-10 08:52:57 +01:00
Phil Werli
2eda393c03 Introduce PublisherProbeAssertWas{,Not}{Subscribed,Cancelled,Requested} Refaster rules (#1423)
While there, fix a typo in `README.md`.
2024-12-09 14:25:06 +01:00
Picnic-DevPla-Bot
512a3bebad Upgrade Error Prone 2.35.1 -> 2.36.0 (#1429)
And update the compatibility matrix and its generation script.

See:
- https://github.com/google/error-prone/releases/tag/v2.36.0
- https://github.com/google/error-prone/compare/v2.35.1...v2.36.0
- https://github.com/PicnicSupermarket/error-prone/compare/v2.35.1-picnic-1...v2.36.0-picnic-1
2024-12-09 12:20:52 +01:00
Stephan Schroevers
db18d6a1fc Drop the JavaKeywords class (#1442)
Instead:
- Move its sole used method `#isValidIdentifier` to the `SourceCode`
  class.
- Delegate most of said method's implementation to
  `javax.lang.model.SourceVersion`.
2024-12-09 09:26:56 +01:00
Picnic-DevPla-Bot
75ca3030f7 Upgrade OpenRewrite Templating 1.17.1 -> 1.19.1 (#1437)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.18.0
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.19.0
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.19.1
- https://github.com/openrewrite/rewrite-templating/compare/v1.17.1...v1.19.1
2024-12-09 08:49:31 +01:00
Picnic-DevPla-Bot
f484c3f10b Upgrade Micrometer 1.14.0 -> 1.14.1 (#1439)
See:
- https://github.com/micrometer-metrics/micrometer/releases/tag/v1.14.1
- https://github.com/micrometer-metrics/micrometer/compare/v1.14.0...v1.14.1
2024-12-08 20:23:43 +01:00
Picnic-DevPla-Bot
0753de05d1 Upgrade Checkstyle 10.20.1 -> 10.20.2 (#1443)
While there, also update the integration test.

See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.20.2
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.20.1...checkstyle-10.20.2
2024-12-08 19:21:16 +01:00
Picnic-DevPla-Bot
ab0847e49f Upgrade Checker Framework Annotations 3.48.2 -> 3.48.3 (#1448)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.48.3
- https://github.com/typetools/checker-framework/compare/checker-framework-3.48.2...checker-framework-3.48.3
2024-12-08 17:00:18 +01:00
Picnic-DevPla-Bot
f9383e4e94 Upgrade OpenRewrite 2.22.0 -> 2.23.1 (#1440)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.23.0
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.23.1
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.22.0...v2.23.1
2024-12-08 16:08:46 +01:00
Picnic-DevPla-Bot
50b6c31675 Upgrade Jackson 2.18.1 -> 2.18.2 (#1441)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.18.2
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.18.1...jackson-bom-2.18.2
2024-12-08 15:35:42 +01:00
Picnic-DevPla-Bot
63e78933ac Upgrade pitest-maven-plugin 1.17.1 -> 1.17.2 (#1444)
See:
- https://github.com/hcoles/pitest/releases/tag/1.17.2
- https://github.com/hcoles/pitest/compare/1.17.1...1.17.2
2024-12-08 15:22:23 +01:00
Picnic-DevPla-Bot
cd0e962ef7 Upgrade s4u/setup-maven-action v1.16.0 -> v1.17.0 (#1451)
See:
- https://github.com/s4u/setup-maven-action/releases/tag/v1.17.0
2024-12-08 15:04:27 +01:00
Picnic-DevPla-Bot
107d135894 Upgrade maven-javadoc-plugin 3.11.1 -> 3.11.2 (#1450)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MJAVADOC%20AND%20fixVersion%20%3E%203.11.1%20AND%20fixVersion%20%3C%3D%203.11.2
- https://github.com/apache/maven-javadoc-plugin/releases/tag/maven-javadoc-plugin-3.11.2
- https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.11.1...maven-javadoc-plugin-3.11.2
2024-12-08 14:51:46 +01:00
Picnic-DevPla-Bot
0bc43a32b9 Upgrade Project Reactor 2023.0.11 -> 2024.0.0 (#1417)
See:
- https://github.com/reactor/reactor/releases/tag/2023.0.12
- https://github.com/reactor/reactor/releases/tag/2024.0.0-M1
- https://github.com/reactor/reactor/releases/tag/2024.0.0-M2
- https://github.com/reactor/reactor/releases/tag/2024.0.0-M3
- https://github.com/reactor/reactor/releases/tag/2024.0.0-M4
- https://github.com/reactor/reactor/releases/tag/2024.0.0-M5
- https://github.com/reactor/reactor/releases/tag/2024.0.0-M6
- https://github.com/reactor/reactor/releases/tag/2024.0.0-RC1
- https://github.com/reactor/reactor/releases/tag/2024.0.0
- https://github.com/reactor/reactor/compare/2023.0.11...2024.0.0
2024-12-03 08:43:28 +01:00
Picnic-DevPla-Bot
1024f0e671 Upgrade step-security/harden-runner v2.10.1 -> v2.10.2 (#1428)
See:
- https://github.com/step-security/harden-runner/releases/tag/v2.10.2
2024-12-02 10:26:55 +01:00
Picnic-DevPla-Bot
3eb7cf740f Upgrade ruby/setup-ruby v1.199.0 -> v1.202.0 (#1447)
See:
- https://github.com/ruby/setup-ruby/releases/tag/v1.202.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.201.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.200.0
2024-12-02 10:05:37 +01:00
Picnic-DevPla-Bot
2713a7ed67 Upgrade CodeQL v3.25.1 -> v3.27.5 (#1446)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/releases/tag/v3.25.2
- https://github.com/github/codeql-action/releases/tag/v3.25.3
- https://github.com/github/codeql-action/releases/tag/v3.25.4
- https://github.com/github/codeql-action/releases/tag/v3.25.5
- https://github.com/github/codeql-action/releases/tag/v3.25.6
- https://github.com/github/codeql-action/releases/tag/v3.25.7
- https://github.com/github/codeql-action/releases/tag/v3.25.8
- https://github.com/github/codeql-action/releases/tag/v3.25.9
- https://github.com/github/codeql-action/releases/tag/v3.25.10
- https://github.com/github/codeql-action/releases/tag/v3.25.11
- https://github.com/github/codeql-action/releases/tag/v3.25.12
- https://github.com/github/codeql-action/releases/tag/v3.25.13
- https://github.com/github/codeql-action/releases/tag/v3.25.14
- https://github.com/github/codeql-action/releases/tag/v3.25.15
- https://github.com/github/codeql-action/releases/tag/v3.26.0
- https://github.com/github/codeql-action/releases/tag/v3.26.1
- https://github.com/github/codeql-action/releases/tag/v3.26.2
- https://github.com/github/codeql-action/releases/tag/v3.26.3
- https://github.com/github/codeql-action/releases/tag/v3.26.4
- https://github.com/github/codeql-action/releases/tag/v3.26.5
- https://github.com/github/codeql-action/releases/tag/v3.26.6
- https://github.com/github/codeql-action/releases/tag/v3.26.7
- https://github.com/github/codeql-action/releases/tag/v3.26.8
- https://github.com/github/codeql-action/releases/tag/v3.26.9
- https://github.com/github/codeql-action/releases/tag/v3.26.10
- https://github.com/github/codeql-action/releases/tag/v3.26.11
- https://github.com/github/codeql-action/releases/tag/v3.26.12
- https://github.com/github/codeql-action/releases/tag/v3.26.13
- https://github.com/github/codeql-action/releases/tag/v3.27.0
- https://github.com/github/codeql-action/releases/tag/v3.27.1
- https://github.com/github/codeql-action/releases/tag/v3.27.2
- https://github.com/github/codeql-action/releases/tag/v3.27.3
- https://github.com/github/codeql-action/releases/tag/v3.27.4
- https://github.com/github/codeql-action/releases/tag/v3.27.5
- https://github.com/github/codeql-action/compare/v3.25.1...v3.27.5
2024-12-02 09:45:37 +01:00
Picnic-DevPla-Bot
8ba75245b4 Upgrade Google Java Format 1.24.0 -> 1.25.0 (#1430)
See:
- https://github.com/google/google-java-format/releases/tag/v1.25.0
- https://github.com/google/google-java-format/compare/v1.24.0...v1.25.0
2024-12-01 23:42:46 +01:00
Rick Ossendrijver
b3d391c80d Introduce Dropwizard Metrics integration test (#1426) 2024-11-28 15:05:35 +01:00
Picnic-DevPla-Bot
43a1ea1d6c Upgrade Spring 6.1.14 -> 6.2.0 (#1422)
See:
- https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-6.2-Release-Notes
- https://github.com/spring-projects/spring-framework/releases/tag/v6.1.15
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.0-M1
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.0-M2
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.0-M3
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.0-M4
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.0-M5
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.0-M6
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.0-M7
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.0-RC1
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.0-RC2
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.0-RC3
- https://github.com/spring-projects/spring-framework/releases/tag/v6.2.0
- https://github.com/spring-projects/spring-framework/compare/v6.1.14...v6.2.0
2024-11-27 23:04:26 +01:00
Picnic-DevPla-Bot
c4fd4871fc Replace deprecated Renovate configuration (#1438) 2024-11-27 18:24:54 +01:00
Picnic-DevPla-Bot
23bbb34fb7 Upgrade Spring Boot 3.3.5 -> 3.4.0 (#1435)
See:
- https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.4-Release-Notes
- https://github.com/spring-projects/spring-boot/releases/tag/v3.3.6
- https://github.com/spring-projects/spring-boot/releases/tag/v3.4.0-M1
- https://github.com/spring-projects/spring-boot/releases/tag/v3.4.0-M2
- https://github.com/spring-projects/spring-boot/releases/tag/v3.4.0-M3
- https://github.com/spring-projects/spring-boot/releases/tag/v3.4.0-RC1
- https://github.com/spring-projects/spring-boot/releases/tag/v3.4.0
- https://github.com/spring-projects/spring-boot/compare/v3.3.5...v3.4.0
2024-11-27 15:42:03 +01:00
Picnic-DevPla-Bot
56a82e56c0 Upgrade Micrometer 1.13.6 -> 1.14.0 (#1415)
While there, use the provided BOM.

See:
- https://github.com/micrometer-metrics/micrometer/releases/tag/v1.14.0
- https://github.com/micrometer-metrics/micrometer/releases/tag/v1.13.7
- https://github.com/micrometer-metrics/micrometer/compare/v1.13.6...v1.14.0
2024-11-27 14:50:05 +01:00
Picnic-DevPla-Bot
8f0d870fff Upgrade Spring Security 6.3.4 -> 6.4.1 (#1433)
See:
- https://docs.spring.io/spring-security/reference/6.4/whats-new.html
- https://github.com/spring-projects/spring-security/releases/tag/6.3.5
- https://github.com/spring-projects/spring-security/releases/tag/6.4.0-M1
- https://github.com/spring-projects/spring-security/releases/tag/6.4.0-M2
- https://github.com/spring-projects/spring-security/releases/tag/6.4.0-M3
- https://github.com/spring-projects/spring-security/releases/tag/6.4.0-M4
- https://github.com/spring-projects/spring-security/releases/tag/6.4.0-RC1
- https://github.com/spring-projects/spring-security/releases/tag/6.4.0
- https://github.com/spring-projects/spring-security/releases/tag/6.4.1
- https://github.com/spring-projects/spring-security/compare/6.3.4...6.4.1
2024-11-27 14:38:11 +01:00
Stephan Schroevers
d531ceb9c6 Fix Slf4jLoggerDeclaration flag name (#1436) 2024-11-25 09:07:04 +01:00
Stephan Schroevers
dc87aeda6c Improve integration test setup (#1427)
Summary of changes:
- Configure Renovate to update AssertJ and fmt-maven-plugin version
  references in patch files and shell scripts any time those
  dependencies are updated in the top-level `pom.xml`.
- Enhance the `--sync` flag such that it also updates the initial patch
  file, avoiding drift due to line shifts.
2024-11-20 13:58:28 +01:00
Picnic-DevPla-Bot
1668546450 Upgrade Swagger 2.2.25 -> 2.2.26 (#1432)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.26
- https://github.com/swagger-api/swagger-core/compare/v2.2.25...v2.2.26
2024-11-20 09:04:42 +01:00
Stephan Schroevers
fc9c20062a Introduce RedundantStringEscape check (#1138)
This check aims to simplify string constants by dropping redundant
single quote escape sequences. The check is optimized for performance.

While there, update existing checks such that they do not introduce
violations of the type flagged by this new check.
2024-11-18 20:33:08 +01:00
Rick Ossendrijver
27e9fe79a5 Upgrade Checkstyle integration test target 10.14.0 -> 10.21.1 (#1425) 2024-11-18 18:00:39 +01:00
Picnic-DevPla-Bot
e37280b752 Upgrade MongoDB driver 5.2.0 -> 5.2.1 (#1408)
See:
- https://jira.mongodb.org/issues/?jql=project%20%3D%20JAVA%20AND%20fixVersion%20%3E%205.2.0%20AND%20fixVersion%20%3C%3D%205.2.1
- https://github.com/mongodb/mongo-java-driver/releases/tag/r5.2.1
- https://github.com/mongodb/mongo-java-driver/compare/r5.2.0...r5.2.1
2024-11-18 09:03:57 +01:00
Stephan Schroevers
fff368c80a Update Checkstyle integration test (#1424)
Summary of changes:
- Move Checkstyle-specific build parameters out of
  `run-integration-test.sh`.
- Build with `-Dmaven.compiler.failOnError=true` to compensate for
  `<failOnError>false</failOnError>` configured by the enabled Maven
  profiles.
- Tweak `XdocGenerator.java` logic prior to integration test execution,
  to work around a subtle semantic difference introduced by the
  `FilesCreateTempFileToFile` Refaster rule.
- Document this difference on the relevant Refaster rules.
- To aid debugging, run Maven commands with `set -x`, such that the
  exact command executed is logged.
- Update the patch file containing the expected changes.
2024-11-18 06:32:51 +01:00
Picnic-DevPla-Bot
37cbee0f0a Upgrade OpenRewrite Templating 1.17.0 -> 1.17.1 (#1418)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.17.1
- https://github.com/openrewrite/rewrite-templating/compare/v1.17.0...v1.17.1
2024-11-15 13:49:51 +01:00
Picnic-DevPla-Bot
141822b614 Upgrade OpenRewrite 2.21.1 -> 2.22.0 (#1419)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.22.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.21.1...v2.22.0
2024-11-15 13:19:35 +01:00
Picnic-DevPla-Bot
b1bfc1fd36 Upgrade versions-maven-plugin 2.17.1 -> 2.18.0 (#1420)
See:
- https://github.com/mojohaus/versions/releases/tag/2.18.0
- https://github.com/mojohaus/versions-maven-plugin/compare/2.17.1...2.18.0
2024-11-15 08:59:27 +01:00
Stephan Schroevers
13684ec59d Replace deprecated build-helper:remove-project-artifact goal (#1413) 2024-11-13 18:27:41 +01:00
Picnic-DevPla-Bot
a51ff4de4e Upgrade actions/checkout v4.1.6 -> v4.2.2 (#1401)
See:
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v422
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v421
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v420
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v417
2024-11-12 11:11:52 +01:00
Phil Werli
da9b313ff7 Introduce assorted Reactor StepVerifier Refaster rules (#1132) 2024-11-11 14:08:05 +01:00
Phil Werli
6a50fe2d9c Introduce Instant{Identity,TruncatedTo{Milliseconds,Seconds}} Refaster rules (#1395)
While there, have `IdentityConversion` support `Instant#from`.
2024-11-11 10:42:05 +01:00
Stephan Schroevers
ed32cbae06 Update step-security/harden-runner configuration (#1412)
By allowing access to Open Source Insights.
2024-11-11 08:46:49 +01:00
Picnic-DevPla-Bot
00549a3ba6 Upgrade org.openrewrite:rewrite-java-17 8.38.1 -> 8.40.0 (#1390)
See:
- https://github.com/openrewrite/rewrite/releases/tag/v8.40.0
- https://github.com/openrewrite/rewrite/releases/tag/v8.39.0
- https://github.com/openrewrite/rewrite/releases/tag/v8.38.3
- https://github.com/openrewrite/rewrite/releases/tag/v8.38.2
- https://github.com/openrewrite/rewrite/compare/v8.38.1...v8.40.0
2024-11-11 07:54:49 +01:00
Picnic-DevPla-Bot
13f1fa3167 Upgrade ossf/scorecard-action v2.3.3 -> v2.4.0 (#1403)
See:
- https://github.com/ossf/scorecard-action/releases/tag/v2.4.0
- https://github.com/ossf/scorecard-action/compare/v2.3.3...v2.4.0
2024-11-11 07:44:12 +01:00
Picnic-DevPla-Bot
6396def588 Upgrade sonar-maven-plugin 4.0.0.4121 -> 5.0.0.4389 (#1405)
See:
- https://github.com/SonarSource/sonar-scanner-maven/releases/tag/5.0.0.4389
- https://github.com/SonarSource/sonar-scanner-maven/compare/4.0.0.4121...5.0.0.4389
2024-11-10 22:04:47 +01:00
Picnic-DevPla-Bot
7599b0f22f Upgrade step-security/harden-runner v2.8.0 -> v2.10.1 (#1404)
See:
- https://github.com/step-security/harden-runner/releases/tag/v2.10.1
- https://github.com/step-security/harden-runner/releases/tag/v2.10.0
- https://github.com/step-security/harden-runner/releases/tag/v2.9.1
- https://github.com/step-security/harden-runner/releases/tag/v2.9.0
- https://github.com/step-security/harden-runner/releases/tag/v2.8.1
2024-11-10 21:33:56 +01:00
Picnic-DevPla-Bot
08eb7e7699 Upgrade OpenRewrite Templating 1.16.3 -> 1.17.0 (#1409)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.17.0
- https://github.com/openrewrite/rewrite-templating/compare/v1.16.3...v1.17.0
2024-11-10 18:38:30 +01:00
Stephan Schroevers
89f918c23e Update step-security/harden-runner configuration (#1411)
By allowing Docker Hub and Maven Central access.
2024-11-10 18:26:40 +01:00
Stephan Schroevers
f08fc344f5 Track StreamFlatMapOptional Refaster rule caveat (#1410) 2024-11-10 15:14:08 +01:00
Picnic-DevPla-Bot
99aa656a1e Upgrade s4u/setup-maven-action v1.13.0 -> v1.16.0 (#1400)
See:
- https://github.com/s4u/setup-maven-action/releases/tag/v1.16.0
- https://github.com/s4u/setup-maven-action/releases/tag/v1.15.0
- https://github.com/s4u/setup-maven-action/releases/tag/v1.14.0
2024-11-09 10:27:57 +01:00
Picnic-DevPla-Bot
86fbaf7403 Upgrade Checkstyle 10.20.0 -> 10.20.1 (#1407)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.20.1
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.20.0...checkstyle-10.20.1
2024-11-08 19:37:12 +01:00
Picnic-DevPla-Bot
563012549a Upgrade pitest-maven-plugin 1.17.0 -> 1.17.1 (#1397)
See:
- https://github.com/hcoles/pitest/releases/tag/1.17.1
- https://github.com/hcoles/pitest/compare/1.17.0...1.17.1
2024-11-07 21:29:39 +01:00
Picnic-DevPla-Bot
4f46eb30d2 Upgrade actions/upload-artifact v4.3.3 -> v4.4.3 (#1402)
See:
- https://github.com/actions/upload-artifact/releases/tag/v4.4.3
- https://github.com/actions/upload-artifact/releases/tag/v4.4.2
- https://github.com/actions/upload-artifact/releases/tag/v4.4.1
- https://github.com/actions/upload-artifact/releases/tag/v4.4.0
- https://github.com/actions/upload-artifact/releases/tag/v4.3.6
- https://github.com/actions/upload-artifact/releases/tag/v4.3.5
- https://github.com/actions/upload-artifact/releases/tag/v4.3.4
2024-11-07 16:39:05 +01:00
Picnic-DevPla-Bot
2f30082127 Upgrade maven-javadoc-plugin 3.10.1 -> 3.11.1 (#1398)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MJAVADOC%20AND%20fixVersion%20%3E%203.10.1%20AND%20fixVersion%20%3C%3D%203.11.1
- https://github.com/apache/maven-javadoc-plugin/releases/tag/maven-javadoc-plugin-3.11.0
- https://github.com/apache/maven-javadoc-plugin/releases/tag/maven-javadoc-plugin-3.11.1
- https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.10.1...maven-javadoc-plugin-3.11.1
2024-11-07 12:48:15 +01:00
Stephan Schroevers
548506fbbb Update Error Prone compatibility matrix (#1406) 2024-11-07 10:54:08 +01:00
Picnic-DevPla-Bot
bdef83bce5 Upgrade Byte Buddy 1.15.7 -> 1.15.10 (#1388)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.15.8
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.15.9
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.15.10
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.15.7...byte-buddy-1.15.10
2024-11-06 09:03:44 +01:00
Picnic-DevPla-Bot
f7f665681d Upgrade Surefire 3.5.1 -> 3.5.2 (#1396)
See:
- https://github.com/apache/maven-surefire/releases/tag/surefire-3.5.2
- https://github.com/apache/maven-surefire/compare/surefire-3.5.1...surefire-3.5.2
2024-11-05 11:36:11 +01:00
Picnic-DevPla-Bot
7c0d544cf8 Upgrade Checker Framework Annotations 3.48.1 -> 3.48.2 (#1389)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.48.2
- https://github.com/typetools/checker-framework/compare/checker-framework-3.48.1...checker-framework-3.48.2
2024-11-04 14:51:00 +01:00
Stephan Schroevers
9390b6f571 Run GitHub Actions workflows on ubuntu-24.04 (#1391)
See https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md
2024-11-03 18:36:54 +01:00
Stephan Schroevers
176a833d89 Upgrade ruby/setup-ruby v1.174.0 -> v1.199.0 (#1392)
See:
- https://github.com/ruby/setup-ruby/releases/tag/v1.175.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.176.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.177.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.178.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.179.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.180.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.181.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.182.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.183.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.184.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.185.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.186.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.187.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.188.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.189.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.190.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.191.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.192.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.193.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.194.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.195.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.196.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.197.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.198.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.199.0
- https://github.com/ruby/setup-ruby/compare/v1.174.0...v1.199.0
2024-11-03 18:17:38 +01:00
Stephan Schroevers
3cacd27248 [maven-release-plugin] prepare for next development iteration 2024-11-03 16:58:19 +01:00
153 changed files with 36432 additions and 7693 deletions

View File

@@ -9,16 +9,16 @@ jobs:
build: build:
strategy: strategy:
matrix: matrix:
os: [ ubuntu-22.04 ] os: [ ubuntu-24.04 ]
jdk: [ 17.0.13, 21.0.5, 23.0.1 ] jdk: [ 17.0.13, 21.0.5, 23.0.1 ]
distribution: [ temurin ] distribution: [ temurin ]
experimental: [ false ] experimental: [ false ]
include: include:
- os: macos-14 - os: macos-15
jdk: 17.0.13 jdk: 17.0.13
distribution: temurin distribution: temurin
experimental: false experimental: false
- os: windows-2022 - os: windows-2025
jdk: 17.0.13 jdk: 17.0.13
distribution: temurin distribution: temurin
experimental: false experimental: false
@@ -26,14 +26,16 @@ jobs:
continue-on-error: ${{ matrix.experimental }} continue-on-error: ${{ matrix.experimental }}
steps: steps:
- name: Install Harden-Runner - name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with: with:
disable-sudo: true disable-sudo: true
egress-policy: block egress-policy: block
allowed-endpoints: > allowed-endpoints: >
api.adoptium.net:443 api.adoptium.net:443
github.com:443 github.com:443
github-registry-files.githubusercontent.com:443
jitpack.io:443 jitpack.io:443
maven.pkg.github.com:443
objects.githubusercontent.com:443 objects.githubusercontent.com:443
repo.maven.apache.org:443 repo.maven.apache.org:443
# We run the build twice for each supported JDK: once against the # 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 # additionally enabling all checks defined in this project and any Error
# Prone checks available only from other artifact repositories. # Prone checks available only from other artifact repositories.
- name: Check out code and set up JDK and Maven - name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0 uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
with: with:
java-version: ${{ matrix.jdk }} java-version: ${{ matrix.jdk }}
java-distribution: ${{ matrix.distribution }} java-distribution: ${{ matrix.distribution }}
@@ -53,7 +55,9 @@ jobs:
run: mvn -T1C install javadoc:jar run: mvn -T1C install javadoc:jar
- name: Build project with self-check against Error Prone fork - 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 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 - name: Remove installed project artifacts
run: mvn build-helper:remove-project-artifact run: mvn dependency:purge-local-repository -DmanualInclude='${project.groupId}' -DresolutionFuzziness=groupId
# XXX: Enable Codecov once we "go public". # XXX: Enable Codecov once we "go public".

View File

@@ -19,10 +19,10 @@ jobs:
permissions: permissions:
contents: read contents: read
security-events: write security-events: write
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
steps: steps:
- name: Install Harden-Runner - name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with: with:
disable-sudo: true disable-sudo: true
egress-policy: block egress-policy: block
@@ -34,19 +34,19 @@ jobs:
repo.maven.apache.org:443 repo.maven.apache.org:443
uploads.github.com:443 uploads.github.com:443
- name: Check out code and set up JDK and Maven - name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0 uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
with: with:
java-version: 17.0.13 java-version: 17.0.13
java-distribution: temurin java-distribution: temurin
maven-version: 3.9.9 maven-version: 3.9.9
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1 uses: github/codeql-action/init@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
- name: Perform minimal build - name: Perform minimal build
if: matrix.language == 'java' if: matrix.language == 'java'
run: mvn -T1C clean package -DskipTests -Dverification.skip run: mvn -T1C clean package -DskipTests -Dverification.skip
- name: Perform CodeQL analysis - name: Perform CodeQL analysis
uses: github/codeql-action/analyze@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1 uses: github/codeql-action/analyze@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12
with: with:
category: /language:${{ matrix.language }} category: /language:${{ matrix.language }}

View File

@@ -9,10 +9,10 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
jobs: jobs:
build: build:
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
steps: steps:
- name: Install Harden-Runner - name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with: with:
disable-sudo: true disable-sudo: true
egress-policy: block egress-policy: block
@@ -21,6 +21,7 @@ jobs:
api.github.com:443 api.github.com:443
bestpractices.coreinfrastructure.org:443 bestpractices.coreinfrastructure.org:443
blog.picnic.nl:443 blog.picnic.nl:443
docs.github.com:443
errorprone.info:443 errorprone.info:443
github.com:443 github.com:443
img.shields.io:443 img.shields.io:443
@@ -39,10 +40,10 @@ jobs:
www.youtube.com:443 www.youtube.com:443
youtrack.jetbrains.com:443 youtrack.jetbrains.com:443
- name: Check out code - name: Check out code
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
persist-credentials: false persist-credentials: false
- uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0 - uses: ruby/setup-ruby@1a615958ad9d422dd932dc1d5823942ee002799f # v1.227.0
with: with:
working-directory: ./website working-directory: ./website
bundler-cache: true bundler-cache: true
@@ -68,13 +69,13 @@ jobs:
permissions: permissions:
id-token: write id-token: write
pages: write pages: write
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
environment: environment:
name: github-pages name: github-pages
url: ${{ steps.deployment.outputs.page_url }} url: ${{ steps.deployment.outputs.page_url }}
steps: steps:
- name: Install Harden-Runner - name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with: with:
disable-sudo: true disable-sudo: true
egress-policy: block egress-policy: block

View File

@@ -18,33 +18,36 @@ jobs:
contents: read contents: read
security-events: write security-events: write
id-token: write id-token: write
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
steps: steps:
- name: Install Harden-Runner - name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with: with:
disable-sudo: true disable-sudo: true
egress-policy: block egress-policy: block
allowed-endpoints: > allowed-endpoints: >
api.deps.dev:443
api.github.com:443 api.github.com:443
api.osv.dev:443 api.osv.dev:443
api.scorecard.dev:443 api.scorecard.dev:443
api.securityscorecards.dev:443 api.securityscorecards.dev:443
github.com:443 github.com:443
index.docker.io:443
oss-fuzz-build-logs.storage.googleapis.com:443 oss-fuzz-build-logs.storage.googleapis.com:443
repo.maven.apache.org:443
*.sigstore.dev:443 *.sigstore.dev:443
www.bestpractices.dev:443 www.bestpractices.dev:443
- name: Check out code - name: Check out code
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
persist-credentials: false persist-credentials: false
- name: Run OpenSSF Scorecard analysis - name: Run OpenSSF Scorecard analysis
uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3 uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
with: with:
results_file: results.sarif results_file: results.sarif
results_format: sarif results_format: sarif
publish_results: ${{ github.ref == 'refs/heads/master' }} publish_results: ${{ github.ref == 'refs/heads/master' }}
- name: Update GitHub's code scanning dashboard - name: Update GitHub's code scanning dashboard
uses: github/codeql-action/upload-sarif@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1 uses: github/codeql-action/upload-sarif@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12
with: with:
sarif_file: results.sarif sarif_file: results.sarif

View File

@@ -9,10 +9,10 @@ permissions:
contents: read contents: read
jobs: jobs:
analyze-pr: analyze-pr:
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
steps: steps:
- name: Install Harden-Runner - name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with: with:
disable-sudo: true disable-sudo: true
egress-policy: block egress-policy: block
@@ -22,7 +22,7 @@ jobs:
objects.githubusercontent.com:443 objects.githubusercontent.com:443
repo.maven.apache.org:443 repo.maven.apache.org:443
- name: Check out code and set up JDK and Maven - name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0 uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
with: with:
checkout-fetch-depth: 2 checkout-fetch-depth: 2
java-version: 17.0.13 java-version: 17.0.13
@@ -38,7 +38,7 @@ jobs:
- name: Aggregate Pitest reports - 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)." 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 - name: Upload Pitest reports as artifact
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: pitest-reports name: pitest-reports
path: ./target/pit-reports-ci path: ./target/pit-reports-ci

View File

@@ -17,10 +17,10 @@ jobs:
checks: write checks: write
contents: read contents: read
pull-requests: write pull-requests: write
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
steps: steps:
- name: Install Harden-Runner - name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with: with:
disable-sudo: true disable-sudo: true
egress-policy: block egress-policy: block
@@ -31,7 +31,7 @@ jobs:
objects.githubusercontent.com:443 objects.githubusercontent.com:443
repo.maven.apache.org:443 repo.maven.apache.org:443
- name: Check out code and set up JDK and Maven - name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0 uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
with: with:
java-version: 17.0.13 java-version: 17.0.13
java-distribution: temurin java-distribution: temurin

View File

@@ -1,9 +1,9 @@
# If requested by means of a pull request comment, runs integration tests # If requested by means of a pull request comment, runs integration tests
# against the project, using the code found on the pull request branch. # against the project, using the code found on the pull request branch.
# XXX: Generalize this to a matrix build of multiple integration tests, # XXX: Review whether then build matrix should also vary JDK or OS versions.
# possibly using multiple JDK or OS versions. # XXX: Support `/integration-test [name...]` comment syntax to specify the
# XXX: Investigate whether the comment can specify which integration tests run # subset of integration tests to run.
# run. See this example of a dynamic build matrix: # See this example of a dynamic build matrix:
# https://docs.github.com/en/actions/learn-github-actions/expressions#example-returning-a-json-object # https://docs.github.com/en/actions/learn-github-actions/expressions#example-returning-a-json-object
name: "Integration tests" name: "Integration tests"
on: on:
@@ -16,24 +16,34 @@ jobs:
name: On-demand integration test name: On-demand integration test
if: | if: |
github.event.issue.pull_request && contains(github.event.comment.body, '/integration-test') github.event.issue.pull_request && contains(github.event.comment.body, '/integration-test')
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
strategy:
matrix:
integration-test: [ "checkstyle", "metrics", "prometheus-java-client" ]
steps: steps:
- name: Install Harden-Runner - name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with: with:
disable-sudo: true disable-sudo: true
egress-policy: block 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: > allowed-endpoints: >
api.adoptium.net:443 api.adoptium.net:443
auth.docker.io:443
checkstyle.org:443 checkstyle.org:443
example.com:80
github.com:443 github.com:443
objects.githubusercontent.com:443 objects.githubusercontent.com:443
oss.sonatype.org:443 oss.sonatype.org:443
production.cloudflare.docker.com:443
raw.githubusercontent.com:443 raw.githubusercontent.com:443
registry-1.docker.io:443
repo.maven.apache.org:443 repo.maven.apache.org:443
repository.sonatype.org:443 repository.sonatype.org:443
- name: Check out code and set up JDK and Maven - name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0 uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
with: with:
checkout-ref: "refs/pull/${{ github.event.issue.number }}/head" checkout-ref: "refs/pull/${{ github.event.issue.number }}/head"
java-version: 17.0.13 java-version: 17.0.13
@@ -42,12 +52,12 @@ jobs:
- name: Install project to local Maven repository - name: Install project to local Maven repository
run: mvn -T1C install -DskipTests -Dverification.skip run: mvn -T1C install -DskipTests -Dverification.skip
- name: Run integration test - name: Run integration test
run: xvfb-run ./integration-tests/checkstyle.sh "${{ runner.temp }}/artifacts" run: xvfb-run "./integration-tests/${{ matrix.integration-test }}.sh" "${{ runner.temp }}/artifacts"
- name: Upload artifacts on failure - name: Upload artifacts on failure
if: ${{ failure() }} if: ${{ failure() }}
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: integration-test-checkstyle name: "integration-test-${{ matrix.integration-test }}"
path: "${{ runner.temp }}/artifacts" path: "${{ runner.temp }}/artifacts"
- name: Remove installed project artifacts - name: Remove installed project artifacts
run: mvn build-helper:remove-project-artifact run: mvn dependency:purge-local-repository -DmanualInclude='${project.groupId}' -DresolutionFuzziness=groupId

View File

@@ -16,10 +16,10 @@ jobs:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
permissions: permissions:
contents: read contents: read
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
steps: steps:
- name: Install Harden-Runner - name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
with: with:
disable-sudo: true disable-sudo: true
egress-policy: block egress-policy: block
@@ -35,7 +35,7 @@ jobs:
*.sonarcloud.io:443 *.sonarcloud.io:443
sonarcloud.io:443 sonarcloud.io:443
- name: Check out code and set up JDK and Maven - name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0 uses: s4u/setup-maven-action@4f7fb9d9675e899ca81c6161dadbba0189a4ebb1 # v1.18.0
with: with:
checkout-fetch-depth: 0 checkout-fetch-depth: 0
java-version: 17.0.13 java-version: 17.0.13

View File

@@ -3,11 +3,24 @@
"extends": [ "extends": [
"helpers:pinGitHubActionDigests" "helpers:pinGitHubActionDigests"
], ],
"customManagers": [
{
"customType": "regex",
"fileMatch": [
"^integration-tests/.*(-init\\.patch|\\.sh)$"
],
"matchStrings": [
"\\b(?<packageName>[a-z0-9_.-]+?:[a-z0-9_.-]+?):(?<currentValue>[^:]+?):[a-zA-Z0-9_-]+\\b",
"<version>(?<currentValue>.*?)<!-- Renovate: (?<packageName>.*?) --></version>"
],
"datasourceTemplate": "maven"
}
],
"packageRules": [ "packageRules": [
{ {
"matchPackagePatterns": [ "matchPackageNames": [
"^org\\.springframework:spring-framework-bom$", "/^org\\.springframework:spring-framework-bom$/",
"^org\\.springframework\\.boot:spring-boot[a-z-]*$" "/^org\\.springframework\\.boot:spring-boot[a-z-]*$/"
], ],
"separateMinorPatch": true "separateMinorPatch": true
}, },

View File

@@ -205,19 +205,20 @@ Relevant Maven build parameters:
version of Error Prone. This is useful e.g. when testing a locally built version of Error Prone. This is useful e.g. when testing a locally built
Error Prone SNAPSHOT. Error Prone SNAPSHOT.
- `-Perror-prone-fork` runs the build using Picnic's [Error Prone - `-Perror-prone-fork` runs the build using Picnic's [Error Prone
fork][error-prone-fork-repo], hosted on [Jitpack][error-prone-fork-jitpack]. fork][error-prone-fork-repo], hosted using [GitHub
This fork generally contains a few changes on top of the latest Error Prone Packages][error-prone-fork-packages]. This fork generally contains a few
release. 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. - `-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: Other highly relevant commands:
- `mvn fmt:format` formats the code using - `mvn fmt:format` formats the code using
[`google-java-format`][google-java-format]. [`google-java-format`][google-java-format].
- [`./run-full-build.sh`][script-run-full-build] builds the project twice, - [`./run-full-build.sh`][script-run-full-build] builds the project twice,
where the second pass validates compatbility with Picnic's [Error Prone where the second pass validates compatibility with Picnic's [Error Prone
fork][error-prone-fork-repo] and compliance of the code with any rules fork][error-prone-fork-repo] and compliance of the code with any rules
defined within this project. (Consider running this before [opening a pull defined within this project. (Consider running this before [opening a pull
request][contributing-pull-request], as the PR checks also perform this request][contributing-pull-request], as the PR checks also perform this
@@ -235,8 +236,9 @@ Other highly relevant commands:
against _all_ code in the current working directory. For more information against _all_ code in the current working directory. For more information
check the [PIT Maven plugin][pitest-maven]. check the [PIT Maven plugin][pitest-maven].
When running the project's tests in IntelliJ IDEA, you might see the following Opening the project in IntelliJ IDEA may require running `mvn clean install`
error: 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 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]: 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 [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-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-fork-repo]: https://github.com/PicnicSupermarket/error-prone
[error-prone-gradle-installation-guide]: https://github.com/tbroyer/gradle-errorprone-plugin [error-prone-gradle-installation-guide]: https://github.com/tbroyer/gradle-errorprone-plugin
[error-prone-installation-guide]: https://errorprone.info/docs/installation#maven [error-prone-installation-guide]: https://errorprone.info/docs/installation#maven
[error-prone-orig-repo]: https://github.com/google/error-prone [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-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-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 [google-java-format]: https://github.com/google/google-java-format
[idea-288052]: https://youtrack.jetbrains.com/issue/IDEA-288052 [idea-288052]: https://youtrack.jetbrains.com/issue/IDEA-288052
[license-badge]: https://img.shields.io/github/license/PicnicSupermarket/error-prone-support [license-badge]: https://img.shields.io/github/license/PicnicSupermarket/error-prone-support

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>tech.picnic.error-prone-support</groupId> <groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId> <artifactId>error-prone-support</artifactId>
<version>0.19.1</version> <version>0.22.1-SNAPSHOT</version>
</parent> </parent>
<artifactId>documentation-support</artifactId> <artifactId>documentation-support</artifactId>
@@ -15,24 +15,6 @@
<url>https://error-prone.picnic.tech</url> <url>https://error-prone.picnic.tech</url>
<dependencies> <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> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>error-prone-utils</artifactId> <artifactId>error-prone-utils</artifactId>
@@ -72,6 +54,24 @@
<artifactId>auto-value-annotations</artifactId> <artifactId>auto-value-annotations</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </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> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <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.Matchers.instanceMethod;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod; import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import static java.util.Objects.requireNonNull;
import static java.util.function.Predicate.not; import static java.util.function.Predicate.not;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 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(..)`, * 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. * 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); String path = ASTHelpers.constValue(inputTree.getArguments().get(0), String.class);
Optional<String> inputCode = getSourceCode(inputTree); Optional<String> inputCode = getSourceCode(inputTree);

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>tech.picnic.error-prone-support</groupId> <groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId> <artifactId>error-prone-support</artifactId>
<version>0.19.1</version> <version>0.22.1-SNAPSHOT</version>
</parent> </parent>
<artifactId>error-prone-contrib</artifactId> <artifactId>error-prone-contrib</artifactId>
@@ -15,31 +15,6 @@
<url>https://error-prone.picnic.tech</url> <url>https://error-prone.picnic.tech</url>
<dependencies> <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> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>documentation-support</artifactId> <artifactId>documentation-support</artifactId>
@@ -87,6 +62,41 @@
<artifactId>auto-value-annotations</artifactId> <artifactId>auto-value-annotations</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </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> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
@@ -167,6 +177,11 @@
<artifactId>value-annotations</artifactId> <artifactId>value-annotations</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.jspecify</groupId> <groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId> <artifactId>jspecify</artifactId>

View File

@@ -18,6 +18,7 @@ import com.sun.source.tree.LambdaExpressionTree;
import com.sun.source.tree.TypeCastTree; import com.sun.source.tree.TypeCastTree;
import com.sun.source.tree.VariableTree; import com.sun.source.tree.VariableTree;
import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type;
import javax.lang.model.type.TypeKind;
import tech.picnic.errorprone.utils.SourceCode; import tech.picnic.errorprone.utils.SourceCode;
/** /**
@@ -48,11 +49,14 @@ public final class ClassCastLambdaUsage extends BugChecker implements LambdaExpr
} }
Type type = ASTHelpers.getType(typeCast); Type type = ASTHelpers.getType(typeCast);
if (type == null || type.isParameterized() || type.isPrimitive()) { if (type == null
|| type.isParameterized()
|| type.isPrimitive()
|| type.getKind() == TypeKind.TYPEVAR) {
/* /*
* The method reference syntax does not support casting to parameterized types. Additionally, * The method reference syntax does not support casting to parameterized types, and type
* `Class#cast` does not support the same range of type conversions between (boxed) primitive * variables aren't supported either. Additionally, `Class#cast` does not support the same
* types as the cast operator. * range of type conversions between (boxed) primitive types as the cast operator.
*/ */
// XXX: Depending on the declared type of the value being cast, in some cases we _can_ rewrite // XXX: Depending on the declared type of the value being cast, in some cases we _can_ rewrite
// primitive casts. Add support for this. // primitive casts. Add support for this.

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.returnStatement;
import static com.google.errorprone.matchers.Matchers.staticMethod; import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.matchers.Matchers.toType; 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 static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
@@ -79,7 +80,10 @@ public final class DirectReturn extends BugChecker implements BlockTreeMatcher {
return Description.NO_MATCH; 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); StatementTree precedingStatement = statements.get(statements.size() - 2);
return tryMatchAssignment(variableSymbol, precedingStatement) 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

@@ -0,0 +1,251 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.PERFORMANCE;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static com.google.errorprone.matchers.Matchers.allOf;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.matchers.Matchers.symbolMatcher;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableCollection;
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;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.util.ASTHelpers;
import com.google.errorprone.util.Visibility;
import com.sun.source.tree.ExpressionTree;
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;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import javax.lang.model.element.Element;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags single-argument method invocations with an iterable of explicitly
* enumerated values, for which a semantically equivalent varargs variant (appears to) exists as
* well.
*
* <p>This check drops selected {@link ImmutableSet#of} and {@link Set#of} invocations, with the
* assumption that these operations do not deduplicate the collection of explicitly enumerated
* values. It also drops {@link ImmutableMultiset#of} and {@link Set#of} invocations, with the
* assumption that these do not materially impact iteration order.
*
* <p>This checker attempts to identify {@link Iterable}-accepting methods for which a varargs
* overload exists, and suggests calling the varargs overload instead. This is an imperfect
* heuristic, but it e.g. allows invocations of <a
* href="https://immutables.github.io/immutable.html#copy-methods">Immutables-generated {@code
* with*}</a> methods to be simplified.
*/
@AutoService(BugChecker.class)
@BugPattern(
summary = "Iterable creation can be avoided by using a varargs alternative method",
link = BUG_PATTERNS_BASE_URL + "ExplicitArgumentEnumeration",
linkType = CUSTOM,
severity = SUGGESTION,
tags = {PERFORMANCE, SIMPLIFICATION})
public final class ExplicitArgumentEnumeration extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> EXPLICIT_ITERABLE_CREATOR =
anyOf(
staticMethod()
.onClassAny(
ImmutableList.class.getCanonicalName(),
ImmutableMultiset.class.getCanonicalName(),
ImmutableSet.class.getCanonicalName(),
List.class.getCanonicalName(),
Set.class.getCanonicalName())
.named("of"),
allOf(
staticMethod()
.onClassAny(
ImmutableList.class.getCanonicalName(),
ImmutableMultiset.class.getCanonicalName(),
ImmutableSet.class.getCanonicalName())
.named("copyOf"),
symbolMatcher(
(symbol, state) ->
state
.getSymtab()
.arrayClass
.equals(((MethodSymbol) symbol).params().get(0).type.tsym))),
staticMethod().onClass(Arrays.class.getCanonicalName()).named("asList"));
private static final Matcher<ExpressionTree> IMMUTABLE_COLLECTION_BUILDER =
instanceMethod().onDescendantOf(ImmutableCollection.Builder.class.getCanonicalName());
private static final Matcher<ExpressionTree> OBJECT_ENUMERABLE_ASSERT =
instanceMethod().onDescendantOf("org.assertj.core.api.ObjectEnumerableAssert");
private static final Matcher<ExpressionTree> STEP_VERIFIER_STEP =
instanceMethod().onDescendantOf("reactor.test.StepVerifier.Step");
private static final ImmutableTable<Matcher<ExpressionTree>, String, String> ALTERNATIVE_METHODS =
ImmutableTable.<Matcher<ExpressionTree>, String, String>builder()
.put(IMMUTABLE_COLLECTION_BUILDER, "addAll", "add")
.put(OBJECT_ENUMERABLE_ASSERT, "containsAnyElementsOf", "containsAnyOf")
.put(OBJECT_ENUMERABLE_ASSERT, "containsAll", "contains")
.put(OBJECT_ENUMERABLE_ASSERT, "containsExactlyElementsOf", "containsExactly")
.put(
OBJECT_ENUMERABLE_ASSERT,
"containsExactlyInAnyOrderElementsOf",
"containsExactlyInAnyOrder")
.put(OBJECT_ENUMERABLE_ASSERT, "containsOnlyElementsOf", "containsOnly")
.put(OBJECT_ENUMERABLE_ASSERT, "containsOnlyOnceElementsOf", "containsOnlyOnce")
.put(OBJECT_ENUMERABLE_ASSERT, "doesNotContainAnyElementsOf", "doesNotContain")
.put(OBJECT_ENUMERABLE_ASSERT, "hasSameElementsAs", "containsOnly")
.put(STEP_VERIFIER_STEP, "expectNextSequence", "expectNext")
.buildOrThrow();
/** Instantiates a new {@link ExplicitArgumentEnumeration} instance. */
public ExplicitArgumentEnumeration() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (tree.getArguments().size() != 1) {
/* Performance optimization: non-unary method invocations cannot be simplified. */
return Description.NO_MATCH;
}
MethodSymbol method = ASTHelpers.getSymbol(tree);
if (!isUnaryIterableAcceptingMethod(method, state) || isLocalOverload(method, state)) {
/*
* This isn't a method invocation we can simplify, or it's an invocation of a local overload.
* The latter type of invocation we do not suggest replacing, as this is fairly likely to
* introduce an unbounded recursive call chain.
*/
return Description.NO_MATCH;
}
ExpressionTree argument = tree.getArguments().get(0);
if (!EXPLICIT_ITERABLE_CREATOR.matches(argument, state)) {
return Description.NO_MATCH;
}
return trySuggestCallingVarargsOverload(method, (MethodInvocationTree) argument, state)
.or(() -> trySuggestCallingCustomAlternative(tree, (MethodInvocationTree) argument, state))
.map(fix -> describeMatch(tree, fix))
.orElse(Description.NO_MATCH);
}
private static boolean isUnaryIterableAcceptingMethod(MethodSymbol method, VisitorState state) {
List<VarSymbol> params = method.params();
return !method.isVarArgs()
&& params.size() == 1
&& ASTHelpers.isSubtype(params.get(0).type, state.getSymtab().iterableType, state);
}
private static boolean isLocalOverload(MethodSymbol calledMethod, VisitorState state) {
MethodTree enclosingMethod = state.findEnclosing(MethodTree.class);
if (enclosingMethod == null) {
return false;
}
MethodSymbol callingMethod = ASTHelpers.getSymbol(enclosingMethod);
return Objects.equals(callingMethod.getEnclosingElement(), calledMethod.getEnclosingElement())
&& callingMethod.getSimpleName().equals(calledMethod.getSimpleName());
}
private static Optional<SuggestedFix> trySuggestCallingVarargsOverload(
MethodSymbol method, MethodInvocationTree argument, VisitorState state) {
/*
* Collect all overloads of the given method that we are sure to be able to call. Note that the
* `isAtLeastAsVisible` check is conservative heuristic.
*/
ImmutableList<MethodSymbol> overloads =
ASTHelpers.matchingMethods(
method.getSimpleName(),
m -> isAtLeastAsVisible(m, method),
method.enclClass().type,
state.getTypes())
.collect(toImmutableList());
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()
.filter(e -> e.getKey().matches(tree, state))
.findFirst()
.flatMap(e -> trySuggestCallingCustomAlternative(tree, argument, state, e.getValue()));
}
private static Optional<SuggestedFix> trySuggestCallingCustomAlternative(
MethodInvocationTree tree,
MethodInvocationTree argument,
VisitorState state,
Map<String, String> alternatives) {
return Optional.ofNullable(
alternatives.get(ASTHelpers.getSymbol(tree).getSimpleName().toString()))
.map(
replacement ->
SuggestedFix.builder()
.merge(SuggestedFixes.renameMethodInvocation(tree, replacement, state))
.merge(SourceCode.unwrapMethodInvocation(argument, state))
.build());
}
private static boolean isAtLeastAsVisible(Element symbol, Element reference) {
return Visibility.fromModifiers(symbol.getModifiers())
.compareTo(Visibility.fromModifiers(reference.getModifiers()))
>= 0;
}
}

View File

@@ -39,6 +39,7 @@ import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types; import com.sun.tools.javac.code.Types;
import java.time.Instant;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import tech.picnic.errorprone.utils.SourceCode; import tech.picnic.errorprone.utils.SourceCode;
@@ -84,6 +85,7 @@ public final class IdentityConversion extends BugChecker implements MethodInvoca
ImmutableSetMultimap.class.getCanonicalName(), ImmutableSetMultimap.class.getCanonicalName(),
ImmutableTable.class.getCanonicalName()) ImmutableTable.class.getCanonicalName())
.named("copyOf"), .named("copyOf"),
staticMethod().onClass(Instant.class.getCanonicalName()).namedAnyOf("from"),
staticMethod().onClass(Matchers.class.getCanonicalName()).namedAnyOf("allOf", "anyOf"), staticMethod().onClass(Matchers.class.getCanonicalName()).namedAnyOf("allOf", "anyOf"),
staticMethod().onClass("reactor.adapter.rxjava.RxJava2Adapter"), staticMethod().onClass("reactor.adapter.rxjava.RxJava2Adapter"),
staticMethod() staticMethod()

View File

@@ -101,6 +101,8 @@ public final class JUnitMethodDeclaration extends BugChecker implements MethodTr
.build()); .build());
} }
// XXX: Consider dropping leading underscores that otherwise result when canonicalizing
// `test_some_method_name`.
private static Optional<String> tryCanonicalizeMethodName(MethodSymbol symbol) { private static Optional<String> tryCanonicalizeMethodName(MethodSymbol symbol) {
return Optional.of(symbol.getQualifiedName().toString()) return Optional.of(symbol.getQualifiedName().toString())
.filter(name -> name.startsWith(TEST_PREFIX)) .filter(name -> name.startsWith(TEST_PREFIX))

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.methodHasParameters;
import static com.google.errorprone.matchers.Matchers.staticMethod; import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.matchers.Matchers.toType; 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.function.Predicate.not;
import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.joining;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL; 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; 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) return findMethodSourceAnnotation(tree, state)
.flatMap( .flatMap(
@@ -173,7 +177,9 @@ public final class JUnitValueSource extends BugChecker implements MethodTreeMatc
private static Optional<MethodTree> findMatchingSibling( private static Optional<MethodTree> findMatchingSibling(
MethodTree tree, Predicate<? super MethodTree> predicate, VisitorState state) { 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) .filter(MethodTree.class::isInstance)
.map(MethodTree.class::cast) .map(MethodTree.class::cast)
.filter(not(tree::equals)) .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.BugPattern.StandardTags.SIMPLIFICATION;
import static com.google.errorprone.matchers.Matchers.anyOf; import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.instanceMethod; 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 static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
@@ -86,7 +87,9 @@ public final class NonEmptyMono extends BugChecker implements MethodInvocationTr
return Description.NO_MATCH; 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)) { if (!NON_EMPTY_MONO.matches(receiver, state)) {
return Description.NO_MATCH; 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.source.util.TreeScanner;
import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol;
import java.time.Clock; import java.time.Clock;
import java.time.InstantSource;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.util.Collections; import java.util.Collections;
import java.util.Locale; import java.util.Locale;
@@ -69,6 +70,7 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
ImmutableSet.of( ImmutableSet.of(
ASTHelpers.class.getCanonicalName(), ASTHelpers.class.getCanonicalName(),
Clock.class.getCanonicalName(), Clock.class.getCanonicalName(),
InstantSource.class.getCanonicalName(),
Strings.class.getCanonicalName(), Strings.class.getCanonicalName(),
VisitorState.class.getCanonicalName(), VisitorState.class.getCanonicalName(),
ZoneOffset.class.getCanonicalName(), ZoneOffset.class.getCanonicalName(),
@@ -129,6 +131,7 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
"builder", "builder",
"copyOf", "copyOf",
"create", "create",
"EPOCH",
"from", "from",
"getDefaultInstance", "getDefaultInstance",
"INSTANCE", "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) { private static boolean shouldNotBeStaticallyImported(String type, String member) {

View File

@@ -0,0 +1,95 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.LiteralTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.LiteralTree;
import tech.picnic.errorprone.utils.SourceCode;
/** A {@link BugChecker} that flags string constants with extraneous escaping. */
// XXX: Also cover `\"` sequences inside text blocks. Note that this requires a more subtle
// approach, as double-quote characters will need to remain escaped if removing the backslash would
// create a new sequence of three or more double-quotes. (TBD whether we'd like to enforce a
// "preferred" approach to escaping, e.g. by always escaping the last of a triplet, such that the
// over-all number of escaped characters is minimized.)
// XXX: Also flag `'\"'` char literals.
@AutoService(BugChecker.class)
@BugPattern(
summary = "Inside string expressions single quotes do not need to be escaped",
link = BUG_PATTERNS_BASE_URL + "RedundantStringEscape",
linkType = CUSTOM,
severity = SUGGESTION,
tags = SIMPLIFICATION)
public final class RedundantStringEscape extends BugChecker implements LiteralTreeMatcher {
private static final long serialVersionUID = 1L;
/** Instantiates a new {@link RedundantStringEscape} instance. */
public RedundantStringEscape() {}
@Override
public Description matchLiteral(LiteralTree tree, VisitorState state) {
String constant = ASTHelpers.constValue(tree, String.class);
if (constant == null || constant.indexOf('\'') < 0) {
/* Fast path: this isn't a string constant with a single quote. */
return Description.NO_MATCH;
}
String source = SourceCode.treeToString(tree, state);
if (!containsBannedEscapeSequence(source)) {
/* Semi-fast path: this expression doesn't contain an escaped single quote. */
return Description.NO_MATCH;
}
/* Slow path: suggest dropping the escape characters. */
return describeMatch(tree, SuggestedFix.replace(tree, dropRedundantEscapeSequences(source)));
}
/**
* Tells whether the given string constant source expression contains an escaped single quote.
*
* @implNote As the input is a literal Java string expression, it will start and end with a double
* quote; as such any found backslash will not be the string's final character.
*/
private static boolean containsBannedEscapeSequence(String source) {
for (int p = source.indexOf('\\'); p != -1; p = source.indexOf('\\', p + 2)) {
if (source.charAt(p + 1) == '\'') {
return true;
}
}
return false;
}
/**
* Simplifies the given string constant source expression by dropping the backslash preceding an
* escaped single quote.
*
* @implNote Note that this method does not delegate to {@link
* SourceCode#toStringConstantExpression}, as that operation may replace other Unicode
* characters with their associated escape sequence.
* @implNote As the input is a literal Java string expression, it will start and end with a double
* quote; as such any found backslash will not be the string's final character.
*/
private static String dropRedundantEscapeSequences(String source) {
StringBuilder result = new StringBuilder();
for (int p = 0; p < source.length(); p++) {
char c = source.charAt(p);
if (c != '\\' || source.charAt(p + 1) != '\'') {
result.append(c);
}
}
return result.toString();
}
}

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. */ /** 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 // 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. // 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 // XXX: Write a similar checker for Spring RestTemplates, String.format and friends, Guava
// preconditions, ... // preconditions, ...
@AutoService(BugChecker.class) @AutoService(BugChecker.class)
@@ -41,7 +39,7 @@ import tech.picnic.errorprone.utils.SourceCode;
tags = LIKELY_ERROR) tags = LIKELY_ERROR)
public final class Slf4jLogStatement extends BugChecker implements MethodInvocationTreeMatcher { public final class Slf4jLogStatement extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> MARKER = isSubtypeOf("org.slf4j.Marker"); 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> THROWABLE = isSubtypeOf(Throwable.class);
private static final Matcher<ExpressionTree> SLF4J_LOGGER_INVOCATION = private static final Matcher<ExpressionTree> SLF4J_LOGGER_INVOCATION =
instanceMethod() instanceMethod()
@@ -71,7 +69,7 @@ public final class Slf4jLogStatement extends BugChecker implements MethodInvocat
* SLF4J log statements may accept a "marker" as a first argument, before the format string. * SLF4J log statements may accept a "marker" as a first argument, before the format string.
* We ignore such markers. * We ignore such markers.
*/ */
int lTrim = MARKER.matches(args.get(0), state) ? 1 : 0; int lTrim = SLF4J_MARKER.matches(args.get(0), state) ? 1 : 0;
/* /*
* SLF4J treats the final argument to a log statement specially if it is a `Throwabe`: it * SLF4J treats the final argument to a log statement specially if it is a `Throwabe`: it
* will always choose to render the associated stacktrace, even if the argument has a * will always choose to render the associated stacktrace, even if the argument has a

View File

@@ -53,7 +53,7 @@ public final class Slf4jLoggerDeclaration extends BugChecker implements Variable
private static final Matcher<ExpressionTree> IS_GET_LOGGER = private static final Matcher<ExpressionTree> IS_GET_LOGGER =
staticMethod().onDescendantOf("org.slf4j.LoggerFactory").named("getLogger"); staticMethod().onDescendantOf("org.slf4j.LoggerFactory").named("getLogger");
private static final String CANONICAL_STATIC_LOGGER_NAME_FLAG = private static final String CANONICAL_STATIC_LOGGER_NAME_FLAG =
"Slf4jLogDeclaration:CanonicalStaticLoggerName"; "Slf4jLoggerDeclaration:CanonicalStaticLoggerName";
private static final String DEFAULT_CANONICAL_LOGGER_NAME = "LOG"; private static final String DEFAULT_CANONICAL_LOGGER_NAME = "LOG";
private static final Matcher<ExpressionTree> IS_STATIC_ENCLOSING_CLASS_REFERENCE = private static final Matcher<ExpressionTree> IS_STATIC_ENCLOSING_CLASS_REFERENCE =
classLiteral(Slf4jLoggerDeclaration::isEnclosingClassReference); classLiteral(Slf4jLoggerDeclaration::isEnclosingClassReference);

View File

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

View File

@@ -23,7 +23,6 @@ import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.util.Constants;
import java.util.Formattable; import java.util.Formattable;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -37,7 +36,9 @@ import tech.picnic.errorprone.utils.SourceCode;
*/ */
// XXX: What about `v1 + "sep" + v2` and similar expressions? Do we want to rewrite those to // XXX: What about `v1 + "sep" + v2` and similar expressions? Do we want to rewrite those to
// `String.join`, or should some `String.join` invocations be rewritten to use the `+` operator? // `String.join`, or should some `String.join` invocations be rewritten to use the `+` operator?
// (The latter suggestion would conflict with the `FormatStringConcatenation` check.) // (The latter suggestion would conflict with the `FormatStringConcatenation` check, but does make
// more sense when `"sep"` is a long string. Similarly for `String.format("%s some long text %s",
// arg1, arg2)`.)
@AutoService(BugChecker.class) @AutoService(BugChecker.class)
@BugPattern( @BugPattern(
summary = "Prefer `String#join` over `String#format`", summary = "Prefer `String#join` over `String#format`",
@@ -150,7 +151,7 @@ public final class StringJoin extends BugChecker implements MethodInvocationTree
SuggestedFix.Builder fix = SuggestedFix.Builder fix =
SuggestedFix.builder() SuggestedFix.builder()
.replace(tree.getMethodSelect(), "String.join") .replace(tree.getMethodSelect(), "String.join")
.replace(arguments.next(), Constants.format(separator)); .replace(arguments.next(), SourceCode.toStringConstantExpression(separator, state));
while (arguments.hasNext()) { while (arguments.hasNext()) {
ExpressionTree argument = arguments.next(); ExpressionTree argument = arguments.next();

View File

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

View File

@@ -18,6 +18,7 @@ final class AssertJCharSequenceRules {
@BeforeTemplate @BeforeTemplate
void before(CharSequence charSequence) { void before(CharSequence charSequence) {
Refaster.anyOf( Refaster.anyOf(
assertThat(charSequence.isEmpty()).isTrue(),
assertThat(charSequence.length()).isEqualTo(0L), assertThat(charSequence.length()).isEqualTo(0L),
assertThat(charSequence.length()).isNotPositive()); assertThat(charSequence.length()).isNotPositive());
} }
@@ -33,6 +34,7 @@ final class AssertJCharSequenceRules {
@BeforeTemplate @BeforeTemplate
AbstractAssert<?, ?> before(CharSequence charSequence) { AbstractAssert<?, ?> before(CharSequence charSequence) {
return Refaster.anyOf( return Refaster.anyOf(
assertThat(charSequence.isEmpty()).isFalse(),
assertThat(charSequence.length()).isNotEqualTo(0), assertThat(charSequence.length()).isNotEqualTo(0),
assertThat(charSequence.length()).isPositive()); 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.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate; import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.Collection; 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 org.assertj.core.api.EnumerableAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation; import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@@ -21,6 +24,11 @@ final class AssertJEnumerableRules {
enumAssert.hasSizeLessThan(1)); enumAssert.hasSizeLessThan(1));
} }
@BeforeTemplate
void before(AbstractIterableAssert<?, ?, E, ?> enumAssert) {
enumAssert.size().isNotPositive();
}
@AfterTemplate @AfterTemplate
void after(EnumerableAssert<?, E> enumAssert) { void after(EnumerableAssert<?, E> enumAssert) {
enumAssert.isEmpty(); enumAssert.isEmpty();
@@ -34,30 +42,175 @@ final class AssertJEnumerableRules {
enumAssert.hasSizeGreaterThan(0), enumAssert.hasSizeGreaterThanOrEqualTo(1)); 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 @AfterTemplate
EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert) { EnumerableAssert<?, E> after(EnumerableAssert<?, E> enumAssert) {
return enumAssert.isNotEmpty(); return enumAssert.isNotEmpty();
} }
} }
static final class EnumerableAssertHasSameSizeAs<S, T> { static final class EnumerableAssertHasSize<E> {
@BeforeTemplate @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)); return enumAssert.hasSize(Iterables.size(iterable));
} }
@BeforeTemplate @BeforeTemplate
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, Collection<T> iterable) { EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, Collection<E> iterable) {
return enumAssert.hasSize(iterable.size()); return enumAssert.hasSize(iterable.size());
} }
@BeforeTemplate @BeforeTemplate
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, T[] iterable) { EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, E[] iterable) {
return enumAssert.hasSize(iterable.length); return enumAssert.hasSize(iterable.length);
} }
@BeforeTemplate
EnumerableAssert<?, S> before(EnumerableAssert<?, S> enumAssert, CharSequence iterable) {
return enumAssert.hasSize(iterable.length());
}
@AfterTemplate @AfterTemplate
EnumerableAssert<?, S> after(EnumerableAssert<?, S> enumAssert, Iterable<T> iterable) { EnumerableAssert<?, S> after(EnumerableAssert<?, S> enumAssert, Iterable<E> iterable) {
return enumAssert.hasSameSizeAs(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 com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.assertj.core.api.AbstractAssert; import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractBooleanAssert; import org.assertj.core.api.AbstractBooleanAssert;
import org.assertj.core.api.AbstractCollectionAssert; import org.assertj.core.api.AbstractCollectionAssert;
@@ -182,13 +181,13 @@ final class AssertJMapRules {
static final class AssertThatMapContainsOnlyKeys<K, V> { static final class AssertThatMapContainsOnlyKeys<K, V> {
@BeforeTemplate @BeforeTemplate
AbstractCollectionAssert<?, Collection<? extends K>, K, ?> before( 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); return assertThat(map.keySet()).hasSameElementsAs(keys);
} }
@AfterTemplate @AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS) @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); return assertThat(map).containsOnlyKeys(keys);
} }
} }

View File

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

@@ -7,7 +7,10 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatNullPointerException; import static org.assertj.core.api.Assertions.assertThatNullPointerException;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.InstanceOfAssertFactories.throwable;
import static org.assertj.core.api.InstanceOfAssertFactories.type;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate; import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate; import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Repeated; import com.google.errorprone.refaster.annotation.Repeated;
@@ -16,6 +19,7 @@ import java.io.IOException;
import org.assertj.core.api.AbstractObjectAssert; import org.assertj.core.api.AbstractObjectAssert;
import org.assertj.core.api.AbstractThrowableAssert; import org.assertj.core.api.AbstractThrowableAssert;
import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
import org.assertj.core.api.ThrowableAssertAlternative;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation; import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** /**
@@ -31,6 +35,21 @@ import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class AssertJThrowingCallableRules { final class AssertJThrowingCallableRules {
private AssertJThrowingCallableRules() {} private AssertJThrowingCallableRules() {}
static final class AssertThatThrownByIsInstanceOf<T extends Throwable> {
@BeforeTemplate
void before(ThrowingCallable throwingCallable, Class<T> exceptionType) {
Refaster.anyOf(
assertThatThrownBy(throwingCallable).asInstanceOf(throwable(exceptionType)),
assertThatThrownBy(throwingCallable).asInstanceOf(type(exceptionType)));
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
void after(ThrowingCallable throwingCallable, Class<T> exceptionType) {
assertThatThrownBy(throwingCallable).isInstanceOf(exceptionType);
}
}
static final class AssertThatThrownByIllegalArgumentException { static final class AssertThatThrownByIllegalArgumentException {
@BeforeTemplate @BeforeTemplate
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable) { AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable) {
@@ -61,6 +80,27 @@ final class AssertJThrowingCallableRules {
} }
} }
static final class AssertThatThrownByIllegalArgumentExceptionRootCauseHasMessage {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalArgumentException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalArgumentException()
.isThrownBy(throwingCallable)
.havingRootCause()
.withMessage(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IllegalArgumentException.class)
.rootCause()
.hasMessage(message);
}
}
static final class AssertThatThrownByIllegalArgumentExceptionHasMessageParameters { static final class AssertThatThrownByIllegalArgumentExceptionHasMessageParameters {
@BeforeTemplate @BeforeTemplate
@SuppressWarnings( @SuppressWarnings(
@@ -171,6 +211,27 @@ final class AssertJThrowingCallableRules {
} }
} }
static final class AssertThatThrownByIllegalStateExceptionRootCauseHasMessage {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalStateException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalStateException()
.isThrownBy(throwingCallable)
.havingRootCause()
.withMessage(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IllegalStateException.class)
.rootCause()
.hasMessage(message);
}
}
static final class AssertThatThrownByIllegalStateExceptionHasMessageParameters { static final class AssertThatThrownByIllegalStateExceptionHasMessageParameters {
@BeforeTemplate @BeforeTemplate
@SuppressWarnings( @SuppressWarnings(
@@ -279,6 +340,27 @@ final class AssertJThrowingCallableRules {
} }
} }
static final class AssertThatThrownByNullPointerExceptionRootCauseHasMessage {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByNullPointerException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatNullPointerException()
.isThrownBy(throwingCallable)
.havingRootCause()
.withMessage(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(NullPointerException.class)
.rootCause()
.hasMessage(message);
}
}
static final class AssertThatThrownByNullPointerExceptionHasMessageParameters { static final class AssertThatThrownByNullPointerExceptionHasMessageParameters {
@BeforeTemplate @BeforeTemplate
@SuppressWarnings( @SuppressWarnings(
@@ -386,6 +468,26 @@ final class AssertJThrowingCallableRules {
} }
} }
static final class AssertThatThrownByIOExceptionRootCauseHasMessage {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownByIOException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIOException()
.isThrownBy(throwingCallable)
.havingRootCause()
.withMessage(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IOException.class)
.rootCause()
.hasMessage(message);
}
}
static final class AssertThatThrownByIOExceptionHasMessageParameters { static final class AssertThatThrownByIOExceptionHasMessageParameters {
@BeforeTemplate @BeforeTemplate
@SuppressWarnings("AssertThatThrownByIOException" /* This is a more specific template. */) @SuppressWarnings("AssertThatThrownByIOException" /* This is a more specific template. */)
@@ -452,24 +554,24 @@ final class AssertJThrowingCallableRules {
} }
} }
static final class AssertThatThrownBy { static final class AssertThatThrownByAsInstanceOfThrowable<T extends Throwable> {
@BeforeTemplate @BeforeTemplate
AbstractObjectAssert<?, ?> before( ThrowableAssertAlternative<T> before(
ThrowingCallable throwingCallable, Class<? extends Throwable> exceptionType) { ThrowingCallable throwingCallable, Class<T> exceptionType) {
return assertThatExceptionOfType(exceptionType).isThrownBy(throwingCallable); return assertThatExceptionOfType(exceptionType).isThrownBy(throwingCallable);
} }
@AfterTemplate @AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS) @UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after( AbstractThrowableAssert<?, T> after(ThrowingCallable throwingCallable, Class<T> exceptionType) {
ThrowingCallable throwingCallable, Class<? extends Throwable> exceptionType) { return assertThatThrownBy(throwingCallable).asInstanceOf(throwable(exceptionType));
return assertThatThrownBy(throwingCallable).isInstanceOf(exceptionType);
} }
} }
static final class AssertThatThrownByHasMessage { static final class AssertThatThrownByHasMessage {
@BeforeTemplate @BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */) @SuppressWarnings(
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before( AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType, Class<? extends Throwable> exceptionType,
@@ -489,9 +591,37 @@ final class AssertJThrowingCallableRules {
} }
} }
static final class AssertThatThrownByRootCauseHasMessage {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
String message) {
return assertThatExceptionOfType(exceptionType)
.isThrownBy(throwingCallable)
.havingRootCause()
.withMessage(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(exceptionType)
.rootCause()
.hasMessage(message);
}
}
static final class AssertThatThrownByHasMessageParameters { static final class AssertThatThrownByHasMessageParameters {
@BeforeTemplate @BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */) @SuppressWarnings(
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before( AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType, Class<? extends Throwable> exceptionType,
@@ -517,7 +647,8 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByHasMessageStartingWith { static final class AssertThatThrownByHasMessageStartingWith {
@BeforeTemplate @BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */) @SuppressWarnings(
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before( AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType, Class<? extends Throwable> exceptionType,
@@ -541,7 +672,8 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByHasMessageContaining { static final class AssertThatThrownByHasMessageContaining {
@BeforeTemplate @BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */) @SuppressWarnings(
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before( AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType, Class<? extends Throwable> exceptionType,
@@ -565,7 +697,8 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByHasMessageNotContaining { static final class AssertThatThrownByHasMessageNotContaining {
@BeforeTemplate @BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */) @SuppressWarnings(
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before( AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType, Class<? extends Throwable> exceptionType,

View File

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

View File

@@ -11,6 +11,7 @@ import com.sun.tools.javac.util.Constants;
import com.sun.tools.javac.util.Convert; import com.sun.tools.javac.util.Convert;
import javax.lang.model.element.Name; import javax.lang.model.element.Name;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation; import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.utils.SourceCode;
/** Refaster rules related to {@link com.google.errorprone.bugpatterns.BugChecker} classes. */ /** Refaster rules related to {@link com.google.errorprone.bugpatterns.BugChecker} classes. */
@OnlineDocumentation @OnlineDocumentation
@@ -56,16 +57,26 @@ final class BugCheckerRules {
} }
} }
/** Prefer using the {@link Constants} API over more verbose alternatives. */ /**
* Prefer {@link SourceCode#toStringConstantExpression(Object,
* com.google.errorprone.VisitorState)} over alternatives that unnecessarily escape single quote
* characters.
*/
static final class ConstantsFormat { static final class ConstantsFormat {
@BeforeTemplate
String before(CharSequence value) {
return Constants.format(value);
}
@BeforeTemplate @BeforeTemplate
String before(String value) { String before(String value) {
return String.format("\"%s\"", Convert.quote(value)); return String.format("\"%s\"", Convert.quote(value));
} }
@AfterTemplate @AfterTemplate
String after(String value) { String after(CharSequence value) {
return Constants.format(value); return SourceCode.toStringConstantExpression(
value, Refaster.emitCommentBefore("REPLACEME", null));
} }
} }

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 @BeforeTemplate
void before(Set<T> removeFrom, Collection<S> elementsToRemove) { void before(Collection<T> removeFrom, Collection<S> elementsToRemove) {
elementsToRemove.forEach(removeFrom::remove); elementsToRemove.forEach(removeFrom::remove);
} }
@BeforeTemplate @BeforeTemplate
void before2(Set<T> removeFrom, Collection<S> elementsToRemove) { void before2(Collection<T> removeFrom, Collection<S> elementsToRemove) {
for (T element : elementsToRemove) { for (T element : elementsToRemove) {
removeFrom.remove(element); 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 // 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`. // constraint; ideally this check applies to any `S`.
@BeforeTemplate @BeforeTemplate
void before3(Set<T> removeFrom, Collection<S> elementsToRemove) { void before3(Collection<T> removeFrom, Collection<S> elementsToRemove) {
for (S element : elementsToRemove) { for (S element : elementsToRemove) {
removeFrom.remove(element); removeFrom.remove(element);
} }
} }
@AfterTemplate @AfterTemplate
void after(Set<T> removeFrom, Collection<S> elementsToRemove) { void after(Collection<T> removeFrom, Collection<S> elementsToRemove) {
removeFrom.removeAll(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.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate; 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.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Repeated; import com.google.errorprone.refaster.annotation.Repeated;
import java.io.File; import java.io.File;
@@ -11,6 +12,7 @@ import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.FileAttribute;
@@ -93,6 +95,12 @@ final class FileRules {
/** /**
* Prefer {@link Files#createTempFile(String, String, FileAttribute[])} over alternatives that * Prefer {@link Files#createTempFile(String, String, FileAttribute[])} over alternatives that
* create files with more liberal permissions. * create files with more liberal permissions.
*
* <p>Note that {@link File#createTempFile} treats the given prefix as a path, and ignores all but
* its file name. That is, the actual prefix used is derived from all characters following the
* final file separator (if any). This is not the case with {@link Files#createTempFile}, which
* will instead throw an {@link IllegalArgumentException} if the prefix contains any file
* separators.
*/ */
static final class FilesCreateTempFileToFile { static final class FilesCreateTempFileToFile {
@BeforeTemplate @BeforeTemplate
@@ -117,6 +125,12 @@ final class FileRules {
/** /**
* Prefer {@link Files#createTempFile(Path, String, String, FileAttribute[])} over alternatives * Prefer {@link Files#createTempFile(Path, String, String, FileAttribute[])} over alternatives
* that create files with more liberal permissions. * that create files with more liberal permissions.
*
* <p>Note that {@link File#createTempFile} treats the given prefix as a path, and ignores all but
* its file name. That is, the actual prefix used is derived from all characters following the
* final file separator (if any). This is not the case with {@link Files#createTempFile}, which
* will instead throw an {@link IllegalArgumentException} if the prefix contains any file
* separators.
*/ */
static final class FilesCreateTempFileInCustomDirectoryToFile { static final class FilesCreateTempFileInCustomDirectoryToFile {
@BeforeTemplate @BeforeTemplate
@@ -129,4 +143,35 @@ final class FileRules {
return Files.createTempFile(directory.toPath(), prefix, suffix).toFile(); 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 * Prefer {@link ImmutableListMultimap#builder()} over the associated constructor on constructions
* that produce a less-specific type. * that produce a less-specific type.
*/ */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See // XXX: This rule may drop generic type information, leading to non-compilable code.
// https://github.com/google/error-prone/pull/2706.
static final class ImmutableListMultimapBuilder<K, V> { static final class ImmutableListMultimapBuilder<K, V> {
@BeforeTemplate @BeforeTemplate
ImmutableMultimap.Builder<K, V> before() { ImmutableMultimap.Builder<K, V> before() {

View File

@@ -28,8 +28,7 @@ final class ImmutableListRules {
private ImmutableListRules() {} private ImmutableListRules() {}
/** Prefer {@link ImmutableList#builder()} over the associated constructor. */ /** Prefer {@link ImmutableList#builder()} over the associated constructor. */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See // XXX: This rule may drop generic type information, leading to non-compilable code.
// https://github.com/google/error-prone/pull/2706.
static final class ImmutableListBuilder<T> { static final class ImmutableListBuilder<T> {
@BeforeTemplate @BeforeTemplate
ImmutableList.Builder<T> before() { 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.Matches;
import com.google.errorprone.refaster.annotation.MayOptionallyUse; import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.Placeholder; import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.Repeated;
import com.google.errorprone.refaster.annotation.UseImportPolicy; import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
@@ -31,8 +32,7 @@ final class ImmutableMapRules {
private ImmutableMapRules() {} private ImmutableMapRules() {}
/** Prefer {@link ImmutableMap#builder()} over the associated constructor. */ /** Prefer {@link ImmutableMap#builder()} over the associated constructor. */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See // XXX: This rule may drop generic type information, leading to non-compilable code.
// https://github.com/google/error-prone/pull/2706.
static final class ImmutableMapBuilder<K, V> { static final class ImmutableMapBuilder<K, V> {
@BeforeTemplate @BeforeTemplate
ImmutableMap.Builder<K, V> before() { 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. */ /** Prefer {@link ImmutableMap#of(Object, Object)} over more contrived alternatives. */
static final class EntryToImmutableMap<K, V> { static final class EntryToImmutableMap<K, V> {
@BeforeTemplate @BeforeTemplate
ImmutableMap<K, V> before(Map.Entry<? extends K, ? extends V> entry) { ImmutableMap<K, V> before(Map.Entry<? extends K, ? extends V> entry) {
return Refaster.anyOf( 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))); 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. */ /** Prefer {@link ImmutableMap#copyOf(Iterable)} over more contrived alternatives. */
static final class EntryIterableToImmutableMap<K, V> { static final class EntryIterableToImmutableMap<K, V> {
@BeforeTemplate @BeforeTemplate
ImmutableMap<K, V> before(Map<? extends K, ? extends V> iterable) { Map<K, V> before(Map<? extends K, ? extends V> iterable) {
return Refaster.anyOf( return Refaster.anyOf(
ImmutableMap.copyOf(iterable.entrySet()), ImmutableMap.copyOf(iterable.entrySet()),
ImmutableMap.<K, V>builder().putAll(iterable).build()); ImmutableMap.<K, V>builder().putAll(iterable).buildOrThrow(),
Map.copyOf(iterable));
} }
@BeforeTemplate @BeforeTemplate
ImmutableMap<K, V> before(Iterable<? extends Map.Entry<? extends K, ? extends V>> iterable) { ImmutableMap<K, V> before(Iterable<? extends Map.Entry<? extends K, ? extends V>> iterable) {
return Refaster.anyOf( 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))); Streams.stream(iterable).collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)));
} }
@@ -140,8 +157,6 @@ final class ImmutableMapRules {
@Placeholder(allowsIdentity = true) @Placeholder(allowsIdentity = true)
abstract V valueFunction(@MayOptionallyUse E element); 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 @BeforeTemplate
ImmutableMap<K, V> before(Stream<E> stream) { ImmutableMap<K, V> before(Stream<E> stream) {
return stream return stream
@@ -225,7 +240,11 @@ final class ImmutableMapRules {
static final class ImmutableMapOf<K, V> { static final class ImmutableMapOf<K, V> {
@BeforeTemplate @BeforeTemplate
Map<K, V> before() { 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 @AfterTemplate
@@ -244,7 +263,10 @@ final class ImmutableMapRules {
@BeforeTemplate @BeforeTemplate
Map<K, V> before(K k1, V v1) { Map<K, V> before(K k1, V v1) {
return Refaster.anyOf( 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 @AfterTemplate
@@ -262,7 +284,8 @@ final class ImmutableMapRules {
static final class ImmutableMapOf2<K, V> { static final class ImmutableMapOf2<K, V> {
@BeforeTemplate @BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2) { 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 @AfterTemplate
@@ -280,7 +303,9 @@ final class ImmutableMapRules {
static final class ImmutableMapOf3<K, V> { static final class ImmutableMapOf3<K, V> {
@BeforeTemplate @BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3) { 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 @AfterTemplate
@@ -300,7 +325,10 @@ final class ImmutableMapRules {
static final class ImmutableMapOf4<K, V> { static final class ImmutableMapOf4<K, V> {
@BeforeTemplate @BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { 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 @AfterTemplate
@@ -320,7 +348,14 @@ final class ImmutableMapRules {
static final class ImmutableMapOf5<K, V> { static final class ImmutableMapOf5<K, V> {
@BeforeTemplate @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) { 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 @AfterTemplate
@@ -338,14 +373,14 @@ final class ImmutableMapRules {
abstract boolean keyFilter(@MayOptionallyUse K key); abstract boolean keyFilter(@MayOptionallyUse K key);
@BeforeTemplate @BeforeTemplate
ImmutableMap<K, V> before(ImmutableMap<K, V> map) { ImmutableMap<K, V> before(Map<K, V> map) {
return map.entrySet().stream() return map.entrySet().stream()
.filter(e -> keyFilter(e.getKey())) .filter(e -> keyFilter(e.getKey()))
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)); .collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
} }
@AfterTemplate @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))); return ImmutableMap.copyOf(Maps.filterKeys(map, k -> keyFilter(k)));
} }
} }
@@ -359,18 +394,34 @@ final class ImmutableMapRules {
abstract boolean valueFilter(@MayOptionallyUse V value); abstract boolean valueFilter(@MayOptionallyUse V value);
@BeforeTemplate @BeforeTemplate
ImmutableMap<K, V> before(ImmutableMap<K, V> map) { ImmutableMap<K, V> before(Map<K, V> map) {
return map.entrySet().stream() return map.entrySet().stream()
.filter(e -> valueFilter(e.getValue())) .filter(e -> valueFilter(e.getValue()))
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)); .collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
} }
@AfterTemplate @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))); 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: // XXX: Add a rule for this:
// Maps.transformValues(streamOfEntries.collect(groupBy(fun)), ImmutableMap::copyOf) // Maps.transformValues(streamOfEntries.collect(groupBy(fun)), ImmutableMap::copyOf)
// -> // ->

View File

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

View File

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

View File

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

View File

@@ -37,8 +37,7 @@ final class ImmutableSortedMapRules {
* Prefer {@link ImmutableSortedMap#naturalOrder()} over the alternative that requires explicitly * Prefer {@link ImmutableSortedMap#naturalOrder()} over the alternative that requires explicitly
* providing the {@link Comparator}. * providing the {@link Comparator}.
*/ */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See // XXX: This rule may drop generic type information, leading to non-compilable code.
// https://github.com/google/error-prone/pull/2706.
static final class ImmutableSortedMapNaturalOrderBuilder<K extends Comparable<? super K>, V> { static final class ImmutableSortedMapNaturalOrderBuilder<K extends Comparable<? super K>, V> {
@BeforeTemplate @BeforeTemplate
ImmutableSortedMap.Builder<K, V> before() { ImmutableSortedMap.Builder<K, V> before() {
@@ -55,8 +54,7 @@ final class ImmutableSortedMapRules {
* Prefer {@link ImmutableSortedMap#reverseOrder()} over the alternative that requires explicitly * Prefer {@link ImmutableSortedMap#reverseOrder()} over the alternative that requires explicitly
* providing the {@link Comparator}. * providing the {@link Comparator}.
*/ */
// XXX: This drops generic type information, sometimes leading to non-compilable code. See // XXX: This rule may drop generic type information, leading to non-compilable code.
// https://github.com/google/error-prone/pull/2706.
static final class ImmutableSortedMapReverseOrderBuilder<K extends Comparable<? super K>, V> { static final class ImmutableSortedMapReverseOrderBuilder<K extends Comparable<? super K>, V> {
@BeforeTemplate @BeforeTemplate
ImmutableSortedMap.Builder<K, V> before() { ImmutableSortedMap.Builder<K, V> before() {
@@ -73,7 +71,7 @@ final class ImmutableSortedMapRules {
static final class EmptyImmutableSortedMap<K extends Comparable<? super K>, V> { static final class EmptyImmutableSortedMap<K extends Comparable<? super K>, V> {
@BeforeTemplate @BeforeTemplate
ImmutableSortedMap<K, V> before() { ImmutableSortedMap<K, V> before() {
return ImmutableSortedMap.<K, V>naturalOrder().build(); return ImmutableSortedMap.<K, V>naturalOrder().buildOrThrow();
} }
@AfterTemplate @AfterTemplate
@@ -91,7 +89,7 @@ final class ImmutableSortedMapRules {
static final class PairToImmutableSortedMap<K extends Comparable<? super K>, V> { static final class PairToImmutableSortedMap<K extends Comparable<? super K>, V> {
@BeforeTemplate @BeforeTemplate
ImmutableSortedMap<K, V> before(K key, V value) { 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 @AfterTemplate
@@ -107,7 +105,7 @@ final class ImmutableSortedMapRules {
@BeforeTemplate @BeforeTemplate
ImmutableSortedMap<K, V> before(Map.Entry<? extends K, ? extends V> entry) { ImmutableSortedMap<K, V> before(Map.Entry<? extends K, ? extends V> entry) {
return Refaster.anyOf( return Refaster.anyOf(
ImmutableSortedMap.<K, V>naturalOrder().put(entry).build(), ImmutableSortedMap.<K, V>naturalOrder().put(entry).buildOrThrow(),
Stream.of(entry) Stream.of(entry)
.collect( .collect(
toImmutableSortedMap(naturalOrder(), Map.Entry::getKey, Map.Entry::getValue))); toImmutableSortedMap(naturalOrder(), Map.Entry::getKey, Map.Entry::getValue)));
@@ -128,7 +126,7 @@ final class ImmutableSortedMapRules {
return Refaster.anyOf( return Refaster.anyOf(
ImmutableSortedMap.copyOf(iterable, naturalOrder()), ImmutableSortedMap.copyOf(iterable, naturalOrder()),
ImmutableSortedMap.copyOf(iterable.entrySet()), ImmutableSortedMap.copyOf(iterable.entrySet()),
ImmutableSortedMap.<K, V>naturalOrder().putAll(iterable).build()); ImmutableSortedMap.<K, V>naturalOrder().putAll(iterable).buildOrThrow());
} }
@BeforeTemplate @BeforeTemplate
@@ -136,7 +134,7 @@ final class ImmutableSortedMapRules {
Iterable<? extends Map.Entry<? extends K, ? extends V>> iterable) { Iterable<? extends Map.Entry<? extends K, ? extends V>> iterable) {
return Refaster.anyOf( return Refaster.anyOf(
ImmutableSortedMap.copyOf(iterable, naturalOrder()), ImmutableSortedMap.copyOf(iterable, naturalOrder()),
ImmutableSortedMap.<K, V>naturalOrder().putAll(iterable).build(), ImmutableSortedMap.<K, V>naturalOrder().putAll(iterable).buildOrThrow(),
Streams.stream(iterable) Streams.stream(iterable)
.collect( .collect(
toImmutableSortedMap( 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.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.fail; 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.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf; 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 * <p>Note that, while both libraries throw an {@link AssertionError} in case of an assertion
* failure, the exact subtype used generally differs. * 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 // 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. // 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 // 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, Collection<Executable>)",
"assertAll(String, Executable[])", "assertAll(String, Executable[])",
"assertAll(String, Stream<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)", "assertEquals(Byte, byte)",
"assertEquals(byte, Byte)", "assertEquals(byte, Byte)",
@@ -302,6 +272,436 @@ import tech.picnic.errorprone.refaster.annotation.TypeMigration;
final class JUnitToAssertJRules { final class JUnitToAssertJRules {
private 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> { static final class Fail<T> {
@BeforeTemplate @BeforeTemplate
T before() { 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 com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Objects.requireNonNullElse; import static java.util.Objects.requireNonNullElse;
import static java.util.Objects.requireNonNullElseGet; import static java.util.Objects.requireNonNullElseGet;
import static java.util.function.Predicate.not;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import com.google.errorprone.refaster.Refaster; 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> { static final class IsNullFunction<T> {
@BeforeTemplate @BeforeTemplate
Predicate<T> before() { Predicate<T> before() {
return o -> o == null; return Refaster.anyOf(o -> o == null, not(Objects::nonNull));
} }
@AfterTemplate @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> { static final class NonNullFunction<T> {
@BeforeTemplate @BeforeTemplate
Predicate<T> before() { Predicate<T> before() {
return o -> o != null; return Refaster.anyOf(o -> o != null, not(Objects::isNull));
} }
@AfterTemplate @AfterTemplate

View File

@@ -279,6 +279,11 @@ final class OptionalRules {
*/ */
// XXX: Do we need the `.filter(Optional::isPresent)`? If it's absent the caller probably assumed // XXX: Do we need the `.filter(Optional::isPresent)`? If it's absent the caller probably assumed
// that the values are present. (If we drop it, we should rewrite vacuous filter steps.) // that the values are present. (If we drop it, we should rewrite vacuous filter steps.)
// 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> { static final class StreamFlatMapOptional<T> {
@BeforeTemplate @BeforeTemplate
Stream<T> before(Stream<Optional<T>> stream) { Stream<T> before(Stream<Optional<T>> stream) {
@@ -395,10 +400,7 @@ final class OptionalRules {
} }
} }
/** /** Don't unnecessarily transform an {@link Optional} to an equivalent instance. */
* Avoid unnecessary operations on an {@link Optional} that ultimately result in that very same
* {@link Optional}.
*/
static final class OptionalIdentity<T> { static final class OptionalIdentity<T> {
@BeforeTemplate @BeforeTemplate
@SuppressWarnings("NestedOptionals") @SuppressWarnings("NestedOptionals")

View File

@@ -8,12 +8,15 @@ import com.google.common.primitives.Floats;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs; import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts; import com.google.common.primitives.Shorts;
import com.google.common.primitives.UnsignedBytes;
import com.google.common.primitives.UnsignedInts; import com.google.common.primitives.UnsignedInts;
import com.google.common.primitives.UnsignedLongs; import com.google.common.primitives.UnsignedLongs;
import com.google.errorprone.refaster.Refaster; import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate; import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation; import com.google.errorprone.refaster.annotation.AlsoNegation;
import com.google.errorprone.refaster.annotation.BeforeTemplate; import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.Arrays;
import java.util.Comparator;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation; import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster rules related to expressions dealing with primitives. */ /** 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 alternatives. */
* Prefer JDK's {@link Integer#toUnsignedString(int,int)} over third-party or more verbose
* alternatives.
*/
static final class IntegerToUnsignedStringWithRadix { static final class IntegerToUnsignedStringWithRadix {
@BeforeTemplate @BeforeTemplate
String before(int i, int radix) { String before(int i, int radix) {
@@ -541,10 +541,7 @@ final class PrimitiveRules {
} }
} }
/** /** Prefer JDK's {@link Long#toUnsignedString(long,int)} over third-party alternatives. */
* Prefer JDK's {@link Long#toUnsignedString(long,int)} over third-party or more verbose
* alternatives.
*/
static final class LongToUnsignedStringWithRadix { static final class LongToUnsignedStringWithRadix {
@BeforeTemplate @BeforeTemplate
String before(long i, int radix) { String before(long i, int radix) {
@@ -556,4 +553,49 @@ final class PrimitiveRules {
return Long.toUnsignedString(i, radix); 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); 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 @BeforeTemplate
Flux<T> before(T value) { 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 @AfterTemplate
@@ -508,8 +515,14 @@ final class ReactorRules {
mono.switchIfEmpty(Mono.empty()), mono.flux().next(), mono.flux().singleOrEmpty()); mono.switchIfEmpty(Mono.empty()), mono.flux().next(), mono.flux().singleOrEmpty());
} }
// XXX: Consider filing a SonarCloud issue for the S2637 false positive.
@BeforeTemplate @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()); 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. */ /** Prefer {@link Mono#flux()}} over more contrived alternatives. */
static final class MonoFlux<T> { static final class MonoFlux<T> {
@BeforeTemplate @BeforeTemplate
@@ -906,12 +951,18 @@ final class ReactorRules {
/** Prefer direct invocation of {@link Mono#then()}} over more contrived alternatives. */ /** Prefer direct invocation of {@link Mono#then()}} over more contrived alternatives. */
static final class MonoThen<T> { static final class MonoThen<T> {
@BeforeTemplate @BeforeTemplate
Mono<@Nullable Void> before(Mono<T> mono) { @SuppressWarnings("java:S4968" /* Result may be `Mono<Void>`. */)
return Refaster.anyOf(mono.ignoreElement().then(), mono.flux().then()); Mono<? extends @Nullable Void> before(Mono<T> mono) {
return Refaster.anyOf(
mono.ignoreElement().then(),
mono.flux().then(),
Mono.when(mono),
Mono.whenDelayError(mono));
} }
@AfterTemplate @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(); return mono.then();
} }
} }
@@ -919,17 +970,25 @@ final class ReactorRules {
/** Avoid vacuous invocations of {@link Flux#ignoreElements()}. */ /** Avoid vacuous invocations of {@link Flux#ignoreElements()}. */
static final class FluxThen<T> { static final class FluxThen<T> {
@BeforeTemplate @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(); return flux.ignoreElements().then();
} }
// XXX: Consider filing a SonarCloud issue for the S2637 false positive.
@BeforeTemplate @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(); return flux.ignoreElements();
} }
@AfterTemplate @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(); return flux.then();
} }
} }
@@ -937,12 +996,14 @@ final class ReactorRules {
/** Avoid vacuous invocations of {@link Mono#ignoreElement()}. */ /** Avoid vacuous invocations of {@link Mono#ignoreElement()}. */
static final class MonoThenEmpty<T> { static final class MonoThenEmpty<T> {
@BeforeTemplate @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); return mono.ignoreElement().thenEmpty(publisher);
} }
@AfterTemplate @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); return mono.thenEmpty(publisher);
} }
} }
@@ -950,12 +1011,14 @@ final class ReactorRules {
/** Avoid vacuous invocations of {@link Flux#ignoreElements()}. */ /** Avoid vacuous invocations of {@link Flux#ignoreElements()}. */
static final class FluxThenEmpty<T> { static final class FluxThenEmpty<T> {
@BeforeTemplate @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); return flux.ignoreElements().thenEmpty(publisher);
} }
@AfterTemplate @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); return flux.thenEmpty(publisher);
} }
} }
@@ -1011,7 +1074,8 @@ final class ReactorRules {
} }
@BeforeTemplate @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); return mono1.thenEmpty(mono2);
} }
@@ -1029,7 +1093,8 @@ final class ReactorRules {
} }
@BeforeTemplate @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); return flux.thenEmpty(mono);
} }
@@ -1046,10 +1111,12 @@ final class ReactorRules {
// rule. Consider introducing an Error Prone check for this. // rule. Consider introducing an Error Prone check for this.
static final class MonoSingleOptional<T> { static final class MonoSingleOptional<T> {
@BeforeTemplate @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( return Refaster.anyOf(
mono.flux().collect(toOptional()), 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)); mono.transform(Mono::singleOptional));
} }
@@ -1742,6 +1809,91 @@ final class ReactorRules {
} }
} }
/** Prefer {@link PublisherProbe#assertWasSubscribed()} over more verbose alternatives. */
static final class PublisherProbeAssertWasSubscribed<T> {
@BeforeTemplate
void before(PublisherProbe<T> probe) {
Refaster.anyOf(
assertThat(probe.wasSubscribed()).isTrue(),
assertThat(probe.subscribeCount()).isNotNegative(),
assertThat(probe.subscribeCount()).isNotEqualTo(0),
assertThat(probe.subscribeCount()).isPositive());
}
@AfterTemplate
void after(PublisherProbe<T> probe) {
probe.assertWasSubscribed();
}
}
/** Prefer {@link PublisherProbe#assertWasNotSubscribed()} over more verbose alternatives. */
static final class PublisherProbeAssertWasNotSubscribed<T> {
@BeforeTemplate
void before(PublisherProbe<T> probe) {
Refaster.anyOf(
assertThat(probe.wasSubscribed()).isFalse(),
assertThat(probe.subscribeCount()).isEqualTo(0),
assertThat(probe.subscribeCount()).isNotPositive());
}
@AfterTemplate
void after(PublisherProbe<T> probe) {
probe.assertWasNotSubscribed();
}
}
/** Prefer {@link PublisherProbe#assertWasCancelled()} over more verbose alternatives. */
static final class PublisherProbeAssertWasCancelled<T> {
@BeforeTemplate
void before(PublisherProbe<T> probe) {
assertThat(probe.wasCancelled()).isTrue();
}
@AfterTemplate
void after(PublisherProbe<T> probe) {
probe.assertWasCancelled();
}
}
/** Prefer {@link PublisherProbe#assertWasNotCancelled()} over more verbose alternatives. */
static final class PublisherProbeAssertWasNotCancelled<T> {
@BeforeTemplate
void before(PublisherProbe<T> probe) {
assertThat(probe.wasCancelled()).isFalse();
}
@AfterTemplate
void after(PublisherProbe<T> probe) {
probe.assertWasNotCancelled();
}
}
/** Prefer {@link PublisherProbe#assertWasRequested()} over more verbose alternatives. */
static final class PublisherProbeAssertWasRequested<T> {
@BeforeTemplate
void before(PublisherProbe<T> probe) {
assertThat(probe.wasRequested()).isTrue();
}
@AfterTemplate
void after(PublisherProbe<T> probe) {
probe.assertWasRequested();
}
}
/** Prefer {@link PublisherProbe#assertWasNotRequested()} over more verbose alternatives. */
static final class PublisherProbeAssertWasNotRequested<T> {
@BeforeTemplate
void before(PublisherProbe<T> probe) {
assertThat(probe.wasRequested()).isFalse();
}
@AfterTemplate
void after(PublisherProbe<T> probe) {
probe.assertWasNotRequested();
}
}
/** Prefer {@link Mono#as(Function)} when creating a {@link StepVerifier}. */ /** Prefer {@link Mono#as(Function)} when creating a {@link StepVerifier}. */
static final class StepVerifierFromMono<T> { static final class StepVerifierFromMono<T> {
@BeforeTemplate @BeforeTemplate
@@ -1768,6 +1920,60 @@ final class ReactorRules {
} }
} }
/**
* Prefer {@link StepVerifier#verify()} over a dangling {@link
* StepVerifier#verifyThenAssertThat()}.
*/
// XXX: Application of this rule (and several others in this class) will cause invalid code if the
// result of the rewritten expression is dereferenced. Consider introducing a bug checker that
// identifies rules that change the return type of an expression and annotates them accordingly.
// The associated annotation can then be used to instruct an annotation processor to generate
// corresponding `void` rules that match only statements. This would allow the `Refaster` check to
// conditionally skip "not fully safe" rules. This allows conditionally flagging more dubious
// code, at the risk of compilation failures. With this rule, for example, we want to explicitly
// nudge users towards `StepVerifier.Step#assertNext(Consumer)` or
// `StepVerifier.Step#expectNext(Object)`, together with `Step#verifyComplete()`.
static final class StepVerifierVerify {
@BeforeTemplate
StepVerifier.Assertions before(StepVerifier stepVerifier) {
return stepVerifier.verifyThenAssertThat();
}
@AfterTemplate
Duration after(StepVerifier stepVerifier) {
return stepVerifier.verify();
}
}
/**
* Prefer {@link StepVerifier#verify(Duration)} over a dangling {@link
* StepVerifier#verifyThenAssertThat(Duration)}.
*/
static final class StepVerifierVerifyDuration {
@BeforeTemplate
StepVerifier.Assertions before(StepVerifier stepVerifier, Duration duration) {
return stepVerifier.verifyThenAssertThat(duration);
}
@AfterTemplate
Duration after(StepVerifier stepVerifier, Duration duration) {
return stepVerifier.verify(duration);
}
}
/** Don't unnecessarily invoke {@link StepVerifier#verifyLater()} multiple times. */
static final class StepVerifierVerifyLater {
@BeforeTemplate
StepVerifier before(StepVerifier stepVerifier) {
return stepVerifier.verifyLater().verifyLater();
}
@AfterTemplate
StepVerifier after(StepVerifier stepVerifier) {
return stepVerifier.verifyLater();
}
}
/** Don't unnecessarily have {@link StepVerifier.Step} expect no elements. */ /** Don't unnecessarily have {@link StepVerifier.Step} expect no elements. */
static final class StepVerifierStepIdentity<T> { static final class StepVerifierStepIdentity<T> {
@BeforeTemplate @BeforeTemplate
@@ -1868,6 +2074,12 @@ final class ReactorRules {
return step.expectErrorMatches(predicate).verify(); return step.expectErrorMatches(predicate).verify();
} }
@BeforeTemplate
@SuppressWarnings("StepVerifierVerify" /* This is a more specific template. */)
StepVerifier.Assertions before2(StepVerifier.LastStep step, Predicate<Throwable> predicate) {
return step.expectError().verifyThenAssertThat().hasOperatorErrorMatching(predicate);
}
@AfterTemplate @AfterTemplate
Duration after(StepVerifier.LastStep step, Predicate<Throwable> predicate) { Duration after(StepVerifier.LastStep step, Predicate<Throwable> predicate) {
return step.verifyErrorMatches(predicate); return step.verifyErrorMatches(predicate);
@@ -1890,6 +2102,30 @@ final class ReactorRules {
} }
} }
/**
* Prefer {@link StepVerifier.LastStep#verifyErrorSatisfies(Consumer)} with AssertJ over more
* contrived alternatives.
*/
static final class StepVerifierLastStepVerifyErrorSatisfiesAssertJ<T extends Throwable> {
@BeforeTemplate
@SuppressWarnings("StepVerifierVerify" /* This is a more specific template. */)
StepVerifier.Assertions before(StepVerifier.LastStep step, Class<T> clazz, String message) {
return Refaster.anyOf(
step.expectError()
.verifyThenAssertThat()
.hasOperatorErrorOfType(clazz)
.hasOperatorErrorWithMessage(message),
step.expectError(clazz).verifyThenAssertThat().hasOperatorErrorWithMessage(message),
step.expectErrorMessage(message).verifyThenAssertThat().hasOperatorErrorOfType(clazz));
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Duration after(StepVerifier.LastStep step, Class<T> clazz, String message) {
return step.verifyErrorSatisfies(t -> assertThat(t).isInstanceOf(clazz).hasMessage(message));
}
}
/** /**
* Prefer {@link StepVerifier.LastStep#verifyErrorMessage(String)} over more verbose alternatives. * Prefer {@link StepVerifier.LastStep#verifyErrorMessage(String)} over more verbose alternatives.
*/ */
@@ -1973,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 * 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 * 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}. */ /** Use the fluent API style when using {@link RxJava2Adapter#completableToMono}. */
static final class CompletableToMono { static final class CompletableToMono {
@BeforeTemplate @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( return Refaster.anyOf(
RxJava2Adapter.completableToMono(completable), RxJava2Adapter.completableToMono(completable),
completable.to(RxJava2Adapter::completableToMono)); completable.to(RxJava2Adapter::completableToMono));
} }
@AfterTemplate @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); return completable.as(RxJava2Adapter::completableToMono);
} }
} }

View File

@@ -297,6 +297,22 @@ final class StreamRules {
} }
} }
/**
* Prefer an unconditional {@link Map#get(Object)} call followed by a {@code null} check over a
* call to {@link Map#containsKey(Object)}, as the former avoids a second lookup operation.
*/
static final class StreamMapFilter<T, K, V> {
@BeforeTemplate
Stream<V> before(Stream<T> stream, Map<K, V> map) {
return stream.filter(map::containsKey).map(map::get);
}
@AfterTemplate
Stream<V> after(Stream<T> stream, Map<K, V> map) {
return stream.map(map::get).filter(Objects::nonNull);
}
}
static final class StreamMin<T> { static final class StreamMin<T> {
@BeforeTemplate @BeforeTemplate
@SuppressWarnings("java:S4266" /* This violation will be rewritten. */) @SuppressWarnings("java:S4266" /* This violation will be rewritten. */)

View File

@@ -29,11 +29,14 @@ final class StringRules {
private StringRules() {} private StringRules() {}
/** Prefer {@link String#isEmpty()} over alternatives that consult the string's length. */ /** 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` // XXX: Drop this rule once we (and OpenRewrite) no longer support projects targeting Java 14 or
// subtypes. This does require a mechanism (perhaps an annotation, or a separate Maven module) to // below. The `CharSequenceIsEmpty` rule then suffices. (This rule exists so that e.g. projects
// make sure that non-String expressions are rewritten only if client code also targets JDK 15+. // 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 { static final class StringIsEmpty {
@BeforeTemplate @BeforeTemplate
@SuppressWarnings("CharSequenceIsEmpty" /* This is a more specific template. */)
boolean before(String str) { boolean before(String str) {
return Refaster.anyOf(str.length() == 0, str.length() <= 0, str.length() < 1); return Refaster.anyOf(str.length() == 0, str.length() <= 0, str.length() < 1);
} }

View File

@@ -1,5 +1,6 @@
package tech.picnic.errorprone.refasterrules; package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.VisitorState;
import com.google.errorprone.fixes.SuggestedFix; import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.refaster.annotation.AfterTemplate; import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate; 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 { static final class SuggestedFixSwap {
@BeforeTemplate @BeforeTemplate
SuggestedFix before(Tree tree1, Tree tree2) { SuggestedFix before(Tree tree1, Tree tree2, VisitorState state) {
return SuggestedFix.builder().swap(tree1, tree2).build(); return SuggestedFix.builder().swap(tree1, tree2, state).build();
} }
@AfterTemplate @AfterTemplate
SuggestedFix after(Tree tree1, Tree tree2) { SuggestedFix after(Tree tree1, Tree tree2, VisitorState state) {
return SuggestedFix.swap(tree1, tree2); 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: // XXX: As-is these rules do not result in a complete migration:
// - Expressions containing comments are skipped due to a limitation of Refaster. // - Expressions containing comments are skipped due to a limitation of Refaster.
// - Assertions inside lambda expressions are also skipped. Unclear why. // - 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 // `actual`, which makes the validation weaker than necessary; fix this. (And investigate whether we
// can introduce validation for this.) // can introduce validation for this.)
@OnlineDocumentation @OnlineDocumentation
@TypeMigration( @TypeMigration(
of = Assert.class, of = Assert.class,
unmigratedMethods = { 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 * These `assertEqualsDeep` methods cannot (easily) be expressed using AssertJ because they
* mix regular equality and array equality: * mix regular equality and array equality:
*/ */
"assertEqualsDeep(Map<?, ?>, Map<?, ?>)", "assertEqualsDeep(Map<?, ?>, Map<?, ?>)",
"assertEqualsDeep(Map<?, ?>, Map<?, ?>, String)", "assertEqualsDeep(Map<?, ?>, Map<?, ?>, String)",
"assertEqualsDeep(Set<?>, Set<?>)",
"assertEqualsDeep(Set<?>, Set<?>, String)", "assertEqualsDeep(Set<?>, Set<?>, String)",
// XXX: Add migrations for the methods below. // XXX: Add migrations for the methods below.
"assertEqualsNoOrder(Collection<?>, Collection<?>)", "assertEqualsNoOrder(Collection<?>, Collection<?>)",
@@ -351,47 +300,168 @@ final class TestNGToAssertJRules {
} }
} }
@SuppressWarnings("java:S1448" /* Each variant requires a separate `@BeforeTemplate` method. */)
static final class AssertEqual { static final class AssertEqual {
@BeforeTemplate @BeforeTemplate
void before(boolean actual, boolean expected) { void before(boolean actual, boolean expected) {
assertEquals(actual, 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 @BeforeTemplate
void before(byte actual, byte expected) { void before(byte actual, byte expected) {
assertEquals(actual, 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 @BeforeTemplate
void before(char actual, char expected) { void before(char actual, char expected) {
assertEquals(actual, 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 @BeforeTemplate
void before(short actual, short expected) { void before(short actual, short expected) {
assertEquals(actual, 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 @BeforeTemplate
void before(int actual, int expected) { void before(int actual, int expected) {
assertEquals(actual, 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 @BeforeTemplate
void before(long actual, long expected) { void before(long actual, long expected) {
assertEquals(actual, 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 @BeforeTemplate
void before(float actual, float expected) { void before(float actual, float expected) {
assertEquals(actual, 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 @BeforeTemplate
void before(double actual, double expected) { void before(double actual, double expected) {
assertEquals(actual, 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 @BeforeTemplate
void before(Object actual, Object expected) { void before(Object actual, Object expected) {
assertEquals(actual, 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 { static final class AssertEqualWithMessage {
@BeforeTemplate @BeforeTemplate
void before(boolean actual, String message, boolean expected) { void before(boolean actual, String message, boolean expected) {
assertEquals(actual, expected, message); 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 @BeforeTemplate
void before(byte actual, String message, byte expected) { void before(byte actual, String message, byte expected) {
assertEquals(actual, expected, message); 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 @BeforeTemplate
void before(char actual, String message, char expected) { void before(char actual, String message, char expected) {
assertEquals(actual, expected, message); 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 @BeforeTemplate
void before(short actual, String message, short expected) { void before(short actual, String message, short expected) {
assertEquals(actual, expected, message); 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 @BeforeTemplate
void before(int actual, String message, int expected) { void before(int actual, String message, int expected) {
assertEquals(actual, expected, message); 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 @BeforeTemplate
void before(long actual, String message, long expected) { void before(long actual, String message, long expected) {
assertEquals(actual, expected, message); 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 @BeforeTemplate
void before(float actual, String message, float expected) { void before(float actual, String message, float expected) {
assertEquals(actual, expected, message); 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 @BeforeTemplate
void before(double actual, String message, double expected) { void before(double actual, String message, double expected) {
assertEquals(actual, expected, message); 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 @BeforeTemplate
void before(Object actual, String message, Object expected) { void before(Object actual, String message, Object expected) {
assertEquals(actual, expected, message); assertEquals(actual, expected, message);
@@ -485,7 +676,7 @@ final class TestNGToAssertJRules {
@AfterTemplate @AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS) @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)); 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 { static final class AssertEqualArraysIrrespectiveOfOrder {
@BeforeTemplate @BeforeTemplate
void before(Object[] actual, Object[] expected) { void before(Object[] actual, Object[] expected) {

View File

@@ -142,6 +142,63 @@ final class TimeRules {
} }
} }
/** Don't unnecessarily transform an {@link Instant} to an equivalent instance. */
static final class InstantIdentity {
@BeforeTemplate
Instant before(Instant instant, TemporalUnit temporalUnit) {
return Refaster.anyOf(
instant.plus(Duration.ZERO),
instant.plus(0, temporalUnit),
instant.plusNanos(0),
instant.plusMillis(0),
instant.plusSeconds(0),
instant.minus(Duration.ZERO),
instant.minus(0, temporalUnit),
instant.minusNanos(0),
instant.minusMillis(0),
instant.minusSeconds(0),
Instant.parse(instant.toString()),
instant.truncatedTo(ChronoUnit.NANOS),
Instant.ofEpochSecond(instant.getEpochSecond(), instant.getNano()));
}
@AfterTemplate
Instant after(Instant instant) {
return instant;
}
}
/**
* Prefer {@link Instant#truncatedTo(TemporalUnit)} over less obvious alternatives.
*
* <p>Note that {@link Instant#toEpochMilli()} throws an {@link ArithmeticException} for dates
* very far in the past or future, while the suggested alternative doesn't.
*/
static final class InstantTruncatedToMilliseconds {
@BeforeTemplate
Instant before(Instant instant) {
return Instant.ofEpochMilli(instant.toEpochMilli());
}
@AfterTemplate
Instant after(Instant instant) {
return instant.truncatedTo(ChronoUnit.MILLIS);
}
}
/** Prefer {@link Instant#truncatedTo(TemporalUnit)} over less obvious alternatives. */
static final class InstantTruncatedToSeconds {
@BeforeTemplate
Instant before(Instant instant) {
return Instant.ofEpochSecond(instant.getEpochSecond());
}
@AfterTemplate
Instant after(Instant instant) {
return instant.truncatedTo(ChronoUnit.SECONDS);
}
}
/** Prefer {@link Instant#atOffset(ZoneOffset)} over more verbose alternatives. */ /** Prefer {@link Instant#atOffset(ZoneOffset)} over more verbose alternatives. */
static final class InstantAtOffset { static final class InstantAtOffset {
@BeforeTemplate @BeforeTemplate

View File

@@ -16,7 +16,7 @@ final class ClassCastLambdaUsageTest {
"import java.util.stream.Stream;", "import java.util.stream.Stream;",
"", "",
"class A {", "class A {",
" void m() {", " <T> void m() {",
" Number localVariable = 0;", " Number localVariable = 0;",
"", "",
" Stream.of(0).map(i -> i);", " Stream.of(0).map(i -> i);",
@@ -32,13 +32,14 @@ final class ClassCastLambdaUsageTest {
" i -> {", " i -> {",
" return (Integer) i;", " return (Integer) i;",
" });", " });",
" Stream.<ImmutableSet>of(ImmutableSet.of(5)).map(s -> (ImmutableSet<Number>) s);", " Stream.<ImmutableSet>of(ImmutableSet.of(6)).map(s -> (ImmutableSet<Number>) s);",
" Stream.of(ImmutableSet.of(6)).map(s -> (ImmutableSet<?>) s);", " Stream.of(ImmutableSet.of(7)).map(s -> (ImmutableSet<?>) s);",
" Stream.of(7).reduce((a, b) -> (Integer) a);", " Stream.of(8).reduce((a, b) -> (Integer) a);",
" IntStream.of(8).mapToObj(i -> (char) i);", " IntStream.of(9).mapToObj(i -> (char) i);",
" Stream.of(10).map(i -> (T) i);",
"", "",
" // BUG: Diagnostic contains:", " // BUG: Diagnostic contains:",
" Stream.of(8).map(i -> (Integer) i);", " Stream.of(11).map(i -> (Integer) i);",
" }", " }",
"}") "}")
.doTest(); .doTest();

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

@@ -0,0 +1,179 @@
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 ExplicitArgumentEnumerationTest {
@Test
void identification() {
CompilationTestHelper.newInstance(ExplicitArgumentEnumeration.class, getClass())
.addSourceLines(
"A.java",
"import static org.assertj.core.api.Assertions.assertThat;",
"",
"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;",
"",
"class A {",
" // BUG: Diagnostic contains:",
" private final int value = unaryMethod(ImmutableList.of(1, 2));",
"",
" void m() {",
" ImmutableList<String> list = ImmutableList.of();",
" assertThat(ImmutableList.of()).containsAnyElementsOf(list);",
"",
" ImmutableList.<ImmutableList<String>>builder().add(ImmutableList.of());",
"",
" 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));",
" binaryMethod(ImmutableList.of(1, 2), 3);",
"",
" ImmutableList.builder()",
" // BUG: Diagnostic contains:",
" .addAll(ImmutableList.of())",
" // BUG: Diagnostic contains:",
" .addAll(ImmutableList.copyOf(new String[0]))",
" .addAll(ImmutableList.copyOf(ImmutableList.of()))",
" .build();",
"",
" assertThat(ImmutableList.of(1))",
" // BUG: Diagnostic contains:",
" .containsAnyElementsOf(ImmutableList.of(1))",
" // BUG: Diagnostic contains:",
" .isSubsetOf(ImmutableList.of(1));",
"",
" Flux.just(1, 2)",
" .as(StepVerifier::create)",
" // BUG: Diagnostic contains:",
" .expectNextSequence(ImmutableList.of(1, 2))",
" .verifyComplete();",
"",
" CompilationTestHelper.newInstance(BugChecker.class, getClass())",
" // BUG: Diagnostic contains:",
" .setArgs(ImmutableList.of(\"foo\"))",
" .withClasspath();",
" }",
"",
" private int unaryMethod(ImmutableList<Integer> args) {",
" return 0;",
" }",
"",
" private int unaryMethod(Integer... args) {",
" return unaryMethod(ImmutableList.copyOf(args));",
" }",
"",
" void unaryMethodWithLessVisibleOverload(ImmutableList<Integer> args) {}",
"",
" private void unaryMethodWithLessVisibleOverload(Integer... args) {",
" unaryMethodWithLessVisibleOverload(ImmutableList.copyOf(args));",
" }",
"",
" private void binaryMethod(ImmutableList<Integer> args, int extraArg) {}",
"",
" private void binaryMethod(Integer... args) {",
" binaryMethod(ImmutableList.copyOf(args), 0);",
" }",
"}")
.doTest();
}
@Test
void replacement() {
BugCheckerRefactoringTestHelper.newInstance(ExplicitArgumentEnumeration.class, getClass())
.addInputLines(
"A.java",
"import static org.assertj.core.api.Assertions.assertThat;",
"",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableMultiset;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"import java.util.Arrays;",
"import java.util.List;",
"import java.util.Set;",
"import reactor.core.publisher.Flux;",
"import reactor.test.StepVerifier;",
"",
"class A {",
" void m() {",
" ImmutableList.builder().addAll(ImmutableList.of()).build();",
"",
" assertThat(ImmutableList.of()).containsAnyElementsOf(ImmutableMultiset.of());",
" assertThat(ImmutableList.of()).containsAll(ImmutableSet.of());",
" assertThat(ImmutableList.of()).containsExactlyElementsOf(List.of());",
" assertThat(ImmutableList.of()).containsExactlyInAnyOrderElementsOf(Set.of());",
" assertThat(ImmutableList.of()).containsSequence(Arrays.asList());",
" assertThat(ImmutableList.of()).containsSubsequence(ImmutableList.of(1));",
" assertThat(ImmutableList.of()).doesNotContainAnyElementsOf(ImmutableMultiset.of(2));",
" assertThat(ImmutableList.of()).doesNotContainSequence(ImmutableSet.of(3));",
" assertThat(ImmutableList.of()).doesNotContainSubsequence(List.of(4));",
" assertThat(ImmutableList.of()).hasSameElementsAs(Set.of(5));",
" assertThat(ImmutableList.of()).isSubsetOf(Arrays.asList(6));",
"",
" Flux.empty()",
" .as(StepVerifier::create)",
" .expectNextSequence(ImmutableList.of(1, 2))",
" .verifyComplete();",
"",
" BugCheckerRefactoringTestHelper.newInstance(BugChecker.class, getClass())",
" .setArgs(ImmutableList.of(\"foo\", \"bar\"));",
" CompilationTestHelper.newInstance(BugChecker.class, getClass())",
" .setArgs(ImmutableList.of(\"foo\", \"bar\"));",
" }",
"}")
.addOutputLines(
"A.java",
"import static org.assertj.core.api.Assertions.assertThat;",
"",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableMultiset;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"import java.util.Arrays;",
"import java.util.List;",
"import java.util.Set;",
"import reactor.core.publisher.Flux;",
"import reactor.test.StepVerifier;",
"",
"class A {",
" void m() {",
" ImmutableList.builder().add().build();",
"",
" assertThat(ImmutableList.of()).containsAnyOf();",
" assertThat(ImmutableList.of()).contains();",
" assertThat(ImmutableList.of()).containsExactly();",
" assertThat(ImmutableList.of()).containsExactlyInAnyOrder();",
" assertThat(ImmutableList.of()).containsSequence();",
" assertThat(ImmutableList.of()).containsSubsequence(1);",
" assertThat(ImmutableList.of()).doesNotContain(2);",
" assertThat(ImmutableList.of()).doesNotContainSequence(3);",
" assertThat(ImmutableList.of()).doesNotContainSubsequence(4);",
" assertThat(ImmutableList.of()).containsOnly(5);",
" assertThat(ImmutableList.of()).isSubsetOf(6);",
"",
" Flux.empty().as(StepVerifier::create).expectNext(1, 2).verifyComplete();",
"",
" BugCheckerRefactoringTestHelper.newInstance(BugChecker.class, getClass()).setArgs(\"foo\", \"bar\");",
" CompilationTestHelper.newInstance(BugChecker.class, getClass()).setArgs(\"foo\", \"bar\");",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -28,6 +28,8 @@ final class IdentityConversionTest {
"import com.google.common.collect.ImmutableTable;", "import com.google.common.collect.ImmutableTable;",
"import com.google.errorprone.matchers.Matcher;", "import com.google.errorprone.matchers.Matcher;",
"import com.google.errorprone.matchers.Matchers;", "import com.google.errorprone.matchers.Matchers;",
"import java.time.Instant;",
"import java.time.ZonedDateTime;",
"import reactor.adapter.rxjava.RxJava2Adapter;", "import reactor.adapter.rxjava.RxJava2Adapter;",
"import reactor.core.publisher.Flux;", "import reactor.core.publisher.Flux;",
"import reactor.core.publisher.Mono;", "import reactor.core.publisher.Mono;",
@@ -149,6 +151,10 @@ final class IdentityConversionTest {
" // BUG: Diagnostic contains:", " // BUG: Diagnostic contains:",
" ImmutableTable<Object, Object, Object> o11 = ImmutableTable.copyOf(ImmutableTable.of());", " ImmutableTable<Object, Object, Object> o11 = ImmutableTable.copyOf(ImmutableTable.of());",
"", "",
" Instant instant1 = Instant.from(ZonedDateTime.now());",
" // BUG: Diagnostic contains:",
" Instant instant2 = Instant.from(Instant.now());",
"",
" // BUG: Diagnostic contains:", " // BUG: Diagnostic contains:",
" Matcher allOf1 = Matchers.allOf(instanceMethod());", " Matcher allOf1 = Matchers.allOf(instanceMethod());",
" Matcher allOf2 = Matchers.allOf(instanceMethod(), staticMethod());", " Matcher allOf2 = Matchers.allOf(instanceMethod(), staticMethod());",

View File

@@ -11,7 +11,7 @@ final class JUnitMethodDeclarationTest {
CompilationTestHelper.newInstance(JUnitMethodDeclaration.class, getClass()) CompilationTestHelper.newInstance(JUnitMethodDeclaration.class, getClass())
.addSourceLines( .addSourceLines(
"A.java", "A.java",
"import static org.junit.jupiter.params.provider.Arguments.arguments;", "import static org.junit.jupiter.params.provider.Arguments.*;",
"", "",
"import org.junit.jupiter.api.AfterAll;", "import org.junit.jupiter.api.AfterAll;",
"import org.junit.jupiter.api.AfterEach;", "import org.junit.jupiter.api.AfterEach;",
@@ -154,8 +154,10 @@ final class JUnitMethodDeclarationTest {
" void overload() {}", " void overload() {}",
"", "",
" @Test", " @Test",
" // BUG: Diagnostic contains: (but note that `arguments` is already statically imported)", " // BUG: Diagnostic contains: (but note that another method named `arguments` is in scope)",
" void testArguments() {}", " void testArguments() {",
" arguments();",
" }",
"", "",
" @Test", " @Test",
" // BUG: Diagnostic contains: (but note that `public` is not a valid identifier)", " // BUG: Diagnostic contains: (but note that `public` is not a valid identifier)",

View File

@@ -1,6 +1,5 @@
package tech.picnic.errorprone.bugpatterns; package tech.picnic.errorprone.bugpatterns;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugCheckerRefactoringTestHelper; import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode; import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper; import com.google.errorprone.CompilationTestHelper;
@@ -294,9 +293,8 @@ final class LexicographicalAnnotationAttributeListingTest {
/* Some violations are not flagged because they are not in- or excluded. */ /* Some violations are not flagged because they are not in- or excluded. */
CompilationTestHelper.newInstance(LexicographicalAnnotationAttributeListing.class, getClass()) CompilationTestHelper.newInstance(LexicographicalAnnotationAttributeListing.class, getClass())
.setArgs( .setArgs(
ImmutableList.of( "-XepOpt:LexicographicalAnnotationAttributeListing:Includes=pkg.A.Foo,pkg.A.Bar",
"-XepOpt:LexicographicalAnnotationAttributeListing:Includes=pkg.A.Foo,pkg.A.Bar", "-XepOpt:LexicographicalAnnotationAttributeListing:Excludes=pkg.A.Bar#value")
"-XepOpt:LexicographicalAnnotationAttributeListing:Excludes=pkg.A.Bar#value"))
.addSourceLines( .addSourceLines(
"pkg/A.java", "pkg/A.java",
"package pkg;", "package pkg;",

View File

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

View File

@@ -1,6 +1,5 @@
package tech.picnic.errorprone.bugpatterns; package tech.picnic.errorprone.bugpatterns;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugCheckerRefactoringTestHelper; import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode; import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper; import com.google.errorprone.CompilationTestHelper;
@@ -408,8 +407,7 @@ final class RedundantStringConversionTest {
void identificationOfCustomConversionMethod() { void identificationOfCustomConversionMethod() {
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass()) CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.setArgs( .setArgs(
ImmutableList.of( "-XepOpt:RedundantStringConversion:ExtraConversionMethods=java.lang.Enum#name(),A#name(),A.B#toString(int)")
"-XepOpt:RedundantStringConversion:ExtraConversionMethods=java.lang.Enum#name(),A#name(),A.B#toString(int)"))
.addSourceLines( .addSourceLines(
"A.java", "A.java",
"import java.math.RoundingMode;", "import java.math.RoundingMode;",

View File

@@ -0,0 +1,90 @@
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 RedundantStringEscapeTest {
@Test
void identification() {
CompilationTestHelper.newInstance(RedundantStringEscape.class, getClass())
.addSourceLines(
"A.java",
"import java.util.Arrays;",
"import java.util.List;",
"",
"class A {",
" List<String> m() {",
" return Arrays.asList(",
" \"foo\",",
" \"ß\",",
" \"'\",",
" \"\\\"\",",
" \"\\\\\",",
" \"\\\\'\",",
" \"'\\\\\",",
" // BUG: Diagnostic contains:",
" \"\\\\\\'\",",
" // BUG: Diagnostic contains:",
" \"\\'\\\\\",",
" // BUG: Diagnostic contains:",
" \"\\'\",",
" // BUG: Diagnostic contains:",
" \"'\\'\",",
" // BUG: Diagnostic contains:",
" \"\\''\",",
" // BUG: Diagnostic contains:",
" \"\\'\\'\",",
" (",
" // BUG: Diagnostic contains:",
" /* Leading comment. */ \"\\'\" /* Trailing comment. */),",
" // BUG: Diagnostic contains:",
" \"\\'foo\\\"bar\\'baz\\\"qux\\'\");",
" }",
"}")
.doTest();
}
@Test
void replacement() {
BugCheckerRefactoringTestHelper.newInstance(RedundantStringEscape.class, getClass())
.addInputLines(
"A.java",
"import java.util.Arrays;",
"import java.util.List;",
"",
"class A {",
" List<String> m() {",
" return Arrays.asList(",
" \"\\'\",",
" \"'\\'\",",
" \"\\''\",",
" \"\\'\\'\",",
" \"\\\\'\",",
" (",
" /* Leading comment. */ \"\\'\" /* Trailing comment. */),",
" \"\\'foo\\\"bar\\'baz\\\"qux\\'\");",
" }",
"}")
.addOutputLines(
"A.java",
"import java.util.Arrays;",
"import java.util.List;",
"",
"class A {",
" List<String> m() {",
" return Arrays.asList(",
" \"'\",",
" \"''\",",
" \"''\",",
" \"''\",",
" \"'ß'\",",
" (",
" /* Leading comment. */ \"'\" /* Trailing comment. */),",
" \"'foo\\\"bar'baz\\\"qux'\");",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -1,6 +1,5 @@
package tech.picnic.errorprone.bugpatterns; package tech.picnic.errorprone.bugpatterns;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugCheckerRefactoringTestHelper; import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode; import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper; import com.google.errorprone.CompilationTestHelper;
@@ -189,7 +188,7 @@ final class Slf4jLoggerDeclarationTest {
@Test @Test
void replacementWithCustomLoggerName() { void replacementWithCustomLoggerName() {
BugCheckerRefactoringTestHelper.newInstance(Slf4jLoggerDeclaration.class, getClass()) BugCheckerRefactoringTestHelper.newInstance(Slf4jLoggerDeclaration.class, getClass())
.setArgs(ImmutableList.of("-XepOpt:Slf4jLogDeclaration:CanonicalStaticLoggerName=FOO_BAR")) .setArgs("-XepOpt:Slf4jLoggerDeclaration:CanonicalStaticLoggerName=FOO_BAR")
.addInputLines( .addInputLines(
"A.java", "A.java",
"import org.slf4j.Logger;", "import org.slf4j.Logger;",

View File

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

View File

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

View File

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

View File

@@ -9,11 +9,15 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJCharSequenceRulesTest implements RefasterRuleCollectionTestCase { final class AssertJCharSequenceRulesTest implements RefasterRuleCollectionTestCase {
void testAssertThatCharSequenceIsEmpty() { void testAssertThatCharSequenceIsEmpty() {
assertThat("foo").isEmpty(); assertThat("foo").isEmpty();
assertThat("foo").isEmpty(); assertThat("bar").isEmpty();
assertThat("baz").isEmpty();
} }
ImmutableSet<AbstractAssert<?, ?>> testAssertThatCharSequenceIsNotEmpty() { 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() { 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.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.EnumerableAssert; import org.assertj.core.api.EnumerableAssert;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase; import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
@@ -14,20 +15,63 @@ final class AssertJEnumerableRulesTest implements RefasterRuleCollectionTestCase
} }
void testEnumerableAssertIsEmpty() { void testEnumerableAssertIsEmpty() {
assertThat(ImmutableSet.of()).hasSize(0); assertThat(ImmutableSet.of(1)).hasSize(0);
assertThat(ImmutableSet.of()).hasSizeLessThanOrEqualTo(0); assertThat(ImmutableSet.of(2)).hasSizeLessThanOrEqualTo(0);
assertThat(ImmutableSet.of()).hasSizeLessThan(1); assertThat(ImmutableSet.of(3)).hasSizeLessThan(1);
assertThat(ImmutableSet.of(4)).size().isNotPositive();
} }
ImmutableSet<EnumerableAssert<?, Character>> testEnumerableAssertIsNotEmpty() { ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertIsNotEmpty() {
return ImmutableSet.of( 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( return ImmutableSet.of(
assertThat(ImmutableSet.of(1)).hasSize(Iterables.size(ImmutableSet.of(2))), assertThat(ImmutableSet.of(1)).size().isEqualTo(2).returnToIterable(),
assertThat(ImmutableSet.of(3)).hasSize(ImmutableSet.of(4).size()), assertThat(ImmutableSet.of(3)).size().isEqualTo(4));
assertThat(ImmutableSet.of(5)).hasSize(new Integer[0].length)); }
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.ImmutableSet;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.EnumerableAssert; import org.assertj.core.api.EnumerableAssert;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase; import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
@@ -14,19 +15,62 @@ final class AssertJEnumerableRulesTest implements RefasterRuleCollectionTestCase
} }
void testEnumerableAssertIsEmpty() { void testEnumerableAssertIsEmpty() {
assertThat(ImmutableSet.of()).isEmpty(); assertThat(ImmutableSet.of(1)).isEmpty();
assertThat(ImmutableSet.of()).isEmpty(); assertThat(ImmutableSet.of(2)).isEmpty();
assertThat(ImmutableSet.of()).isEmpty(); assertThat(ImmutableSet.of(3)).isEmpty();
assertThat(ImmutableSet.of(4)).isEmpty();
} }
ImmutableSet<EnumerableAssert<?, Character>> testEnumerableAssertIsNotEmpty() { ImmutableSet<AbstractAssert<?, ?>> testEnumerableAssertIsNotEmpty() {
return ImmutableSet.of(assertThat("foo").isNotEmpty(), assertThat("bar").isNotEmpty());
}
ImmutableSet<EnumerableAssert<?, Integer>> testEnumerableAssertHasSameSizeAs() {
return ImmutableSet.of( return ImmutableSet.of(
assertThat(ImmutableSet.of(1)).hasSameSizeAs(ImmutableSet.of(2)), assertThat(ImmutableSet.of(1)).isNotEmpty(),
assertThat(ImmutableSet.of(3)).hasSameSizeAs(ImmutableSet.of(4)), assertThat(ImmutableSet.of(2)).isNotEmpty(),
assertThat(ImmutableSet.of(5)).hasSameSizeAs(new Integer[0])); 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(""); assertThat("foo").isEqualTo("");
} }
void testAssertThatStringIsEmpty() {
assertThat("foo".isEmpty()).isTrue();
}
AbstractStringAssert<?> testAbstractStringAssertStringIsNotEmpty() { AbstractStringAssert<?> testAbstractStringAssertStringIsNotEmpty() {
return assertThat("foo").isNotEqualTo(""); return assertThat("foo").isNotEqualTo("");
} }
AbstractAssert<?, ?> testAssertThatStringIsNotEmpty() { AbstractAssert<?, ?> testAssertThatStringContains() {
return assertThat("foo".isEmpty()).isFalse(); return assertThat("foo".contains("bar")).isTrue();
}
AbstractAssert<?, ?> testAssertThatStringDoesNotContain() {
return assertThat("foo".contains("bar")).isFalse();
} }
AbstractAssert<?, ?> testAssertThatMatches() { AbstractAssert<?, ?> testAssertThatMatches() {

View File

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

View File

@@ -6,6 +6,8 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatNullPointerException; import static org.assertj.core.api.Assertions.assertThatNullPointerException;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.InstanceOfAssertFactories.throwable;
import static org.assertj.core.api.InstanceOfAssertFactories.type;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import org.assertj.core.api.AbstractObjectAssert; import org.assertj.core.api.AbstractObjectAssert;
@@ -20,7 +22,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
assertThatIOException(), assertThatIOException(),
assertThatIllegalArgumentException(), assertThatIllegalArgumentException(),
assertThatIllegalStateException(), assertThatIllegalStateException(),
assertThatNullPointerException()); assertThatNullPointerException(),
type(Throwable.class));
}
void testAssertThatThrownByIsInstanceOf() {
assertThatThrownBy(() -> {}).asInstanceOf(throwable(IllegalArgumentException.class));
assertThatThrownBy(() -> {}).asInstanceOf(type(IllegalArgumentException.class));
} }
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentException() { AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentException() {
@@ -31,6 +39,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatIllegalArgumentException().isThrownBy(() -> {}).withMessage("foo"); return assertThatIllegalArgumentException().isThrownBy(() -> {}).withMessage("foo");
} }
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentExceptionRootCauseHasMessage() {
return assertThatIllegalArgumentException()
.isThrownBy(() -> {})
.havingRootCause()
.withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentExceptionHasMessageParameters() { AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentExceptionHasMessageParameters() {
return assertThatIllegalArgumentException().isThrownBy(() -> {}).withMessage("foo %s", "bar"); return assertThatIllegalArgumentException().isThrownBy(() -> {}).withMessage("foo %s", "bar");
} }
@@ -59,6 +74,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatIllegalStateException().isThrownBy(() -> {}).withMessage("foo"); return assertThatIllegalStateException().isThrownBy(() -> {}).withMessage("foo");
} }
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalStateExceptionRootCauseHasMessage() {
return assertThatIllegalStateException()
.isThrownBy(() -> {})
.havingRootCause()
.withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalStateExceptionHasMessageParameters() { AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalStateExceptionHasMessageParameters() {
return assertThatIllegalStateException().isThrownBy(() -> {}).withMessage("foo %s", "bar"); return assertThatIllegalStateException().isThrownBy(() -> {}).withMessage("foo %s", "bar");
} }
@@ -83,6 +105,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatNullPointerException().isThrownBy(() -> {}).withMessage("foo"); return assertThatNullPointerException().isThrownBy(() -> {}).withMessage("foo");
} }
AbstractObjectAssert<?, ?> testAssertThatThrownByNullPointerExceptionRootCauseHasMessage() {
return assertThatNullPointerException()
.isThrownBy(() -> {})
.havingRootCause()
.withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByNullPointerExceptionHasMessageParameters() { AbstractObjectAssert<?, ?> testAssertThatThrownByNullPointerExceptionHasMessageParameters() {
return assertThatNullPointerException().isThrownBy(() -> {}).withMessage("foo %s", "bar"); return assertThatNullPointerException().isThrownBy(() -> {}).withMessage("foo %s", "bar");
} }
@@ -107,6 +136,10 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatIOException().isThrownBy(() -> {}).withMessage("foo"); return assertThatIOException().isThrownBy(() -> {}).withMessage("foo");
} }
AbstractObjectAssert<?, ?> testAssertThatThrownByIOExceptionRootCauseHasMessage() {
return assertThatIOException().isThrownBy(() -> {}).havingRootCause().withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIOExceptionHasMessageParameters() { AbstractObjectAssert<?, ?> testAssertThatThrownByIOExceptionHasMessageParameters() {
return assertThatIOException().isThrownBy(() -> {}).withMessage("foo %s", "bar"); return assertThatIOException().isThrownBy(() -> {}).withMessage("foo %s", "bar");
} }
@@ -123,7 +156,7 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatIOException().isThrownBy(() -> {}).withMessageNotContaining("foo"); return assertThatIOException().isThrownBy(() -> {}).withMessageNotContaining("foo");
} }
AbstractObjectAssert<?, ?> testAssertThatThrownBy() { AbstractObjectAssert<?, ?> testAssertThatThrownByAsInstanceOfThrowable() {
return assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {}); return assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {});
} }
@@ -133,6 +166,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
.withMessage("foo"); .withMessage("foo");
} }
AbstractObjectAssert<?, ?> testAssertThatThrownByRootCauseHasMessage() {
return assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> {})
.havingRootCause()
.withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByHasMessageParameters() { AbstractObjectAssert<?, ?> testAssertThatThrownByHasMessageParameters() {
return assertThatExceptionOfType(IllegalArgumentException.class) return assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> {}) .isThrownBy(() -> {})

View File

@@ -6,6 +6,8 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatNullPointerException; import static org.assertj.core.api.Assertions.assertThatNullPointerException;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.InstanceOfAssertFactories.throwable;
import static org.assertj.core.api.InstanceOfAssertFactories.type;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import java.io.IOException; import java.io.IOException;
@@ -21,7 +23,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
assertThatIOException(), assertThatIOException(),
assertThatIllegalArgumentException(), assertThatIllegalArgumentException(),
assertThatIllegalStateException(), assertThatIllegalStateException(),
assertThatNullPointerException()); assertThatNullPointerException(),
type(Throwable.class));
}
void testAssertThatThrownByIsInstanceOf() {
assertThatThrownBy(() -> {}).isInstanceOf(IllegalArgumentException.class);
assertThatThrownBy(() -> {}).isInstanceOf(IllegalArgumentException.class);
} }
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentException() { AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentException() {
@@ -34,6 +42,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
.hasMessage("foo"); .hasMessage("foo");
} }
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentExceptionRootCauseHasMessage() {
return assertThatThrownBy(() -> {})
.isInstanceOf(IllegalArgumentException.class)
.rootCause()
.hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentExceptionHasMessageParameters() { AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentExceptionHasMessageParameters() {
return assertThatThrownBy(() -> {}) return assertThatThrownBy(() -> {})
.isInstanceOf(IllegalArgumentException.class) .isInstanceOf(IllegalArgumentException.class)
@@ -68,6 +83,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatThrownBy(() -> {}).isInstanceOf(IllegalStateException.class).hasMessage("foo"); return assertThatThrownBy(() -> {}).isInstanceOf(IllegalStateException.class).hasMessage("foo");
} }
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalStateExceptionRootCauseHasMessage() {
return assertThatThrownBy(() -> {})
.isInstanceOf(IllegalStateException.class)
.rootCause()
.hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalStateExceptionHasMessageParameters() { AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalStateExceptionHasMessageParameters() {
return assertThatThrownBy(() -> {}) return assertThatThrownBy(() -> {})
.isInstanceOf(IllegalStateException.class) .isInstanceOf(IllegalStateException.class)
@@ -100,6 +122,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatThrownBy(() -> {}).isInstanceOf(NullPointerException.class).hasMessage("foo"); return assertThatThrownBy(() -> {}).isInstanceOf(NullPointerException.class).hasMessage("foo");
} }
AbstractObjectAssert<?, ?> testAssertThatThrownByNullPointerExceptionRootCauseHasMessage() {
return assertThatThrownBy(() -> {})
.isInstanceOf(NullPointerException.class)
.rootCause()
.hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByNullPointerExceptionHasMessageParameters() { AbstractObjectAssert<?, ?> testAssertThatThrownByNullPointerExceptionHasMessageParameters() {
return assertThatThrownBy(() -> {}) return assertThatThrownBy(() -> {})
.isInstanceOf(NullPointerException.class) .isInstanceOf(NullPointerException.class)
@@ -132,6 +161,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatThrownBy(() -> {}).isInstanceOf(IOException.class).hasMessage("foo"); return assertThatThrownBy(() -> {}).isInstanceOf(IOException.class).hasMessage("foo");
} }
AbstractObjectAssert<?, ?> testAssertThatThrownByIOExceptionRootCauseHasMessage() {
return assertThatThrownBy(() -> {})
.isInstanceOf(IOException.class)
.rootCause()
.hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIOExceptionHasMessageParameters() { AbstractObjectAssert<?, ?> testAssertThatThrownByIOExceptionHasMessageParameters() {
return assertThatThrownBy(() -> {}).isInstanceOf(IOException.class).hasMessage("foo %s", "bar"); return assertThatThrownBy(() -> {}).isInstanceOf(IOException.class).hasMessage("foo %s", "bar");
} }
@@ -152,8 +188,8 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
.hasMessageNotContaining("foo"); .hasMessageNotContaining("foo");
} }
AbstractObjectAssert<?, ?> testAssertThatThrownBy() { AbstractObjectAssert<?, ?> testAssertThatThrownByAsInstanceOfThrowable() {
return assertThatThrownBy(() -> {}).isInstanceOf(IllegalArgumentException.class); return assertThatThrownBy(() -> {}).asInstanceOf(throwable(IllegalArgumentException.class));
} }
AbstractObjectAssert<?, ?> testAssertThatThrownByHasMessage() { AbstractObjectAssert<?, ?> testAssertThatThrownByHasMessage() {
@@ -162,6 +198,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
.hasMessage("foo"); .hasMessage("foo");
} }
AbstractObjectAssert<?, ?> testAssertThatThrownByRootCauseHasMessage() {
return assertThatThrownBy(() -> {})
.isInstanceOf(IllegalArgumentException.class)
.rootCause()
.hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByHasMessageParameters() { AbstractObjectAssert<?, ?> testAssertThatThrownByHasMessageParameters() {
return assertThatThrownBy(() -> {}) return assertThatThrownBy(() -> {})
.isInstanceOf(IllegalArgumentException.class) .isInstanceOf(IllegalArgumentException.class)

View File

@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.errorprone.BugCheckerRefactoringTestHelper; import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers; import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;
import com.google.errorprone.bugpatterns.BugChecker; import com.google.errorprone.bugpatterns.BugChecker;
import com.sun.tools.javac.util.Constants;
import com.sun.tools.javac.util.Convert; import com.sun.tools.javac.util.Convert;
import javax.lang.model.element.Name; import javax.lang.model.element.Name;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase; import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
@@ -11,7 +12,7 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase { final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase {
@Override @Override
public ImmutableSet<Object> elidedTypesAndStaticImports() { public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(Convert.class, FixChoosers.class); return ImmutableSet.of(Constants.class, Convert.class, FixChoosers.class);
} }
ImmutableSet<BugCheckerRefactoringTestHelper> testBugCheckerRefactoringTestHelperIdentity() { ImmutableSet<BugCheckerRefactoringTestHelper> testBugCheckerRefactoringTestHelperIdentity() {
@@ -29,8 +30,8 @@ final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase {
.addOutputLines("A.java", "class A {}"); .addOutputLines("A.java", "class A {}");
} }
String testConstantsFormat() { ImmutableSet<String> testConstantsFormat() {
return String.format("\"%s\"", Convert.quote("foo")); return ImmutableSet.of(Constants.format("foo"), String.format("\"%s\"", Convert.quote("bar")));
} }
ImmutableSet<Boolean> testNameContentEquals() { ImmutableSet<Boolean> testNameContentEquals() {

View File

@@ -8,11 +8,12 @@ import com.sun.tools.javac.util.Constants;
import com.sun.tools.javac.util.Convert; import com.sun.tools.javac.util.Convert;
import javax.lang.model.element.Name; import javax.lang.model.element.Name;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase; import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
import tech.picnic.errorprone.utils.SourceCode;
final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase { final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase {
@Override @Override
public ImmutableSet<Object> elidedTypesAndStaticImports() { public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(Convert.class, FixChoosers.class); return ImmutableSet.of(Constants.class, Convert.class, FixChoosers.class);
} }
ImmutableSet<BugCheckerRefactoringTestHelper> testBugCheckerRefactoringTestHelperIdentity() { ImmutableSet<BugCheckerRefactoringTestHelper> testBugCheckerRefactoringTestHelperIdentity() {
@@ -28,8 +29,10 @@ final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase {
.expectUnchanged(); .expectUnchanged();
} }
String testConstantsFormat() { ImmutableSet<String> testConstantsFormat() {
return Constants.format("foo"); return ImmutableSet.of(
SourceCode.toStringConstantExpression("foo", /* REPLACEME */ null),
SourceCode.toStringConstantExpression("bar", /* REPLACEME */ null));
} }
ImmutableSet<Boolean> testNameContentEquals() { ImmutableSet<Boolean> testNameContentEquals() {

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")); return Iterables.removeAll(new ArrayList<>(), ImmutableSet.of("foo"));
} }
void testSetRemoveAllCollection() { void testCollectionRemoveAllFromCollectionBlock() {
ImmutableSet.of("foo").forEach(new HashSet<>()::remove); ImmutableSet.of("foo").forEach(new HashSet<>()::remove);
for (Number element : ImmutableList.of(1)) { for (Number element : ImmutableList.of(1)) {
new HashSet<Number>().remove(element); new HashSet<Number>().remove(element);

View File

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

View File

@@ -39,4 +39,16 @@ final class FileRulesTest implements RefasterRuleCollectionTestCase {
File testFilesCreateTempFileInCustomDirectoryToFile() throws IOException { File testFilesCreateTempFileInCustomDirectoryToFile() throws IOException {
return File.createTempFile("foo", "bar", new File("baz")); 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 { File testFilesCreateTempFileInCustomDirectoryToFile() throws IOException {
return Files.createTempFile(new File("baz").toPath(), "foo", "bar").toFile(); 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<>(); return new ImmutableMap.Builder<>();
} }
ImmutableMap<Object, Object> testImmutableMapBuilderBuildOrThrow() {
return ImmutableMap.builder().build();
}
ImmutableSet<ImmutableMap<String, Integer>> testEntryToImmutableMap() { ImmutableSet<ImmutableMap<String, Integer>> testEntryToImmutableMap() {
return ImmutableSet.of( 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)) Stream.of(Map.entry("foo", 1))
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue))); .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))); ImmutableMap.copyOf(Maps.asMap(ImmutableSet.of(10), Integer::valueOf)));
} }
ImmutableSet<ImmutableMap<String, Integer>> testEntryIterableToImmutableMap() { ImmutableSet<Map<String, Integer>> testEntryIterableToImmutableMap() {
return ImmutableSet.of( return ImmutableSet.of(
ImmutableMap.copyOf(ImmutableMap.of("foo", 1).entrySet()), 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() ImmutableMap.<String, Integer>builder()
.putAll(ImmutableMap.of("foo", 1).entrySet()) .putAll(ImmutableMap.of("foo", 1).entrySet())
.build(), .buildOrThrow(),
ImmutableMap.of("foo", 1).entrySet().stream() ImmutableMap.of("foo", 1).entrySet().stream()
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)), .collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)),
Streams.stream(Iterables.cycle(Map.entry("foo", 1))) Streams.stream(Iterables.cycle(Map.entry("foo", 1)))
@@ -100,32 +105,51 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
ImmutableSet<Map<String, String>> testImmutableMapOf() { ImmutableSet<Map<String, String>> testImmutableMapOf() {
return ImmutableSet.of( return ImmutableSet.of(
ImmutableMap.<String, String>builder().build(), ImmutableMap.<String, String>builder().buildOrThrow(),
ImmutableMap.ofEntries(),
Collections.<String, String>emptyMap(), Collections.<String, String>emptyMap(),
Map.<String, String>of()); Map.<String, String>of());
} }
ImmutableSet<Map<String, String>> testImmutableMapOf1() { ImmutableSet<Map<String, String>> testImmutableMapOf1() {
return ImmutableSet.of( 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"), Collections.singletonMap("k1", "v1"),
Map.of("k1", "v1")); Map.of("k1", "v1"));
} }
Map<String, String> testImmutableMapOf2() { ImmutableSet<Map<String, String>> testImmutableMapOf2() {
return Map.of("k1", "v1", "k2", "v2"); return ImmutableSet.of(
ImmutableMap.ofEntries(Map.entry("k1", "v1"), Map.entry("k2", "v2")),
Map.of("k1", "v1", "k2", "v2"));
} }
Map<String, String> testImmutableMapOf3() { ImmutableSet<Map<String, String>> testImmutableMapOf3() {
return Map.of("k1", "v1", "k2", "v2", "k3", "v3"); 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() { ImmutableSet<Map<String, String>> testImmutableMapOf4() {
return Map.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4"); 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() { ImmutableSet<Map<String, String>> testImmutableMapOf5() {
return Map.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4", "k5", "v5"); 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() { ImmutableMap<String, Integer> testImmutableMapCopyOfMapsFilterKeys() {
@@ -139,4 +163,11 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
.filter(entry -> entry.getValue() > 0) .filter(entry -> entry.getValue() > 0)
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)); .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(); return ImmutableMap.builder();
} }
ImmutableMap<Object, Object> testImmutableMapBuilderBuildOrThrow() {
return ImmutableMap.builder().buildOrThrow();
}
ImmutableSet<ImmutableMap<String, Integer>> testEntryToImmutableMap() { ImmutableSet<ImmutableMap<String, Integer>> testEntryToImmutableMap() {
return ImmutableSet.of( return ImmutableSet.of(
ImmutableMap.of(Map.entry("foo", 1).getKey(), Map.entry("foo", 1).getValue()), 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)); Maps.toMap(ImmutableSet.of(10), Integer::valueOf));
} }
ImmutableSet<ImmutableMap<String, Integer>> testEntryIterableToImmutableMap() { ImmutableSet<Map<String, Integer>> testEntryIterableToImmutableMap() {
return ImmutableSet.of( 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)), ImmutableMap.copyOf(ImmutableMap.of("foo", 1)),
ImmutableMap.copyOf(ImmutableMap.of("foo", 1).entrySet()), ImmutableMap.copyOf(ImmutableMap.of("foo", 1).entrySet()),
@@ -83,28 +88,39 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
} }
ImmutableSet<Map<String, String>> testImmutableMapOf() { 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() { ImmutableSet<Map<String, String>> testImmutableMapOf1() {
return ImmutableSet.of( 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() { ImmutableSet<Map<String, String>> testImmutableMapOf2() {
return ImmutableMap.of("k1", "v1", "k2", "v2"); return ImmutableSet.of(
ImmutableMap.of("k1", "v1", "k2", "v2"), ImmutableMap.of("k1", "v1", "k2", "v2"));
} }
Map<String, String> testImmutableMapOf3() { ImmutableSet<Map<String, String>> testImmutableMapOf3() {
return ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3"); return ImmutableSet.of(
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3"),
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3"));
} }
Map<String, String> testImmutableMapOf4() { ImmutableSet<Map<String, String>> testImmutableMapOf4() {
return ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4"); 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() { ImmutableSet<Map<String, String>> testImmutableMapOf5() {
return ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4", "k5", "v5"); 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() { ImmutableMap<String, Integer> testImmutableMapCopyOfMapsFilterKeys() {
@@ -114,4 +130,11 @@ final class ImmutableMapRulesTest implements RefasterRuleCollectionTestCase {
ImmutableMap<String, Integer> testImmutableMapCopyOfMapsFilterValues() { ImmutableMap<String, Integer> testImmutableMapCopyOfMapsFilterValues() {
return ImmutableMap.copyOf(Maps.filterValues(ImmutableMap.of("foo", 1), v -> v > 0)); 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() { ImmutableSortedMap<String, Integer> testEmptyImmutableSortedMap() {
return ImmutableSortedMap.<String, Integer>naturalOrder().build(); return ImmutableSortedMap.<String, Integer>naturalOrder().buildOrThrow();
} }
ImmutableSortedMap<String, Integer> testPairToImmutableSortedMap() { 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() { ImmutableSet<ImmutableSortedMap<String, Integer>> testEntryToImmutableSortedMap() {
return ImmutableSet.of( 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)) Stream.of(Map.entry("foo", 1))
.collect(toImmutableSortedMap(naturalOrder(), Map.Entry::getKey, Map.Entry::getValue))); .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.copyOf(ImmutableSortedMap.of("foo", 1).entrySet()),
ImmutableSortedMap.<String, Integer>naturalOrder() ImmutableSortedMap.<String, Integer>naturalOrder()
.putAll(ImmutableSortedMap.of("foo", 1)) .putAll(ImmutableSortedMap.of("foo", 1))
.build(), .buildOrThrow(),
ImmutableSortedMap.<String, Integer>naturalOrder() ImmutableSortedMap.<String, Integer>naturalOrder()
.putAll(ImmutableSortedMap.of("foo", 1).entrySet()) .putAll(ImmutableSortedMap.of("foo", 1).entrySet())
.build(), .buildOrThrow(),
ImmutableSortedMap.of("foo", 1).entrySet().stream() ImmutableSortedMap.of("foo", 1).entrySet().stream()
.collect(toImmutableSortedMap(naturalOrder(), Map.Entry::getKey, Map.Entry::getValue)), .collect(toImmutableSortedMap(naturalOrder(), Map.Entry::getKey, Map.Entry::getValue)),
Streams.stream(Iterables.cycle(Map.entry("foo", 1))) 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; 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.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertInstanceOf;
@@ -24,6 +26,8 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
assertInstanceOf(null, null), assertInstanceOf(null, null),
assertThrows(null, null), assertThrows(null, null),
assertThrowsExactly(null, null), assertThrowsExactly(null, null),
offset(0.0),
(Runnable) () -> assertArrayEquals((int[]) null, null),
(Runnable) () -> assertFalse(true), (Runnable) () -> assertFalse(true),
(Runnable) () -> assertNotNull(null), (Runnable) () -> assertNotNull(null),
(Runnable) () -> assertNotSame(null, null), (Runnable) () -> assertNotSame(null, null),
@@ -32,6 +36,138 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
(Runnable) () -> assertTrue(true)); (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() { Object testFail() {
return Assertions.fail(); 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.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy; 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.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertInstanceOf;
@@ -27,6 +29,8 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
assertInstanceOf(null, null), assertInstanceOf(null, null),
assertThrows(null, null), assertThrows(null, null),
assertThrowsExactly(null, null), assertThrowsExactly(null, null),
offset(0.0),
(Runnable) () -> assertArrayEquals((int[]) null, null),
(Runnable) () -> assertFalse(true), (Runnable) () -> assertFalse(true),
(Runnable) () -> assertNotNull(null), (Runnable) () -> assertNotNull(null),
(Runnable) () -> assertNotSame(null, null), (Runnable) () -> assertNotSame(null, null),
@@ -35,6 +39,150 @@ final class JUnitToAssertJRulesTest implements RefasterRuleCollectionTestCase {
(Runnable) () -> assertTrue(true)); (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() { Object testFail() {
return org.assertj.core.api.Assertions.fail(); return org.assertj.core.api.Assertions.fail();
} }

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