Compare commits

...

85 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
90 changed files with 33696 additions and 6872 deletions

View File

@@ -26,7 +26,7 @@ jobs:
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,7 +42,7 @@ jobs:
# additionally enabling all checks defined in this project and any Error
# Prone checks available only from other artifact repositories.
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
with:
java-version: ${{ matrix.jdk }}
java-distribution: ${{ matrix.distribution }}
@@ -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

@@ -22,7 +22,7 @@ jobs:
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.13
java-distribution: temurin
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

@@ -12,7 +12,7 @@ jobs:
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@7d3497fd78c07c0d84ebafa58d8dac60cd1f0763 # v1.199.0
- uses: ruby/setup-ruby@a2bbe5b1b236842c1cb7dd11e8e3b51e0a616acc # v1.202.0
with:
working-directory: ./website
bundler-cache: true
@@ -74,7 +74,7 @@ jobs:
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

@@ -21,30 +21,33 @@ jobs:
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
github.com:443
index.docker.io:443
oss-fuzz-build-logs.storage.googleapis.com: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

@@ -12,7 +12,7 @@ jobs:
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,7 +22,7 @@ jobs:
objects.githubusercontent.com:443
repo.maven.apache.org:443
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
with:
checkout-fetch-depth: 2
java-version: 17.0.13
@@ -38,7 +38,7 @@ jobs:
- name: Aggregate Pitest reports
run: mvn pitest-git:aggregate -DkilledEmoji=":tada:" -DmutantEmoji=":zombie:" -DtrailingText="Mutation testing report by [Pitest](https://pitest.org/). Review any surviving mutants by inspecting the line comments under [_Files changed_](${{ github.event.number }}/files)."
- name: Upload Pitest reports as artifact
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: pitest-reports
path: ./target/pit-reports-ci

View File

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

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:
@@ -17,23 +17,33 @@ jobs:
if: |
github.event.issue.pull_request && contains(github.event.comment.body, '/integration-test')
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.13
@@ -42,12 +52,12 @@ jobs:
- 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

@@ -19,7 +19,7 @@ jobs:
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
@@ -35,7 +35,7 @@ jobs:
*.sonarcloud.io:443
sonarcloud.io:443
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
with:
checkout-fetch-depth: 0
java-version: 17.0.13

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

View File

@@ -72,6 +72,10 @@
<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>
@@ -162,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>

View File

@@ -18,6 +18,7 @@ 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;
/**
@@ -48,11 +49,14 @@ public final class ClassCastLambdaUsage extends BugChecker implements LambdaExpr
}
Type type = ASTHelpers.getType(typeCast);
if (type == null || type.isParameterized() || type.isPrimitive()) {
if (type == null
|| type.isParameterized()
|| type.isPrimitive()
|| type.getKind() == TypeKind.TYPEVAR) {
/*
* The method reference syntax does not support casting to parameterized types. Additionally,
* `Class#cast` does not support the same range of type conversions between (boxed) primitive
* types as the cast operator.
* 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.

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

@@ -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;
@@ -84,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

@@ -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

@@ -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

@@ -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

@@ -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

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

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

@@ -11,6 +11,7 @@ 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
@@ -56,16 +57,26 @@ final class BugCheckerRules {
}
}
/** Prefer using the {@link Constants} API over more verbose alternatives. */
/**
* Prefer {@link SourceCode#toStringConstantExpression(Object,
* com.google.errorprone.VisitorState)} over alternatives that unnecessarily escape single quote
* characters.
*/
static final class ConstantsFormat {
@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));
}
}

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

@@ -93,6 +93,12 @@ final class FileRules {
/**
* 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
@@ -117,6 +123,12 @@ final class FileRules {
/**
* 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

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

@@ -279,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) {
@@ -395,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

@@ -1742,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
@@ -1768,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
@@ -1868,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);
@@ -1890,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.
*/

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);
}

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

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

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

@@ -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;
@@ -294,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

@@ -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

@@ -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;
@@ -189,7 +188,7 @@ final class Slf4jLoggerDeclarationTest {
@Test
void replacementWithCustomLoggerName() {
BugCheckerRefactoringTestHelper.newInstance(Slf4jLoggerDeclaration.class, getClass())
.setArgs(ImmutableList.of("-XepOpt:Slf4jLogDeclaration:CanonicalStaticLoggerName=FOO_BAR"))
.setArgs("-XepOpt:Slf4jLoggerDeclaration:CanonicalStaticLoggerName=FOO_BAR")
.addInputLines(
"A.java",
"import org.slf4j.Logger;",

View File

@@ -36,6 +36,7 @@ final class RefasterRulesTest {
AssortedRules.class,
BigDecimalRules.class,
BugCheckerRules.class,
CharSequenceRules.class,
ClassRules.class,
CollectionRules.class,
ComparatorRules.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

@@ -4,6 +4,7 @@ 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;
@@ -11,7 +12,7 @@ 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() {
@@ -29,8 +30,8 @@ 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() {

View File

@@ -8,11 +8,12 @@ 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() {
@@ -28,8 +29,10 @@ 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() {

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

@@ -44,6 +44,7 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
List.class,
ImmutableCollection.class,
ImmutableMap.class,
assertThat(false),
assertThat(0),
maxBy(null),
minBy(null),
@@ -589,6 +590,35 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableSet.of(PublisherProbe.of(Mono.empty()), PublisherProbe.of(Flux.empty()));
}
void testPublisherProbeAssertWasSubscribed() {
assertThat(PublisherProbe.of(Mono.just(1)).wasSubscribed()).isTrue();
assertThat(PublisherProbe.of(Mono.just(2)).subscribeCount()).isNotNegative();
assertThat(PublisherProbe.of(Mono.just(3)).subscribeCount()).isNotEqualTo(0);
assertThat(PublisherProbe.of(Mono.just(4)).subscribeCount()).isPositive();
}
void testPublisherProbeAssertWasNotSubscribed() {
assertThat(PublisherProbe.of(Mono.just(1)).wasSubscribed()).isFalse();
assertThat(PublisherProbe.of(Mono.just(2)).subscribeCount()).isEqualTo(0);
assertThat(PublisherProbe.of(Mono.just(3)).subscribeCount()).isNotPositive();
}
void testPublisherProbeAssertWasCancelled() {
assertThat(PublisherProbe.empty().wasCancelled()).isTrue();
}
void testPublisherProbeAssertWasNotCancelled() {
assertThat(PublisherProbe.empty().wasCancelled()).isFalse();
}
void testPublisherProbeAssertWasRequested() {
assertThat(PublisherProbe.empty().wasRequested()).isTrue();
}
void testPublisherProbeAssertWasNotRequested() {
assertThat(PublisherProbe.empty().wasRequested()).isFalse();
}
ImmutableSet<StepVerifier.FirstStep<Integer>> testStepVerifierFromMono() {
return ImmutableSet.of(
StepVerifier.create(Mono.just(1)), Mono.just(2).flux().as(StepVerifier::create));
@@ -598,6 +628,18 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return StepVerifier.create(Flux.just(1));
}
Object testStepVerifierVerify() {
return Mono.empty().as(StepVerifier::create).expectError().verifyThenAssertThat();
}
Object testStepVerifierVerifyDuration() {
return Mono.empty().as(StepVerifier::create).expectError().verifyThenAssertThat(Duration.ZERO);
}
StepVerifier testStepVerifierVerifyLater() {
return Mono.empty().as(StepVerifier::create).expectError().verifyLater().verifyLater();
}
ImmutableSet<StepVerifier.Step<Integer>> testStepVerifierStepIdentity() {
return ImmutableSet.of(
Mono.just(1).as(StepVerifier::create).expectNext(),
@@ -638,17 +680,43 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
.verifyErrorSatisfies(t -> assertThat(t).isInstanceOf(AssertionError.class)));
}
Duration testStepVerifierLastStepVerifyErrorMatches() {
return Mono.empty()
.as(StepVerifier::create)
.expectErrorMatches(IllegalArgumentException.class::equals)
.verify();
ImmutableSet<?> testStepVerifierLastStepVerifyErrorMatches() {
return ImmutableSet.of(
Mono.empty()
.as(StepVerifier::create)
.expectErrorMatches(IllegalArgumentException.class::equals)
.verify(),
Mono.empty()
.as(StepVerifier::create)
.expectError()
.verifyThenAssertThat()
.hasOperatorErrorMatching(IllegalStateException.class::equals));
}
Duration testStepVerifierLastStepVerifyErrorSatisfies() {
return Mono.empty().as(StepVerifier::create).expectErrorSatisfies(t -> {}).verify();
}
ImmutableSet<?> testStepVerifierLastStepVerifyErrorSatisfiesAssertJ() {
return ImmutableSet.of(
Mono.empty()
.as(StepVerifier::create)
.expectError()
.verifyThenAssertThat()
.hasOperatorErrorOfType(IllegalArgumentException.class)
.hasOperatorErrorWithMessage("foo"),
Mono.empty()
.as(StepVerifier::create)
.expectError(IllegalStateException.class)
.verifyThenAssertThat()
.hasOperatorErrorWithMessage("bar"),
Mono.empty()
.as(StepVerifier::create)
.expectErrorMessage("baz")
.verifyThenAssertThat()
.hasOperatorErrorOfType(AssertionError.class));
}
Duration testStepVerifierLastStepVerifyErrorMessage() {
return Mono.empty().as(StepVerifier::create).expectErrorMessage("foo").verify();
}

View File

@@ -47,6 +47,7 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
List.class,
ImmutableCollection.class,
ImmutableMap.class,
assertThat(false),
assertThat(0),
maxBy(null),
minBy(null),
@@ -577,6 +578,35 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return ImmutableSet.of(PublisherProbe.empty(), PublisherProbe.empty());
}
void testPublisherProbeAssertWasSubscribed() {
PublisherProbe.of(Mono.just(1)).assertWasSubscribed();
PublisherProbe.of(Mono.just(2)).assertWasSubscribed();
PublisherProbe.of(Mono.just(3)).assertWasSubscribed();
PublisherProbe.of(Mono.just(4)).assertWasSubscribed();
}
void testPublisherProbeAssertWasNotSubscribed() {
PublisherProbe.of(Mono.just(1)).assertWasNotSubscribed();
PublisherProbe.of(Mono.just(2)).assertWasNotSubscribed();
PublisherProbe.of(Mono.just(3)).assertWasNotSubscribed();
}
void testPublisherProbeAssertWasCancelled() {
PublisherProbe.empty().assertWasCancelled();
}
void testPublisherProbeAssertWasNotCancelled() {
PublisherProbe.empty().assertWasNotCancelled();
}
void testPublisherProbeAssertWasRequested() {
PublisherProbe.empty().assertWasRequested();
}
void testPublisherProbeAssertWasNotRequested() {
PublisherProbe.empty().assertWasNotRequested();
}
ImmutableSet<StepVerifier.FirstStep<Integer>> testStepVerifierFromMono() {
return ImmutableSet.of(
Mono.just(1).as(StepVerifier::create), Mono.just(2).as(StepVerifier::create));
@@ -586,6 +616,18 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
return Flux.just(1).as(StepVerifier::create);
}
Object testStepVerifierVerify() {
return Mono.empty().as(StepVerifier::create).expectError().verify();
}
Object testStepVerifierVerifyDuration() {
return Mono.empty().as(StepVerifier::create).expectError().verify(Duration.ZERO);
}
StepVerifier testStepVerifierVerifyLater() {
return Mono.empty().as(StepVerifier::create).expectError().verifyLater();
}
ImmutableSet<StepVerifier.Step<Integer>> testStepVerifierStepIdentity() {
return ImmutableSet.of(
Mono.just(1).as(StepVerifier::create),
@@ -619,16 +661,36 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
Mono.empty().as(StepVerifier::create).verifyError(AssertionError.class));
}
Duration testStepVerifierLastStepVerifyErrorMatches() {
return Mono.empty()
.as(StepVerifier::create)
.verifyErrorMatches(IllegalArgumentException.class::equals);
ImmutableSet<?> testStepVerifierLastStepVerifyErrorMatches() {
return ImmutableSet.of(
Mono.empty()
.as(StepVerifier::create)
.verifyErrorMatches(IllegalArgumentException.class::equals),
Mono.empty()
.as(StepVerifier::create)
.verifyErrorMatches(IllegalStateException.class::equals));
}
Duration testStepVerifierLastStepVerifyErrorSatisfies() {
return Mono.empty().as(StepVerifier::create).verifyErrorSatisfies(t -> {});
}
ImmutableSet<?> testStepVerifierLastStepVerifyErrorSatisfiesAssertJ() {
return ImmutableSet.of(
Mono.empty()
.as(StepVerifier::create)
.verifyErrorSatisfies(
t -> assertThat(t).isInstanceOf(IllegalArgumentException.class).hasMessage("foo")),
Mono.empty()
.as(StepVerifier::create)
.verifyErrorSatisfies(
t -> assertThat(t).isInstanceOf(IllegalStateException.class).hasMessage("bar")),
Mono.empty()
.as(StepVerifier::create)
.verifyErrorSatisfies(
t -> assertThat(t).isInstanceOf(AssertionError.class).hasMessage("baz")));
}
Duration testStepVerifierLastStepVerifyErrorMessage() {
return Mono.empty().as(StepVerifier::create).verifyErrorMessage("foo");
}

View File

@@ -141,6 +141,12 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
return Stream.of(1).findFirst().isPresent();
}
Stream<Integer> testStreamMapFilter() {
return Stream.of("foo")
.filter(ImmutableMap.of(1, 2)::containsKey)
.map(ImmutableMap.of(1, 2)::get);
}
ImmutableSet<Optional<String>> testStreamMin() {
return ImmutableSet.of(
Stream.of("foo").max(comparingInt(String::length).reversed()),

View File

@@ -141,6 +141,10 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
return Stream.of(1).findAny().isPresent();
}
Stream<Integer> testStreamMapFilter() {
return Stream.of("foo").map(ImmutableMap.of(1, 2)::get).filter(Objects::nonNull);
}
ImmutableSet<Optional<String>> testStreamMin() {
return ImmutableSet.of(
Stream.of("foo").min(comparingInt(String::length)),

View File

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

View File

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

View File

@@ -66,6 +66,32 @@ final class TimeRulesTest implements RefasterRuleCollectionTestCase {
return Instant.EPOCH.atZone(ZoneOffset.UTC).toOffsetDateTime();
}
ImmutableSet<Instant> testInstantIdentity() {
return ImmutableSet.of(
Instant.EPOCH.plusMillis(1).plus(Duration.ZERO),
Instant.EPOCH.plusMillis(2).plus(0, ChronoUnit.MILLIS),
Instant.EPOCH.plusMillis(3).plusNanos(0L),
Instant.EPOCH.plusMillis(4).plusMillis(0),
Instant.EPOCH.plusMillis(5).plusSeconds(0L),
Instant.EPOCH.plusMillis(6).minus(Duration.ZERO),
Instant.EPOCH.plusMillis(7).minus(0, ChronoUnit.SECONDS),
Instant.EPOCH.plusMillis(8).minusNanos(0L),
Instant.EPOCH.plusMillis(9).minusMillis(0),
Instant.EPOCH.plusMillis(10).minusSeconds(0L),
Instant.parse(Instant.EPOCH.plusMillis(11).toString()),
Instant.EPOCH.plusMillis(12).truncatedTo(ChronoUnit.NANOS),
Instant.ofEpochSecond(
Instant.EPOCH.plusMillis(13).getEpochSecond(), Instant.EPOCH.plusMillis(13).getNano()));
}
Instant testInstantTruncatedToMilliseconds() {
return Instant.ofEpochMilli(Instant.EPOCH.toEpochMilli());
}
Instant testInstantTruncatedToSeconds() {
return Instant.ofEpochSecond(Instant.EPOCH.getEpochSecond());
}
OffsetDateTime testInstantAtOffset() {
return OffsetDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC);
}

View File

@@ -66,6 +66,31 @@ final class TimeRulesTest implements RefasterRuleCollectionTestCase {
return OffsetDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC);
}
ImmutableSet<Instant> testInstantIdentity() {
return ImmutableSet.of(
Instant.EPOCH.plusMillis(1),
Instant.EPOCH.plusMillis(2),
Instant.EPOCH.plusMillis(3),
Instant.EPOCH.plusMillis(4),
Instant.EPOCH.plusMillis(5),
Instant.EPOCH.plusMillis(6),
Instant.EPOCH.plusMillis(7),
Instant.EPOCH.plusMillis(8),
Instant.EPOCH.plusMillis(9),
Instant.EPOCH.plusMillis(10),
Instant.EPOCH.plusMillis(11),
Instant.EPOCH.plusMillis(12),
Instant.EPOCH.plusMillis(13));
}
Instant testInstantTruncatedToMilliseconds() {
return Instant.EPOCH.truncatedTo(ChronoUnit.MILLIS);
}
Instant testInstantTruncatedToSeconds() {
return Instant.EPOCH.truncatedTo(ChronoUnit.SECONDS);
}
OffsetDateTime testInstantAtOffset() {
return Instant.EPOCH.atOffset(ZoneOffset.UTC);
}

View File

@@ -30,8 +30,8 @@ import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.Tree.Kind;
import com.sun.tools.javac.util.Constants;
import javax.lang.model.element.Name;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags {@link BugChecker} declarations inside {@code
@@ -126,7 +126,9 @@ public final class BugPatternLink extends BugChecker implements ClassTreeMatcher
state,
"link",
ImmutableList.of(
linkPrefix + " + " + Constants.format(tree.getSimpleName().toString()))));
linkPrefix
+ " + "
+ SourceCode.toStringConstantExpression(tree.getSimpleName(), state))));
String linkType =
SuggestedFixes.qualifyStaticImport(

View File

@@ -26,8 +26,8 @@ import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.util.Constants;
import java.util.regex.Pattern;
import tech.picnic.errorprone.utils.SourceCode;
import tech.picnic.errorprone.utils.ThirdPartyLibrary;
/**
@@ -123,7 +123,8 @@ public final class ErrorProneRuntimeClasspath extends BugChecker
.setMessage("This type may not be on the runtime classpath; use a string literal instead")
.addFix(
SuggestedFix.replace(
tree, Constants.format(receiver.owner.getQualifiedName().toString())))
tree,
SourceCode.toStringConstantExpression(receiver.owner.getQualifiedName(), state)))
.build();
}
@@ -150,7 +151,9 @@ public final class ErrorProneRuntimeClasspath extends BugChecker
original,
identifier
+ ".class.getCanonicalName()"
+ (suffix.isEmpty() ? "" : (" + " + Constants.format(suffix))))
+ (suffix.isEmpty()
? ""
: (" + " + SourceCode.toStringConstantExpression(suffix, state))))
.build();
}

View File

@@ -38,7 +38,6 @@ import com.sun.tools.javac.code.Attribute;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Symbol.TypeSymbol;
import com.sun.tools.javac.util.Constants;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@@ -49,6 +48,7 @@ import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Modifier;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that validates the claim made by {@link
@@ -129,7 +129,9 @@ public final class ExhaustiveRefasterTypeMigration extends BugChecker implements
migrationAnnotation,
state,
TYPE_MIGRATION_UNMIGRATED_METHODS_ELEMENT,
unmigratedMethods.stream().map(Constants::format).collect(toImmutableList()))
unmigratedMethods.stream()
.map(m -> SourceCode.toStringConstantExpression(m, state))
.collect(toImmutableList()))
.build());
}

View File

@@ -1,14 +1,17 @@
package tech.picnic.errorprone.utils;
import static tech.picnic.errorprone.utils.JavaKeywords.isValidIdentifier;
import static java.util.Objects.requireNonNull;
import com.google.errorprone.VisitorState;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ImportTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.util.TreeScanner;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Type;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
/** A set of helper methods for detecting conflicts that would be caused when applying fixes. */
public final class ConflictDetection {
@@ -24,9 +27,10 @@ public final class ConflictDetection {
* <ul>
* <li>Whether the rename would merely introduce a method overload, rather than clashing with an
* existing method declaration in its class or a supertype.
* <li>Whether the rename would in fact clash with a static import. (It could be that a static
* import of the same name is only referenced from lexical scopes in which the method under
* consideration cannot be referenced directly.)
* <li>Whether the rename would in fact change the target of an existing method invocation in
* the scope of its containing class. (It could e.g. be that said invocation targets an
* identically-named method with different parameter types in some non-static nested type
* declaration.)
* </ul>
*
* @param method The method considered for renaming.
@@ -43,11 +47,11 @@ public final class ConflictDetection {
"a method named `%s` is already defined in this class or a supertype", newName));
}
if (isSimpleNameStaticallyImported(newName, state)) {
return Optional.of(String.format("`%s` is already statically imported", newName));
if (isLocalMethodInvocation(newName, state)) {
return Optional.of(String.format("another method named `%s` is in scope", newName));
}
if (!isValidIdentifier(newName)) {
if (!SourceCode.isValidIdentifier(newName)) {
return Optional.of(String.format("`%s` is not a valid identifier", newName));
}
@@ -60,16 +64,35 @@ public final class ConflictDetection {
.isPresent();
}
private static boolean isSimpleNameStaticallyImported(String simpleName, VisitorState state) {
return state.getPath().getCompilationUnit().getImports().stream()
.filter(ImportTree::isStatic)
.map(ImportTree::getQualifiedIdentifier)
.map(tree -> getStaticImportSimpleName(tree, state))
.anyMatch(simpleName::contentEquals);
}
private static boolean isLocalMethodInvocation(String name, VisitorState state) {
return Boolean.TRUE.equals(
new TreeScanner<Boolean, @Nullable Void>() {
@Override
public Boolean visitClass(ClassTree tree, @Nullable Void unused) {
if (ASTHelpers.getSymbol(tree).isStatic()) {
/*
* Don't descend into static type definitions: in those context, any unqualified
* method invocation cannot refer to a method in the outer scope.
*/
return Boolean.FALSE;
}
private static CharSequence getStaticImportSimpleName(Tree tree, VisitorState state) {
String source = SourceCode.treeToString(tree, state);
return source.subSequence(source.lastIndexOf('.') + 1, source.length());
return super.visitClass(tree, null);
}
@Override
public Boolean visitMethodInvocation(MethodInvocationTree tree, @Nullable Void unused) {
return (tree.getMethodSelect() instanceof IdentifierTree identifier
&& name.contentEquals(identifier.getName()))
|| super.visitMethodInvocation(tree, null);
}
@Override
public Boolean reduce(Boolean r1, Boolean r2) {
return Boolean.TRUE.equals(r1) || Boolean.TRUE.equals(r2);
}
}.scan(
requireNonNull(state.findEnclosing(ClassTree.class), "No enclosing class").getMembers(),
null));
}
}

View File

@@ -1,159 +0,0 @@
package tech.picnic.errorprone.utils;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
/** Utility class that can be used to identify reserved keywords of the Java language. */
// XXX: This class is no longer only about keywords. Consider changing its name and class-level
// documentation.
public final class JavaKeywords {
/**
* Enumeration of boolean and null literals.
*
* @see <a href="https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.10.3">JDK 17
* JLS section 3.10.3: Boolean Literals</a>
* @see <a href="https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.10.8">JDK 17
* JLS section 3.10.8: The Null Literal</a>
*/
private static final ImmutableSet<String> BOOLEAN_AND_NULL_LITERALS =
ImmutableSet.of("true", "false", "null");
/**
* List of all reserved keywords in the Java language.
*
* @see <a href="https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.9">JDK 17 JLS
* section 3.9: Keywords</a>
*/
private static final ImmutableSet<String> RESERVED_KEYWORDS =
ImmutableSet.of(
"_",
"abstract",
"assert",
"boolean",
"break",
"byte",
"case",
"catch",
"char",
"class",
"const",
"continue",
"default",
"do",
"double",
"else",
"enum",
"extends",
"final",
"finally",
"float",
"for",
"goto",
"if",
"implements",
"import",
"instanceof",
"int",
"interface",
"long",
"native",
"new",
"package",
"private",
"protected",
"public",
"return",
"short",
"static",
"strictfp",
"super",
"switch",
"synchronized",
"this",
"throw",
"throws",
"transient",
"try",
"void",
"volatile",
"while");
/**
* List of all contextual keywords in the Java language.
*
* @see <a href="https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.9">JDK 17 JLS
* section 3.9: Keywords</a>
*/
private static final ImmutableSet<String> CONTEXTUAL_KEYWORDS =
ImmutableSet.of(
"exports",
"module",
"non-sealed",
"open",
"opens",
"permits",
"provides",
"record",
"requires",
"sealed",
"to",
"transitive",
"uses",
"var",
"with",
"yield");
/** List of all keywords in the Java language. */
private static final ImmutableSet<String> ALL_KEYWORDS =
Sets.union(RESERVED_KEYWORDS, CONTEXTUAL_KEYWORDS).immutableCopy();
private JavaKeywords() {}
/**
* Tells whether the given string is a valid identifier in the Java language.
*
* @param str The string of interest.
* @return {@code true} if the given string is a valid identifier in the Java language.
* @see <a href="https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.8">JDK 17 JLS
* section 3.8: Identifiers</a>
*/
@SuppressWarnings("java:S1067" /* Chaining conjunctions like this does not impact readability. */)
public static boolean isValidIdentifier(String str) {
return !str.isEmpty()
&& !isReservedKeyword(str)
&& !BOOLEAN_AND_NULL_LITERALS.contains(str)
&& Character.isJavaIdentifierStart(str.codePointAt(0))
&& str.codePoints().skip(1).allMatch(Character::isUnicodeIdentifierPart);
}
/**
* Tells whether the given string is a reserved keyword in the Java language.
*
* @param str The string of interest.
* @return {@code true} if the given string is a reserved keyword in the Java language.
*/
public static boolean isReservedKeyword(String str) {
return RESERVED_KEYWORDS.contains(str);
}
/**
* Tells whether the given string is a contextual keyword in the Java language.
*
* @param str The string of interest.
* @return {@code true} if the given string is a contextual keyword in the Java language.
*/
public static boolean isContextualKeyword(String str) {
return CONTEXTUAL_KEYWORDS.contains(str);
}
/**
* Tells whether the given string is a reserved or contextual keyword in the Java language.
*
* @param str The string of interest.
* @return {@code true} if the given string is a reserved or contextual keyword in the Java
* language.
*/
public static boolean isKeyword(String str) {
return ALL_KEYWORDS.contains(str);
}
}

View File

@@ -17,6 +17,7 @@ import com.sun.source.tree.Tree;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.Position;
import java.util.Optional;
import javax.lang.model.SourceVersion;
/**
* A collection of Error Prone utility methods for dealing with the source code representation of
@@ -28,6 +29,18 @@ public final class SourceCode {
private SourceCode() {}
/**
* Tells whether the given string is a valid identifier in the Java language.
*
* @param str The string of interest.
* @return {@code true} if the given string is a valid identifier in the Java language.
* @see <a href="https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.8">JDK 17 JLS
* section 3.8: Identifiers</a>
*/
public static boolean isValidIdentifier(String str) {
return str.indexOf('.') < 0 && SourceVersion.isName(str);
}
/**
* Returns a string representation of the given {@link Tree}, preferring the original source code
* (if available) over its prettified representation.
@@ -42,6 +55,24 @@ public final class SourceCode {
return src != null ? src : tree.toString();
}
/**
* Returns a Java string constant expression (i.e., a quoted string) representing the given input.
*
* @param value The value of interest.
* @param state A {@link VisitorState} describing the context in which the given {@link Tree} is
* found.
* @return A non-{@code null} string.
* @apiNote This method differs from {@link com.sun.tools.javac.util.Constants#format(Object)} in
* that it does not superfluously escape single quote characters. It is different from {@link
* VisitorState#getConstantExpression(Object)} in that it is more performant and accepts any
* {@link CharSequence} instance.
*/
// XXX: Drop this method if https://github.com/google/error-prone/pull/4586 is merged and released
// with the proposed `CharSequence` compatibility change.
public static String toStringConstantExpression(Object value, VisitorState state) {
return state.getConstantExpression(value instanceof CharSequence ? value.toString() : value);
}
/**
* Creates a {@link SuggestedFix} for the deletion of the given {@link Tree}, including any
* whitespace that follows it.

View File

@@ -21,13 +21,13 @@ final class ConflictDetectionTest {
"pkg/A.java",
"package pkg;",
"",
"import static pkg.A.B.method3t;",
"import static pkg.A.StaticType.method3t;",
"import static pkg.A.StaticType.method4t;",
"",
"import pkg.A.method4t;",
"",
"class A {",
" void method1() {",
" method3t();",
" method4(method4t.class);",
" }",
"",
@@ -37,7 +37,7 @@ final class ConflictDetectionTest {
"",
" void method2t() {}",
"",
" // BUG: Diagnostic contains: `method3t` is already statically imported",
" // BUG: Diagnostic contains: another method named `method3t` is in scope",
" void method3() {}",
"",
" void method4(Object o) {}",
@@ -45,8 +45,34 @@ final class ConflictDetectionTest {
" // BUG: Diagnostic contains: `int` is not a valid identifier",
" void in() {}",
"",
" static class B {",
" static void method3t() {}",
" class InstanceType {",
" void m() {",
" System.out.println(method3t());",
" }",
" }",
"",
" static class StaticType {",
" static int method3t() {",
" return 0;",
" }",
"",
" static void method4t() {",
" method4t();",
" }",
" }",
"",
" record RecordType() {",
" void m() {",
" method4t();",
" }",
" }",
"",
" enum EnumType {",
" ELEM;",
"",
" void m() {",
" method4t();",
" }",
" }",
"",
" class method4t {}",

View File

@@ -1,34 +0,0 @@
package tech.picnic.errorprone.utils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
final class JavaKeywordsTest {
private static Stream<Arguments> isValidIdentifierTestCases() {
/* { string, expected } */
return Stream.of(
arguments("", false),
arguments("public", false),
arguments("true", false),
arguments("false", false),
arguments("null", false),
arguments("0", false),
arguments("\0", false),
arguments("a%\0", false),
arguments("a", true),
arguments("a0", true),
arguments("_a0", true),
arguments("test", true));
}
@MethodSource("isValidIdentifierTestCases")
@ParameterizedTest
void isValidIdentifier(String string, boolean expected) {
assertThat(JavaKeywords.isValidIdentifier(string)).isEqualTo(expected);
}
}

View File

@@ -1,6 +1,8 @@
package tech.picnic.errorprone.utils;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
@@ -8,18 +10,80 @@ import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.LiteralTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import java.util.Optional;
import java.util.stream.Stream;
import javax.lang.model.element.Name;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
final class SourceCodeTest {
private static Stream<Arguments> isValidIdentifierTestCases() {
/* { string, expected } */
return Stream.of(
arguments("", false),
arguments(".", false),
arguments("a.", false),
arguments(".a", false),
arguments("a.b", false),
arguments("public", false),
arguments("true", false),
arguments("false", false),
arguments("null", false),
arguments("0", false),
arguments("\0", false),
arguments("a%\0", false),
arguments("a", true),
arguments("a0", true),
arguments("_a0", true),
arguments("test", true));
}
@MethodSource("isValidIdentifierTestCases")
@ParameterizedTest
void isValidIdentifier(String string, boolean expected) {
assertThat(SourceCode.isValidIdentifier(string)).isEqualTo(expected);
}
@Test
void toStringConstantExpression() {
BugCheckerRefactoringTestHelper.newInstance(
ToStringConstantExpressionTestChecker.class, getClass())
.addInputLines(
"A.java",
"class A {",
" String m() {",
" char a = 'c';",
" char b = '\\'';",
" return \"foo\\\"bar\\'baz\\bqux\";",
" }",
"}")
.addOutputLines(
"A.java",
"class A {",
" String m() {",
" char a = 'c' /* 'c' */; /* \"a\" */",
" char b = '\\'' /* '\\'' */; /* \"b\" */",
" return \"foo\\\"bar\\'baz\\bqux\" /* \"foo\\\"bar'baz\\bqux\" */;",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
@Test
void deleteWithTrailingWhitespaceAnnotations() {
BugCheckerRefactoringTestHelper.newInstance(
@@ -228,6 +292,41 @@ final class SourceCodeTest {
.doTest(TestMode.TEXT_MATCH);
}
/**
* A {@link BugChecker} that applies {@link SourceCode#toStringConstantExpression(Object,
* VisitorState)} to string literals.
*/
@BugPattern(severity = ERROR, summary = "Interacts with `SourceCode` for testing purposes")
public static final class ToStringConstantExpressionTestChecker extends BugChecker
implements LiteralTreeMatcher, VariableTreeMatcher {
private static final long serialVersionUID = 1L;
@Override
public Description matchLiteral(LiteralTree tree, VisitorState state) {
// XXX: The character conversion is a workaround for the fact that `ASTHelpers#constValue`
// returns an `Integer` value for `char` constants.
return Optional.ofNullable(ASTHelpers.constValue(tree))
.map(
constant ->
ASTHelpers.isSubtype(ASTHelpers.getType(tree), state.getSymtab().charType, state)
? (char) (int) constant
: constant)
.map(constant -> describeMatch(tree, addComment(tree, constant, state)))
.orElse(Description.NO_MATCH);
}
@Override
public Description matchVariable(VariableTree tree, VisitorState state) {
return describeMatch(
tree, addComment(tree, ASTHelpers.getSymbol(tree).getSimpleName(), state));
}
private static SuggestedFix addComment(Tree tree, Object value, VisitorState state) {
return SuggestedFix.postfixWith(
tree, "/* %s */".formatted(SourceCode.toStringConstantExpression(value, state)));
}
}
/**
* A {@link BugChecker} that uses {@link SourceCode#deleteWithTrailingWhitespace(Tree,
* VisitorState)} to suggest the deletion of annotations and methods with a name containing

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +1,66 @@
src/it/java/com/google/checkstyle/test/chapter7javadoc/rule711generalform/InvalidJavadocPositionTest.java:[35,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/com/google/checkstyle/test/chapter7javadoc/rule734nonrequiredjavadoc/InvalidJavadocPositionTest.java:[35,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/com/google/checkstyle/test/chapter7javadoc/rule734nonrequiredjavadoc/NonRequiredJavadocTest.java:[33,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/com/sun/checkstyle/test/chapter5comments/rule52documentationcomments/InvalidJavadocPositionTest.java:[35,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAbbreviationAsWordInNameTest.java:[117,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `enum` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAbbreviationAsWordInNameTest.java:[169,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAbbreviationAsWordInNameTest.java:[116,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `enum` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAbbreviationAsWordInNameTest.java:[166,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAbbreviationAsWordInNameTest.java:[91,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `class` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAnnotationLocationTest.java:[104,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `enum` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAnnotationLocationTest.java:[101,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `enum` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAnnotationLocationTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `class` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAnnotationLocationTest.java:[71,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAnnotationLocationTest.java:[69,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAnonInnerLengthTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAvoidEscapedUnicodeCharactersTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionAvoidNoArgumentSuperConstructorCallTest.java:[41,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionCatchParameterNameTest.java:[166,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `enum` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionCatchParameterNameTest.java:[193,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionCatchParameterNameTest.java:[161,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `enum` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionCatchParameterNameTest.java:[187,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionClassMemberImpliedModifierTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionClassMemberImpliedModifierTest.java:[71,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `enum` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionClassTypeParameterNameTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `class` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionClassTypeParameterNameTest.java:[69,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionConstructorsDeclarationGroupingTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `class` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionConstructorsDeclarationGroupingTest.java:[70,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `enum` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionDeclarationOrderTest.java:[64,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `static` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionEqualsAvoidNullTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `equals` is already defined in this class or a supertype)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionFinalClassTest.java:[38,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionIllegalImportTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionIllegalImportTest.java:[53,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `static` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionIllegalInstantiationTest.java:[91,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionLambdaBodyLengthTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionIllegalTokenTest.java:[56,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `native` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionIllegalTokenTextTest.java:[91,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionIndentationTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionLambdaParameterNameTest.java:[41,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMemberNameTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMethodCountTest.java:[109,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `protected` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMethodCountTest.java:[134,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `public` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMethodCountTest.java:[37,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMethodCountTest.java:[61,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `private` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMethodCountTest.java:[85,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `package` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMethodNameTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMissingJavadocTypeTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `class` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMissingOverrideTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `class` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMissingOverrideTest.java:[67,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMissingOverrideTest.java:[66,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMultipleStringLiteralsTest.java:[41,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionMutableExceptionTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionNeedBracesTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `do` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionNoLineWrapTest.java:[37,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionOuterTypeNumberTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionOverloadMethodsDeclarationOrderTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionParameterNumberTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionRecordComponentNameTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionRecordComponentNumberTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionReturnCountTest.java:[38,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `void` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionSeparatorWrapTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `class` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionSeparatorWrapTest.java:[60,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionSimplifyBooleanExpressionTest.java:[90,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `interface` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionSuperFinalizeTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionThrowsCountTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionTypeNameTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionUncommentedMainTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionUnnecessarySemicolonAfterTypeMemberDeclarationTest.java:[41,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionUnnecessarySemicolonInTryWithResourcesTest.java:[41,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionUnusedImportsTest.java:[57,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `static` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/DetailAstImplTest.java:[595,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
src/test/java/com/puppycrawl/tools/checkstyle/PackageNamesLoaderTest.java:[58,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/api/FilterSetTest.java:[49,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
src/test/java/com/puppycrawl/tools/checkstyle/api/FullIdentTest.java:[41,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
src/test/java/com/puppycrawl/tools/checkstyle/api/FullIdentTest.java:[42,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
src/test/java/com/puppycrawl/tools/checkstyle/checks/AvoidEscapedUnicodeCharactersCheckTest.java:[77,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/DescendantTokenCheckTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/OrderedPropertiesCheckTest.java:[49,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
@@ -46,6 +78,7 @@ src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/ArrayTrailingCommaCh
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/AvoidDoubleBraceInitializationCheckTest.java:[37,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/AvoidInlineConditionalsCheckTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/AvoidNoArgumentSuperConstructorCallCheckTest.java:[37,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/ConstructorsDeclarationGroupingCheckTest.java:[35,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/CovariantEqualsCheckTest.java:[36,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/DeclarationOrderCheckTest.java:[44,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/DefaultComesLastCheckTest.java:[55,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
@@ -70,8 +103,7 @@ src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/UnnecessarySemicolon
src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/UnnecessarySemicolonInTryWithResourcesCheckTest.java:[38,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/design/InterfaceIsTypeCheckTest.java:[37,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/design/MutableExceptionCheckTest.java:[54,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/design/ThrowsCountCheckTest.java:[39,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheckTest.java:[99,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `null` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheckTest.java:[100,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `null` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheckTest.java:[81,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/InvalidJavadocPositionCheckTest.java:[59,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocContentLocationCheckTest.java:[57,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
@@ -81,8 +113,8 @@ src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocNodeImplTest
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTagInfoTest.java:[230,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `throws` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTagInfoTest.java:[294,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `return` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTagTest.java:[58,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTypeCheckTest.java:[83,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `protected` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTypeCheckTest.java:[89,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `public` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTypeCheckTest.java:[84,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `protected` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTypeCheckTest.java:[90,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `public` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocVariableCheckTest.java:[60,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/MissingJavadocTypeCheckTest.java:[118,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `protected` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/MissingJavadocTypeCheckTest.java:[126,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `public` is not a valid identifier)
@@ -133,7 +165,7 @@ src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressWithNearbyCommentF
src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionCommentFilterTest.java:[151,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionSingleFilterTest.java:[42,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `default` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/grammar/antlr4/Antlr4AstRegressionTest.java:[34,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `package` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/grammar/comments/CommentsTest.java:[53,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
src/test/java/com/puppycrawl/tools/checkstyle/grammar/comments/CommentsTest.java:[69,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
src/test/java/com/puppycrawl/tools/checkstyle/grammar/java8/DefaultMethodsTest.java:[40,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that `switch` is not a valid identifier)
src/test/java/com/puppycrawl/tools/checkstyle/gui/BaseCellEditorTest.java:[31,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
src/test/java/com/puppycrawl/tools/checkstyle/utils/CheckUtilTest.java:[71,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `equals` is already defined in this class or a supertype)

View File

@@ -1,19 +1,24 @@
--- a/pom.xml
+++ b/pom.xml
@@ -366,6 +366,12 @@
<version>1.4.1</version>
@@ -368,6 +368,12 @@
<version>1.4.4</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <version>${assertj.version}</version>
+ <version>3.27.0<!-- Renovate: org.assertj:assertj-bom --></version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
@@ -2422,6 +2428,8 @@
@@ -2421,9 +2427,13 @@
<compilerArgs>
<arg>-Xpkginfo:always</arg>
<arg>-XDcompilePolicy=simple</arg>
+ <!-- XXX: Drop this flag once the project uses Error Prone 2.36.0+ by default. -->
+ <arg>--should-stop=ifError=FLOW</arg>
<arg>
-Xplugin:ErrorProne ${error-prone.configuration-args}
</arg>
@@ -22,7 +27,7 @@
</compilerArgs>
<annotationProcessorPaths>
<path>
@@ -2434,6 +2442,11 @@
@@ -2436,6 +2446,11 @@
<artifactId>error-prone-contrib</artifactId>
<version>${error-prone-support.version}</version>
</path>
@@ -34,8 +39,12 @@
</annotationProcessorPaths>
</configuration>
</execution>
@@ -2476,9 +2489,10 @@
@@ -2476,11 +2491,14 @@
<compilerArgs>
<arg>-Xpkginfo:always</arg>
<arg>-XDcompilePolicy=simple</arg>
+ <!-- XXX: Drop this flag once the project uses Error Prone 2.36.0+ by default. -->
+ <arg>--should-stop=ifError=FLOW</arg>
<arg>
-Xplugin:ErrorProne \
- -XepExcludedPaths:.*[\\/]resources[\\/].* \
@@ -46,7 +55,7 @@
</compilerArgs>
<annotationProcessorPaths>
<path>
@@ -2491,6 +2505,11 @@
@@ -2493,6 +2511,11 @@
<artifactId>error-prone-contrib</artifactId>
<version>${error-prone-support.version}</version>
</path>
@@ -58,6 +67,39 @@
</annotationProcessorPaths>
</configuration>
</execution>
--- a/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule21filename/FileNameTest.java
+++ b/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule21filename/FileNameTest.java
@@ -23,6 +23,8 @@ import org.junit.jupiter.api.Test;
import com.google.checkstyle.test.base.AbstractGoogleModuleTestSupport;
+// This class is referenced from another package.
+@SuppressWarnings("JUnitClassModifiers")
public class FileNameTest extends AbstractGoogleModuleTestSupport {
@Override
--- a/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule3sourcefile/SourceFileStructureTest.java
+++ b/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule3sourcefile/SourceFileStructureTest.java
@@ -23,6 +23,8 @@ import org.junit.jupiter.api.Test;
import com.google.checkstyle.test.base.AbstractGoogleModuleTestSupport;
+// This class is referenced from another package.
+@SuppressWarnings("JUnitClassModifiers")
public class SourceFileStructureTest extends AbstractGoogleModuleTestSupport {
@Override
--- a/src/it/java/com/google/checkstyle/test/chapter3filestructure/toolongpackagetotestcoveragegooglesjavastylerule/PackageStatementTest.java
+++ b/src/it/java/com/google/checkstyle/test/chapter3filestructure/toolongpackagetotestcoveragegooglesjavastylerule/PackageStatementTest.java
@@ -23,6 +23,8 @@ import org.junit.jupiter.api.Test;
import com.google.checkstyle.test.base.AbstractGoogleModuleTestSupport;
+// This class is referenced from another package.
+@SuppressWarnings("JUnitClassModifiers")
public class PackageStatementTest extends AbstractGoogleModuleTestSupport {
@Override
--- a/src/main/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinter.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinter.java
@@ -63,6 +63,8 @@ public final class DetailNodeTreeStringPrinter {
@@ -71,7 +113,7 @@
final ParseStatus status = parser.parseJavadocAsDetailNode(blockComment);
--- a/src/main/java/com/puppycrawl/tools/checkstyle/SarifLogger.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/SarifLogger.java
@@ -139,6 +139,9 @@ public class SarifLogger extends AbstractAutomaticBean implements AuditListener
@@ -157,6 +157,9 @@ public class SarifLogger extends AbstractAutomaticBean implements AuditListener
@Override
public void auditFinished(AuditEvent event) {
final String version = SarifLogger.class.getPackage().getImplementationVersion();
@@ -83,7 +125,7 @@
.replace(RESULTS_PLACEHOLDER, String.join(",\n", results));
--- a/src/test/java/com/puppycrawl/tools/checkstyle/CheckerTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/CheckerTest.java
@@ -93,6 +93,8 @@ import de.thetaphi.forbiddenapis.SuppressForbidden;
@@ -97,6 +97,8 @@ import de.thetaphi.forbiddenapis.SuppressForbidden;
* @noinspectionreason ClassWithTooManyDependencies - complex tests require a large number
* of imports
*/
@@ -125,7 +167,7 @@
assertWithMessage("Exception is expected but got " + test).fail();
--- a/src/test/java/com/puppycrawl/tools/checkstyle/TreeWalkerTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/TreeWalkerTest.java
@@ -80,6 +80,8 @@ import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
@@ -84,6 +84,8 @@ import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
* @noinspectionreason ClassWithTooManyDependencies - complex tests require a
* large number of imports
*/

View File

@@ -5,10 +5,10 @@ set -e -u -o pipefail
test_name="$(basename "${0}" .sh)"
project='checkstyle'
repository='https://github.com/checkstyle/checkstyle.git'
revision='checkstyle-10.14.0'
# XXX: Configure Renovate to manage the AssertJ version declared here.
additional_build_flags='-Dassertj.version=3.24.2'
revision='checkstyle-10.21.0'
additional_build_flags='-Perror-prone-compile,error-prone-test-compile -Dmaven.compiler.failOnError=true'
additional_source_directories='${project.basedir}${file.separator}src${file.separator}it${file.separator}java,${project.basedir}${file.separator}src${file.separator}xdocs-examples${file.separator}java'
shared_error_prone_flags='-XepExcludedPaths:(\Q${project.basedir}${file.separator}src${file.separator}\E(it|test|xdocs-examples)\Q${file.separator}resources\E|\Q${project.build.directory}${file.separator}\E).*'
patch_error_prone_flags=''
validation_error_prone_flags=''
# Validation skips some tests:
@@ -30,6 +30,7 @@ fi
"${revision}" \
"${additional_build_flags}" \
"${additional_source_directories}" \
"${shared_error_prone_flags}" \
"${patch_error_prone_flags}" \
"${validation_error_prone_flags}" \
"${validation_build_flags}" \

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
metrics-collectd/src/main/java/io/dropwizard/metrics5/collectd/CollectdReporter.java:[306,57] [rawtypes] found raw type: Gauge
metrics-collectd/src/main/java/io/dropwizard/metrics5/collectd/PacketWriter.java:[164,12] [cast] redundant cast to ByteBuffer
metrics-collectd/src/main/java/io/dropwizard/metrics5/collectd/PacketWriter.java:[169,11] [cast] redundant cast to ByteBuffer
metrics-collectd/src/main/java/io/dropwizard/metrics5/collectd/PacketWriter.java:[175,17] [cast] redundant cast to ByteBuffer
metrics-collectd/src/main/java/io/dropwizard/metrics5/collectd/PacketWriter.java:[200,8] [cast] redundant cast to ByteBuffer
metrics-collectd/src/main/java/io/dropwizard/metrics5/collectd/PacketWriter.java:[203,21] [cast] redundant cast to ByteBuffer
metrics-collectd/src/main/java/io/dropwizard/metrics5/collectd/PacketWriter.java:[206,11] [cast] redundant cast to ByteBuffer
metrics-collectd/src/main/java/io/dropwizard/metrics5/collectd/PacketWriter.java:[250,36] [cast] redundant cast to ByteBuffer
metrics-core/src/main/java/io/dropwizard/metrics5/CsvReporter.java:[390,35] [FormatStringConcatenation] Defer string concatenation to the invoked method
metrics-core/src/main/java/io/dropwizard/metrics5/InstrumentedExecutorService.java:[244,25] [try] auto-closeable resource durationContext is never referenced in body of corresponding try statement
metrics-core/src/main/java/io/dropwizard/metrics5/InstrumentedExecutorService.java:[266,25] [try] auto-closeable resource context is never referenced in body of corresponding try statement
metrics-graphite/src/main/java/io/dropwizard/metrics5/graphite/GraphiteReporter.java:[431,14] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-graphite/src/main/java/io/dropwizard/metrics5/graphite/GraphiteReporter.java:[436,16] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-graphite/src/main/java/io/dropwizard/metrics5/graphite/GraphiteReporter.java:[449,17] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-healthchecks/src/test/java/io/dropwizard/metrics5/health/HealthCheckTest.java:[189,46] [TimeZoneUsage] Derive the current time from an existing `Clock` Spring bean, and don't rely on a `Clock`'s time zone
metrics-healthchecks/src/test/java/io/dropwizard/metrics5/health/HealthCheckTest.java:[203,46] [TimeZoneUsage] Derive the current time from an existing `Clock` Spring bean, and don't rely on a `Clock`'s time zone
metrics-httpclient/src/test/java/io/dropwizard/metrics5/httpclient/HttpClientMetricNameStrategiesTest.java:[124,22] [deprecation] rewriteURI(URI,HttpHost,boolean) in URIUtils has been deprecated
metrics-httpclient5/src/main/java/io/dropwizard/metrics5/httpclient5/InstrumentedAsyncClientConnectionManager.java:[29,62] [deprecation] getDefault() in DefaultClientTlsStrategy has been deprecated
metrics-httpclient5/src/main/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpClientConnectionManager.java:[116,50] [deprecation] ConnectionSocketFactory in org.apache.hc.client5.http.socket has been deprecated
metrics-httpclient5/src/main/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpClientConnectionManager.java:[160,12] [deprecation] DefaultHttpClientConnectionOperator(Lookup<ConnectionSocketFactory>,SchemePortResolver,DnsResolver) in DefaultHttpClientConnectionOperator has been deprecated
metrics-httpclient5/src/main/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpClientConnectionManager.java:[30,28] [deprecation] ConnectionSocketFactory in org.apache.hc.client5.http.socket has been deprecated
metrics-httpclient5/src/main/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpClientConnectionManager.java:[31,28] [deprecation] ConnectionSocketFactory in org.apache.hc.client5.http.socket has been deprecated
metrics-httpclient5/src/main/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpClientConnectionManager.java:[32,37] [deprecation] PlainConnectionSocketFactory in org.apache.hc.client5.http.socket has been deprecated
metrics-httpclient5/src/main/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpClientConnectionManager.java:[33,38] [deprecation] SSLConnectionSocketFactory in org.apache.hc.client5.http.ssl has been deprecated
metrics-httpclient5/src/main/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpClientConnectionManager.java:[96,21] [deprecation] ConnectionSocketFactory in org.apache.hc.client5.http.socket has been deprecated
metrics-httpclient5/src/main/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpRequestExecutor.java:[49,4] [deprecation] HttpRequestExecutor(Timeout,ConnectionReuseStrategy,Http1StreamListener) in HttpRequestExecutor has been deprecated
metrics-httpclient5/src/test/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpClientsTest.java:[46,10] [deprecation] execute(ClassicHttpRequest) in HttpClient has been deprecated
metrics-httpclient5/src/test/java/io/dropwizard/metrics5/httpclient5/InstrumentedHttpClientsTest.java:[68,12] [deprecation] execute(ClassicHttpRequest) in HttpClient has been deprecated
metrics-influxdb/src/main/java/io/dropwizard/metrics5/influxdb/InfluxDbReporter.java:[282,14] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-influxdb/src/main/java/io/dropwizard/metrics5/influxdb/InfluxDbReporter.java:[287,16] [Slf4jLogStatement] Log statement contains 0 placeholders, but specifies 1 matching argument(s)
metrics-jakarta-servlets/src/test/java/io/dropwizard/metrics5/servlets/HealthCheckServletTest.java:[31,67] [TimeZoneUsage] Derive the current time from an existing `Clock` Spring bean, and don't rely on a `Clock`'s time zone
metrics-jdbi3/src/test/java/io/dropwizard/metrics5/jdbi3/strategies/SmartNameStrategyTest.java:[18,10] [deprecation] InstrumentedTimingCollector in io.dropwizard.metrics5.jdbi3 has been deprecated
metrics-jdbi3/src/test/java/io/dropwizard/metrics5/jdbi3/strategies/SmartNameStrategyTest.java:[24,20] [deprecation] InstrumentedTimingCollector in io.dropwizard.metrics5.jdbi3 has been deprecated
metrics-jvm/src/test/java/io/dropwizard/metrics5/jvm/BufferPoolMetricSetTest.java:[101,74] [unchecked] unchecked cast
metrics-jvm/src/test/java/io/dropwizard/metrics5/jvm/BufferPoolMetricSetTest.java:[56,74] [unchecked] unchecked cast
metrics-jvm/src/test/java/io/dropwizard/metrics5/jvm/BufferPoolMetricSetTest.java:[65,74] [unchecked] unchecked cast
metrics-jvm/src/test/java/io/dropwizard/metrics5/jvm/BufferPoolMetricSetTest.java:[74,74] [unchecked] unchecked cast
metrics-jvm/src/test/java/io/dropwizard/metrics5/jvm/BufferPoolMetricSetTest.java:[83,74] [unchecked] unchecked cast
metrics-jvm/src/test/java/io/dropwizard/metrics5/jvm/BufferPoolMetricSetTest.java:[92,74] [unchecked] unchecked cast
metrics-legacy-adapter/src/main/java/com/codahale/metrics/MetricRegistry.java:[108,27] [rawtypes] found raw type: Gauge
metrics-legacy-adapter/src/main/java/com/codahale/metrics/MetricRegistry.java:[112,27] [rawtypes] found raw type: Gauge
metrics-legacy-adapter/src/main/java/com/codahale/metrics/MetricRegistry.java:[51,49] [rawtypes] found raw type: Gauge
metrics-legacy-adapter/src/main/java/com/codahale/metrics/MetricRegistry.java:[51,9] [rawtypes] found raw type: Gauge
metrics-legacy-adapter/src/test/java/com/codahale/metrics/MetricRegistryTest.java:[367,22] [rawtypes] found raw type: Gauge
metrics-legacy-adapter/src/test/java/com/codahale/metrics/MetricRegistryTest.java:[50,4] [rawtypes] found raw type: Gauge
metrics-log4j2/src/main/java/io/dropwizard/metrics5/log4j2/InstrumentedAppender.java:[85,4] [deprecation] AbstractAppender(String,Filter,Layout<? extends Serializable>,boolean) in AbstractAppender has been deprecated
metrics-log4j2/src/main/java/io/dropwizard/metrics5/log4j2/InstrumentedAppender.java:[96,4] [deprecation] AbstractAppender(String,Filter,Layout<? extends Serializable>,boolean) in AbstractAppender has been deprecated
metrics-servlets/src/test/java/io/dropwizard/metrics5/servlets/HealthCheckServletTest.java:[31,67] [TimeZoneUsage] Derive the current time from an existing `Clock` Spring bean, and don't rely on a `Clock`'s time zone

View File

@@ -0,0 +1,100 @@
--- a/metrics-jakarta-servlets/src/main/java/io/dropwizard/metrics5/servlets/MetricsServlet.java
+++ b/metrics-jakarta-servlets/src/main/java/io/dropwizard/metrics5/servlets/MetricsServlet.java
@@ -188,6 +188,9 @@ public class MetricsServlet extends HttpServlet {
return mapper.writer();
}
+ // Here `value` may be `null`, while `TimeUnit#valueOf` requires a non-`null` argument.
+ // XXX: Investigate better nullness handling by `IdentityConversion`.
+ @SuppressWarnings("IdentityConversion")
protected TimeUnit parseTimeUnit(String value, TimeUnit defaultValue) {
try {
return TimeUnit.valueOf(String.valueOf(value).toUpperCase(Locale.US));
--- a/metrics-servlets/src/main/java/io/dropwizard/metrics5/servlets/MetricsServlet.java
+++ b/metrics-servlets/src/main/java/io/dropwizard/metrics5/servlets/MetricsServlet.java
@@ -188,6 +188,9 @@ public class MetricsServlet extends HttpServlet {
return mapper.writer();
}
+ // Here `value` may be `null`, while `TimeUnit#valueOf` requires a non-`null` argument.
+ // XXX: Investigate better nullness handling by `IdentityConversion`.
+ @SuppressWarnings("IdentityConversion")
protected TimeUnit parseTimeUnit(String value, TimeUnit defaultValue) {
try {
return TimeUnit.valueOf(String.valueOf(value).toUpperCase(Locale.US));
--- a/pom.xml
+++ b/pom.xml
@@ -136,6 +136,27 @@
</repository>
</distributionManagement>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.errorprone</groupId>
+ <artifactId>error_prone_annotations</artifactId>
+ <version>${error-prone.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>33.4.0-jre<!-- Renovate: com.google.guava:guava-bom --></version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ </dependencies>
+
<profiles>
<profile>
<id>jdk8</id>
@@ -218,7 +239,9 @@
<compilerArgs>
<arg>-Xlint:all</arg>
<arg>-XDcompilePolicy=simple</arg>
- <arg>-Xplugin:ErrorProne -XepExcludedPaths:.*/target/generated-sources/.*</arg>
+ <!-- XXX: Drop this flag once the project uses Error Prone 2.36.0+ by default. -->
+ <arg>--should-stop=ifError=FLOW</arg>
+ <arg>-Xplugin:ErrorProne ${error-prone.configuration-args}</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
@@ -229,12 +252,24 @@
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
+ <arg>-Xmaxwarns</arg>
+ <arg>1000000</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
- <version>${errorprone.version}</version>
+ <version>${error-prone.version}</version>
+ </path>
+ <path>
+ <groupId>tech.picnic.error-prone-support</groupId>
+ <artifactId>error-prone-contrib</artifactId>
+ <version>${error-prone-support.version}</version>
+ </path>
+ <path>
+ <groupId>tech.picnic.error-prone-support</groupId>
+ <artifactId>refaster-runner</artifactId>
+ <version>${error-prone-support.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
@@ -364,7 +399,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
- <release>8</release>
+ <release>11</release>
<fork>true</fork>
<parameters>true</parameters>
<showWarnings>true</showWarnings>

36
integration-tests/metrics.sh Executable file
View File

@@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -e -u -o pipefail
test_name="$(basename "${0}" .sh)"
project='metrics'
repository='https://github.com/dropwizard/metrics.git'
revision='v5.0.0-rc22'
additional_build_flags=''
additional_source_directories=''
# XXX: Minimize the diff by including
# `-XepOpt:Slf4jLoggerDeclaration:CanonicalStaticLoggerName=LOGGER` once such
# flags are supported in patch mode. See
# https://github.com/google/error-prone/pull/4699.
shared_error_prone_flags='-XepExcludedPaths:.*/target/generated-sources/.*'
patch_error_prone_flags=''
validation_error_prone_flags=''
validation_build_flags=''
if [ "${#}" -gt 2 ] || ([ "${#}" = 2 ] && [ "${1:---sync}" != '--sync' ]); then
>&2 echo "Usage: ${0} [--sync] [<report_directory>]"
exit 1
fi
"$(dirname "${0}")/run-integration-test.sh" \
"${test_name}" \
"${project}" \
"${repository}" \
"${revision}" \
"${additional_build_flags}" \
"${additional_source_directories}" \
"${shared_error_prone_flags}" \
"${patch_error_prone_flags}" \
"${validation_error_prone_flags}" \
"${validation_build_flags}" \
$@

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
integration-tests/it-exporter/it-exporter-httpserver-sample/src/main/java/io/prometheus/metrics/it/exporter/httpserver/HTTPServerSample.java:[15,5] [ConstantNaming] Constant variables should adhere to the `UPPER_SNAKE_CASE` naming convention; consider renaming to 'SUCCESS', though note that this is not a private constant
integration-tests/it-exporter/it-exporter-httpserver-sample/src/main/java/io/prometheus/metrics/it/exporter/httpserver/HTTPServerSample.java:[16,5] [ConstantNaming] Constant variables should adhere to the `UPPER_SNAKE_CASE` naming convention; consider renaming to 'ERROR', though note that this is not a private constant
integration-tests/it-exporter/it-exporter-no-protobuf/src/main/java/io/prometheus/metrics/it/exporter/httpserver/HTTPServerSample.java:[15,5] [ConstantNaming] Constant variables should adhere to the `UPPER_SNAKE_CASE` naming convention; consider renaming to 'SUCCESS', though note that this is not a private constant
integration-tests/it-exporter/it-exporter-no-protobuf/src/main/java/io/prometheus/metrics/it/exporter/httpserver/HTTPServerSample.java:[16,5] [ConstantNaming] Constant variables should adhere to the `UPPER_SNAKE_CASE` naming convention; consider renaming to 'ERROR', though note that this is not a private constant
integration-tests/it-exporter/it-exporter-servlet-jetty-sample/src/main/java/io/prometheus/metrics/it/exporter/servlet/jetty/ExporterServletJettySample.java:[18,5] [ConstantNaming] Constant variables should adhere to the `UPPER_SNAKE_CASE` naming convention; consider renaming to 'SUCCESS', though note that this is not a private constant
integration-tests/it-exporter/it-exporter-servlet-jetty-sample/src/main/java/io/prometheus/metrics/it/exporter/servlet/jetty/ExporterServletJettySample.java:[19,5] [ConstantNaming] Constant variables should adhere to the `UPPER_SNAKE_CASE` naming convention; consider renaming to 'ERROR', though note that this is not a private constant
integration-tests/it-exporter/it-exporter-servlet-tomcat-sample/src/main/java/io/prometheus/metrics/it/exporter/servlet/tomcat/ExporterServletTomcatSample.java:[21,5] [ConstantNaming] Constant variables should adhere to the `UPPER_SNAKE_CASE` naming convention; consider renaming to 'SUCCESS', though note that this is not a private constant
integration-tests/it-exporter/it-exporter-servlet-tomcat-sample/src/main/java/io/prometheus/metrics/it/exporter/servlet/tomcat/ExporterServletTomcatSample.java:[22,5] [ConstantNaming] Constant variables should adhere to the `UPPER_SNAKE_CASE` naming convention; consider renaming to 'ERROR', though note that this is not a private constant
prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/CounterTest.java:[180,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `incWithExemplar` is already defined in this class or a supertype)
prometheus-metrics-instrumentation-jvm/src/main/java/io/prometheus/metrics/instrumentation/jvm/JvmNativeMemoryMetrics.java:[96,30] [ConstantNaming] Constant variables should adhere to the `UPPER_SNAKE_CASE` naming convention; consider renaming to 'IS_ENABLED', though note that this is not a private constant
prometheus-metrics-instrumentation-jvm/src/main/java/io/prometheus/metrics/instrumentation/jvm/NativeImageChecker.java:[11,24] [ConstantNaming] Constant variables should adhere to the `UPPER_SNAKE_CASE` naming convention; consider renaming to 'IS_GRAAL_VM_NATIVE_IMAGE', though note that this is not a private constant
prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/registry/PrometheusRegistry.java:[16,42] [ConstantNaming] Constant variables should adhere to the `UPPER_SNAKE_CASE` naming convention; consider renaming to 'DEFAULT_REGISTRY', though note that this is not a private constant
prometheus-metrics-model/src/test/java/io/prometheus/metrics/model/snapshots/LabelTest.java:[19,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `toString` is already defined in this class or a supertype)
prometheus-metrics-model/src/test/java/io/prometheus/metrics/model/snapshots/LabelTest.java:[24,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `equals` is already defined in this class or a supertype)
prometheus-metrics-model/src/test/java/io/prometheus/metrics/model/snapshots/LabelTest.java:[29,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that a method named `hashCode` is already defined in this class or a supertype)
prometheus-metrics-model/src/test/java/io/prometheus/metrics/model/snapshots/PrometheusNamingTest.java:[12,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that another method named `sanitizeMetricName` is in scope)
prometheus-metrics-model/src/test/java/io/prometheus/metrics/model/snapshots/PrometheusNamingTest.java:[44,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that another method named `sanitizeLabelName` is in scope)
prometheus-metrics-model/src/test/java/io/prometheus/metrics/model/snapshots/PrometheusNamingTest.java:[55,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that another method named `validateUnitName` is in scope)
prometheus-metrics-model/src/test/java/io/prometheus/metrics/model/snapshots/PrometheusNamingTest.java:[67,8] [JUnitMethodDeclaration] This method's name should not redundantly start with `test` (but note that another method named `sanitizeUnitName` is in scope)

View File

@@ -0,0 +1,36 @@
--- a/pom.xml
+++ b/pom.xml
@@ -128,7 +128,6 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
@@ -370,13 +369,24 @@
-Xep:LongDoubleConversion:OFF
-Xep:StringSplitter:OFF
-XepExcludedPaths:.*/generated/.*
+ ${error-prone.configuration-args}
</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
- <version>2.36.0</version>
+ <version>${error-prone.version}</version>
+ </path>
+ <path>
+ <groupId>tech.picnic.error-prone-support</groupId>
+ <artifactId>error-prone-contrib</artifactId>
+ <version>${error-prone-support.version}</version>
+ </path>
+ <path>
+ <groupId>tech.picnic.error-prone-support</groupId>
+ <artifactId>refaster-runner</artifactId>
+ <version>${error-prone-support.version}</version>
</path>
<!-- Other annotation processors go here.

View File

@@ -0,0 +1,40 @@
#!/usr/bin/env bash
set -e -u -o pipefail
test_name="$(basename "${0}" .sh)"
project='prometheus-java-client'
repository='https://github.com/prometheus/client_java.git'
revision='v1.3.5'
additional_build_flags='-Djava.version=11 -Dwarnings='
additional_source_directories=''
shared_error_prone_flags=''
patch_error_prone_flags=''
validation_error_prone_flags=''
# Validation skips some tests:
# - Starting from a clean repository, the `PushGatewayIT` tests reference a JAR
# file that is created only after test completion, causing the tests to fail.
# - The `SlidingWindowTest#rotate` test is flaky.
# XXX: Drop the `SlidingWindowTest` exclusion once prometheus/client_java#1242
# is resolved. For unclear reasons, it appears that without this exclusion the
# integration tests are no longer executed, meaning that perhaps all flags
# specified here can then be dropped.
validation_build_flags='-Dtest=!PushGatewayIT,!SlidingWindowTest#rotate -Dsurefire.failIfNoSpecifiedTests=false'
if [ "${#}" -gt 2 ] || ([ "${#}" = 2 ] && [ "${1:---sync}" != '--sync' ]); then
>&2 echo "Usage: ${0} [--sync] [<report_directory>]"
exit 1
fi
"$(dirname "${0}")/run-integration-test.sh" \
"${test_name}" \
"${project}" \
"${repository}" \
"${revision}" \
"${additional_build_flags}" \
"${additional_source_directories}" \
"${shared_error_prone_flags}" \
"${patch_error_prone_flags}" \
"${validation_error_prone_flags}" \
"${validation_build_flags}" \
$@

View File

@@ -12,8 +12,8 @@ integration_test_root="$(cd "$(dirname -- "${0}")" && pwd)"
error_prone_support_root="${integration_test_root}/.."
repos_root="${integration_test_root}/.repos"
if [ "${#}" -lt 9 ] || [ "${#}" -gt 11 ] || ([ "${#}" = 11 ] && [ "${10:---sync}" != '--sync' ]); then
>&2 echo "Usage: $(basename "${0}") <test_name> <project> <repository> <revision> <additional_build_flags> <additional_source_directories> <patch_error_prone_flags> <validation_error_prone_flags> <validation_build_flags> [--sync] [<report_directory>]"
if [ "${#}" -lt 10 ] || [ "${#}" -gt 12 ] || ([ "${#}" = 12 ] && [ "${11:---sync}" != '--sync' ]); then
>&2 echo "Usage: $(basename "${0}") <test_name> <project> <repository> <revision> <additional_build_flags> <additional_source_directories> <shared_error_prone_flags> <patch_error_prone_flags> <validation_error_prone_flags> <validation_build_flags> [--sync] [<report_directory>]"
exit 1
fi
@@ -23,11 +23,12 @@ repository="${3}"
revision="${4}"
additional_build_flags="${5}"
additional_source_directories="${6}"
patch_error_prone_flags="${7}"
validation_error_prone_flags="${8}"
validation_build_flags="${9}"
do_sync="$([ "${#}" = 9 ] || [ "${10:-}" != '--sync' ] || echo 1)"
report_directory="$([ "${#}" = 9 ] || ([ -z "${do_sync}" ] && echo "${10}") || ([ "${#}" = 10 ] || echo "${11}"))"
shared_error_prone_flags="${7}"
patch_error_prone_flags="${8}"
validation_error_prone_flags="${9}"
validation_build_flags="${10}"
do_sync="$([ "${#}" = 10 ] || [ "${11:-}" != '--sync' ] || echo 1)"
report_directory="$([ "${#}" = 10 ] || ([ -z "${do_sync}" ] && echo "${11}") || ([ "${#}" = 11 ] || echo "${12}"))"
if [ -n "${report_directory}" ]; then
mkdir -p "${report_directory}"
@@ -52,7 +53,6 @@ case "$(uname -s)" in
esac
shared_build_flags="
-Perror-prone-compile,error-prone-test-compile
-Derror-prone.version=$(
mvn -f "${error_prone_support_root}" help:evaluate -Dexpression=version.error-prone -q -DforceStdout
)
@@ -63,15 +63,9 @@ shared_build_flags="
${additional_build_flags}
"
# XXX: Configure Renovate to manage the fmt-maven-plugin version declared here.
# XXX: Once GitHub actions uses Maven 3.9.2+, we can inline this variable with
# version reference `${fmt.version}`, and `-Dfmt.version=2.21.1` added to
# `shared_build_flags`.
format_goal='com.spotify.fmt:fmt-maven-plugin:2.21.1:format'
format_goal='com.spotify.fmt:fmt-maven-plugin:2.25:format'
error_prone_shared_flags='-XepExcludedPaths:(\Q${project.basedir}${file.separator}src${file.separator}\E(it|test|xdocs-examples)\Q${file.separator}resources\E|\Q${project.build.directory}${file.separator}\E).*'
error_prone_patch_flags="${error_prone_shared_flags} -XepPatchLocation:IN_PLACE -XepPatchChecks:$(
error_prone_patch_flags="${shared_error_prone_flags} -XepPatchLocation:IN_PLACE -XepPatchChecks:$(
find "${error_prone_support_root}" \
-path "*/META-INF/services/com.google.errorprone.bugpatterns.BugChecker" \
-not -path "*/error-prone-experimental/*" \
@@ -81,7 +75,7 @@ error_prone_patch_flags="${error_prone_shared_flags} -XepPatchLocation:IN_PLACE
| paste -s -d ',' -
) ${patch_error_prone_flags}"
error_prone_validation_flags="${error_prone_shared_flags} -XepDisableAllChecks $(
error_prone_validation_flags="${shared_error_prone_flags} -XepDisableAllChecks $(
find "${error_prone_support_root}" \
-path "*/META-INF/services/com.google.errorprone.bugpatterns.BugChecker" \
-not -path "*/error-prone-experimental/*" \
@@ -125,14 +119,22 @@ pushd "${project_root}"
git config user.email || git config user.email 'integration-test@example.com'
git config user.name || git config user.name 'Integration Test'
# Prepare the code for analysis by (a) applying the minimal set of changes
# required to run Error Prone with Error Prone Support and (b) formatting the
# code using the same method by which it will be formatted after each
# compilation round. The initial formatting operation ensures that subsequent
# modifications can be rendered in a clean manner.
# Prepare the code for analysis by applying the minimal set of changes required
# to run Error Prone with Error Prone Support.
initial_patch="${integration_test_root}/${test_name}-init.patch"
git clean -fdx
git apply < "${integration_test_root}/${test_name}-init.patch"
git apply < "${initial_patch}"
git commit -m 'dependency: Introduce Error Prone Support' .
if [ -n "${do_sync}" ]; then
# The initial patch applied successfully, but if it was created against a
# different version, then offsets may have changed. Here we update the patch
# to exactly match the new state.
git diff HEAD~1 | "${grep_command}" -vP '^(diff|index)' > "${initial_patch}"
fi
# Format the patched code using the same method by which it will be formatted
# after each compilation round. This initial formatting operation ensures that
# subsequent modifications can be rendered in a clean manner.
mvn ${shared_build_flags} "${format_goal}"
git commit -m 'minor: Reformat using Google Java Format' .
diff_base="$(git rev-parse HEAD)"
@@ -141,10 +143,13 @@ diff_base="$(git rev-parse HEAD)"
function apply_patch() {
local extra_build_args="${1}"
mvn ${shared_build_flags} ${extra_build_args} \
package "${format_goal}" \
-Derror-prone.configuration-args="${error_prone_patch_flags}" \
-DskipTests
(
set -x \
&& mvn ${shared_build_flags} ${extra_build_args} \
package "${format_goal}" \
-Derror-prone.configuration-args="${error_prone_patch_flags}" \
-DskipTests
)
if ! git diff --exit-code; then
git commit -m 'minor: Apply patches' .
@@ -168,12 +173,13 @@ apply_patch ''
# By also running the tests, we validate that the (majority of) applied changes
# are behavior preserving.
validation_build_log="${report_directory}/${test_name}-validation-build-log.txt"
mvn ${shared_build_flags} \
clean package \
-Derror-prone.configuration-args="${error_prone_validation_flags}" \
${validation_build_flags} \
| tee "${validation_build_log}" \
|| failure=1
(
set -x \
&& mvn ${shared_build_flags} \
clean package \
-Derror-prone.configuration-args="${error_prone_validation_flags}" \
${validation_build_flags}
) | tee "${validation_build_log}" || failure=1
# Collect the applied changes.
expected_changes="${integration_test_root}/${test_name}-expected-changes.patch"

103
pom.xml
View File

@@ -93,6 +93,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
@@ -113,7 +114,7 @@
-Xmx${argLine.xmx}
<!-- Configure the Byte Buddy Java agent used by Mockito to create
mocks. -->
-javaagent:${org.mockito:mockito-core:jar}
<!-- -javaagent:${org.mockito:mockito-core:jar} -->
<!-- This argument cannot be set through Surefire's
'systemPropertyVariables' configuration setting. Setting the file
encoding is necessary because forked unit test invocations
@@ -211,16 +212,16 @@
<version.auto-value>1.11.0</version.auto-value>
<version.error-prone>${version.error-prone-orig}</version.error-prone>
<version.error-prone-fork>v${version.error-prone-orig}-picnic-1</version.error-prone-fork>
<version.error-prone-orig>2.35.1</version.error-prone-orig>
<version.error-prone-orig>2.36.0</version.error-prone-orig>
<version.error-prone-slf4j>0.1.28</version.error-prone-slf4j>
<version.guava-beta-checker>1.0</version.guava-beta-checker>
<version.jdk>17</version.jdk>
<version.maven>3.9.9</version.maven>
<version.mockito>5.14.2</version.mockito>
<version.nopen-checker>1.0.1</version.nopen-checker>
<version.nullaway>0.12.1</version.nullaway>
<version.nullaway>0.12.2</version.nullaway>
<version.pitest-git>1.1.4</version.pitest-git>
<version.rewrite-templating>1.16.3</version.rewrite-templating>
<version.rewrite-templating>1.20.2</version.rewrite-templating>
<version.surefire>3.2.3</version.surefire>
</properties>
@@ -299,7 +300,7 @@
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>2.18.1</version>
<version>2.18.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -336,7 +337,7 @@
<dependency>
<groupId>com.google.googlejavaformat</groupId>
<artifactId>google-java-format</artifactId>
<version>1.24.0</version>
<version>1.25.2</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
@@ -346,7 +347,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-bom</artifactId>
<version>33.3.1-jre</version>
<version>33.4.0-jre</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -367,13 +368,15 @@
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<version>1.13.6</version>
<artifactId>micrometer-bom</artifactId>
<version>1.14.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-bom</artifactId>
<version>2023.0.11</version>
<version>2024.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -390,7 +393,7 @@
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.2.25</version>
<version>2.2.27</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
@@ -425,7 +428,7 @@
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.15.10</version>
<version>1.15.11</version>
</dependency>
<!-- Specified so that Renovate will file Maven upgrade PRs, which
subsequently will cause `maven-enforcer-plugin` to require that
@@ -443,14 +446,19 @@
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-bom</artifactId>
<version>3.26.3</version>
<version>3.27.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
<version>3.48.2</version>
<version>3.48.3</version>
</dependency>
<dependency>
<groupId>org.gaul</groupId>
<artifactId>modernizer-maven-plugin</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
@@ -462,6 +470,11 @@
<artifactId>value-annotations</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>3.19.16</version>
</dependency>
<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
@@ -470,7 +483,7 @@
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.11.3</version>
<version>5.11.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -484,14 +497,7 @@
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-core</artifactId>
<version>5.2.0</version>
</dependency>
<!-- XXX: Drop this `rewrite-java-17` version declaration once
`rewrite-recipe-bom` pulls in version 8.39.1 or greater. -->
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-java-17</artifactId>
<version>8.38.1</version>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
@@ -501,7 +507,7 @@
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-recipe-bom</artifactId>
<version>2.21.1</version>
<version>2.23.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -515,19 +521,19 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>6.1.14</version>
<version>6.2.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>3.3.5</version>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-bom</artifactId>
<version>6.3.4</version>
<version>6.4.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -928,7 +934,7 @@
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>10.20.0</version>
<version>10.21.0</version>
</dependency>
<dependency>
<groupId>io.spring.nohttp</groupId>
@@ -979,6 +985,7 @@
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
@@ -1227,7 +1234,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.10.1</version>
<version>3.11.2</version>
<configuration>
<additionalJOptions>
<additionalJOption>--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</additionalJOption>
@@ -1310,15 +1317,10 @@
<redirectTestOutputToFile>true</redirectTestOutputToFile>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.6.0</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>license-maven-plugin</artifactId>
<version>2.4.0</version>
<version>2.5.0</version>
<configuration>
<includedLicenses>
<!-- The SPDX IDs of licenses of third-party
@@ -1360,6 +1362,7 @@
<!-- XXX: Get projects referencing just "BSD"
to explicitly state the clause count. -->
BSD-2-Clause
| The BSD 2-Clause License
| The BSD License
</licenseMerge>
<licenseMerge>
@@ -1373,6 +1376,8 @@
| BSD licence
| BSD License 3
| Eclipse Distribution License (New BSD License)
| Eclipse Distribution License - v 1.0
| EDL 1.0
| New BSD License
</licenseMerge>
<licenseMerge>
@@ -1457,7 +1462,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.17.1</version>
<version>2.18.0</version>
<configuration>
<updateBuildOutputTimestampPolicy>never</updateBuildOutputTimestampPolicy>
</configuration>
@@ -1526,7 +1531,7 @@
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>1.17.0</version>
<version>1.17.3</version>
<configuration>
<excludedClasses>
<!-- AutoValue generated classes. -->
@@ -1580,7 +1585,7 @@
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>4.0.0.4121</version>
<version>5.0.0.4389</version>
</plugin>
</plugins>
</pluginManagement>
@@ -1972,12 +1977,6 @@
<!-- XXX: Enable this once we open-source
this library. -->
-Xep:BetaApi:OFF
<!-- This check flags bad member names, but
also type names that we may want to accept.
Consider contributing a flag to toggle this
behavior. See
https://github.com/google/error-prone/issues/4616 -->
-Xep:IdentifierName:OFF
<!-- We don't target JDK 7. -->
-Xep:Java7ApiChecker:OFF
<!-- We don't target JDK 8. -->
@@ -1993,6 +1992,9 @@
<!-- XXX: Enable once there are fewer
false-positives.
-XepOpt:CheckReturnValue:CheckAllMethods=true -->
<!-- XXX: Consider renaming flagged types
instead. -->
-XepOpt:IdentifierName:AllowInitialismsInTypeName=true
-XepOpt:InlineMe:SkipInliningsWithComments=false
-XepOpt:NullAway:AnnotatedPackages=tech.picnic
-XepOpt:NullAway:AssertsEnabled=true
@@ -2007,11 +2009,18 @@
</arg>
<!-- The Error Prone plugin makes certain
assumptions about the state of the AST at the
moment it is invoked. Those assumptions are met
when using the `simple` compile policy. This
flag may be dropped after resolution of
moment it is invoked. Those assumptions require
the `simple` compile policy. This flag may be
dropped after resolution of
https://bugs.openjdk.java.net/browse/JDK-8155674. -->
<arg>-XDcompilePolicy=simple</arg>
<!-- Similarly, Error Prone requires that flow
analysis has been performed, e.g. to determine
whether variables are effectively final. This
flag may be dropped if it ever becomes the
default. See
https://bugs.openjdk.org/browse/JDK-8134117. -->
<arg>--should-stop=ifError=FLOW</arg>
</compilerArgs>
</configuration>
</plugin>

View File

@@ -1,8 +1,32 @@
# An overview of Error Prone Support releases, along with compatible Error
# Prone releases. This data was generated by `generate-version-compatibility-overview.sh`.
releases:
- version: 0.19.1
compatible:
- "2.36.0"
- "2.35.1"
- "2.35.0"
- "2.34.0"
- "2.33.0"
- "2.32.0"
- "2.31.0"
- "2.30.0"
- version: 0.19.0
compatible:
- "2.36.0"
- "2.35.1"
- "2.35.0"
- "2.34.0"
- "2.33.0"
- "2.32.0"
- "2.31.0"
- "2.30.0"
- version: 0.18.0
compatible:
- "2.36.0"
- "2.35.1"
- "2.35.0"
- "2.34.0"
- "2.33.0"
- "2.32.0"
- "2.31.0"

View File

@@ -45,6 +45,13 @@ for eps_version in ${eps_versions}; do
(set +u && echo n | sdk install maven "${mvn_version}")
sdk use maven "${mvn_version}"
# As of version 2.36.0, Error Prone requires that the
# `--should-stop=ifError=FLOW` flag is provided. Make sure that this flag is
# always specified. (The `-XDcompilePolicy=simple` flag has been specified
# since the first Error Prone Support release. It's okay if the added flag is
# present more than once; the last variant listed wins.)
sed -i 's,<arg>-XDcompilePolicy=simple</arg>,<arg>-XDcompilePolicy=simple</arg><arg>--should-stop=ifError=FLOW</arg>,' pom.xml
# Collect the list of checks supported by this version of Error Prone
# Support.
# XXX: Conditionally omit the `MethodReferenceUsage` exclusion once that