Compare commits

...

226 Commits

Author SHA1 Message Date
Stephan Schroevers
c3b5ead02b WIP: Model modernizer-maven-plugin 2024-12-29 00:22:32 +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
Stephan Schroevers
f06a2e4d43 [maven-release-plugin] prepare release v0.19.1 2024-11-03 16:58:19 +01:00
Stephan Schroevers
cd06288f5b Fix error-prone-contrib runtime classpath (#1387) 2024-11-03 16:53:15 +01:00
Picnic-DevPla-Bot
4b458e01bd Upgrade Checkstyle 10.19.0 -> 10.20.0 (#1386)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.20.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.19.0...checkstyle-10.20.0
2024-11-01 09:37:37 +01:00
Stephan Schroevers
eccfc34c78 [maven-release-plugin] prepare for next development iteration 2024-10-31 20:57:03 +01:00
Stephan Schroevers
0317cb73d6 [maven-release-plugin] prepare release v0.19.0 2024-10-31 20:57:03 +01:00
Mohamed Sameh
ce6931cc36 Ignore primitive casts in ClassCastLambdaUsage check (#1385) 2024-10-30 15:37:40 +01:00
Stephan Schroevers
9940576ea8 Introduce NameContentEquals Refaster rule (#1379) 2024-10-29 10:55:55 +01:00
Mohamed Sameh
caf2a86922 Introduce ClassCastLambdaUsage check (#1381)
This new check replaces the `ClassLiteralCast` Refaster rule, as the 
latter produced invalid code by suggesting expressions of the form
`T.class::cast` for generic `T`.
2024-10-29 10:35:36 +01:00
Stephan Schroevers
507d759d02 Upgrade JDKs used by GitHub Actions builds (#1329)
Summary of changes:
- Use JDK 17.0.13 instead of 17.0.10.
- Use JDK 21.0.5 instead of 21.0.2.
- Use JDK 23.0.1 instead of 22.0.2.
- Have GitHub issue template reference more recent version numbers.

See:
- https://adoptium.net/temurin/release-notes/?version=jdk-17.0.11+9
- https://adoptium.net/temurin/release-notes/?version=jdk-17.0.12+7
- https://adoptium.net/temurin/release-notes/?version=jdk-17.0.13+11
- https://adoptium.net/temurin/release-notes/?version=jdk-21.0.3+9
- https://adoptium.net/temurin/release-notes/?version=jdk-21.0.4+7
- https://adoptium.net/temurin/release-notes/?version=jdk-21.0.5+11
- https://adoptium.net/temurin/release-notes/?version=jdk-23+37
- https://adoptium.net/temurin/release-notes/?version=jdk-23.0.1+11
2024-10-29 10:26:04 +01:00
Picnic-DevPla-Bot
8ec4936980 Upgrade NullAway 0.12.0 -> 0.12.1 (#1383)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.12.1
- https://github.com/uber/NullAway/compare/v0.12.0...v0.12.1
2024-10-29 10:16:33 +01:00
Picnic-DevPla-Bot
0f0b27abb7 Upgrade Jackson 2.18.0 -> 2.18.1 (#1382)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.18.1
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.18.0...jackson-bom-2.18.1
2024-10-29 09:43:59 +01:00
Mohamed Sameh
2b1dbd98cd Introduce Slf4jLoggerDeclaration check (#783) 2024-10-28 12:37:10 +01:00
Picnic-DevPla-Bot
e0583a8f0a Upgrade OpenRewrite Templating 1.16.2 -> 1.16.3 (#1380)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.16.3
- https://github.com/openrewrite/rewrite-templating/compare/v1.16.2...v1.16.3
2024-10-28 08:44:43 +01:00
Mohamed Sameh
21437a43aa Introduce ConstantNaming check (#794)
This check flags static constants that do not follow the upper snake
case naming convention.

While there, introduce the `Flags#getSet` utility method, and use it to
replace `Flags#getList` in relevant places.
2024-10-27 14:23:59 +01:00
Stephan Schroevers
cf8af8c5cf Use dynamic Reproducible Builds badge (#1378) 2024-10-27 13:19:46 +01:00
Picnic-DevPla-Bot
07bd4b0b54 Upgrade maven-checkstyle-plugin 3.5.0 -> 3.6.0 (#1377)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MCHECKSTYLE%20AND%20fixVersion%20%3E%203.5.0%20AND%20fixVersion%20%3C%3D%203.6.0
- https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.5.0...maven-checkstyle-plugin-3.6.0
2024-10-27 12:46:41 +01:00
Picnic-DevPla-Bot
d1765fea0e Upgrade maven-dependency-plugin 3.8.0 -> 3.8.1 (#1375)
See:
- https://github.com/apache/maven-dependency-plugin/releases/tag/maven-dependency-plugin-3.8.1
- https://github.com/apache/maven-dependency-plugin/compare/maven-dependency-plugin-3.8.0...maven-dependency-plugin-3.8.1
2024-10-27 12:37:15 +01:00
Picnic-DevPla-Bot
5922c5b032 Upgrade Checkstyle 10.18.2 -> 10.19.0 (#1376)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.19.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.18.2...checkstyle-10.19.0
2024-10-27 12:12:35 +01:00
Danylo Naumenko
56b60f5cf6 Introduce MicrometerRules Refaster rule collection (#1365) 2024-10-26 14:56:11 +02:00
Mohamed Sameh
be6b17b7dc Introduce ImmutableEnumSetRules Refaster rule collection (#1302) 2024-10-26 14:01:25 +02:00
Picnic-DevPla-Bot
f782ec2d8f Upgrade Spring Boot 3.3.4 -> 3.3.5 (#1374)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v3.3.5
- https://github.com/spring-projects/spring-boot/compare/v3.3.4...v3.3.5
2024-10-26 13:36:32 +02:00
Picnic-DevPla-Bot
6e88e3cea8 Upgrade Error Prone 2.33.0 -> 2.35.1 (#1363)
See:
- https://github.com/google/error-prone/releases/tag/v2.34.0
- https://github.com/google/error-prone/releases/tag/v2.35.0
- https://github.com/google/error-prone/releases/tag/v2.35.1
- https://github.com/google/error-prone/compare/v2.33.0...v2.35.1
- https://github.com/PicnicSupermarket/error-prone/compare/v2.33.0-picnic-2...v2.35.1-picnic-1
2024-10-26 13:20:13 +02:00
Picnic-DevPla-Bot
09fb21358a Upgrade Project Reactor 2023.0.10 -> 2023.0.11 (#1359)
See:
- https://github.com/reactor/reactor/releases/tag/2023.0.11
- https://github.com/reactor/reactor/compare/2023.0.10...2023.0.11
2024-10-26 11:53:55 +02:00
Picnic-DevPla-Bot
c27a626042 Upgrade OpenRewrite 2.21.0 -> 2.21.1 (#1369)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.21.1
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.21.0...v2.21.1
2024-10-26 11:33:07 +02:00
Picnic-DevPla-Bot
da33e800fa Upgrade Spring Security 6.3.3 -> 6.3.4 (#1367)
See:
- https://github.com/spring-projects/spring-security/releases/tag/6.3.4
- https://github.com/spring-projects/spring-security/compare/6.3.3...6.3.4
2024-10-25 23:50:12 +02:00
Picnic-DevPla-Bot
bc13976cc7 Upgrade OpenRewrite Templating 1.16.1 -> 1.16.2 (#1370)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.16.2
- https://github.com/openrewrite/rewrite-templating/compare/v1.16.1...v1.16.2
2024-10-25 23:36:02 +02:00
Picnic-DevPla-Bot
7f1f0656fd Upgrade maven-site-plugin 3.20.0 -> 3.21.0 (#1371)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MSITE%20AND%20fixVersion%20%3E%203.20.0%20AND%20fixVersion%20%3C%3D%203.21.0
- https://github.com/apache/maven-site-plugin/compare/maven-site-plugin-3.20.0...maven-site-plugin-3.21.0
2024-10-25 23:26:57 +02:00
Picnic-DevPla-Bot
4e99382f42 Upgrade pomchecker-maven-plugin 1.13.0 -> 1.14.0 (#1372)
See:
- https://github.com/kordamp/pomchecker/releases/tag/v1.14.0
- https://github.com/kordamp/pomchecker/compare/v1.13.0...v1.14.0
2024-10-25 22:50:26 +02:00
Picnic-DevPla-Bot
9aa03aa842 Upgrade JUnit 5 5.11.2 -> 5.11.3 (#1366)
See:
- https://junit.org/junit5/docs/current/release-notes/
- https://github.com/junit-team/junit5/releases/tag/r5.11.3
- https://github.com/junit-team/junit5/compare/r5.11.2...r5.11.3
2024-10-25 22:39:48 +02:00
Picnic-DevPla-Bot
71cc09a7e7 Upgrade Spring 6.1.13 -> 6.1.14 (#1362)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v6.1.14
- https://github.com/spring-projects/spring-framework/compare/v6.1.13...v6.1.14
2024-10-25 17:07:18 +02:00
Picnic-DevPla-Bot
9b4cbfb84d Upgrade Byte Buddy 1.15.5 -> 1.15.7 (#1368)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.15.6
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.15.7
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.15.5...byte-buddy-1.15.7
2024-10-24 09:01:49 +02:00
Picnic-DevPla-Bot
f2238c779c Upgrade Guava 33.3.0-jre -> 33.3.1-jre (#1336)
And drop some Refaster rules now covered by `@InlineMe` instructions.

See:
- https://guava.dev/releases/33.3.1-jre/api/diffs/
- https://github.com/google/guava/releases/tag/v33.3.1
- https://github.com/google/guava/compare/v33.3.0...v33.3.1
2024-10-23 10:06:19 +02:00
Picnic-DevPla-Bot
6e893e9869 Upgrade fmt-maven-plugin 2.24 -> 2.25 (#1356)
See:
- https://github.com/spotify/fmt-maven-plugin/releases/tag/2.25
- https://github.com/spotify/fmt-maven-plugin/compare/2.24...2.25
2024-10-23 09:30:41 +02:00
Picnic-DevPla-Bot
7ee8826e96 Upgrade NullAway 0.11.3 -> 0.12.0 (#1364)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.12.0
- https://github.com/uber/NullAway/compare/v0.11.3...v0.12.0
2024-10-20 12:35:33 +02:00
Picnic-DevPla-Bot
a0689f62b4 Upgrade Byte Buddy 1.15.4 -> 1.15.5 (#1360)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.15.5
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.15.4...byte-buddy-1.15.5
2024-10-18 13:53:23 +02:00
Picnic-DevPla-Bot
1b00c87b2f Upgrade Mockito 5.14.0 -> 5.14.2 (#1361)
See:
- https://github.com/mockito/mockito/releases/tag/v5.14.1
- https://github.com/mockito/mockito/releases/tag/v5.14.2
- https://github.com/mockito/mockito/compare/v5.14.0...v5.14.2
2024-10-18 13:23:57 +02:00
Picnic-DevPla-Bot
0bce1a0e29 Upgrade Mockito 5.13.0 -> 5.14.0 (#1345)
And configure its Java agent such that Byte Buddy does not need to use
the deprecated self-attach mechanism.

See:
- https://github.com/mockito/mockito/releases/tag/v5.14.0
- https://github.com/mockito/mockito/compare/v5.13.0...v5.14.0
2024-10-17 15:11:27 +02:00
Picnic-DevPla-Bot
ce18b0c058 Upgrade Google Java Format 1.23.0 -> 1.24.0 (#1352)
See:
- https://github.com/google/google-java-format/releases/tag/v1.24.0
- https://github.com/google/google-java-format/compare/v1.23.0...v1.24.0
2024-10-16 20:53:44 +02:00
Picnic-DevPla-Bot
4f2c143b9c Upgrade maven-gpg-plugin 3.2.6 -> 3.2.7 (#1344)
See:
- https://github.com/apache/maven-gpg-plugin/releases/tag/maven-gpg-plugin-3.2.7
- https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.6...maven-gpg-plugin-3.2.7
2024-10-16 19:07:41 +02:00
Picnic-DevPla-Bot
f4740e0e64 Upgrade JUnit 5 5.11.1 -> 5.11.2 (#1351)
See:
- https://junit.org/junit5/docs/current/release-notes/
- https://github.com/junit-team/junit5/releases/tag/r5.11.2
- https://github.com/junit-team/junit5/compare/r5.11.1...r5.11.2
2024-10-15 09:07:40 +02:00
Picnic-DevPla-Bot
3a155169ef Upgrade MongoDB driver 5.1.4 -> 5.2.0 (#1341)
See:
- https://jira.mongodb.org/issues/?jql=project%20%3D%20JAVA%20AND%20fixVersion%20%3E%205.1.4%20AND%20fixVersion%20%3C%3D%205.2.0
- https://github.com/mongodb/mongo-java-driver/releases/tag/r5.2.0
- https://github.com/mongodb/mongo-java-driver/compare/r5.1.4...r5.2.0
2024-10-14 14:22:27 +02:00
Picnic-DevPla-Bot
13847f6d2c Upgrade Jackson 2.17.2 -> 2.18.0 (#1343)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.18
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.17.2...jackson-bom-2.18.0
2024-10-14 13:26:24 +02:00
Picnic-DevPla-Bot
6a81b92e11 Upgrade Surefire 3.5.0 -> 3.5.1 (#1354)
See:
- https://github.com/apache/maven-surefire/releases/tag/surefire-3.5.1
- https://github.com/apache/maven-surefire/compare/surefire-3.5.0...surefire-3.5.1
2024-10-14 12:06:14 +02:00
Stephan Schroevers
5794b404f2 Update Error Prone compatibility matrix (#1358) 2024-10-14 09:53:24 +02:00
Picnic-DevPla-Bot
b2d7ed4dc7 Upgrade Forbidden APIs plugin 3.7 -> 3.8 (#1355)
See:
- https://github.com/policeman-tools/forbidden-apis/wiki/Changes
- https://github.com/policeman-tools/forbidden-apis/compare/3.7...3.8
2024-10-14 07:03:03 +02:00
Picnic-DevPla-Bot
0fdc102aa5 Upgrade Swagger 2.2.23 -> 2.2.25 (#1337)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.24
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.25
- https://github.com/swagger-api/swagger-core/compare/v2.2.23...v2.2.25
2024-10-13 20:52:45 +02:00
Picnic-DevPla-Bot
ce3cf6a2d0 Upgrade maven-javadoc-plugin 3.10.0 -> 3.10.1 (#1349)
See:
- https://github.com/apache/maven-javadoc-plugin/releases/tag/maven-javadoc-plugin-3.10.1
- https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.10.0...maven-javadoc-plugin-3.10.1
2024-10-13 18:22:35 +02:00
Picnic-DevPla-Bot
0f657f8835 Upgrade OpenRewrite 2.19.0 -> 2.21.0 (#1338)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.20.0
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.21.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.19.0...v2.21.0
2024-10-13 16:52:43 +02:00
Picnic-DevPla-Bot
5f56f43c40 Upgrade OpenRewrite Templating 1.15.0 -> 1.16.1 (#1339)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.16.0
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.16.1
- https://github.com/openrewrite/rewrite-templating/compare/v1.15.0...v1.16.1
2024-10-13 16:03:59 +02:00
Picnic-DevPla-Bot
ef6faf518a Upgrade Checker Framework Annotations 3.47.0 -> 3.48.1 (#1350)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.48.0
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.48.1
- https://github.com/typetools/checker-framework/compare/checker-framework-3.47.0...checker-framework-3.48.1
2024-10-13 15:55:12 +02:00
Picnic-DevPla-Bot
aa08d954a0 Upgrade Byte Buddy 1.15.1 -> 1.15.4 (#1340)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.15.2
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.15.3
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.15.4
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.15.1...byte-buddy-1.15.4
2024-10-13 15:43:21 +02:00
Picnic-DevPla-Bot
e4d1818ed0 Upgrade Error Prone 2.32.0 -> 2.33.0 (#1348)
See:
- https://github.com/google/error-prone/releases/tag/v2.33.0
- https://github.com/google/error-prone/compare/v2.32.0...v2.33.0
- https://github.com/PicnicSupermarket/error-prone/compare/v2.32.0-picnic-1...v2.33.0-picnic-2
2024-10-13 15:27:01 +02:00
Mohamed Sameh
beb96f0f4b Introduce CollectionIterator Refaster rule (#1347)
This rule supersedes the more specific `ImmutableCollectionIterator` rule.
2024-10-01 10:05:33 +02:00
Picnic-DevPla-Bot
4d1eeb2be1 Upgrade Checkstyle 10.18.1 -> 10.18.2 (#1346)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.18.2
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.18.1...checkstyle-10.18.2
2024-09-30 14:04:53 +02:00
Stephan Schroevers
9cbc6f875c Have LexicographicalAnnotationAttributeListing also sort booleans and chars (#1334) 2024-09-30 06:38:44 +02:00
Picnic-DevPla-Bot
5583630fb4 Upgrade JUnit 5 5.11.0 -> 5.11.1 (#1342)
See:
- https://junit.org/junit5/docs/current/release-notes/
- https://github.com/junit-team/junit5/releases/tag/r5.11.1
- https://github.com/junit-team/junit5/compare/r5.11.0...r5.11.1
2024-09-27 14:17:50 +02:00
Picnic-DevPla-Bot
91e841ce12 Upgrade maven-gpg-plugin 3.2.5 -> 3.2.6 (#1331)
See:
- https://github.com/apache/maven-gpg-plugin/releases/tag/maven-gpg-plugin-3.2.6
- https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.5...maven-gpg-plugin-3.2.6
2024-09-24 11:40:34 +02:00
Picnic-DevPla-Bot
3956a82cd5 Upgrade extra-enforcer-rules 1.8.0 -> 1.9.0 (#1335)
See:
- https://github.com/mojohaus/extra-enforcer-rules/releases/tag/1.9.0
- https://github.com/mojohaus/extra-enforcer-rules/compare/1.8.0...1.9.0
2024-09-23 10:26:57 +02:00
Picnic-DevPla-Bot
c57debdc25 Upgrade maven-site-plugin 3.12.1 -> 3.20.0 (#1296)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MSITE%20AND%20fixVersion%20%3E%203.12.1%20AND%20fixVersion%20%3C%3D%203.20.0
- https://github.com/apache/maven-site-plugin/releases/tag/maven-site-plugin-3.20.0
- https://github.com/apache/maven-site-plugin/compare/maven-site-plugin-3.12.1...maven-site-plugin-3.20.0
2024-09-23 09:46:35 +02:00
Picnic-DevPla-Bot
6a13efded8 Upgrade Spring Boot 3.3.3 -> 3.3.4 (#1333)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v3.3.4
- https://github.com/spring-projects/spring-boot/compare/v3.3.3...v3.3.4
2024-09-20 22:27:00 +02:00
Picnic-DevPla-Bot
432cf4560d Upgrade pitest-maven-plugin 1.16.1 -> 1.17.0 (#1313)
See:
- https://github.com/hcoles/pitest/releases/tag/1.16.2
- https://github.com/hcoles/pitest/releases/tag/1.16.3
- https://github.com/hcoles/pitest/releases/tag/1.17.0
- https://github.com/hcoles/pitest/compare/1.16.1...1.17.0
2024-09-19 13:03:04 +02:00
Picnic-DevPla-Bot
966fb36ac9 Upgrade Spring 6.1.12 -> 6.1.13 (#1328)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v6.1.13
- https://github.com/spring-projects/spring-framework/compare/v6.1.12...v6.1.13
2024-09-17 11:55:54 +02:00
Picnic-DevPla-Bot
c63d9350d2 Upgrade OpenRewrite Templating 1.14.1 -> 1.15.0 (#1327)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.15.0
- https://github.com/openrewrite/rewrite-templating/compare/v1.14.1...v1.15.0
2024-09-17 11:37:37 +02:00
Picnic-DevPla-Bot
e74874b04c Upgrade OpenRewrite 2.18.0 -> 2.19.0 (#1326)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.19.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.18.0...v2.19.0
2024-09-17 11:17:35 +02:00
Picnic-DevPla-Bot
f821d3775b Upgrade NullAway 0.11.2 -> 0.11.3 (#1332)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.11.3
- https://github.com/uber/NullAway/compare/v0.11.2...v0.11.3
2024-09-17 10:48:58 +02:00
Stephan Schroevers
3d5ee10d93 Introduce Refaster rules for Sonar's java:S4635 rule (#1320)
As well as two related expressions that can be optimized.

See:
- https://sonarcloud.io/organizations/picnic-technologies/rules?open=java%3AS4635&rule_key=java%3AS4635
- 2615792731/java-checks/src/main/java/org/sonar/java/checks/StringOffsetMethodsCheck.java
2024-09-16 09:15:12 +02:00
Stephan Schroevers
26da67d1f5 Use rewrite-java-17 rather than rewrite-java-11 (#1330) 2024-09-16 08:02:56 +02:00
Stephan Schroevers
b3ca01a6c7 Introduce RefasterRuleTestExtractor for documentation generation (#1317)
This new `Extractor` implementation collects Refaster example input and 
output code from rule collection tests.

This change also introduces explicit compilation steps for the test
code. As a side-effect this produces faster feedback in case of invalid
input or output code.
2024-09-14 12:02:37 +02:00
Picnic-DevPla-Bot
9f222e9efe Upgrade Error Prone 2.31.0 -> 2.32.0 (#1325)
See:
- https://github.com/google/error-prone/releases/tag/v2.32.0
- https://github.com/google/error-prone/compare/v2.31.0...v2.32.0
- https://github.com/PicnicSupermarket/error-prone/compare/v2.31.0-picnic-1...v2.32.0-picnic-1
2024-09-13 09:44:18 +02:00
Picnic-DevPla-Bot
097af51a3e Upgrade Project Reactor 2023.0.9 -> 2023.0.10 (#1323)
See:
- https://github.com/reactor/reactor/releases/tag/2023.0.10
- https://github.com/reactor/reactor/compare/2023.0.9...2023.0.10
2024-09-11 15:00:08 +02:00
Picnic-DevPla-Bot
c62e6c1127 Upgrade errorprone-slf4j 0.1.25 -> 0.1.28 (#1324)
See:
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.28
- https://github.com/KengoTODA/errorprone-slf4j/compare/v0.1.25...v0.1.28
2024-09-11 12:55:23 +02:00
Picnic-DevPla-Bot
5960423c4e Upgrade maven-dependency-plugin 3.7.1 -> 3.8.0 (#1304)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MDEP%20AND%20fixVersion%20%3E%203.7.1%20AND%20fixVersion%20%3C%3D%203.8.0
- https://github.com/apache/maven-dependency-plugin/releases/tag/maven-dependency-plugin-3.8.0
- https://github.com/apache/maven-dependency-plugin/compare/maven-dependency-plugin-3.7.1...maven-dependency-plugin-3.8.0
2024-09-11 09:42:34 +02:00
Picnic-DevPla-Bot
188715c3c0 Upgrade Checkstyle 10.18.0 -> 10.18.1 (#1318)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.18.1
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.18.0...checkstyle-10.18.1
2024-09-11 09:25:26 +02:00
Picnic-DevPla-Bot
fb45bb00ed Upgrade maven-javadoc-plugin 3.8.0 -> 3.10.0 (#1310)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MJAVADOC%20AND%20fixVersion%20%3E%203.8.0%20AND%20fixVersion%20%3C%3D%203.10.0
- https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.8.0...maven-javadoc-plugin-3.10.0
2024-09-10 19:55:17 +02:00
Picnic-DevPla-Bot
fd5fc913ce Upgrade maven-install-plugin 3.1.2 -> 3.1.3 (#1301)
See:
- https://github.com/apache/maven-install-plugin/releases/tag/maven-install-plugin-3.1.3
- https://github.com/apache/maven-install-plugin/compare/maven-install-plugin-3.1.2...maven-install-plugin-3.1.3
2024-09-10 19:44:45 +02:00
Picnic-DevPla-Bot
ae20c6069d Upgrade OpenRewrite 2.17.0 -> 2.18.0 (#1315)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.18.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.17.0...v2.18.0
2024-09-10 19:14:25 +02:00
Picnic-DevPla-Bot
8457bd5026 Upgrade MongoDB driver 5.1.3 -> 5.1.4 (#1321)
See:
- https://jira.mongodb.org/issues/?jql=project%20%3D%20JAVA%20AND%20fixVersion%20%3E%204.11.3%20AND%20fixVersion%20%3C%3D%204.11.4
- https://github.com/mongodb/mongo-java-driver/releases/tag/r5.1.4
- https://github.com/mongodb/mongo-java-driver/compare/r5.1.3...r5.1.4
2024-09-10 18:07:43 +02:00
Picnic-DevPla-Bot
fcfb97b0e0 Upgrade maven-deploy-plugin 3.1.2 -> 3.1.3 (#1300)
See:
- https://github.com/apache/maven-deploy-plugin/releases/tag/maven-deploy-plugin-3.1.3
- https://github.com/apache/maven-deploy-plugin/compare/maven-deploy-plugin-3.1.2...maven-deploy-plugin-3.1.3
2024-09-10 17:57:22 +02:00
Picnic-DevPla-Bot
15680b4cb3 Upgrade Surefire 3.3.1 -> 3.5.0 (#1298)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20SUREFIRE%20AND%20fixVersion%20%3E%203.3.1%20AND%20fixVersion%20%3C%3D%203.5.0
- https://github.com/apache/maven-surefire/releases/tag/surefire-3.4.0
- https://github.com/apache/maven-surefire/releases/tag/surefire-3.5.0
- https://github.com/apache/maven-surefire/compare/surefire-3.3.1...surefire-3.5.0
2024-09-10 17:05:51 +02:00
Picnic-DevPla-Bot
afebfbf478 Upgrade pomchecker-maven-plugin 1.11.0 -> 1.13.0 (#1319)
See:
- https://github.com/kordamp/pomchecker/releases/tag/v1.12.0
- https://github.com/kordamp/pomchecker/releases/tag/v1.13.0
- https://github.com/kordamp/pomchecker/compare/v1.11.0...v1.13.0
2024-09-10 13:32:08 +02:00
Picnic-DevPla-Bot
fe2ac938f3 Upgrade Checker Framework Annotations 3.46.0 -> 3.47.0 (#1322)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.47.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.46.0...checker-framework-3.47.0
2024-09-10 10:55:36 +02:00
Picnic-DevPla-Bot
078d8c16fa Upgrade OpenRewrite Templating 1.14.0 -> 1.14.1 (#1311)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.14.1
- https://github.com/openrewrite/rewrite-templating/compare/v1.14.0...v1.14.1
2024-09-04 15:01:36 +02:00
Stephan Schroevers
c679a3fc0c Improve Optional#orElse{,Get} support (#1283)
Summary of changes:
- Consolidate the `OptionalOrElseGet` Refaster rule and the 
  `OptionalOrElse` bug checker into the latter, keeping the best of
  both.
- Rename the `OptionalOrElse` bug checker to `OptionalOrElseGet` to
  avoid confusion.
- Replace the `IsLikelyTrivialComputation` matcher with the inverse
  `RequiresComputation` variant.
- Introduce an `OptionalOrElse` Refaster rule that simplifies
  expressions in the "opposite direction".
2024-09-03 16:00:33 +02:00
Stephan Schroevers
de54b4bf64 Introduce assorted unsigned int/long Refaster rules (#1291) 2024-09-03 15:35:15 +02:00
Picnic-DevPla-Bot
ea60241782 Upgrade Maven 3.9.8 -> 3.9.9 (#1295)
See:
- https://maven.apache.org/release-notes-all.html
- https://github.com/apache/maven/compare/maven-3.9.8...maven-3.9.9
2024-09-03 15:26:41 +02:00
Picnic-Bot
e4f928addb Upgrade fmt-maven-plugin 2.22.1 -> 2.24 (#1069)
See:
- https://github.com/spotify/fmt-maven-plugin/releases/tag/2.23
- https://github.com/spotify/fmt-maven-plugin/releases/tag/2.24
- https://github.com/spotify/fmt-maven-plugin/compare/2.22.1...2.24
2024-09-03 13:13:18 +02:00
Picnic-DevPla-Bot
059cc9e2db Upgrade Error Prone 2.30.0 -> 2.31.0 (#1314)
See:
- https://github.com/google/error-prone/releases/tag/v2.31.0
- https://github.com/google/error-prone/compare/v2.30.0...v2.31.0
2024-09-03 12:19:04 +02:00
Picnic-DevPla-Bot
1e43c28c95 Upgrade Byte Buddy 1.15.0 -> 1.15.1 (#1316)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.15.1
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.15.0...byte-buddy-1.15.1
2024-09-02 21:10:41 +02:00
Picnic-DevPla-Bot
a07e9b3115 Upgrade Swagger 2.2.22 -> 2.2.23 (#1312)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.23
- https://github.com/swagger-api/swagger-core/compare/v2.2.22...v2.2.23
2024-08-29 09:23:09 +02:00
Picnic-DevPla-Bot
aec38d2e33 Upgrade Mockito 5.12.0 -> 5.13.0 (#1309)
See:
- https://github.com/mockito/mockito/releases/tag/v5.13.0
- https://github.com/mockito/mockito/compare/v5.12.0...v5.13.0
2024-08-28 09:32:16 +02:00
Picnic-DevPla-Bot
5b77663288 Upgrade Spring 6.1.11 -> 6.1.12 (#1288)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v6.1.12
- https://github.com/spring-projects/spring-framework/compare/v6.1.11...v6.1.12
2024-08-27 15:48:14 +02:00
Stephan Schroevers
97c2bbd4b1 Introduce MonoFromFutureAsyncLoadingCacheGet Refaster rule (#1290) 2024-08-26 16:33:57 +02:00
Picnic-DevPla-Bot
9c8fbfd36a Upgrade OpenRewrite Templating 1.13.0 -> 1.14.0 (#1294)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.14.0
- https://github.com/openrewrite/rewrite-templating/compare/v1.13.0...v1.14.0
2024-08-26 13:42:53 +02:00
Picnic-DevPla-Bot
38e6c3fdb5 Upgrade OpenRewrite 2.16.0 -> 2.17.0 (#1286)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.17.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.16.0...v2.17.0
2024-08-26 13:24:42 +02:00
Picnic-DevPla-Bot
5b1d82cfeb Upgrade Guava 33.2.1-jre -> 33.3.0-jre (#1293)
And drop some Refaster rules now covered by `@InlineMe` instructions.

See:
- https://guava.dev/releases/33.3.0-jre/api/diffs/
- https://github.com/google/guava/releases/tag/v33.3.0
- https://github.com/google/guava/compare/v33.2.0...v33.3.0
2024-08-26 13:02:15 +02:00
Picnic-DevPla-Bot
0821a95fcc Upgrade Spring Security 6.3.1 -> 6.3.3 (#1303)
See:
- https://github.com/spring-projects/spring-security/releases/tag/6.3.2
- https://github.com/spring-projects/spring-security/releases/tag/6.3.3
- https://github.com/spring-projects/spring-security/compare/6.3.1...6.3.3
2024-08-26 12:50:25 +02:00
Picnic-DevPla-Bot
f4afe457cb Upgrade Checkstyle 10.17.0 -> 10.18.0 (#1308)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.18.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.17.0...checkstyle-10.18.0
2024-08-26 09:19:52 +02:00
Picnic-DevPla-Bot
fd56ca8b6e Upgrade Spring Boot 3.3.2 -> 3.3.3 (#1305)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v3.3.3
- https://github.com/spring-projects/spring-boot/compare/v3.3.2...v3.3.3
2024-08-26 09:04:43 +02:00
Picnic-DevPla-Bot
882794d63b Upgrade maven-checkstyle-plugin 3.4.0 -> 3.5.0 (#1307)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MCHECKSTYLE%20AND%20fixVersion%20%3E%203.4.0%20AND%20fixVersion%20%3C%3D%203.5.0
- https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.4.0...maven-checkstyle-plugin-3.5.0
2024-08-26 08:22:34 +02:00
Mohamed Sameh
73ed6e32c7 Introduce Collections{Max,Min,Sort} Refaster rules (#1297)
While there, rename `{Max,Min}OfCollection` to
`Collections{Max,Min}WithComparator`.
2024-08-26 07:38:26 +02:00
Picnic-DevPla-Bot
ca5c3dd3b4 Upgrade Byte Buddy 1.14.19 -> 1.15.0 (#1306)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.15.0
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.19...byte-buddy-1.15.0
2024-08-26 07:28:00 +02:00
Picnic-DevPla-Bot
f6e9dbb996 Upgrade Byte Buddy 1.14.18 -> 1.14.19 (#1292)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.19
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.18...byte-buddy-1.14.19
2024-08-23 19:39:59 +02:00
Picnic-DevPla-Bot
260021c961 Upgrade NullAway 0.11.1 -> 0.11.2 (#1299)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.11.2
- https://github.com/uber/NullAway/compare/v0.11.1...v0.11.2
2024-08-23 19:31:03 +02:00
Stephan Schroevers
ec54e79f3e Introduce {Max,Min}Of{Array,Collection} Refaster rules (#1276)
While there, generalize the `{Max,Min}OfVarargs` rules.
2024-08-23 08:47:35 +02:00
Stephan Schroevers
4cbfdba521 Introduce additional File and Path Refaster rules (#1282) 2024-08-22 09:58:09 +02:00
Picnic-DevPla-Bot
d94f65a1f0 Upgrade JUnit 5 5.10.3 -> 5.11.0 (#1289)
See:
- https://junit.org/junit5/docs/current/release-notes/
- https://github.com/junit-team/junit5/releases/tag/r5.11.0-M1
- https://github.com/junit-team/junit5/releases/tag/r5.11.0-M2
- https://github.com/junit-team/junit5/releases/tag/r5.11.0-RC1
- https://github.com/junit-team/junit5/releases/tag/r5.11.0
- https://github.com/junit-team/junit5/compare/r5.10.3...r5.11.0
2024-08-15 09:21:45 +02:00
Picnic-DevPla-Bot
9afdf2ddf3 Upgrade OpenRewrite Templating 1.12.3 -> 1.13.0 (#1287)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.13.0
- https://github.com/openrewrite/rewrite-templating/compare/v1.12.3...v1.13.0
2024-08-14 11:35:36 +02:00
Picnic-DevPla-Bot
060c901479 Upgrade maven-gpg-plugin 3.2.4 -> 3.2.5 (#1284)
See:
- https://github.com/apache/maven-gpg-plugin/releases/tag/maven-gpg-plugin-3.2.5
- https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.4...maven-gpg-plugin-3.2.5
2024-08-14 08:56:02 +02:00
Picnic-DevPla-Bot
1feee4f64a Upgrade Project Reactor 2023.0.8 -> 2023.0.9 (#1285)
See:
- https://github.com/reactor/reactor/releases/tag/2023.0.9
- https://github.com/reactor/reactor/compare/2023.0.8...2023.0.9
2024-08-14 08:26:16 +02:00
Picnic-Bot
552ddf6a7d Upgrade Maven API 3.9.5 -> 3.9.8 (#701)
See:
- https://maven.apache.org/release-notes-all.html
- https://github.com/apache/maven/releases/tag/maven-3.9.6
- https://github.com/apache/maven/releases/tag/maven-3.9.7
- https://github.com/apache/maven/releases/tag/maven-3.9.8
- https://github.com/apache/maven/compare/maven-3.9.5...maven-3.9.8
2024-08-12 16:14:46 +02:00
Stephan Schroevers
5d92c6c6ce Update Error Prone compatibility matrix (#1281) 2024-08-12 08:28:56 +02:00
Stephan Schroevers
fa8ca80040 [maven-release-plugin] prepare for next development iteration 2024-08-11 15:05:54 +02:00
Stephan Schroevers
b733179cd0 [maven-release-plugin] prepare release v0.18.0 2024-08-11 15:05:54 +02:00
Mohamed Sameh
3d9aab7c5b Introduce Class{Literal,Reference}Cast Refaster rules (#1269) 2024-08-11 15:01:53 +02:00
Picnic-DevPla-Bot
366cdda3d8 Upgrade Error Prone 2.29.2 -> 2.30.0 (#1280)
See:
- https://github.com/google/error-prone/releases/tag/v2.30.0
- https://github.com/google/error-prone/compare/v2.29.2...v2.30.0
- https://github.com/PicnicSupermarket/error-prone/compare/v2.29.2-picnic-1...v2.30.0-picnic-1
2024-08-11 12:48:15 +02:00
Picnic-DevPla-Bot
5b6dd147ef Upgrade MongoDB driver 5.1.2 -> 5.1.3 (#1274)
See:
- https://jira.mongodb.org/issues/?jql=project%20%3D%20JAVA%20AND%20fixVersion%20%3E%204.11.2%20AND%20fixVersion%20%3C%3D%204.11.3
- https://github.com/mongodb/mongo-java-driver/releases/tag/r4.11.3
- https://github.com/mongodb/mongo-java-driver/compare/r4.11.2...r4.11.3
2024-08-11 12:23:58 +02:00
Picnic-DevPla-Bot
a868b03130 Upgrade SLF4J 2.0.15 -> 2.0.16 (#1279)
See:
- https://www.slf4j.org/news.html
- https://github.com/qos-ch/slf4j/compare/v_2.0.15...v_2.0.16
2024-08-11 12:11:31 +02:00
Stephan Schroevers
fdf9bb5d25 Make the build JDK 22-compatible (#1277)
And verify the build with JDK 22.0.2.
2024-08-10 23:13:23 +02:00
Mohamed Sameh
363b0c22c7 Introduce ArraysAsList Refaster rule (#1275) 2024-08-10 16:49:44 +02:00
Picnic-DevPla-Bot
32ec35a354 Upgrade SLF4J 2.0.13 -> 2.0.15 (#1272)
See:
- https://www.slf4j.org/news.html
- https://github.com/qos-ch/slf4j/compare/v_2.0.13...v_2.0.15
2024-08-09 14:37:40 +02:00
Picnic-DevPla-Bot
635fe280f8 Upgrade OpenRewrite Templating 1.12.1 -> 1.12.3 (#1273)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.12.2
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.12.3
- https://github.com/openrewrite/rewrite-templating/compare/v1.12.1...v1.12.3
2024-08-09 09:49:34 +02:00
Stephan Schroevers
aac9b6bf10 Package OpenRewrite recipes in separate JAR, targeting Java 8 (#1270)
This is a prerequisite for openrewrite/rewrite-third-party#11. The new JAR has
classifier `recipes`.
2024-08-07 23:21:35 +02:00
Rick Ossendrijver
c322ea1bbc Introduce generic run-integration-test.sh script (#1141)
This new script contains reusable logic extracted from
`integration-tests/checkstyle.sh`, facilitating the introduction of additional
integration tests.
2024-08-07 23:12:55 +02:00
Stephan Schroevers
a433a90673 Introduce FilesCreateTempFileToFile Refaster rule (#1162) 2024-08-07 15:41:45 +02:00
Picnic-DevPla-Bot
5a37d65632 Upgrade Checker Framework Annotations 3.45.0 -> 3.46.0 (#1268)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.46.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.45.0...checker-framework-3.46.0
2024-08-07 11:46:32 +02:00
Rick Ossendrijver
77d183f8fd Introduce FluxFromStreamSupplier Refaster rule (#1261) 2024-08-07 10:44:41 +02:00
Picnic-DevPla-Bot
2eb4e853c5 Upgrade OpenRewrite Templating 1.12.0 -> 1.12.1 (#1265)
See:
- https://github.com/openrewrite/rewrite-templating/releases/tag/v1.12.1
- https://github.com/openrewrite/rewrite-templating/compare/v1.12.0...v1.12.1
2024-08-06 16:34:53 +02:00
Picnic-DevPla-Bot
45a7242cf5 Upgrade OpenRewrite 2.15.0 -> 2.16.0 (#1266)
See:
- https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v2.16.0
- https://github.com/openrewrite/rewrite-recipe-bom/compare/v2.15.0...v2.16.0
2024-08-06 16:17:43 +02:00
Picnic-DevPla-Bot
c85070ba23 Upgrade org.hamcrest:hamcrest-core 2.2 -> 3.0 (#1267)
See:
- https://github.com/hamcrest/JavaHamcrest/releases/tag/v3.0-rc1
- https://github.com/hamcrest/JavaHamcrest/releases/tag/v3.0
- https://github.com/hamcrest/JavaHamcrest/compare/v2.2...v3.0
2024-08-06 14:34:47 +02:00
Mohamed Sameh
a687f09bf0 Introduce SetStream Refaster rule (#1264) 2024-08-06 14:05:53 +02:00
Picnic-DevPla-Bot
2e4fdcb0db Upgrade maven-javadoc-plugin 3.7.0 -> 3.8.0 (#1259)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MJAVADOC%20AND%20fixVersion%20%3E%203.7.0%20AND%20fixVersion%20%3C%3D%203.8.0
- https://github.com/apache/maven-javadoc-plugin/releases/tag/maven-javadoc-plugin-3.8.0
- https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.7.0...maven-javadoc-plugin-3.8.0
2024-08-06 08:53:06 +02:00
Stephan Schroevers
1005d93b7e Update step-security/harden-runner configuration (#1271)
While apparently the build doesn't fail without this, it is reasonable
for SonarCloud analysis to access the two additional domains.

While there, introduce subdomain wildcards for `sigstore.dev` and
`sonarcloud.io`.
2024-08-05 09:31:25 +02:00
Picnic-DevPla-Bot
136123f6b4 Upgrade NullAway 0.11.0 -> 0.11.1 (#1262)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.11.1
- https://github.com/uber/NullAway/compare/v0.11.0...v0.11.1
2024-08-05 09:03:14 +02:00
Picnic-DevPla-Bot
4cb5f0079d Upgrade Google Java Format 1.22.0 -> 1.23.0 (#1263)
See:
- https://github.com/google/google-java-format/releases/tag/v1.23.0
- https://github.com/google/google-java-format/compare/v1.22.0...v1.23.0
2024-08-05 08:15:16 +02:00
Stephan Schroevers
290ddf1972 [maven-release-plugin] prepare for next development iteration 2024-07-20 14:15:44 +02:00
155 changed files with 37240 additions and 7514 deletions

View File

@@ -42,9 +42,9 @@ Please replace this sentence with log output, if applicable.
<!-- Please complete the following information: -->
- Operating system (e.g. MacOS Monterey).
- Java version (i.e. `java --version`, e.g. `17.0.10`).
- Error Prone version (e.g. `2.25.0`).
- Error Prone Support version (e.g. `0.15.0`).
- Java version (i.e. `java --version`, e.g. `17.0.13`).
- Error Prone version (e.g. `2.35.1`).
- Error Prone Support version (e.g. `0.19.0`).
### Additional context

View File

@@ -9,24 +9,24 @@ jobs:
build:
strategy:
matrix:
os: [ ubuntu-22.04 ]
jdk: [ 17.0.10, 21.0.2 ]
os: [ ubuntu-24.04 ]
jdk: [ 17.0.13, 21.0.5, 23.0.1 ]
distribution: [ temurin ]
experimental: [ false ]
include:
- os: macos-14
jdk: 17.0.10
jdk: 17.0.13
distribution: temurin
experimental: false
- os: windows-2022
jdk: 17.0.10
jdk: 17.0.13
distribution: temurin
experimental: false
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental }}
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
disable-sudo: true
egress-policy: block
@@ -42,11 +42,11 @@ jobs:
# additionally enabling all checks defined in this project and any Error
# Prone checks available only from other artifact repositories.
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
with:
java-version: ${{ matrix.jdk }}
java-distribution: ${{ matrix.distribution }}
maven-version: 3.9.6
maven-version: 3.9.9
- name: Display build environment details
run: mvn --version
- name: Build project against vanilla Error Prone, compile Javadoc
@@ -54,6 +54,6 @@ jobs:
- name: Build project with self-check against Error Prone fork
run: mvn -T1C clean verify -Perror-prone-fork -Pnon-maven-central -Pself-check -s settings.xml
- name: Remove installed project artifacts
run: mvn build-helper:remove-project-artifact
run: mvn dependency:purge-local-repository -DmanualInclude='${project.groupId}' -DresolutionFuzziness=groupId
# XXX: Enable Codecov once we "go public".

View File

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

View File

@@ -9,10 +9,10 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
build:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
disable-sudo: true
egress-policy: block
@@ -39,10 +39,10 @@ jobs:
www.youtube.com:443
youtrack.jetbrains.com:443
- name: Check out code
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.0
- uses: ruby/setup-ruby@a2bbe5b1b236842c1cb7dd11e8e3b51e0a616acc # v1.202.0
with:
working-directory: ./website
bundler-cache: true
@@ -68,13 +68,13 @@ jobs:
permissions:
id-token: write
pages: write
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
disable-sudo: true
egress-policy: block

View File

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

View File

@@ -9,10 +9,10 @@ permissions:
contents: read
jobs:
analyze-pr:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
disable-sudo: true
egress-policy: block
@@ -22,12 +22,12 @@ jobs:
objects.githubusercontent.com:443
repo.maven.apache.org:443
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
with:
checkout-fetch-depth: 2
java-version: 17.0.10
java-version: 17.0.13
java-distribution: temurin
maven-version: 3.9.6
maven-version: 3.9.9
- name: Run Pitest
# By running with features `+GIT(from[HEAD~1]), +gitci`, Pitest only
# analyzes lines changed in the associated pull request, as GitHub
@@ -38,7 +38,7 @@ jobs:
- name: Aggregate Pitest reports
run: mvn pitest-git:aggregate -DkilledEmoji=":tada:" -DmutantEmoji=":zombie:" -DtrailingText="Mutation testing report by [Pitest](https://pitest.org/). Review any surviving mutants by inspecting the line comments under [_Files changed_](${{ github.event.number }}/files)."
- name: Upload Pitest reports as artifact
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: pitest-reports
path: ./target/pit-reports-ci

View File

@@ -17,10 +17,10 @@ jobs:
checks: write
contents: read
pull-requests: write
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
disable-sudo: true
egress-policy: block
@@ -31,11 +31,11 @@ jobs:
objects.githubusercontent.com:443
repo.maven.apache.org:443
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
with:
java-version: 17.0.10
java-version: 17.0.13
java-distribution: temurin
maven-version: 3.9.6
maven-version: 3.9.9
- name: Download Pitest analysis artifact
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
with:

View File

@@ -1,9 +1,9 @@
# If requested by means of a pull request comment, runs integration tests
# against the project, using the code found on the pull request branch.
# XXX: Generalize this to a matrix build of multiple integration tests,
# possibly using multiple JDK or OS versions.
# XXX: Investigate whether the comment can specify which integration tests run
# run. See this example of a dynamic build matrix:
# XXX: Review whether then build matrix should also vary JDK or OS versions.
# XXX: Support `/integration-test [name...]` comment syntax to specify the
# subset of integration tests to run.
# See this example of a dynamic build matrix:
# https://docs.github.com/en/actions/learn-github-actions/expressions#example-returning-a-json-object
name: "Integration tests"
on:
@@ -16,38 +16,48 @@ jobs:
name: On-demand integration test
if: |
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:
- name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
disable-sudo: true
egress-policy: block
allowed-endpoints: >
# XXX: After updating the validation build flags in
# `integration-tests/prometheus-java-client.sh`, review whether the
# Docker domains specified here can be dropped.
api.adoptium.net:443
auth.docker.io:443
checkstyle.org:443
example.com:80
github.com:443
objects.githubusercontent.com:443
oss.sonatype.org:443
production.cloudflare.docker.com:443
raw.githubusercontent.com:443
registry-1.docker.io:443
repo.maven.apache.org:443
repository.sonatype.org:443
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
with:
checkout-ref: "refs/pull/${{ github.event.issue.number }}/head"
java-version: 17.0.10
java-version: 17.0.13
java-distribution: temurin
maven-version: 3.9.6
maven-version: 3.9.9
- name: Install project to local Maven repository
run: mvn -T1C install -DskipTests -Dverification.skip
- name: Run integration test
run: xvfb-run ./integration-tests/checkstyle.sh "${{ runner.temp }}/artifacts"
run: xvfb-run "./integration-tests/${{ matrix.integration-test }}.sh" "${{ runner.temp }}/artifacts"
- name: Upload artifacts on failure
if: ${{ failure() }}
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: integration-test-checkstyle
name: "integration-test-${{ matrix.integration-test }}"
path: "${{ runner.temp }}/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,30 +16,31 @@ jobs:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
permissions:
contents: read
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
disable-sudo: true
egress-policy: block
allowed-endpoints: >
analysis-sensorcache-eu-central-1-prod.s3.amazonaws.com:443
api.adoptium.net:443
api.sonarcloud.io:443
api.nuget.org:443
ea6ne4j2sb.execute-api.eu-central-1.amazonaws.com:443
github.com:443
objects.githubusercontent.com:443
repo.maven.apache.org:443
sc-cleancode-sensorcache-eu-central-1-prod.s3.amazonaws.com:443
scanner.sonarcloud.io:443
*.sonarcloud.io:443
sonarcloud.io:443
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
with:
checkout-fetch-depth: 0
java-version: 17.0.10
java-version: 17.0.13
java-distribution: temurin
maven-version: 3.9.6
maven-version: 3.9.9
- name: Create missing `test` directory
# XXX: Drop this step in favour of actually having a test.
run: mkdir refaster-compiler/src/test

View File

@@ -4,6 +4,7 @@
--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED

View File

@@ -3,11 +3,24 @@
"extends": [
"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": [
{
"matchPackagePatterns": [
"^org\\.springframework:spring-framework-bom$",
"^org\\.springframework\\.boot:spring-boot[a-z-]*$"
"matchPackageNames": [
"/^org\\.springframework:spring-framework-bom$/",
"/^org\\.springframework\\.boot:spring-boot[a-z-]*$/"
],
"separateMinorPatch": true
},

View File

@@ -217,7 +217,7 @@ Other highly relevant commands:
- `mvn fmt:format` formats the code using
[`google-java-format`][google-java-format].
- [`./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
defined within this project. (Consider running this before [opening a pull
request][contributing-pull-request], as the PR checks also perform this
@@ -302,7 +302,7 @@ channel; please see our [security policy][security] for details.
[refaster]: https://errorprone.info/docs/refaster
[refaster-rules-bigdecimal]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/BigDecimalRules.java
[refaster-rules]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/
[reproducible-builds-badge]: https://img.shields.io/badge/Reproducible_Builds-ok-success?labelColor=1e5b96
[reproducible-builds-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/jvm-repo-rebuild/reproducible-central/master/content/tech/picnic/error-prone-support/error-prone-support/badge.json
[reproducible-builds-report]: https://github.com/jvm-repo-rebuild/reproducible-central/blob/master/content/tech/picnic/error-prone-support/error-prone-support/README.md
[script-apply-error-prone-suggestions]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/apply-error-prone-suggestions.sh
[script-run-branch-mutation-tests]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-branch-mutation-tests.sh

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.17.0</version>
<version>0.19.2-SNAPSHOT</version>
</parent>
<artifactId>documentation-support</artifactId>
@@ -33,6 +33,15 @@
<artifactId>error_prone_test_helpers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>error-prone-utils</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>refaster-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>

View File

@@ -27,7 +27,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.TestCases;
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.BugPatternTestCases;
/**
* An {@link Extractor} that describes how to extract data from classes that test a {@code
@@ -40,7 +40,7 @@ import tech.picnic.errorprone.documentation.BugPatternTestExtractor.TestCases;
@Immutable
@AutoService(Extractor.class)
@SuppressWarnings("rawtypes" /* See https://github.com/google/auto/issues/870. */)
public final class BugPatternTestExtractor implements Extractor<TestCases> {
public final class BugPatternTestExtractor implements Extractor<BugPatternTestCases> {
/** Instantiates a new {@link BugPatternTestExtractor} instance. */
public BugPatternTestExtractor() {}
@@ -50,7 +50,7 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
}
@Override
public Optional<TestCases> tryExtract(ClassTree tree, VisitorState state) {
public Optional<BugPatternTestCases> tryExtract(ClassTree tree, VisitorState state) {
BugPatternTestCollector collector = new BugPatternTestCollector();
collector.scan(tree, state);
@@ -59,7 +59,7 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
.filter(not(ImmutableList::isEmpty))
.map(
tests ->
new AutoValue_BugPatternTestExtractor_TestCases(
new AutoValue_BugPatternTestExtractor_BugPatternTestCases(
state.getPath().getCompilationUnit().getSourceFile().toUri(),
ASTHelpers.getSymbol(tree).className(),
tests));
@@ -95,10 +95,10 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
.onDescendantOf("com.google.errorprone.BugCheckerRefactoringTestHelper.ExpectOutput")
.namedAnyOf("addOutputLines", "expectUnchanged");
private final List<TestCase> collectedTestCases = new ArrayList<>();
private final List<BugPatternTestCase> collectedBugPatternTestCases = new ArrayList<>();
private ImmutableList<TestCase> getCollectedTests() {
return ImmutableList.copyOf(collectedTestCases);
private ImmutableList<BugPatternTestCase> getCollectedTests() {
return ImmutableList.copyOf(collectedBugPatternTestCases);
}
@Override
@@ -110,14 +110,14 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
classUnderTest -> {
List<TestEntry> entries = new ArrayList<>();
if (isReplacementTest) {
extractReplacementTestCases(node, entries, state);
extractReplacementBugPatternTestCases(node, entries, state);
} else {
extractIdentificationTestCases(node, entries, state);
extractIdentificationBugPatternTestCases(node, entries, state);
}
if (!entries.isEmpty()) {
collectedTestCases.add(
new AutoValue_BugPatternTestExtractor_TestCase(
collectedBugPatternTestCases.add(
new AutoValue_BugPatternTestExtractor_BugPatternTestCase(
classUnderTest, ImmutableList.copyOf(entries).reverse()));
}
});
@@ -140,7 +140,7 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
: Optional.empty();
}
private static void extractIdentificationTestCases(
private static void extractIdentificationBugPatternTestCases(
MethodInvocationTree tree, List<TestEntry> sink, VisitorState state) {
if (IDENTIFICATION_SOURCE_LINES.matches(tree, state)) {
String path = ASTHelpers.constValue(tree.getArguments().get(0), String.class);
@@ -155,11 +155,11 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
if (receiver instanceof MethodInvocationTree methodInvocation) {
extractIdentificationTestCases(methodInvocation, sink, state);
extractIdentificationBugPatternTestCases(methodInvocation, sink, state);
}
}
private static void extractReplacementTestCases(
private static void extractReplacementBugPatternTestCases(
MethodInvocationTree tree, List<TestEntry> sink, VisitorState state) {
if (REPLACEMENT_OUTPUT_SOURCE_LINES.matches(tree, state)) {
/*
@@ -185,7 +185,7 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
if (receiver instanceof MethodInvocationTree methodInvocation) {
extractReplacementTestCases(methodInvocation, sink, state);
extractReplacementBugPatternTestCases(methodInvocation, sink, state);
}
}
@@ -208,24 +208,26 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
}
@AutoValue
@JsonDeserialize(as = AutoValue_BugPatternTestExtractor_TestCases.class)
abstract static class TestCases {
static TestCases create(URI source, String testClass, ImmutableList<TestCase> testCases) {
return new AutoValue_BugPatternTestExtractor_TestCases(source, testClass, testCases);
@JsonDeserialize(as = AutoValue_BugPatternTestExtractor_BugPatternTestCases.class)
abstract static class BugPatternTestCases {
static BugPatternTestCases create(
URI source, String testClass, ImmutableList<BugPatternTestCase> testCases) {
return new AutoValue_BugPatternTestExtractor_BugPatternTestCases(
source, testClass, testCases);
}
abstract URI source();
abstract String testClass();
abstract ImmutableList<TestCase> testCases();
abstract ImmutableList<BugPatternTestCase> testCases();
}
@AutoValue
@JsonDeserialize(as = AutoValue_BugPatternTestExtractor_TestCase.class)
abstract static class TestCase {
static TestCase create(String classUnderTest, ImmutableList<TestEntry> entries) {
return new AutoValue_BugPatternTestExtractor_TestCase(classUnderTest, entries);
@JsonDeserialize(as = AutoValue_BugPatternTestExtractor_BugPatternTestCase.class)
abstract static class BugPatternTestCase {
static BugPatternTestCase create(String classUnderTest, ImmutableList<TestEntry> entries) {
return new AutoValue_BugPatternTestExtractor_BugPatternTestCase(classUnderTest, entries);
}
abstract String classUnderTest();

View File

@@ -14,7 +14,6 @@ import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ServiceLoader;
import javax.tools.JavaFileObject;
@@ -87,6 +86,6 @@ final class DocumentationGeneratorTaskListener implements TaskListener {
}
private static String getSimpleClassName(URI path) {
return Paths.get(path).getFileName().toString().replace(".java", "");
return Path.of(path).getFileName().toString().replace(".java", "");
}
}

View File

@@ -0,0 +1,176 @@
package tech.picnic.errorprone.documentation;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
import static java.util.stream.Collectors.joining;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.google.auto.service.AutoService;
import com.google.auto.value.AutoValue;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.VisitorState;
import com.google.errorprone.annotations.FormatMethod;
import com.google.errorprone.annotations.Immutable;
import com.google.errorprone.matchers.Matcher;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import java.net.URI;
import java.util.Optional;
import java.util.regex.Pattern;
import tech.picnic.errorprone.documentation.RefasterRuleCollectionTestExtractor.RefasterTestCases;
import tech.picnic.errorprone.utils.SourceCode;
/**
* An {@link Extractor} that describes how to extract data from Refaster rule input and output test
* classes.
*/
// XXX: Drop this extractor if/when the Refaster test framework is reimplemented such that tests can
// be located alongside rules, rather than in two additional resource files as currently required by
// `RefasterRuleCollection`.
@Immutable
@AutoService(Extractor.class)
@SuppressWarnings("rawtypes" /* See https://github.com/google/auto/issues/870. */)
public final class RefasterRuleCollectionTestExtractor implements Extractor<RefasterTestCases> {
private static final Matcher<ClassTree> IS_REFASTER_RULE_COLLECTION_TEST_CASE =
isSubtypeOf("tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase");
private static final Pattern TEST_CLASS_NAME_PATTERN = Pattern.compile("(.*)Test");
private static final Pattern TEST_CLASS_FILE_NAME_PATTERN =
Pattern.compile(".*(Input|Output)\\.java");
private static final Pattern TEST_METHOD_NAME_PATTERN = Pattern.compile("test(.*)");
private static final String LINE_SEPARATOR = "\n";
private static final Splitter LINE_SPLITTER = Splitter.on(LINE_SEPARATOR);
/** Instantiates a new {@link RefasterRuleCollectionTestExtractor} instance. */
public RefasterRuleCollectionTestExtractor() {}
@Override
public String identifier() {
return "refaster-rule-collection-test";
}
@Override
public Optional<RefasterTestCases> tryExtract(ClassTree tree, VisitorState state) {
if (!IS_REFASTER_RULE_COLLECTION_TEST_CASE.matches(tree, state)) {
return Optional.empty();
}
URI sourceFile = state.getPath().getCompilationUnit().getSourceFile().toUri();
return Optional.of(
RefasterTestCases.create(
sourceFile,
getRuleCollectionName(tree),
isInputFile(sourceFile),
getRefasterTestCases(tree, state)));
}
private static String getRuleCollectionName(ClassTree tree) {
String className = tree.getSimpleName().toString();
// XXX: Instead of throwing an error here, it'd be nicer to have a bug checker validate key
// aspects of `RefasterRuleCollectionTestCase` subtypes.
return tryExtractPatternGroup(className, TEST_CLASS_NAME_PATTERN)
.orElseThrow(
violation(
"Refaster rule collection test class name '%s' does not match '%s'",
className, TEST_CLASS_NAME_PATTERN));
}
private static boolean isInputFile(URI sourceFile) {
String path = sourceFile.getPath();
// XXX: Instead of throwing an error here, it'd be nicer to have a bug checker validate key
// aspects of `RefasterRuleCollectionTestCase` subtypes.
return "Input"
.equals(
tryExtractPatternGroup(path, TEST_CLASS_FILE_NAME_PATTERN)
.orElseThrow(
violation(
"Refaster rule collection test file name '%s' does not match '%s'",
path, TEST_CLASS_FILE_NAME_PATTERN)));
}
private static ImmutableList<RefasterTestCase> getRefasterTestCases(
ClassTree tree, VisitorState state) {
return tree.getMembers().stream()
.filter(MethodTree.class::isInstance)
.map(MethodTree.class::cast)
.flatMap(m -> tryExtractRefasterTestCase(m, state).stream())
.collect(toImmutableList());
}
private static Optional<RefasterTestCase> tryExtractRefasterTestCase(
MethodTree method, VisitorState state) {
return tryExtractPatternGroup(method.getName().toString(), TEST_METHOD_NAME_PATTERN)
.map(name -> RefasterTestCase.create(name, getFormattedSource(method, state)));
}
/**
* Returns the source code for the specified method.
*
* @implNote This operation attempts to trim leading whitespace, such that the start and end of
* the method declaration are aligned. The implemented heuristic assumes that the code is
* formatted using Google Java Format.
*/
// XXX: Leading Javadoc and other comments are currently not extracted. Consider fixing this.
private static String getFormattedSource(MethodTree method, VisitorState state) {
String source = SourceCode.treeToString(method, state);
int finalNewline = source.lastIndexOf(LINE_SEPARATOR);
if (finalNewline < 0) {
return source;
}
int indentation = Math.max(0, source.lastIndexOf(' ') - finalNewline);
String prefixToStrip = " ".repeat(indentation);
return LINE_SPLITTER
.splitToStream(source)
.map(line -> line.startsWith(prefixToStrip) ? line.substring(indentation) : line)
.collect(joining(LINE_SEPARATOR));
}
private static Optional<String> tryExtractPatternGroup(String input, Pattern pattern) {
java.util.regex.Matcher matcher = pattern.matcher(input);
return matcher.matches() ? Optional.of(matcher.group(1)) : Optional.empty();
}
@FormatMethod
private static Supplier<VerifyException> violation(String format, Object... args) {
return () -> new VerifyException(String.format(format, args));
}
@AutoValue
@JsonDeserialize(as = AutoValue_RefasterRuleCollectionTestExtractor_RefasterTestCases.class)
abstract static class RefasterTestCases {
static RefasterTestCases create(
URI source,
String ruleCollection,
boolean isInput,
ImmutableList<RefasterTestCase> testCases) {
return new AutoValue_RefasterRuleCollectionTestExtractor_RefasterTestCases(
source, ruleCollection, isInput, testCases);
}
abstract URI source();
abstract String ruleCollection();
abstract boolean isInput();
abstract ImmutableList<RefasterTestCase> testCases();
}
@AutoValue
@JsonDeserialize(as = AutoValue_RefasterRuleCollectionTestExtractor_RefasterTestCase.class)
abstract static class RefasterTestCase {
static RefasterTestCase create(String name, String content) {
return new AutoValue_RefasterRuleCollectionTestExtractor_RefasterTestCase(name, content);
}
abstract String name();
abstract String content();
}
}

View File

@@ -7,10 +7,10 @@ import java.net.URI;
import java.nio.file.Path;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.BugPatternTestCase;
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.BugPatternTestCases;
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.IdentificationTestEntry;
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.ReplacementTestEntry;
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.TestCase;
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.TestCases;
final class BugPatternTestExtractorTest {
@Test
@@ -269,11 +269,11 @@ final class BugPatternTestExtractorTest {
verifyGeneratedFileContent(
outputDirectory,
"SingleFileCompilationTestHelperTest",
TestCases.create(
BugPatternTestCases.create(
URI.create("file:///SingleFileCompilationTestHelperTest.java"),
"SingleFileCompilationTestHelperTest",
ImmutableList.of(
TestCase.create(
BugPatternTestCase.create(
"SingleFileCompilationTestHelperTest.TestChecker",
ImmutableList.of(
IdentificationTestEntry.create(
@@ -302,11 +302,11 @@ final class BugPatternTestExtractorTest {
verifyGeneratedFileContent(
outputDirectory,
"SingleFileCompilationTestHelperWithSetArgsTest",
TestCases.create(
BugPatternTestCases.create(
URI.create("file:///SingleFileCompilationTestHelperWithSetArgsTest.java"),
"SingleFileCompilationTestHelperWithSetArgsTest",
ImmutableList.of(
TestCase.create(
BugPatternTestCase.create(
"SingleFileCompilationTestHelperWithSetArgsTest.TestChecker",
ImmutableList.of(
IdentificationTestEntry.create(
@@ -335,11 +335,11 @@ final class BugPatternTestExtractorTest {
verifyGeneratedFileContent(
outputDirectory,
"MultiFileCompilationTestHelperTest",
TestCases.create(
BugPatternTestCases.create(
URI.create("file:///MultiFileCompilationTestHelperTest.java"),
"MultiFileCompilationTestHelperTest",
ImmutableList.of(
TestCase.create(
BugPatternTestCase.create(
"MultiFileCompilationTestHelperTest.TestChecker",
ImmutableList.of(
IdentificationTestEntry.create(
@@ -370,11 +370,11 @@ final class BugPatternTestExtractorTest {
verifyGeneratedFileContent(
outputDirectory,
"SingleFileBugCheckerRefactoringTestHelperTest",
TestCases.create(
BugPatternTestCases.create(
URI.create("file:///SingleFileBugCheckerRefactoringTestHelperTest.java"),
"SingleFileBugCheckerRefactoringTestHelperTest",
ImmutableList.of(
TestCase.create(
BugPatternTestCase.create(
"SingleFileBugCheckerRefactoringTestHelperTest.TestChecker",
ImmutableList.of(
ReplacementTestEntry.create(
@@ -408,12 +408,12 @@ final class BugPatternTestExtractorTest {
verifyGeneratedFileContent(
outputDirectory,
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest",
TestCases.create(
BugPatternTestCases.create(
URI.create(
"file:///SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest.java"),
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest",
ImmutableList.of(
TestCase.create(
BugPatternTestCase.create(
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest.TestChecker",
ImmutableList.of(
ReplacementTestEntry.create(
@@ -444,11 +444,11 @@ final class BugPatternTestExtractorTest {
verifyGeneratedFileContent(
outputDirectory,
"MultiFileBugCheckerRefactoringTestHelperTest",
TestCases.create(
BugPatternTestCases.create(
URI.create("file:///MultiFileBugCheckerRefactoringTestHelperTest.java"),
"MultiFileBugCheckerRefactoringTestHelperTest",
ImmutableList.of(
TestCase.create(
BugPatternTestCase.create(
"MultiFileBugCheckerRefactoringTestHelperTest.TestChecker",
ImmutableList.of(
ReplacementTestEntry.create(
@@ -484,16 +484,16 @@ final class BugPatternTestExtractorTest {
verifyGeneratedFileContent(
outputDirectory,
"CompilationAndBugCheckerRefactoringTestHelpersTest",
TestCases.create(
BugPatternTestCases.create(
URI.create("file:///CompilationAndBugCheckerRefactoringTestHelpersTest.java"),
"CompilationAndBugCheckerRefactoringTestHelpersTest",
ImmutableList.of(
TestCase.create(
BugPatternTestCase.create(
"CompilationAndBugCheckerRefactoringTestHelpersTest.TestChecker",
ImmutableList.of(
IdentificationTestEntry.create(
"A.java", "// BUG: Diagnostic contains:\nclass A {}\n"))),
TestCase.create(
BugPatternTestCase.create(
"CompilationAndBugCheckerRefactoringTestHelpersTest.TestChecker",
ImmutableList.of(
ReplacementTestEntry.create(
@@ -532,17 +532,17 @@ final class BugPatternTestExtractorTest {
verifyGeneratedFileContent(
outputDirectory,
"CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest",
TestCases.create(
BugPatternTestCases.create(
URI.create(
"file:///CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.java"),
"pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest",
ImmutableList.of(
TestCase.create(
BugPatternTestCase.create(
"pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.CustomTestChecker",
ImmutableList.of(
IdentificationTestEntry.create(
"A.java", "// BUG: Diagnostic contains:\nclass A {}\n"))),
TestCase.create(
BugPatternTestCase.create(
"pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.CustomTestChecker2",
ImmutableList.of(
ReplacementTestEntry.create(
@@ -550,9 +550,9 @@ final class BugPatternTestExtractorTest {
}
private static void verifyGeneratedFileContent(
Path outputDirectory, String testClass, TestCases expected) {
Path outputDirectory, String testClass, BugPatternTestCases expected) {
assertThat(outputDirectory.resolve(String.format("bugpattern-test-%s.json", testClass)))
.exists()
.returns(expected, path -> Json.read(path, TestCases.class));
.returns(expected, path -> Json.read(path, BugPatternTestCases.class));
}
}

View File

@@ -10,7 +10,6 @@ import static org.junit.jupiter.api.condition.OS.WINDOWS;
import com.google.auto.service.AutoService;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
import com.google.errorprone.VisitorState;
@@ -41,7 +40,8 @@ final class DocumentationGeneratorTaskListenerTest {
entry ->
AclEntry.newBuilder(entry)
.setPermissions(
Sets.difference(entry.permissions(), ImmutableSet.of(ADD_SUBDIRECTORY)))
Sets.difference(
entry.permissions(), Sets.immutableEnumSet(ADD_SUBDIRECTORY)))
.build())
.collect(toImmutableList()));

View File

@@ -0,0 +1,166 @@
package tech.picnic.errorprone.documentation;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList;
import java.net.URI;
import java.nio.file.Path;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import tech.picnic.errorprone.documentation.RefasterRuleCollectionTestExtractor.RefasterTestCase;
import tech.picnic.errorprone.documentation.RefasterRuleCollectionTestExtractor.RefasterTestCases;
final class RefasterRuleCollectionTestExtractorTest {
@Test
void noRefasterRuleTest(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory, "NoRefasterRuleTest.java", "public final class NoRefasterRuleTest {}");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@Test
void invalidTestClassName(@TempDir Path outputDirectory) {
assertThatThrownBy(
() ->
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"InvalidTestClassNameInput.java",
"import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;",
"",
"final class InvalidTestClassName implements RefasterRuleCollectionTestCase {}"))
.cause()
.isInstanceOf(VerifyException.class)
.hasMessage(
"Refaster rule collection test class name 'InvalidTestClassName' does not match '(.*)Test'");
}
@Test
void invalidFileName(@TempDir Path outputDirectory) {
assertThatThrownBy(
() ->
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"InvalidFileNameTest.java",
"import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;",
"",
"final class InvalidFileNameTest implements RefasterRuleCollectionTestCase {}"))
.cause()
.isInstanceOf(VerifyException.class)
.hasMessage(
"Refaster rule collection test file name '/InvalidFileNameTest.java' does not match '.*(Input|Output)\\.java'");
}
@Test
void emptyRefasterRuleCollectionTestInput(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"EmptyRefasterRuleCollectionTestInput.java",
"import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;",
"",
"final class EmptyRefasterRuleCollectionTest implements RefasterRuleCollectionTestCase {}");
verifyGeneratedFileContent(
outputDirectory,
"EmptyRefasterRuleCollectionTestInput",
RefasterTestCases.create(
URI.create("file:///EmptyRefasterRuleCollectionTestInput.java"),
"EmptyRefasterRuleCollection",
/* isInput= */ true,
ImmutableList.of()));
}
@Test
void singletonRefasterRuleCollectionTestOutput(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"SingletonRefasterRuleCollectionTestOutput.java",
"import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;",
"",
"final class SingletonRefasterRuleCollectionTest implements RefasterRuleCollectionTestCase {",
" int testMyRule() {",
" return 42;",
" }",
"}");
verifyGeneratedFileContent(
outputDirectory,
"SingletonRefasterRuleCollectionTestOutput",
RefasterTestCases.create(
URI.create("file:///SingletonRefasterRuleCollectionTestOutput.java"),
"SingletonRefasterRuleCollection",
/* isInput= */ false,
ImmutableList.of(
RefasterTestCase.create(
"MyRule",
"""
int testMyRule() {
return 42;
}"""))));
}
@Test
void complexRefasterRuleCollectionTestOutput(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"pkg/ComplexRefasterRuleCollectionTestInput.java",
"package pkg;",
"",
"import com.google.common.collect.ImmutableSet;",
"import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;",
"",
"final class ComplexRefasterRuleCollectionTest implements RefasterRuleCollectionTestCase {",
" private static final String IGNORED_CONSTANT = \"constant\";",
"",
" @Override",
" public ImmutableSet<Object> elidedTypesAndStaticImports() {",
" return ImmutableSet.of();",
" }",
"",
" /** Javadoc. */",
" String testFirstRule() {",
" return \"Don't panic\";",
" }",
"",
" // Comment.",
" String testSecondRule() {",
" return \"Carry a towel\";",
" }",
"",
" void testEmptyRule() {}",
"}");
verifyGeneratedFileContent(
outputDirectory,
"ComplexRefasterRuleCollectionTestInput",
RefasterTestCases.create(
URI.create("file:///pkg/ComplexRefasterRuleCollectionTestInput.java"),
"ComplexRefasterRuleCollection",
/* isInput= */ true,
ImmutableList.of(
RefasterTestCase.create(
"FirstRule",
"""
String testFirstRule() {
return "Don't panic";
}"""),
RefasterTestCase.create(
"SecondRule",
"""
String testSecondRule() {
return "Carry a towel";
}"""),
RefasterTestCase.create("EmptyRule", "void testEmptyRule() {}"))));
}
private static void verifyGeneratedFileContent(
Path outputDirectory, String testIdentifier, RefasterTestCases expected) {
assertThat(
outputDirectory.resolve(
String.format("refaster-rule-collection-test-%s.json", testIdentifier)))
.exists()
.returns(expected, path -> Json.read(path, RefasterTestCases.class));
}
}

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.17.0</version>
<version>0.19.2-SNAPSHOT</version>
</parent>
<artifactId>error-prone-contrib</artifactId>
@@ -55,7 +55,12 @@
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>refaster-support</artifactId>
<scope>provided</scope>
<!-- XXX: One would expect this to be a `provided` dependency (as
Refaster rules are interpreted by the `refaster-runner` module),
but the `OptionalOrElseGet` bug checker defined by this module
depends on the `RequiresComputation` matcher that
`refaster-support` primarily exposes for use by Refaster rules.
Review this setup. (Should the matchers be moved elsewhere?) -->
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
@@ -67,6 +72,15 @@
<artifactId>jackson-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service-annotations</artifactId>
@@ -82,6 +96,11 @@
<artifactId>guava</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
@@ -147,11 +166,22 @@
<artifactId>assertj-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gaul</groupId>
<artifactId>modernizer-maven-plugin</artifactId>
<scope>runtime</scope>
<!-- XXX: Consider making optional? Ship only the definitions? -->
</dependency>
<dependency>
<groupId>org.immutables</groupId>
<artifactId>value-annotations</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
@@ -196,7 +226,7 @@
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-java-11</artifactId>
<artifactId>rewrite-java-17</artifactId>
<scope>test</scope>
</dependency>
<dependency>
@@ -287,6 +317,55 @@
<arg>-Xplugin:DocumentationGenerator -XoutputDirectory=${project.build.directory}/docs</arg>
</compilerArgs>
</configuration>
<executions>
<!-- The Refaster input/output test classes used by
`RefasterRuleCollection` are modelled as classpath
resources, and thus not subject to the default test
compilation step. These two custom compilation steps
serve two purposes:
- To provide early feedback in case of syntax errors.
- To enable the `DocumentationGenerator` compiler
plugin to extract documentation metadata from them.
Note that the input and output files must be compiled
separately and to distinct output directories, as they
define the same set of class names. -->
<!-- XXX: Drop these executions if/when the Refaster
test framework is reimplemented such that tests can be
located alongside rules, rather than in two additional
resource files. -->
<execution>
<id>compile-refaster-test-input</id>
<goals>
<goal>testCompile</goal>
</goals>
<phase>process-test-resources</phase>
<configuration>
<compileSourceRoots>
<compileSourceRoot>${project.basedir}/src/test/resources</compileSourceRoot>
</compileSourceRoots>
<testIncludes>
<testInclude>**/*Input.java</testInclude>
</testIncludes>
<outputDirectory>${project.build.directory}/refaster-test-input</outputDirectory>
</configuration>
</execution>
<execution>
<id>compile-refaster-test-output</id>
<goals>
<goal>testCompile</goal>
</goals>
<phase>process-test-resources</phase>
<configuration>
<compileSourceRoots>
<compileSourceRoot>${project.basedir}/src/test/resources</compileSourceRoot>
</compileSourceRoots>
<testIncludes>
<testInclude>**/*Output.java</testInclude>
</testIncludes>
<outputDirectory>${project.build.directory}/refaster-test-output</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>

View File

@@ -0,0 +1,76 @@
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.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.LambdaExpressionTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.LambdaExpressionTree;
import com.sun.source.tree.TypeCastTree;
import com.sun.source.tree.VariableTree;
import com.sun.tools.javac.code.Type;
import javax.lang.model.type.TypeKind;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags lambda expressions that can be replaced with a method reference
* of the form {@code T.class::cast}.
*/
// XXX: Consider folding this logic into the `MethodReferenceUsage` check of the
// `error-prone-experimental` module.
// XXX: This check and its tests are structurally nearly identical to `IsInstanceLambdaUsage`.
// Unless folded into `MethodReferenceUsage`, consider merging the two.
@AutoService(BugChecker.class)
@BugPattern(
summary = "Prefer `Class::cast` method reference over equivalent lambda expression",
link = BUG_PATTERNS_BASE_URL + "ClassCastLambdaUsage",
linkType = CUSTOM,
severity = SUGGESTION,
tags = SIMPLIFICATION)
public final class ClassCastLambdaUsage extends BugChecker implements LambdaExpressionTreeMatcher {
private static final long serialVersionUID = 1L;
/** Instantiates a new {@link ClassCastLambdaUsage} instance. */
public ClassCastLambdaUsage() {}
@Override
public Description matchLambdaExpression(LambdaExpressionTree tree, VisitorState state) {
if (tree.getParameters().size() != 1 || !(tree.getBody() instanceof TypeCastTree typeCast)) {
return Description.NO_MATCH;
}
Type type = ASTHelpers.getType(typeCast);
if (type == null
|| type.isParameterized()
|| type.isPrimitive()
|| type.getKind() == TypeKind.TYPEVAR) {
/*
* The method reference syntax does not support casting to parameterized types, and type
* variables aren't supported either. Additionally, `Class#cast` does not support the same
* 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
// primitive casts. Add support for this.
return Description.NO_MATCH;
}
VariableTree param = Iterables.getOnlyElement(tree.getParameters());
if (!ASTHelpers.getSymbol(param).equals(ASTHelpers.getSymbol(typeCast.getExpression()))) {
return Description.NO_MATCH;
}
return describeMatch(
tree,
SuggestedFix.replace(
tree, SourceCode.treeToString(typeCast.getType(), state) + ".class::cast"));
}
}

View File

@@ -0,0 +1,125 @@
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.STYLE;
import static com.google.errorprone.matchers.Matchers.allOf;
import static com.google.errorprone.matchers.Matchers.hasModifier;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.errorprone.BugPattern;
import com.google.errorprone.ErrorProneFlags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher;
import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreeScanner;
import java.util.Locale;
import java.util.regex.Pattern;
import javax.inject.Inject;
import javax.lang.model.element.Modifier;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.utils.Flags;
/**
* A {@link BugChecker} that flags static constants that do not follow the upper snake case naming
* convention.
*/
@AutoService(BugChecker.class)
@BugPattern(
summary = "Constant variables should adhere to the `UPPER_SNAKE_CASE` naming convention",
link = BUG_PATTERNS_BASE_URL + "ConstantNaming",
linkType = CUSTOM,
severity = WARNING,
tags = STYLE)
@SuppressWarnings("java:S2160" /* Super class equality definition suffices. */)
public final class ConstantNaming extends BugChecker implements VariableTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<VariableTree> IS_CONSTANT =
allOf(hasModifier(Modifier.STATIC), hasModifier(Modifier.FINAL));
private static final Matcher<VariableTree> IS_PRIVATE = hasModifier(Modifier.PRIVATE);
private static final Pattern SNAKE_CASE = Pattern.compile("([a-z])([A-Z])");
private static final ImmutableSet<String> DEFAULT_EXEMPTED_NAMES =
ImmutableSet.of("serialVersionUID");
/**
* Flag using which constant names that must not be flagged (in addition to those defined by
* {@link #DEFAULT_EXEMPTED_NAMES}) can be specified.
*/
private static final String ADDITIONAL_EXEMPTED_NAMES_FLAG =
"CanonicalConstantNaming:ExemptedNames";
private final ImmutableSet<String> exemptedNames;
/** Instantiates a default {@link ConstantNaming} instance. */
public ConstantNaming() {
this(ErrorProneFlags.empty());
}
/**
* Instantiates a customized {@link ConstantNaming}.
*
* @param flags Any provided command line flags.
*/
@Inject
ConstantNaming(ErrorProneFlags flags) {
exemptedNames =
Sets.union(DEFAULT_EXEMPTED_NAMES, Flags.getSet(flags, ADDITIONAL_EXEMPTED_NAMES_FLAG))
.immutableCopy();
}
@Override
public Description matchVariable(VariableTree tree, VisitorState state) {
String variableName = tree.getName().toString();
if (!IS_CONSTANT.matches(tree, state) || exemptedNames.contains(variableName)) {
return Description.NO_MATCH;
}
String replacement = toUpperSnakeCase(variableName);
if (replacement.equals(variableName)) {
return Description.NO_MATCH;
}
Description.Builder description = buildDescription(tree);
if (!IS_PRIVATE.matches(tree, state)) {
description.setMessage(
"%s; consider renaming to '%s', though note that this is not a private constant"
.formatted(message(), replacement));
} else if (isVariableNameInUse(replacement, state)) {
description.setMessage(
"%s; consider renaming to '%s', though note that a variable with this name is already declared"
.formatted(message(), replacement));
} else {
description.addFix(SuggestedFixes.renameVariable(tree, replacement, state));
}
return description.build();
}
private static String toUpperSnakeCase(String variableName) {
return SNAKE_CASE.matcher(variableName).replaceAll("$1_$2").toUpperCase(Locale.ROOT);
}
private static boolean isVariableNameInUse(String name, VisitorState state) {
return Boolean.TRUE.equals(
new TreeScanner<Boolean, @Nullable Void>() {
@Override
public Boolean visitVariable(VariableTree tree, @Nullable Void unused) {
return ASTHelpers.getSymbol(tree).getSimpleName().contentEquals(name)
|| super.visitVariable(tree, null);
}
@Override
public Boolean reduce(Boolean r1, Boolean r2) {
return Boolean.TRUE.equals(r1) || Boolean.TRUE.equals(r2);
}
}.scan(state.getPath().getCompilationUnit(), null));
}
}

View File

@@ -62,7 +62,7 @@ public final class EmptyMethod extends BugChecker implements MethodTreeMatcher {
}
private static boolean isInPossibleTestHelperClass(VisitorState state) {
return Optional.ofNullable(ASTHelpers.findEnclosingNode(state.getPath(), ClassTree.class))
return Optional.ofNullable(state.findEnclosing(ClassTree.class))
.map(ClassTree::getSimpleName)
.filter(name -> name.toString().contains("Test"))
.isPresent();

View File

@@ -0,0 +1,233 @@
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.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 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")
.build();
/** 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());
/*
* If all overloads have a single parameter, and at least one of them is a varargs method, then
* we assume that unwrapping the iterable argument will cause a suitable overload to be invoked.
* (Note that there may be multiple varargs overloads, either with different parameter types, or
* due to method overriding; this check does not attempt to determine which exact method or
* overload will be invoked as a result of the suggested simplification.)
*
* Note that this is a (highly!) imperfect heuristic, but it is sufficient to prevent e.g.
* unwrapping of arguments to `org.jooq.impl.DSL#row`, which can cause the expression's return
* type to change from `RowN` to (e.g.) `Row2`.
*/
// XXX: There are certainly cases where it _would_ be nice to unwrap the arguments to
// `org.jooq.impl.DSL#row(Collection<?>)`. Look into this.
// XXX: Ideally we do check that one of the overloads accepts the unwrapped arguments.
// XXX: Ideally we validate that eligible overloads have compatible return types.
boolean hasLikelySuitableVarargsOverload =
overloads.stream().allMatch(m -> m.params().size() == 1)
&& overloads.stream().anyMatch(MethodSymbol::isVarArgs);
return hasLikelySuitableVarargsOverload
? Optional.of(SourceCode.unwrapMethodInvocation(argument, state))
: Optional.empty();
}
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

@@ -36,6 +36,7 @@ import java.util.Formatter;
import java.util.List;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.utils.MoreASTHelpers;
import tech.picnic.errorprone.utils.SourceCode;
/**
@@ -203,14 +204,10 @@ public final class FormatStringConcatenation extends BugChecker
ExpressionTree argument = ASTHelpers.stripParentheses(arguments.get(argPosition));
return argument instanceof BinaryTree
&& isStringTyped(argument, state)
&& MoreASTHelpers.isStringTyped(argument, state)
&& ASTHelpers.constValue(argument, String.class) == null;
}
private static boolean isStringTyped(ExpressionTree tree, VisitorState state) {
return ASTHelpers.isSameType(ASTHelpers.getType(tree), state.getSymtab().stringType, state);
}
private static class ReplacementArgumentsConstructor
extends SimpleTreeVisitor<@Nullable Void, VisitorState> {
private final StringBuilder formatString = new StringBuilder();
@@ -223,7 +220,7 @@ public final class FormatStringConcatenation extends BugChecker
@Override
public @Nullable Void visitBinary(BinaryTree tree, VisitorState state) {
if (tree.getKind() == Kind.PLUS && isStringTyped(tree, state)) {
if (tree.getKind() == Kind.PLUS && MoreASTHelpers.isStringTyped(tree, state)) {
tree.getLeftOperand().accept(this, state);
tree.getRightOperand().accept(this, state);
} else {

View File

@@ -39,6 +39,7 @@ import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import java.time.Instant;
import java.util.Arrays;
import java.util.List;
import tech.picnic.errorprone.utils.SourceCode;
@@ -51,6 +52,7 @@ import tech.picnic.errorprone.utils.SourceCode;
// is effectively the identity operation.
// XXX: Also flag nullary instance method invocations that represent an identity conversion, such as
// `Boolean#booleanValue()`, `Byte#byteValue()` and friends.
// XXX: Also flag redundant round-trip conversions such as `path.toFile().toPath()`.
@AutoService(BugChecker.class)
@BugPattern(
summary = "Avoid or clarify identity conversions",
@@ -83,6 +85,7 @@ public final class IdentityConversion extends BugChecker implements MethodInvoca
ImmutableSetMultimap.class.getCanonicalName(),
ImmutableTable.class.getCanonicalName())
.named("copyOf"),
staticMethod().onClass(Instant.class.getCanonicalName()).namedAnyOf("from"),
staticMethod().onClass(Matchers.class.getCanonicalName()).namedAnyOf("allOf", "anyOf"),
staticMethod().onClass("reactor.adapter.rxjava.RxJava2Adapter"),
staticMethod()

View File

@@ -25,6 +25,8 @@ import tech.picnic.errorprone.utils.SourceCode;
*/
// XXX: Consider folding this logic into the `MethodReferenceUsage` check of the
// `error-prone-experimental` module.
// XXX: This check and its tests are structurally nearly identical to `ClassCastLambdaUsage`. Unless
// folded into `MethodReferenceUsage`, consider merging the two.
@AutoService(BugChecker.class)
@BugPattern(
summary = "Prefer `Class::isInstance` method reference over equivalent lambda expression",

View File

@@ -16,7 +16,7 @@ import static tech.picnic.errorprone.utils.MoreJUnitMatchers.TEST_METHOD;
import static tech.picnic.errorprone.utils.MoreMatchers.hasMetaAnnotation;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
@@ -70,7 +70,7 @@ public final class JUnitClassModifiers extends BugChecker implements ClassTreeMa
SuggestedFixes.removeModifiers(
tree.getModifiers(),
state,
ImmutableSet.of(Modifier.PRIVATE, Modifier.PROTECTED, Modifier.PUBLIC))
Sets.immutableEnumSet(Modifier.PRIVATE, Modifier.PROTECTED, Modifier.PUBLIC))
.ifPresent(fixBuilder::merge);
if (!HAS_SPRING_CONFIGURATION_ANNOTATION.matches(tree, state)) {

View File

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

View File

@@ -14,6 +14,7 @@ import com.google.common.base.Splitter;
import com.google.common.collect.Comparators;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.errorprone.BugPattern;
import com.google.errorprone.ErrorProneFlags;
import com.google.errorprone.VisitorState;
@@ -34,10 +35,8 @@ import com.sun.source.tree.Tree;
import com.sun.source.util.TreeScanner;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import javax.inject.Inject;
import org.jspecify.annotations.Nullable;
@@ -163,7 +162,12 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
/* For now we don't force sorting on numeric types. */
return Stream.of(
symtab.annotationType, symtab.classType, symtab.enumSym.type, symtab.stringType)
symtab.annotationType,
symtab.booleanType,
symtab.charType,
symtab.classType,
symtab.enumSym.type,
symtab.stringType)
.anyMatch(t -> ASTHelpers.isSubtype(elemType, t, state));
}
@@ -225,10 +229,8 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
excludedAnnotations(flags));
}
private static ImmutableList<String> excludedAnnotations(ErrorProneFlags flags) {
Set<String> exclusions = new HashSet<>();
exclusions.addAll(Flags.getList(flags, EXCLUDED_ANNOTATIONS_FLAG));
exclusions.addAll(BLACKLISTED_ANNOTATIONS);
return ImmutableList.copyOf(exclusions);
private static ImmutableSet<String> excludedAnnotations(ErrorProneFlags flags) {
return Sets.union(BLACKLISTED_ANNOTATIONS, Flags.getSet(flags, EXCLUDED_ANNOTATIONS_FLAG))
.immutableCopy();
}
}

View File

@@ -0,0 +1,371 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableTable.toImmutableTable;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.REFACTORING;
import static com.google.errorprone.matchers.Matchers.allOf;
import static com.google.errorprone.predicates.TypePredicates.isDescendantOf;
import static com.google.errorprone.predicates.TypePredicates.isExactType;
import static java.util.Objects.requireNonNull;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.google.auto.service.AutoService;
import com.google.auto.value.AutoValue;
import com.google.auto.value.AutoValue.CopyAnnotations;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableTable;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.annotations.Immutable;
import com.google.errorprone.annotations.Var;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.IdentifierTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.MemberReferenceTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.MemberSelectTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.NewClassTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.predicates.TypePredicate;
import com.google.errorprone.suppliers.Supplier;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MemberReferenceTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.util.JavacTask;
import com.sun.tools.javac.api.BasicJavacTask;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.jvm.Target;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Name;
/**
* A {@link BugChecker} that flags the same legacy APIs as the <a
* href="https://github.com/gaul/modernizer-maven-plugin">Modernizer Maven Plugin</a>.
*
* <p>This checker is primarily useful for people who run Error Prone anyway; it obviates the need
* for an additional source code analysis pass using another Maven plugin.
*/
@AutoService(BugChecker.class)
@BugPattern(
summary = "Avoid constants and methods superseded by more recent equivalents",
link = BUG_PATTERNS_BASE_URL + "Modernizer",
linkType = CUSTOM,
severity = SUGGESTION,
tags = REFACTORING)
public final class Modernizer extends BugChecker
implements AnnotationTreeMatcher,
IdentifierTreeMatcher,
MemberReferenceTreeMatcher,
MemberSelectTreeMatcher,
NewClassTreeMatcher {
private static final long serialVersionUID = 1L;
// XXX: Load lazily?
private final ImmutableTable<String, Matcher<ExpressionTree>, String> violations =
loadViolations();
/** Instantiates a new {@link MockitoStubbing} instance. */
public Modernizer() {}
@Override
public Description matchAnnotation(AnnotationTree tree, VisitorState state) {
// XXX: Use or drop
// XXX: See
// https://github.com/google/guava-beta-checker/commit/9b26aa980be7f70631921fd6695013547728eb1e;
// we may be on the right track without this.
return Description.NO_MATCH;
}
@Override
public Description matchIdentifier(IdentifierTree tree, VisitorState state) {
return match(tree.getName(), tree, state);
}
@Override
public Description matchMemberReference(MemberReferenceTree tree, VisitorState state) {
return match(tree.getName(), tree, state);
}
@Override
public Description matchMemberSelect(MemberSelectTree tree, VisitorState state) {
return match(tree.getIdentifier(), tree, state);
}
@Override
public Description matchNewClass(NewClassTree tree, VisitorState state) {
Symbol createdType =
requireNonNull(ASTHelpers.getSymbol(tree).getEnclosingElement(), "No enclosing class");
return match(createdType.getQualifiedName(), tree, state);
}
private Description match(Name identifier, ExpressionTree tree, VisitorState state) {
return violations.row(identifier.toString()).entrySet().stream()
.filter(e -> e.getKey().matches(tree, state))
.findFirst()
.map(e -> buildDescription(tree).setMessage(e.getValue()).build())
.orElse(Description.NO_MATCH);
}
private ImmutableTable<String, Matcher<ExpressionTree>, String> loadViolations() {
InputStream resource = getClass().getResourceAsStream("/modernizer.xml");
// XXX: Or silently skip?
checkState(resource != null, "Modernizer configuration not found on classpath");
XmlMapper mapper = new XmlMapper();
try (resource) {
return mapper.readValue(resource, Violations.class).getViolation().stream()
.filter(v -> v.getChecker().isPresent())
.collect(
toImmutableTable(
Violation::getIdentifier,
v -> v.getChecker().orElseThrow(),
Violation::getComment));
} catch (IOException e) {
throw new UncheckedIOException("Failed to parse Modernizer configuration", e);
}
}
// XXX: Further simplify with Auto Value?
@Immutable
static final class Violations {
@JacksonXmlElementWrapper(useWrapping = false)
private final ImmutableList<Violation> violation;
@JsonCreator
private Violations(@JsonProperty("violation") List<Violation> violation) {
this.violation = ImmutableList.copyOf(violation);
}
// XXX: Jackson relies on this naming and visibility. Ugh.
public ImmutableList<Violation> getViolation() {
return violation;
}
}
@Immutable
@AutoValue
abstract static class Violation {
private static final Pattern NAME_PATTERN =
Pattern.compile(
"(?<type>[^.]+)(?:\\.(?<member>[^:]+):(?:\\((?<params>[^)]*)\\))?(?<return>[^()]+))?");
abstract Optional<Target> getTarget();
abstract String getIdentifier();
@CopyAnnotations
@SuppressWarnings("Immutable")
abstract Matcher<ExpressionTree> getMatcher();
abstract String getComment();
Optional<Matcher<ExpressionTree>> getChecker() {
return getTarget().map(t -> allOf(getMatcher(), targetMatcher(t)));
}
// XXX: Overkill? Not if we use auto value.
// XXX: Modernizer also flags annotation declarations, presumably by type.
// XXX: `ExpressionTree` is wrong here. Depends on type.
@JsonCreator
static Violation create(
@JsonProperty("version") String version,
@JsonProperty("name") String signature,
@JsonProperty("comment") String comment) {
Optional<Target> target = Optional.ofNullable(Target.lookup(version));
java.util.regex.Matcher matcher = NAME_PATTERN.matcher(signature);
checkState(matcher.matches(), "Failed to parse signature '%s'", signature);
String type =
replaceSlashes(requireNonNull(matcher.group("type"), "Signature must contain type"));
String member = matcher.group("member");
if (member == null) {
// XXX: Should not implement this interface. Something like:
// violations.put(type, allOf(isSubtypeOf(type), versionRequirement), this.comment)
return new AutoValue_Modernizer_Violation(target, type, (t, s) -> false, comment);
}
String params = matcher.group("params");
if (params == null) {
return new AutoValue_Modernizer_Violation(target, member, isField(type), comment);
}
ImmutableList<Supplier<Type>> parameters = parseParams(params);
if ("\"<init>\"".equals(member)) {
return new AutoValue_Modernizer_Violation(
target, type, isConstructor(type, parameters), comment);
}
// XXX: Should we disallow _extension_ of this method?
return new AutoValue_Modernizer_Violation(
target, member, isMethod(type, parameters), comment);
}
private static Matcher<ExpressionTree> targetMatcher(Target target) {
return (tree, state) -> target.compareTo(getTargetVersion(state)) <= 0;
}
private static Target getTargetVersion(VisitorState state) {
return Target.instance(
Optional.ofNullable(state.context.get(JavacTask.class))
.filter(BasicJavacTask.class::isInstance)
.map(BasicJavacTask.class::cast)
.map(BasicJavacTask::getContext)
.orElse(state.context));
}
private static Matcher<ExpressionTree> isField(String onDescendantOf) {
return isMember(ElementKind::isField, isDescendantOf(onDescendantOf), ImmutableList.of());
}
private static Matcher<ExpressionTree> isConstructor(
String ofClass, ImmutableList<Supplier<Type>> withParameters) {
return isMember(k -> k == ElementKind.CONSTRUCTOR, isExactType(ofClass), withParameters);
}
private static Matcher<ExpressionTree> isMethod(
String onDescendantOf, ImmutableList<Supplier<Type>> withParameters) {
return isMember(k -> k == ElementKind.METHOD, isDescendantOf(onDescendantOf), withParameters);
}
private static Matcher<ExpressionTree> isMember(
Predicate<ElementKind> ofKind,
TypePredicate ownedBy,
ImmutableList<Supplier<Type>> withParameters) {
return (tree, state) ->
Optional.ofNullable(ASTHelpers.getSymbol(tree))
.filter(s -> ofKind.test(s.getKind()))
.filter(s -> isOwnedBy(s, ownedBy, state))
.filter(s -> hasSameParameters(s, withParameters, state))
.isPresent();
}
private static boolean isOwnedBy(Symbol symbol, TypePredicate expected, VisitorState state) {
Symbol owner = symbol.getEnclosingElement();
return owner != null && expected.apply(owner.asType(), state);
}
private static boolean hasSameParameters(
Symbol method, ImmutableList<Supplier<Type>> expected, VisitorState state) {
List<Type> actual = method.asType().getParameterTypes();
if (actual.size() != expected.size()) {
return false;
}
for (int i = 0; i < actual.size(); ++i) {
if (!ASTHelpers.isSameType(actual.get(i), expected.get(i).get(state), state)) {
return false;
}
}
return true;
}
private static ImmutableList<Supplier<Type>> parseParams(String params) {
ImmutableList.Builder<Supplier<Type>> types = ImmutableList.builder();
@Var int index = 0;
while (index < params.length()) {
index = parseType(params, index, types::add);
}
return types.build();
}
private static int parseType(String params, int index, Consumer<Supplier<Type>> sink) {
return switch (params.charAt(index)) {
case '[' -> parseArrayType(params, index, sink);
case 'L' -> parseTypeReference(params, index, sink);
default -> parsePrimitiveType(params, index, sink);
};
}
private static int parseArrayType(String params, int index, Consumer<Supplier<Type>> sink) {
int typeIndex = index + 1;
checkArgument(
params.length() > typeIndex && params.charAt(index) == '[',
"Cannot parse array type in parameter string '%s' at index %s",
params,
index);
return parseType(
params,
typeIndex,
type ->
sink.accept(s -> s.getType(type.get(s), /* isArray= */ true, ImmutableList.of())));
}
private static int parsePrimitiveType(String params, int index, Consumer<Supplier<Type>> sink) {
String primitive =
Optional.of(params)
.filter(p -> p.length() > index)
.flatMap(p -> fromPrimitiveAlias(p.charAt(index)))
.orElseThrow(
() ->
new IllegalArgumentException(
String.format(
"Cannot parse primitive type in parameter string '%s' at index %s",
params, index)));
sink.accept(s -> s.getTypeFromString(primitive));
return index + 1;
}
private static Optional<String> fromPrimitiveAlias(char alias) {
return switch (alias) {
case 'Z' -> Optional.of("boolean");
case 'B' -> Optional.of("byte");
case 'C' -> Optional.of("char");
case 'S' -> Optional.of("short");
case 'I' -> Optional.of("int");
case 'J' -> Optional.of("long");
case 'F' -> Optional.of("float");
case 'D' -> Optional.of("double");
default -> Optional.empty();
};
}
private static int parseTypeReference(String params, int index, Consumer<Supplier<Type>> sink) {
int identifierIndex = index + 1;
if (params.length() > identifierIndex && params.charAt(index) == 'L') {
int delimiter = params.indexOf(';', identifierIndex);
if (delimiter > index) {
sink.accept(
s ->
s.getTypeFromString(
replaceSlashes(params.substring(identifierIndex, delimiter))));
return delimiter + 1;
}
}
throw new IllegalArgumentException(
String.format(
"Cannot parse reference type in parameter string '%s' at index %s", params, index));
}
private static String replaceSlashes(String typeName) {
return typeName.replace('/', '.');
}
}
}

View File

@@ -18,14 +18,12 @@ import com.google.errorprone.fixes.SuggestedFixes;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import java.util.Optional;
import java.util.function.Supplier;
import tech.picnic.errorprone.refaster.matchers.RequiresComputation;
import tech.picnic.errorprone.utils.SourceCode;
/**
@@ -36,12 +34,12 @@ import tech.picnic.errorprone.utils.SourceCode;
* it does, the suggested fix changes the program's semantics. Such fragile code must instead be
* refactored such that the side-effectful code does not appear accidental.
*/
// XXX: Consider also implementing the inverse, in which `.orElseGet(() -> someConstant)` is
// flagged.
// XXX: Once the `MethodReferenceUsageCheck` becomes generally usable, consider leaving the method
// reference cleanup to that check, and express the remainder of the logic in this class using a
// Refaster template, i.c.w. a `@Matches` constraint that implements the `requiresComputation`
// logic.
// XXX: This rule may introduce a compilation error: the `value` expression may reference a
// non-effectively final variable, which is not allowed in the replacement lambda expression.
// Review whether a `@Matcher` can be used to avoid this.
// XXX: Once the `MethodReferenceUsageCheck` bug checker becomes generally usable, consider leaving
// the method reference cleanup to that check, and express the remainder of the logic in this class
// using a Refaster template, i.c.w. a `@NotMatches(RequiresComputation.class)` constraint.
@AutoService(BugChecker.class)
@BugPattern(
summary =
@@ -51,16 +49,17 @@ import tech.picnic.errorprone.utils.SourceCode;
linkType = NONE,
severity = WARNING,
tags = PERFORMANCE)
public final class OptionalOrElse extends BugChecker implements MethodInvocationTreeMatcher {
public final class OptionalOrElseGet extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> REQUIRES_COMPUTATION = new RequiresComputation();
private static final Matcher<ExpressionTree> OPTIONAL_OR_ELSE_METHOD =
instanceMethod().onExactClass(Optional.class.getCanonicalName()).namedAnyOf("orElse");
// XXX: Also exclude invocations of `@Placeholder`-annotated methods.
private static final Matcher<ExpressionTree> REFASTER_METHOD =
staticMethod().onClass(Refaster.class.getCanonicalName());
/** Instantiates a new {@link OptionalOrElse} instance. */
public OptionalOrElse() {}
/** Instantiates a new {@link OptionalOrElseGet} instance. */
public OptionalOrElseGet() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
@@ -69,7 +68,8 @@ public final class OptionalOrElse extends BugChecker implements MethodInvocation
}
ExpressionTree argument = Iterables.getOnlyElement(tree.getArguments());
if (!requiresComputation(argument) || REFASTER_METHOD.matches(argument, state)) {
if (!REQUIRES_COMPUTATION.matches(argument, state)
|| REFASTER_METHOD.matches(argument, state)) {
return Description.NO_MATCH;
}
@@ -91,18 +91,6 @@ public final class OptionalOrElse extends BugChecker implements MethodInvocation
return describeMatch(tree, fix);
}
/**
* Tells whether the given expression contains anything other than a literal or a (possibly
* dereferenced) variable or constant.
*/
private static boolean requiresComputation(ExpressionTree tree) {
return !(tree instanceof IdentifierTree
|| tree instanceof LiteralTree
|| (tree instanceof MemberSelectTree memberSelect
&& !requiresComputation(memberSelect.getExpression()))
|| ASTHelpers.constValue(tree) != null);
}
/** Returns the nullary method reference matching the given expression, if any. */
private static Optional<String> tryMethodReferenceConversion(
ExpressionTree tree, VisitorState state) {
@@ -118,7 +106,7 @@ public final class OptionalOrElse extends BugChecker implements MethodInvocation
return Optional.empty();
}
if (requiresComputation(memberSelect.getExpression())) {
if (REQUIRES_COMPUTATION.matches(memberSelect.getExpression(), state)) {
return Optional.empty();
}

View File

@@ -378,11 +378,11 @@ public final class RedundantStringConversion extends BugChecker
private static Matcher<MethodInvocationTree> createConversionMethodMatcher(
ErrorProneFlags flags) {
// XXX: ErrorProneFlags#getList splits by comma, but method signatures may also contain commas.
// For this class methods accepting more than one argument are not valid, but still: not nice.
// XXX: `Flags#getSet` splits by comma, but method signatures may also contain commas. For this
// class methods accepting more than one argument are not valid, but still: not nice.
return anyOf(
WELL_KNOWN_STRING_CONVERSION_METHODS,
new MethodMatcherFactory()
.create(Flags.getList(flags, EXTRA_STRING_CONVERSION_METHODS_FLAG)));
.create(Flags.getSet(flags, EXTRA_STRING_CONVERSION_METHODS_FLAG)));
}
}

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

@@ -15,8 +15,8 @@ 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.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.BugPattern;
import com.google.errorprone.ErrorProneFlags;
import com.google.errorprone.VisitorState;
@@ -74,10 +74,10 @@ public final class RequestParamType extends BugChecker implements VariableTreeMa
return allOf(
annotations(AT_LEAST_ONE, isType("org.springframework.web.bind.annotation.RequestParam")),
anyOf(isSubtypeOf(ImmutableCollection.class), isSubtypeOf(ImmutableMap.class)),
not(isSubtypeOfAny(Flags.getList(flags, SUPPORTED_CUSTOM_TYPES_FLAG))));
not(isSubtypeOfAny(Flags.getSet(flags, SUPPORTED_CUSTOM_TYPES_FLAG))));
}
private static Matcher<Tree> isSubtypeOfAny(ImmutableList<String> inclusions) {
private static Matcher<Tree> isSubtypeOfAny(ImmutableSet<String> inclusions) {
return anyOf(
inclusions.stream()
.map(inclusion -> isSubtypeOf(Suppliers.typeFromString(inclusion)))

View File

@@ -41,7 +41,7 @@ import tech.picnic.errorprone.utils.SourceCode;
tags = LIKELY_ERROR)
public final class Slf4jLogStatement extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> MARKER = isSubtypeOf("org.slf4j.Marker");
private static final Matcher<ExpressionTree> SLF4J_MARKER = isSubtypeOf("org.slf4j.Marker");
private static final Matcher<ExpressionTree> THROWABLE = isSubtypeOf(Throwable.class);
private static final Matcher<ExpressionTree> SLF4J_LOGGER_INVOCATION =
instanceMethod()
@@ -71,7 +71,7 @@ public final class Slf4jLogStatement extends BugChecker implements MethodInvocat
* SLF4J log statements may accept a "marker" as a first argument, before the format string.
* 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
* will always choose to render the associated stacktrace, even if the argument has a

View File

@@ -0,0 +1,185 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.base.Verify.verify;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.STYLE;
import static com.google.errorprone.matchers.Matchers.allOf;
import static com.google.errorprone.matchers.Matchers.classLiteral;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.matchers.Matchers.toType;
import static java.util.Objects.requireNonNull;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.base.CaseFormat;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.errorprone.BugPattern;
import com.google.errorprone.ErrorProneFlags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher;
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.sun.source.tree.ClassTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.ModifiersTree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.tree.VariableTree;
import com.sun.tools.javac.code.Symbol;
import java.util.EnumSet;
import javax.inject.Inject;
import javax.lang.model.element.Modifier;
import tech.picnic.errorprone.utils.MoreASTHelpers;
/** A {@link BugChecker} that flags non-canonical SLF4J logger declarations. */
@AutoService(BugChecker.class)
@BugPattern(
summary = "SLF4J logger declarations should follow established best-practices",
link = BUG_PATTERNS_BASE_URL + "Slf4jLoggerDeclaration",
linkType = CUSTOM,
severity = WARNING,
tags = STYLE)
@SuppressWarnings("java:S2160" /* Super class equality definition suffices. */)
public final class Slf4jLoggerDeclaration extends BugChecker implements VariableTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> IS_GET_LOGGER =
staticMethod().onDescendantOf("org.slf4j.LoggerFactory").named("getLogger");
private static final String CANONICAL_STATIC_LOGGER_NAME_FLAG =
"Slf4jLoggerDeclaration:CanonicalStaticLoggerName";
private static final String DEFAULT_CANONICAL_LOGGER_NAME = "LOG";
private static final Matcher<ExpressionTree> IS_STATIC_ENCLOSING_CLASS_REFERENCE =
classLiteral(Slf4jLoggerDeclaration::isEnclosingClassReference);
private static final Matcher<ExpressionTree> IS_DYNAMIC_ENCLOSING_CLASS_REFERENCE =
toType(
MethodInvocationTree.class,
allOf(
instanceMethod().anyClass().named("getClass").withNoParameters(),
Slf4jLoggerDeclaration::getClassReceiverIsEnclosingClassInstance));
private static final ImmutableSet<Modifier> INSTANCE_DECLARATION_MODIFIERS =
Sets.immutableEnumSet(Modifier.PRIVATE, Modifier.FINAL);
private static final ImmutableSet<Modifier> STATIC_DECLARATION_MODIFIERS =
Sets.immutableEnumSet(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL);
private final String canonicalStaticFieldName;
private final String canonicalInstanceFieldName;
/** Instantiates a default {@link Slf4jLoggerDeclaration} instance. */
public Slf4jLoggerDeclaration() {
this(ErrorProneFlags.empty());
}
/**
* Instantiates a customized {@link Slf4jLoggerDeclaration}.
*
* @param flags Any provided command line flags.
*/
@Inject
Slf4jLoggerDeclaration(ErrorProneFlags flags) {
canonicalStaticFieldName =
flags.get(CANONICAL_STATIC_LOGGER_NAME_FLAG).orElse(DEFAULT_CANONICAL_LOGGER_NAME);
canonicalInstanceFieldName =
CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, canonicalStaticFieldName);
}
@Override
public Description matchVariable(VariableTree tree, VisitorState state) {
ExpressionTree initializer = tree.getInitializer();
if (!IS_GET_LOGGER.matches(initializer, state)) {
return Description.NO_MATCH;
}
ClassTree clazz = getEnclosingClass(state);
ExpressionTree factoryArg =
Iterables.getOnlyElement(((MethodInvocationTree) initializer).getArguments());
SuggestedFix.Builder fix = SuggestedFix.builder();
if (clazz.getModifiers().getFlags().contains(Modifier.ABSTRACT)
&& IS_DYNAMIC_ENCLOSING_CLASS_REFERENCE.matches(factoryArg, state)) {
/*
* While generally we prefer `Logger` declarations to be static and named after their
* enclosing class, we allow one exception: loggers in abstract classes with a name derived
* from `getClass()`.
*/
suggestModifiers(tree, INSTANCE_DECLARATION_MODIFIERS, fix, state);
suggestRename(tree, canonicalInstanceFieldName, fix, state);
} else {
suggestModifiers(
tree,
clazz.getKind() == Kind.INTERFACE ? ImmutableSet.of() : STATIC_DECLARATION_MODIFIERS,
fix,
state);
suggestRename(tree, canonicalStaticFieldName, fix, state);
if (!MoreASTHelpers.isStringTyped(factoryArg, state)
&& !IS_STATIC_ENCLOSING_CLASS_REFERENCE.matches(factoryArg, state)) {
/*
* Loggers with a custom string name are generally "special", but those with a name derived
* from a class other than the one that encloses it are likely in error.
*/
fix.merge(SuggestedFix.replace(factoryArg, clazz.getSimpleName() + ".class"));
}
}
return fix.isEmpty() ? Description.NO_MATCH : describeMatch(tree, fix.build());
}
private static void suggestModifiers(
VariableTree tree,
ImmutableSet<Modifier> modifiers,
SuggestedFix.Builder fixBuilder,
VisitorState state) {
ModifiersTree modifiersTree =
requireNonNull(ASTHelpers.getModifiers(tree), "`VariableTree` must have modifiers");
SuggestedFixes.addModifiers(tree, modifiersTree, state, modifiers).ifPresent(fixBuilder::merge);
SuggestedFixes.removeModifiers(
modifiersTree, state, Sets.difference(EnumSet.allOf(Modifier.class), modifiers))
.ifPresent(fixBuilder::merge);
}
private static void suggestRename(
VariableTree variableTree, String name, SuggestedFix.Builder fixBuilder, VisitorState state) {
if (!variableTree.getName().contentEquals(name)) {
fixBuilder.merge(SuggestedFixes.renameVariable(variableTree, name, state));
}
}
private static boolean isEnclosingClassReference(ExpressionTree tree, VisitorState state) {
return ASTHelpers.getSymbol(getEnclosingClass(state)).equals(ASTHelpers.getSymbol(tree));
}
private static boolean getClassReceiverIsEnclosingClassInstance(
MethodInvocationTree getClassInvocationTree, VisitorState state) {
ExpressionTree receiver = ASTHelpers.getReceiver(getClassInvocationTree);
if (receiver == null) {
/*
* Method invocations without an explicit receiver either involve static methods (possibly
* statically imported), or instance methods invoked on the enclosing class. As the given
* `getClassInvocationTree` is guaranteed to be a nullary `#getClass()` invocation, the latter
* must be the case.
*/
return true;
}
Symbol symbol = ASTHelpers.getSymbol(receiver);
return symbol != null
&& symbol.asType().tsym.equals(ASTHelpers.getSymbol(getEnclosingClass(state)));
}
private static ClassTree getEnclosingClass(VisitorState state) {
ClassTree clazz = state.findEnclosing(ClassTree.class);
// XXX: Review whether we should relax this constraint in the face of so-called anonymous
// classes. See
// https://docs.oracle.com/en/java/javase/23/language/implicitly-declared-classes-and-instance-main-methods.html
verify(clazz != null, "Variable not defined inside class");
return clazz;
}
}

View File

@@ -23,7 +23,6 @@ import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.util.Constants;
import java.util.Formattable;
import java.util.Iterator;
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
// `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)
@BugPattern(
summary = "Prefer `String#join` over `String#format`",
@@ -150,7 +151,7 @@ public final class StringJoin extends BugChecker implements MethodInvocationTree
SuggestedFix.Builder fix =
SuggestedFix.builder()
.replace(tree.getMethodSelect(), "String.join")
.replace(arguments.next(), Constants.format(separator));
.replace(arguments.next(), SourceCode.toStringConstantExpression(separator, state));
while (arguments.hasNext()) {
ExpressionTree argument = arguments.next();

View File

@@ -3,9 +3,6 @@ package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multiset;
import com.google.errorprone.refaster.Refaster;
@@ -15,7 +12,6 @@ import com.google.errorprone.refaster.annotation.Matches;
import com.google.errorprone.refaster.annotation.NotMatches;
import com.google.errorprone.refaster.annotation.Repeated;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -204,32 +200,8 @@ final class AssertJRules {
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T element) {
return Refaster.anyOf(
iterAssert.containsAnyElementsOf(
Refaster.anyOf(
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element))),
iterAssert.containsAnyOf(element),
iterAssert.containsAll(
Refaster.anyOf(
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element))),
iterAssert.containsSequence(
Refaster.anyOf(
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element))),
iterAssert.containsSequence(element),
iterAssert.containsSubsequence(
Refaster.anyOf(
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element))),
iterAssert.containsSubsequence(element));
}
@@ -244,20 +216,7 @@ final class AssertJRules {
@BeforeTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T element) {
return Refaster.anyOf(
iterAssert.doesNotContainAnyElementsOf(
Refaster.anyOf(
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element))),
iterAssert.doesNotContainSequence(
Refaster.anyOf(
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element))),
iterAssert.doesNotContainSequence(element));
return iterAssert.doesNotContainSequence(element);
}
@AfterTemplate
@@ -270,25 +229,7 @@ final class AssertJRules {
static final class ObjectEnumerableContainsExactlyOneElement<S, T extends S> {
@BeforeTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T element) {
return Refaster.anyOf(
iterAssert.containsExactlyElementsOf(
Refaster.anyOf(
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element))),
iterAssert.containsExactlyInAnyOrderElementsOf(
Refaster.anyOf(
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element))));
}
@BeforeTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> before2(
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, @NotMatches(IsArray.class) T element) {
return iterAssert.containsExactlyInAnyOrder(element);
}
@@ -313,42 +254,6 @@ final class AssertJRules {
}
}
static final class ObjectEnumerableContainsOneDistinctElement<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T element) {
return iterAssert.hasSameElementsAs(
Refaster.anyOf(
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T element) {
return iterAssert.containsOnly(element);
}
}
static final class ObjectEnumerableIsSubsetOfOneElement<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T element) {
return iterAssert.isSubsetOf(
Refaster.anyOf(
ImmutableList.of(element),
Arrays.asList(element),
ImmutableSet.of(element),
ImmutableMultiset.of(element)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T element) {
return iterAssert.isSubsetOf(element);
}
}
//
// Iterable
//
@@ -359,6 +264,7 @@ final class AssertJRules {
Refaster.anyOf(
assertThat(iterable).hasSize(0),
assertThat(iterable.iterator().hasNext()).isFalse(),
assertThat(iterable.iterator()).isExhausted(),
assertThat(Iterables.size(iterable)).isEqualTo(0L),
assertThat(Iterables.size(iterable)).isNotPositive());
}
@@ -1155,824 +1061,6 @@ final class AssertJRules {
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// BELOW: Generated code.
//
// ObjectEnumerableAssert: containsAnyOf
//
static final class ObjectEnumerableContainsAnyOfTwoElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.containsAnyElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2),
Arrays.asList(e1, e2),
ImmutableSet.of(e1, e2),
ImmutableMultiset.of(e1, e2)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.containsAnyOf(e1, e2);
}
}
static final class ObjectEnumerableContainsAnyOfThreeElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.containsAnyElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3),
Arrays.asList(e1, e2, e3),
ImmutableSet.of(e1, e2, e3),
ImmutableMultiset.of(e1, e2, e3)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.containsAnyOf(e1, e2, e3);
}
}
static final class ObjectEnumerableContainsAnyOfFourElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.containsAnyElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4),
Arrays.asList(e1, e2, e3, e4),
ImmutableSet.of(e1, e2, e3, e4),
ImmutableMultiset.of(e1, e2, e3, e4)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.containsAnyOf(e1, e2, e3, e4);
}
}
// XXX: Add variants for 6+ elements?
static final class ObjectEnumerableContainsAnyOfFiveElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.containsAnyElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4, e5),
Arrays.asList(e1, e2, e3, e4, e5),
ImmutableSet.of(e1, e2, e3, e4, e5),
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.containsAnyOf(e1, e2, e3, e4, e5);
}
}
//
// ObjectEnumerableAssert: contains
//
static final class ObjectEnumerableContainsTwoElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.containsAll(
Refaster.anyOf(
ImmutableList.of(e1, e2),
Arrays.asList(e1, e2),
ImmutableSet.of(e1, e2),
ImmutableMultiset.of(e1, e2)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.contains(e1, e2);
}
}
static final class ObjectEnumerableContainsThreeElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.containsAll(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3),
Arrays.asList(e1, e2, e3),
ImmutableSet.of(e1, e2, e3),
ImmutableMultiset.of(e1, e2, e3)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.contains(e1, e2, e3);
}
}
static final class ObjectEnumerableContainsFourElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.containsAll(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4),
Arrays.asList(e1, e2, e3, e4),
ImmutableSet.of(e1, e2, e3, e4),
ImmutableMultiset.of(e1, e2, e3, e4)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.contains(e1, e2, e3, e4);
}
}
// XXX: Add variants for 6+ elements?
static final class ObjectEnumerableContainsFiveElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.containsAll(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4, e5),
Arrays.asList(e1, e2, e3, e4, e5),
ImmutableSet.of(e1, e2, e3, e4, e5),
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.contains(e1, e2, e3, e4, e5);
}
}
//
// ObjectEnumerableAssert: containsExactly
//
static final class ObjectEnumerableContainsExactlyTwoElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.containsExactlyElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2),
Arrays.asList(e1, e2),
ImmutableSet.of(e1, e2),
ImmutableMultiset.of(e1, e2)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.containsExactly(e1, e2);
}
}
static final class ObjectEnumerableContainsExactlyThreeElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.containsExactlyElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3),
Arrays.asList(e1, e2, e3),
ImmutableSet.of(e1, e2, e3),
ImmutableMultiset.of(e1, e2, e3)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.containsExactly(e1, e2, e3);
}
}
static final class ObjectEnumerableContainsExactlyFourElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.containsExactlyElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4),
Arrays.asList(e1, e2, e3, e4),
ImmutableSet.of(e1, e2, e3, e4),
ImmutableMultiset.of(e1, e2, e3, e4)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.containsExactly(e1, e2, e3, e4);
}
}
// XXX: Add variants for 6+ elements?
static final class ObjectEnumerableContainsExactlyFiveElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.containsExactlyElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4, e5),
Arrays.asList(e1, e2, e3, e4, e5),
ImmutableSet.of(e1, e2, e3, e4, e5),
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.containsExactly(e1, e2, e3, e4, e5);
}
}
//
// ObjectEnumerableAssert: containsExactlyInAnyOrder
//
static final class ObjectEnumerableContainsExactlyInAnyOrderTwoElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.containsExactlyInAnyOrderElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2),
Arrays.asList(e1, e2),
ImmutableSet.of(e1, e2),
ImmutableMultiset.of(e1, e2)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.containsExactlyInAnyOrder(e1, e2);
}
}
static final class ObjectEnumerableContainsExactlyInAnyOrderThreeElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.containsExactlyInAnyOrderElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3),
Arrays.asList(e1, e2, e3),
ImmutableSet.of(e1, e2, e3),
ImmutableMultiset.of(e1, e2, e3)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.containsExactlyInAnyOrder(e1, e2, e3);
}
}
static final class ObjectEnumerableContainsExactlyInAnyOrderFourElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.containsExactlyInAnyOrderElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4),
Arrays.asList(e1, e2, e3, e4),
ImmutableSet.of(e1, e2, e3, e4),
ImmutableMultiset.of(e1, e2, e3, e4)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.containsExactlyInAnyOrder(e1, e2, e3, e4);
}
}
// XXX: Add variants for 6+ elements?
static final class ObjectEnumerableContainsExactlyInAnyOrderFiveElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.containsExactlyInAnyOrderElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4, e5),
Arrays.asList(e1, e2, e3, e4, e5),
ImmutableSet.of(e1, e2, e3, e4, e5),
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.containsExactlyInAnyOrder(e1, e2, e3, e4, e5);
}
}
//
// ObjectEnumerableAssert: containsSequence
//
static final class ObjectEnumerableContainsSequenceTwoElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.containsSequence(
Refaster.anyOf(
ImmutableList.of(e1, e2),
Arrays.asList(e1, e2),
ImmutableSet.of(e1, e2),
ImmutableMultiset.of(e1, e2)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.containsSequence(e1, e2);
}
}
static final class ObjectEnumerableContainsSequenceThreeElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.containsSequence(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3),
Arrays.asList(e1, e2, e3),
ImmutableSet.of(e1, e2, e3),
ImmutableMultiset.of(e1, e2, e3)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.containsSequence(e1, e2, e3);
}
}
static final class ObjectEnumerableContainsSequenceFourElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.containsSequence(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4),
Arrays.asList(e1, e2, e3, e4),
ImmutableSet.of(e1, e2, e3, e4),
ImmutableMultiset.of(e1, e2, e3, e4)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.containsSequence(e1, e2, e3, e4);
}
}
// XXX: Add variants for 6+ elements?
static final class ObjectEnumerableContainsSequenceFiveElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.containsSequence(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4, e5),
Arrays.asList(e1, e2, e3, e4, e5),
ImmutableSet.of(e1, e2, e3, e4, e5),
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.containsSequence(e1, e2, e3, e4, e5);
}
}
//
// ObjectEnumerableAssert: containsSubsequence
//
static final class ObjectEnumerableContainsSubsequenceTwoElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.containsSubsequence(
Refaster.anyOf(
ImmutableList.of(e1, e2),
Arrays.asList(e1, e2),
ImmutableSet.of(e1, e2),
ImmutableMultiset.of(e1, e2)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.containsSubsequence(e1, e2);
}
}
static final class ObjectEnumerableContainsSubsequenceThreeElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.containsSubsequence(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3),
Arrays.asList(e1, e2, e3),
ImmutableSet.of(e1, e2, e3),
ImmutableMultiset.of(e1, e2, e3)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.containsSubsequence(e1, e2, e3);
}
}
static final class ObjectEnumerableContainsSubsequenceFourElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.containsSubsequence(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4),
Arrays.asList(e1, e2, e3, e4),
ImmutableSet.of(e1, e2, e3, e4),
ImmutableMultiset.of(e1, e2, e3, e4)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.containsSubsequence(e1, e2, e3, e4);
}
}
// XXX: Add variants for 6+ elements?
static final class ObjectEnumerableContainsSubsequenceFiveElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.containsSubsequence(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4, e5),
Arrays.asList(e1, e2, e3, e4, e5),
ImmutableSet.of(e1, e2, e3, e4, e5),
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.containsSubsequence(e1, e2, e3, e4, e5);
}
}
//
// ObjectEnumerableAssert: doesNotContain
//
static final class ObjectEnumerableDoesNotContainTwoElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.doesNotContainAnyElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2),
Arrays.asList(e1, e2),
ImmutableSet.of(e1, e2),
ImmutableMultiset.of(e1, e2)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.doesNotContain(e1, e2);
}
}
static final class ObjectEnumerableDoesNotContainThreeElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.doesNotContainAnyElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3),
Arrays.asList(e1, e2, e3),
ImmutableSet.of(e1, e2, e3),
ImmutableMultiset.of(e1, e2, e3)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.doesNotContain(e1, e2, e3);
}
}
static final class ObjectEnumerableDoesNotContainFourElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.doesNotContainAnyElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4),
Arrays.asList(e1, e2, e3, e4),
ImmutableSet.of(e1, e2, e3, e4),
ImmutableMultiset.of(e1, e2, e3, e4)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.doesNotContain(e1, e2, e3, e4);
}
}
// XXX: Add variants for 6+ elements?
static final class ObjectEnumerableDoesNotContainFiveElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.doesNotContainAnyElementsOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4, e5),
Arrays.asList(e1, e2, e3, e4, e5),
ImmutableSet.of(e1, e2, e3, e4, e5),
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.doesNotContain(e1, e2, e3, e4, e5);
}
}
//
// ObjectEnumerableAssert: doesNotContainSequence
//
static final class ObjectEnumerableDoesNotContainSequenceTwoElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.doesNotContainSequence(
Refaster.anyOf(
ImmutableList.of(e1, e2),
Arrays.asList(e1, e2),
ImmutableSet.of(e1, e2),
ImmutableMultiset.of(e1, e2)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.doesNotContainSequence(e1, e2);
}
}
static final class ObjectEnumerableDoesNotContainSequenceThreeElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.doesNotContainSequence(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3),
Arrays.asList(e1, e2, e3),
ImmutableSet.of(e1, e2, e3),
ImmutableMultiset.of(e1, e2, e3)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.doesNotContainSequence(e1, e2, e3);
}
}
static final class ObjectEnumerableDoesNotContainSequenceFourElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.doesNotContainSequence(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4),
Arrays.asList(e1, e2, e3, e4),
ImmutableSet.of(e1, e2, e3, e4),
ImmutableMultiset.of(e1, e2, e3, e4)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.doesNotContainSequence(e1, e2, e3, e4);
}
}
// XXX: Add variants for 6+ elements?
static final class ObjectEnumerableDoesNotContainSequenceFiveElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.doesNotContainSequence(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4, e5),
Arrays.asList(e1, e2, e3, e4, e5),
ImmutableSet.of(e1, e2, e3, e4, e5),
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.doesNotContainSequence(e1, e2, e3, e4, e5);
}
}
//
// ObjectEnumerableAssert: containsOnly
//
static final class ObjectEnumerableContainsOnlyTwoElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.hasSameElementsAs(
Refaster.anyOf(
ImmutableList.of(e1, e2),
Arrays.asList(e1, e2),
ImmutableSet.of(e1, e2),
ImmutableMultiset.of(e1, e2)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.containsOnly(e1, e2);
}
}
static final class ObjectEnumerableContainsOnlyThreeElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.hasSameElementsAs(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3),
Arrays.asList(e1, e2, e3),
ImmutableSet.of(e1, e2, e3),
ImmutableMultiset.of(e1, e2, e3)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.containsOnly(e1, e2, e3);
}
}
static final class ObjectEnumerableContainsOnlyFourElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.hasSameElementsAs(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4),
Arrays.asList(e1, e2, e3, e4),
ImmutableSet.of(e1, e2, e3, e4),
ImmutableMultiset.of(e1, e2, e3, e4)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.containsOnly(e1, e2, e3, e4);
}
}
// XXX: Add variants for 6+ elements?
static final class ObjectEnumerableContainsOnlyFiveElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.hasSameElementsAs(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4, e5),
Arrays.asList(e1, e2, e3, e4, e5),
ImmutableSet.of(e1, e2, e3, e4, e5),
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.containsOnly(e1, e2, e3, e4, e5);
}
}
//
// ObjectEnumerableAssert: isSubsetOf
//
static final class ObjectEnumerableIsSubsetOfTwoElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.isSubsetOf(
Refaster.anyOf(
ImmutableList.of(e1, e2),
Arrays.asList(e1, e2),
ImmutableSet.of(e1, e2),
ImmutableMultiset.of(e1, e2)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
return iterAssert.isSubsetOf(e1, e2);
}
}
static final class ObjectEnumerableIsSubsetOfThreeElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.isSubsetOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3),
Arrays.asList(e1, e2, e3),
ImmutableSet.of(e1, e2, e3),
ImmutableMultiset.of(e1, e2, e3)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
return iterAssert.isSubsetOf(e1, e2, e3);
}
}
static final class ObjectEnumerableIsSubsetOfFourElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.isSubsetOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4),
Arrays.asList(e1, e2, e3, e4),
ImmutableSet.of(e1, e2, e3, e4),
ImmutableMultiset.of(e1, e2, e3, e4)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
return iterAssert.isSubsetOf(e1, e2, e3, e4);
}
}
// XXX: Add variants for 6+ elements?
static final class ObjectEnumerableIsSubsetOfFiveElements<S, T extends S> {
@BeforeTemplate
ObjectEnumerableAssert<?, S> before(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.isSubsetOf(
Refaster.anyOf(
ImmutableList.of(e1, e2, e3, e4, e5),
Arrays.asList(e1, e2, e3, e4, e5),
ImmutableSet.of(e1, e2, e3, e4, e5),
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ObjectEnumerableAssert<?, S> after(
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
return iterAssert.isSubsetOf(e1, e2, e3, e4, e5);
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Above: Generated code.
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Organize the code below.

View File

@@ -12,6 +12,7 @@ import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractBooleanAssert;
import org.assertj.core.api.AbstractStringAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@@ -69,6 +70,32 @@ final class AssertJStringRules {
}
}
static final class AssertThatStringContains {
@BeforeTemplate
AbstractBooleanAssert<?> before(String string, String substring) {
return assertThat(string.contains(substring)).isTrue();
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractStringAssert<?> after(String string, String substring) {
return assertThat(string).contains(substring);
}
}
static final class AssertThatStringDoesNotContain {
@BeforeTemplate
AbstractBooleanAssert<?> before(String string, String substring) {
return assertThat(string.contains(substring)).isFalse();
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractStringAssert<?> after(String string, String substring) {
return assertThat(string).doesNotContain(substring);
}
}
static final class AssertThatMatches {
@BeforeTemplate
AbstractAssert<?, ?> before(String string, String regex) {

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.assertThatNullPointerException;
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.BeforeTemplate;
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.AbstractThrowableAssert;
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
import org.assertj.core.api.ThrowableAssertAlternative;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/**
@@ -31,6 +35,21 @@ import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class 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 {
@BeforeTemplate
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 {
@BeforeTemplate
@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 {
@BeforeTemplate
@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 {
@BeforeTemplate
@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 {
@BeforeTemplate
@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
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, Class<? extends Throwable> exceptionType) {
ThrowableAssertAlternative<T> before(
ThrowingCallable throwingCallable, Class<T> exceptionType) {
return assertThatExceptionOfType(exceptionType).isThrownBy(throwingCallable);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
ThrowingCallable throwingCallable, Class<? extends Throwable> exceptionType) {
return assertThatThrownBy(throwingCallable).isInstanceOf(exceptionType);
AbstractThrowableAssert<?, T> after(ThrowingCallable throwingCallable, Class<T> exceptionType) {
return assertThatThrownBy(throwingCallable).asInstanceOf(throwable(exceptionType));
}
}
static final class AssertThatThrownByHasMessage {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
@SuppressWarnings(
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable,
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 {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
@SuppressWarnings(
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
@@ -517,7 +647,8 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByHasMessageStartingWith {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
@SuppressWarnings(
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
@@ -541,7 +672,8 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByHasMessageContaining {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
@SuppressWarnings(
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,
@@ -565,7 +697,8 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByHasMessageNotContaining {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
@SuppressWarnings(
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable,
Class<? extends Throwable> exceptionType,

View File

@@ -1,8 +1,6 @@
package tech.picnic.errorprone.refasterrules;
import static com.google.common.base.Preconditions.checkElementIndex;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Sets.toImmutableEnumSet;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Collections.disjoint;
import static java.util.Objects.checkIndex;
@@ -70,28 +68,6 @@ final class AssortedRules {
}
}
/**
* Use {@link Sets#toImmutableEnumSet()} when possible, as it is more efficient than {@link
* ImmutableSet#toImmutableSet()} and produces a more compact object.
*
* <p><strong>Warning:</strong> this rewrite rule is not completely behavior preserving: while the
* original code produces a set that iterates over the elements in encounter order, the
* replacement code iterates over the elements in enum definition order.
*/
// XXX: ^ Consider emitting a comment warning about this fact?
static final class StreamToImmutableEnumSet<T extends Enum<T>> {
@BeforeTemplate
ImmutableSet<T> before(Stream<T> stream) {
return stream.collect(toImmutableSet());
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ImmutableSet<T> after(Stream<T> stream) {
return stream.collect(toImmutableEnumSet());
}
}
/** Prefer {@link Iterators#getNext(Iterator, Object)} over more contrived alternatives. */
static final class IteratorGetNextOrDefault<T> {
@BeforeTemplate

View File

@@ -9,7 +9,9 @@ import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.sun.tools.javac.util.Constants;
import com.sun.tools.javac.util.Convert;
import javax.lang.model.element.Name;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.utils.SourceCode;
/** Refaster rules related to {@link com.google.errorprone.bugpatterns.BugChecker} classes. */
@OnlineDocumentation
@@ -55,16 +57,44 @@ 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 {
@BeforeTemplate
String before(CharSequence value) {
return Constants.format(value);
}
@BeforeTemplate
String before(String value) {
return String.format("\"%s\"", Convert.quote(value));
}
@AfterTemplate
String after(String value) {
return Constants.format(value);
String after(CharSequence value) {
return SourceCode.toStringConstantExpression(
value, Refaster.emitCommentBefore("REPLACEME", null));
}
}
/** Prefer {@link Name#contentEquals(CharSequence)} over more verbose alternatives. */
static final class NameContentEquals {
@BeforeTemplate
boolean before(Name name, CharSequence string) {
return name.toString().equals(string.toString());
}
@BeforeTemplate
boolean before(Name name, String string) {
return name.toString().equals(string);
}
@AfterTemplate
boolean after(Name name, CharSequence string) {
return name.contentEquals(string);
}
}
}

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

@@ -3,6 +3,7 @@ package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import java.util.function.Function;
import java.util.function.Predicate;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@@ -37,7 +38,12 @@ final class ClassRules {
}
}
/** Prefer {@link Class#isInstance(Object)} method references over more verbose alternatives. */
/**
* Prefer {@link Class#isInstance(Object)} method references over lambda expressions that require
* naming a variable.
*/
// XXX: Once the `ClassReferenceIsInstancePredicate` rule is dropped, rename this rule to just
// `ClassIsInstancePredicate`.
static final class ClassLiteralIsInstancePredicate<T, S> {
@BeforeTemplate
Predicate<S> before() {
@@ -50,7 +56,11 @@ final class ClassRules {
}
}
/** Prefer {@link Class#isInstance(Object)} method references over more verbose alternatives. */
/**
* Prefer {@link Class#isInstance(Object)} method references over lambda expressions that require
* naming a variable.
*/
// XXX: Drop this rule once the `MethodReferenceUsage` rule is enabled by default.
static final class ClassReferenceIsInstancePredicate<T, S> {
@BeforeTemplate
Predicate<S> before(Class<T> clazz) {
@@ -62,4 +72,21 @@ final class ClassRules {
return clazz::isInstance;
}
}
/**
* Prefer {@link Class#cast(Object)} method references over lambda expressions that require naming
* a variable.
*/
// XXX: Drop this rule once the `MethodReferenceUsage` rule is enabled by default.
static final class ClassReferenceCast<T, S> {
@BeforeTemplate
Function<T, S> before(Class<? extends S> clazz) {
return o -> clazz.cast(o);
}
@AfterTemplate
Function<T, S> after(Class<? extends S> clazz) {
return clazz::cast;
}
}
}

View File

@@ -8,7 +8,9 @@ import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.NotMatches;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
@@ -21,6 +23,7 @@ import java.util.function.Consumer;
import java.util.function.IntFunction;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.matchers.IsRefasterAsVarargs;
/** Refaster rules related to expressions dealing with (arbitrary) collections. */
// XXX: There are other Guava `Iterables` methods that should not be called if the input is known to
@@ -184,6 +187,24 @@ final class CollectionRules {
}
}
/** Don't unnecessarily call {@link Stream#distinct()} on an already-unique stream of elements. */
// XXX: This rule assumes that the `Set` relies on `Object#equals`, rather than a custom
// equivalence relation.
// XXX: Expressions that drop or reorder elements from the stream, such as `.filter`, `.skip` and
// `sorted`, can similarly be simplified. Covering all cases is better done using an Error Prone
// check.
static final class SetStream<T> {
@BeforeTemplate
Stream<?> before(Set<T> set) {
return set.stream().distinct();
}
@AfterTemplate
Stream<?> after(Set<T> set) {
return set.stream();
}
}
/** Prefer {@link ArrayList#ArrayList(Collection)} over the Guava alternative. */
@SuppressWarnings(
"NonApiType" /* Matching against `List` would unnecessarily constrain the rule. */)
@@ -276,6 +297,23 @@ final class CollectionRules {
}
}
/** Prefer {@link Arrays#asList(Object[])} over more contrived alternatives. */
// XXX: Consider moving this rule to `ImmutableListRules` and having it suggest
// `ImmutableList#copyOf`. That would retain immutability, at the cost of no longer handling
// `null`s.
static final class ArraysAsList<T> {
// XXX: This expression produces an unmodifiable list, while the alternative doesn't.
@BeforeTemplate
List<T> before(@NotMatches(IsRefasterAsVarargs.class) T[] array) {
return Arrays.stream(array).toList();
}
@AfterTemplate
List<T> after(T[] array) {
return Arrays.asList(array);
}
}
/** Prefer calling {@link Collection#toArray()} over more contrived alternatives. */
static final class CollectionToArray<T> {
@BeforeTemplate
@@ -327,18 +365,20 @@ final class CollectionRules {
}
}
/**
* Don't call {@link ImmutableCollection#asList()} if {@link ImmutableCollection#iterator()} is
* called on the result; call it directly.
*/
static final class ImmutableCollectionIterator<T> {
/** Prefer {@link Collection#iterator()} over more contrived or less efficient alternatives. */
static final class CollectionIterator<T> {
@BeforeTemplate
Iterator<T> before(Collection<T> collection) {
return collection.stream().iterator();
}
@BeforeTemplate
Iterator<T> before(ImmutableCollection<T> collection) {
return collection.asList().iterator();
}
@AfterTemplate
Iterator<T> after(ImmutableCollection<T> collection) {
Iterator<T> after(Collection<T> collection) {
return collection.iterator();
}
}

View File

@@ -24,8 +24,10 @@ import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.Repeated;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.function.Function;
@@ -243,18 +245,77 @@ final class ComparatorRules {
}
}
/** Prefer {@link Collections#sort(List)} over more verbose alternatives. */
static final class CollectionsSort<T extends Comparable<? super T>> {
@BeforeTemplate
void before(List<T> collection) {
Collections.sort(collection, naturalOrder());
}
@AfterTemplate
void after(List<T> collection) {
Collections.sort(collection);
}
}
/** Prefer {@link Collections#min(Collection)} over more verbose alternatives. */
static final class CollectionsMin<T extends Comparable<? super T>> {
@BeforeTemplate
T before(Collection<T> collection) {
return Refaster.anyOf(
Collections.min(collection, naturalOrder()), Collections.max(collection, reverseOrder()));
}
@AfterTemplate
T after(Collection<T> collection) {
return Collections.min(collection);
}
}
/**
* Avoid unnecessary creation of a {@link Stream} to determine the minimum of a known collection
* of values.
*/
static final class MinOfVarargs<T> {
static final class MinOfArray<S, T extends S> {
@BeforeTemplate
T before(@Repeated T value, Comparator<T> cmp) {
T before(T[] array, Comparator<S> cmp) {
return Arrays.stream(array).min(cmp).orElseThrow();
}
@AfterTemplate
T after(T[] array, Comparator<S> cmp) {
return Collections.min(Arrays.asList(array), cmp);
}
}
/**
* Avoid unnecessary creation of a {@link Stream} to determine the minimum of a known collection
* of values.
*/
static final class CollectionsMinWithComparator<S, T extends S> {
@BeforeTemplate
T before(Collection<T> collection, Comparator<S> cmp) {
return collection.stream().min(cmp).orElseThrow();
}
@AfterTemplate
T after(Collection<T> collection, Comparator<S> cmp) {
return Collections.min(collection, cmp);
}
}
/**
* Avoid unnecessary creation of a {@link Stream} to determine the minimum of a known collection
* of values.
*/
static final class MinOfVarargs<S, T extends S> {
@BeforeTemplate
T before(@Repeated T value, Comparator<S> cmp) {
return Stream.of(Refaster.asVarargs(value)).min(cmp).orElseThrow();
}
@AfterTemplate
T after(@Repeated T value, Comparator<T> cmp) {
T after(@Repeated T value, Comparator<S> cmp) {
return Collections.min(Arrays.asList(value), cmp);
}
}
@@ -310,18 +371,64 @@ final class ComparatorRules {
}
}
/** Prefer {@link Collections#max(Collection)} over more verbose alternatives. */
static final class CollectionsMax<T extends Comparable<? super T>> {
@BeforeTemplate
T before(Collection<T> collection) {
return Refaster.anyOf(
Collections.max(collection, naturalOrder()), Collections.min(collection, reverseOrder()));
}
@AfterTemplate
T after(Collection<T> collection) {
return Collections.max(collection);
}
}
/**
* Avoid unnecessary creation of a {@link Stream} to determine the maximum of a known collection
* of values.
*/
static final class MaxOfVarargs<T> {
static final class MaxOfArray<S, T extends S> {
@BeforeTemplate
T before(@Repeated T value, Comparator<T> cmp) {
T before(T[] array, Comparator<S> cmp) {
return Arrays.stream(array).max(cmp).orElseThrow();
}
@AfterTemplate
T after(T[] array, Comparator<S> cmp) {
return Collections.max(Arrays.asList(array), cmp);
}
}
/**
* Avoid unnecessary creation of a {@link Stream} to determine the maximum of a known collection
* of values.
*/
static final class CollectionsMaxWithComparator<S, T extends S> {
@BeforeTemplate
T before(Collection<T> collection, Comparator<S> cmp) {
return collection.stream().max(cmp).orElseThrow();
}
@AfterTemplate
T after(Collection<T> collection, Comparator<S> cmp) {
return Collections.max(collection, cmp);
}
}
/**
* Avoid unnecessary creation of a {@link Stream} to determine the maximum of a known collection
* of values.
*/
static final class MaxOfVarargs<S, T extends S> {
@BeforeTemplate
T before(@Repeated T value, Comparator<S> cmp) {
return Stream.of(Refaster.asVarargs(value)).max(cmp).orElseThrow();
}
@AfterTemplate
T after(@Repeated T value, Comparator<T> cmp) {
T after(@Repeated T value, Comparator<S> cmp) {
return Collections.max(Arrays.asList(value), cmp);
}
}

View File

@@ -2,12 +2,18 @@ package tech.picnic.errorprone.refasterrules;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Repeated;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileAttribute;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster rules related to expressions dealing with files. */
@@ -15,6 +21,49 @@ import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class FileRules {
private FileRules() {}
/** Prefer the more idiomatic {@link Path#of(URI)} over {@link Paths#get(URI)}. */
static final class PathOfUri {
@BeforeTemplate
Path before(URI uri) {
return Paths.get(uri);
}
@AfterTemplate
Path after(URI uri) {
return Path.of(uri);
}
}
/**
* Prefer the more idiomatic {@link Path#of(String, String...)} over {@link Paths#get(String,
* String...)}.
*/
static final class PathOfString {
@BeforeTemplate
Path before(String first, @Repeated String more) {
return Paths.get(first, more);
}
@AfterTemplate
Path after(String first, @Repeated String more) {
return Path.of(first, more);
}
}
/** Avoid redundant conversions from {@link Path} to {@link File}. */
// XXX: Review whether a rule such as this one is better handled by the `IdentityConversion` rule.
static final class PathInstance {
@BeforeTemplate
Path before(Path path) {
return path.toFile().toPath();
}
@AfterTemplate
Path after(Path path) {
return path;
}
}
/** Prefer {@link Files#readString(Path, Charset)} over more contrived alternatives. */
static final class FilesReadStringWithCharset {
@BeforeTemplate
@@ -40,4 +89,56 @@ final class FileRules {
return Files.readString(path);
}
}
/**
* Prefer {@link Files#createTempFile(String, String, FileAttribute[])} over alternatives 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 FilesCreateTempFileToFile {
@BeforeTemplate
@SuppressWarnings({
"FilesCreateTempFileInCustomDirectoryToFile" /* This is a more specific template. */,
"java:S5443" /* This violation will be rewritten. */,
"key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict"
})
File before(String prefix, String suffix) throws IOException {
return Refaster.anyOf(
File.createTempFile(prefix, suffix), File.createTempFile(prefix, suffix, null));
}
@AfterTemplate
@SuppressWarnings(
"java:S5443" /* On POSIX systems the file will only have user read-write permissions. */)
File after(String prefix, String suffix) throws IOException {
return Files.createTempFile(prefix, suffix).toFile();
}
}
/**
* Prefer {@link Files#createTempFile(Path, String, String, FileAttribute[])} over alternatives
* 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 {
@BeforeTemplate
File before(File directory, String prefix, String suffix) throws IOException {
return File.createTempFile(prefix, suffix, directory);
}
@AfterTemplate
File after(File directory, String prefix, String suffix) throws IOException {
return Files.createTempFile(directory.toPath(), prefix, suffix).toFile();
}
}
}

View File

@@ -0,0 +1,246 @@
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Sets.toImmutableEnumSet;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.Repeated;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/**
* Refaster rules related to expressions dealing with {@code
* com.google.common.collect.ImmutableEnumSet}s.
*/
// XXX: Some of the rules defined here impact iteration order. That's a rather subtle change. Should
// we emit a comment warning about this fact? (This may produce a lot of noise. A bug checker could
// in some cases determine whether iteration order is important.)
// XXX: Consider replacing the `SetsImmutableEnumSet[N]` Refaster rules with a bug checker, such
// that call to `ImmutableSet#of(Object, Object, Object, Object, Object, Object, Object[])` with
// enum-typed values can also be rewritten.
@OnlineDocumentation
final class ImmutableEnumSetRules {
private ImmutableEnumSetRules() {}
/**
* Prefer {@link Sets#immutableEnumSet(Iterable)} for enum collections to take advantage of the
* internally used {@link EnumSet}.
*
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the
* original code produces a set that iterates over its elements in the same order as the input
* {@link Iterable}, the replacement code iterates over the elements in enum definition order.
*/
static final class SetsImmutableEnumSetIterable<T extends Enum<T>> {
@BeforeTemplate
ImmutableSet<T> before(Iterable<T> elements) {
return ImmutableSet.copyOf(elements);
}
@BeforeTemplate
ImmutableSet<T> before(Collection<T> elements) {
return ImmutableSet.copyOf(elements);
}
@AfterTemplate
ImmutableSet<T> after(Iterable<T> elements) {
return Sets.immutableEnumSet(elements);
}
}
/**
* Prefer {@link Sets#immutableEnumSet(Iterable)} for enum collections to take advantage of the
* internally used {@link EnumSet}.
*
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the
* original code produces a set that iterates over its elements in the same order as defined in
* the array, the replacement code iterates over the elements in enum definition order.
*/
static final class SetsImmutableEnumSetArraysAsList<T extends Enum<T>> {
@BeforeTemplate
ImmutableSet<T> before(T[] elements) {
return ImmutableSet.copyOf(elements);
}
@AfterTemplate
ImmutableSet<T> after(T[] elements) {
return Sets.immutableEnumSet(Arrays.asList(elements));
}
}
/**
* Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
* the internally used {@link EnumSet}.
*/
static final class SetsImmutableEnumSet1<T extends Enum<T>> {
@BeforeTemplate
@SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
ImmutableSet<T> before(T e1) {
return Refaster.anyOf(ImmutableSet.of(e1), ImmutableSet.copyOf(EnumSet.of(e1)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ImmutableSet<T> after(T e1) {
return Sets.immutableEnumSet(e1);
}
}
/**
* Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
* the internally used {@link EnumSet}.
*
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the {@link
* ImmutableSet#of} expression produces a set that iterates over its elements in the listed order,
* the replacement code iterates over the elements in enum definition order.
*/
static final class SetsImmutableEnumSet2<T extends Enum<T>> {
@BeforeTemplate
@SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
ImmutableSet<T> before(T e1, T e2) {
return Refaster.anyOf(ImmutableSet.of(e1, e2), ImmutableSet.copyOf(EnumSet.of(e1, e2)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ImmutableSet<T> after(T e1, T e2) {
return Sets.immutableEnumSet(e1, e2);
}
}
/**
* Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
* the internally used {@link EnumSet}.
*
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the {@link
* ImmutableSet#of} expression produces a set that iterates over its elements in the listed order,
* the replacement code iterates over the elements in enum definition order.
*/
static final class SetsImmutableEnumSet3<T extends Enum<T>> {
@BeforeTemplate
@SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
ImmutableSet<T> before(T e1, T e2, T e3) {
return Refaster.anyOf(
ImmutableSet.of(e1, e2, e3), ImmutableSet.copyOf(EnumSet.of(e1, e2, e3)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ImmutableSet<T> after(T e1, T e2, T e3) {
return Sets.immutableEnumSet(e1, e2, e3);
}
}
/**
* Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
* the internally used {@link EnumSet}.
*
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the {@link
* ImmutableSet#of} expression produces a set that iterates over its elements in the listed order,
* the replacement code iterates over the elements in enum definition order.
*/
static final class SetsImmutableEnumSet4<T extends Enum<T>> {
@BeforeTemplate
@SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
ImmutableSet<T> before(T e1, T e2, T e3, T e4) {
return Refaster.anyOf(
ImmutableSet.of(e1, e2, e3, e4), ImmutableSet.copyOf(EnumSet.of(e1, e2, e3, e4)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ImmutableSet<T> after(T e1, T e2, T e3, T e4) {
return Sets.immutableEnumSet(e1, e2, e3, e4);
}
}
/**
* Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
* the internally used {@link EnumSet}.
*
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the {@link
* ImmutableSet#of} expression produces a set that iterates over its elements in the listed order,
* the replacement code iterates over the elements in enum definition order.
*/
static final class SetsImmutableEnumSet5<T extends Enum<T>> {
@BeforeTemplate
@SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
ImmutableSet<T> before(T e1, T e2, T e3, T e4, T e5) {
return Refaster.anyOf(
ImmutableSet.of(e1, e2, e3, e4, e5), ImmutableSet.copyOf(EnumSet.of(e1, e2, e3, e4, e5)));
}
@AfterTemplate
@SuppressWarnings("unchecked")
ImmutableSet<T> after(T e1, T e2, T e3, T e4, T e5) {
return Sets.immutableEnumSet(e1, e2, e3, e4, e5);
}
}
/**
* Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
* the internally used {@link EnumSet}.
*
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the
* original code produces a set that iterates over its elements in the listed order, the
* replacement code iterates over the elements in enum definition order.
*/
static final class SetsImmutableEnumSet6<T extends Enum<T>> {
@BeforeTemplate
ImmutableSet<T> before(T e1, T e2, T e3, T e4, T e5, T e6) {
return ImmutableSet.of(e1, e2, e3, e4, e5, e6);
}
@AfterTemplate
@SuppressWarnings("unchecked")
ImmutableSet<T> after(T e1, T e2, T e3, T e4, T e5, T e6) {
return Sets.immutableEnumSet(e1, e2, e3, e4, e5, e6);
}
}
/**
* Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
* the internally used {@link EnumSet}.
*/
static final class SetsImmutableEnumSetVarArgs<T extends Enum<T>> {
@BeforeTemplate
@SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
ImmutableSet<T> before(T e1, @Repeated T elements) {
return ImmutableSet.copyOf(EnumSet.of(e1, Refaster.asVarargs(elements)));
}
@AfterTemplate
ImmutableSet<T> after(T e1, @Repeated T elements) {
return Sets.immutableEnumSet(e1, Refaster.asVarargs(elements));
}
}
/**
* Use {@link Sets#toImmutableEnumSet()} when possible, as it is more efficient than {@link
* ImmutableSet#toImmutableSet()} and produces a more compact object.
*
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the
* original code produces a set that iterates over its elements in encounter order, the
* replacement code iterates over the elements in enum definition order.
*/
static final class StreamToImmutableEnumSet<T extends Enum<T>> {
@BeforeTemplate
ImmutableSet<T> before(Stream<T> stream) {
return stream.collect(toImmutableSet());
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
ImmutableSet<T> after(Stream<T> stream) {
return stream.collect(toImmutableEnumSet());
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -37,8 +37,7 @@ final class ImmutableSortedMapRules {
* Prefer {@link ImmutableSortedMap#naturalOrder()} over the alternative that requires explicitly
* providing the {@link Comparator}.
*/
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
// https://github.com/google/error-prone/pull/2706.
// XXX: This rule may drop generic type information, leading to non-compilable code.
static final class ImmutableSortedMapNaturalOrderBuilder<K extends Comparable<? super K>, V> {
@BeforeTemplate
ImmutableSortedMap.Builder<K, V> before() {
@@ -55,8 +54,7 @@ final class ImmutableSortedMapRules {
* Prefer {@link ImmutableSortedMap#reverseOrder()} over the alternative that requires explicitly
* providing the {@link Comparator}.
*/
// XXX: This drops generic type information, sometimes leading to non-compilable code. See
// https://github.com/google/error-prone/pull/2706.
// XXX: This rule may drop generic type information, leading to non-compilable code.
static final class ImmutableSortedMapReverseOrderBuilder<K extends Comparable<? super K>, V> {
@BeforeTemplate
ImmutableSortedMap.Builder<K, V> before() {

View File

@@ -0,0 +1,88 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster rules related to expressions dealing with Micrometer. */
// XXX: Consider replacing the `TagsOf[N]` rules with a bug checker, so that various other
// expressions (e.g. those creating other collection types, those passing in tags some other way, or
// those passing in more tags) can be replaced as wel.
@OnlineDocumentation
final class MicrometerRules {
private MicrometerRules() {}
/** Prefer using {@link Tags} over other immutable collections. */
static final class TagsOf1 {
@BeforeTemplate
ImmutableCollection<Tag> before(Tag tag) {
return Refaster.anyOf(ImmutableSet.of(tag), ImmutableList.of(tag));
}
@AfterTemplate
Iterable<Tag> after(Tag tag) {
return Tags.of(tag);
}
}
/** Prefer using {@link Tags} over other immutable collections. */
static final class TagsOf2 {
@BeforeTemplate
ImmutableCollection<Tag> before(Tag tag1, Tag tag2) {
return Refaster.anyOf(ImmutableSet.of(tag1, tag2), ImmutableList.of(tag1, tag2));
}
@AfterTemplate
Iterable<Tag> after(Tag tag1, Tag tag2) {
return Tags.of(tag1, tag2);
}
}
/** Prefer using {@link Tags} over other immutable collections. */
static final class TagsOf3 {
@BeforeTemplate
ImmutableCollection<Tag> before(Tag tag1, Tag tag2, Tag tag3) {
return Refaster.anyOf(ImmutableSet.of(tag1, tag2, tag3), ImmutableList.of(tag1, tag2, tag3));
}
@AfterTemplate
Iterable<Tag> after(Tag tag1, Tag tag2, Tag tag3) {
return Tags.of(tag1, tag2, tag3);
}
}
/** Prefer using {@link Tags} over other immutable collections. */
static final class TagsOf4 {
@BeforeTemplate
ImmutableCollection<Tag> before(Tag tag1, Tag tag2, Tag tag3, Tag tag4) {
return Refaster.anyOf(
ImmutableSet.of(tag1, tag2, tag3, tag4), ImmutableList.of(tag1, tag2, tag3, tag4));
}
@AfterTemplate
Iterable<Tag> after(Tag tag1, Tag tag2, Tag tag3, Tag tag4) {
return Tags.of(tag1, tag2, tag3, tag4);
}
}
/** Prefer using {@link Tags} over other immutable collections. */
static final class TagsOf5 {
@BeforeTemplate
ImmutableCollection<Tag> before(Tag tag1, Tag tag2, Tag tag3, Tag tag4, Tag tag5) {
return Refaster.anyOf(
ImmutableSet.of(tag1, tag2, tag3, tag4, tag5),
ImmutableList.of(tag1, tag2, tag3, tag4, tag5));
}
@AfterTemplate
Iterable<Tag> after(Tag tag1, Tag tag2, Tag tag3, Tag tag4, Tag tag5) {
return Tags.of(tag1, tag2, tag3, tag4, tag5);
}
}
}

View File

@@ -20,7 +20,7 @@ import java.util.function.Supplier;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.matchers.IsLikelyTrivialComputation;
import tech.picnic.errorprone.refaster.matchers.RequiresComputation;
/** Refaster rules related to expressions dealing with {@link Optional}s. */
@OnlineDocumentation
@@ -255,24 +255,21 @@ final class OptionalRules {
}
/**
* Prefer {@link Optional#orElseGet(Supplier)} over {@link Optional#orElse(Object)} if the
* fallback value is not the result of a trivial computation.
* Prefer {@link Optional#orElse(Object)} over {@link Optional#orElseGet(Supplier)} if the
* fallback value does not require non-trivial computation.
*/
// XXX: This rule may introduce a compilation error: the `value` expression may reference a
// non-effectively final variable, which is not allowed in the replacement lambda expression.
// Review whether a `@Matcher` can be used to avoid this.
// XXX: Once `MethodReferenceUsage` is "production ready", replace
// `@NotMatches(IsLikelyTrivialComputation.class)` with `@Matches(RequiresComputation.class)` (and
// reimplement the matcher accordingly).
static final class OptionalOrElseGet<T> {
// XXX: This rule is the counterpart to the `OptionalOrElseGet` bug checker. Once the
// `MethodReferenceUsage` bug checker is "production ready", that bug checker may similarly be
// replaced with a Refaster rule.
static final class OptionalOrElse<T> {
@BeforeTemplate
T before(Optional<T> optional, @NotMatches(IsLikelyTrivialComputation.class) T value) {
return optional.orElse(value);
T before(Optional<T> optional, @NotMatches(RequiresComputation.class) T value) {
return optional.orElseGet(() -> value);
}
@AfterTemplate
T after(Optional<T> optional, T value) {
return optional.orElseGet(() -> value);
return optional.orElse(value);
}
}
@@ -282,6 +279,9 @@ final class OptionalRules {
*/
// 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.)
// 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.)
static final class StreamFlatMapOptional<T> {
@BeforeTemplate
Stream<T> before(Stream<Optional<T>> stream) {
@@ -373,7 +373,12 @@ final class OptionalRules {
/** Prefer {@link Optional#or(Supplier)} over more verbose alternatives. */
static final class OptionalOrOtherOptional<T> {
@BeforeTemplate
@SuppressWarnings("NestedOptionals")
@SuppressWarnings({
"LexicographicalAnnotationAttributeListing" /* `key-*` entry must remain last. */,
"NestedOptionals" /* This violation will be rewritten. */,
"OptionalOrElse" /* Parameters represent expressions that may require computation. */,
"key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict"
})
Optional<T> before(Optional<T> optional1, Optional<T> optional2) {
// XXX: Note that rewriting the first and third variant will change the code's behavior if
// `optional2` has side-effects.
@@ -393,10 +398,7 @@ final class OptionalRules {
}
}
/**
* Avoid unnecessary operations on an {@link Optional} that ultimately result in that very same
* {@link Optional}.
*/
/** Don't unnecessarily transform an {@link Optional} to an equivalent instance. */
static final class OptionalIdentity<T> {
@BeforeTemplate
@SuppressWarnings("NestedOptionals")

View File

@@ -8,6 +8,8 @@ import com.google.common.primitives.Floats;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts;
import com.google.common.primitives.UnsignedInts;
import com.google.common.primitives.UnsignedLongs;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation;
@@ -76,6 +78,8 @@ final class PrimitiveRules {
}
/** Prefer {@link Math#toIntExact(long)} over the Guava alternative. */
// XXX: This rule changes the exception possibly thrown from `IllegalArgumentException` to
// `ArithmeticException`.
static final class LongToIntExact {
@BeforeTemplate
int before(long l) {
@@ -192,97 +196,6 @@ final class PrimitiveRules {
}
}
/** Prefer {@link Boolean#compare(boolean, boolean)} over the Guava alternative. */
static final class BooleanCompare {
@BeforeTemplate
int before(boolean a, boolean b) {
return Booleans.compare(a, b);
}
@AfterTemplate
int after(boolean a, boolean b) {
return Boolean.compare(a, b);
}
}
/** Prefer {@link Character#compare(char, char)} over the Guava alternative. */
static final class CharacterCompare {
@BeforeTemplate
int before(char a, char b) {
return Chars.compare(a, b);
}
@AfterTemplate
int after(char a, char b) {
return Character.compare(a, b);
}
}
/** Prefer {@link Short#compare(short, short)} over the Guava alternative. */
static final class ShortCompare {
@BeforeTemplate
int before(short a, short b) {
return Shorts.compare(a, b);
}
@AfterTemplate
int after(short a, short b) {
return Short.compare(a, b);
}
}
/** Prefer {@link Integer#compare(int, int)} over the Guava alternative. */
static final class IntegerCompare {
@BeforeTemplate
int before(int a, int b) {
return Ints.compare(a, b);
}
@AfterTemplate
int after(int a, int b) {
return Integer.compare(a, b);
}
}
/** Prefer {@link Long#compare(long, long)} over the Guava alternative. */
static final class LongCompare {
@BeforeTemplate
int before(long a, long b) {
return Longs.compare(a, b);
}
@AfterTemplate
int after(long a, long b) {
return Long.compare(a, b);
}
}
/** Prefer {@link Float#compare(float, float)} over the Guava alternative. */
static final class FloatCompare {
@BeforeTemplate
int before(float a, float b) {
return Floats.compare(a, b);
}
@AfterTemplate
int after(float a, float b) {
return Float.compare(a, b);
}
}
/** Prefer {@link Double#compare(double, double)} over the Guava alternative. */
static final class DoubleCompare {
@BeforeTemplate
int before(double a, double b) {
return Doubles.compare(a, b);
}
@AfterTemplate
int after(double a, double b) {
return Double.compare(a, b);
}
}
/** Prefer {@link Character#BYTES} over the Guava alternative. */
static final class CharacterBytes {
@BeforeTemplate
@@ -442,4 +355,205 @@ final class PrimitiveRules {
return Long.signum(l) == -1;
}
}
/** Prefer JDK's {@link Integer#compareUnsigned(int, int)} over third-party alternatives. */
static final class IntegerCompareUnsigned {
@BeforeTemplate
int before(int x, int y) {
return UnsignedInts.compare(x, y);
}
@AfterTemplate
int after(int x, int y) {
return Integer.compareUnsigned(x, y);
}
}
/** Prefer JDK's {@link Long#compareUnsigned(long, long)} over third-party alternatives. */
static final class LongCompareUnsigned {
@BeforeTemplate
long before(long x, long y) {
return UnsignedLongs.compare(x, y);
}
@AfterTemplate
long after(long x, long y) {
return Long.compareUnsigned(x, y);
}
}
/** Prefer JDK's {@link Integer#divideUnsigned(int, int)} over third-party alternatives. */
static final class IntegerDivideUnsigned {
@BeforeTemplate
int before(int x, int y) {
return UnsignedInts.divide(x, y);
}
@AfterTemplate
int after(int x, int y) {
return Integer.divideUnsigned(x, y);
}
}
/** Prefer JDK's {@link Long#divideUnsigned(long, long)} over third-party alternatives. */
static final class LongDivideUnsigned {
@BeforeTemplate
long before(long x, long y) {
return UnsignedLongs.divide(x, y);
}
@AfterTemplate
long after(long x, long y) {
return Long.divideUnsigned(x, y);
}
}
/** Prefer JDK's {@link Integer#remainderUnsigned(int, int)} over third-party alternatives. */
static final class IntegerRemainderUnsigned {
@BeforeTemplate
int before(int x, int y) {
return UnsignedInts.remainder(x, y);
}
@AfterTemplate
int after(int x, int y) {
return Integer.remainderUnsigned(x, y);
}
}
/** Prefer JDK's {@link Long#remainderUnsigned(long, long)} over third-party alternatives. */
static final class LongRemainderUnsigned {
@BeforeTemplate
long before(long x, long y) {
return UnsignedLongs.remainder(x, y);
}
@AfterTemplate
long after(long x, long y) {
return Long.remainderUnsigned(x, y);
}
}
/**
* Prefer JDK's {@link Integer#parseUnsignedInt(String)} over third-party or more verbose
* alternatives.
*/
static final class IntegerParseUnsignedInt {
@BeforeTemplate
int before(String string) {
return Refaster.anyOf(
UnsignedInts.parseUnsignedInt(string), Integer.parseUnsignedInt(string, 10));
}
@AfterTemplate
int after(String string) {
return Integer.parseUnsignedInt(string);
}
}
/**
* Prefer JDK's {@link Long#parseUnsignedLong(String)} over third-party or more verbose
* alternatives.
*/
static final class LongParseUnsignedLong {
@BeforeTemplate
long before(String string) {
return Refaster.anyOf(
UnsignedLongs.parseUnsignedLong(string), Long.parseUnsignedLong(string, 10));
}
@AfterTemplate
long after(String string) {
return Long.parseUnsignedLong(string);
}
}
/** Prefer JDK's {@link Integer#parseUnsignedInt(String, int)} over third-party alternatives. */
static final class IntegerParseUnsignedIntWithRadix {
@BeforeTemplate
int before(String string, int radix) {
return UnsignedInts.parseUnsignedInt(string, radix);
}
@AfterTemplate
int after(String string, int radix) {
return Integer.parseUnsignedInt(string, radix);
}
}
/** Prefer JDK's {@link Long#parseUnsignedLong(String, int)} over third-party alternatives. */
static final class LongParseUnsignedLongWithRadix {
@BeforeTemplate
long before(String string, int radix) {
return UnsignedLongs.parseUnsignedLong(string, radix);
}
@AfterTemplate
long after(String string, int radix) {
return Long.parseUnsignedLong(string, radix);
}
}
/**
* Prefer JDK's {@link Integer#toUnsignedString(int)} over third-party or more verbose
* alternatives.
*/
static final class IntegerToUnsignedString {
@BeforeTemplate
String before(int i) {
return Refaster.anyOf(UnsignedInts.toString(i), Integer.toUnsignedString(i, 10));
}
@AfterTemplate
String after(int i) {
return Integer.toUnsignedString(i);
}
}
/**
* Prefer JDK's {@link Long#toUnsignedString(long)} over third-party or more verbose alternatives.
*/
static final class LongToUnsignedString {
@BeforeTemplate
String before(long i) {
return Refaster.anyOf(UnsignedLongs.toString(i), Long.toUnsignedString(i, 10));
}
@AfterTemplate
String after(long i) {
return Long.toUnsignedString(i);
}
}
/**
* Prefer JDK's {@link Integer#toUnsignedString(int,int)} over third-party or more verbose
* alternatives.
*/
static final class IntegerToUnsignedStringWithRadix {
@BeforeTemplate
String before(int i, int radix) {
return UnsignedInts.toString(i, radix);
}
@AfterTemplate
String after(int i, int radix) {
return Integer.toUnsignedString(i, radix);
}
}
/**
* Prefer JDK's {@link Long#toUnsignedString(long,int)} over third-party or more verbose
* alternatives.
*/
static final class LongToUnsignedStringWithRadix {
@BeforeTemplate
String before(long i, int radix) {
return UnsignedLongs.toString(i, radix);
}
@AfterTemplate
String after(long i, int radix) {
return Long.toUnsignedString(i, radix);
}
}
}

View File

@@ -13,6 +13,7 @@ import static java.util.stream.Collectors.toCollection;
import static org.assertj.core.api.Assertions.assertThat;
import static reactor.function.TupleUtils.function;
import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -41,6 +42,7 @@ import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
@@ -1204,10 +1206,17 @@ final class ReactorRules {
}
/** Prefer {@link Flux#fromIterable(Iterable)} over less efficient alternatives. */
// XXX: Once the `FluxFromStreamSupplier` rule is constrained using
// `@NotMatches(IsIdentityOperation.class)`, this rule should also cover
// `Flux.fromStream(collection.stream())`.
static final class FluxFromIterable<T> {
// XXX: Once the `MethodReferenceUsage` check is generally enabled, drop the second
// `Refaster.anyOf` variant.
@BeforeTemplate
Flux<T> before(Collection<T> collection) {
return Flux.fromStream(collection.stream());
return Flux.fromStream(
Refaster.<Supplier<Stream<? extends T>>>anyOf(
collection::stream, () -> collection.stream()));
}
@AfterTemplate
@@ -1733,6 +1742,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}. */
static final class StepVerifierFromMono<T> {
@BeforeTemplate
@@ -1759,6 +1853,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. */
static final class StepVerifierStepIdentity<T> {
@BeforeTemplate
@@ -1859,6 +2007,12 @@ final class ReactorRules {
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
Duration after(StepVerifier.LastStep step, Predicate<Throwable> predicate) {
return step.verifyErrorMatches(predicate);
@@ -1881,6 +2035,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.
*/
@@ -1913,7 +2091,7 @@ final class ReactorRules {
/**
* Prefer {@link Mono#fromFuture(Supplier)} over {@link Mono#fromFuture(CompletableFuture)}, as
* the former may defer initiation of the asynchornous computation until subscription.
* the former may defer initiation of the asynchronous computation until subscription.
*/
static final class MonoFromFutureSupplier<T> {
// XXX: Constrain the `future` parameter using `@NotMatches(IsIdentityOperation.class)` once
@@ -1932,7 +2110,7 @@ final class ReactorRules {
/**
* Prefer {@link Mono#fromFuture(Supplier, boolean)} over {@link
* Mono#fromFuture(CompletableFuture, boolean)}, as the former may defer initiation of the
* asynchornous computation until subscription.
* asynchronous computation until subscription.
*/
static final class MonoFromFutureSupplierBoolean<T> {
// XXX: Constrain the `future` parameter using `@NotMatches(IsIdentityOperation.class)` once
@@ -1947,4 +2125,39 @@ final class ReactorRules {
return Mono.fromFuture(() -> future, suppressCancel);
}
}
/**
* Don't propagate {@link Mono} cancellations to an upstream cache value computation, as
* completion of such computations may benefit concurrent or subsequent cache usages.
*/
static final class MonoFromFutureAsyncLoadingCacheGet<K, V> {
@BeforeTemplate
Mono<V> before(AsyncLoadingCache<K, V> cache, K key) {
return Mono.fromFuture(() -> cache.get(key));
}
@AfterTemplate
Mono<V> after(AsyncLoadingCache<K, V> cache, K key) {
return Mono.fromFuture(() -> cache.get(key), /* suppressCancel= */ true);
}
}
/**
* Prefer {@link Flux#fromStream(Supplier)} over {@link Flux#fromStream(Stream)}, as the former
* yields a {@link Flux} that is more likely to behave as expected when subscribed to more than
* once.
*/
static final class FluxFromStreamSupplier<T> {
// XXX: Constrain the `stream` parameter using `@NotMatches(IsIdentityOperation.class)` once
// `IsIdentityOperation` no longer matches nullary method invocations.
@BeforeTemplate
Flux<T> before(Stream<T> stream) {
return Flux.fromStream(stream);
}
@AfterTemplate
Flux<T> after(Stream<T> stream) {
return Flux.fromStream(() -> stream);
}
}
}

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> {
@BeforeTemplate
@SuppressWarnings("java:S4266" /* This violation will be rewritten. */)

View File

@@ -29,11 +29,14 @@ final class StringRules {
private StringRules() {}
/** Prefer {@link String#isEmpty()} over alternatives that consult the string's length. */
// XXX: Now that we build with JDK 15+, this rule can be generalized to cover all `CharSequence`
// subtypes. This does require a mechanism (perhaps an annotation, or a separate Maven module) to
// make sure that non-String expressions are rewritten only if client code also targets JDK 15+.
// XXX: Drop this rule once we (and OpenRewrite) no longer support projects targeting Java 14 or
// below. The `CharSequenceIsEmpty` rule then suffices. (This rule exists so that e.g. projects
// that target JDK 11 can disable `CharSequenceIsEmpty` without losing a valuable rule.)
// XXX: Look into a more general approach to supporting different Java language levels, such as
// rule selection based on some annotation, or a separate Maven module.
static final class StringIsEmpty {
@BeforeTemplate
@SuppressWarnings("CharSequenceIsEmpty" /* This is a more specific template. */)
boolean before(String str) {
return Refaster.anyOf(str.length() == 0, str.length() <= 0, str.length() < 1);
}
@@ -244,4 +247,105 @@ final class StringRules {
return Utf8.encodedLength(str);
}
}
/** Prefer {@link String#indexOf(int, int)} over less efficient alternatives. */
static final class StringIndexOfChar {
@BeforeTemplate
@SuppressWarnings("java:S4635" /* This violation will be rewritten. */)
int before(String string, int ch, int fromIndex) {
return string.substring(fromIndex).indexOf(ch);
}
@AfterTemplate
int after(String string, int ch, int fromIndex) {
return Math.max(-1, string.indexOf(ch, fromIndex) - fromIndex);
}
}
/** Prefer {@link String#indexOf(String, int)} over less efficient alternatives. */
static final class StringIndexOfString {
@BeforeTemplate
@SuppressWarnings("java:S4635" /* This violation will be rewritten. */)
int before(String string, String substring, int fromIndex) {
return string.substring(fromIndex).indexOf(substring);
}
@AfterTemplate
int after(String string, String substring, int fromIndex) {
return Math.max(-1, string.indexOf(substring, fromIndex) - fromIndex);
}
}
// XXX: Once we compile Refaster templates with JDK 21 also suggest `String#indexOf(int, int,
// int)` and `String#indexOf(String, int, int)`.
/** Prefer {@link String#lastIndexOf(int, int)} over less efficient alternatives. */
static final class StringLastIndexOfChar {
@BeforeTemplate
@SuppressWarnings("java:S4635" /* This violation will be rewritten. */)
int before(String string, int ch, int fromIndex) {
return string.substring(fromIndex).lastIndexOf(ch);
}
@AfterTemplate
int after(String string, int ch, int fromIndex) {
return Math.max(-1, string.lastIndexOf(ch) - fromIndex);
}
}
/** Prefer {@link String#lastIndexOf(String, int)} over less efficient alternatives. */
static final class StringLastIndexOfString {
@BeforeTemplate
@SuppressWarnings("java:S4635" /* This violation will be rewritten. */)
int before(String string, String substring, int fromIndex) {
return string.substring(fromIndex).lastIndexOf(substring);
}
@AfterTemplate
int after(String string, String substring, int fromIndex) {
return Math.max(-1, string.lastIndexOf(substring) - fromIndex);
}
}
/** Prefer {@link String#lastIndexOf(int, int)} over less efficient alternatives. */
static final class StringLastIndexOfCharWithIndex {
@BeforeTemplate
int before(String string, int ch, int fromIndex) {
return string.substring(0, fromIndex).lastIndexOf(ch);
}
@AfterTemplate
int after(String string, int ch, int fromIndex) {
return string.lastIndexOf(ch, fromIndex - 1);
}
}
/** Prefer {@link String#lastIndexOf(String, int)} over less efficient alternatives. */
// XXX: The replacement expression isn't fully equivalent: in case `substring` is empty, then
// the replacement yields `fromIndex - 1` rather than `fromIndex`.
static final class StringLastIndexOfStringWithIndex {
@BeforeTemplate
int before(String string, String substring, int fromIndex) {
return string.substring(0, fromIndex).lastIndexOf(substring);
}
@AfterTemplate
int after(String string, String substring, int fromIndex) {
return string.lastIndexOf(substring, fromIndex - 1);
}
}
/** Prefer {@link String#startsWith(String, int)} over less efficient alternatives. */
static final class StringStartsWith {
@BeforeTemplate
@SuppressWarnings("java:S4635" /* This violation will be rewritten. */)
boolean before(String string, String prefix, int fromIndex) {
return string.substring(fromIndex).startsWith(prefix);
}
@AfterTemplate
boolean after(String string, String prefix, int fromIndex) {
return string.startsWith(prefix, fromIndex);
}
}
}

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. */
static final class InstantAtOffset {
@BeforeTemplate

View File

@@ -0,0 +1,71 @@
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 ClassCastLambdaUsageTest {
@Test
void identification() {
CompilationTestHelper.newInstance(ClassCastLambdaUsage.class, getClass())
.addSourceLines(
"A.java",
"import com.google.common.collect.ImmutableSet;",
"import java.util.stream.IntStream;",
"import java.util.stream.Stream;",
"",
"class A {",
" <T> void m() {",
" Number localVariable = 0;",
"",
" Stream.of(0).map(i -> i);",
" Stream.of(1).map(i -> i + 1);",
" Stream.of(2).map(Integer.class::cast);",
" Stream.of(3).map(i -> (Integer) 2);",
" Stream.of(4).map(i -> (Integer) localVariable);",
" // XXX: Ideally this case is also flagged. Pick this up in the context of merging the",
" // `ClassCastLambdaUsage` and `MethodReferenceUsage` checks, or introduce a separate check that",
" // simplifies unnecessary block lambda expressions.",
" Stream.of(5)",
" .map(",
" i -> {",
" return (Integer) i;",
" });",
" Stream.<ImmutableSet>of(ImmutableSet.of(6)).map(s -> (ImmutableSet<Number>) s);",
" Stream.of(ImmutableSet.of(7)).map(s -> (ImmutableSet<?>) s);",
" Stream.of(8).reduce((a, b) -> (Integer) a);",
" IntStream.of(9).mapToObj(i -> (char) i);",
" Stream.of(10).map(i -> (T) i);",
"",
" // BUG: Diagnostic contains:",
" Stream.of(11).map(i -> (Integer) i);",
" }",
"}")
.doTest();
}
@Test
void replacement() {
BugCheckerRefactoringTestHelper.newInstance(ClassCastLambdaUsage.class, getClass())
.addInputLines(
"A.java",
"import java.util.stream.Stream;",
"",
"class A {",
" void m() {",
" Stream.of(1).map(i -> (Integer) i);",
" }",
"}")
.addOutputLines(
"A.java",
"import java.util.stream.Stream;",
"",
"class A {",
" void m() {",
" Stream.of(1).map(Integer.class::cast);",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -0,0 +1,78 @@
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 ConstantNamingTest {
@Test
void identification() {
CompilationTestHelper.newInstance(ConstantNaming.class, getClass())
.addSourceLines(
"A.java",
"class A {",
" private static final long serialVersionUID = 1L;",
" private static final int FOO = 1;",
" // BUG: Diagnostic contains: consider renaming to 'BAR', though note that this is not a private",
" // constant",
" static final int bar = 2;",
" // BUG: Diagnostic contains:",
" private static final int baz = 3;",
" // BUG: Diagnostic contains: consider renaming to 'QUX_QUUX', though note that a variable with",
" // this name is already declared",
" private static final int qux_QUUX = 4;",
" // BUG: Diagnostic contains: consider renaming to 'QUUZ', though note that a variable with",
" // this name is already declared",
" private static final int quuz = 3;",
"",
" private final int foo = 4;",
" private final Runnable QUX_QUUX =",
" new Runnable() {",
" private static final int QUUZ = 1;",
"",
" @Override",
" public void run() {}",
" };",
"}")
.doTest();
}
@Test
void identificationWithCustomExemption() {
CompilationTestHelper.newInstance(ConstantNaming.class, getClass())
.setArgs("-XepOpt:CanonicalConstantNaming:ExemptedNames=foo,baz")
.addSourceLines(
"A.java",
"class A {",
" private static final long serialVersionUID = 1L;",
" private static final int foo = 1;",
" // BUG: Diagnostic contains:",
" private static final int bar = 2;",
" private static final int baz = 3;",
"}")
.doTest();
}
@Test
void replacement() {
BugCheckerRefactoringTestHelper.newInstance(ConstantNaming.class, getClass())
.addInputLines(
"A.java",
"class A {",
" static final int foo = 1;",
" private static final int bar = 2;",
" private static final int baz = 3;",
" private static final int BAZ = 4;",
"}")
.addOutputLines(
"A.java",
"class A {",
" static final int foo = 1;",
" private static final int BAR = 2;",
" private static final int baz = 3;",
" private static final int BAZ = 4;",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -0,0 +1,175 @@
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 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));",
"",
" // 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.errorprone.matchers.Matcher;",
"import com.google.errorprone.matchers.Matchers;",
"import java.time.Instant;",
"import java.time.ZonedDateTime;",
"import reactor.adapter.rxjava.RxJava2Adapter;",
"import reactor.core.publisher.Flux;",
"import reactor.core.publisher.Mono;",
@@ -149,6 +151,10 @@ final class IdentityConversionTest {
" // BUG: Diagnostic contains:",
" 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:",
" Matcher allOf1 = Matchers.allOf(instanceMethod());",
" Matcher allOf2 = Matchers.allOf(instanceMethod(), staticMethod());",

View File

@@ -18,22 +18,23 @@ final class IsInstanceLambdaUsageTest {
" void m() {",
" Integer localVariable = 0;",
"",
" Stream.of(0).map(i -> i + 1);",
" Stream.of(1).filter(Integer.class::isInstance);",
" Stream.of(2).filter(i -> i.getClass() instanceof Class);",
" Stream.of(3).filter(i -> localVariable instanceof Integer);",
" Stream.of(0).map(i -> i);",
" Stream.of(1).map(i -> i + 1);",
" Stream.of(2).filter(Integer.class::isInstance);",
" Stream.of(3).filter(i -> i.getClass() instanceof Class);",
" Stream.of(4).filter(i -> localVariable instanceof Integer);",
" // XXX: Ideally this case is also flagged. Pick this up in the context of merging the",
" // `IsInstanceLambdaUsage` and `MethodReferenceUsage` checks, or introduce a separate check that",
" // simplifies unnecessary block lambda expressions.",
" Stream.of(4)",
" Stream.of(5)",
" .filter(",
" i -> {",
" return localVariable instanceof Integer;",
" return i instanceof Integer;",
" });",
" Flux.just(5, \"foo\").distinctUntilChanged(v -> v, (a, b) -> a instanceof Integer);",
" Flux.just(6, \"foo\").distinctUntilChanged(v -> v, (a, b) -> a instanceof Integer);",
"",
" // BUG: Diagnostic contains:",
" Stream.of(6).filter(i -> i instanceof Integer);",
" Stream.of(7).filter(i -> i instanceof Integer);",
" }",
"}")
.doTest();

View File

@@ -11,7 +11,7 @@ final class JUnitMethodDeclarationTest {
CompilationTestHelper.newInstance(JUnitMethodDeclaration.class, getClass())
.addSourceLines(
"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.AfterEach;",
@@ -154,8 +154,10 @@ final class JUnitMethodDeclarationTest {
" void overload() {}",
"",
" @Test",
" // BUG: Diagnostic contains: (but note that `arguments` is already statically imported)",
" void testArguments() {}",
" // BUG: Diagnostic contains: (but note that another method named `arguments` is in scope)",
" void testArguments() {",
" arguments();",
" }",
"",
" @Test",
" // BUG: Diagnostic contains: (but note that `public` is not a valid identifier)",

View File

@@ -1,6 +1,5 @@
package tech.picnic.errorprone.bugpatterns;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
@@ -29,6 +28,10 @@ final class LexicographicalAnnotationAttributeListingTest {
" @interface Foo {",
" String[] value() default {};",
"",
" boolean[] bools() default {};",
"",
" char[] chars() default {};",
"",
" int[] ints() default {};",
"",
" Class<?>[] cls() default {};",
@@ -69,6 +72,32 @@ final class LexicographicalAnnotationAttributeListingTest {
" @Foo({\"a\", \"A\"})",
" A unsortedStringCaseInsensitiveWithTotalOrderFallback();",
"",
" @Foo(bools = {})",
" A noBools();",
"",
" @Foo(bools = {false})",
" A oneBool();",
"",
" @Foo(bools = {false, true})",
" A sortedBools();",
"",
" // BUG: Diagnostic contains:",
" @Foo(bools = {true, false})",
" A unsortedBools();",
"",
" @Foo(chars = {})",
" A noChars();",
"",
" @Foo(chars = {'a'})",
" A oneChar();",
"",
" @Foo(chars = {'a', 'b'})",
" A sortedChars();",
"",
" // BUG: Diagnostic contains:",
" @Foo(chars = {'b', 'a'})",
" A unsortedChars();",
"",
" @Foo(ints = {})",
" A noInts();",
"",
@@ -173,6 +202,10 @@ final class LexicographicalAnnotationAttributeListingTest {
" @interface Foo {",
" String[] value() default {};",
"",
" boolean[] bools() default {};",
"",
" char[] chars() default {};",
"",
" Class<?>[] cls() default {};",
"",
" RoundingMode[] enums() default {};",
@@ -185,7 +218,13 @@ final class LexicographicalAnnotationAttributeListingTest {
" }",
"",
" @Foo({\" \", \"\", \"b\", \"a\"})",
" A unsortedString();",
" A unsortedStrings();",
"",
" @Foo(bools = {true, false})",
" A unsortedBooleans();",
"",
" @Foo(chars = {'b', 'a'})",
" A unsortedChars();",
"",
" @Foo(cls = {long.class, int.class})",
" A unsortedClasses();",
@@ -210,6 +249,10 @@ final class LexicographicalAnnotationAttributeListingTest {
" @interface Foo {",
" String[] value() default {};",
"",
" boolean[] bools() default {};",
"",
" char[] chars() default {};",
"",
" Class<?>[] cls() default {};",
"",
" RoundingMode[] enums() default {};",
@@ -222,7 +265,13 @@ final class LexicographicalAnnotationAttributeListingTest {
" }",
"",
" @Foo({\"\", \" \", \"a\", \"b\"})",
" A unsortedString();",
" A unsortedStrings();",
"",
" @Foo(bools = {false, true})",
" A unsortedBooleans();",
"",
" @Foo(chars = {'a', 'b'})",
" A unsortedChars();",
"",
" @Foo(cls = {int.class, long.class})",
" A unsortedClasses();",
@@ -244,9 +293,8 @@ final class LexicographicalAnnotationAttributeListingTest {
/* Some violations are not flagged because they are not in- or excluded. */
CompilationTestHelper.newInstance(LexicographicalAnnotationAttributeListing.class, getClass())
.setArgs(
ImmutableList.of(
"-XepOpt:LexicographicalAnnotationAttributeListing:Includes=pkg.A.Foo,pkg.A.Bar",
"-XepOpt:LexicographicalAnnotationAttributeListing:Excludes=pkg.A.Bar#value"))
"-XepOpt:LexicographicalAnnotationAttributeListing:Includes=pkg.A.Foo,pkg.A.Bar",
"-XepOpt:LexicographicalAnnotationAttributeListing:Excludes=pkg.A.Bar#value")
.addSourceLines(
"pkg/A.java",
"package pkg;",

View File

@@ -0,0 +1,221 @@
package tech.picnic.errorprone.bugpatterns;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
public final class ModernizerTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(Modernizer.class, getClass());
// XXX: Also add calls that should not be flagged.
// XXX: Test extension, field references, instance methods, static methods.
// methods with primitives, primitive arrays, references, reference arrays
// zero, one two args.
// XXX: Also test constructors!
// XXX: Test that the appropriate "prefer" message is emitted.
// XXX: List the test cases in `ModernizerTest`?
@Test
void fieldIdentification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import static com.google.common.base.Charsets.ISO_8859_1;",
"",
"import com.google.common.base.Charsets;",
"import java.nio.charset.StandardCharsets;",
"",
"class A {",
" {",
" // BUG: Diagnostic contains: Prefer java.nio.charset.StandardCharsets",
" Object o1 = ISO_8859_1;",
" // BUG: Diagnostic contains: Prefer java.nio.charset.StandardCharsets",
" Object o2 = Charsets.ISO_8859_1;",
" // BUG: Diagnostic contains: Prefer java.nio.charset.StandardCharsets",
" Object o3 = com.google.common.base.Charsets.ISO_8859_1;",
"",
" Object o4 = StandardCharsets.ISO_8859_1;",
" Object o5 = java.nio.charset.StandardCharsets.ISO_8859_1;",
" }",
"}")
.doTest();
}
@Test
void nullaryMethodIdentification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import static com.google.common.base.Optional.absent;",
"",
"import com.google.common.base.Optional;",
"import java.util.function.Supplier;",
"",
"class A {",
" {",
" // BUG: Diagnostic contains: Prefer java.util.Optional",
" absent();",
" // BUG: Diagnostic contains: Prefer java.util.Optional",
" Optional.absent();",
" // BUG: Diagnostic contains: Prefer java.util.Optional",
" com.google.common.base.Optional.absent();",
" // BUG: Diagnostic contains: Prefer java.util.Optional",
" Supplier<?> s1 = Optional::absent;",
" // BUG: Diagnostic contains: Prefer java.util.Optional",
" Supplier<?> s2 = com.google.common.base.Optional::absent;",
"",
" java.util.Optional.empty();",
" Supplier<?> s3 = java.util.Optional::empty;",
"",
" Dummy.absent();",
" }",
"",
" static final class Dummy {",
" static Optional<?> absent() {",
" return null;",
" }",
" }",
"}")
.doTest();
}
@Test
void unaryMethodWithIntegerArgumentIdentification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import static com.google.common.collect.Lists.newArrayListWithCapacity;",
"",
"import com.google.common.collect.Lists;",
"import java.util.ArrayList;",
"import java.util.function.IntFunction;",
"",
"class A {",
" {",
" // BUG: Diagnostic contains: Prefer java.util.ArrayList<>(int)",
" newArrayListWithCapacity(0);",
" // BUG: Diagnostic contains: Prefer java.util.ArrayList<>(int)",
" Lists.newArrayListWithCapacity(1);",
" // BUG: Diagnostic contains: Prefer java.util.ArrayList<>(int)",
" com.google.common.collect.Lists.newArrayListWithCapacity(2);",
" // BUG: Diagnostic contains: Prefer java.util.ArrayList<>(int)",
" IntFunction<?> f1 = Lists::newArrayListWithCapacity;",
" // BUG: Diagnostic contains: Prefer java.util.ArrayList<>(int)",
" IntFunction<?> f2 = com.google.common.collect.Lists::newArrayListWithCapacity;",
"",
" new ArrayList<>(3);",
" IntFunction<?> f3 = ArrayList::new;",
" IntFunction<?> f4 = java.util.ArrayList::new;",
"",
" Dummy.newArrayListWithCapacity(4);",
" }",
"",
" static final class Dummy {",
" static ArrayList<?> newArrayListWithCapacity(int initialArraySize) {",
" return null;",
" }",
" }",
"}")
.doTest();
}
@Test
void binaryMethodWithObjectArgumentsIdentification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import static com.google.common.base.Objects.equal;",
"",
"import com.google.common.base.Objects;",
"import java.util.function.BiPredicate;",
"",
"class A {",
" {",
" // BUG: Diagnostic contains: Prefer java.util.Objects.equals(Object, Object)",
" equal(null, null);",
" // BUG: Diagnostic contains: Prefer java.util.Objects.equals(Object, Object)",
" Objects.equal(null, null);",
" // BUG: Diagnostic contains: Prefer java.util.Objects.equals(Object, Object)",
" com.google.common.base.Objects.equal(null, null);",
" // BUG: Diagnostic contains: Prefer java.util.Objects.equals(Object, Object)",
" BiPredicate<?, ?> p1 = Objects::equal;",
" // BUG: Diagnostic contains: Prefer java.util.Objects.equals(Object, Object)",
" BiPredicate<?, ?> p2 = com.google.common.base.Objects::equal;",
"",
" java.util.Objects.equals(null, null);",
" BiPredicate<?, ?> p3 = java.util.Objects::equals;",
"",
" Dummy.equal(null, null);",
" }",
"",
" static final class Dummy {",
" static boolean equal(Object a, Object b) {",
" return false;",
" }",
" }",
"}")
.doTest();
}
@Test
void varargsMethodWithObjectArgumentsIdentification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import com.google.common.base.Objects;",
"import java.util.function.ToIntFunction;",
"",
"class A {",
" {",
" // BUG: Diagnostic contains: Prefer java.util.Objects.hash(Object...)",
" Objects.hashCode((Object) null);",
" // BUG: Diagnostic contains: Prefer java.util.Objects.hash(Object...)",
" com.google.common.base.Objects.hashCode(null, null);",
" // BUG: Diagnostic contains: Prefer java.util.Objects.hash(Object...)",
" ToIntFunction<?> f1 = Objects::hashCode;",
" // BUG: Diagnostic contains: Prefer java.util.Objects.hash(Object...)",
" ToIntFunction<?> f2 = com.google.common.base.Objects::hashCode;",
"",
" java.util.Objects.hash(null, null, null);",
" ToIntFunction<?> f3 = java.util.Objects::hash;",
"",
" Dummy.hashCode(null, null, null, null);",
" }",
"",
" static final class Dummy {",
" static int hashCode(Object... objects) {",
" return 0;",
" }",
" }",
"}")
.doTest();
}
@Test
void binaryConstructorWithByteArrayAndObjectArgumentsIdentification() {
compilationTestHelper
.addSourceLines(
"A.java",
"import java.io.UnsupportedEncodingException;",
"import java.nio.charset.StandardCharsets;",
"",
"class A {",
" void m() throws UnsupportedEncodingException {",
" // BUG: Diagnostic contains: Prefer java.lang.String.<init>(byte[], java.nio.charset.Charset)",
" new String(new byte[0], \"\");",
" // BUG: Diagnostic contains: Prefer java.lang.String.<init>(byte[], java.nio.charset.Charset)",
" new java.lang.String(new byte[] {}, toString());",
"",
" new String(new byte[0], StandardCharsets.UTF_8);",
" new java.lang.String(new byte[0], StandardCharsets.UTF_8);",
"",
" new Dummy(new byte[0], \"\");",
" }",
"",
" static final class Dummy {",
" Dummy(byte bytes[], String charsetName) {}",
" }",
"}")
.doTest();
}
}

View File

@@ -5,14 +5,15 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class OptionalOrElseTest {
final class OptionalOrElseGetTest {
@Test
void identification() {
CompilationTestHelper.newInstance(OptionalOrElse.class, getClass())
CompilationTestHelper.newInstance(OptionalOrElseGet.class, getClass())
.addSourceLines(
"A.java",
"import com.google.errorprone.refaster.Refaster;",
"import java.util.Optional;",
"import java.util.function.Supplier;",
"",
"class A {",
" private final Optional<Object> optional = Optional.empty();",
@@ -27,6 +28,7 @@ final class OptionalOrElseTest {
" optional.orElse(string);",
" optional.orElse(this.string);",
" optional.orElse(Refaster.anyOf(\"constant\", \"another\"));",
" Optional.<Supplier<String>>empty().orElse(() -> \"constant\");",
"",
" // BUG: Diagnostic contains:",
" Optional.empty().orElse(string + \"constant\");",
@@ -67,7 +69,7 @@ final class OptionalOrElseTest {
@Test
void replacement() {
BugCheckerRefactoringTestHelper.newInstance(OptionalOrElse.class, getClass())
BugCheckerRefactoringTestHelper.newInstance(OptionalOrElseGet.class, getClass())
.addInputLines(
"A.java",
"import java.util.Optional;",

View File

@@ -1,6 +1,5 @@
package tech.picnic.errorprone.bugpatterns;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
@@ -408,8 +407,7 @@ final class RedundantStringConversionTest {
void identificationOfCustomConversionMethod() {
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.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(
"A.java",
"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

@@ -0,0 +1,218 @@
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 Slf4jLoggerDeclarationTest {
@Test
void identification() {
CompilationTestHelper.newInstance(Slf4jLoggerDeclaration.class, getClass())
.addSourceLines(
"A.java",
"import static java.lang.Class.forName;",
"",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"",
"class A {",
" private static final long serialVersionUID = 1L;",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
"",
" abstract static class DynamicLogger {",
" private final Logger log = LoggerFactory.getLogger(getClass());",
" }",
"",
" abstract static class DynamicLoggerWithExplicitThis {",
" private final Logger log = LoggerFactory.getLogger(this.getClass());",
" }",
"",
" static final class StaticLogger {",
" private static final Logger LOG = LoggerFactory.getLogger(StaticLogger.class);",
" }",
"",
" static final class StaticLoggerWithCustomIdentifier {",
" private static final Logger LOG = LoggerFactory.getLogger(\"custom-identifier\");",
" }",
"",
" interface StaticLoggerForInterface {",
" Logger LOG = LoggerFactory.getLogger(StaticLoggerForInterface.class);",
" }",
"",
" abstract static class DynamicLoggerForWrongTypeWithoutReceiver {",
" // BUG: Diagnostic contains:",
" private final Logger log = LoggerFactory.getLogger(forName(\"A.class\"));",
"",
" DynamicLoggerForWrongTypeWithoutReceiver() throws ClassNotFoundException {}",
" }",
"",
" abstract static class DynamicLoggerForWrongTypeWithoutSymbol {",
" // BUG: Diagnostic contains:",
" private final Logger log = LoggerFactory.getLogger(\"foo\".getClass());",
" }",
"",
" abstract static class DynamicLoggerForWrongTypeWithSymbol {",
" // BUG: Diagnostic contains:",
" private final Logger log = LoggerFactory.getLogger(new A().getClass());",
" }",
"",
" static final class NonAbstractDynamicLogger {",
" // BUG: Diagnostic contains:",
" private final Logger log = LoggerFactory.getLogger(getClass());",
" }",
"",
" abstract static class DynamicLoggerWithMissingModifier {",
" // BUG: Diagnostic contains:",
" final Logger log = LoggerFactory.getLogger(getClass());",
" }",
"",
" abstract static class DynamicLoggerWithExcessModifier {",
" // BUG: Diagnostic contains:",
" private final transient Logger log = LoggerFactory.getLogger(getClass());",
" }",
"",
" abstract static class MisnamedDynamicLogger {",
" // BUG: Diagnostic contains:",
" private final Logger LOG = LoggerFactory.getLogger(getClass());",
" }",
"",
" static final class StaticLoggerWithMissingModifier {",
" // BUG: Diagnostic contains:",
" static final Logger LOG = LoggerFactory.getLogger(StaticLoggerWithMissingModifier.class);",
" }",
"",
" static final class StaticLoggerWithExcessModifier {",
" // BUG: Diagnostic contains:",
" private static final transient Logger LOG =",
" LoggerFactory.getLogger(StaticLoggerWithExcessModifier.class);",
" }",
"",
" static final class MisnamedStaticLogger {",
" // BUG: Diagnostic contains:",
" private static final Logger log = LoggerFactory.getLogger(MisnamedStaticLogger.class);",
" }",
"",
" static final class StaticLoggerWithIncorrectIdentifier {",
" // BUG: Diagnostic contains:",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
" }",
"",
" static final class StaticLoggerWithCustomIdentifierAndMissingModifier {",
" // BUG: Diagnostic contains:",
" static final Logger LOG = LoggerFactory.getLogger(\"custom-identifier\");",
" }",
"",
" static final class StaticLoggerWithCustomIdentifierAndExcessModifier {",
" // BUG: Diagnostic contains:",
" private static final transient Logger LOG = LoggerFactory.getLogger(\"custom-identifier\");",
" }",
"",
" static final class MisnamedStaticLoggerWithCustomIdentifier {",
" // BUG: Diagnostic contains:",
" private static final Logger log = LoggerFactory.getLogger(\"custom-identifier\");",
" }",
"",
" interface StaticLoggerForInterfaceWithExcessModifier {",
" // BUG: Diagnostic contains:",
" static Logger LOG = LoggerFactory.getLogger(StaticLoggerForInterfaceWithExcessModifier.class);",
" }",
"",
" interface MisnamedStaticLoggerForInterface {",
" // BUG: Diagnostic contains:",
" Logger log = LoggerFactory.getLogger(MisnamedStaticLoggerForInterface.class);",
" }",
"",
" interface StaticLoggerForInterfaceWithIncorrectIdentifier {",
" // BUG: Diagnostic contains:",
" Logger LOG = LoggerFactory.getLogger(A.class);",
" }",
"}")
.doTest();
}
@Test
void replacement() {
BugCheckerRefactoringTestHelper.newInstance(Slf4jLoggerDeclaration.class, getClass())
.addInputLines(
"A.java",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"",
"class A {",
" static Logger foo = LoggerFactory.getLogger(Logger.class);",
"",
" abstract static class DynamicLogger {",
" transient Logger BAR = LoggerFactory.getLogger(getClass());",
" }",
"",
" static final class StaticLogger {",
" transient Logger baz = LoggerFactory.getLogger(LoggerFactory.class);",
" }",
"",
" static final class StaticLoggerWithCustomIdentifier {",
" transient Logger qux = LoggerFactory.getLogger(\"custom-identifier\");",
" }",
"",
" interface StaticLoggerForInterface {",
" public static final Logger quux = LoggerFactory.getLogger(A.class);",
" }",
"}")
.addOutputLines(
"A.java",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"",
"class A {",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
"",
" abstract static class DynamicLogger {",
" private final Logger log = LoggerFactory.getLogger(getClass());",
" }",
"",
" static final class StaticLogger {",
" private static final Logger LOG = LoggerFactory.getLogger(StaticLogger.class);",
" }",
"",
" static final class StaticLoggerWithCustomIdentifier {",
" private static final Logger LOG = LoggerFactory.getLogger(\"custom-identifier\");",
" }",
"",
" interface StaticLoggerForInterface {",
" Logger LOG = LoggerFactory.getLogger(StaticLoggerForInterface.class);",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
@Test
void replacementWithCustomLoggerName() {
BugCheckerRefactoringTestHelper.newInstance(Slf4jLoggerDeclaration.class, getClass())
.setArgs("-XepOpt:Slf4jLoggerDeclaration:CanonicalStaticLoggerName=FOO_BAR")
.addInputLines(
"A.java",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"",
"class A {",
" transient Logger LOG = LoggerFactory.getLogger(Logger.class);",
"",
" abstract static class DynamicLogger {",
" transient Logger log = LoggerFactory.getLogger(getClass());",
" }",
"}")
.addOutputLines(
"A.java",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"",
"class A {",
" private static final Logger FOO_BAR = LoggerFactory.getLogger(A.class);",
"",
" abstract static class DynamicLogger {",
" private final Logger fooBar = LoggerFactory.getLogger(getClass());",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -36,6 +36,7 @@ final class RefasterRulesTest {
AssortedRules.class,
BigDecimalRules.class,
BugCheckerRules.class,
CharSequenceRules.class,
ClassRules.class,
CollectionRules.class,
ComparatorRules.class,
@@ -43,6 +44,7 @@ final class RefasterRulesTest {
EqualityRules.class,
FileRules.class,
InputStreamRules.class,
ImmutableEnumSetRules.class,
ImmutableListRules.class,
ImmutableListMultimapRules.class,
ImmutableMapRules.class,
@@ -58,6 +60,7 @@ final class RefasterRulesTest {
LongStreamRules.class,
MapEntryRules.class,
MapRules.class,
MicrometerRules.class,
MockitoRules.class,
MultimapRules.class,
NullRules.class,

View File

@@ -33,6 +33,14 @@ final class AssertJStringRulesTest implements RefasterRuleCollectionTestCase {
return assertThat("foo".isEmpty()).isFalse();
}
AbstractAssert<?, ?> testAssertThatStringContains() {
return assertThat("foo".contains("bar")).isTrue();
}
AbstractAssert<?, ?> testAssertThatStringDoesNotContain() {
return assertThat("foo".contains("bar")).isFalse();
}
AbstractAssert<?, ?> testAssertThatMatches() {
return assertThat("foo".matches(".*")).isTrue();
}

View File

@@ -34,6 +34,14 @@ final class AssertJStringRulesTest implements RefasterRuleCollectionTestCase {
return assertThat("foo").isNotEmpty();
}
AbstractAssert<?, ?> testAssertThatStringContains() {
return assertThat("foo").contains("bar");
}
AbstractAssert<?, ?> testAssertThatStringDoesNotContain() {
return assertThat("foo").doesNotContain("bar");
}
AbstractAssert<?, ?> testAssertThatMatches() {
return assertThat("foo").matches(".*");
}

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.assertThatNullPointerException;
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 org.assertj.core.api.AbstractObjectAssert;
@@ -20,7 +22,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
assertThatIOException(),
assertThatIllegalArgumentException(),
assertThatIllegalStateException(),
assertThatNullPointerException());
assertThatNullPointerException(),
type(Throwable.class));
}
void testAssertThatThrownByIsInstanceOf() {
assertThatThrownBy(() -> {}).asInstanceOf(throwable(IllegalArgumentException.class));
assertThatThrownBy(() -> {}).asInstanceOf(type(IllegalArgumentException.class));
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentException() {
@@ -31,6 +39,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatIllegalArgumentException().isThrownBy(() -> {}).withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentExceptionRootCauseHasMessage() {
return assertThatIllegalArgumentException()
.isThrownBy(() -> {})
.havingRootCause()
.withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentExceptionHasMessageParameters() {
return assertThatIllegalArgumentException().isThrownBy(() -> {}).withMessage("foo %s", "bar");
}
@@ -59,6 +74,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatIllegalStateException().isThrownBy(() -> {}).withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalStateExceptionRootCauseHasMessage() {
return assertThatIllegalStateException()
.isThrownBy(() -> {})
.havingRootCause()
.withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalStateExceptionHasMessageParameters() {
return assertThatIllegalStateException().isThrownBy(() -> {}).withMessage("foo %s", "bar");
}
@@ -83,6 +105,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatNullPointerException().isThrownBy(() -> {}).withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByNullPointerExceptionRootCauseHasMessage() {
return assertThatNullPointerException()
.isThrownBy(() -> {})
.havingRootCause()
.withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByNullPointerExceptionHasMessageParameters() {
return assertThatNullPointerException().isThrownBy(() -> {}).withMessage("foo %s", "bar");
}
@@ -107,6 +136,10 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatIOException().isThrownBy(() -> {}).withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIOExceptionRootCauseHasMessage() {
return assertThatIOException().isThrownBy(() -> {}).havingRootCause().withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIOExceptionHasMessageParameters() {
return assertThatIOException().isThrownBy(() -> {}).withMessage("foo %s", "bar");
}
@@ -123,7 +156,7 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatIOException().isThrownBy(() -> {}).withMessageNotContaining("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownBy() {
AbstractObjectAssert<?, ?> testAssertThatThrownByAsInstanceOfThrowable() {
return assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {});
}
@@ -133,6 +166,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
.withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByRootCauseHasMessage() {
return assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> {})
.havingRootCause()
.withMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByHasMessageParameters() {
return assertThatExceptionOfType(IllegalArgumentException.class)
.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.assertThatNullPointerException;
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 java.io.IOException;
@@ -21,7 +23,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
assertThatIOException(),
assertThatIllegalArgumentException(),
assertThatIllegalStateException(),
assertThatNullPointerException());
assertThatNullPointerException(),
type(Throwable.class));
}
void testAssertThatThrownByIsInstanceOf() {
assertThatThrownBy(() -> {}).isInstanceOf(IllegalArgumentException.class);
assertThatThrownBy(() -> {}).isInstanceOf(IllegalArgumentException.class);
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentException() {
@@ -34,6 +42,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
.hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentExceptionRootCauseHasMessage() {
return assertThatThrownBy(() -> {})
.isInstanceOf(IllegalArgumentException.class)
.rootCause()
.hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalArgumentExceptionHasMessageParameters() {
return assertThatThrownBy(() -> {})
.isInstanceOf(IllegalArgumentException.class)
@@ -68,6 +83,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatThrownBy(() -> {}).isInstanceOf(IllegalStateException.class).hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalStateExceptionRootCauseHasMessage() {
return assertThatThrownBy(() -> {})
.isInstanceOf(IllegalStateException.class)
.rootCause()
.hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIllegalStateExceptionHasMessageParameters() {
return assertThatThrownBy(() -> {})
.isInstanceOf(IllegalStateException.class)
@@ -100,6 +122,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatThrownBy(() -> {}).isInstanceOf(NullPointerException.class).hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByNullPointerExceptionRootCauseHasMessage() {
return assertThatThrownBy(() -> {})
.isInstanceOf(NullPointerException.class)
.rootCause()
.hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByNullPointerExceptionHasMessageParameters() {
return assertThatThrownBy(() -> {})
.isInstanceOf(NullPointerException.class)
@@ -132,6 +161,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
return assertThatThrownBy(() -> {}).isInstanceOf(IOException.class).hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIOExceptionRootCauseHasMessage() {
return assertThatThrownBy(() -> {})
.isInstanceOf(IOException.class)
.rootCause()
.hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByIOExceptionHasMessageParameters() {
return assertThatThrownBy(() -> {}).isInstanceOf(IOException.class).hasMessage("foo %s", "bar");
}
@@ -152,8 +188,8 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
.hasMessageNotContaining("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownBy() {
return assertThatThrownBy(() -> {}).isInstanceOf(IllegalArgumentException.class);
AbstractObjectAssert<?, ?> testAssertThatThrownByAsInstanceOfThrowable() {
return assertThatThrownBy(() -> {}).asInstanceOf(throwable(IllegalArgumentException.class));
}
AbstractObjectAssert<?, ?> testAssertThatThrownByHasMessage() {
@@ -162,6 +198,13 @@ final class AssertJThrowingCallableRulesTest implements RefasterRuleCollectionTe
.hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByRootCauseHasMessage() {
return assertThatThrownBy(() -> {})
.isInstanceOf(IllegalArgumentException.class)
.rootCause()
.hasMessage("foo");
}
AbstractObjectAssert<?, ?> testAssertThatThrownByHasMessageParameters() {
return assertThatThrownBy(() -> {})
.isInstanceOf(IllegalArgumentException.class)

View File

@@ -1,10 +1,7 @@
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.BoundType;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@@ -24,8 +21,7 @@ final class AssortedRulesTest implements RefasterRuleCollectionTestCase {
Preconditions.class,
Sets.class,
Splitter.class,
Streams.class,
toImmutableSet());
Streams.class);
}
int testCheckIndex() {
@@ -38,10 +34,6 @@ final class AssortedRulesTest implements RefasterRuleCollectionTestCase {
}
}
ImmutableSet<BoundType> testStreamToImmutableEnumSet() {
return Stream.of(BoundType.OPEN).collect(toImmutableSet());
}
ImmutableSet<String> testIteratorGetNextOrDefault() {
return ImmutableSet.of(
ImmutableList.of("a").iterator().hasNext()

View File

@@ -1,12 +1,9 @@
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Sets.toImmutableEnumSet;
import static java.util.Objects.checkIndex;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.BoundType;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@@ -27,8 +24,7 @@ final class AssortedRulesTest implements RefasterRuleCollectionTestCase {
Preconditions.class,
Sets.class,
Splitter.class,
Streams.class,
toImmutableSet());
Streams.class);
}
int testCheckIndex() {
@@ -39,10 +35,6 @@ final class AssortedRulesTest implements RefasterRuleCollectionTestCase {
checkIndex(1, 2);
}
ImmutableSet<BoundType> testStreamToImmutableEnumSet() {
return Stream.of(BoundType.OPEN).collect(toImmutableEnumSet());
}
ImmutableSet<String> testIteratorGetNextOrDefault() {
return ImmutableSet.of(
Iterators.getNext(ImmutableList.of("a").iterator(), "foo"),

View File

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

View File

@@ -6,12 +6,14 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;
import com.google.errorprone.bugpatterns.BugChecker;
import com.sun.tools.javac.util.Constants;
import com.sun.tools.javac.util.Convert;
import javax.lang.model.element.Name;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
import tech.picnic.errorprone.utils.SourceCode;
final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(Convert.class, FixChoosers.class);
return ImmutableSet.of(Constants.class, Convert.class, FixChoosers.class);
}
ImmutableSet<BugCheckerRefactoringTestHelper> testBugCheckerRefactoringTestHelperIdentity() {
@@ -27,7 +29,15 @@ final class BugCheckerRulesTest implements RefasterRuleCollectionTestCase {
.expectUnchanged();
}
String testConstantsFormat() {
return Constants.format("foo");
ImmutableSet<String> testConstantsFormat() {
return ImmutableSet.of(
SourceCode.toStringConstantExpression("foo", /* REPLACEME */ null),
SourceCode.toStringConstantExpression("bar", /* REPLACEME */ null));
}
ImmutableSet<Boolean> testNameContentEquals() {
return ImmutableSet.of(
((Name) null).contentEquals("foo".subSequence(0, 1)),
((com.sun.tools.javac.util.Name) null).contentEquals("bar"));
}
}

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

@@ -1,26 +1,30 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.util.function.Function;
import java.util.function.Predicate;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class ClassRulesTest implements RefasterRuleCollectionTestCase {
boolean testClassIsInstance() throws IOException {
boolean testClassIsInstance() {
return CharSequence.class.isAssignableFrom("foo".getClass());
}
ImmutableSet<Boolean> testInstanceof() throws IOException {
ImmutableSet<Boolean> testInstanceof() {
Class<?> clazz = CharSequence.class;
return ImmutableSet.of(CharSequence.class.isInstance("foo"), clazz.isInstance("bar"));
}
Predicate<String> testClassLiteralIsInstancePredicate() throws IOException {
Predicate<String> testClassLiteralIsInstancePredicate() {
return s -> s instanceof CharSequence;
}
Predicate<String> testClassReferenceIsInstancePredicate() throws IOException {
Predicate<String> testClassReferenceIsInstancePredicate() {
Class<?> clazz = CharSequence.class;
return s -> clazz.isInstance(s);
}
Function<Number, Integer> testClassReferenceCast() {
return i -> Integer.class.cast(i);
}
}

View File

@@ -1,26 +1,30 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.util.function.Function;
import java.util.function.Predicate;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class ClassRulesTest implements RefasterRuleCollectionTestCase {
boolean testClassIsInstance() throws IOException {
boolean testClassIsInstance() {
return CharSequence.class.isInstance("foo");
}
ImmutableSet<Boolean> testInstanceof() throws IOException {
ImmutableSet<Boolean> testInstanceof() {
Class<?> clazz = CharSequence.class;
return ImmutableSet.of("foo" instanceof CharSequence, clazz.isInstance("bar"));
}
Predicate<String> testClassLiteralIsInstancePredicate() throws IOException {
Predicate<String> testClassLiteralIsInstancePredicate() {
return CharSequence.class::isInstance;
}
Predicate<String> testClassReferenceIsInstancePredicate() throws IOException {
Predicate<String> testClassReferenceIsInstancePredicate() {
Class<?> clazz = CharSequence.class;
return clazz::isInstance;
}
Function<Number, Integer> testClassReferenceCast() {
return Integer.class::cast;
}
}

View File

@@ -6,9 +6,11 @@ import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.TreeSet;
import java.util.stream.Stream;
@@ -70,6 +72,10 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
}
}
Stream<Integer> testSetStream() {
return ImmutableSet.of(1).stream().distinct();
}
ArrayList<String> testNewArrayListFromCollection() {
return Lists.newArrayList(ImmutableList.of("foo"));
}
@@ -94,6 +100,10 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableSet.of(1).asList().toString();
}
List<String> testArraysAsList() {
return Arrays.stream(new String[0]).toList();
}
ImmutableSet<Object[]> testCollectionToArray() {
return ImmutableSet.of(
ImmutableSet.of(1).toArray(new Object[1]),
@@ -109,8 +119,9 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableSet.of(1).asList().toArray(Integer[]::new);
}
Iterator<Integer> testImmutableCollectionIterator() {
return ImmutableSet.of(1).asList().iterator();
ImmutableSet<Iterator<Integer>> testCollectionIterator() {
return ImmutableSet.of(
ImmutableSet.of(1).stream().iterator(), ImmutableSet.of(2).asList().iterator());
}
ImmutableSet<Optional<Integer>> testOptionalFirstCollectionElement() {

View File

@@ -6,9 +6,11 @@ import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.TreeSet;
import java.util.stream.Stream;
@@ -62,6 +64,10 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
new HashSet<Number>().removeAll(ImmutableSet.of(2));
}
Stream<Integer> testSetStream() {
return ImmutableSet.of(1).stream();
}
ArrayList<String> testNewArrayListFromCollection() {
return new ArrayList<>(ImmutableList.of("foo"));
}
@@ -86,6 +92,10 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableSet.of(1).toString();
}
List<String> testArraysAsList() {
return Arrays.asList(new String[0]);
}
ImmutableSet<Object[]> testCollectionToArray() {
return ImmutableSet.of(
ImmutableSet.of(1).toArray(), ImmutableSet.of(2).toArray(), ImmutableSet.of(3).toArray());
@@ -99,8 +109,8 @@ final class CollectionRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableSet.of(1).toArray(Integer[]::new);
}
Iterator<Integer> testImmutableCollectionIterator() {
return ImmutableSet.of(1).iterator();
ImmutableSet<Iterator<Integer>> testCollectionIterator() {
return ImmutableSet.of(ImmutableSet.of(1).iterator(), ImmutableSet.of(2).iterator());
}
ImmutableSet<Optional<Integer>> testOptionalFirstCollectionElement() {

View File

@@ -107,6 +107,24 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
Comparator.<String>reverseOrder().compare("baz", "qux"));
}
void testCollectionsSort() {
Collections.sort(ImmutableList.of("foo", "bar"), naturalOrder());
}
ImmutableSet<String> testCollectionsMin() {
return ImmutableSet.of(
Collections.min(ImmutableList.of("foo"), naturalOrder()),
Collections.max(ImmutableList.of("bar"), reverseOrder()));
}
String testMinOfArray() {
return Arrays.stream(new String[0]).min(naturalOrder()).orElseThrow();
}
String testCollectionsMinWithComparator() {
return ImmutableSet.of("foo", "bar").stream().min(naturalOrder()).orElseThrow();
}
int testMinOfVarargs() {
return Stream.of(1, 2).min(naturalOrder()).orElseThrow();
}
@@ -135,6 +153,20 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
Collections.min(ImmutableSet.of("a", "b"), (a, b) -> 1));
}
ImmutableSet<String> testCollectionsMax() {
return ImmutableSet.of(
Collections.max(ImmutableList.of("foo"), naturalOrder()),
Collections.min(ImmutableList.of("bar"), reverseOrder()));
}
String testMaxOfArray() {
return Arrays.stream(new String[0]).max(naturalOrder()).orElseThrow();
}
String testCollectionsMaxWithComparator() {
return ImmutableSet.of("foo", "bar").stream().max(naturalOrder()).orElseThrow();
}
int testMaxOfVarargs() {
return Stream.of(1, 2).max(naturalOrder()).orElseThrow();
}

View File

@@ -98,6 +98,23 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableSet.of("foo".compareTo("bar"), "qux".compareTo("baz"));
}
void testCollectionsSort() {
Collections.sort(ImmutableList.of("foo", "bar"));
}
ImmutableSet<String> testCollectionsMin() {
return ImmutableSet.of(
Collections.min(ImmutableList.of("foo")), Collections.min(ImmutableList.of("bar")));
}
String testMinOfArray() {
return Collections.min(Arrays.asList(new String[0]), naturalOrder());
}
String testCollectionsMinWithComparator() {
return Collections.min(ImmutableSet.of("foo", "bar"), naturalOrder());
}
int testMinOfVarargs() {
return Collections.min(Arrays.asList(1, 2), naturalOrder());
}
@@ -126,6 +143,19 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
Comparators.min("a", "b", (a, b) -> 1));
}
ImmutableSet<String> testCollectionsMax() {
return ImmutableSet.of(
Collections.max(ImmutableList.of("foo")), Collections.max(ImmutableList.of("bar")));
}
String testMaxOfArray() {
return Collections.max(Arrays.asList(new String[0]), naturalOrder());
}
String testCollectionsMaxWithComparator() {
return Collections.max(ImmutableSet.of("foo", "bar"), naturalOrder());
}
int testMaxOfVarargs() {
return Collections.max(Arrays.asList(1, 2), naturalOrder());
}

View File

@@ -1,12 +1,28 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.ImmutableSet;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class FileRulesTest implements RefasterRuleCollectionTestCase {
Path testPathOfUri() {
return Paths.get(URI.create("foo"));
}
ImmutableSet<Path> testPathOfString() {
return ImmutableSet.of(Paths.get("foo"), Paths.get("bar", "baz", "qux"));
}
Path testPathInstance() {
return Path.of("foo").toFile().toPath();
}
String testFilesReadStringWithCharset() throws IOException {
return new String(Files.readAllBytes(Paths.get("foo")), StandardCharsets.ISO_8859_1);
}
@@ -14,4 +30,13 @@ final class FileRulesTest implements RefasterRuleCollectionTestCase {
String testFilesReadString() throws IOException {
return Files.readString(Paths.get("foo"), StandardCharsets.UTF_8);
}
ImmutableSet<File> testFilesCreateTempFileToFile() throws IOException {
return ImmutableSet.of(
File.createTempFile("foo", "bar"), File.createTempFile("baz", "qux", null));
}
File testFilesCreateTempFileInCustomDirectoryToFile() throws IOException {
return File.createTempFile("foo", "bar", new File("baz"));
}
}

View File

@@ -1,12 +1,28 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.ImmutableSet;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class FileRulesTest implements RefasterRuleCollectionTestCase {
Path testPathOfUri() {
return Path.of(URI.create("foo"));
}
ImmutableSet<Path> testPathOfString() {
return ImmutableSet.of(Path.of("foo"), Path.of("bar", "baz", "qux"));
}
Path testPathInstance() {
return Path.of("foo");
}
String testFilesReadStringWithCharset() throws IOException {
return Files.readString(Paths.get("foo"), StandardCharsets.ISO_8859_1);
}
@@ -14,4 +30,13 @@ final class FileRulesTest implements RefasterRuleCollectionTestCase {
String testFilesReadString() throws IOException {
return Files.readString(Paths.get("foo"));
}
ImmutableSet<File> testFilesCreateTempFileToFile() throws IOException {
return ImmutableSet.of(
Files.createTempFile("foo", "bar").toFile(), Files.createTempFile("baz", "qux").toFile());
}
File testFilesCreateTempFileInCustomDirectoryToFile() throws IOException {
return Files.createTempFile(new File("baz").toPath(), "foo", "bar").toFile();
}
}

View File

@@ -0,0 +1,96 @@
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import com.google.common.collect.BoundType;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import java.math.RoundingMode;
import java.util.EnumSet;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class ImmutableEnumSetRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(EnumSet.class, toImmutableSet());
}
ImmutableSet<ImmutableSet<RoundingMode>> testSetsImmutableEnumSetIterable() {
return ImmutableSet.of(
ImmutableSet.copyOf(Iterables.cycle(RoundingMode.UP)),
ImmutableSet.copyOf(EnumSet.allOf(RoundingMode.class)));
}
ImmutableSet<RoundingMode> testSetsImmutableEnumSetArraysAsList() {
return ImmutableSet.copyOf(RoundingMode.values());
}
ImmutableSet<ImmutableSet<RoundingMode>> testSetsImmutableEnumSet1() {
return ImmutableSet.of(
ImmutableSet.of(RoundingMode.UP), ImmutableSet.copyOf(EnumSet.of(RoundingMode.UP)));
}
ImmutableSet<ImmutableSet<RoundingMode>> testSetsImmutableEnumSet2() {
return ImmutableSet.of(
ImmutableSet.of(RoundingMode.UP, RoundingMode.DOWN),
ImmutableSet.copyOf(EnumSet.of(RoundingMode.UP, RoundingMode.DOWN)));
}
ImmutableSet<ImmutableSet<RoundingMode>> testSetsImmutableEnumSet3() {
return ImmutableSet.of(
ImmutableSet.of(RoundingMode.UP, RoundingMode.DOWN, RoundingMode.CEILING),
ImmutableSet.copyOf(EnumSet.of(RoundingMode.UP, RoundingMode.DOWN, RoundingMode.CEILING)));
}
ImmutableSet<ImmutableSet<RoundingMode>> testSetsImmutableEnumSet4() {
return ImmutableSet.of(
ImmutableSet.of(
RoundingMode.UP, RoundingMode.DOWN, RoundingMode.CEILING, RoundingMode.FLOOR),
ImmutableSet.copyOf(
EnumSet.of(
RoundingMode.UP, RoundingMode.DOWN, RoundingMode.CEILING, RoundingMode.FLOOR)));
}
ImmutableSet<ImmutableSet<RoundingMode>> testSetsImmutableEnumSet5() {
return ImmutableSet.of(
ImmutableSet.of(
RoundingMode.UP,
RoundingMode.DOWN,
RoundingMode.CEILING,
RoundingMode.FLOOR,
RoundingMode.UNNECESSARY),
ImmutableSet.copyOf(
EnumSet.of(
RoundingMode.UP,
RoundingMode.DOWN,
RoundingMode.CEILING,
RoundingMode.FLOOR,
RoundingMode.UNNECESSARY)));
}
ImmutableSet<RoundingMode> testSetsImmutableEnumSet6() {
return ImmutableSet.of(
RoundingMode.UP,
RoundingMode.DOWN,
RoundingMode.CEILING,
RoundingMode.FLOOR,
RoundingMode.UNNECESSARY,
RoundingMode.HALF_EVEN);
}
ImmutableSet<RoundingMode> testSetsImmutableEnumSetVarArgs() {
return ImmutableSet.copyOf(
EnumSet.of(
RoundingMode.UP,
RoundingMode.DOWN,
RoundingMode.CEILING,
RoundingMode.FLOOR,
RoundingMode.UNNECESSARY,
RoundingMode.HALF_EVEN));
}
ImmutableSet<BoundType> testStreamToImmutableEnumSet() {
return Stream.of(BoundType.OPEN).collect(toImmutableSet());
}
}

View File

@@ -0,0 +1,96 @@
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Sets.toImmutableEnumSet;
import com.google.common.collect.BoundType;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class ImmutableEnumSetRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(EnumSet.class, toImmutableSet());
}
ImmutableSet<ImmutableSet<RoundingMode>> testSetsImmutableEnumSetIterable() {
return ImmutableSet.of(
Sets.immutableEnumSet(Iterables.cycle(RoundingMode.UP)),
Sets.immutableEnumSet(EnumSet.allOf(RoundingMode.class)));
}
ImmutableSet<RoundingMode> testSetsImmutableEnumSetArraysAsList() {
return Sets.immutableEnumSet(Arrays.asList(RoundingMode.values()));
}
ImmutableSet<ImmutableSet<RoundingMode>> testSetsImmutableEnumSet1() {
return ImmutableSet.of(
Sets.immutableEnumSet(RoundingMode.UP), Sets.immutableEnumSet(RoundingMode.UP));
}
ImmutableSet<ImmutableSet<RoundingMode>> testSetsImmutableEnumSet2() {
return ImmutableSet.of(
Sets.immutableEnumSet(RoundingMode.UP, RoundingMode.DOWN),
Sets.immutableEnumSet(RoundingMode.UP, RoundingMode.DOWN));
}
ImmutableSet<ImmutableSet<RoundingMode>> testSetsImmutableEnumSet3() {
return ImmutableSet.of(
Sets.immutableEnumSet(RoundingMode.UP, RoundingMode.DOWN, RoundingMode.CEILING),
Sets.immutableEnumSet(RoundingMode.UP, RoundingMode.DOWN, RoundingMode.CEILING));
}
ImmutableSet<ImmutableSet<RoundingMode>> testSetsImmutableEnumSet4() {
return ImmutableSet.of(
Sets.immutableEnumSet(
RoundingMode.UP, RoundingMode.DOWN, RoundingMode.CEILING, RoundingMode.FLOOR),
Sets.immutableEnumSet(
RoundingMode.UP, RoundingMode.DOWN, RoundingMode.CEILING, RoundingMode.FLOOR));
}
ImmutableSet<ImmutableSet<RoundingMode>> testSetsImmutableEnumSet5() {
return ImmutableSet.of(
Sets.immutableEnumSet(
RoundingMode.UP,
RoundingMode.DOWN,
RoundingMode.CEILING,
RoundingMode.FLOOR,
RoundingMode.UNNECESSARY),
Sets.immutableEnumSet(
RoundingMode.UP,
RoundingMode.DOWN,
RoundingMode.CEILING,
RoundingMode.FLOOR,
RoundingMode.UNNECESSARY));
}
ImmutableSet<RoundingMode> testSetsImmutableEnumSet6() {
return Sets.immutableEnumSet(
RoundingMode.UP,
RoundingMode.DOWN,
RoundingMode.CEILING,
RoundingMode.FLOOR,
RoundingMode.UNNECESSARY,
RoundingMode.HALF_EVEN);
}
ImmutableSet<RoundingMode> testSetsImmutableEnumSetVarArgs() {
return Sets.immutableEnumSet(
RoundingMode.UP,
RoundingMode.DOWN,
RoundingMode.CEILING,
RoundingMode.FLOOR,
RoundingMode.UNNECESSARY,
RoundingMode.HALF_EVEN);
}
ImmutableSet<BoundType> testStreamToImmutableEnumSet() {
return Stream.of(BoundType.OPEN).collect(toImmutableEnumSet());
}
}

View File

@@ -26,6 +26,7 @@ final class ImmutableMultisetRulesTest implements RefasterRuleCollectionTestCase
Stream.<Integer>empty().collect(toImmutableMultiset()));
}
@SuppressWarnings("unchecked")
ImmutableMultiset<ImmutableMultiset<Integer>> testIterableToImmutableMultiset() {
return ImmutableMultiset.of(
ImmutableList.of(1).stream().collect(toImmutableMultiset()),

View File

@@ -24,6 +24,7 @@ final class ImmutableMultisetRulesTest implements RefasterRuleCollectionTestCase
return ImmutableMultiset.of(ImmutableMultiset.of(), ImmutableMultiset.of());
}
@SuppressWarnings("unchecked")
ImmutableMultiset<ImmutableMultiset<Integer>> testIterableToImmutableMultiset() {
return ImmutableMultiset.of(
ImmutableMultiset.copyOf(ImmutableList.of(1)),

View File

@@ -37,6 +37,7 @@ final class ImmutableSortedMultisetRulesTest implements RefasterRuleCollectionTe
Stream.<Integer>empty().collect(toImmutableSortedMultiset(naturalOrder())));
}
@SuppressWarnings("unchecked")
ImmutableMultiset<ImmutableSortedMultiset<Integer>> testIterableToImmutableSortedMultiset() {
return ImmutableMultiset.of(
ImmutableSortedMultiset.copyOf(naturalOrder(), ImmutableList.of(1)),

View File

@@ -35,6 +35,7 @@ final class ImmutableSortedMultisetRulesTest implements RefasterRuleCollectionTe
return ImmutableMultiset.of(ImmutableSortedMultiset.of(), ImmutableSortedMultiset.of());
}
@SuppressWarnings("unchecked")
ImmutableMultiset<ImmutableSortedMultiset<Integer>> testIterableToImmutableSortedMultiset() {
return ImmutableMultiset.of(
ImmutableSortedMultiset.copyOf(ImmutableList.of(1)),

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