Compare commits

...

90 Commits

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

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

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

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

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

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

View File

@@ -9,7 +9,7 @@ jobs:
build:
strategy:
matrix:
os: [ ubuntu-22.04 ]
os: [ ubuntu-24.04 ]
jdk: [ 17.0.13, 21.0.5, 23.0.1 ]
distribution: [ temurin ]
experimental: [ false ]
@@ -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

@@ -19,10 +19,10 @@ jobs:
permissions:
contents: read
security-events: write
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
disable-sudo: true
egress-policy: block
@@ -34,19 +34,19 @@ jobs:
repo.maven.apache.org:443
uploads.github.com:443
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
with:
java-version: 17.0.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

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

View File

@@ -18,33 +18,36 @@ jobs:
contents: read
security-events: write
id-token: write
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
disable-sudo: true
egress-policy: block
allowed-endpoints: >
api.deps.dev:443
api.github.com:443
api.osv.dev:443
api.scorecard.dev:443
api.securityscorecards.dev:443
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

@@ -9,10 +9,10 @@ permissions:
contents: read
jobs:
analyze-pr:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
disable-sudo: true
egress-policy: block
@@ -22,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

@@ -17,10 +17,10 @@ jobs:
checks: write
contents: read
pull-requests: write
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
disable-sudo: true
egress-policy: block
@@ -31,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:
@@ -16,24 +16,34 @@ jobs:
name: On-demand integration test
if: |
github.event.issue.pull_request && contains(github.event.comment.body, '/integration-test')
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
strategy:
matrix:
integration-test: [ "checkstyle", "metrics", "prometheus-java-client" ]
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
disable-sudo: true
egress-policy: block
allowed-endpoints: >
# XXX: After updating the validation build flags in
# `integration-tests/prometheus-java-client.sh`, review whether the
# Docker domains specified here can be dropped.
api.adoptium.net:443
auth.docker.io:443
checkstyle.org:443
example.com:80
github.com:443
objects.githubusercontent.com:443
oss.sonatype.org:443
production.cloudflare.docker.com:443
raw.githubusercontent.com:443
registry-1.docker.io:443
repo.maven.apache.org:443
repository.sonatype.org:443
- name: Check out code and set up JDK and Maven
uses: s4u/setup-maven-action@489441643219d2b93ee2a127b2402eb640a1b947 # v1.13.0
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
with:
checkout-ref: "refs/pull/${{ github.event.issue.number }}/head"
java-version: 17.0.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

@@ -16,10 +16,10 @@ jobs:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
permissions:
contents: read
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Install Harden-Runner
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
with:
disable-sudo: true
egress-policy: block
@@ -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

@@ -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
@@ -247,6 +247,12 @@ Java Compiler_ and deselect the option _Use '--release' option for
cross-compilation (Java 9 and later)_. See [IDEA-288052][idea-288052] for
details.
The `BugChecker` implementations provided by this project are tested using
Error Prone's `CompilationTestHelper` and `BugCheckerRefactoringTestHelper`
classes. These utilities accept text blocks containing inline Java source code.
To ease modification of this inline source code, consider using IntelliJ IDEA's
[language injection][idea-language-injection] feature.
## 💡 How it works
This project provides additional [`BugChecker`][error-prone-bugchecker]
@@ -284,6 +290,7 @@ channel; please see our [security policy][security] for details.
[github-actions-build-master]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yml?query=branch:master&event=push
[google-java-format]: https://github.com/google/google-java-format
[idea-288052]: https://youtrack.jetbrains.com/issue/IDEA-288052
[idea-language-injection]: https://www.jetbrains.com/help/idea/using-language-injections.html
[license-badge]: https://img.shields.io/github/license/PicnicSupermarket/error-prone-support
[license]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/LICENSE.md
[maven-central-badge]: https://img.shields.io/maven-central/v/tech.picnic.error-prone-support/error-prone-support?color=blue

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.19.1</version>
<version>0.19.2-SNAPSHOT</version>
</parent>
<artifactId>documentation-support</artifactId>
@@ -81,6 +81,11 @@
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>

View File

@@ -28,6 +28,7 @@ import java.util.List;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.BugPatternTestCases;
import tech.picnic.errorprone.utils.SourceCode;
/**
* An {@link Extractor} that describes how to extract data from classes that test a {@code
@@ -189,21 +190,10 @@ public final class BugPatternTestExtractor implements Extractor<BugPatternTestCa
}
}
// XXX: This logic is duplicated in `ErrorProneTestSourceFormat`. Can we do better?
private static Optional<String> getSourceCode(MethodInvocationTree tree) {
List<? extends ExpressionTree> sourceLines =
tree.getArguments().subList(1, tree.getArguments().size());
StringBuilder source = new StringBuilder();
for (ExpressionTree sourceLine : sourceLines) {
String value = ASTHelpers.constValue(sourceLine, String.class);
if (value == null) {
return Optional.empty();
}
source.append(value).append('\n');
}
return Optional.of(source.toString());
return SourceCode.joinConstantSourceCodeLines(
tree.getArguments().subList(1, tree.getArguments().size()))
.map(s -> s + '\n');
}
}

View File

@@ -19,9 +19,11 @@ final class BugPatternExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerWithoutAnnotation.java",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"public final class TestCheckerWithoutAnnotation extends BugChecker {}");
"""
import com.google.errorprone.bugpatterns.BugChecker;
public final class TestCheckerWithoutAnnotation extends BugChecker {}
""");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@@ -31,14 +33,16 @@ final class BugPatternExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"MinimalBugChecker.java",
"package pkg;",
"",
"import com.google.errorprone.BugPattern;",
"import com.google.errorprone.BugPattern.SeverityLevel;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"@BugPattern(summary = \"MinimalBugChecker summary\", severity = SeverityLevel.ERROR)",
"public final class MinimalBugChecker extends BugChecker {}");
"""
package pkg;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.bugpatterns.BugChecker;
@BugPattern(summary = "MinimalBugChecker summary", severity = SeverityLevel.ERROR)
public final class MinimalBugChecker extends BugChecker {}
""");
verifyGeneratedFileContent(
outputDirectory,
@@ -62,25 +66,27 @@ final class BugPatternExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"CompleteBugChecker.java",
"package pkg;",
"",
"import com.google.errorprone.BugPattern;",
"import com.google.errorprone.BugPattern.SeverityLevel;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"import org.junit.jupiter.api.Test;",
"",
"@BugPattern(",
" name = \"OtherName\",",
" summary = \"CompleteBugChecker summary\",",
" linkType = BugPattern.LinkType.CUSTOM,",
" link = \"https://error-prone.picnic.tech\",",
" explanation = \"Example explanation\",",
" severity = SeverityLevel.SUGGESTION,",
" altNames = \"Check\",",
" tags = BugPattern.StandardTags.SIMPLIFICATION,",
" disableable = false,",
" suppressionAnnotations = {BugPattern.class, Test.class})",
"public final class CompleteBugChecker extends BugChecker {}");
"""
package pkg;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.bugpatterns.BugChecker;
import org.junit.jupiter.api.Test;
@BugPattern(
name = "OtherName",
summary = "CompleteBugChecker summary",
linkType = BugPattern.LinkType.CUSTOM,
link = "https://error-prone.picnic.tech",
explanation = "Example explanation",
severity = SeverityLevel.SUGGESTION,
altNames = "Check",
tags = BugPattern.StandardTags.SIMPLIFICATION,
disableable = false,
suppressionAnnotations = {BugPattern.class, Test.class})
public final class CompleteBugChecker extends BugChecker {}
""");
verifyGeneratedFileContent(
outputDirectory,
@@ -104,17 +110,19 @@ final class BugPatternExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"UndocumentedSuppressionBugPattern.java",
"package pkg;",
"",
"import com.google.errorprone.BugPattern;",
"import com.google.errorprone.BugPattern.SeverityLevel;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"@BugPattern(",
" summary = \"UndocumentedSuppressionBugPattern summary\",",
" severity = SeverityLevel.WARNING,",
" documentSuppression = false)",
"public final class UndocumentedSuppressionBugPattern extends BugChecker {}");
"""
package pkg;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.bugpatterns.BugChecker;
@BugPattern(
summary = "UndocumentedSuppressionBugPattern summary",
severity = SeverityLevel.WARNING,
documentSuppression = false)
public final class UndocumentedSuppressionBugPattern extends BugChecker {}
""");
verifyGeneratedFileContent(
outputDirectory,

View File

@@ -18,9 +18,11 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerWithoutAnnotation.java",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"public final class TestCheckerWithoutAnnotation extends BugChecker {}");
"""
import com.google.errorprone.bugpatterns.BugChecker;
public final class TestCheckerWithoutAnnotation extends BugChecker {}
""");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@@ -30,22 +32,24 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class TestCheckerTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\");",
"",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\");",
" }",
"}");
"""
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
final class TestCheckerTest {
private static class TestChecker extends BugChecker {}
void m() {
CompilationTestHelper.newInstance(TestChecker.class, getClass())
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}");
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
.addInputLines("A.java", "class A {}")
.addOutputLines("A.java", "class A { /* This is a change. */ }");
}
}
""");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@@ -55,22 +59,24 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class TestCheckerTest {",
" void m() {",
" CompilationTestHelper.newInstance((Class<BugChecker>) null, getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance((Class<BugChecker>) null, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .doTest();",
" }",
"}");
"""
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
final class TestCheckerTest {
void m() {
CompilationTestHelper.newInstance((Class<BugChecker>) null, getClass())
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
.doTest();
BugCheckerRefactoringTestHelper.newInstance((Class<BugChecker>) null, getClass())
.addInputLines("A.java", "class A {}")
.addOutputLines("A.java", "class A { /* This is a change. */ }")
.doTest();
}
}
""");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@@ -80,28 +86,30 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class TestCheckerTest {",
" private static class TestChecker extends BugChecker {}",
"",
" @SuppressWarnings(\"unchecked\")",
" void m() {",
" @SuppressWarnings(\"rawtypes\")",
" Class bugChecker = TestChecker.class;",
"",
" CompilationTestHelper.newInstance(bugChecker, getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance(bugChecker, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .doTest();",
" }",
"}");
"""
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
final class TestCheckerTest {
private static class TestChecker extends BugChecker {}
@SuppressWarnings("unchecked")
void m() {
@SuppressWarnings("rawtypes")
Class bugChecker = TestChecker.class;
CompilationTestHelper.newInstance(bugChecker, getClass())
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
.doTest();
BugCheckerRefactoringTestHelper.newInstance(bugChecker, getClass())
.addInputLines("A.java", "class A {}")
.addOutputLines("A.java", "class A { /* This is a change. */ }")
.doTest();
}
}
""");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@@ -111,27 +119,29 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"import com.google.errorprone.scanner.ScannerSupplier;",
"",
"final class TestCheckerTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(",
" ScannerSupplier.fromBugCheckerClasses(TestChecker.class), getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance(",
" ScannerSupplier.fromBugCheckerClasses(TestChecker.class), getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .doTest();",
" }",
"}");
"""
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.scanner.ScannerSupplier;
final class TestCheckerTest {
private static class TestChecker extends BugChecker {}
void m() {
CompilationTestHelper.newInstance(
ScannerSupplier.fromBugCheckerClasses(TestChecker.class), getClass())
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
.doTest();
BugCheckerRefactoringTestHelper.newInstance(
ScannerSupplier.fromBugCheckerClasses(TestChecker.class), getClass())
.addInputLines("A.java", "class A {}")
.addOutputLines("A.java", "class A { /* This is a change. */ }")
.doTest();
}
}
""");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@@ -141,29 +151,31 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class TestCheckerTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .addSourceLines(toString() + \"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .addSourceLines(\"B.java\", \"// BUG: Diagnostic contains:\", \"class B {}\", toString())",
" .doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .addInputLines(toString() + \"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .addInputLines(\"B.java\", \"class B {}\", toString())",
" .addOutputLines(\"B.java\", \"class B { /* This is a change. */ }\")",
" .addInputLines(\"C.java\", \"class C {}\")",
" .addOutputLines(\"C.java\", \"class C { /* This is a change. */ }\", toString())",
" .doTest();",
" }",
"}");
"""
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
final class TestCheckerTest {
private static class TestChecker extends BugChecker {}
void m() {
CompilationTestHelper.newInstance(TestChecker.class, getClass())
.addSourceLines(toString() + "A.java", "// BUG: Diagnostic contains:", "class A {}")
.addSourceLines("B.java", "// BUG: Diagnostic contains:", "class B {}", toString())
.doTest();
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
.addInputLines(toString() + "A.java", "class A {}")
.addOutputLines("A.java", "class A { /* This is a change. */ }")
.addInputLines("B.java", "class B {}", toString())
.addOutputLines("B.java", "class B { /* This is a change. */ }")
.addInputLines("C.java", "class C {}")
.addOutputLines("C.java", "class C { /* This is a change. */ }", toString())
.doTest();
}
}
""");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@@ -173,26 +185,28 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class TestCheckerTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper testHelper =",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .addSourceLines(\"A.java\", \"class A {}\");",
" testHelper.doTest();",
"",
" BugCheckerRefactoringTestHelper.ExpectOutput expectedOutput =",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .addInputLines(\"A.java\", \"class A {}\");",
" expectedOutput.addOutputLines(\"A.java\", \"class A {}\").doTest();",
" expectedOutput.expectUnchanged().doTest();",
" }",
"}");
"""
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
final class TestCheckerTest {
private static class TestChecker extends BugChecker {}
void m() {
CompilationTestHelper testHelper =
CompilationTestHelper.newInstance(TestChecker.class, getClass())
.addSourceLines("A.java", "class A {}");
testHelper.doTest();
BugCheckerRefactoringTestHelper.ExpectOutput expectedOutput =
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
.addInputLines("A.java", "class A {}");
expectedOutput.addOutputLines("A.java", "class A {}").doTest();
expectedOutput.expectUnchanged().doTest();
}
}
""");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@@ -202,19 +216,21 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class TestCheckerTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass()).doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass()).doTest();",
" }",
"}");
"""
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
final class TestCheckerTest {
private static class TestChecker extends BugChecker {}
void m() {
CompilationTestHelper.newInstance(TestChecker.class, getClass()).doTest();
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass()).doTest();
}
}
""");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@@ -224,26 +240,28 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"TestCheckerTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class TestCheckerTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .addSourceLines(\"A.java\", \"class A {}\")",
" .doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A {}\")",
" .addInputLines(\"B.java\", \"class B {}\")",
" .expectUnchanged()",
" .doTest();",
" }",
"}");
"""
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
final class TestCheckerTest {
private static class TestChecker extends BugChecker {}
void m() {
CompilationTestHelper.newInstance(TestChecker.class, getClass())
.addSourceLines("A.java", "class A {}")
.doTest();
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
.addInputLines("A.java", "class A {}")
.addOutputLines("A.java", "class A {}")
.addInputLines("B.java", "class B {}")
.expectUnchanged()
.doTest();
}
}
""");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@@ -253,18 +271,20 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"SingleFileCompilationTestHelperTest.java",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class SingleFileCompilationTestHelperTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .doTest();",
" }",
"}");
"""
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
final class SingleFileCompilationTestHelperTest {
private static class TestChecker extends BugChecker {}
void m() {
CompilationTestHelper.newInstance(TestChecker.class, getClass())
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
.doTest();
}
}
""");
verifyGeneratedFileContent(
outputDirectory,
@@ -285,19 +305,21 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"SingleFileCompilationTestHelperWithSetArgsTest.java",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class SingleFileCompilationTestHelperWithSetArgsTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .setArgs(\"-XepAllSuggestionsAsWarnings\")",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .doTest();",
" }",
"}");
"""
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
final class SingleFileCompilationTestHelperWithSetArgsTest {
private static class TestChecker extends BugChecker {}
void m() {
CompilationTestHelper.newInstance(TestChecker.class, getClass())
.setArgs("-XepAllSuggestionsAsWarnings")
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
.doTest();
}
}
""");
verifyGeneratedFileContent(
outputDirectory,
@@ -318,19 +340,21 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"MultiFileCompilationTestHelperTest.java",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class MultiFileCompilationTestHelperTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .addSourceLines(\"B.java\", \"// BUG: Diagnostic contains:\", \"class B {}\")",
" .doTest();",
" }",
"}");
"""
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
final class MultiFileCompilationTestHelperTest {
private static class TestChecker extends BugChecker {}
void m() {
CompilationTestHelper.newInstance(TestChecker.class, getClass())
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
.addSourceLines("B.java", "// BUG: Diagnostic contains:", "class B {}")
.doTest();
}
}
""");
verifyGeneratedFileContent(
outputDirectory,
@@ -353,19 +377,21 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"SingleFileBugCheckerRefactoringTestHelperTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class SingleFileBugCheckerRefactoringTestHelperTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .doTest();",
" }",
"}");
"""
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
final class SingleFileBugCheckerRefactoringTestHelperTest {
private static class TestChecker extends BugChecker {}
void m() {
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
.addInputLines("A.java", "class A {}")
.addOutputLines("A.java", "class A { /* This is a change. */ }")
.doTest();
}
}
""");
verifyGeneratedFileContent(
outputDirectory,
@@ -387,23 +413,25 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;",
"import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .setArgs(\"-XepAllSuggestionsAsWarnings\")",
" .setFixChooser(FixChoosers.SECOND)",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .doTest(TestMode.TEXT_MATCH);",
" }",
"}");
"""
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.bugpatterns.BugChecker;
final class SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest {
private static class TestChecker extends BugChecker {}
void m() {
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
.setArgs("-XepAllSuggestionsAsWarnings")
.setFixChooser(FixChoosers.SECOND)
.addInputLines("A.java", "class A {}")
.addOutputLines("A.java", "class A { /* This is a change. */ }")
.doTest(TestMode.TEXT_MATCH);
}
}
""");
verifyGeneratedFileContent(
outputDirectory,
@@ -425,21 +453,23 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"MultiFileBugCheckerRefactoringTestHelperTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class MultiFileBugCheckerRefactoringTestHelperTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .addInputLines(\"B.java\", \"class B {}\")",
" .addOutputLines(\"B.java\", \"class B { /* This is a change. */ }\")",
" .doTest();",
" }",
"}");
"""
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
final class MultiFileBugCheckerRefactoringTestHelperTest {
private static class TestChecker extends BugChecker {}
void m() {
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
.addInputLines("A.java", "class A {}")
.addOutputLines("A.java", "class A { /* This is a change. */ }")
.addInputLines("B.java", "class B {}")
.addOutputLines("B.java", "class B { /* This is a change. */ }")
.doTest();
}
}
""");
verifyGeneratedFileContent(
outputDirectory,
@@ -462,24 +492,26 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"CompilationAndBugCheckerRefactoringTestHelpersTest.java",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class CompilationAndBugCheckerRefactoringTestHelpersTest {",
" private static class TestChecker extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .doTest();",
" }",
"}");
"""
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
final class CompilationAndBugCheckerRefactoringTestHelpersTest {
private static class TestChecker extends BugChecker {}
void m() {
CompilationTestHelper.newInstance(TestChecker.class, getClass())
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
.doTest();
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
.addInputLines("A.java", "class A {}")
.addOutputLines("A.java", "class A { /* This is a change. */ }")
.doTest();
}
}
""");
verifyGeneratedFileContent(
outputDirectory,
@@ -506,28 +538,30 @@ final class BugPatternTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.java",
"package pkg;",
"",
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
"import com.google.errorprone.CompilationTestHelper;",
"import com.google.errorprone.bugpatterns.BugChecker;",
"",
"final class CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest {",
" private static class CustomTestChecker extends BugChecker {}",
"",
" private static class CustomTestChecker2 extends BugChecker {}",
"",
" void m() {",
" CompilationTestHelper.newInstance(CustomTestChecker.class, getClass())",
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
" .doTest();",
"",
" BugCheckerRefactoringTestHelper.newInstance(CustomTestChecker2.class, getClass())",
" .addInputLines(\"A.java\", \"class A {}\")",
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
" .doTest();",
" }",
"}");
"""
package pkg;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
final class CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest {
private static class CustomTestChecker extends BugChecker {}
private static class CustomTestChecker2 extends BugChecker {}
void m() {
CompilationTestHelper.newInstance(CustomTestChecker.class, getClass())
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
.doTest();
BugCheckerRefactoringTestHelper.newInstance(CustomTestChecker2.class, getClass())
.addInputLines("A.java", "class A {}")
.addOutputLines("A.java", "class A { /* This is a change. */ }")
.doTest();
}
}
""");
verifyGeneratedFileContent(
outputDirectory,

View File

@@ -14,21 +14,29 @@ import java.util.List;
import javax.tools.Diagnostic;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import org.intellij.lang.annotations.Language;
// XXX: Generalize and move this class so that it can also be used by `refaster-compiler`.
// XXX: This class is supported by the `ErrorProneTestHelperSourceFormat` check, but until that
// support is covered by unit tests, make sure to update that logic if this class or its methods are
// XXX: This class is supported by the `TestHelperSourceFormat` check, but until that support is
// covered by unit tests, make sure to update that logic if this class or its methods are
// moved/renamed.
public final class Compilation {
private Compilation() {}
// XXX: Drop this method in favour of only supporting the text block-accepting variant.
public static void compileWithDocumentationGenerator(
Path outputDirectory, String path, String... lines) {
compileWithDocumentationGenerator(outputDirectory.toAbsolutePath().toString(), path, lines);
Path outputDirectory, String path, @Language("JAVA") String... source) {
compileWithDocumentationGenerator(
outputDirectory.toAbsolutePath().toString(), path, String.join("\n", source));
}
public static void compileWithDocumentationGenerator(
String outputDirectory, String path, String... lines) {
Path outputDirectory, String path, @Language("JAVA") String source) {
compileWithDocumentationGenerator(outputDirectory.toAbsolutePath().toString(), path, source);
}
public static void compileWithDocumentationGenerator(
String outputDirectory, String path, @Language("JAVA") String source) {
/*
* The compiler options specified here largely match those used by Error Prone's
* `CompilationTestHelper`. A key difference is the stricter linting configuration. When
@@ -49,7 +57,7 @@ public final class Compilation {
"-Xplugin:DocumentationGenerator -XoutputDirectory=" + outputDirectory,
"-XDdev",
"-XDcompilePolicy=simple"),
FileObjects.forSourceLines(path, lines));
FileObjects.forSourceLines(path, source));
}
private static void compile(ImmutableList<String> options, JavaFileObject javaFileObject) {

View File

@@ -62,15 +62,26 @@ final class DocumentationGeneratorTaskListenerTest {
assertThatThrownBy(
() ->
Compilation.compileWithDocumentationGenerator(
outputDirectory, "A.java", "class A {}"))
outputDirectory,
"A.java",
"""
class A {}
"""))
.hasRootCauseInstanceOf(FileSystemException.class)
.hasCauseInstanceOf(IllegalStateException.class)
.hasMessageEndingWith("Error while creating directory with path '%s'", outputDirectory);
}
// XXX: For this case the text block conversion introduces too much indentation. (Possibly i.c.w.
// post-processing by GJF; TBD.)
@Test
void noClassNoOutput(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(outputDirectory, "A.java", "package pkg;");
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"A.java",
"""
package pkg;
""");
assertThat(outputDirectory).isEmptyDirectory();
}
@@ -81,7 +92,11 @@ final class DocumentationGeneratorTaskListenerTest {
assertThatThrownBy(
() ->
Compilation.compileWithDocumentationGenerator(
actualOutputDirectory, "A.java", "package pkg;"))
actualOutputDirectory,
"A.java",
"""
package pkg;
"""))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Precisely one path must be provided");
}
@@ -91,7 +106,9 @@ final class DocumentationGeneratorTaskListenerTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"DocumentationGeneratorTaskListenerTestClass.java",
"class DocumentationGeneratorTaskListenerTestClass {}");
"""
class DocumentationGeneratorTaskListenerTestClass {}
""");
assertThat(
outputDirectory.resolve(

View File

@@ -16,7 +16,11 @@ final class RefasterRuleCollectionTestExtractorTest {
@Test
void noRefasterRuleTest(@TempDir Path outputDirectory) {
Compilation.compileWithDocumentationGenerator(
outputDirectory, "NoRefasterRuleTest.java", "public final class NoRefasterRuleTest {}");
outputDirectory,
"NoRefasterRuleTest.java",
"""
public final class NoRefasterRuleTest {}
""");
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
}
@@ -28,9 +32,11 @@ final class RefasterRuleCollectionTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"InvalidTestClassNameInput.java",
"import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;",
"",
"final class InvalidTestClassName implements RefasterRuleCollectionTestCase {}"))
"""
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class InvalidTestClassName implements RefasterRuleCollectionTestCase {}
"""))
.cause()
.isInstanceOf(VerifyException.class)
.hasMessage(
@@ -44,9 +50,11 @@ final class RefasterRuleCollectionTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"InvalidFileNameTest.java",
"import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;",
"",
"final class InvalidFileNameTest implements RefasterRuleCollectionTestCase {}"))
"""
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class InvalidFileNameTest implements RefasterRuleCollectionTestCase {}
"""))
.cause()
.isInstanceOf(VerifyException.class)
.hasMessage(
@@ -58,9 +66,11 @@ final class RefasterRuleCollectionTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"EmptyRefasterRuleCollectionTestInput.java",
"import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;",
"",
"final class EmptyRefasterRuleCollectionTest implements RefasterRuleCollectionTestCase {}");
"""
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class EmptyRefasterRuleCollectionTest implements RefasterRuleCollectionTestCase {}
""");
verifyGeneratedFileContent(
outputDirectory,
@@ -77,13 +87,15 @@ final class RefasterRuleCollectionTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"SingletonRefasterRuleCollectionTestOutput.java",
"import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;",
"",
"final class SingletonRefasterRuleCollectionTest implements RefasterRuleCollectionTestCase {",
" int testMyRule() {",
" return 42;",
" }",
"}");
"""
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class SingletonRefasterRuleCollectionTest implements RefasterRuleCollectionTestCase {
int testMyRule() {
return 42;
}
}
""");
verifyGeneratedFileContent(
outputDirectory,
@@ -106,31 +118,33 @@ final class RefasterRuleCollectionTestExtractorTest {
Compilation.compileWithDocumentationGenerator(
outputDirectory,
"pkg/ComplexRefasterRuleCollectionTestInput.java",
"package pkg;",
"",
"import com.google.common.collect.ImmutableSet;",
"import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;",
"",
"final class ComplexRefasterRuleCollectionTest implements RefasterRuleCollectionTestCase {",
" private static final String IGNORED_CONSTANT = \"constant\";",
"",
" @Override",
" public ImmutableSet<Object> elidedTypesAndStaticImports() {",
" return ImmutableSet.of();",
" }",
"",
" /** Javadoc. */",
" String testFirstRule() {",
" return \"Don't panic\";",
" }",
"",
" // Comment.",
" String testSecondRule() {",
" return \"Carry a towel\";",
" }",
"",
" void testEmptyRule() {}",
"}");
"""
package pkg;
import com.google.common.collect.ImmutableSet;
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class ComplexRefasterRuleCollectionTest implements RefasterRuleCollectionTestCase {
private static final String IGNORED_CONSTANT = "constant";
@Override
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of();
}
/** Javadoc. */
String testFirstRule() {
return "Don't panic";
}
// Comment.
String testSecondRule() {
return "Carry a towel";
}
void testEmptyRule() {}
}
""");
verifyGeneratedFileContent(
outputDirectory,

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.19.1</version>
<version>0.19.2-SNAPSHOT</version>
</parent>
<artifactId>error-prone-contrib</artifactId>
@@ -167,6 +167,11 @@
<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,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

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

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

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

@@ -13,99 +13,101 @@ final class AmbiguousJsonCreatorTest {
"X", m -> m.contains("`JsonCreator.Mode` should be set for single-argument creators"))
.addSourceLines(
"Container.java",
"import com.fasterxml.jackson.annotation.JsonCreator;",
"import com.fasterxml.jackson.annotation.JsonValue;",
"",
"interface Container {",
" enum A {",
" FOO(1);",
"",
" private final int i;",
"",
" A(int i) {",
" this.i = i;",
" }",
"",
" // BUG: Diagnostic matches: X",
" @JsonCreator",
" public static A of(int i) {",
" return FOO;",
" }",
" }",
"",
" enum B {",
" FOO(1);",
"",
" private final int i;",
"",
" B(int i) {",
" this.i = i;",
" }",
"",
" @JsonCreator(mode = JsonCreator.Mode.DELEGATING)",
" public static B of(int i) {",
" return FOO;",
" }",
" }",
"",
" enum C {",
" FOO(1, \"s\");",
"",
" @JsonValue private final int i;",
" private final String s;",
"",
" C(int i, String s) {",
" this.i = i;",
" this.s = s;",
" }",
"",
" // BUG: Diagnostic matches: X",
" @JsonCreator",
" public static C of(int i) {",
" return FOO;",
" }",
" }",
"",
" enum D {",
" FOO(1, \"s\");",
"",
" private final int i;",
" private final String s;",
"",
" D(int i, String s) {",
" this.i = i;",
" this.s = s;",
" }",
"",
" @JsonCreator",
" public static D of(int i, String s) {",
" return FOO;",
" }",
" }",
"",
" enum E {",
" FOO;",
"",
" // BUG: Diagnostic matches: X",
" @JsonCreator",
" public static E of(String s) {",
" return FOO;",
" }",
" }",
"",
" class F {",
" private final String s;",
"",
" F(String s) {",
" this.s = s;",
" }",
"",
" @JsonCreator",
" public static F of(String s) {",
" return new F(s);",
" }",
" }",
"}")
"""
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
interface Container {
enum A {
FOO(1);
private final int i;
A(int i) {
this.i = i;
}
// BUG: Diagnostic matches: X
@JsonCreator
public static A of(int i) {
return FOO;
}
}
enum B {
FOO(1);
private final int i;
B(int i) {
this.i = i;
}
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public static B of(int i) {
return FOO;
}
}
enum C {
FOO(1, "s");
@JsonValue private final int i;
private final String s;
C(int i, String s) {
this.i = i;
this.s = s;
}
// BUG: Diagnostic matches: X
@JsonCreator
public static C of(int i) {
return FOO;
}
}
enum D {
FOO(1, "s");
private final int i;
private final String s;
D(int i, String s) {
this.i = i;
this.s = s;
}
@JsonCreator
public static D of(int i, String s) {
return FOO;
}
}
enum E {
FOO;
// BUG: Diagnostic matches: X
@JsonCreator
public static E of(String s) {
return FOO;
}
}
class F {
private final String s;
F(String s) {
this.s = s;
}
@JsonCreator
public static F of(String s) {
return new F(s);
}
}
}
""")
.doTest();
}
@@ -114,28 +116,32 @@ final class AmbiguousJsonCreatorTest {
BugCheckerRefactoringTestHelper.newInstance(AmbiguousJsonCreator.class, getClass())
.addInputLines(
"A.java",
"import com.fasterxml.jackson.annotation.JsonCreator;",
"",
"enum A {",
" FOO;",
"",
" @JsonCreator",
" public static A of(String s) {",
" return FOO;",
" }",
"}")
"""
import com.fasterxml.jackson.annotation.JsonCreator;
enum A {
FOO;
@JsonCreator
public static A of(String s) {
return FOO;
}
}
""")
.addOutputLines(
"A.java",
"import com.fasterxml.jackson.annotation.JsonCreator;",
"",
"enum A {",
" FOO;",
"",
" @JsonCreator(mode = JsonCreator.Mode.DELEGATING)",
" public static A of(String s) {",
" return FOO;",
" }",
"}")
"""
import com.fasterxml.jackson.annotation.JsonCreator;
enum A {
FOO;
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public static A of(String s) {
return FOO;
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,22 +11,24 @@ final class AssertJIsNullTest {
CompilationTestHelper.newInstance(AssertJIsNull.class, getClass())
.addSourceLines(
"A.java",
"import static org.assertj.core.api.Assertions.assertThat;",
"",
"class A {",
" void m() {",
" assertThat(1).isEqualTo(1);",
" // BUG: Diagnostic contains:",
" assertThat(1).isEqualTo(null);",
" // BUG: Diagnostic contains:",
" assertThat(\"foo\").isEqualTo(null);",
" isEqualTo(null);",
" }",
"",
" private boolean isEqualTo(Object value) {",
" return value.equals(\"bar\");",
" }",
"}")
"""
import static org.assertj.core.api.Assertions.assertThat;
class A {
void m() {
assertThat(1).isEqualTo(1);
// BUG: Diagnostic contains:
assertThat(1).isEqualTo(null);
// BUG: Diagnostic contains:
assertThat("foo").isEqualTo(null);
isEqualTo(null);
}
private boolean isEqualTo(Object value) {
return value.equals("bar");
}
}
""")
.doTest();
}
@@ -35,24 +37,28 @@ final class AssertJIsNullTest {
BugCheckerRefactoringTestHelper.newInstance(AssertJIsNull.class, getClass())
.addInputLines(
"A.java",
"import static org.assertj.core.api.Assertions.assertThat;",
"",
"class A {",
" void m() {",
" assertThat(1).isEqualTo(null);",
" assertThat(\"foo\").isEqualTo(null);",
" }",
"}")
"""
import static org.assertj.core.api.Assertions.assertThat;
class A {
void m() {
assertThat(1).isEqualTo(null);
assertThat("foo").isEqualTo(null);
}
}
""")
.addOutputLines(
"A.java",
"import static org.assertj.core.api.Assertions.assertThat;",
"",
"class A {",
" void m() {",
" assertThat(1).isNull();",
" assertThat(\"foo\").isNull();",
" }",
"}")
"""
import static org.assertj.core.api.Assertions.assertThat;
class A {
void m() {
assertThat(1).isNull();
assertThat("foo").isNull();
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,56 +11,58 @@ final class AutowiredConstructorTest {
CompilationTestHelper.newInstance(AutowiredConstructor.class, getClass())
.addSourceLines(
"Container.java",
"import com.google.errorprone.annotations.Immutable;",
"import java.util.List;",
"import org.springframework.beans.factory.annotation.Autowired;",
"",
"interface Container {",
" @Immutable",
" class A {",
" A() {}",
" }",
"",
" class B {",
" @Autowired",
" void setProperty(Object o) {}",
" }",
"",
" class C {",
" // BUG: Diagnostic contains:",
" @Autowired",
" C() {}",
" }",
"",
" class D {",
" // BUG: Diagnostic contains:",
" @Autowired",
" D(String x) {}",
" }",
"",
" class E {",
" @Autowired",
" E() {}",
"",
" E(String x) {}",
" }",
"",
" class F {",
" F() {}",
"",
" @Autowired",
" F(String x) {}",
" }",
"",
" class G {",
" @Autowired private Object o;",
" }",
"",
" class H {",
" @SafeVarargs",
" H(List<String>... lists) {}",
" }",
"}")
"""
import com.google.errorprone.annotations.Immutable;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
interface Container {
@Immutable
class A {
A() {}
}
class B {
@Autowired
void setProperty(Object o) {}
}
class C {
// BUG: Diagnostic contains:
@Autowired
C() {}
}
class D {
// BUG: Diagnostic contains:
@Autowired
D(String x) {}
}
class E {
@Autowired
E() {}
E(String x) {}
}
class F {
F() {}
@Autowired
F(String x) {}
}
class G {
@Autowired private Object o;
}
class H {
@SafeVarargs
H(List<String>... lists) {}
}
}
""")
.doTest();
}
@@ -69,34 +71,38 @@ final class AutowiredConstructorTest {
BugCheckerRefactoringTestHelper.newInstance(AutowiredConstructor.class, getClass())
.addInputLines(
"Container.java",
"import org.springframework.beans.factory.annotation.Autowired;",
"",
"interface Container {",
" class A {",
" @Autowired",
" @Deprecated",
" A() {}",
" }",
"",
" class B {",
" @Autowired",
" B(String x) {}",
" }",
"}")
"""
import org.springframework.beans.factory.annotation.Autowired;
interface Container {
class A {
@Autowired
@Deprecated
A() {}
}
class B {
@Autowired
B(String x) {}
}
}
""")
.addOutputLines(
"Container.java",
"import org.springframework.beans.factory.annotation.Autowired;",
"",
"interface Container {",
" class A {",
" @Deprecated",
" A() {}",
" }",
"",
" class B {",
" B(String x) {}",
" }",
"}")
"""
import org.springframework.beans.factory.annotation.Autowired;
interface Container {
class A {
@Deprecated
A() {}
}
class B {
B(String x) {}
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,128 +11,130 @@ final class CanonicalAnnotationSyntaxTest {
CompilationTestHelper.newInstance(CanonicalAnnotationSyntax.class, getClass())
.addSourceLines(
"pkg/A.java",
"package pkg;",
"",
"import pkg.A.Foo;",
"",
"interface A {",
" @interface Foo {",
" int[] value() default {};",
"",
" int[] value2() default {};",
" }",
"",
" @pkg.A.Foo",
" A minimal1();",
"",
" @A.Foo",
" A minimal2();",
"",
" @Foo",
" A minimal3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo()",
" A functional1();",
"",
" // BUG: Diagnostic contains:",
" @A.Foo()",
" A functional2();",
"",
" // BUG: Diagnostic contains:",
" @Foo()",
" A functional3();",
"",
" @pkg.A.Foo(1)",
" A simple1();",
"",
" @A.Foo(1)",
" A simple2();",
"",
" @Foo(1)",
" A simple3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo({1})",
" A singleton1();",
"",
" // BUG: Diagnostic contains:",
" @A.Foo({1})",
" A singleton2();",
"",
" // BUG: Diagnostic contains:",
" @Foo({1})",
" A singleton3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo(value = 1)",
" A verbose1();",
"",
" // BUG: Diagnostic contains:",
" @A.Foo(value = 1)",
" A verbose2();",
"",
" // BUG: Diagnostic contains:",
" @Foo(value = 1)",
" A verbose3();",
"",
" @pkg.A.Foo(value2 = 2)",
" A custom1();",
"",
" @A.Foo(value2 = 2)",
" A custom2();",
"",
" @Foo(value2 = 2)",
" A custom3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo(value2 = {2})",
" A customSingleton1();",
"",
" // BUG: Diagnostic contains:",
" @A.Foo(value2 = {2})",
" A customSingleton2();",
"",
" // BUG: Diagnostic contains:",
" @Foo(value2 = {2})",
" A customSingleton3();",
"",
" @pkg.A.Foo(value2 = {2, 2})",
" A customPair1();",
"",
" @A.Foo(value2 = {2, 2})",
" A customPair2();",
"",
" @Foo(value2 = {2, 2})",
" A customPair3();",
"",
" @pkg.A.Foo(value = 1, value2 = 2)",
" A extended1();",
"",
" @A.Foo(value = 1, value2 = 2)",
" A extended2();",
"",
" @Foo(value = 1, value2 = 2)",
" A extended3();",
"",
" // BUG: Diagnostic contains:",
" @pkg.A.Foo({",
" 1, 1,",
" })",
" A trailingComma1();",
"",
" // BUG: Diagnostic contains:",
" @A.Foo({",
" 1, 1,",
" })",
" A trailingComma2();",
"",
" // BUG: Diagnostic contains:",
" @Foo({",
" 1, 1,",
" })",
" A trailingComma3();",
"}")
"""
package pkg;
import pkg.A.Foo;
interface A {
@interface Foo {
int[] value() default {};
int[] value2() default {};
}
@pkg.A.Foo
A minimal1();
@A.Foo
A minimal2();
@Foo
A minimal3();
// BUG: Diagnostic contains:
@pkg.A.Foo()
A functional1();
// BUG: Diagnostic contains:
@A.Foo()
A functional2();
// BUG: Diagnostic contains:
@Foo()
A functional3();
@pkg.A.Foo(1)
A simple1();
@A.Foo(1)
A simple2();
@Foo(1)
A simple3();
// BUG: Diagnostic contains:
@pkg.A.Foo({1})
A singleton1();
// BUG: Diagnostic contains:
@A.Foo({1})
A singleton2();
// BUG: Diagnostic contains:
@Foo({1})
A singleton3();
// BUG: Diagnostic contains:
@pkg.A.Foo(value = 1)
A verbose1();
// BUG: Diagnostic contains:
@A.Foo(value = 1)
A verbose2();
// BUG: Diagnostic contains:
@Foo(value = 1)
A verbose3();
@pkg.A.Foo(value2 = 2)
A custom1();
@A.Foo(value2 = 2)
A custom2();
@Foo(value2 = 2)
A custom3();
// BUG: Diagnostic contains:
@pkg.A.Foo(value2 = {2})
A customSingleton1();
// BUG: Diagnostic contains:
@A.Foo(value2 = {2})
A customSingleton2();
// BUG: Diagnostic contains:
@Foo(value2 = {2})
A customSingleton3();
@pkg.A.Foo(value2 = {2, 2})
A customPair1();
@A.Foo(value2 = {2, 2})
A customPair2();
@Foo(value2 = {2, 2})
A customPair3();
@pkg.A.Foo(value = 1, value2 = 2)
A extended1();
@A.Foo(value = 1, value2 = 2)
A extended2();
@Foo(value = 1, value2 = 2)
A extended3();
// BUG: Diagnostic contains:
@pkg.A.Foo({
1, 1,
})
A trailingComma1();
// BUG: Diagnostic contains:
@A.Foo({
1, 1,
})
A trailingComma2();
// BUG: Diagnostic contains:
@Foo({
1, 1,
})
A trailingComma3();
}
""")
.doTest();
}
@@ -141,139 +143,143 @@ final class CanonicalAnnotationSyntaxTest {
BugCheckerRefactoringTestHelper.newInstance(CanonicalAnnotationSyntax.class, getClass())
.addInputLines(
"pkg/A.java",
"package pkg;",
"",
"import pkg.A.Foo;",
"",
"interface A {",
" @interface Foo {",
" String[] value() default {};",
"",
" int[] value2() default {};",
" }",
"",
" @pkg.A.Foo()",
" A functional1();",
"",
" @A.Foo()",
" A functional2();",
"",
" @Foo()",
" A functional3();",
"",
" @pkg.A.Foo(value = \"foo\")",
" A verbose1();",
"",
" @A.Foo(value = \"a'b\")",
" A verbose2();",
"",
" @Foo(value = \"a\" + \"\\nb\")",
" A verbose3();",
"",
" @pkg.A.Foo(value = {\"foo\"})",
" A moreVerbose1();",
"",
" @A.Foo(value = {\"a'b\"})",
" A moreVerbose2();",
"",
" @Foo(value = {\"a\" + \"\\nb\"})",
" A moreVerbose3();",
"",
" @pkg.A.Foo(",
" value = {\"foo\", \"bar\"},",
" value2 = {2})",
" A extended1();",
"",
" @A.Foo(",
" value = {\"a'b\", \"c'd\"},",
" value2 = {2})",
" A extended2();",
"",
" @Foo(",
" value = {\"a\" + \"\\nb\", \"c\" + \"\\nd\"},",
" value2 = {2})",
" A extended3();",
"",
" @pkg.A.Foo({",
" \"foo\", \"bar\",",
" })",
" A trailingComma1();",
"",
" @A.Foo({",
" \"a'b\", \"c'd\",",
" })",
" A trailingComma2();",
"",
" @Foo({",
" \"a\" + \"\\nb\",",
" \"c\" + \"\\nd\",",
" })",
" A trailingComma3();",
"}")
"""
package pkg;
import pkg.A.Foo;
interface A {
@interface Foo {
String[] value() default {};
int[] value2() default {};
}
@pkg.A.Foo()
A functional1();
@A.Foo()
A functional2();
@Foo()
A functional3();
@pkg.A.Foo(value = "foo")
A verbose1();
@A.Foo(value = "a'b")
A verbose2();
@Foo(value = "a" + "\\nb")
A verbose3();
@pkg.A.Foo(value = {"foo"})
A moreVerbose1();
@A.Foo(value = {"a'b"})
A moreVerbose2();
@Foo(value = {"a" + "\\nb"})
A moreVerbose3();
@pkg.A.Foo(
value = {"foo", "bar"},
value2 = {2})
A extended1();
@A.Foo(
value = {"a'b", "c'd"},
value2 = {2})
A extended2();
@Foo(
value = {"a" + "\\nb", "c" + "\\nd"},
value2 = {2})
A extended3();
@pkg.A.Foo({
"foo", "bar",
})
A trailingComma1();
@A.Foo({
"a'b", "c'd",
})
A trailingComma2();
@Foo({
"a" + "\\nb",
"c" + "\\nd",
})
A trailingComma3();
}
""")
.addOutputLines(
"pkg/A.java",
"package pkg;",
"",
"import pkg.A.Foo;",
"",
"interface A {",
" @interface Foo {",
" String[] value() default {};",
"",
" int[] value2() default {};",
" }",
"",
" @pkg.A.Foo",
" A functional1();",
"",
" @A.Foo",
" A functional2();",
"",
" @Foo",
" A functional3();",
"",
" @pkg.A.Foo(\"foo\")",
" A verbose1();",
"",
" @A.Foo(\"a'b\")",
" A verbose2();",
"",
" @Foo(\"a\" + \"\\nb\")",
" A verbose3();",
"",
" @pkg.A.Foo(\"foo\")",
" A moreVerbose1();",
"",
" @A.Foo(\"a'b\")",
" A moreVerbose2();",
"",
" @Foo(\"a\" + \"\\nb\")",
" A moreVerbose3();",
"",
" @pkg.A.Foo(",
" value = {\"foo\", \"bar\"},",
" value2 = 2)",
" A extended1();",
"",
" @A.Foo(",
" value = {\"a'b\", \"c'd\"},",
" value2 = 2)",
" A extended2();",
"",
" @Foo(",
" value = {\"a\" + \"\\nb\", \"c\" + \"\\nd\"},",
" value2 = 2)",
" A extended3();",
"",
" @pkg.A.Foo({\"foo\", \"bar\"})",
" A trailingComma1();",
"",
" @A.Foo({\"a'b\", \"c'd\"})",
" A trailingComma2();",
"",
" @Foo({\"a\" + \"\\nb\", \"c\" + \"\\nd\"})",
" A trailingComma3();",
"}")
"""
package pkg;
import pkg.A.Foo;
interface A {
@interface Foo {
String[] value() default {};
int[] value2() default {};
}
@pkg.A.Foo
A functional1();
@A.Foo
A functional2();
@Foo
A functional3();
@pkg.A.Foo("foo")
A verbose1();
@A.Foo("a'b")
A verbose2();
@Foo("a" + "\\nb")
A verbose3();
@pkg.A.Foo("foo")
A moreVerbose1();
@A.Foo("a'b")
A moreVerbose2();
@Foo("a" + "\\nb")
A moreVerbose3();
@pkg.A.Foo(
value = {"foo", "bar"},
value2 = 2)
A extended1();
@A.Foo(
value = {"a'b", "c'd"},
value2 = 2)
A extended2();
@Foo(
value = {"a" + "\\nb", "c" + "\\nd"},
value2 = 2)
A extended3();
@pkg.A.Foo({"foo", "bar"})
A trailingComma1();
@A.Foo({"a'b", "c'd"})
A trailingComma2();
@Foo({"a" + "\\nb", "c" + "\\nd"})
A trailingComma3();
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -14,35 +14,37 @@ final class CanonicalClassNameUsageTest {
"--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED")
.addSourceLines(
"A.java",
"import static com.google.errorprone.matchers.Matchers.instanceMethod;",
"",
"import com.google.errorprone.VisitorState;",
"import tech.picnic.errorprone.utils.MoreTypes;",
"",
"class A {",
" void m(VisitorState state) {",
" String a = A.class.getName();",
" String b = getClass().getName();",
" A.class.getName().toString();",
" System.out.println(A.class.getName());",
" methodInUnnamedPackage(A.class.getName());",
" instanceMethod().onExactClass(A.class.getCanonicalName());",
" MoreTypes.type(A.class.getCanonicalName());",
" MoreTypes.type(A.class.getCanonicalName() + \".SubType\");",
" instanceMethod().onExactClass(new Object() {}.getClass().getName());",
" instanceMethod().onExactClass(methodInUnnamedPackage(A.class.getName()));",
" // BUG: Diagnostic contains:",
" instanceMethod().onExactClass(A.class.getName());",
" // BUG: Diagnostic contains:",
" MoreTypes.type(A.class.getName());",
" // BUG: Diagnostic contains:",
" state.binaryNameFromClassname(A.class.getName() + \".SubType\");",
" }",
"",
" String methodInUnnamedPackage(String str) {",
" return str;",
" }",
"}")
"""
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import com.google.errorprone.VisitorState;
import tech.picnic.errorprone.utils.MoreTypes;
class A {
void m(VisitorState state) {
String a = A.class.getName();
String b = getClass().getName();
A.class.getName().toString();
System.out.println(A.class.getName());
methodInUnnamedPackage(A.class.getName());
instanceMethod().onExactClass(A.class.getCanonicalName());
MoreTypes.type(A.class.getCanonicalName());
MoreTypes.type(A.class.getCanonicalName() + ".SubType");
instanceMethod().onExactClass(new Object() {}.getClass().getName());
instanceMethod().onExactClass(methodInUnnamedPackage(A.class.getName()));
// BUG: Diagnostic contains:
instanceMethod().onExactClass(A.class.getName());
// BUG: Diagnostic contains:
MoreTypes.type(A.class.getName());
// BUG: Diagnostic contains:
state.binaryNameFromClassname(A.class.getName() + ".SubType");
}
String methodInUnnamedPackage(String str) {
return str;
}
}
""")
.doTest();
}
@@ -51,32 +53,36 @@ final class CanonicalClassNameUsageTest {
BugCheckerRefactoringTestHelper.newInstance(CanonicalClassNameUsage.class, getClass())
.addInputLines(
"A.java",
"import static com.google.errorprone.matchers.Matchers.instanceMethod;",
"",
"import com.google.errorprone.BugPattern;",
"import tech.picnic.errorprone.utils.MoreTypes;",
"",
"class A {",
" void m() {",
" instanceMethod().onDescendantOfAny(A.class.getName(), BugPattern.LinkType.class.getName());",
" MoreTypes.type(String.class.getName());",
" }",
"}")
"""
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import com.google.errorprone.BugPattern;
import tech.picnic.errorprone.utils.MoreTypes;
class A {
void m() {
instanceMethod().onDescendantOfAny(A.class.getName(), BugPattern.LinkType.class.getName());
MoreTypes.type(String.class.getName());
}
}
""")
.addOutputLines(
"A.java",
"import static com.google.errorprone.matchers.Matchers.instanceMethod;",
"",
"import com.google.errorprone.BugPattern;",
"import tech.picnic.errorprone.utils.MoreTypes;",
"",
"class A {",
" void m() {",
" instanceMethod()",
" .onDescendantOfAny(",
" A.class.getCanonicalName(), BugPattern.LinkType.class.getCanonicalName());",
" MoreTypes.type(String.class.getCanonicalName());",
" }",
"}")
"""
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import com.google.errorprone.BugPattern;
import tech.picnic.errorprone.utils.MoreTypes;
class A {
void m() {
instanceMethod()
.onDescendantOfAny(
A.class.getCanonicalName(), BugPattern.LinkType.class.getCanonicalName());
MoreTypes.type(String.class.getCanonicalName());
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

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

View File

@@ -13,50 +13,52 @@ final class CollectorMutabilityTest {
CompilationTestHelper.newInstance(CollectorMutability.class, getClass())
.addSourceLines(
"A.java",
"import static com.google.common.collect.ImmutableList.toImmutableList;",
"import static com.google.common.collect.ImmutableMap.toImmutableMap;",
"import static com.google.common.collect.ImmutableSet.toImmutableSet;",
"import static java.util.stream.Collectors.toCollection;",
"import static java.util.stream.Collectors.toList;",
"import static java.util.stream.Collectors.toMap;",
"import static java.util.stream.Collectors.toSet;",
"",
"import java.util.ArrayList;",
"import java.util.HashMap;",
"import java.util.HashSet;",
"import java.util.stream.Collectors;",
"import java.util.stream.Stream;",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" // BUG: Diagnostic contains:",
" Flux.just(1).collect(Collectors.toList());",
" // BUG: Diagnostic contains:",
" Flux.just(2).collect(toList());",
" Flux.just(3).collect(toImmutableList());",
" Flux.just(4).collect(toCollection(ArrayList::new));",
"",
" // BUG: Diagnostic contains:",
" Flux.just(\"foo\").collect(Collectors.toMap(String::getBytes, String::length));",
" // BUG: Diagnostic contains:",
" Flux.just(\"bar\").collect(toMap(String::getBytes, String::length));",
" Flux.just(\"baz\").collect(toImmutableMap(String::getBytes, String::length));",
" // BUG: Diagnostic contains:",
" Flux.just(\"qux\").collect(toMap(String::getBytes, String::length, (a, b) -> a));",
" Flux.just(\"quux\").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> a));",
" Flux.just(\"quuz\").collect(toMap(String::getBytes, String::length, (a, b) -> a, HashMap::new));",
"",
" // BUG: Diagnostic contains:",
" Stream.of(1).collect(Collectors.toSet());",
" // BUG: Diagnostic contains:",
" Stream.of(2).collect(toSet());",
" Stream.of(3).collect(toImmutableSet());",
" Stream.of(4).collect(toCollection(HashSet::new));",
"",
" Flux.just(\"foo\").collect(Collectors.joining());",
" }",
"}")
"""
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import reactor.core.publisher.Flux;
class A {
void m() {
// BUG: Diagnostic contains:
Flux.just(1).collect(Collectors.toList());
// BUG: Diagnostic contains:
Flux.just(2).collect(toList());
Flux.just(3).collect(toImmutableList());
Flux.just(4).collect(toCollection(ArrayList::new));
// BUG: Diagnostic contains:
Flux.just("foo").collect(Collectors.toMap(String::getBytes, String::length));
// BUG: Diagnostic contains:
Flux.just("bar").collect(toMap(String::getBytes, String::length));
Flux.just("baz").collect(toImmutableMap(String::getBytes, String::length));
// BUG: Diagnostic contains:
Flux.just("qux").collect(toMap(String::getBytes, String::length, (a, b) -> a));
Flux.just("quux").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> a));
Flux.just("quuz").collect(toMap(String::getBytes, String::length, (a, b) -> a, HashMap::new));
// BUG: Diagnostic contains:
Stream.of(1).collect(Collectors.toSet());
// BUG: Diagnostic contains:
Stream.of(2).collect(toSet());
Stream.of(3).collect(toImmutableSet());
Stream.of(4).collect(toCollection(HashSet::new));
Flux.just("foo").collect(Collectors.joining());
}
}
""")
.doTest();
}
@@ -66,14 +68,16 @@ final class CollectorMutabilityTest {
.withClasspath()
.addSourceLines(
"A.java",
"import java.util.stream.Collectors;",
"import java.util.stream.Stream;",
"",
"class A {",
" void m() {",
" Stream.empty().collect(Collectors.toList());",
" }",
"}")
"""
import java.util.stream.Collectors;
import java.util.stream.Stream;
class A {
void m() {
Stream.empty().collect(Collectors.toList());
}
}
""")
.doTest();
}
@@ -82,55 +86,59 @@ final class CollectorMutabilityTest {
BugCheckerRefactoringTestHelper.newInstance(CollectorMutability.class, getClass())
.addInputLines(
"A.java",
"import static java.util.stream.Collectors.toList;",
"import static java.util.stream.Collectors.toMap;",
"import static java.util.stream.Collectors.toSet;",
"",
"import java.util.stream.Collectors;",
"import java.util.stream.Stream;",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).collect(Collectors.toList());",
" Flux.just(2).collect(toList());",
"",
" Stream.of(\"foo\").collect(Collectors.toMap(String::getBytes, String::length));",
" Stream.of(\"bar\").collect(toMap(String::getBytes, String::length));",
" Flux.just(\"baz\").collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b));",
" Flux.just(\"qux\").collect(toMap(String::getBytes, String::length, (a, b) -> b));",
"",
" Stream.of(1).collect(Collectors.toSet());",
" Stream.of(2).collect(toSet());",
" }",
"}")
"""
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import reactor.core.publisher.Flux;
class A {
void m() {
Flux.just(1).collect(Collectors.toList());
Flux.just(2).collect(toList());
Stream.of("foo").collect(Collectors.toMap(String::getBytes, String::length));
Stream.of("bar").collect(toMap(String::getBytes, String::length));
Flux.just("baz").collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b));
Flux.just("qux").collect(toMap(String::getBytes, String::length, (a, b) -> b));
Stream.of(1).collect(Collectors.toSet());
Stream.of(2).collect(toSet());
}
}
""")
.addOutputLines(
"A.java",
"import static com.google.common.collect.ImmutableList.toImmutableList;",
"import static com.google.common.collect.ImmutableMap.toImmutableMap;",
"import static com.google.common.collect.ImmutableSet.toImmutableSet;",
"import static java.util.stream.Collectors.toList;",
"import static java.util.stream.Collectors.toMap;",
"import static java.util.stream.Collectors.toSet;",
"",
"import java.util.stream.Collectors;",
"import java.util.stream.Stream;",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).collect(toImmutableList());",
" Flux.just(2).collect(toImmutableList());",
"",
" Stream.of(\"foo\").collect(toImmutableMap(String::getBytes, String::length));",
" Stream.of(\"bar\").collect(toImmutableMap(String::getBytes, String::length));",
" Flux.just(\"baz\").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> b));",
" Flux.just(\"qux\").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> b));",
"",
" Stream.of(1).collect(toImmutableSet());",
" Stream.of(2).collect(toImmutableSet());",
" }",
"}")
"""
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import reactor.core.publisher.Flux;
class A {
void m() {
Flux.just(1).collect(toImmutableList());
Flux.just(2).collect(toImmutableList());
Stream.of("foo").collect(toImmutableMap(String::getBytes, String::length));
Stream.of("bar").collect(toImmutableMap(String::getBytes, String::length));
Flux.just("baz").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> b));
Flux.just("qux").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> b));
Stream.of(1).collect(toImmutableSet());
Stream.of(2).collect(toImmutableSet());
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
@@ -140,73 +148,77 @@ final class CollectorMutabilityTest {
.setFixChooser(SECOND)
.addInputLines(
"A.java",
"import static java.util.stream.Collectors.toList;",
"import static java.util.stream.Collectors.toMap;",
"import static java.util.stream.Collectors.toSet;",
"",
"import java.util.stream.Collectors;",
"import java.util.stream.Stream;",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).collect(Collectors.toList());",
" Flux.just(2).collect(toList());",
"",
" Stream.of(\"foo\").collect(Collectors.toMap(String::getBytes, String::length));",
" Stream.of(\"bar\").collect(toMap(String::getBytes, String::length));",
" Flux.just(\"baz\").collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b));",
" Flux.just(\"qux\").collect(toMap(String::getBytes, String::length, (a, b) -> b));",
"",
" Stream.of(1).collect(Collectors.toSet());",
" Stream.of(2).collect(toSet());",
" }",
"}")
"""
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import reactor.core.publisher.Flux;
class A {
void m() {
Flux.just(1).collect(Collectors.toList());
Flux.just(2).collect(toList());
Stream.of("foo").collect(Collectors.toMap(String::getBytes, String::length));
Stream.of("bar").collect(toMap(String::getBytes, String::length));
Flux.just("baz").collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b));
Flux.just("qux").collect(toMap(String::getBytes, String::length, (a, b) -> b));
Stream.of(1).collect(Collectors.toSet());
Stream.of(2).collect(toSet());
}
}
""")
.addOutputLines(
"A.java",
"import static java.util.stream.Collectors.toCollection;",
"import static java.util.stream.Collectors.toList;",
"import static java.util.stream.Collectors.toMap;",
"import static java.util.stream.Collectors.toSet;",
"",
"import java.util.ArrayList;",
"import java.util.HashMap;",
"import java.util.HashSet;",
"import java.util.stream.Collectors;",
"import java.util.stream.Stream;",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).collect(toCollection(ArrayList::new));",
" Flux.just(2).collect(toCollection(ArrayList::new));",
"",
" Stream.of(\"foo\")",
" .collect(",
" Collectors.toMap(",
" String::getBytes,",
" String::length,",
" (a, b) -> {",
" throw new IllegalStateException();",
" },",
" HashMap::new));",
" Stream.of(\"bar\")",
" .collect(",
" toMap(",
" String::getBytes,",
" String::length,",
" (a, b) -> {",
" throw new IllegalStateException();",
" },",
" HashMap::new));",
" Flux.just(\"baz\")",
" .collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b, HashMap::new));",
" Flux.just(\"qux\").collect(toMap(String::getBytes, String::length, (a, b) -> b, HashMap::new));",
"",
" Stream.of(1).collect(toCollection(HashSet::new));",
" Stream.of(2).collect(toCollection(HashSet::new));",
" }",
"}")
"""
import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import reactor.core.publisher.Flux;
class A {
void m() {
Flux.just(1).collect(toCollection(ArrayList::new));
Flux.just(2).collect(toCollection(ArrayList::new));
Stream.of("foo")
.collect(
Collectors.toMap(
String::getBytes,
String::length,
(a, b) -> {
throw new IllegalStateException();
},
HashMap::new));
Stream.of("bar")
.collect(
toMap(
String::getBytes,
String::length,
(a, b) -> {
throw new IllegalStateException();
},
HashMap::new));
Flux.just("baz")
.collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b, HashMap::new));
Flux.just("qux").collect(toMap(String::getBytes, String::length, (a, b) -> b, HashMap::new));
Stream.of(1).collect(toCollection(HashSet::new));
Stream.of(2).collect(toCollection(HashSet::new));
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,30 +11,32 @@ final class ConstantNamingTest {
CompilationTestHelper.newInstance(ConstantNaming.class, getClass())
.addSourceLines(
"A.java",
"class A {",
" private static final long serialVersionUID = 1L;",
" private static final int FOO = 1;",
" // BUG: Diagnostic contains: consider renaming to 'BAR', though note that this is not a private",
" // constant",
" static final int bar = 2;",
" // BUG: Diagnostic contains:",
" private static final int baz = 3;",
" // BUG: Diagnostic contains: consider renaming to 'QUX_QUUX', though note that a variable with",
" // this name is already declared",
" private static final int qux_QUUX = 4;",
" // BUG: Diagnostic contains: consider renaming to 'QUUZ', though note that a variable with",
" // this name is already declared",
" private static final int quuz = 3;",
"",
" private final int foo = 4;",
" private final Runnable QUX_QUUX =",
" new Runnable() {",
" private static final int QUUZ = 1;",
"",
" @Override",
" public void run() {}",
" };",
"}")
"""
class A {
private static final long serialVersionUID = 1L;
private static final int FOO = 1;
// BUG: Diagnostic contains: consider renaming to 'BAR', though note that this is not a private
// constant
static final int bar = 2;
// BUG: Diagnostic contains:
private static final int baz = 3;
// BUG: Diagnostic contains: consider renaming to 'QUX_QUUX', though note that a variable with
// this name is already declared
private static final int qux_QUUX = 4;
// BUG: Diagnostic contains: consider renaming to 'QUUZ', though note that a variable with
// this name is already declared
private static final int quuz = 3;
private final int foo = 4;
private final Runnable QUX_QUUX =
new Runnable() {
private static final int QUUZ = 1;
@Override
public void run() {}
};
}
""")
.doTest();
}
@@ -44,13 +46,15 @@ final class ConstantNamingTest {
.setArgs("-XepOpt:CanonicalConstantNaming:ExemptedNames=foo,baz")
.addSourceLines(
"A.java",
"class A {",
" private static final long serialVersionUID = 1L;",
" private static final int foo = 1;",
" // BUG: Diagnostic contains:",
" private static final int bar = 2;",
" private static final int baz = 3;",
"}")
"""
class A {
private static final long serialVersionUID = 1L;
private static final int foo = 1;
// BUG: Diagnostic contains:
private static final int bar = 2;
private static final int baz = 3;
}
""")
.doTest();
}
@@ -59,20 +63,24 @@ final class ConstantNamingTest {
BugCheckerRefactoringTestHelper.newInstance(ConstantNaming.class, getClass())
.addInputLines(
"A.java",
"class A {",
" static final int foo = 1;",
" private static final int bar = 2;",
" private static final int baz = 3;",
" private static final int BAZ = 4;",
"}")
"""
class A {
static final int foo = 1;
private static final int bar = 2;
private static final int baz = 3;
private static final int BAZ = 4;
}
""")
.addOutputLines(
"A.java",
"class A {",
" static final int foo = 1;",
" private static final int BAR = 2;",
" private static final int baz = 3;",
" private static final int BAZ = 4;",
"}")
"""
class A {
static final int foo = 1;
private static final int BAR = 2;
private static final int baz = 3;
private static final int BAZ = 4;
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,184 +11,186 @@ final class DirectReturnTest {
CompilationTestHelper.newInstance(DirectReturn.class, getClass())
.addSourceLines(
"A.java",
"import static org.mockito.Mockito.mock;",
"import static org.mockito.Mockito.spy;",
"",
"import java.util.function.Supplier;",
"",
"class A {",
" private String field;",
"",
" void emptyMethod() {}",
"",
" void voidMethod() {",
" toString();",
" return;",
" }",
"",
" String directReturnOfParam(String param) {",
" return param;",
" }",
"",
" String assignmentToField() {",
" field = toString();",
" return field;",
" }",
"",
" Object redundantAssignmentToParam(String param) {",
" // BUG: Diagnostic contains:",
" param = toString();",
" return param;",
" }",
"",
" String redundantMockAssignmentToParam(String param) {",
" // BUG: Diagnostic contains:",
" param = mock();",
" return param;",
" }",
"",
" Object redundantMockWithExplicitTypeAssignmentToParam(String param) {",
" // BUG: Diagnostic contains:",
" param = mock(String.class);",
" return param;",
" }",
"",
" Object salientMockAssignmentToParam(String param) {",
" param = mock();",
" return param;",
" }",
"",
" String redundantAssignmentToLocalVariable() {",
" String variable = null;",
" // BUG: Diagnostic contains:",
" variable = toString();",
" return variable;",
" }",
"",
" String unusedAssignmentToLocalVariable(String param) {",
" String variable = null;",
" variable = toString();",
" return param;",
" }",
"",
" String redundantVariableDeclaration() {",
" // BUG: Diagnostic contains:",
" String variable = toString();",
" return variable;",
" }",
"",
" String redundantSpyVariableDeclaration() {",
" // BUG: Diagnostic contains:",
" String variable = spy();",
" return variable;",
" }",
"",
" Object redundantSpyWithExplicitTypeVariableDeclaration() {",
" // BUG: Diagnostic contains:",
" String variable = spy(String.class);",
" return variable;",
" }",
"",
" Object salientSpyTypeVariableDeclaration() {",
" String variable = spy(\"name\");",
" return variable;",
" }",
"",
" String unusedVariableDeclaration(String param) {",
" String variable = toString();",
" return param;",
" }",
"",
" String assignmentToAnnotatedVariable() {",
" @SuppressWarnings(\"HereBeDragons\")",
" String variable = toString();",
" return variable;",
" }",
"",
" String complexReturnStatement() {",
" String variable = toString();",
" return variable + toString();",
" }",
"",
" String assignmentInsideIfClause() {",
" String variable = null;",
" if (true) {",
" variable = toString();",
" }",
" return variable;",
" }",
"",
" String redundantAssignmentInsideElseClause() {",
" String variable = toString();",
" if (true) {",
" return variable;",
" } else {",
" // BUG: Diagnostic contains:",
" variable = \"foo\";",
" return variable;",
" }",
" }",
"",
" Supplier<String> redundantAssignmentInsideLambda() {",
" return () -> {",
" // BUG: Diagnostic contains:",
" String variable = toString();",
" return variable;",
" };",
" }",
"",
" String redundantAssignmentInsideTryBlock(AutoCloseable closeable) throws Exception {",
" try (closeable) {",
" // BUG: Diagnostic contains:",
" String variable = toString();",
" return variable;",
" }",
" }",
"",
" String redundantAssignmentsInsideTryAndFinallyBlocks() {",
" String variable = toString();",
" try {",
" // BUG: Diagnostic contains:",
" variable = \"foo\";",
" return variable;",
" } finally {",
" String variable2 = toString();",
" if (true) {",
" // BUG: Diagnostic contains:",
" String variable3 = toString();",
" return variable3;",
" }",
" return variable2;",
" }",
" }",
"",
" String assignmentUsedInsideFinallyBlock() {",
" String variable = toString();",
" try {",
" variable = \"foo\";",
" return variable;",
" } finally {",
" String variable2 = toString();",
" return variable + variable2;",
" }",
" }",
"",
" String redundantAssignmentToVariableUsedInsideUnexecutedFinallyBlock(AutoCloseable closeable)",
" throws Exception {",
" String variable = toString();",
" try (closeable) {",
" if (true) {",
" // BUG: Diagnostic contains:",
" variable = \"foo\";",
" return variable;",
" }",
" }",
" try {",
" } finally {",
" return variable;",
" }",
" }",
"}")
"""
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import java.util.function.Supplier;
class A {
private String field;
void emptyMethod() {}
void voidMethod() {
toString();
return;
}
String directReturnOfParam(String param) {
return param;
}
String assignmentToField() {
field = toString();
return field;
}
Object redundantAssignmentToParam(String param) {
// BUG: Diagnostic contains:
param = toString();
return param;
}
String redundantMockAssignmentToParam(String param) {
// BUG: Diagnostic contains:
param = mock();
return param;
}
Object redundantMockWithExplicitTypeAssignmentToParam(String param) {
// BUG: Diagnostic contains:
param = mock(String.class);
return param;
}
Object salientMockAssignmentToParam(String param) {
param = mock();
return param;
}
String redundantAssignmentToLocalVariable() {
String variable = null;
// BUG: Diagnostic contains:
variable = toString();
return variable;
}
String unusedAssignmentToLocalVariable(String param) {
String variable = null;
variable = toString();
return param;
}
String redundantVariableDeclaration() {
// BUG: Diagnostic contains:
String variable = toString();
return variable;
}
String redundantSpyVariableDeclaration() {
// BUG: Diagnostic contains:
String variable = spy();
return variable;
}
Object redundantSpyWithExplicitTypeVariableDeclaration() {
// BUG: Diagnostic contains:
String variable = spy(String.class);
return variable;
}
Object salientSpyTypeVariableDeclaration() {
String variable = spy("name");
return variable;
}
String unusedVariableDeclaration(String param) {
String variable = toString();
return param;
}
String assignmentToAnnotatedVariable() {
@SuppressWarnings("HereBeDragons")
String variable = toString();
return variable;
}
String complexReturnStatement() {
String variable = toString();
return variable + toString();
}
String assignmentInsideIfClause() {
String variable = null;
if (true) {
variable = toString();
}
return variable;
}
String redundantAssignmentInsideElseClause() {
String variable = toString();
if (true) {
return variable;
} else {
// BUG: Diagnostic contains:
variable = "foo";
return variable;
}
}
Supplier<String> redundantAssignmentInsideLambda() {
return () -> {
// BUG: Diagnostic contains:
String variable = toString();
return variable;
};
}
String redundantAssignmentInsideTryBlock(AutoCloseable closeable) throws Exception {
try (closeable) {
// BUG: Diagnostic contains:
String variable = toString();
return variable;
}
}
String redundantAssignmentsInsideTryAndFinallyBlocks() {
String variable = toString();
try {
// BUG: Diagnostic contains:
variable = "foo";
return variable;
} finally {
String variable2 = toString();
if (true) {
// BUG: Diagnostic contains:
String variable3 = toString();
return variable3;
}
return variable2;
}
}
String assignmentUsedInsideFinallyBlock() {
String variable = toString();
try {
variable = "foo";
return variable;
} finally {
String variable2 = toString();
return variable + variable2;
}
}
String redundantAssignmentToVariableUsedInsideUnexecutedFinallyBlock(AutoCloseable closeable)
throws Exception {
String variable = toString();
try (closeable) {
if (true) {
// BUG: Diagnostic contains:
variable = "foo";
return variable;
}
}
try {
} finally {
return variable;
}
}
}
""")
.doTest();
}
@@ -197,30 +199,34 @@ final class DirectReturnTest {
BugCheckerRefactoringTestHelper.newInstance(DirectReturn.class, getClass())
.addInputLines(
"A.java",
"class A {",
" String m1() {",
" String variable = null;",
" variable = toString();",
" return variable;",
" }",
"",
" String m2() {",
" String variable = toString();",
" return variable;",
" }",
"}")
"""
class A {
String m1() {
String variable = null;
variable = toString();
return variable;
}
String m2() {
String variable = toString();
return variable;
}
}
""")
.addOutputLines(
"A.java",
"class A {",
" String m1() {",
" String variable = null;",
" return toString();",
" }",
"",
" String m2() {",
" return toString();",
" }",
"}")
"""
class A {
String m1() {
String variable = null;
return toString();
}
String m2() {
return toString();
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,54 +11,58 @@ final class EmptyMethodTest {
CompilationTestHelper.newInstance(EmptyMethod.class, getClass())
.addSourceLines(
"A.java",
"class A {",
" Object m1() {",
" return null;",
" }",
"",
" void m2() {",
" System.out.println(42);",
" }",
"",
" void m3() {}",
"",
" // BUG: Diagnostic contains:",
" static void m4() {}",
"",
" interface F {",
" void fun();",
" }",
"",
" final class MyTestClass {",
" void helperMethod() {}",
" }",
"}")
"""
class A {
Object m1() {
return null;
}
void m2() {
System.out.println(42);
}
void m3() {}
// BUG: Diagnostic contains:
static void m4() {}
interface F {
void fun();
}
final class MyTestClass {
void helperMethod() {}
}
}
""")
.addSourceLines(
"B.java",
"import org.aspectj.lang.annotation.Pointcut;",
"",
"final class B implements A.F {",
" @Override",
" public void fun() {}",
"",
" // BUG: Diagnostic contains:",
" void m3() {}",
"",
" /** Javadoc. */",
" // BUG: Diagnostic contains:",
" void m4() {}",
"",
" void m5() {",
" // Single-line comment.",
" }",
"",
" void m6() {",
" /* Multi-line comment. */",
" }",
"",
" @Pointcut",
" void m7() {}",
"}")
"""
import org.aspectj.lang.annotation.Pointcut;
final class B implements A.F {
@Override
public void fun() {}
// BUG: Diagnostic contains:
void m3() {}
/** Javadoc. */
// BUG: Diagnostic contains:
void m4() {}
void m5() {
// Single-line comment.
}
void m6() {
/* Multi-line comment. */
}
@Pointcut
void m7() {}
}
""")
.doTest();
}
@@ -67,22 +71,26 @@ final class EmptyMethodTest {
BugCheckerRefactoringTestHelper.newInstance(EmptyMethod.class, getClass())
.addInputLines(
"A.java",
"final class A {",
" void instanceMethod() {}",
"",
" static void staticMethod() {}",
"",
" static void staticMethodWithComment() {",
" /* Foo. */",
" }",
"}")
"""
final class A {
void instanceMethod() {}
static void staticMethod() {}
static void staticMethodWithComment() {
/* Foo. */
}
}
""")
.addOutputLines(
"A.java",
"final class A {",
" static void staticMethodWithComment() {",
" /* Foo. */",
" }",
"}")
"""
final class A {
static void staticMethodWithComment() {
/* Foo. */
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -19,62 +19,64 @@ final class EmptyMonoZipTest {
"Invoking `Mono#zipWith` on `Mono#empty()` or a `Mono<Void>` is a no-op"))
.addSourceLines(
"A.java",
"import static reactor.core.publisher.Mono.zip;",
"",
"import reactor.core.publisher.Flux;",
"import reactor.core.publisher.Mono;",
"",
"class A {",
" void m() {",
" Flux.just(1).zip(Mono.empty(), Flux.just(2));",
"",
" Mono<Void> voidMono = Mono.empty();",
" Mono<Integer> integerMono = Mono.empty();",
"",
" zip(Mono.just(1), Mono.just(2));",
" Mono.zip(Mono.just(1), Mono.just(2));",
" Mono.zip(Mono.just(1), Mono.just(2), Mono.just(3));",
" Mono.zip(integerMono, integerMono);",
"",
" // BUG: Diagnostic matches: ARGUMENT",
" zip(Mono.empty(), Mono.empty());",
" // BUG: Diagnostic matches: ARGUMENT",
" Mono.zip(Mono.empty(), Mono.empty());",
" // BUG: Diagnostic matches: ARGUMENT",
" Mono.zip(voidMono, Mono.just(1));",
" // BUG: Diagnostic matches: ARGUMENT",
" Mono.zip(voidMono, voidMono);",
" // BUG: Diagnostic matches: ARGUMENT",
" Mono.zip(Mono.just(1).then(), Mono.just(2));",
" // BUG: Diagnostic matches: ARGUMENT",
" Mono.zip(Mono.just(1), Mono.just(2), voidMono);",
"",
" Mono.just(1).zipWith(Mono.just(2));",
" Mono.just(1).zipWith(integerMono);",
" Mono.just(1).zipWith(integerMono, (a, b) -> a + b);",
"",
" // BUG: Diagnostic matches: ARGUMENT",
" Mono.just(1).zipWith(Mono.empty());",
" // BUG: Diagnostic matches: ARGUMENT",
" Mono.just(1).zipWith(voidMono);",
" // BUG: Diagnostic matches: RECEIVER",
" Mono.empty().zipWith(Mono.just(1));",
" // BUG: Diagnostic matches: RECEIVER",
" voidMono.zipWith(Mono.just(1));",
" }",
"",
" abstract class MyMono extends Mono<Object> {",
" void m() {",
" zip(Mono.just(1), Mono.just(2));",
" // BUG: Diagnostic matches: ARGUMENT",
" zip(Mono.empty(), Mono.empty());",
"",
" zipWith(Mono.just(1));",
" // BUG: Diagnostic matches: ARGUMENT",
" zipWith(Mono.empty());",
" }",
" }",
"}")
"""
import static reactor.core.publisher.Mono.zip;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
class A {
void m() {
Flux.just(1).zip(Mono.empty(), Flux.just(2));
Mono<Void> voidMono = Mono.empty();
Mono<Integer> integerMono = Mono.empty();
zip(Mono.just(1), Mono.just(2));
Mono.zip(Mono.just(1), Mono.just(2));
Mono.zip(Mono.just(1), Mono.just(2), Mono.just(3));
Mono.zip(integerMono, integerMono);
// BUG: Diagnostic matches: ARGUMENT
zip(Mono.empty(), Mono.empty());
// BUG: Diagnostic matches: ARGUMENT
Mono.zip(Mono.empty(), Mono.empty());
// BUG: Diagnostic matches: ARGUMENT
Mono.zip(voidMono, Mono.just(1));
// BUG: Diagnostic matches: ARGUMENT
Mono.zip(voidMono, voidMono);
// BUG: Diagnostic matches: ARGUMENT
Mono.zip(Mono.just(1).then(), Mono.just(2));
// BUG: Diagnostic matches: ARGUMENT
Mono.zip(Mono.just(1), Mono.just(2), voidMono);
Mono.just(1).zipWith(Mono.just(2));
Mono.just(1).zipWith(integerMono);
Mono.just(1).zipWith(integerMono, (a, b) -> a + b);
// BUG: Diagnostic matches: ARGUMENT
Mono.just(1).zipWith(Mono.empty());
// BUG: Diagnostic matches: ARGUMENT
Mono.just(1).zipWith(voidMono);
// BUG: Diagnostic matches: RECEIVER
Mono.empty().zipWith(Mono.just(1));
// BUG: Diagnostic matches: RECEIVER
voidMono.zipWith(Mono.just(1));
}
abstract class MyMono extends Mono<Object> {
void m() {
zip(Mono.just(1), Mono.just(2));
// BUG: Diagnostic matches: ARGUMENT
zip(Mono.empty(), Mono.empty());
zipWith(Mono.just(1));
// BUG: Diagnostic matches: ARGUMENT
zipWith(Mono.empty());
}
}
}
""")
.doTest();
}
}

View File

@@ -0,0 +1,181 @@
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

@@ -9,76 +9,78 @@ final class ExplicitEnumOrderingTest {
CompilationTestHelper.newInstance(ExplicitEnumOrdering.class, getClass())
.addSourceLines(
"A.java",
"import static java.lang.annotation.RetentionPolicy.CLASS;",
"import static java.lang.annotation.RetentionPolicy.RUNTIME;",
"import static java.lang.annotation.RetentionPolicy.SOURCE;",
"import static java.time.chrono.IsoEra.BCE;",
"import static java.time.chrono.IsoEra.CE;",
"",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.Ordering;",
"import java.lang.annotation.RetentionPolicy;",
"import java.time.chrono.IsoEra;",
"",
"class A {",
" {",
" // The `List`-accepting overload is currently ignored.",
" Ordering.explicit(ImmutableList.of(RetentionPolicy.SOURCE, RetentionPolicy.CLASS));",
"",
" Ordering.explicit(IsoEra.BCE, IsoEra.CE);",
" // BUG: Diagnostic contains: IsoEra.CE",
" Ordering.explicit(IsoEra.BCE);",
" // BUG: Diagnostic contains: IsoEra.BCE",
" Ordering.explicit(IsoEra.CE);",
"",
" Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.CLASS, RetentionPolicy.RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.CLASS, RetentionPolicy.RUNTIME",
" Ordering.explicit(RetentionPolicy.SOURCE);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME",
" Ordering.explicit(RetentionPolicy.CLASS);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.CLASS",
" Ordering.explicit(RetentionPolicy.RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.RUNTIME",
" Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.CLASS);",
" // BUG: Diagnostic contains: RetentionPolicy.CLASS",
" Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE",
" Ordering.explicit(RetentionPolicy.CLASS, RetentionPolicy.RUNTIME);",
"",
" Ordering.explicit(BCE, CE);",
" // BUG: Diagnostic contains: IsoEra.CE",
" Ordering.explicit(BCE);",
" // BUG: Diagnostic contains: IsoEra.BCE",
" Ordering.explicit(CE);",
"",
" Ordering.explicit(SOURCE, CLASS, RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.CLASS, RetentionPolicy.RUNTIME",
" Ordering.explicit(SOURCE);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME",
" Ordering.explicit(CLASS);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.CLASS",
" Ordering.explicit(RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.RUNTIME",
" Ordering.explicit(SOURCE, CLASS);",
" // BUG: Diagnostic contains: RetentionPolicy.CLASS",
" Ordering.explicit(SOURCE, RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE",
" Ordering.explicit(CLASS, RUNTIME);",
"",
" Ordering.explicit(RetentionPolicy.SOURCE, BCE, RetentionPolicy.CLASS, CE, RUNTIME);",
" Ordering.explicit(SOURCE, IsoEra.BCE, CLASS, IsoEra.CE, RetentionPolicy.RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.CLASS",
" Ordering.explicit(RetentionPolicy.SOURCE, BCE, CE, RUNTIME);",
" // BUG: Diagnostic contains: RetentionPolicy.CLASS",
" Ordering.explicit(IsoEra.BCE, SOURCE, IsoEra.CE, RetentionPolicy.RUNTIME);",
" // BUG: Diagnostic contains: IsoEra.CE, RetentionPolicy.RUNTIME",
" Ordering.explicit(IsoEra.BCE, SOURCE, RetentionPolicy.CLASS);",
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, IsoEra.BCE",
" Ordering.explicit(CLASS, RUNTIME, CE);",
"",
" Ordering.explicit(BCE, null, CE);",
" }",
"}")
"""
import static java.lang.annotation.RetentionPolicy.CLASS;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import static java.time.chrono.IsoEra.BCE;
import static java.time.chrono.IsoEra.CE;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Ordering;
import java.lang.annotation.RetentionPolicy;
import java.time.chrono.IsoEra;
class A {
{
// The `List`-accepting overload is currently ignored.
Ordering.explicit(ImmutableList.of(RetentionPolicy.SOURCE, RetentionPolicy.CLASS));
Ordering.explicit(IsoEra.BCE, IsoEra.CE);
// BUG: Diagnostic contains: IsoEra.CE
Ordering.explicit(IsoEra.BCE);
// BUG: Diagnostic contains: IsoEra.BCE
Ordering.explicit(IsoEra.CE);
Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.CLASS, RetentionPolicy.RUNTIME);
// BUG: Diagnostic contains: RetentionPolicy.CLASS, RetentionPolicy.RUNTIME
Ordering.explicit(RetentionPolicy.SOURCE);
// BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME
Ordering.explicit(RetentionPolicy.CLASS);
// BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.CLASS
Ordering.explicit(RetentionPolicy.RUNTIME);
// BUG: Diagnostic contains: RetentionPolicy.RUNTIME
Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.CLASS);
// BUG: Diagnostic contains: RetentionPolicy.CLASS
Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME);
// BUG: Diagnostic contains: RetentionPolicy.SOURCE
Ordering.explicit(RetentionPolicy.CLASS, RetentionPolicy.RUNTIME);
Ordering.explicit(BCE, CE);
// BUG: Diagnostic contains: IsoEra.CE
Ordering.explicit(BCE);
// BUG: Diagnostic contains: IsoEra.BCE
Ordering.explicit(CE);
Ordering.explicit(SOURCE, CLASS, RUNTIME);
// BUG: Diagnostic contains: RetentionPolicy.CLASS, RetentionPolicy.RUNTIME
Ordering.explicit(SOURCE);
// BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME
Ordering.explicit(CLASS);
// BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.CLASS
Ordering.explicit(RUNTIME);
// BUG: Diagnostic contains: RetentionPolicy.RUNTIME
Ordering.explicit(SOURCE, CLASS);
// BUG: Diagnostic contains: RetentionPolicy.CLASS
Ordering.explicit(SOURCE, RUNTIME);
// BUG: Diagnostic contains: RetentionPolicy.SOURCE
Ordering.explicit(CLASS, RUNTIME);
Ordering.explicit(RetentionPolicy.SOURCE, BCE, RetentionPolicy.CLASS, CE, RUNTIME);
Ordering.explicit(SOURCE, IsoEra.BCE, CLASS, IsoEra.CE, RetentionPolicy.RUNTIME);
// BUG: Diagnostic contains: RetentionPolicy.CLASS
Ordering.explicit(RetentionPolicy.SOURCE, BCE, CE, RUNTIME);
// BUG: Diagnostic contains: RetentionPolicy.CLASS
Ordering.explicit(IsoEra.BCE, SOURCE, IsoEra.CE, RetentionPolicy.RUNTIME);
// BUG: Diagnostic contains: IsoEra.CE, RetentionPolicy.RUNTIME
Ordering.explicit(IsoEra.BCE, SOURCE, RetentionPolicy.CLASS);
// BUG: Diagnostic contains: RetentionPolicy.SOURCE, IsoEra.BCE
Ordering.explicit(CLASS, RUNTIME, CE);
Ordering.explicit(BCE, null, CE);
}
}
""")
.doTest();
}
}

View File

@@ -12,55 +12,57 @@ final class FluxFlatMapUsageTest {
CompilationTestHelper.newInstance(FluxFlatMapUsage.class, getClass())
.addSourceLines(
"A.java",
"import java.util.function.BiFunction;",
"import java.util.function.Function;",
"import reactor.core.publisher.Flux;",
"import reactor.core.publisher.Mono;",
"",
"class A {",
" void m() {",
" // BUG: Diagnostic contains:",
" Flux.just(1).flatMap(Flux::just);",
" // BUG: Diagnostic contains:",
" Flux.just(1).<String>flatMap(i -> Flux.just(String.valueOf(i)));",
" // BUG: Diagnostic contains:",
" Flux.just(1).flatMapSequential(Flux::just);",
" // BUG: Diagnostic contains:",
" Flux.just(1).<String>flatMapSequential(i -> Flux.just(String.valueOf(i)));",
" // BUG: Diagnostic contains:",
" Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just);",
" // BUG: Diagnostic contains:",
" Flux.just(1, 2).groupBy(i -> i).<String>flatMap(i -> Flux.just(String.valueOf(i)));",
" // BUG: Diagnostic contains:",
" Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just);",
" // BUG: Diagnostic contains:",
" Flux.just(1, 2).groupBy(i -> i).<String>flatMapSequential(i -> Flux.just(String.valueOf(i)));",
"",
" Mono.just(1).flatMap(Mono::just);",
" Flux.just(1).concatMap(Flux::just);",
"",
" Flux.just(1).flatMap(Flux::just, 1);",
" Flux.just(1).flatMap(Flux::just, 1, 1);",
" Flux.just(1).flatMap(Flux::just, throwable -> Flux.empty(), Flux::empty);",
"",
" Flux.just(1).flatMapSequential(Flux::just, 1);",
" Flux.just(1).flatMapSequential(Flux::just, 1, 1);",
"",
" // BUG: Diagnostic contains:",
" this.<String, Flux<String>>sink(Flux::flatMap);",
" // BUG: Diagnostic contains:",
" this.<Integer, Flux<Integer>>sink(Flux::<Integer>flatMap);",
"",
" // BUG: Diagnostic contains:",
" this.<String, Flux<String>>sink(Flux::flatMapSequential);",
" // BUG: Diagnostic contains:",
" this.<Integer, Flux<Integer>>sink(Flux::<Integer>flatMapSequential);",
"",
" this.<String, Mono<String>>sink(Mono::flatMap);",
" }",
"",
" private <T, P> void sink(BiFunction<P, Function<T, P>, P> fun) {}",
"}")
"""
import java.util.function.BiFunction;
import java.util.function.Function;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
class A {
void m() {
// BUG: Diagnostic contains:
Flux.just(1).flatMap(Flux::just);
// BUG: Diagnostic contains:
Flux.just(1).<String>flatMap(i -> Flux.just(String.valueOf(i)));
// BUG: Diagnostic contains:
Flux.just(1).flatMapSequential(Flux::just);
// BUG: Diagnostic contains:
Flux.just(1).<String>flatMapSequential(i -> Flux.just(String.valueOf(i)));
// BUG: Diagnostic contains:
Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just);
// BUG: Diagnostic contains:
Flux.just(1, 2).groupBy(i -> i).<String>flatMap(i -> Flux.just(String.valueOf(i)));
// BUG: Diagnostic contains:
Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just);
// BUG: Diagnostic contains:
Flux.just(1, 2).groupBy(i -> i).<String>flatMapSequential(i -> Flux.just(String.valueOf(i)));
Mono.just(1).flatMap(Mono::just);
Flux.just(1).concatMap(Flux::just);
Flux.just(1).flatMap(Flux::just, 1);
Flux.just(1).flatMap(Flux::just, 1, 1);
Flux.just(1).flatMap(Flux::just, throwable -> Flux.empty(), Flux::empty);
Flux.just(1).flatMapSequential(Flux::just, 1);
Flux.just(1).flatMapSequential(Flux::just, 1, 1);
// BUG: Diagnostic contains:
this.<String, Flux<String>>sink(Flux::flatMap);
// BUG: Diagnostic contains:
this.<Integer, Flux<Integer>>sink(Flux::<Integer>flatMap);
// BUG: Diagnostic contains:
this.<String, Flux<String>>sink(Flux::flatMapSequential);
// BUG: Diagnostic contains:
this.<Integer, Flux<Integer>>sink(Flux::<Integer>flatMapSequential);
this.<String, Mono<String>>sink(Mono::flatMap);
}
private <T, P> void sink(BiFunction<P, Function<T, P>, P> fun) {}
}
""")
.doTest();
}
@@ -69,32 +71,36 @@ final class FluxFlatMapUsageTest {
BugCheckerRefactoringTestHelper.newInstance(FluxFlatMapUsage.class, getClass())
.addInputLines(
"A.java",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" private static final int MAX_CONCURRENCY = 8;",
"",
" void m() {",
" Flux.just(1).flatMap(Flux::just);",
" Flux.just(1).flatMapSequential(Flux::just);",
" Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just);",
" Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just);",
" }",
"}")
"""
import reactor.core.publisher.Flux;
class A {
private static final int MAX_CONCURRENCY = 8;
void m() {
Flux.just(1).flatMap(Flux::just);
Flux.just(1).flatMapSequential(Flux::just);
Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just);
Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just);
}
}
""")
.addOutputLines(
"A.java",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" private static final int MAX_CONCURRENCY = 8;",
"",
" void m() {",
" Flux.just(1).concatMap(Flux::just);",
" Flux.just(1).concatMap(Flux::just);",
" Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just, MAX_CONCURRENCY);",
" Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just, MAX_CONCURRENCY);",
" }",
"}")
"""
import reactor.core.publisher.Flux;
class A {
private static final int MAX_CONCURRENCY = 8;
void m() {
Flux.just(1).concatMap(Flux::just);
Flux.just(1).concatMap(Flux::just);
Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just, MAX_CONCURRENCY);
Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just, MAX_CONCURRENCY);
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
@@ -104,32 +110,36 @@ final class FluxFlatMapUsageTest {
.setFixChooser(FixChoosers.SECOND)
.addInputLines(
"A.java",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" private static final int MAX_CONCURRENCY = 8;",
"",
" void m() {",
" Flux.just(1).flatMap(Flux::just);",
" Flux.just(1).flatMapSequential(Flux::just);",
" Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just);",
" Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just);",
" }",
"}")
"""
import reactor.core.publisher.Flux;
class A {
private static final int MAX_CONCURRENCY = 8;
void m() {
Flux.just(1).flatMap(Flux::just);
Flux.just(1).flatMapSequential(Flux::just);
Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just);
Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just);
}
}
""")
.addOutputLines(
"A.java",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" private static final int MAX_CONCURRENCY = 8;",
"",
" void m() {",
" Flux.just(1).flatMap(Flux::just, MAX_CONCURRENCY);",
" Flux.just(1).flatMapSequential(Flux::just, MAX_CONCURRENCY);",
" Flux.just(1, 2).groupBy(i -> i).concatMap(Flux::just);",
" Flux.just(1, 2).groupBy(i -> i).concatMap(Flux::just);",
" }",
"}")
"""
import reactor.core.publisher.Flux;
class A {
private static final int MAX_CONCURRENCY = 8;
void m() {
Flux.just(1).flatMap(Flux::just, MAX_CONCURRENCY);
Flux.just(1).flatMapSequential(Flux::just, MAX_CONCURRENCY);
Flux.just(1, 2).groupBy(i -> i).concatMap(Flux::just);
Flux.just(1, 2).groupBy(i -> i).concatMap(Flux::just);
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -21,36 +21,38 @@ final class FluxImplicitBlockTest {
m -> Stream.of("SuppressWarnings", "toImmutableList", "toList").allMatch(m::contains))
.addSourceLines(
"A.java",
"import com.google.common.collect.ImmutableList;",
"import java.util.stream.Stream;",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" // BUG: Diagnostic matches: X",
" Flux.just(1).toIterable();",
" // BUG: Diagnostic matches: X",
" Flux.just(2).toStream();",
" // BUG: Diagnostic matches: X",
" long count = Flux.just(3).toStream().count();",
"",
" Flux.just(4).toIterable(1);",
" Flux.just(5).toIterable(2, null);",
" Flux.just(6).toStream(3);",
" new Foo().toIterable();",
" new Foo().toStream();",
" }",
"",
" class Foo<T> {",
" Iterable<T> toIterable() {",
" return ImmutableList.of();",
" }",
"",
" Stream<T> toStream() {",
" return Stream.empty();",
" }",
" }",
"}")
"""
import com.google.common.collect.ImmutableList;
import java.util.stream.Stream;
import reactor.core.publisher.Flux;
class A {
void m() {
// BUG: Diagnostic matches: X
Flux.just(1).toIterable();
// BUG: Diagnostic matches: X
Flux.just(2).toStream();
// BUG: Diagnostic matches: X
long count = Flux.just(3).toStream().count();
Flux.just(4).toIterable(1);
Flux.just(5).toIterable(2, null);
Flux.just(6).toStream(3);
new Foo().toIterable();
new Foo().toStream();
}
class Foo<T> {
Iterable<T> toIterable() {
return ImmutableList.of();
}
Stream<T> toStream() {
return Stream.empty();
}
}
}
""")
.doTest();
}
@@ -61,16 +63,18 @@ final class FluxImplicitBlockTest {
.expectErrorMessage("X", m -> !m.contains("toImmutableList"))
.addSourceLines(
"A.java",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" // BUG: Diagnostic matches: X",
" Flux.just(1).toIterable();",
" // BUG: Diagnostic matches: X",
" Flux.just(2).toStream();",
" }",
"}")
"""
import reactor.core.publisher.Flux;
class A {
void m() {
// BUG: Diagnostic matches: X
Flux.just(1).toIterable();
// BUG: Diagnostic matches: X
Flux.just(2).toStream();
}
}
""")
.doTest();
}
@@ -79,25 +83,29 @@ final class FluxImplicitBlockTest {
BugCheckerRefactoringTestHelper.newInstance(FluxImplicitBlock.class, getClass())
.addInputLines(
"A.java",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).toIterable();",
" Flux.just(2).toStream();",
" }",
"}")
"""
import reactor.core.publisher.Flux;
class A {
void m() {
Flux.just(1).toIterable();
Flux.just(2).toStream();
}
}
""")
.addOutputLines(
"A.java",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" @SuppressWarnings(\"FluxImplicitBlock\")",
" void m() {",
" Flux.just(1).toIterable();",
" Flux.just(2).toStream();",
" }",
"}")
"""
import reactor.core.publisher.Flux;
class A {
@SuppressWarnings("FluxImplicitBlock")
void m() {
Flux.just(1).toIterable();
Flux.just(2).toStream();
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
@@ -107,34 +115,38 @@ final class FluxImplicitBlockTest {
.setFixChooser(SECOND)
.addInputLines(
"A.java",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).toIterable();",
" Flux.just(2).toStream();",
" Flux.just(3).toIterable().iterator();",
" Flux.just(4).toStream().count();",
" Flux.just(5) /* a */./* b */ toIterable /* c */(/* d */ ) /* e */;",
" Flux.just(6) /* a */./* b */ toStream /* c */(/* d */ ) /* e */;",
" }",
"}")
"""
import reactor.core.publisher.Flux;
class A {
void m() {
Flux.just(1).toIterable();
Flux.just(2).toStream();
Flux.just(3).toIterable().iterator();
Flux.just(4).toStream().count();
Flux.just(5) /* a */./* b */ toIterable /* c */(/* d */ ) /* e */;
Flux.just(6) /* a */./* b */ toStream /* c */(/* d */ ) /* e */;
}
}
""")
.addOutputLines(
"A.java",
"import static com.google.common.collect.ImmutableList.toImmutableList;",
"",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).collect(toImmutableList()).block();",
" Flux.just(2).collect(toImmutableList()).block().stream();",
" Flux.just(3).collect(toImmutableList()).block().iterator();",
" Flux.just(4).collect(toImmutableList()).block().stream().count();",
" Flux.just(5).collect(toImmutableList()).block() /* e */;",
" Flux.just(6).collect(toImmutableList()).block().stream() /* e */;",
" }",
"}")
"""
import static com.google.common.collect.ImmutableList.toImmutableList;
import reactor.core.publisher.Flux;
class A {
void m() {
Flux.just(1).collect(toImmutableList()).block();
Flux.just(2).collect(toImmutableList()).block().stream();
Flux.just(3).collect(toImmutableList()).block().iterator();
Flux.just(4).collect(toImmutableList()).block().stream().count();
Flux.just(5).collect(toImmutableList()).block() /* e */;
Flux.just(6).collect(toImmutableList()).block().stream() /* e */;
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
@@ -144,34 +156,38 @@ final class FluxImplicitBlockTest {
.setFixChooser(THIRD)
.addInputLines(
"A.java",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).toIterable();",
" Flux.just(2).toStream();",
" Flux.just(3).toIterable().iterator();",
" Flux.just(4).toStream().count();",
" Flux.just(5) /* a */./* b */ toIterable /* c */(/* d */ ) /* e */;",
" Flux.just(6) /* a */./* b */ toStream /* c */(/* d */ ) /* e */;",
" }",
"}")
"""
import reactor.core.publisher.Flux;
class A {
void m() {
Flux.just(1).toIterable();
Flux.just(2).toStream();
Flux.just(3).toIterable().iterator();
Flux.just(4).toStream().count();
Flux.just(5) /* a */./* b */ toIterable /* c */(/* d */ ) /* e */;
Flux.just(6) /* a */./* b */ toStream /* c */(/* d */ ) /* e */;
}
}
""")
.addOutputLines(
"A.java",
"import static java.util.stream.Collectors.toList;",
"",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Flux.just(1).collect(toList()).block();",
" Flux.just(2).collect(toList()).block().stream();",
" Flux.just(3).collect(toList()).block().iterator();",
" Flux.just(4).collect(toList()).block().stream().count();",
" Flux.just(5).collect(toList()).block() /* e */;",
" Flux.just(6).collect(toList()).block().stream() /* e */;",
" }",
"}")
"""
import static java.util.stream.Collectors.toList;
import reactor.core.publisher.Flux;
class A {
void m() {
Flux.just(1).collect(toList()).block();
Flux.just(2).collect(toList()).block().stream();
Flux.just(3).collect(toList()).block().iterator();
Flux.just(4).collect(toList()).block().stream().count();
Flux.just(5).collect(toList()).block() /* e */;
Flux.just(6).collect(toList()).block().stream() /* e */;
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,294 +11,296 @@ final class FormatStringConcatenationTest {
CompilationTestHelper.newInstance(FormatStringConcatenation.class, getClass())
.addSourceLines(
"A.java",
"import static com.google.common.base.Preconditions.checkArgument;",
"import static com.google.common.base.Preconditions.checkNotNull;",
"import static com.google.common.base.Preconditions.checkState;",
"import static com.google.common.base.Verify.verify;",
"import static org.assertj.core.api.Assertions.assertThat;",
"import static org.assertj.core.api.SoftAssertions.assertSoftly;",
"",
"import java.util.Formatter;",
"import java.util.Locale;",
"import org.assertj.core.api.Assertions;",
"import org.assertj.core.api.BDDAssertions;",
"import org.assertj.core.api.Fail;",
"import org.assertj.core.api.ThrowableAssertAlternative;",
"import org.assertj.core.api.WithAssertions;",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"import org.slf4j.Marker;",
"",
"class A {",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
"",
" void negative() {",
" hashCode();",
" equals(new A());",
" equals(toString());",
" equals(0);",
" equals(\"str\");",
" equals(\"str\" + 0);",
" equals(0 + 0);",
" equals(0 - 0);",
" equals(\"str \" + toString());",
" }",
"",
" void assertj() {",
" assertThat(0).overridingErrorMessage(toString());",
" assertThat(0).overridingErrorMessage(\"str\");",
" assertThat(0).overridingErrorMessage(\"str \" + 0);",
" assertThat(0).overridingErrorMessage(\"str %s\", 2 * 3);",
" assertThat(0).overridingErrorMessage(\"str %s\", toString());",
" // BUG: Diagnostic contains:",
" assertThat(0).overridingErrorMessage(\"str \" + hashCode() / 2);",
" // BUG: Diagnostic contains:",
" assertThat(0).overridingErrorMessage((\"str \" + toString()));",
" // BUG: Diagnostic contains:",
" assertThat(0).overridingErrorMessage(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" assertThat(0).overridingErrorMessage(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" assertThat(0).withFailMessage(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" assertThat(0).withFailMessage(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" assertSoftly(softly -> softly.fail(\"str \" + toString()));",
" // BUG: Diagnostic contains:",
" assertSoftly(softly -> softly.fail(\"%s \" + toString(), \"arg\"));",
" assertSoftly(softly -> softly.fail(\"str \" + toString(), new Throwable()));",
"",
" // BUG: Diagnostic contains:",
" assertThat(\"\").isEqualTo(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" assertThat(\"\").isEqualTo(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" assertThat(new Error()).hasMessage(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" assertThat(new Error()).hasMessage(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" assertThat(new Error()).hasMessageContaining(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" assertThat(new Error()).hasMessageContaining(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" assertThat(new Error()).hasMessageEndingWith(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" assertThat(new Error()).hasMessageEndingWith(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" assertThat(new Error()).hasMessageStartingWith(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" assertThat(new Error()).hasMessageStartingWith(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" assertThat(new Error()).hasRootCauseMessage(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" assertThat(new Error()).hasRootCauseMessage(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" assertThat(new Error()).hasStackTraceContaining(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" assertThat(new Error()).hasStackTraceContaining(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" assertThat(0).as(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" assertThat(0).as(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" assertThat(0).describedAs(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" assertThat(0).describedAs(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" ((ThrowableAssertAlternative) null).withMessage(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" ((ThrowableAssertAlternative) null).withMessage(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" ((ThrowableAssertAlternative) null).withMessageContaining(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" ((ThrowableAssertAlternative) null).withMessageContaining(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" ((ThrowableAssertAlternative) null).withMessageEndingWith(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" ((ThrowableAssertAlternative) null).withMessageEndingWith(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" ((ThrowableAssertAlternative) null).withMessageStartingWith(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" ((ThrowableAssertAlternative) null).withMessageStartingWith(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" ((ThrowableAssertAlternative) null).withStackTraceContaining(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" ((ThrowableAssertAlternative) null).withStackTraceContaining(\"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" ((WithAssertions) null).fail(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" ((WithAssertions) null).fail(\"%s \" + toString(), \"arg\");",
" ((WithAssertions) null).fail(\"str \" + toString(), new Throwable());",
"",
" // BUG: Diagnostic contains:",
" Assertions.fail(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" Assertions.fail(\"%s \" + toString(), \"arg\");",
" Assertions.fail(\"str \" + toString(), new Throwable());",
"",
" // BUG: Diagnostic contains:",
" BDDAssertions.fail(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" BDDAssertions.fail(\"%s \" + toString(), \"arg\");",
" BDDAssertions.fail(\"str \" + toString(), new Throwable());",
"",
" // BUG: Diagnostic contains:",
" Fail.fail(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" Fail.fail(\"%s \" + toString(), \"arg\");",
" Fail.fail(\"str \" + toString(), new Throwable());",
" }",
"",
" void guava() {",
" checkArgument(true);",
" checkArgument(true, toString());",
" checkArgument(true, \"str\");",
" checkArgument(true, \"str \" + 0);",
" checkArgument(true, \"str %s\", 2 * 3);",
" checkArgument(true, \"str %s\", toString());",
" // BUG: Diagnostic contains:",
" checkArgument(true, \"str \" + hashCode() / 2);",
" // BUG: Diagnostic contains:",
" checkArgument(true, (\"str \" + toString()));",
" // BUG: Diagnostic contains:",
" checkArgument(true, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" checkArgument(true, \"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" checkNotNull(true, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" checkNotNull(true, \"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" checkState(true, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" checkState(true, \"%s \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" verify(true, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" verify(true, \"%s \" + toString(), \"arg\");",
" }",
"",
" void jdk() {",
" String.format(\"str\");",
" String.format(\"str \" + 0);",
" String.format(\"str {}\", 2 * 3);",
" String.format(\"str {}\", toString());",
" // BUG: Diagnostic contains:",
" String.format(\"str \" + hashCode() / 2);",
" // BUG: Diagnostic contains:",
" String.format((\"str \" + toString()));",
" // BUG: Diagnostic contains:",
" String.format(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" String.format(\"{} \" + toString(), \"arg\");",
"",
" String.format(Locale.ROOT, \"str\");",
" String.format(Locale.ROOT, \"str \" + 0);",
" String.format(Locale.ROOT, \"str {}\", 2 * 3);",
" String.format(Locale.ROOT, \"str {}\", toString());",
" // BUG: Diagnostic contains:",
" String.format(Locale.ROOT, (\"str \" + toString()));",
" // BUG: Diagnostic contains:",
" String.format(Locale.ROOT, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" String.format(Locale.ROOT, \"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" new Formatter().format(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" new Formatter().format(\"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" new Formatter().format(Locale.ROOT, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" new Formatter().format(Locale.ROOT, \"{} \" + toString(), \"arg\");",
" }",
"",
" void slf4j() {",
" LOG.debug(\"str\");",
" LOG.debug(\"str \" + 0);",
" LOG.debug(\"str {}\", 2 * 3);",
" LOG.debug(\"str {}\", toString());",
" // BUG: Diagnostic contains:",
" LOG.debug(\"str \" + hashCode() / 2);",
" // BUG: Diagnostic contains:",
" LOG.debug((\"str \" + toString()));",
" // BUG: Diagnostic contains:",
" LOG.debug(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" LOG.debug(\"{} \" + toString(), \"arg\");",
"",
" LOG.debug((Marker) null, \"str\");",
" LOG.debug((Marker) null, \"str \" + 0);",
" LOG.debug((Marker) null, \"str {}\", 2 * 3);",
" LOG.debug((Marker) null, \"str {}\", toString());",
" // BUG: Diagnostic contains:",
" LOG.debug((Marker) null, (\"str \" + toString()));",
" // BUG: Diagnostic contains:",
" LOG.debug((Marker) null, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" LOG.debug((Marker) null, \"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.error(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" LOG.error(\"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.error((Marker) null, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" LOG.error((Marker) null, \"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.info(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" LOG.info(\"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.info((Marker) null, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" LOG.info((Marker) null, \"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.trace(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" LOG.trace(\"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.trace((Marker) null, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" LOG.trace((Marker) null, \"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.warn(\"str \" + toString());",
" // BUG: Diagnostic contains:",
" LOG.warn(\"{} \" + toString(), \"arg\");",
"",
" // BUG: Diagnostic contains:",
" LOG.warn((Marker) null, \"str \" + toString());",
" // BUG: Diagnostic contains:",
" LOG.warn((Marker) null, \"{} \" + toString(), \"arg\");",
" }",
"}")
"""
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Verify.verify;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.SoftAssertions.assertSoftly;
import java.util.Formatter;
import java.util.Locale;
import org.assertj.core.api.Assertions;
import org.assertj.core.api.BDDAssertions;
import org.assertj.core.api.Fail;
import org.assertj.core.api.ThrowableAssertAlternative;
import org.assertj.core.api.WithAssertions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
class A {
private static final Logger LOG = LoggerFactory.getLogger(A.class);
void negative() {
hashCode();
equals(new A());
equals(toString());
equals(0);
equals("str");
equals("str" + 0);
equals(0 + 0);
equals(0 - 0);
equals("str " + toString());
}
void assertj() {
assertThat(0).overridingErrorMessage(toString());
assertThat(0).overridingErrorMessage("str");
assertThat(0).overridingErrorMessage("str " + 0);
assertThat(0).overridingErrorMessage("str %s", 2 * 3);
assertThat(0).overridingErrorMessage("str %s", toString());
// BUG: Diagnostic contains:
assertThat(0).overridingErrorMessage("str " + hashCode() / 2);
// BUG: Diagnostic contains:
assertThat(0).overridingErrorMessage(("str " + toString()));
// BUG: Diagnostic contains:
assertThat(0).overridingErrorMessage("str " + toString());
// BUG: Diagnostic contains:
assertThat(0).overridingErrorMessage("%s " + toString(), "arg");
// BUG: Diagnostic contains:
assertThat(0).withFailMessage("str " + toString());
// BUG: Diagnostic contains:
assertThat(0).withFailMessage("%s " + toString(), "arg");
// BUG: Diagnostic contains:
assertSoftly(softly -> softly.fail("str " + toString()));
// BUG: Diagnostic contains:
assertSoftly(softly -> softly.fail("%s " + toString(), "arg"));
assertSoftly(softly -> softly.fail("str " + toString(), new Throwable()));
// BUG: Diagnostic contains:
assertThat("").isEqualTo("str " + toString());
// BUG: Diagnostic contains:
assertThat("").isEqualTo("%s " + toString(), "arg");
// BUG: Diagnostic contains:
assertThat(new Error()).hasMessage("str " + toString());
// BUG: Diagnostic contains:
assertThat(new Error()).hasMessage("%s " + toString(), "arg");
// BUG: Diagnostic contains:
assertThat(new Error()).hasMessageContaining("str " + toString());
// BUG: Diagnostic contains:
assertThat(new Error()).hasMessageContaining("%s " + toString(), "arg");
// BUG: Diagnostic contains:
assertThat(new Error()).hasMessageEndingWith("str " + toString());
// BUG: Diagnostic contains:
assertThat(new Error()).hasMessageEndingWith("%s " + toString(), "arg");
// BUG: Diagnostic contains:
assertThat(new Error()).hasMessageStartingWith("str " + toString());
// BUG: Diagnostic contains:
assertThat(new Error()).hasMessageStartingWith("%s " + toString(), "arg");
// BUG: Diagnostic contains:
assertThat(new Error()).hasRootCauseMessage("str " + toString());
// BUG: Diagnostic contains:
assertThat(new Error()).hasRootCauseMessage("%s " + toString(), "arg");
// BUG: Diagnostic contains:
assertThat(new Error()).hasStackTraceContaining("str " + toString());
// BUG: Diagnostic contains:
assertThat(new Error()).hasStackTraceContaining("%s " + toString(), "arg");
// BUG: Diagnostic contains:
assertThat(0).as("str " + toString());
// BUG: Diagnostic contains:
assertThat(0).as("%s " + toString(), "arg");
// BUG: Diagnostic contains:
assertThat(0).describedAs("str " + toString());
// BUG: Diagnostic contains:
assertThat(0).describedAs("%s " + toString(), "arg");
// BUG: Diagnostic contains:
((ThrowableAssertAlternative) null).withMessage("str " + toString());
// BUG: Diagnostic contains:
((ThrowableAssertAlternative) null).withMessage("%s " + toString(), "arg");
// BUG: Diagnostic contains:
((ThrowableAssertAlternative) null).withMessageContaining("str " + toString());
// BUG: Diagnostic contains:
((ThrowableAssertAlternative) null).withMessageContaining("%s " + toString(), "arg");
// BUG: Diagnostic contains:
((ThrowableAssertAlternative) null).withMessageEndingWith("str " + toString());
// BUG: Diagnostic contains:
((ThrowableAssertAlternative) null).withMessageEndingWith("%s " + toString(), "arg");
// BUG: Diagnostic contains:
((ThrowableAssertAlternative) null).withMessageStartingWith("str " + toString());
// BUG: Diagnostic contains:
((ThrowableAssertAlternative) null).withMessageStartingWith("%s " + toString(), "arg");
// BUG: Diagnostic contains:
((ThrowableAssertAlternative) null).withStackTraceContaining("str " + toString());
// BUG: Diagnostic contains:
((ThrowableAssertAlternative) null).withStackTraceContaining("%s " + toString(), "arg");
// BUG: Diagnostic contains:
((WithAssertions) null).fail("str " + toString());
// BUG: Diagnostic contains:
((WithAssertions) null).fail("%s " + toString(), "arg");
((WithAssertions) null).fail("str " + toString(), new Throwable());
// BUG: Diagnostic contains:
Assertions.fail("str " + toString());
// BUG: Diagnostic contains:
Assertions.fail("%s " + toString(), "arg");
Assertions.fail("str " + toString(), new Throwable());
// BUG: Diagnostic contains:
BDDAssertions.fail("str " + toString());
// BUG: Diagnostic contains:
BDDAssertions.fail("%s " + toString(), "arg");
BDDAssertions.fail("str " + toString(), new Throwable());
// BUG: Diagnostic contains:
Fail.fail("str " + toString());
// BUG: Diagnostic contains:
Fail.fail("%s " + toString(), "arg");
Fail.fail("str " + toString(), new Throwable());
}
void guava() {
checkArgument(true);
checkArgument(true, toString());
checkArgument(true, "str");
checkArgument(true, "str " + 0);
checkArgument(true, "str %s", 2 * 3);
checkArgument(true, "str %s", toString());
// BUG: Diagnostic contains:
checkArgument(true, "str " + hashCode() / 2);
// BUG: Diagnostic contains:
checkArgument(true, ("str " + toString()));
// BUG: Diagnostic contains:
checkArgument(true, "str " + toString());
// BUG: Diagnostic contains:
checkArgument(true, "%s " + toString(), "arg");
// BUG: Diagnostic contains:
checkNotNull(true, "str " + toString());
// BUG: Diagnostic contains:
checkNotNull(true, "%s " + toString(), "arg");
// BUG: Diagnostic contains:
checkState(true, "str " + toString());
// BUG: Diagnostic contains:
checkState(true, "%s " + toString(), "arg");
// BUG: Diagnostic contains:
verify(true, "str " + toString());
// BUG: Diagnostic contains:
verify(true, "%s " + toString(), "arg");
}
void jdk() {
String.format("str");
String.format("str " + 0);
String.format("str {}", 2 * 3);
String.format("str {}", toString());
// BUG: Diagnostic contains:
String.format("str " + hashCode() / 2);
// BUG: Diagnostic contains:
String.format(("str " + toString()));
// BUG: Diagnostic contains:
String.format("str " + toString());
// BUG: Diagnostic contains:
String.format("{} " + toString(), "arg");
String.format(Locale.ROOT, "str");
String.format(Locale.ROOT, "str " + 0);
String.format(Locale.ROOT, "str {}", 2 * 3);
String.format(Locale.ROOT, "str {}", toString());
// BUG: Diagnostic contains:
String.format(Locale.ROOT, ("str " + toString()));
// BUG: Diagnostic contains:
String.format(Locale.ROOT, "str " + toString());
// BUG: Diagnostic contains:
String.format(Locale.ROOT, "{} " + toString(), "arg");
// BUG: Diagnostic contains:
new Formatter().format("str " + toString());
// BUG: Diagnostic contains:
new Formatter().format("{} " + toString(), "arg");
// BUG: Diagnostic contains:
new Formatter().format(Locale.ROOT, "str " + toString());
// BUG: Diagnostic contains:
new Formatter().format(Locale.ROOT, "{} " + toString(), "arg");
}
void slf4j() {
LOG.debug("str");
LOG.debug("str " + 0);
LOG.debug("str {}", 2 * 3);
LOG.debug("str {}", toString());
// BUG: Diagnostic contains:
LOG.debug("str " + hashCode() / 2);
// BUG: Diagnostic contains:
LOG.debug(("str " + toString()));
// BUG: Diagnostic contains:
LOG.debug("str " + toString());
// BUG: Diagnostic contains:
LOG.debug("{} " + toString(), "arg");
LOG.debug((Marker) null, "str");
LOG.debug((Marker) null, "str " + 0);
LOG.debug((Marker) null, "str {}", 2 * 3);
LOG.debug((Marker) null, "str {}", toString());
// BUG: Diagnostic contains:
LOG.debug((Marker) null, ("str " + toString()));
// BUG: Diagnostic contains:
LOG.debug((Marker) null, "str " + toString());
// BUG: Diagnostic contains:
LOG.debug((Marker) null, "{} " + toString(), "arg");
// BUG: Diagnostic contains:
LOG.error("str " + toString());
// BUG: Diagnostic contains:
LOG.error("{} " + toString(), "arg");
// BUG: Diagnostic contains:
LOG.error((Marker) null, "str " + toString());
// BUG: Diagnostic contains:
LOG.error((Marker) null, "{} " + toString(), "arg");
// BUG: Diagnostic contains:
LOG.info("str " + toString());
// BUG: Diagnostic contains:
LOG.info("{} " + toString(), "arg");
// BUG: Diagnostic contains:
LOG.info((Marker) null, "str " + toString());
// BUG: Diagnostic contains:
LOG.info((Marker) null, "{} " + toString(), "arg");
// BUG: Diagnostic contains:
LOG.trace("str " + toString());
// BUG: Diagnostic contains:
LOG.trace("{} " + toString(), "arg");
// BUG: Diagnostic contains:
LOG.trace((Marker) null, "str " + toString());
// BUG: Diagnostic contains:
LOG.trace((Marker) null, "{} " + toString(), "arg");
// BUG: Diagnostic contains:
LOG.warn("str " + toString());
// BUG: Diagnostic contains:
LOG.warn("{} " + toString(), "arg");
// BUG: Diagnostic contains:
LOG.warn((Marker) null, "str " + toString());
// BUG: Diagnostic contains:
LOG.warn((Marker) null, "{} " + toString(), "arg");
}
}
""")
.doTest();
}
@@ -307,102 +309,106 @@ final class FormatStringConcatenationTest {
BugCheckerRefactoringTestHelper.newInstance(FormatStringConcatenation.class, getClass())
.addInputLines(
"A.java",
"import static com.google.common.base.Preconditions.checkArgument;",
"import static org.assertj.core.api.Assertions.assertThat;",
"",
"import java.util.Locale;",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"import org.slf4j.Marker;",
"",
"class A {",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
"",
" void assertj() {",
" assertThat(0).overridingErrorMessage(toString() + \" str\");",
" assertThat(0).overridingErrorMessage(\"str \" + toString());",
" assertThat(0).overridingErrorMessage(toString() + toString());",
" assertThat(0).overridingErrorMessage(\"str \" + toString() + \" word \" + new A().hashCode());",
" assertThat(0).overridingErrorMessage(\"str \" + (toString() + \" word \") + (hashCode() / 2));",
"",
" // Flagged but not auto-fixed.",
" assertThat(0).overridingErrorMessage(\"%s \" + toString(), \"arg\");",
" }",
"",
" void guava() {",
" checkArgument(true, \"str \" + toString());",
"",
" // Flagged but not auto-fixed.",
" checkArgument(true, \"%s \" + toString(), \"arg\");",
" }",
"",
" void jdk() {",
" String.format(\"str \" + toString());",
" String.format(Locale.ROOT, \"str \" + toString());",
"",
" // Flagged but not auto-fixed.",
" String.format(\"{} \" + toString(), \"arg\");",
" String.format(Locale.ROOT, \"{} \" + toString(), \"arg\");",
" }",
"",
" void slf4j() {",
" LOG.debug(\"str \" + toString());",
" LOG.debug((Marker) null, \"str \" + toString());",
"",
" // Flagged but not auto-fixed.",
" LOG.debug(\"{} \" + toString(), \"arg\");",
" LOG.debug((Marker) null, \"{} \" + toString(), \"arg\");",
" }",
"}")
"""
import static com.google.common.base.Preconditions.checkArgument;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
class A {
private static final Logger LOG = LoggerFactory.getLogger(A.class);
void assertj() {
assertThat(0).overridingErrorMessage(toString() + " str");
assertThat(0).overridingErrorMessage("str " + toString());
assertThat(0).overridingErrorMessage(toString() + toString());
assertThat(0).overridingErrorMessage("str " + toString() + " word " + new A().hashCode());
assertThat(0).overridingErrorMessage("str " + (toString() + " word ") + (hashCode() / 2));
// Flagged but not auto-fixed.
assertThat(0).overridingErrorMessage("%s " + toString(), "arg");
}
void guava() {
checkArgument(true, "str " + toString());
// Flagged but not auto-fixed.
checkArgument(true, "%s " + toString(), "arg");
}
void jdk() {
String.format("str " + toString());
String.format(Locale.ROOT, "str " + toString());
// Flagged but not auto-fixed.
String.format("{} " + toString(), "arg");
String.format(Locale.ROOT, "{} " + toString(), "arg");
}
void slf4j() {
LOG.debug("str " + toString());
LOG.debug((Marker) null, "str " + toString());
// Flagged but not auto-fixed.
LOG.debug("{} " + toString(), "arg");
LOG.debug((Marker) null, "{} " + toString(), "arg");
}
}
""")
.addOutputLines(
"A.java",
"import static com.google.common.base.Preconditions.checkArgument;",
"import static org.assertj.core.api.Assertions.assertThat;",
"",
"import java.util.Locale;",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"import org.slf4j.Marker;",
"",
"class A {",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
"",
" void assertj() {",
" assertThat(0).overridingErrorMessage(\"%s str\", toString());",
" assertThat(0).overridingErrorMessage(\"str %s\", toString());",
" assertThat(0).overridingErrorMessage(\"%s%s\", toString(), toString());",
" assertThat(0).overridingErrorMessage(\"str %s word %s\", toString(), new A().hashCode());",
" assertThat(0).overridingErrorMessage(\"str %s word %s\", toString(), hashCode() / 2);",
"",
" // Flagged but not auto-fixed.",
" assertThat(0).overridingErrorMessage(\"%s \" + toString(), \"arg\");",
" }",
"",
" void guava() {",
" checkArgument(true, \"str %s\", toString());",
"",
" // Flagged but not auto-fixed.",
" checkArgument(true, \"%s \" + toString(), \"arg\");",
" }",
"",
" void jdk() {",
" String.format(\"str %s\", toString());",
" String.format(Locale.ROOT, \"str %s\", toString());",
"",
" // Flagged but not auto-fixed.",
" String.format(\"{} \" + toString(), \"arg\");",
" String.format(Locale.ROOT, \"{} \" + toString(), \"arg\");",
" }",
"",
" void slf4j() {",
" LOG.debug(\"str {}\", toString());",
" LOG.debug((Marker) null, \"str {}\", toString());",
"",
" // Flagged but not auto-fixed.",
" LOG.debug(\"{} \" + toString(), \"arg\");",
" LOG.debug((Marker) null, \"{} \" + toString(), \"arg\");",
" }",
"}")
"""
import static com.google.common.base.Preconditions.checkArgument;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
class A {
private static final Logger LOG = LoggerFactory.getLogger(A.class);
void assertj() {
assertThat(0).overridingErrorMessage("%s str", toString());
assertThat(0).overridingErrorMessage("str %s", toString());
assertThat(0).overridingErrorMessage("%s%s", toString(), toString());
assertThat(0).overridingErrorMessage("str %s word %s", toString(), new A().hashCode());
assertThat(0).overridingErrorMessage("str %s word %s", toString(), hashCode() / 2);
// Flagged but not auto-fixed.
assertThat(0).overridingErrorMessage("%s " + toString(), "arg");
}
void guava() {
checkArgument(true, "str %s", toString());
// Flagged but not auto-fixed.
checkArgument(true, "%s " + toString(), "arg");
}
void jdk() {
String.format("str %s", toString());
String.format(Locale.ROOT, "str %s", toString());
// Flagged but not auto-fixed.
String.format("{} " + toString(), "arg");
String.format(Locale.ROOT, "{} " + toString(), "arg");
}
void slf4j() {
LOG.debug("str {}", toString());
LOG.debug((Marker) null, "str {}", toString());
// Flagged but not auto-fixed.
LOG.debug("{} " + toString(), "arg");
LOG.debug((Marker) null, "{} " + toString(), "arg");
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -12,168 +12,176 @@ final class IdentityConversionTest {
CompilationTestHelper.newInstance(IdentityConversion.class, getClass())
.addSourceLines(
"A.java",
"import static com.google.errorprone.matchers.Matchers.instanceMethod;",
"import static com.google.errorprone.matchers.Matchers.staticMethod;",
"",
"import com.google.common.collect.ImmutableBiMap;",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableListMultimap;",
"import com.google.common.collect.ImmutableMap;",
"import com.google.common.collect.ImmutableMultimap;",
"import com.google.common.collect.ImmutableMultiset;",
"import com.google.common.collect.ImmutableRangeMap;",
"import com.google.common.collect.ImmutableRangeSet;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.common.collect.ImmutableSetMultimap;",
"import com.google.common.collect.ImmutableTable;",
"import com.google.errorprone.matchers.Matcher;",
"import com.google.errorprone.matchers.Matchers;",
"import reactor.adapter.rxjava.RxJava2Adapter;",
"import reactor.core.publisher.Flux;",
"import reactor.core.publisher.Mono;",
"",
"public final class A {",
" public void m() {",
" // BUG: Diagnostic contains:",
" Boolean b1 = Boolean.valueOf(Boolean.FALSE);",
" // BUG: Diagnostic contains:",
" Boolean b2 = Boolean.valueOf(false);",
" // BUG: Diagnostic contains:",
" boolean b3 = Boolean.valueOf(Boolean.FALSE);",
" // BUG: Diagnostic contains:",
" boolean b4 = Boolean.valueOf(false);",
"",
" // BUG: Diagnostic contains:",
" Byte byte1 = Byte.valueOf((Byte) Byte.MIN_VALUE);",
" // BUG: Diagnostic contains:",
" Byte byte2 = Byte.valueOf(Byte.MIN_VALUE);",
" // BUG: Diagnostic contains:",
" byte byte3 = Byte.valueOf((Byte) Byte.MIN_VALUE);",
" // BUG: Diagnostic contains:",
" byte byte4 = Byte.valueOf(Byte.MIN_VALUE);",
"",
" // BUG: Diagnostic contains:",
" Character c1 = Character.valueOf((Character) 'a');",
" // BUG: Diagnostic contains:",
" Character c2 = Character.valueOf('a');",
" // BUG: Diagnostic contains:",
" char c3 = Character.valueOf((Character) 'a');",
" // BUG: Diagnostic contains:",
" char c4 = Character.valueOf('a');",
"",
" // BUG: Diagnostic contains:",
" Double d1 = Double.valueOf((Double) 0.0);",
" // BUG: Diagnostic contains:",
" Double d2 = Double.valueOf(0.0);",
" // BUG: Diagnostic contains:",
" double d3 = Double.valueOf((Double) 0.0);",
" // BUG: Diagnostic contains:",
" double d4 = Double.valueOf(0.0);",
"",
" // BUG: Diagnostic contains:",
" Float f1 = Float.valueOf((Float) 0.0F);",
" // BUG: Diagnostic contains:",
" Float f2 = Float.valueOf(0.0F);",
" // BUG: Diagnostic contains:",
" float f3 = Float.valueOf((Float) 0.0F);",
" // BUG: Diagnostic contains:",
" float f4 = Float.valueOf(0.0F);",
"",
" // BUG: Diagnostic contains:",
" Integer i1 = Integer.valueOf((Integer) 1);",
" // BUG: Diagnostic contains:",
" Integer i2 = Integer.valueOf(1);",
" // BUG: Diagnostic contains:",
" int i3 = Integer.valueOf((Integer) 1);",
" // BUG: Diagnostic contains:",
" int i4 = Integer.valueOf(1);",
"",
" // BUG: Diagnostic contains:",
" Long l1 = Long.valueOf((Long) 1L);",
" // BUG: Diagnostic contains:",
" Long l2 = Long.valueOf(1L);",
" // BUG: Diagnostic contains:",
" long l3 = Long.valueOf((Long) 1L);",
" // BUG: Diagnostic contains:",
" long l4 = Long.valueOf(1L);",
"",
" Long l5 = Long.valueOf((Integer) 1);",
" Long l6 = Long.valueOf(1);",
" // BUG: Diagnostic contains:",
" long l7 = Long.valueOf((Integer) 1);",
" // BUG: Diagnostic contains:",
" long l8 = Long.valueOf(1);",
"",
" // BUG: Diagnostic contains:",
" Short s1 = Short.valueOf((Short) Short.MIN_VALUE);",
" // BUG: Diagnostic contains:",
" Short s2 = Short.valueOf(Short.MIN_VALUE);",
" // BUG: Diagnostic contains:",
" short s3 = Short.valueOf((Short) Short.MIN_VALUE);",
" // BUG: Diagnostic contains:",
" short s4 = Short.valueOf(Short.MIN_VALUE);",
"",
" // BUG: Diagnostic contains:",
" String boolStr = Boolean.valueOf(Boolean.FALSE).toString();",
" int boolHash = Boolean.valueOf(false).hashCode();",
" // BUG: Diagnostic contains:",
" int byteHash = Byte.valueOf((Byte) Byte.MIN_VALUE).hashCode();",
" String byteStr = Byte.valueOf(Byte.MIN_VALUE).toString();",
"",
" String str1 = String.valueOf(0);",
" // BUG: Diagnostic contains:",
" String str2 = String.valueOf(\"1\");",
"",
" // BUG: Diagnostic contains:",
" ImmutableBiMap<Object, Object> o1 = ImmutableBiMap.copyOf(ImmutableBiMap.of());",
" // BUG: Diagnostic contains:",
" ImmutableList<Object> o2 = ImmutableList.copyOf(ImmutableList.of());",
" ImmutableListMultimap<Object, Object> o3 =",
" // BUG: Diagnostic contains:",
" ImmutableListMultimap.copyOf(ImmutableListMultimap.of());",
" // BUG: Diagnostic contains:",
" ImmutableMap<Object, Object> o4 = ImmutableMap.copyOf(ImmutableMap.of());",
" // BUG: Diagnostic contains:",
" ImmutableMultimap<Object, Object> o5 = ImmutableMultimap.copyOf(ImmutableMultimap.of());",
" // BUG: Diagnostic contains:",
" ImmutableMultiset<Object> o6 = ImmutableMultiset.copyOf(ImmutableMultiset.of());",
" // BUG: Diagnostic contains:",
" ImmutableRangeMap<String, Object> o7 = ImmutableRangeMap.copyOf(ImmutableRangeMap.of());",
" // BUG: Diagnostic contains:",
" ImmutableRangeSet<String> o8 = ImmutableRangeSet.copyOf(ImmutableRangeSet.of());",
" // BUG: Diagnostic contains:",
" ImmutableSet<Object> o9 = ImmutableSet.copyOf(ImmutableSet.of());",
" ImmutableSetMultimap<Object, Object> o10 =",
" // BUG: Diagnostic contains:",
" ImmutableSetMultimap.copyOf(ImmutableSetMultimap.of());",
" // BUG: Diagnostic contains:",
" ImmutableTable<Object, Object, Object> o11 = ImmutableTable.copyOf(ImmutableTable.of());",
"",
" // BUG: Diagnostic contains:",
" Matcher allOf1 = Matchers.allOf(instanceMethod());",
" Matcher allOf2 = Matchers.allOf(instanceMethod(), staticMethod());",
" // BUG: Diagnostic contains:",
" Matcher anyOf1 = Matchers.anyOf(staticMethod());",
" Matcher anyOf2 = Matchers.anyOf(instanceMethod(), staticMethod());",
"",
" // BUG: Diagnostic contains:",
" Flux<Integer> flux1 = Flux.just(1).flatMap(e -> RxJava2Adapter.fluxToFlowable(Flux.just(2)));",
"",
" // BUG: Diagnostic contains:",
" Flux<Integer> flux2 = Flux.concat(Flux.just(1));",
" // BUG: Diagnostic contains:",
" Flux<Integer> flux3 = Flux.firstWithSignal(Flux.just(1));",
" // BUG: Diagnostic contains:",
" Flux<Integer> flux4 = Flux.from(Flux.just(1));",
" // BUG: Diagnostic contains:",
" Flux<Integer> flux5 = Flux.merge(Flux.just(1));",
"",
" // BUG: Diagnostic contains:",
" Mono<Integer> mono1 = Mono.from(Mono.just(1));",
" // BUG: Diagnostic contains:",
" Mono<Integer> mono2 = Mono.fromDirect(Mono.just(1));",
" }",
"}")
"""
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableRangeMap;
import com.google.common.collect.ImmutableRangeSet;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
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;
public final class A {
public void m() {
// BUG: Diagnostic contains:
Boolean b1 = Boolean.valueOf(Boolean.FALSE);
// BUG: Diagnostic contains:
Boolean b2 = Boolean.valueOf(false);
// BUG: Diagnostic contains:
boolean b3 = Boolean.valueOf(Boolean.FALSE);
// BUG: Diagnostic contains:
boolean b4 = Boolean.valueOf(false);
// BUG: Diagnostic contains:
Byte byte1 = Byte.valueOf((Byte) Byte.MIN_VALUE);
// BUG: Diagnostic contains:
Byte byte2 = Byte.valueOf(Byte.MIN_VALUE);
// BUG: Diagnostic contains:
byte byte3 = Byte.valueOf((Byte) Byte.MIN_VALUE);
// BUG: Diagnostic contains:
byte byte4 = Byte.valueOf(Byte.MIN_VALUE);
// BUG: Diagnostic contains:
Character c1 = Character.valueOf((Character) 'a');
// BUG: Diagnostic contains:
Character c2 = Character.valueOf('a');
// BUG: Diagnostic contains:
char c3 = Character.valueOf((Character) 'a');
// BUG: Diagnostic contains:
char c4 = Character.valueOf('a');
// BUG: Diagnostic contains:
Double d1 = Double.valueOf((Double) 0.0);
// BUG: Diagnostic contains:
Double d2 = Double.valueOf(0.0);
// BUG: Diagnostic contains:
double d3 = Double.valueOf((Double) 0.0);
// BUG: Diagnostic contains:
double d4 = Double.valueOf(0.0);
// BUG: Diagnostic contains:
Float f1 = Float.valueOf((Float) 0.0F);
// BUG: Diagnostic contains:
Float f2 = Float.valueOf(0.0F);
// BUG: Diagnostic contains:
float f3 = Float.valueOf((Float) 0.0F);
// BUG: Diagnostic contains:
float f4 = Float.valueOf(0.0F);
// BUG: Diagnostic contains:
Integer i1 = Integer.valueOf((Integer) 1);
// BUG: Diagnostic contains:
Integer i2 = Integer.valueOf(1);
// BUG: Diagnostic contains:
int i3 = Integer.valueOf((Integer) 1);
// BUG: Diagnostic contains:
int i4 = Integer.valueOf(1);
// BUG: Diagnostic contains:
Long l1 = Long.valueOf((Long) 1L);
// BUG: Diagnostic contains:
Long l2 = Long.valueOf(1L);
// BUG: Diagnostic contains:
long l3 = Long.valueOf((Long) 1L);
// BUG: Diagnostic contains:
long l4 = Long.valueOf(1L);
Long l5 = Long.valueOf((Integer) 1);
Long l6 = Long.valueOf(1);
// BUG: Diagnostic contains:
long l7 = Long.valueOf((Integer) 1);
// BUG: Diagnostic contains:
long l8 = Long.valueOf(1);
// BUG: Diagnostic contains:
Short s1 = Short.valueOf((Short) Short.MIN_VALUE);
// BUG: Diagnostic contains:
Short s2 = Short.valueOf(Short.MIN_VALUE);
// BUG: Diagnostic contains:
short s3 = Short.valueOf((Short) Short.MIN_VALUE);
// BUG: Diagnostic contains:
short s4 = Short.valueOf(Short.MIN_VALUE);
// BUG: Diagnostic contains:
String boolStr = Boolean.valueOf(Boolean.FALSE).toString();
int boolHash = Boolean.valueOf(false).hashCode();
// BUG: Diagnostic contains:
int byteHash = Byte.valueOf((Byte) Byte.MIN_VALUE).hashCode();
String byteStr = Byte.valueOf(Byte.MIN_VALUE).toString();
String str1 = String.valueOf(0);
// BUG: Diagnostic contains:
String str2 = String.valueOf("1");
// BUG: Diagnostic contains:
ImmutableBiMap<Object, Object> o1 = ImmutableBiMap.copyOf(ImmutableBiMap.of());
// BUG: Diagnostic contains:
ImmutableList<Object> o2 = ImmutableList.copyOf(ImmutableList.of());
ImmutableListMultimap<Object, Object> o3 =
// BUG: Diagnostic contains:
ImmutableListMultimap.copyOf(ImmutableListMultimap.of());
// BUG: Diagnostic contains:
ImmutableMap<Object, Object> o4 = ImmutableMap.copyOf(ImmutableMap.of());
// BUG: Diagnostic contains:
ImmutableMultimap<Object, Object> o5 = ImmutableMultimap.copyOf(ImmutableMultimap.of());
// BUG: Diagnostic contains:
ImmutableMultiset<Object> o6 = ImmutableMultiset.copyOf(ImmutableMultiset.of());
// BUG: Diagnostic contains:
ImmutableRangeMap<String, Object> o7 = ImmutableRangeMap.copyOf(ImmutableRangeMap.of());
// BUG: Diagnostic contains:
ImmutableRangeSet<String> o8 = ImmutableRangeSet.copyOf(ImmutableRangeSet.of());
// BUG: Diagnostic contains:
ImmutableSet<Object> o9 = ImmutableSet.copyOf(ImmutableSet.of());
ImmutableSetMultimap<Object, Object> o10 =
// BUG: Diagnostic contains:
ImmutableSetMultimap.copyOf(ImmutableSetMultimap.of());
// 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());
// BUG: Diagnostic contains:
Matcher anyOf1 = Matchers.anyOf(staticMethod());
Matcher anyOf2 = Matchers.anyOf(instanceMethod(), staticMethod());
// BUG: Diagnostic contains:
Flux<Integer> flux1 = Flux.just(1).flatMap(e -> RxJava2Adapter.fluxToFlowable(Flux.just(2)));
// BUG: Diagnostic contains:
Flux<Integer> flux2 = Flux.concat(Flux.just(1));
// BUG: Diagnostic contains:
Flux<Integer> flux3 = Flux.firstWithSignal(Flux.just(1));
// BUG: Diagnostic contains:
Flux<Integer> flux4 = Flux.from(Flux.just(1));
// BUG: Diagnostic contains:
Flux<Integer> flux5 = Flux.merge(Flux.just(1));
// BUG: Diagnostic contains:
Mono<Integer> mono1 = Mono.from(Mono.just(1));
// BUG: Diagnostic contains:
Mono<Integer> mono2 = Mono.fromDirect(Mono.just(1));
}
}
""")
.doTest();
}
@@ -182,104 +190,108 @@ final class IdentityConversionTest {
BugCheckerRefactoringTestHelper.newInstance(IdentityConversion.class, getClass())
.addInputLines(
"A.java",
"import static com.google.errorprone.matchers.Matchers.staticMethod;",
"import static org.mockito.Mockito.when;",
"",
"import com.google.common.collect.ImmutableCollection;",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.errorprone.matchers.Matcher;",
"import com.google.errorprone.matchers.Matchers;",
"import java.util.ArrayList;",
"import java.util.Collection;",
"import org.reactivestreams.Publisher;",
"import reactor.adapter.rxjava.RxJava2Adapter;",
"import reactor.core.publisher.Flux;",
"import reactor.core.publisher.Mono;",
"",
"public final class A {",
" public void m() {",
" ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());",
" ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());",
"",
" ImmutableCollection<Integer> list1 = ImmutableList.copyOf(ImmutableList.of(1));",
" ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));",
"",
" Collection<Integer> c1 = ImmutableSet.copyOf(ImmutableSet.of(1));",
" Collection<Integer> c2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));",
"",
" Flux<Integer> f1 = Flux.just(1).flatMap(e -> RxJava2Adapter.fluxToFlowable(Flux.just(2)));",
" Flux<Integer> f2 = Flux.concat(Flux.just(3));",
" Publisher<Integer> f3 = Flux.firstWithSignal(Flux.just(4));",
" Publisher<Integer> f4 = Flux.from(Flux.just(5));",
" Publisher<Integer> f5 = Flux.merge(Flux.just(6));",
"",
" Mono<Integer> m1 = Mono.from(Mono.just(7));",
" Publisher<Integer> m2 = Mono.fromDirect(Mono.just(8));",
"",
" bar(Flux.concat(Flux.just(9)));",
" bar(Mono.from(Mono.just(10)));",
"",
" Object o1 = ImmutableSet.copyOf(ImmutableList.of());",
" Object o2 = ImmutableSet.copyOf(ImmutableSet.of());",
"",
" Matcher matcher = Matchers.allOf(staticMethod());",
"",
" when(\"foo\".contains(\"f\")).thenAnswer(inv -> ImmutableSet.copyOf(ImmutableList.of(1)));",
" }",
"",
" void bar(Publisher<Integer> publisher) {}",
"}")
"""
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.matchers.Matchers;
import java.util.ArrayList;
import java.util.Collection;
import org.reactivestreams.Publisher;
import reactor.adapter.rxjava.RxJava2Adapter;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public final class A {
public void m() {
ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());
ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());
ImmutableCollection<Integer> list1 = ImmutableList.copyOf(ImmutableList.of(1));
ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));
Collection<Integer> c1 = ImmutableSet.copyOf(ImmutableSet.of(1));
Collection<Integer> c2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));
Flux<Integer> f1 = Flux.just(1).flatMap(e -> RxJava2Adapter.fluxToFlowable(Flux.just(2)));
Flux<Integer> f2 = Flux.concat(Flux.just(3));
Publisher<Integer> f3 = Flux.firstWithSignal(Flux.just(4));
Publisher<Integer> f4 = Flux.from(Flux.just(5));
Publisher<Integer> f5 = Flux.merge(Flux.just(6));
Mono<Integer> m1 = Mono.from(Mono.just(7));
Publisher<Integer> m2 = Mono.fromDirect(Mono.just(8));
bar(Flux.concat(Flux.just(9)));
bar(Mono.from(Mono.just(10)));
Object o1 = ImmutableSet.copyOf(ImmutableList.of());
Object o2 = ImmutableSet.copyOf(ImmutableSet.of());
Matcher matcher = Matchers.allOf(staticMethod());
when("foo".contains("f")).thenAnswer(inv -> ImmutableSet.copyOf(ImmutableList.of(1)));
}
void bar(Publisher<Integer> publisher) {}
}
""")
.addOutputLines(
"A.java",
"import static com.google.errorprone.matchers.Matchers.staticMethod;",
"import static org.mockito.Mockito.when;",
"",
"import com.google.common.collect.ImmutableCollection;",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.errorprone.matchers.Matcher;",
"import com.google.errorprone.matchers.Matchers;",
"import java.util.ArrayList;",
"import java.util.Collection;",
"import org.reactivestreams.Publisher;",
"import reactor.adapter.rxjava.RxJava2Adapter;",
"import reactor.core.publisher.Flux;",
"import reactor.core.publisher.Mono;",
"",
"public final class A {",
" public void m() {",
" ImmutableSet<Object> set1 = ImmutableSet.of();",
" ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());",
"",
" ImmutableCollection<Integer> list1 = ImmutableList.of(1);",
" ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));",
"",
" Collection<Integer> c1 = ImmutableSet.of(1);",
" Collection<Integer> c2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));",
"",
" Flux<Integer> f1 = Flux.just(1).flatMap(e -> Flux.just(2));",
" Flux<Integer> f2 = Flux.just(3);",
" Publisher<Integer> f3 = Flux.just(4);",
" Publisher<Integer> f4 = Flux.just(5);",
" Publisher<Integer> f5 = Flux.just(6);",
"",
" Mono<Integer> m1 = Mono.just(7);",
" Publisher<Integer> m2 = Mono.just(8);",
"",
" bar(Flux.just(9));",
" bar(Mono.just(10));",
"",
" Object o1 = ImmutableSet.copyOf(ImmutableList.of());",
" Object o2 = ImmutableSet.of();",
"",
" Matcher matcher = staticMethod();",
"",
" when(\"foo\".contains(\"f\")).thenAnswer(inv -> ImmutableSet.copyOf(ImmutableList.of(1)));",
" }",
"",
" void bar(Publisher<Integer> publisher) {}",
"}")
"""
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.matchers.Matchers;
import java.util.ArrayList;
import java.util.Collection;
import org.reactivestreams.Publisher;
import reactor.adapter.rxjava.RxJava2Adapter;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public final class A {
public void m() {
ImmutableSet<Object> set1 = ImmutableSet.of();
ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());
ImmutableCollection<Integer> list1 = ImmutableList.of(1);
ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));
Collection<Integer> c1 = ImmutableSet.of(1);
Collection<Integer> c2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));
Flux<Integer> f1 = Flux.just(1).flatMap(e -> Flux.just(2));
Flux<Integer> f2 = Flux.just(3);
Publisher<Integer> f3 = Flux.just(4);
Publisher<Integer> f4 = Flux.just(5);
Publisher<Integer> f5 = Flux.just(6);
Mono<Integer> m1 = Mono.just(7);
Publisher<Integer> m2 = Mono.just(8);
bar(Flux.just(9));
bar(Mono.just(10));
Object o1 = ImmutableSet.copyOf(ImmutableList.of());
Object o2 = ImmutableSet.of();
Matcher matcher = staticMethod();
when("foo".contains("f")).thenAnswer(inv -> ImmutableSet.copyOf(ImmutableList.of(1)));
}
void bar(Publisher<Integer> publisher) {}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
@@ -289,38 +301,42 @@ final class IdentityConversionTest {
.setFixChooser(FixChoosers.SECOND)
.addInputLines(
"A.java",
"import com.google.common.collect.ImmutableCollection;",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableSet;",
"import java.util.ArrayList;",
"",
"public final class A {",
" public void m() {",
" ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());",
" ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());",
"",
" ImmutableCollection<Integer> list1 = ImmutableList.copyOf(ImmutableList.of(1));",
" ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));",
" }",
"}")
"""
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
public final class A {
public void m() {
ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());
ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());
ImmutableCollection<Integer> list1 = ImmutableList.copyOf(ImmutableList.of(1));
ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));
}
}
""")
.addOutputLines(
"A.java",
"import com.google.common.collect.ImmutableCollection;",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableSet;",
"import java.util.ArrayList;",
"",
"public final class A {",
" public void m() {",
" @SuppressWarnings(\"IdentityConversion\")",
" ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());",
" ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());",
"",
" @SuppressWarnings(\"IdentityConversion\")",
" ImmutableCollection<Integer> list1 = ImmutableList.copyOf(ImmutableList.of(1));",
" ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));",
" }",
"}")
"""
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
public final class A {
public void m() {
@SuppressWarnings("IdentityConversion")
ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());
ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());
@SuppressWarnings("IdentityConversion")
ImmutableCollection<Integer> list1 = ImmutableList.copyOf(ImmutableList.of(1));
ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,94 +11,96 @@ final class ImmutablesSortedSetComparatorTest {
CompilationTestHelper.newInstance(ImmutablesSortedSetComparator.class, getClass())
.addSourceLines(
"A.java",
"import com.google.common.collect.ContiguousSet;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.common.collect.ImmutableSortedSet;",
"import java.util.NavigableSet;",
"import java.util.Set;",
"import java.util.SortedSet;",
"import java.util.TreeSet;",
"import org.immutables.value.Value;",
"",
"interface A {",
" @Value.Immutable",
" interface ImmutableInterface {",
" Set<String> set();",
"",
" // BUG: Diagnostic contains:",
" SortedSet<String> sortedSet();",
"",
" @Value.NaturalOrder",
" SortedSet<String> sortedSet2();",
" }",
"",
" @Value.Modifiable",
" interface ModifiableInterfaceWithDefaults {",
" @Value.Default",
" default Set<Integer> set() {",
" return new TreeSet<>();",
" }",
"",
" @Value.Default",
" // BUG: Diagnostic contains:",
" default NavigableSet<Integer> navigableSet() {",
" return new TreeSet<>();",
" }",
"",
" @Value.Default",
" @Value.ReverseOrder",
" default NavigableSet<Integer> navigableSet2() {",
" return new TreeSet<>();",
" }",
"",
" default NavigableSet<Integer> nonPropertyNavigableSet() {",
" return new TreeSet<>();",
" }",
" }",
"",
" interface NonImmutablesInterface {",
" SortedSet<String> sortedSet();",
" }",
"",
" @Value.Immutable",
" abstract class AbstractImmutableWithDefaults {",
" @Value.Default",
" ImmutableSet<Integer> immutableSet() {",
" return ImmutableSet.of();",
" }",
"",
" @Value.Default",
" // BUG: Diagnostic contains:",
" ImmutableSortedSet<String> immutableSortedSet() {",
" return ImmutableSortedSet.of();",
" }",
"",
" @Value.Default",
" @Value.NaturalOrder",
" ImmutableSortedSet<String> immutableSortedSet2() {",
" return ImmutableSortedSet.of();",
" }",
"",
" ImmutableSortedSet<String> nonPropertyImmutableSortedSet() {",
" return ImmutableSortedSet.of();",
" }",
" }",
"",
" @Value.Modifiable",
" abstract class AbstractModifiable {",
" abstract ImmutableSet<Integer> immutableSet();",
"",
" // BUG: Diagnostic contains:",
" abstract ContiguousSet<Integer> contiguousSet();",
"",
" @Value.ReverseOrder",
" abstract ContiguousSet<Integer> contiguousSet2();",
" }",
"",
" abstract class AbstractNonImmutables {",
" abstract SortedSet<Integer> sortedSet();",
" }",
"}")
"""
import com.google.common.collect.ContiguousSet;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import java.util.NavigableSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.immutables.value.Value;
interface A {
@Value.Immutable
interface ImmutableInterface {
Set<String> set();
// BUG: Diagnostic contains:
SortedSet<String> sortedSet();
@Value.NaturalOrder
SortedSet<String> sortedSet2();
}
@Value.Modifiable
interface ModifiableInterfaceWithDefaults {
@Value.Default
default Set<Integer> set() {
return new TreeSet<>();
}
@Value.Default
// BUG: Diagnostic contains:
default NavigableSet<Integer> navigableSet() {
return new TreeSet<>();
}
@Value.Default
@Value.ReverseOrder
default NavigableSet<Integer> navigableSet2() {
return new TreeSet<>();
}
default NavigableSet<Integer> nonPropertyNavigableSet() {
return new TreeSet<>();
}
}
interface NonImmutablesInterface {
SortedSet<String> sortedSet();
}
@Value.Immutable
abstract class AbstractImmutableWithDefaults {
@Value.Default
ImmutableSet<Integer> immutableSet() {
return ImmutableSet.of();
}
@Value.Default
// BUG: Diagnostic contains:
ImmutableSortedSet<String> immutableSortedSet() {
return ImmutableSortedSet.of();
}
@Value.Default
@Value.NaturalOrder
ImmutableSortedSet<String> immutableSortedSet2() {
return ImmutableSortedSet.of();
}
ImmutableSortedSet<String> nonPropertyImmutableSortedSet() {
return ImmutableSortedSet.of();
}
}
@Value.Modifiable
abstract class AbstractModifiable {
abstract ImmutableSet<Integer> immutableSet();
// BUG: Diagnostic contains:
abstract ContiguousSet<Integer> contiguousSet();
@Value.ReverseOrder
abstract ContiguousSet<Integer> contiguousSet2();
}
abstract class AbstractNonImmutables {
abstract SortedSet<Integer> sortedSet();
}
}
""")
.doTest();
}
@@ -107,36 +109,40 @@ final class ImmutablesSortedSetComparatorTest {
BugCheckerRefactoringTestHelper.newInstance(ImmutablesSortedSetComparator.class, getClass())
.addInputLines(
"A.java",
"import com.google.common.collect.ImmutableSortedSet;",
"import java.util.SortedSet;",
"import org.immutables.value.Value;",
"",
"@Value.Immutable",
"abstract class A {",
" abstract ImmutableSortedSet<String> sortedSet();",
"",
" @Value.Modifiable",
" interface B {",
" SortedSet<String> sortedSet();",
" }",
"}")
"""
import com.google.common.collect.ImmutableSortedSet;
import java.util.SortedSet;
import org.immutables.value.Value;
@Value.Immutable
abstract class A {
abstract ImmutableSortedSet<String> sortedSet();
@Value.Modifiable
interface B {
SortedSet<String> sortedSet();
}
}
""")
.addOutputLines(
"A.java",
"import com.google.common.collect.ImmutableSortedSet;",
"import java.util.SortedSet;",
"import org.immutables.value.Value;",
"",
"@Value.Immutable",
"abstract class A {",
" @Value.NaturalOrder",
" abstract ImmutableSortedSet<String> sortedSet();",
"",
" @Value.Modifiable",
" interface B {",
" @Value.NaturalOrder",
" SortedSet<String> sortedSet();",
" }",
"}")
"""
import com.google.common.collect.ImmutableSortedSet;
import java.util.SortedSet;
import org.immutables.value.Value;
@Value.Immutable
abstract class A {
@Value.NaturalOrder
abstract ImmutableSortedSet<String> sortedSet();
@Value.Modifiable
interface B {
@Value.NaturalOrder
SortedSet<String> sortedSet();
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
@@ -145,33 +151,37 @@ final class ImmutablesSortedSetComparatorTest {
BugCheckerRefactoringTestHelper.newInstance(ImmutablesSortedSetComparator.class, getClass())
.addInputLines(
"MySpringService.java",
"import com.google.common.collect.ImmutableSortedSet;",
"import org.springframework.beans.factory.annotation.Value;",
"",
"class MySpringService {",
" MySpringService(@Value(\"${someProperty}\") String prop) {}",
" ;",
"",
" @org.immutables.value.Value.Immutable",
" interface A {",
" ImmutableSortedSet<String> sortedSet();",
" }",
"}")
"""
import com.google.common.collect.ImmutableSortedSet;
import org.springframework.beans.factory.annotation.Value;
class MySpringService {
MySpringService(@Value("${someProperty}") String prop) {}
;
@org.immutables.value.Value.Immutable
interface A {
ImmutableSortedSet<String> sortedSet();
}
}
""")
.addOutputLines(
"MySpringService.java",
"import com.google.common.collect.ImmutableSortedSet;",
"import org.springframework.beans.factory.annotation.Value;",
"",
"class MySpringService {",
" MySpringService(@Value(\"${someProperty}\") String prop) {}",
" ;",
"",
" @org.immutables.value.Value.Immutable",
" interface A {",
" @org.immutables.value.Value.NaturalOrder",
" ImmutableSortedSet<String> sortedSet();",
" }",
"}")
"""
import com.google.common.collect.ImmutableSortedSet;
import org.springframework.beans.factory.annotation.Value;
class MySpringService {
MySpringService(@Value("${someProperty}") String prop) {}
;
@org.immutables.value.Value.Immutable
interface A {
@org.immutables.value.Value.NaturalOrder
ImmutableSortedSet<String> sortedSet();
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,32 +11,34 @@ final class IsInstanceLambdaUsageTest {
CompilationTestHelper.newInstance(IsInstanceLambdaUsage.class, getClass())
.addSourceLines(
"A.java",
"import java.util.stream.Stream;",
"import reactor.core.publisher.Flux;",
"",
"class A {",
" void m() {",
" Integer localVariable = 0;",
"",
" Stream.of(0).map(i -> i);",
" Stream.of(1).map(i -> i + 1);",
" Stream.of(2).filter(Integer.class::isInstance);",
" Stream.of(3).filter(i -> i.getClass() instanceof Class);",
" Stream.of(4).filter(i -> localVariable instanceof Integer);",
" // XXX: Ideally this case is also flagged. Pick this up in the context of merging the",
" // `IsInstanceLambdaUsage` and `MethodReferenceUsage` checks, or introduce a separate check that",
" // simplifies unnecessary block lambda expressions.",
" Stream.of(5)",
" .filter(",
" i -> {",
" return i instanceof Integer;",
" });",
" Flux.just(6, \"foo\").distinctUntilChanged(v -> v, (a, b) -> a instanceof Integer);",
"",
" // BUG: Diagnostic contains:",
" Stream.of(7).filter(i -> i instanceof Integer);",
" }",
"}")
"""
import java.util.stream.Stream;
import reactor.core.publisher.Flux;
class A {
void m() {
Integer localVariable = 0;
Stream.of(0).map(i -> i);
Stream.of(1).map(i -> i + 1);
Stream.of(2).filter(Integer.class::isInstance);
Stream.of(3).filter(i -> i.getClass() instanceof Class);
Stream.of(4).filter(i -> localVariable instanceof Integer);
// XXX: Ideally this case is also flagged. Pick this up in the context of merging the
// `IsInstanceLambdaUsage` and `MethodReferenceUsage` checks, or introduce a separate check that
// simplifies unnecessary block lambda expressions.
Stream.of(5)
.filter(
i -> {
return i instanceof Integer;
});
Flux.just(6, "foo").distinctUntilChanged(v -> v, (a, b) -> a instanceof Integer);
// BUG: Diagnostic contains:
Stream.of(7).filter(i -> i instanceof Integer);
}
}
""")
.doTest();
}
@@ -45,22 +47,26 @@ final class IsInstanceLambdaUsageTest {
BugCheckerRefactoringTestHelper.newInstance(IsInstanceLambdaUsage.class, getClass())
.addInputLines(
"A.java",
"import java.util.stream.Stream;",
"",
"class A {",
" void m() {",
" Stream.of(1).filter(i -> i instanceof Integer);",
" }",
"}")
"""
import java.util.stream.Stream;
class A {
void m() {
Stream.of(1).filter(i -> i instanceof Integer);
}
}
""")
.addOutputLines(
"A.java",
"import java.util.stream.Stream;",
"",
"class A {",
" void m() {",
" Stream.of(1).filter(Integer.class::isInstance);",
" }",
"}")
"""
import java.util.stream.Stream;
class A {
void m() {
Stream.of(1).filter(Integer.class::isInstance);
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,83 +11,85 @@ final class JUnitClassModifiersTest {
CompilationTestHelper.newInstance(JUnitClassModifiers.class, getClass())
.addSourceLines(
"Container.java",
"import org.junit.jupiter.api.Test;",
"import org.junit.jupiter.params.ParameterizedTest;",
"import org.springframework.boot.test.context.TestConfiguration;",
"import org.springframework.context.annotation.Configuration;",
"",
"class Container {",
" final class FinalAndPackagePrivate {",
" @Test",
" void foo() {}",
" }",
"",
" final class FinalAndPackagePrivateWithCustomTestMethod {",
" @ParameterizedTest",
" void foo() {}",
" }",
"",
" public abstract class Abstract {",
" @Test",
" void foo() {}",
" }",
"",
" @Configuration",
" class WithConfigurationAnnotation {",
" @Test",
" void foo() {}",
" }",
"",
" @TestConfiguration",
" class WithConfigurationMetaAnnotation {",
" @Test",
" void foo() {}",
" }",
"",
" // BUG: Diagnostic contains:",
" private final class Private {",
" @Test",
" void foo() {}",
" }",
"",
" // BUG: Diagnostic contains:",
" protected final class Protected {",
" @Test",
" void foo() {}",
" }",
"",
" // BUG: Diagnostic contains:",
" public final class Public {",
" @Test",
" void foo() {}",
" }",
"",
" // BUG: Diagnostic contains:",
" class NonFinal {",
" @Test",
" void foo() {}",
" }",
"",
" // BUG: Diagnostic contains:",
" class NonFinalWithCustomTestMethod {",
" @ParameterizedTest",
" void foo() {}",
" }",
"",
" @Configuration",
" // BUG: Diagnostic contains:",
" public class PublicWithConfigurationAnnotation {",
" @Test",
" void foo() {}",
" }",
"",
" @TestConfiguration",
" // BUG: Diagnostic contains:",
" protected class ProtectedWithConfigurationMetaAnnotation {",
" @Test",
" void foo() {}",
" }",
"}")
"""
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Configuration;
class Container {
final class FinalAndPackagePrivate {
@Test
void foo() {}
}
final class FinalAndPackagePrivateWithCustomTestMethod {
@ParameterizedTest
void foo() {}
}
public abstract class Abstract {
@Test
void foo() {}
}
@Configuration
class WithConfigurationAnnotation {
@Test
void foo() {}
}
@TestConfiguration
class WithConfigurationMetaAnnotation {
@Test
void foo() {}
}
// BUG: Diagnostic contains:
private final class Private {
@Test
void foo() {}
}
// BUG: Diagnostic contains:
protected final class Protected {
@Test
void foo() {}
}
// BUG: Diagnostic contains:
public final class Public {
@Test
void foo() {}
}
// BUG: Diagnostic contains:
class NonFinal {
@Test
void foo() {}
}
// BUG: Diagnostic contains:
class NonFinalWithCustomTestMethod {
@ParameterizedTest
void foo() {}
}
@Configuration
// BUG: Diagnostic contains:
public class PublicWithConfigurationAnnotation {
@Test
void foo() {}
}
@TestConfiguration
// BUG: Diagnostic contains:
protected class ProtectedWithConfigurationMetaAnnotation {
@Test
void foo() {}
}
}
""")
.doTest();
}
@@ -96,34 +98,38 @@ final class JUnitClassModifiersTest {
BugCheckerRefactoringTestHelper.newInstance(JUnitClassModifiers.class, getClass())
.addInputLines(
"A.java",
"import org.junit.jupiter.api.Test;",
"import org.springframework.context.annotation.Configuration;",
"",
"public class A {",
" @Test",
" void foo() {}",
"",
" @Configuration",
" private static class B {",
" @Test",
" void bar() {}",
" }",
"}")
"""
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Configuration;
public class A {
@Test
void foo() {}
@Configuration
private static class B {
@Test
void bar() {}
}
}
""")
.addOutputLines(
"A.java",
"import org.junit.jupiter.api.Test;",
"import org.springframework.context.annotation.Configuration;",
"",
"final class A {",
" @Test",
" void foo() {}",
"",
" @Configuration",
" static class B {",
" @Test",
" void bar() {}",
" }",
"}")
"""
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Configuration;
final class A {
@Test
void foo() {}
@Configuration
static class B {
@Test
void bar() {}
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,330 +11,338 @@ final class JUnitMethodDeclarationTest {
CompilationTestHelper.newInstance(JUnitMethodDeclaration.class, getClass())
.addSourceLines(
"A.java",
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
"",
"import org.junit.jupiter.api.AfterAll;",
"import org.junit.jupiter.api.AfterEach;",
"import org.junit.jupiter.api.BeforeAll;",
"import org.junit.jupiter.api.BeforeEach;",
"import org.junit.jupiter.api.Test;",
"import org.junit.jupiter.params.ParameterizedTest;",
"",
"class A {",
" {",
" arguments();",
" }",
"",
" @BeforeAll",
" void setUp1() {}",
"",
" @BeforeAll",
" // BUG: Diagnostic contains:",
" public void setUp2() {}",
"",
" @BeforeAll",
" // BUG: Diagnostic contains:",
" protected void setUp3() {}",
"",
" @BeforeAll",
" // BUG: Diagnostic contains:",
" private void setUp4() {}",
"",
" @BeforeEach",
" void setup5() {}",
"",
" @BeforeEach",
" // BUG: Diagnostic contains:",
" public void setUp6() {}",
"",
" @BeforeEach",
" // BUG: Diagnostic contains:",
" protected void setUp7() {}",
"",
" @BeforeEach",
" // BUG: Diagnostic contains:",
" private void setUp8() {}",
"",
" @AfterEach",
" void tearDown1() {}",
"",
" @AfterEach",
" // BUG: Diagnostic contains:",
" public void tearDown2() {}",
"",
" @AfterEach",
" // BUG: Diagnostic contains:",
" protected void tearDown3() {}",
"",
" @AfterEach",
" // BUG: Diagnostic contains:",
" private void tearDown4() {}",
"",
" @AfterAll",
" void tearDown5() {}",
"",
" @AfterAll",
" // BUG: Diagnostic contains:",
" public void tearDown6() {}",
"",
" @AfterAll",
" // BUG: Diagnostic contains:",
" protected void tearDown7() {}",
"",
" @AfterAll",
" // BUG: Diagnostic contains:",
" private void tearDown8() {}",
"",
" @Test",
" void test() {}",
"",
" @Test",
" void method1() {}",
"",
" @Test",
" // BUG: Diagnostic contains:",
" void testMethod2() {}",
"",
" @Test",
" // BUG: Diagnostic contains:",
" public void method3() {}",
"",
" @Test",
" // BUG: Diagnostic contains:",
" protected void method4() {}",
"",
" @Test",
" // BUG: Diagnostic contains:",
" private void method5() {}",
"",
" @ParameterizedTest",
" void method6() {}",
"",
" @ParameterizedTest",
" // BUG: Diagnostic contains:",
" void testMethod7() {}",
"",
" @ParameterizedTest",
" // BUG: Diagnostic contains:",
" public void method8() {}",
"",
" @ParameterizedTest",
" // BUG: Diagnostic contains:",
" protected void method9() {}",
"",
" @ParameterizedTest",
" // BUG: Diagnostic contains:",
" private void method10() {}",
"",
" @BeforeEach",
" @BeforeAll",
" @AfterEach",
" @AfterAll",
" void testNonTestMethod1() {}",
"",
" public void testNonTestMethod2() {}",
"",
" protected void testNonTestMethod3() {}",
"",
" private void testNonTestMethod4() {}",
"",
" @Test",
" void test5() {}",
"",
" @Test",
" // BUG: Diagnostic contains: (but note that a method named `toString` is already defined in this",
" // class or a supertype)",
" void testToString() {}",
"",
" @Test",
" // BUG: Diagnostic contains: (but note that a method named `overload` is already defined in this",
" // class or a supertype)",
" void testOverload() {}",
"",
" void overload() {}",
"",
" @Test",
" // BUG: Diagnostic contains: (but note that `arguments` is already statically imported)",
" void testArguments() {}",
"",
" @Test",
" // BUG: Diagnostic contains: (but note that `public` is not a valid identifier)",
" void testPublic() {}",
"",
" @Test",
" // BUG: Diagnostic contains: (but note that `null` is not a valid identifier)",
" void testNull() {}",
"",
" @Test",
" // BUG: Diagnostic contains:",
" void testRecord() {}",
"",
" @Test",
" // BUG: Diagnostic contains:",
" void testMethodThatIsOverriddenWithoutOverrideAnnotation() {}",
"}")
"""
import static org.junit.jupiter.params.provider.Arguments.*;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
class A {
{
arguments();
}
@BeforeAll
void setUp1() {}
@BeforeAll
// BUG: Diagnostic contains:
public void setUp2() {}
@BeforeAll
// BUG: Diagnostic contains:
protected void setUp3() {}
@BeforeAll
// BUG: Diagnostic contains:
private void setUp4() {}
@BeforeEach
void setup5() {}
@BeforeEach
// BUG: Diagnostic contains:
public void setUp6() {}
@BeforeEach
// BUG: Diagnostic contains:
protected void setUp7() {}
@BeforeEach
// BUG: Diagnostic contains:
private void setUp8() {}
@AfterEach
void tearDown1() {}
@AfterEach
// BUG: Diagnostic contains:
public void tearDown2() {}
@AfterEach
// BUG: Diagnostic contains:
protected void tearDown3() {}
@AfterEach
// BUG: Diagnostic contains:
private void tearDown4() {}
@AfterAll
void tearDown5() {}
@AfterAll
// BUG: Diagnostic contains:
public void tearDown6() {}
@AfterAll
// BUG: Diagnostic contains:
protected void tearDown7() {}
@AfterAll
// BUG: Diagnostic contains:
private void tearDown8() {}
@Test
void test() {}
@Test
void method1() {}
@Test
// BUG: Diagnostic contains:
void testMethod2() {}
@Test
// BUG: Diagnostic contains:
public void method3() {}
@Test
// BUG: Diagnostic contains:
protected void method4() {}
@Test
// BUG: Diagnostic contains:
private void method5() {}
@ParameterizedTest
void method6() {}
@ParameterizedTest
// BUG: Diagnostic contains:
void testMethod7() {}
@ParameterizedTest
// BUG: Diagnostic contains:
public void method8() {}
@ParameterizedTest
// BUG: Diagnostic contains:
protected void method9() {}
@ParameterizedTest
// BUG: Diagnostic contains:
private void method10() {}
@BeforeEach
@BeforeAll
@AfterEach
@AfterAll
void testNonTestMethod1() {}
public void testNonTestMethod2() {}
protected void testNonTestMethod3() {}
private void testNonTestMethod4() {}
@Test
void test5() {}
@Test
// BUG: Diagnostic contains: (but note that a method named `toString` is already defined in this
// class or a supertype)
void testToString() {}
@Test
// BUG: Diagnostic contains: (but note that a method named `overload` is already defined in this
// class or a supertype)
void testOverload() {}
void overload() {}
@Test
// 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)
void testPublic() {}
@Test
// BUG: Diagnostic contains: (but note that `null` is not a valid identifier)
void testNull() {}
@Test
// BUG: Diagnostic contains:
void testRecord() {}
@Test
// BUG: Diagnostic contains:
void testMethodThatIsOverriddenWithoutOverrideAnnotation() {}
}
""")
.addSourceLines(
"B.java",
"import org.junit.jupiter.api.AfterAll;",
"import org.junit.jupiter.api.AfterEach;",
"import org.junit.jupiter.api.BeforeAll;",
"import org.junit.jupiter.api.BeforeEach;",
"import org.junit.jupiter.api.Test;",
"import org.junit.jupiter.params.ParameterizedTest;",
"",
"class B extends A {",
" @Override",
" @BeforeAll",
" void setUp1() {}",
"",
" @Override",
" @BeforeAll",
" public void setUp2() {}",
"",
" @Override",
" @BeforeAll",
" protected void setUp3() {}",
"",
" @Override",
" @BeforeEach",
" void setup5() {}",
"",
" @Override",
" @BeforeEach",
" public void setUp6() {}",
"",
" @Override",
" @BeforeEach",
" protected void setUp7() {}",
"",
" @Override",
" @AfterEach",
" void tearDown1() {}",
"",
" @Override",
" @AfterEach",
" public void tearDown2() {}",
"",
" @Override",
" @AfterEach",
" protected void tearDown3() {}",
"",
" @Override",
" @AfterAll",
" void tearDown5() {}",
"",
" @Override",
" @AfterAll",
" public void tearDown6() {}",
"",
" @Override",
" @AfterAll",
" protected void tearDown7() {}",
"",
" @Override",
" @Test",
" void test() {}",
"",
" @Override",
" @Test",
" void method1() {}",
"",
" @Override",
" @Test",
" void testMethod2() {}",
"",
" @Override",
" @Test",
" public void method3() {}",
"",
" @Override",
" @Test",
" protected void method4() {}",
"",
" @Override",
" @ParameterizedTest",
" void method6() {}",
"",
" @Override",
" @ParameterizedTest",
" void testMethod7() {}",
"",
" @Override",
" @ParameterizedTest",
" public void method8() {}",
"",
" @Override",
" @ParameterizedTest",
" protected void method9() {}",
"",
" @Override",
" @BeforeEach",
" @BeforeAll",
" @AfterEach",
" @AfterAll",
" void testNonTestMethod1() {}",
"",
" @Override",
" public void testNonTestMethod2() {}",
"",
" @Override",
" protected void testNonTestMethod3() {}",
"",
" @Override",
" @Test",
" void test5() {}",
"",
" @Override",
" @Test",
" void testToString() {}",
"",
" @Override",
" @Test",
" void testOverload() {}",
"",
" @Override",
" void overload() {}",
"",
" @Override",
" @Test",
" void testArguments() {}",
"",
" @Override",
" @Test",
" void testPublic() {}",
"",
" @Override",
" @Test",
" void testNull() {}",
"",
" @Override",
" @Test",
" void testRecord() {}",
"",
" @Test",
" void testMethodThatIsOverriddenWithoutOverrideAnnotation() {}",
"}")
"""
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
class B extends A {
@Override
@BeforeAll
void setUp1() {}
@Override
@BeforeAll
public void setUp2() {}
@Override
@BeforeAll
protected void setUp3() {}
@Override
@BeforeEach
void setup5() {}
@Override
@BeforeEach
public void setUp6() {}
@Override
@BeforeEach
protected void setUp7() {}
@Override
@AfterEach
void tearDown1() {}
@Override
@AfterEach
public void tearDown2() {}
@Override
@AfterEach
protected void tearDown3() {}
@Override
@AfterAll
void tearDown5() {}
@Override
@AfterAll
public void tearDown6() {}
@Override
@AfterAll
protected void tearDown7() {}
@Override
@Test
void test() {}
@Override
@Test
void method1() {}
@Override
@Test
void testMethod2() {}
@Override
@Test
public void method3() {}
@Override
@Test
protected void method4() {}
@Override
@ParameterizedTest
void method6() {}
@Override
@ParameterizedTest
void testMethod7() {}
@Override
@ParameterizedTest
public void method8() {}
@Override
@ParameterizedTest
protected void method9() {}
@Override
@BeforeEach
@BeforeAll
@AfterEach
@AfterAll
void testNonTestMethod1() {}
@Override
public void testNonTestMethod2() {}
@Override
protected void testNonTestMethod3() {}
@Override
@Test
void test5() {}
@Override
@Test
void testToString() {}
@Override
@Test
void testOverload() {}
@Override
void overload() {}
@Override
@Test
void testArguments() {}
@Override
@Test
void testPublic() {}
@Override
@Test
void testNull() {}
@Override
@Test
void testRecord() {}
@Test
void testMethodThatIsOverriddenWithoutOverrideAnnotation() {}
}
""")
.addSourceLines(
"C.java",
"import org.junit.jupiter.api.AfterAll;",
"import org.junit.jupiter.api.BeforeAll;",
"import org.junit.jupiter.api.Test;",
"",
"abstract class C {",
" @BeforeAll",
" public void setUp() {}",
"",
" @Test",
" void testMethod1() {}",
"",
" @AfterAll",
" // BUG: Diagnostic contains:",
" private void tearDown() {}",
"",
" @Test",
" // BUG: Diagnostic contains:",
" final void testMethod2() {}",
"}")
"""
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
abstract class C {
@BeforeAll
public void setUp() {}
@Test
void testMethod1() {}
@AfterAll
// BUG: Diagnostic contains:
private void tearDown() {}
@Test
// BUG: Diagnostic contains:
final void testMethod2() {}
}
""")
.doTest();
}
@@ -343,126 +351,130 @@ final class JUnitMethodDeclarationTest {
BugCheckerRefactoringTestHelper.newInstance(JUnitMethodDeclaration.class, getClass())
.addInputLines(
"A.java",
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
"",
"import org.junit.jupiter.api.AfterAll;",
"import org.junit.jupiter.api.AfterEach;",
"import org.junit.jupiter.api.BeforeAll;",
"import org.junit.jupiter.api.BeforeEach;",
"import org.junit.jupiter.api.RepeatedTest;",
"import org.junit.jupiter.api.Test;",
"import org.junit.jupiter.params.ParameterizedTest;",
"",
"class A {",
" {",
" arguments();",
" }",
"",
" @BeforeAll",
" public void setUp1() {}",
"",
" @BeforeEach",
" protected void setUp2() {}",
"",
" @AfterEach",
" private void setUp3() {}",
"",
" @AfterAll",
" private void setUp4() {}",
"",
" @Test",
" void testFoo() {}",
"",
" @ParameterizedTest",
" void testBar() {}",
"",
" @Test",
" public void baz() {}",
"",
" @RepeatedTest(2)",
" private void qux() {}",
"",
" @ParameterizedTest",
" protected void quux() {}",
"",
" @Test",
" public void testToString() {}",
"",
" @Test",
" public void testOverload() {}",
"",
" void overload() {}",
"",
" @Test",
" protected void testArguments() {}",
"",
" @Test",
" private void testClass() {}",
"",
" @Test",
" private void testTrue() {}",
"}")
"""
import static org.junit.jupiter.params.provider.Arguments.arguments;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
class A {
{
arguments();
}
@BeforeAll
public void setUp1() {}
@BeforeEach
protected void setUp2() {}
@AfterEach
private void setUp3() {}
@AfterAll
private void setUp4() {}
@Test
void testFoo() {}
@ParameterizedTest
void testBar() {}
@Test
public void baz() {}
@RepeatedTest(2)
private void qux() {}
@ParameterizedTest
protected void quux() {}
@Test
public void testToString() {}
@Test
public void testOverload() {}
void overload() {}
@Test
protected void testArguments() {}
@Test
private void testClass() {}
@Test
private void testTrue() {}
}
""")
.addOutputLines(
"A.java",
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
"",
"import org.junit.jupiter.api.AfterAll;",
"import org.junit.jupiter.api.AfterEach;",
"import org.junit.jupiter.api.BeforeAll;",
"import org.junit.jupiter.api.BeforeEach;",
"import org.junit.jupiter.api.RepeatedTest;",
"import org.junit.jupiter.api.Test;",
"import org.junit.jupiter.params.ParameterizedTest;",
"",
"class A {",
" {",
" arguments();",
" }",
"",
" @BeforeAll",
" void setUp1() {}",
"",
" @BeforeEach",
" void setUp2() {}",
"",
" @AfterEach",
" void setUp3() {}",
"",
" @AfterAll",
" void setUp4() {}",
"",
" @Test",
" void foo() {}",
"",
" @ParameterizedTest",
" void bar() {}",
"",
" @Test",
" void baz() {}",
"",
" @RepeatedTest(2)",
" void qux() {}",
"",
" @ParameterizedTest",
" void quux() {}",
"",
" @Test",
" void testToString() {}",
"",
" @Test",
" void testOverload() {}",
"",
" void overload() {}",
"",
" @Test",
" void testArguments() {}",
"",
" @Test",
" void testClass() {}",
"",
" @Test",
" void testTrue() {}",
"}")
"""
import static org.junit.jupiter.params.provider.Arguments.arguments;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
class A {
{
arguments();
}
@BeforeAll
void setUp1() {}
@BeforeEach
void setUp2() {}
@AfterEach
void setUp3() {}
@AfterAll
void setUp4() {}
@Test
void foo() {}
@ParameterizedTest
void bar() {}
@Test
void baz() {}
@RepeatedTest(2)
void qux() {}
@ParameterizedTest
void quux() {}
@Test
void testToString() {}
@Test
void testOverload() {}
void overload() {}
@Test
void testArguments() {}
@Test
void testClass() {}
@Test
void testTrue() {}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,25 +11,27 @@ final class JUnitNullaryParameterizedTestDeclarationTest {
CompilationTestHelper.newInstance(JUnitNullaryParameterizedTestDeclaration.class, getClass())
.addSourceLines(
"A.java",
"import org.junit.jupiter.api.Test;",
"import org.junit.jupiter.params.ParameterizedTest;",
"import org.junit.jupiter.params.provider.ValueSource;",
"",
"class A {",
" void nonTest() {}",
"",
" @Test",
" void nonParameterizedTest() {}",
"",
" @ParameterizedTest",
" @ValueSource(ints = {0, 1})",
" void goodParameterizedTest(int someInt) {}",
"",
" @ParameterizedTest",
" @ValueSource(ints = {0, 1})",
" // BUG: Diagnostic contains:",
" void nullaryParameterizedTest() {}",
"}")
"""
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
class A {
void nonTest() {}
@Test
void nonParameterizedTest() {}
@ParameterizedTest
@ValueSource(ints = {0, 1})
void goodParameterizedTest(int someInt) {}
@ParameterizedTest
@ValueSource(ints = {0, 1})
// BUG: Diagnostic contains:
void nullaryParameterizedTest() {}
}
""")
.doTest();
}
@@ -39,117 +41,125 @@ final class JUnitNullaryParameterizedTestDeclarationTest {
JUnitNullaryParameterizedTestDeclaration.class, getClass())
.addInputLines(
"A.java",
"import org.junit.jupiter.params.ParameterizedTest;",
"import org.junit.jupiter.params.provider.ArgumentsProvider;",
"import org.junit.jupiter.params.provider.ArgumentsSource;",
"import org.junit.jupiter.params.provider.ArgumentsSources;",
"import org.junit.jupiter.params.provider.MethodSource;",
"import org.junit.jupiter.params.provider.ValueSource;",
"",
"class A {",
" @ParameterizedTest",
" void withoutArgumentSource() {}",
"",
" @ParameterizedTest",
" @ArgumentsSource(ArgumentsProvider.class)",
" void withCustomArgumentSource() {}",
"",
" @ParameterizedTest",
" @ArgumentsSources({",
" @ArgumentsSource(ArgumentsProvider.class),",
" @ArgumentsSource(ArgumentsProvider.class)",
" })",
" void withCustomerArgumentSources() {}",
"",
" /** Foo. */",
" @ParameterizedTest",
" @ValueSource(ints = {0, 1})",
" void withValueSourceAndJavadoc() {}",
"",
" @ParameterizedTest",
" @MethodSource(\"nonexistentMethod\")",
" @SuppressWarnings(\"foo\")",
" void withMethodSourceAndUnrelatedAnnotation() {}",
"",
" @org.junit.jupiter.params.ParameterizedTest",
" @ArgumentsSource(ArgumentsProvider.class)",
" @ValueSource(ints = {0, 1})",
" @MethodSource(\"nonexistentMethod\")",
" void withMultipleArgumentSourcesAndFullyQualifiedImport() {}",
"",
" class NestedWithTestAnnotationFirst {",
" @ParameterizedTest",
" @ValueSource(ints = {0, 1})",
" void withValueSource() {}",
" }",
"",
" class NestedWithTestAnnotationSecond {",
" @ValueSource(ints = {0, 1})",
" @ParameterizedTest",
" void withValueSource() {}",
" }",
"}")
"""
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.provider.ArgumentsSource;
import org.junit.jupiter.params.provider.ArgumentsSources;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
class A {
@ParameterizedTest
void withoutArgumentSource() {}
@ParameterizedTest
@ArgumentsSource(ArgumentsProvider.class)
void withCustomArgumentSource() {}
@ParameterizedTest
@ArgumentsSources({
@ArgumentsSource(ArgumentsProvider.class),
@ArgumentsSource(ArgumentsProvider.class)
})
void withCustomerArgumentSources() {}
/** Foo. */
@ParameterizedTest
@ValueSource(ints = {0, 1})
void withValueSourceAndJavadoc() {}
@ParameterizedTest
@MethodSource("nonexistentMethod")
@SuppressWarnings("foo")
void withMethodSourceAndUnrelatedAnnotation() {}
@org.junit.jupiter.params.ParameterizedTest
@ArgumentsSource(ArgumentsProvider.class)
@ValueSource(ints = {0, 1})
@MethodSource("nonexistentMethod")
void withMultipleArgumentSourcesAndFullyQualifiedImport() {}
class NestedWithTestAnnotationFirst {
@ParameterizedTest
@ValueSource(ints = {0, 1})
void withValueSource() {}
}
class NestedWithTestAnnotationSecond {
@ValueSource(ints = {0, 1})
@ParameterizedTest
void withValueSource() {}
}
}
""")
.addOutputLines(
"A.java",
"import org.junit.jupiter.api.Test;",
"import org.junit.jupiter.params.ParameterizedTest;",
"import org.junit.jupiter.params.provider.ArgumentsProvider;",
"import org.junit.jupiter.params.provider.ArgumentsSource;",
"import org.junit.jupiter.params.provider.ArgumentsSources;",
"import org.junit.jupiter.params.provider.MethodSource;",
"import org.junit.jupiter.params.provider.ValueSource;",
"",
"class A {",
" @Test",
" void withoutArgumentSource() {}",
"",
" @Test",
" void withCustomArgumentSource() {}",
"",
" @Test",
" void withCustomerArgumentSources() {}",
"",
" /** Foo. */",
" @Test",
" void withValueSourceAndJavadoc() {}",
"",
" @Test",
" @SuppressWarnings(\"foo\")",
" void withMethodSourceAndUnrelatedAnnotation() {}",
"",
" @Test",
" void withMultipleArgumentSourcesAndFullyQualifiedImport() {}",
"",
" class NestedWithTestAnnotationFirst {",
" @Test",
" void withValueSource() {}",
" }",
"",
" class NestedWithTestAnnotationSecond {",
" @Test",
" void withValueSource() {}",
" }",
"}")
"""
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.provider.ArgumentsSource;
import org.junit.jupiter.params.provider.ArgumentsSources;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
class A {
@Test
void withoutArgumentSource() {}
@Test
void withCustomArgumentSource() {}
@Test
void withCustomerArgumentSources() {}
/** Foo. */
@Test
void withValueSourceAndJavadoc() {}
@Test
@SuppressWarnings("foo")
void withMethodSourceAndUnrelatedAnnotation() {}
@Test
void withMultipleArgumentSourcesAndFullyQualifiedImport() {}
class NestedWithTestAnnotationFirst {
@Test
void withValueSource() {}
}
class NestedWithTestAnnotationSecond {
@Test
void withValueSource() {}
}
}
""")
.addInputLines(
"B.java",
"import org.junit.jupiter.params.ParameterizedTest;",
"",
"class B {",
" @ParameterizedTest",
" void scopeInWhichIdentifierTestIsAlreadyDeclared() {}",
"",
" class Test {}",
"}")
"""
import org.junit.jupiter.params.ParameterizedTest;
class B {
@ParameterizedTest
void scopeInWhichIdentifierTestIsAlreadyDeclared() {}
class Test {}
}
""")
.addOutputLines(
"B.java",
"import org.junit.jupiter.params.ParameterizedTest;",
"",
"class B {",
" @org.junit.jupiter.api.Test",
" void scopeInWhichIdentifierTestIsAlreadyDeclared() {}",
"",
" class Test {}",
"}")
"""
import org.junit.jupiter.params.ParameterizedTest;
class B {
@org.junit.jupiter.api.Test
void scopeInWhichIdentifierTestIsAlreadyDeclared() {}
class Test {}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,189 +11,191 @@ final class JUnitValueSourceTest {
CompilationTestHelper.newInstance(JUnitValueSource.class, getClass())
.addSourceLines(
"A.java",
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
"",
"import java.util.Optional;",
"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;",
"",
"class A {",
" private static Stream<Arguments> identificationTestCases() {",
" return Stream.of(arguments(1), Arguments.of(2));",
" }",
"",
" @ParameterizedTest",
" // BUG: Diagnostic contains:",
" @MethodSource(\"identificationTestCases\")",
" void identification(int foo) {}",
"",
" private static int[] identificationWithParensTestCases() {",
" return new int[] {1, 2};",
" }",
"",
" @ParameterizedTest",
" // BUG: Diagnostic contains:",
" @MethodSource(\"identificationWithParensTestCases()\")",
" void identificationWithParens(int foo) {}",
"",
" @ParameterizedTest",
" @MethodSource(\"valueFactoryMissingTestCases\")",
" void valueFactoryMissing(int foo) {}",
"",
" private static Stream<Arguments> multipleUsagesTestCases() {",
" return Stream.of(arguments(1), Arguments.of(2));",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"multipleUsagesTestCases\")",
" void multipleUsages1(int foo) {}",
"",
" @ParameterizedTest",
" @MethodSource(\"multipleUsagesTestCases()\")",
" void multipleUsages2(int bar) {}",
"",
" private static Stream<Arguments> valueFactoryRepeatedTestCases() {",
" return Stream.of(arguments(1), arguments(2));",
" }",
"",
" @ParameterizedTest",
" @MethodSource({\"valueFactoryRepeatedTestCases\", \"valueFactoryRepeatedTestCases\"})",
" void valueFactoryRepeated(int foo) {}",
"",
" private static Stream<Arguments> multipleParametersTestCases() {",
" return Stream.of(arguments(1, 2), arguments(3, 4));",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"multipleParametersTestCases\")",
" void multipleParameters(int first, int second) {}",
"",
" private static int[] arrayWithoutInitializersTestCases() {",
" return new int[1];",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"arrayWithoutInitializersTestCases\")",
" void arrayWithoutInitializers(int foo) {}",
"",
" private static Stream<Arguments> runtimeValueTestCases() {",
" int second = 2;",
" return Stream.of(arguments(1), arguments(second));",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"runtimeValueTestCases\")",
" void runtimeValue(int foo) {}",
"",
" private static Stream<Arguments> streamChainTestCases() {",
" return Stream.of(1, 2).map(Arguments::arguments);",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"streamChainTestCases\")",
" void streamChain(int number) {}",
"",
" private static Stream<Arguments> multipleReturnsTestCases() {",
" if (true) {",
" return Stream.of(arguments(1), arguments(2));",
" } else {",
" return Stream.of(arguments(3), arguments(4));",
" }",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"multipleReturnsTestCases\")",
" void multipleReturns(int number) {}",
"",
" private static Stream<Arguments> multipleFactoriesFooTestCases() {",
" return Stream.of(arguments(1));",
" }",
"",
" private static Stream<Arguments> multipleFactoriesBarTestCases() {",
" return Stream.of(arguments(1));",
" }",
"",
" @ParameterizedTest",
" @MethodSource({\"multipleFactoriesFooTestCases\", \"multipleFactoriesBarTestCases\"})",
" void multipleFactories(int i) {}",
"",
" private static Stream<Arguments> extraArgsTestCases() {",
" return Stream.of(arguments(1), arguments(1, 2));",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"extraArgsTestCases\")",
" void extraArgs(int... i) {}",
"",
" private static Stream<Arguments> localClassTestCases() {",
" class Foo {",
" Stream<Arguments> foo() {",
" return Stream.of(arguments(1), arguments(2));",
" }",
" }",
" return Stream.of(arguments(1), arguments(2));",
" }",
"",
" @ParameterizedTest",
" // BUG: Diagnostic contains:",
" @MethodSource(\"localClassTestCases\")",
" void localClass(int i) {}",
"",
" private static Stream<Arguments> lambdaReturnTestCases() {",
" int foo =",
" Optional.of(10)",
" .map(",
" i -> {",
" return i / 2;",
" })",
" .orElse(0);",
" return Stream.of(arguments(1), arguments(1));",
" }",
"",
" @ParameterizedTest",
" // BUG: Diagnostic contains:",
" @MethodSource(\"lambdaReturnTestCases\")",
" void lambdaReturn(int i) {}",
"",
" @ParameterizedTest",
" @MethodSource(\"tech.picnic.errorprone.Foo#fooTestCases\")",
" void staticMethodReference(int foo) {}",
"",
" private static Stream<Arguments> valueFactoryWithArgumentTestCases(int amount) {",
" return Stream.of(arguments(1), arguments(2));",
" }",
"",
" @ParameterizedTest",
" // BUG: Diagnostic contains:",
" @MethodSource(\"valueFactoryWithArgumentTestCases\")",
" void valueFactoryWithArgument(int foo) {}",
"",
" private static Arguments[] emptyArrayValueFactoryTestCases() {",
" return new Arguments[] {};",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"emptyArrayValueFactoryTestCases\")",
" void emptyArrayValueFactory(int foo) {}",
"",
" private static Stream<Arguments> emptyStreamValueFactoryTestCases() {",
" return Stream.of();",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"emptyStreamValueFactoryTestCases\")",
" void emptyStreamValueFactory(int foo) {}",
"",
" private static Arguments[] invalidValueFactoryArgumentsTestCases() {",
" return new Arguments[] {arguments(1), arguments(new Object() {})};",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"invalidValueFactoryArgumentsTestCases\")",
" void invalidValueFactoryArguments(int foo) {}",
"}")
"""
import static org.junit.jupiter.params.provider.Arguments.arguments;
import java.util.Optional;
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;
class A {
private static Stream<Arguments> identificationTestCases() {
return Stream.of(arguments(1), Arguments.of(2));
}
@ParameterizedTest
// BUG: Diagnostic contains:
@MethodSource("identificationTestCases")
void identification(int foo) {}
private static int[] identificationWithParensTestCases() {
return new int[] {1, 2};
}
@ParameterizedTest
// BUG: Diagnostic contains:
@MethodSource("identificationWithParensTestCases()")
void identificationWithParens(int foo) {}
@ParameterizedTest
@MethodSource("valueFactoryMissingTestCases")
void valueFactoryMissing(int foo) {}
private static Stream<Arguments> multipleUsagesTestCases() {
return Stream.of(arguments(1), Arguments.of(2));
}
@ParameterizedTest
@MethodSource("multipleUsagesTestCases")
void multipleUsages1(int foo) {}
@ParameterizedTest
@MethodSource("multipleUsagesTestCases()")
void multipleUsages2(int bar) {}
private static Stream<Arguments> valueFactoryRepeatedTestCases() {
return Stream.of(arguments(1), arguments(2));
}
@ParameterizedTest
@MethodSource({"valueFactoryRepeatedTestCases", "valueFactoryRepeatedTestCases"})
void valueFactoryRepeated(int foo) {}
private static Stream<Arguments> multipleParametersTestCases() {
return Stream.of(arguments(1, 2), arguments(3, 4));
}
@ParameterizedTest
@MethodSource("multipleParametersTestCases")
void multipleParameters(int first, int second) {}
private static int[] arrayWithoutInitializersTestCases() {
return new int[1];
}
@ParameterizedTest
@MethodSource("arrayWithoutInitializersTestCases")
void arrayWithoutInitializers(int foo) {}
private static Stream<Arguments> runtimeValueTestCases() {
int second = 2;
return Stream.of(arguments(1), arguments(second));
}
@ParameterizedTest
@MethodSource("runtimeValueTestCases")
void runtimeValue(int foo) {}
private static Stream<Arguments> streamChainTestCases() {
return Stream.of(1, 2).map(Arguments::arguments);
}
@ParameterizedTest
@MethodSource("streamChainTestCases")
void streamChain(int number) {}
private static Stream<Arguments> multipleReturnsTestCases() {
if (true) {
return Stream.of(arguments(1), arguments(2));
} else {
return Stream.of(arguments(3), arguments(4));
}
}
@ParameterizedTest
@MethodSource("multipleReturnsTestCases")
void multipleReturns(int number) {}
private static Stream<Arguments> multipleFactoriesFooTestCases() {
return Stream.of(arguments(1));
}
private static Stream<Arguments> multipleFactoriesBarTestCases() {
return Stream.of(arguments(1));
}
@ParameterizedTest
@MethodSource({"multipleFactoriesFooTestCases", "multipleFactoriesBarTestCases"})
void multipleFactories(int i) {}
private static Stream<Arguments> extraArgsTestCases() {
return Stream.of(arguments(1), arguments(1, 2));
}
@ParameterizedTest
@MethodSource("extraArgsTestCases")
void extraArgs(int... i) {}
private static Stream<Arguments> localClassTestCases() {
class Foo {
Stream<Arguments> foo() {
return Stream.of(arguments(1), arguments(2));
}
}
return Stream.of(arguments(1), arguments(2));
}
@ParameterizedTest
// BUG: Diagnostic contains:
@MethodSource("localClassTestCases")
void localClass(int i) {}
private static Stream<Arguments> lambdaReturnTestCases() {
int foo =
Optional.of(10)
.map(
i -> {
return i / 2;
})
.orElse(0);
return Stream.of(arguments(1), arguments(1));
}
@ParameterizedTest
// BUG: Diagnostic contains:
@MethodSource("lambdaReturnTestCases")
void lambdaReturn(int i) {}
@ParameterizedTest
@MethodSource("tech.picnic.errorprone.Foo#fooTestCases")
void staticMethodReference(int foo) {}
private static Stream<Arguments> valueFactoryWithArgumentTestCases(int amount) {
return Stream.of(arguments(1), arguments(2));
}
@ParameterizedTest
// BUG: Diagnostic contains:
@MethodSource("valueFactoryWithArgumentTestCases")
void valueFactoryWithArgument(int foo) {}
private static Arguments[] emptyArrayValueFactoryTestCases() {
return new Arguments[] {};
}
@ParameterizedTest
@MethodSource("emptyArrayValueFactoryTestCases")
void emptyArrayValueFactory(int foo) {}
private static Stream<Arguments> emptyStreamValueFactoryTestCases() {
return Stream.of();
}
@ParameterizedTest
@MethodSource("emptyStreamValueFactoryTestCases")
void emptyStreamValueFactory(int foo) {}
private static Arguments[] invalidValueFactoryArgumentsTestCases() {
return new Arguments[] {arguments(1), arguments(new Object() {})};
}
@ParameterizedTest
@MethodSource("invalidValueFactoryArgumentsTestCases")
void invalidValueFactoryArguments(int foo) {}
}
""")
.doTest();
}
@@ -202,295 +204,299 @@ final class JUnitValueSourceTest {
BugCheckerRefactoringTestHelper.newInstance(JUnitValueSource.class, getClass())
.addInputLines(
"A.java",
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
"",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableSet;",
"import java.util.List;",
"import java.util.Set;",
"import java.util.stream.DoubleStream;",
"import java.util.stream.IntStream;",
"import java.util.stream.LongStream;",
"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;",
"",
"class A {",
" private static final boolean CONST_BOOLEAN = false;",
" private static final byte CONST_BYTE = 42;",
" private static final char CONST_CHARACTER = 'a';",
" private static final short CONST_SHORT = 42;",
" private static final int CONST_INTEGER = 42;",
" private static final long CONST_LONG = 42;",
" private static final float CONST_FLOAT = 42;",
" private static final double CONST_DOUBLE = 42;",
" private static final String CONST_STRING = \"foo\";",
"",
" private static Stream<Arguments> streamOfBooleanArguments() {",
" return Stream.of(arguments(false), arguments(true), arguments(CONST_BOOLEAN));",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"streamOfBooleanArguments\")",
" void primitiveBoolean(boolean b) {}",
"",
" private static Stream<Object> streamOfBooleansAndBooleanArguments() {",
" return Stream.of(false, arguments(true), CONST_BOOLEAN);",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"streamOfBooleansAndBooleanArguments\")",
" void boxedBoolean(Boolean b) {}",
"",
" private static List<Arguments> listOfByteArguments() {",
" return List.of(arguments((byte) 0), arguments((byte) 1), arguments(CONST_BYTE));",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"listOfByteArguments\")",
" void primitiveByte(byte b) {}",
"",
" private static List<Object> listOfBytesAndByteArguments() {",
" return List.of((byte) 0, arguments((byte) 1), CONST_BYTE);",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"listOfBytesAndByteArguments\")",
" void boxedByte(Byte b) {}",
"",
" private static Set<Arguments> setOfCharacterArguments() {",
" return Set.of(arguments((char) 0), arguments((char) 1), arguments(CONST_CHARACTER));",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"setOfCharacterArguments\")",
" void primitiveCharacter(char c) {}",
"",
" private static Set<Object> setOfCharactersAndCharacterArguments() {",
" return Set.of((char) 0, arguments((char) 1), CONST_CHARACTER);",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"setOfCharactersAndCharacterArguments\")",
" void boxedCharacter(Character c) {}",
"",
" private static Arguments[] arrayOfShortArguments() {",
" return new Arguments[] {arguments((short) 0), arguments((short) 1), arguments(CONST_SHORT)};",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"arrayOfShortArguments\")",
" void primitiveShort(short s) {}",
"",
" private static Object[] arrayOfShortsAndShortArguments() {",
" return new Object[] {(short) 0, arguments((short) 1), CONST_SHORT};",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"arrayOfShortsAndShortArguments\")",
" void boxedShort(Short s) {}",
"",
" private static IntStream intStream() {",
" return IntStream.of(0, 1, CONST_INTEGER);",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"intStream\")",
" void primitiveInteger(int i) {}",
"",
" private static int[] intArray() {",
" return new int[] {0, 1, CONST_INTEGER};",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"intArray\")",
" void boxedInteger(Integer i) {}",
"",
" private static LongStream longStream() {",
" return LongStream.of(0, 1, CONST_LONG);",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"longStream\")",
" void primitiveLong(long l) {}",
"",
" private static long[] longArray() {",
" return new long[] {0, 1, CONST_LONG};",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"longArray\")",
" void boxedLong(Long l) {}",
"",
" private static ImmutableList<Arguments> immutableListOfFloatArguments() {",
" return ImmutableList.of(arguments(0.0F), arguments(1.0F), arguments(CONST_FLOAT));",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"immutableListOfFloatArguments\")",
" void primitiveFloat(float f) {}",
"",
" private static Stream<Object> streamOfFloatsAndFloatArguments() {",
" return Stream.of(0.0F, arguments(1.0F), CONST_FLOAT);",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"streamOfFloatsAndFloatArguments\")",
" void boxedFloat(Float f) {}",
"",
" private static DoubleStream doubleStream() {",
" return DoubleStream.of(0, 1, CONST_DOUBLE);",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"doubleStream\")",
" void primitiveDouble(double d) {}",
"",
" private static double[] doubleArray() {",
" return new double[] {0, 1, CONST_DOUBLE};",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"doubleArray\")",
" void boxedDouble(Double d) {}",
"",
" private static ImmutableSet<Arguments> immutableSetOfStringArguments() {",
" return ImmutableSet.of(arguments(\"foo\"), arguments(\"bar\"), arguments(CONST_STRING));",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"immutableSetOfStringArguments\")",
" void string(String s) {}",
"",
" private static Stream<Class<?>> streamOfClasses() {",
" return Stream.of(Stream.class, java.util.Map.class);",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"streamOfClasses\")",
" void clazz(Class<?> c) {}",
"",
" private static Stream<Arguments> sameNameFactoryTestCases() {",
" return Stream.of(arguments(1));",
" }",
"",
" private static Stream<Arguments> sameNameFactoryTestCases(int overload) {",
" return Stream.of(arguments(overload));",
" }",
"",
" @ParameterizedTest",
" @MethodSource(\"sameNameFactoryTestCases\")",
" void sameNameFactory(int i) {}",
"}")
"""
import static org.junit.jupiter.params.provider.Arguments.arguments;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.util.List;
import java.util.Set;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
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;
class A {
private static final boolean CONST_BOOLEAN = false;
private static final byte CONST_BYTE = 42;
private static final char CONST_CHARACTER = 'a';
private static final short CONST_SHORT = 42;
private static final int CONST_INTEGER = 42;
private static final long CONST_LONG = 42;
private static final float CONST_FLOAT = 42;
private static final double CONST_DOUBLE = 42;
private static final String CONST_STRING = "foo";
private static Stream<Arguments> streamOfBooleanArguments() {
return Stream.of(arguments(false), arguments(true), arguments(CONST_BOOLEAN));
}
@ParameterizedTest
@MethodSource("streamOfBooleanArguments")
void primitiveBoolean(boolean b) {}
private static Stream<Object> streamOfBooleansAndBooleanArguments() {
return Stream.of(false, arguments(true), CONST_BOOLEAN);
}
@ParameterizedTest
@MethodSource("streamOfBooleansAndBooleanArguments")
void boxedBoolean(Boolean b) {}
private static List<Arguments> listOfByteArguments() {
return List.of(arguments((byte) 0), arguments((byte) 1), arguments(CONST_BYTE));
}
@ParameterizedTest
@MethodSource("listOfByteArguments")
void primitiveByte(byte b) {}
private static List<Object> listOfBytesAndByteArguments() {
return List.of((byte) 0, arguments((byte) 1), CONST_BYTE);
}
@ParameterizedTest
@MethodSource("listOfBytesAndByteArguments")
void boxedByte(Byte b) {}
private static Set<Arguments> setOfCharacterArguments() {
return Set.of(arguments((char) 0), arguments((char) 1), arguments(CONST_CHARACTER));
}
@ParameterizedTest
@MethodSource("setOfCharacterArguments")
void primitiveCharacter(char c) {}
private static Set<Object> setOfCharactersAndCharacterArguments() {
return Set.of((char) 0, arguments((char) 1), CONST_CHARACTER);
}
@ParameterizedTest
@MethodSource("setOfCharactersAndCharacterArguments")
void boxedCharacter(Character c) {}
private static Arguments[] arrayOfShortArguments() {
return new Arguments[] {arguments((short) 0), arguments((short) 1), arguments(CONST_SHORT)};
}
@ParameterizedTest
@MethodSource("arrayOfShortArguments")
void primitiveShort(short s) {}
private static Object[] arrayOfShortsAndShortArguments() {
return new Object[] {(short) 0, arguments((short) 1), CONST_SHORT};
}
@ParameterizedTest
@MethodSource("arrayOfShortsAndShortArguments")
void boxedShort(Short s) {}
private static IntStream intStream() {
return IntStream.of(0, 1, CONST_INTEGER);
}
@ParameterizedTest
@MethodSource("intStream")
void primitiveInteger(int i) {}
private static int[] intArray() {
return new int[] {0, 1, CONST_INTEGER};
}
@ParameterizedTest
@MethodSource("intArray")
void boxedInteger(Integer i) {}
private static LongStream longStream() {
return LongStream.of(0, 1, CONST_LONG);
}
@ParameterizedTest
@MethodSource("longStream")
void primitiveLong(long l) {}
private static long[] longArray() {
return new long[] {0, 1, CONST_LONG};
}
@ParameterizedTest
@MethodSource("longArray")
void boxedLong(Long l) {}
private static ImmutableList<Arguments> immutableListOfFloatArguments() {
return ImmutableList.of(arguments(0.0F), arguments(1.0F), arguments(CONST_FLOAT));
}
@ParameterizedTest
@MethodSource("immutableListOfFloatArguments")
void primitiveFloat(float f) {}
private static Stream<Object> streamOfFloatsAndFloatArguments() {
return Stream.of(0.0F, arguments(1.0F), CONST_FLOAT);
}
@ParameterizedTest
@MethodSource("streamOfFloatsAndFloatArguments")
void boxedFloat(Float f) {}
private static DoubleStream doubleStream() {
return DoubleStream.of(0, 1, CONST_DOUBLE);
}
@ParameterizedTest
@MethodSource("doubleStream")
void primitiveDouble(double d) {}
private static double[] doubleArray() {
return new double[] {0, 1, CONST_DOUBLE};
}
@ParameterizedTest
@MethodSource("doubleArray")
void boxedDouble(Double d) {}
private static ImmutableSet<Arguments> immutableSetOfStringArguments() {
return ImmutableSet.of(arguments("foo"), arguments("bar"), arguments(CONST_STRING));
}
@ParameterizedTest
@MethodSource("immutableSetOfStringArguments")
void string(String s) {}
private static Stream<Class<?>> streamOfClasses() {
return Stream.of(Stream.class, java.util.Map.class);
}
@ParameterizedTest
@MethodSource("streamOfClasses")
void clazz(Class<?> c) {}
private static Stream<Arguments> sameNameFactoryTestCases() {
return Stream.of(arguments(1));
}
private static Stream<Arguments> sameNameFactoryTestCases(int overload) {
return Stream.of(arguments(overload));
}
@ParameterizedTest
@MethodSource("sameNameFactoryTestCases")
void sameNameFactory(int i) {}
}
""")
.addOutputLines(
"A.java",
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
"",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableSet;",
"import java.util.List;",
"import java.util.Set;",
"import java.util.stream.DoubleStream;",
"import java.util.stream.IntStream;",
"import java.util.stream.LongStream;",
"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;",
"import org.junit.jupiter.params.provider.ValueSource;",
"",
"class A {",
" private static final boolean CONST_BOOLEAN = false;",
" private static final byte CONST_BYTE = 42;",
" private static final char CONST_CHARACTER = 'a';",
" private static final short CONST_SHORT = 42;",
" private static final int CONST_INTEGER = 42;",
" private static final long CONST_LONG = 42;",
" private static final float CONST_FLOAT = 42;",
" private static final double CONST_DOUBLE = 42;",
" private static final String CONST_STRING = \"foo\";",
"",
" @ParameterizedTest",
" @ValueSource(booleans = {false, true, CONST_BOOLEAN})",
" void primitiveBoolean(boolean b) {}",
"",
" @ParameterizedTest",
" @ValueSource(booleans = {false, true, CONST_BOOLEAN})",
" void boxedBoolean(Boolean b) {}",
"",
" @ParameterizedTest",
" @ValueSource(bytes = {(byte) 0, (byte) 1, CONST_BYTE})",
" void primitiveByte(byte b) {}",
"",
" @ParameterizedTest",
" @ValueSource(bytes = {(byte) 0, (byte) 1, CONST_BYTE})",
" void boxedByte(Byte b) {}",
"",
" @ParameterizedTest",
" @ValueSource(chars = {(char) 0, (char) 1, CONST_CHARACTER})",
" void primitiveCharacter(char c) {}",
"",
" @ParameterizedTest",
" @ValueSource(chars = {(char) 0, (char) 1, CONST_CHARACTER})",
" void boxedCharacter(Character c) {}",
"",
" @ParameterizedTest",
" @ValueSource(shorts = {(short) 0, (short) 1, CONST_SHORT})",
" void primitiveShort(short s) {}",
"",
" @ParameterizedTest",
" @ValueSource(shorts = {(short) 0, (short) 1, CONST_SHORT})",
" void boxedShort(Short s) {}",
"",
" @ParameterizedTest",
" @ValueSource(ints = {0, 1, CONST_INTEGER})",
" void primitiveInteger(int i) {}",
"",
" @ParameterizedTest",
" @ValueSource(ints = {0, 1, CONST_INTEGER})",
" void boxedInteger(Integer i) {}",
"",
" @ParameterizedTest",
" @ValueSource(longs = {0, 1, CONST_LONG})",
" void primitiveLong(long l) {}",
"",
" @ParameterizedTest",
" @ValueSource(longs = {0, 1, CONST_LONG})",
" void boxedLong(Long l) {}",
"",
" @ParameterizedTest",
" @ValueSource(floats = {0.0F, 1.0F, CONST_FLOAT})",
" void primitiveFloat(float f) {}",
"",
" @ParameterizedTest",
" @ValueSource(floats = {0.0F, 1.0F, CONST_FLOAT})",
" void boxedFloat(Float f) {}",
"",
" @ParameterizedTest",
" @ValueSource(doubles = {0, 1, CONST_DOUBLE})",
" void primitiveDouble(double d) {}",
"",
" @ParameterizedTest",
" @ValueSource(doubles = {0, 1, CONST_DOUBLE})",
" void boxedDouble(Double d) {}",
"",
" @ParameterizedTest",
" @ValueSource(strings = {\"foo\", \"bar\", CONST_STRING})",
" void string(String s) {}",
"",
" @ParameterizedTest",
" @ValueSource(classes = {Stream.class, java.util.Map.class})",
" void clazz(Class<?> c) {}",
"",
" private static Stream<Arguments> sameNameFactoryTestCases(int overload) {",
" return Stream.of(arguments(overload));",
" }",
"",
" @ParameterizedTest",
" @ValueSource(ints = 1)",
" void sameNameFactory(int i) {}",
"}")
"""
import static org.junit.jupiter.params.provider.Arguments.arguments;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.util.List;
import java.util.Set;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
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;
import org.junit.jupiter.params.provider.ValueSource;
class A {
private static final boolean CONST_BOOLEAN = false;
private static final byte CONST_BYTE = 42;
private static final char CONST_CHARACTER = 'a';
private static final short CONST_SHORT = 42;
private static final int CONST_INTEGER = 42;
private static final long CONST_LONG = 42;
private static final float CONST_FLOAT = 42;
private static final double CONST_DOUBLE = 42;
private static final String CONST_STRING = "foo";
@ParameterizedTest
@ValueSource(booleans = {false, true, CONST_BOOLEAN})
void primitiveBoolean(boolean b) {}
@ParameterizedTest
@ValueSource(booleans = {false, true, CONST_BOOLEAN})
void boxedBoolean(Boolean b) {}
@ParameterizedTest
@ValueSource(bytes = {(byte) 0, (byte) 1, CONST_BYTE})
void primitiveByte(byte b) {}
@ParameterizedTest
@ValueSource(bytes = {(byte) 0, (byte) 1, CONST_BYTE})
void boxedByte(Byte b) {}
@ParameterizedTest
@ValueSource(chars = {(char) 0, (char) 1, CONST_CHARACTER})
void primitiveCharacter(char c) {}
@ParameterizedTest
@ValueSource(chars = {(char) 0, (char) 1, CONST_CHARACTER})
void boxedCharacter(Character c) {}
@ParameterizedTest
@ValueSource(shorts = {(short) 0, (short) 1, CONST_SHORT})
void primitiveShort(short s) {}
@ParameterizedTest
@ValueSource(shorts = {(short) 0, (short) 1, CONST_SHORT})
void boxedShort(Short s) {}
@ParameterizedTest
@ValueSource(ints = {0, 1, CONST_INTEGER})
void primitiveInteger(int i) {}
@ParameterizedTest
@ValueSource(ints = {0, 1, CONST_INTEGER})
void boxedInteger(Integer i) {}
@ParameterizedTest
@ValueSource(longs = {0, 1, CONST_LONG})
void primitiveLong(long l) {}
@ParameterizedTest
@ValueSource(longs = {0, 1, CONST_LONG})
void boxedLong(Long l) {}
@ParameterizedTest
@ValueSource(floats = {0.0F, 1.0F, CONST_FLOAT})
void primitiveFloat(float f) {}
@ParameterizedTest
@ValueSource(floats = {0.0F, 1.0F, CONST_FLOAT})
void boxedFloat(Float f) {}
@ParameterizedTest
@ValueSource(doubles = {0, 1, CONST_DOUBLE})
void primitiveDouble(double d) {}
@ParameterizedTest
@ValueSource(doubles = {0, 1, CONST_DOUBLE})
void boxedDouble(Double d) {}
@ParameterizedTest
@ValueSource(strings = {"foo", "bar", CONST_STRING})
void string(String s) {}
@ParameterizedTest
@ValueSource(classes = {Stream.class, java.util.Map.class})
void clazz(Class<?> c) {}
private static Stream<Arguments> sameNameFactoryTestCases(int overload) {
return Stream.of(arguments(overload));
}
@ParameterizedTest
@ValueSource(ints = 1)
void sameNameFactory(int i) {}
}
""")
.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;
@@ -12,176 +11,178 @@ final class LexicographicalAnnotationAttributeListingTest {
CompilationTestHelper.newInstance(LexicographicalAnnotationAttributeListing.class, getClass())
.addSourceLines(
"A.java",
"import static java.math.RoundingMode.DOWN;",
"import static java.math.RoundingMode.UP;",
"",
"import com.fasterxml.jackson.annotation.JsonPropertyOrder;",
"import io.swagger.annotations.ApiImplicitParam;",
"import io.swagger.annotations.ApiImplicitParams;",
"import io.swagger.v3.oas.annotations.Parameter;",
"import io.swagger.v3.oas.annotations.Parameters;",
"import java.math.RoundingMode;",
"import javax.xml.bind.annotation.XmlType;",
"import org.springframework.context.annotation.PropertySource;",
"import org.springframework.test.context.TestPropertySource;",
"",
"interface A {",
" @interface Foo {",
" String[] value() default {};",
"",
" boolean[] bools() default {};",
"",
" char[] chars() default {};",
"",
" int[] ints() default {};",
"",
" Class<?>[] cls() default {};",
"",
" RoundingMode[] enums() default {};",
"",
" Bar[] anns() default {};",
" }",
"",
" @interface Bar {",
" String[] value() default {};",
" }",
"",
" @Foo({})",
" A noString();",
"",
" @Foo({\"a\"})",
" A oneString();",
"",
" @Foo({\"a\", \"b\"})",
" A sortedStrings();",
"",
" // BUG: Diagnostic contains:",
" @Foo({\"b\", \"a\"})",
" A unsortedString();",
"",
" @Foo({\"ab\", \"Ac\"})",
" A sortedStringCaseInsensitive();",
"",
" // BUG: Diagnostic contains:",
" @Foo({\"ac\", \"Ab\"})",
" A unsortedStringCaseInsensitive();",
"",
" @Foo({\"A\", \"a\"})",
" A sortedStringCaseInsensitiveWithTotalOrderFallback();",
"",
" // BUG: Diagnostic contains:",
" @Foo({\"a\", \"A\"})",
" A unsortedStringCaseInsensitiveWithTotalOrderFallback();",
"",
" @Foo(bools = {})",
" A noBools();",
"",
" @Foo(bools = {false})",
" A oneBool();",
"",
" @Foo(bools = {false, true})",
" A sortedBools();",
"",
" // BUG: Diagnostic contains:",
" @Foo(bools = {true, false})",
" A unsortedBools();",
"",
" @Foo(chars = {})",
" A noChars();",
"",
" @Foo(chars = {'a'})",
" A oneChar();",
"",
" @Foo(chars = {'a', 'b'})",
" A sortedChars();",
"",
" // BUG: Diagnostic contains:",
" @Foo(chars = {'b', 'a'})",
" A unsortedChars();",
"",
" @Foo(ints = {})",
" A noInts();",
"",
" @Foo(ints = {0})",
" A oneInt();",
"",
" @Foo(ints = {0, 1})",
" A sortedInts();",
"",
" @Foo(ints = {1, 0})",
" A unsortedInts();",
"",
" @Foo(cls = {})",
" A noClasses();",
"",
" @Foo(cls = {int.class})",
" A oneClass();",
"",
" @Foo(cls = {int.class, long.class})",
" A sortedClasses();",
"",
" // BUG: Diagnostic contains:",
" @Foo(cls = {long.class, int.class})",
" A unsortedClasses();",
"",
" @Foo(enums = {})",
" A noEnums();",
"",
" @Foo(enums = {DOWN})",
" A oneEnum();",
"",
" @Foo(enums = {DOWN, UP})",
" A sortedEnums();",
"",
" // BUG: Diagnostic contains:",
" @Foo(enums = {UP, DOWN})",
" A unsortedEnums();",
"",
" @Foo(anns = {})",
" A noAnns();",
"",
" @Foo(anns = {@Bar(\"a\")})",
" A oneAnn();",
"",
" @Foo(anns = {@Bar(\"a\"), @Bar(\"b\")})",
" A sortedAnns();",
"",
" // BUG: Diagnostic contains:",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
" A unsortedAnns();",
"",
" // BUG: Diagnostic contains:",
" @Foo(anns = {@Bar(\"a\"), @Bar({\"b\", \"a\"})})",
" A unsortedInnderAnns();",
"",
" @Foo({\"a=foo\", \"a.b=bar\", \"a.c=baz\"})",
" A hierarchicallySorted();",
"",
" // BUG: Diagnostic contains:",
" @Foo({\"a.b=bar\", \"a.c=baz\", \"a=foo\"})",
" A hierarchicallyUnsorted();",
"",
" @JsonPropertyOrder({\"field2\", \"field1\"})",
" A dto();",
"",
" @ApiImplicitParams({@ApiImplicitParam(\"p2\"), @ApiImplicitParam(\"p1\")})",
" A firstEndpoint();",
"",
" @Parameters({@Parameter(name = \"p2\"), @Parameter(name = \"p1\")})",
" A secondEndpoint();",
"",
" @XmlType(propOrder = {\"field2\", \"field1\"})",
" class XmlTypeDummy {}",
"",
" @PropertySource({\"field2\", \"field1\"})",
" class PropertySourceDummy {}",
"",
" @TestPropertySource(locations = {\"field2\", \"field1\"})",
" class FirstTestPropertySourceDummy {}",
"",
" @TestPropertySource({\"field2\", \"field1\"})",
" class SecondTestPropertySourceDummy {}",
"}")
"""
import static java.math.RoundingMode.DOWN;
import static java.math.RoundingMode.UP;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import java.math.RoundingMode;
import javax.xml.bind.annotation.XmlType;
import org.springframework.context.annotation.PropertySource;
import org.springframework.test.context.TestPropertySource;
interface A {
@interface Foo {
String[] value() default {};
boolean[] bools() default {};
char[] chars() default {};
int[] ints() default {};
Class<?>[] cls() default {};
RoundingMode[] enums() default {};
Bar[] anns() default {};
}
@interface Bar {
String[] value() default {};
}
@Foo({})
A noString();
@Foo({"a"})
A oneString();
@Foo({"a", "b"})
A sortedStrings();
// BUG: Diagnostic contains:
@Foo({"b", "a"})
A unsortedString();
@Foo({"ab", "Ac"})
A sortedStringCaseInsensitive();
// BUG: Diagnostic contains:
@Foo({"ac", "Ab"})
A unsortedStringCaseInsensitive();
@Foo({"A", "a"})
A sortedStringCaseInsensitiveWithTotalOrderFallback();
// BUG: Diagnostic contains:
@Foo({"a", "A"})
A unsortedStringCaseInsensitiveWithTotalOrderFallback();
@Foo(bools = {})
A noBools();
@Foo(bools = {false})
A oneBool();
@Foo(bools = {false, true})
A sortedBools();
// BUG: Diagnostic contains:
@Foo(bools = {true, false})
A unsortedBools();
@Foo(chars = {})
A noChars();
@Foo(chars = {'a'})
A oneChar();
@Foo(chars = {'a', 'b'})
A sortedChars();
// BUG: Diagnostic contains:
@Foo(chars = {'b', 'a'})
A unsortedChars();
@Foo(ints = {})
A noInts();
@Foo(ints = {0})
A oneInt();
@Foo(ints = {0, 1})
A sortedInts();
@Foo(ints = {1, 0})
A unsortedInts();
@Foo(cls = {})
A noClasses();
@Foo(cls = {int.class})
A oneClass();
@Foo(cls = {int.class, long.class})
A sortedClasses();
// BUG: Diagnostic contains:
@Foo(cls = {long.class, int.class})
A unsortedClasses();
@Foo(enums = {})
A noEnums();
@Foo(enums = {DOWN})
A oneEnum();
@Foo(enums = {DOWN, UP})
A sortedEnums();
// BUG: Diagnostic contains:
@Foo(enums = {UP, DOWN})
A unsortedEnums();
@Foo(anns = {})
A noAnns();
@Foo(anns = {@Bar("a")})
A oneAnn();
@Foo(anns = {@Bar("a"), @Bar("b")})
A sortedAnns();
// BUG: Diagnostic contains:
@Foo(anns = {@Bar("b"), @Bar("a")})
A unsortedAnns();
// BUG: Diagnostic contains:
@Foo(anns = {@Bar("a"), @Bar({"b", "a"})})
A unsortedInnderAnns();
@Foo({"a=foo", "a.b=bar", "a.c=baz"})
A hierarchicallySorted();
// BUG: Diagnostic contains:
@Foo({"a.b=bar", "a.c=baz", "a=foo"})
A hierarchicallyUnsorted();
@JsonPropertyOrder({"field2", "field1"})
A dto();
@ApiImplicitParams({@ApiImplicitParam("p2"), @ApiImplicitParam("p1")})
A firstEndpoint();
@Parameters({@Parameter(name = "p2"), @Parameter(name = "p1")})
A secondEndpoint();
@XmlType(propOrder = {"field2", "field1"})
class XmlTypeDummy {}
@PropertySource({"field2", "field1"})
class PropertySourceDummy {}
@TestPropertySource(locations = {"field2", "field1"})
class FirstTestPropertySourceDummy {}
@TestPropertySource({"field2", "field1"})
class SecondTestPropertySourceDummy {}
}
""")
.doTest();
}
@@ -194,98 +195,102 @@ final class LexicographicalAnnotationAttributeListingTest {
LexicographicalAnnotationAttributeListing.class, getClass())
.addInputLines(
"A.java",
"import static java.math.RoundingMode.DOWN;",
"import static java.math.RoundingMode.UP;",
"",
"import java.math.RoundingMode;",
"",
"interface A {",
" @interface Foo {",
" String[] value() default {};",
"",
" boolean[] bools() default {};",
"",
" char[] chars() default {};",
"",
" Class<?>[] cls() default {};",
"",
" RoundingMode[] enums() default {};",
"",
" Bar[] anns() default {};",
" }",
"",
" @interface Bar {",
" String[] value() default {};",
" }",
"",
" @Foo({\" \", \"\", \"b\", \"a\"})",
" A unsortedStrings();",
"",
" @Foo(bools = {true, false})",
" A unsortedBooleans();",
"",
" @Foo(chars = {'b', 'a'})",
" A unsortedChars();",
"",
" @Foo(cls = {long.class, int.class})",
" A unsortedClasses();",
"",
" @Foo(enums = {UP, DOWN})",
" A unsortedEnums();",
"",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
" A unsortedAnns();",
"",
" @Foo(anns = {@Bar(\"a\"), @Bar({\"b\", \"a\"})})",
" A unsortedInnderAnns();",
"}")
"""
import static java.math.RoundingMode.DOWN;
import static java.math.RoundingMode.UP;
import java.math.RoundingMode;
interface A {
@interface Foo {
String[] value() default {};
boolean[] bools() default {};
char[] chars() default {};
Class<?>[] cls() default {};
RoundingMode[] enums() default {};
Bar[] anns() default {};
}
@interface Bar {
String[] value() default {};
}
@Foo({" ", "", "b", "a"})
A unsortedStrings();
@Foo(bools = {true, false})
A unsortedBooleans();
@Foo(chars = {'b', 'a'})
A unsortedChars();
@Foo(cls = {long.class, int.class})
A unsortedClasses();
@Foo(enums = {UP, DOWN})
A unsortedEnums();
@Foo(anns = {@Bar("b"), @Bar("a")})
A unsortedAnns();
@Foo(anns = {@Bar("a"), @Bar({"b", "a"})})
A unsortedInnderAnns();
}
""")
.addOutputLines(
"A.java",
"import static java.math.RoundingMode.DOWN;",
"import static java.math.RoundingMode.UP;",
"",
"import java.math.RoundingMode;",
"",
"interface A {",
" @interface Foo {",
" String[] value() default {};",
"",
" boolean[] bools() default {};",
"",
" char[] chars() default {};",
"",
" Class<?>[] cls() default {};",
"",
" RoundingMode[] enums() default {};",
"",
" Bar[] anns() default {};",
" }",
"",
" @interface Bar {",
" String[] value() default {};",
" }",
"",
" @Foo({\"\", \" \", \"a\", \"b\"})",
" A unsortedStrings();",
"",
" @Foo(bools = {false, true})",
" A unsortedBooleans();",
"",
" @Foo(chars = {'a', 'b'})",
" A unsortedChars();",
"",
" @Foo(cls = {int.class, long.class})",
" A unsortedClasses();",
"",
" @Foo(enums = {DOWN, UP})",
" A unsortedEnums();",
"",
" @Foo(anns = {@Bar(\"a\"), @Bar(\"b\")})",
" A unsortedAnns();",
"",
" @Foo(anns = {@Bar(\"a\"), @Bar({\"a\", \"b\"})})",
" A unsortedInnderAnns();",
"}")
"""
import static java.math.RoundingMode.DOWN;
import static java.math.RoundingMode.UP;
import java.math.RoundingMode;
interface A {
@interface Foo {
String[] value() default {};
boolean[] bools() default {};
char[] chars() default {};
Class<?>[] cls() default {};
RoundingMode[] enums() default {};
Bar[] anns() default {};
}
@interface Bar {
String[] value() default {};
}
@Foo({"", " ", "a", "b"})
A unsortedStrings();
@Foo(bools = {false, true})
A unsortedBooleans();
@Foo(chars = {'a', 'b'})
A unsortedChars();
@Foo(cls = {int.class, long.class})
A unsortedClasses();
@Foo(enums = {DOWN, UP})
A unsortedEnums();
@Foo(anns = {@Bar("a"), @Bar("b")})
A unsortedAnns();
@Foo(anns = {@Bar("a"), @Bar({"a", "b"})})
A unsortedInnderAnns();
}
""")
.doTest(TestMode.TEXT_MATCH);
}
@@ -294,53 +299,54 @@ 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;",
"",
"interface A {",
" @interface Foo {",
" String[] value() default {};",
"",
" String[] value2() default {};",
" }",
"",
" @interface Bar {",
" String[] value() default {};",
"",
" String[] value2() default {};",
" }",
"",
" @interface Baz {",
" String[] value() default {};",
"",
" String[] value2() default {};",
" }",
"",
" // BUG: Diagnostic contains:",
" @Foo({\"b\", \"a\"})",
" A fooValue();",
"",
" // BUG: Diagnostic contains:",
" @Foo(value2 = {\"b\", \"a\"})",
" A fooValue2();",
"",
" @Bar({\"b\", \"a\"})",
" A barValue();",
"",
" // BUG: Diagnostic contains:",
" @Bar(value2 = {\"b\", \"a\"})",
" A barValue2();",
"",
" @Baz({\"b\", \"a\"})",
" A bazValue();",
"",
" @Baz(value2 = {\"b\", \"a\"})",
" A bazValue2();",
"}")
"""
package pkg;
interface A {
@interface Foo {
String[] value() default {};
String[] value2() default {};
}
@interface Bar {
String[] value() default {};
String[] value2() default {};
}
@interface Baz {
String[] value() default {};
String[] value2() default {};
}
// BUG: Diagnostic contains:
@Foo({"b", "a"})
A fooValue();
// BUG: Diagnostic contains:
@Foo(value2 = {"b", "a"})
A fooValue2();
@Bar({"b", "a"})
A barValue();
// BUG: Diagnostic contains:
@Bar(value2 = {"b", "a"})
A barValue2();
@Baz({"b", "a"})
A bazValue();
@Baz(value2 = {"b", "a"})
A bazValue2();
}
""")
.doTest();
}
}

View File

@@ -11,122 +11,124 @@ final class LexicographicalAnnotationListingTest {
CompilationTestHelper.newInstance(LexicographicalAnnotationListing.class, getClass())
.addSourceLines(
"A.java",
"import java.lang.annotation.ElementType;",
"import java.lang.annotation.Repeatable;",
"import java.lang.annotation.Target;",
"",
"interface A {",
" @Repeatable(Foos.class)",
" @interface Foo {",
" String[] value() default {};",
"",
" int[] ints() default {};",
"",
" Bar[] anns() default {};",
" }",
"",
" @Target(ElementType.METHOD)",
" @interface Bar {",
" String[] value() default {};",
" }",
"",
" @interface Baz {",
" String[] str() default {};",
" }",
"",
" @interface Foos {",
" Foo[] value();",
" }",
"",
" @Target(ElementType.TYPE_USE)",
" @interface FooTypeUse {",
" String[] value() default {};",
" }",
"",
" @Target(ElementType.TYPE_USE)",
" @interface BarTypeUse {",
" String[] value() default {};",
" }",
"",
" // BUG: Diagnostic contains:",
" @Foo",
" @Bar",
" A unsortedSimpleCase();",
"",
" // BUG: Diagnostic contains:",
" @Foo()",
" @Bar()",
" A unsortedWithParens();",
"",
" @Foo()",
" A onlyOneAnnotation();",
"",
" @Bar",
" @Foo()",
" A sortedAnnotationsOneWithParens();",
"",
" // BUG: Diagnostic contains:",
" @Foo",
" @Baz",
" @Bar",
" A threeUnsortedAnnotationsSameInitialLetter();",
"",
" // BUG: Diagnostic contains:",
" @Bar",
" @Foo()",
" @Baz",
" A firstOrderedWithTwoUnsortedAnnotations();",
"",
" @Bar",
" @Baz",
" @Foo()",
" A threeSortedAnnotations();",
"",
" // BUG: Diagnostic contains:",
" @Foo({\"b\"})",
" @Bar({\"a\"})",
" A unsortedWithStringAttributes();",
"",
" // BUG: Diagnostic contains:",
" @Baz(str = {\"a\", \"b\"})",
" @Foo(ints = {1, 0})",
" @Bar",
" A unsortedWithAttributes();",
"",
" // BUG: Diagnostic contains:",
" @Bar",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
" @Baz",
" A unsortedWithNestedBar();",
"",
" @Bar",
" @Baz",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
" A sortedWithNestedBar();",
"",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
" @Foo(ints = {1, 2})",
" @Foo({\"b\"})",
" A sortedRepeatableAnnotation();",
"",
" // BUG: Diagnostic contains:",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
" @Bar",
" @Foo(ints = {1, 2})",
" A unsortedRepeatableAnnotation();",
"",
" // BUG: Diagnostic contains:",
" default @FooTypeUse @BarTypeUse A unsortedTypeAnnotations() {",
" return null;",
" }",
"",
" // BUG: Diagnostic contains:",
" @Baz",
" @Bar",
" default @FooTypeUse @BarTypeUse A unsortedTypeUseAndOtherAnnotations() {",
" return null;",
" }",
"}")
"""
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Target;
interface A {
@Repeatable(Foos.class)
@interface Foo {
String[] value() default {};
int[] ints() default {};
Bar[] anns() default {};
}
@Target(ElementType.METHOD)
@interface Bar {
String[] value() default {};
}
@interface Baz {
String[] str() default {};
}
@interface Foos {
Foo[] value();
}
@Target(ElementType.TYPE_USE)
@interface FooTypeUse {
String[] value() default {};
}
@Target(ElementType.TYPE_USE)
@interface BarTypeUse {
String[] value() default {};
}
// BUG: Diagnostic contains:
@Foo
@Bar
A unsortedSimpleCase();
// BUG: Diagnostic contains:
@Foo()
@Bar()
A unsortedWithParens();
@Foo()
A onlyOneAnnotation();
@Bar
@Foo()
A sortedAnnotationsOneWithParens();
// BUG: Diagnostic contains:
@Foo
@Baz
@Bar
A threeUnsortedAnnotationsSameInitialLetter();
// BUG: Diagnostic contains:
@Bar
@Foo()
@Baz
A firstOrderedWithTwoUnsortedAnnotations();
@Bar
@Baz
@Foo()
A threeSortedAnnotations();
// BUG: Diagnostic contains:
@Foo({"b"})
@Bar({"a"})
A unsortedWithStringAttributes();
// BUG: Diagnostic contains:
@Baz(str = {"a", "b"})
@Foo(ints = {1, 0})
@Bar
A unsortedWithAttributes();
// BUG: Diagnostic contains:
@Bar
@Foo(anns = {@Bar("b"), @Bar("a")})
@Baz
A unsortedWithNestedBar();
@Bar
@Baz
@Foo(anns = {@Bar("b"), @Bar("a")})
A sortedWithNestedBar();
@Foo(anns = {@Bar("b"), @Bar("a")})
@Foo(ints = {1, 2})
@Foo({"b"})
A sortedRepeatableAnnotation();
// BUG: Diagnostic contains:
@Foo(anns = {@Bar("b"), @Bar("a")})
@Bar
@Foo(ints = {1, 2})
A unsortedRepeatableAnnotation();
// BUG: Diagnostic contains:
default @FooTypeUse @BarTypeUse A unsortedTypeAnnotations() {
return null;
}
// BUG: Diagnostic contains:
@Baz
@Bar
default @FooTypeUse @BarTypeUse A unsortedTypeUseAndOtherAnnotations() {
return null;
}
}
""")
.doTest();
}
@@ -135,166 +137,170 @@ final class LexicographicalAnnotationListingTest {
BugCheckerRefactoringTestHelper.newInstance(LexicographicalAnnotationListing.class, getClass())
.addInputLines(
"A.java",
"import java.lang.annotation.ElementType;",
"import java.lang.annotation.Repeatable;",
"import java.lang.annotation.Target;",
"",
"interface A {",
" @Repeatable(Foos.class)",
" @interface Foo {",
" String[] value() default {};",
"",
" int[] ints() default {};",
"",
" Bar[] anns() default {};",
" }",
"",
" @Target(ElementType.METHOD)",
" @interface Bar {",
" String[] value() default {};",
" }",
"",
" @interface Baz {",
" String[] str() default {};",
" }",
"",
" @interface Foos {",
" Foo[] value();",
" }",
"",
" @Target(ElementType.TYPE_USE)",
" @interface FooTypeUse {",
" String[] value() default {};",
" }",
"",
" @Target(ElementType.TYPE_USE)",
" @interface BarTypeUse {",
" String[] value() default {};",
" }",
"",
" @Bar",
" A singleAnnotation();",
"",
" @Bar",
" @Foo",
" A sortedAnnotations();",
"",
" @Foo",
" @Bar",
" A unsortedAnnotations();",
"",
" @Foo()",
" @Baz()",
" @Bar",
" A unsortedAnnotationsWithSomeParens();",
"",
" @Bar",
" @Baz(str = {\"a\", \"b\"})",
" @Foo()",
" A unsortedAnnotationsOneContainingAttributes();",
"",
" @Baz(str = {\"a\", \"b\"})",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
" @Bar({\"b\"})",
" A unsortedAnnotationsWithAttributes();",
"",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
" @Foo(ints = {1, 2})",
" @Foo({\"b\"})",
" A sortedRepeatableAnnotation();",
"",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
" @Bar",
" @Foo(ints = {1, 2})",
" A unsortedRepeatableAnnotation();",
"",
" @Baz",
" @Bar",
" default @FooTypeUse @BarTypeUse A unsortedWithTypeUseAnnotations() {",
" return null;",
" }",
"}")
"""
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Target;
interface A {
@Repeatable(Foos.class)
@interface Foo {
String[] value() default {};
int[] ints() default {};
Bar[] anns() default {};
}
@Target(ElementType.METHOD)
@interface Bar {
String[] value() default {};
}
@interface Baz {
String[] str() default {};
}
@interface Foos {
Foo[] value();
}
@Target(ElementType.TYPE_USE)
@interface FooTypeUse {
String[] value() default {};
}
@Target(ElementType.TYPE_USE)
@interface BarTypeUse {
String[] value() default {};
}
@Bar
A singleAnnotation();
@Bar
@Foo
A sortedAnnotations();
@Foo
@Bar
A unsortedAnnotations();
@Foo()
@Baz()
@Bar
A unsortedAnnotationsWithSomeParens();
@Bar
@Baz(str = {"a", "b"})
@Foo()
A unsortedAnnotationsOneContainingAttributes();
@Baz(str = {"a", "b"})
@Foo(anns = {@Bar("b"), @Bar("a")})
@Bar({"b"})
A unsortedAnnotationsWithAttributes();
@Foo(anns = {@Bar("b"), @Bar("a")})
@Foo(ints = {1, 2})
@Foo({"b"})
A sortedRepeatableAnnotation();
@Foo(anns = {@Bar("b"), @Bar("a")})
@Bar
@Foo(ints = {1, 2})
A unsortedRepeatableAnnotation();
@Baz
@Bar
default @FooTypeUse @BarTypeUse A unsortedWithTypeUseAnnotations() {
return null;
}
}
""")
.addOutputLines(
"A.java",
"import java.lang.annotation.ElementType;",
"import java.lang.annotation.Repeatable;",
"import java.lang.annotation.Target;",
"",
"interface A {",
" @Repeatable(Foos.class)",
" @interface Foo {",
" String[] value() default {};",
"",
" int[] ints() default {};",
"",
" Bar[] anns() default {};",
" }",
"",
" @Target(ElementType.METHOD)",
" @interface Bar {",
" String[] value() default {};",
" }",
"",
" @interface Baz {",
" String[] str() default {};",
" }",
"",
" @interface Foos {",
" Foo[] value();",
" }",
"",
" @Target(ElementType.TYPE_USE)",
" @interface FooTypeUse {",
" String[] value() default {};",
" }",
"",
" @Target(ElementType.TYPE_USE)",
" @interface BarTypeUse {",
" String[] value() default {};",
" }",
"",
" @Bar",
" A singleAnnotation();",
"",
" @Bar",
" @Foo",
" A sortedAnnotations();",
"",
" @Bar",
" @Foo",
" A unsortedAnnotations();",
"",
" @Bar",
" @Baz()",
" @Foo()",
" A unsortedAnnotationsWithSomeParens();",
"",
" @Bar",
" @Baz(str = {\"a\", \"b\"})",
" @Foo()",
" A unsortedAnnotationsOneContainingAttributes();",
"",
" @Bar({\"b\"})",
" @Baz(str = {\"a\", \"b\"})",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
" A unsortedAnnotationsWithAttributes();",
"",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
" @Foo(ints = {1, 2})",
" @Foo({\"b\"})",
" A sortedRepeatableAnnotation();",
"",
" @Bar",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
" @Foo(ints = {1, 2})",
" A unsortedRepeatableAnnotation();",
"",
" @Bar",
" @Baz",
" default @BarTypeUse @FooTypeUse A unsortedWithTypeUseAnnotations() {",
" return null;",
" }",
"}")
"""
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Target;
interface A {
@Repeatable(Foos.class)
@interface Foo {
String[] value() default {};
int[] ints() default {};
Bar[] anns() default {};
}
@Target(ElementType.METHOD)
@interface Bar {
String[] value() default {};
}
@interface Baz {
String[] str() default {};
}
@interface Foos {
Foo[] value();
}
@Target(ElementType.TYPE_USE)
@interface FooTypeUse {
String[] value() default {};
}
@Target(ElementType.TYPE_USE)
@interface BarTypeUse {
String[] value() default {};
}
@Bar
A singleAnnotation();
@Bar
@Foo
A sortedAnnotations();
@Bar
@Foo
A unsortedAnnotations();
@Bar
@Baz()
@Foo()
A unsortedAnnotationsWithSomeParens();
@Bar
@Baz(str = {"a", "b"})
@Foo()
A unsortedAnnotationsOneContainingAttributes();
@Bar({"b"})
@Baz(str = {"a", "b"})
@Foo(anns = {@Bar("b"), @Bar("a")})
A unsortedAnnotationsWithAttributes();
@Foo(anns = {@Bar("b"), @Bar("a")})
@Foo(ints = {1, 2})
@Foo({"b"})
A sortedRepeatableAnnotation();
@Bar
@Foo(anns = {@Bar("b"), @Bar("a")})
@Foo(ints = {1, 2})
A unsortedRepeatableAnnotation();
@Bar
@Baz
default @BarTypeUse @FooTypeUse A unsortedWithTypeUseAnnotations() {
return null;
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,86 +11,88 @@ final class MockitoMockClassReferenceTest {
CompilationTestHelper.newInstance(MockitoMockClassReference.class, getClass())
.addSourceLines(
"A.java",
"import static org.mockito.Mockito.mock;",
"import static org.mockito.Mockito.spy;",
"import static org.mockito.Mockito.withSettings;",
"",
"import java.util.List;",
"import java.util.Objects;",
"import org.mockito.invocation.InvocationOnMock;",
"",
"class A {",
" {",
" Double d = Objects.requireNonNullElseGet(null, () -> mock(Double.class));",
" Double d2 =",
" Objects.requireNonNullElseGet(",
" null,",
" () -> {",
" return mock(Double.class);",
" });",
" }",
"",
" void m() {",
" Number variableMock = 42;",
" // BUG: Diagnostic contains:",
" variableMock = mock(Number.class);",
" // BUG: Diagnostic contains:",
" variableMock = mock(Number.class, \"name\");",
" // BUG: Diagnostic contains:",
" variableMock = mock(Number.class, InvocationOnMock::callRealMethod);",
" // BUG: Diagnostic contains:",
" variableMock = mock(Number.class, withSettings());",
" variableMock = mock(Integer.class);",
" variableMock = 42;",
" // BUG: Diagnostic contains:",
" List rawMock = mock(List.class);",
" // BUG: Diagnostic contains:",
" List<String> genericMock = mock(List.class);",
" var varMock = mock(Integer.class);",
" Class<? extends Number> numberType = Integer.class;",
" Number variableTypeMock = mock(numberType);",
" Object subtypeMock = mock(Integer.class);",
"",
" Number variableSpy = 42;",
" // BUG: Diagnostic contains:",
" variableSpy = spy(Number.class);",
" variableSpy = spy(Integer.class);",
" variableSpy = 42;",
" // BUG: Diagnostic contains:",
" List rawSpy = spy(List.class);",
" // BUG: Diagnostic contains:",
" List<String> genericSpy = spy(List.class);",
" var varSpy = spy(Integer.class);",
" Number variableTypeSpy = spy(numberType);",
" Object subtypeSpy = spy(Integer.class);",
" Object objectSpy = spy(new Object());",
"",
" Objects.hash(mock(Integer.class));",
" Integer i = mock(mock(Integer.class));",
" String s = new String(mock(String.class));",
" }",
"",
" Double getDoubleMock() {",
" return Objects.requireNonNullElseGet(",
" null,",
" () -> {",
" return mock(Double.class);",
" });",
" }",
"",
" Integer getIntegerMock() {",
" // BUG: Diagnostic contains:",
" return mock(Integer.class);",
" }",
"",
" <T> T getGenericMock(Class<T> clazz) {",
" return mock(clazz);",
" }",
"",
" Number getSubTypeMock() {",
" return mock(Integer.class);",
" }",
"}")
"""
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.withSettings;
import java.util.List;
import java.util.Objects;
import org.mockito.invocation.InvocationOnMock;
class A {
{
Double d = Objects.requireNonNullElseGet(null, () -> mock(Double.class));
Double d2 =
Objects.requireNonNullElseGet(
null,
() -> {
return mock(Double.class);
});
}
void m() {
Number variableMock = 42;
// BUG: Diagnostic contains:
variableMock = mock(Number.class);
// BUG: Diagnostic contains:
variableMock = mock(Number.class, "name");
// BUG: Diagnostic contains:
variableMock = mock(Number.class, InvocationOnMock::callRealMethod);
// BUG: Diagnostic contains:
variableMock = mock(Number.class, withSettings());
variableMock = mock(Integer.class);
variableMock = 42;
// BUG: Diagnostic contains:
List rawMock = mock(List.class);
// BUG: Diagnostic contains:
List<String> genericMock = mock(List.class);
var varMock = mock(Integer.class);
Class<? extends Number> numberType = Integer.class;
Number variableTypeMock = mock(numberType);
Object subtypeMock = mock(Integer.class);
Number variableSpy = 42;
// BUG: Diagnostic contains:
variableSpy = spy(Number.class);
variableSpy = spy(Integer.class);
variableSpy = 42;
// BUG: Diagnostic contains:
List rawSpy = spy(List.class);
// BUG: Diagnostic contains:
List<String> genericSpy = spy(List.class);
var varSpy = spy(Integer.class);
Number variableTypeSpy = spy(numberType);
Object subtypeSpy = spy(Integer.class);
Object objectSpy = spy(new Object());
Objects.hash(mock(Integer.class));
Integer i = mock(mock(Integer.class));
String s = new String(mock(String.class));
}
Double getDoubleMock() {
return Objects.requireNonNullElseGet(
null,
() -> {
return mock(Double.class);
});
}
Integer getIntegerMock() {
// BUG: Diagnostic contains:
return mock(Integer.class);
}
<T> T getGenericMock(Class<T> clazz) {
return mock(clazz);
}
Number getSubTypeMock() {
return mock(Integer.class);
}
}
""")
.doTest();
}
@@ -99,38 +101,42 @@ final class MockitoMockClassReferenceTest {
BugCheckerRefactoringTestHelper.newInstance(MockitoMockClassReference.class, getClass())
.addInputLines(
"A.java",
"import static org.mockito.Mockito.mock;",
"import static org.mockito.Mockito.spy;",
"import static org.mockito.Mockito.withSettings;",
"",
"import org.mockito.invocation.InvocationOnMock;",
"",
"class A {",
" void m() {",
" Number simpleMock = mock(Number.class);",
" Number namedMock = mock(Number.class, \"name\");",
" Number customAnswerMock = mock(Number.class, InvocationOnMock::callRealMethod);",
" Number customSettingsMock = mock(Number.class, withSettings());",
" Number simpleSpy = spy(Number.class);",
" }",
"}")
"""
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.withSettings;
import org.mockito.invocation.InvocationOnMock;
class A {
void m() {
Number simpleMock = mock(Number.class);
Number namedMock = mock(Number.class, "name");
Number customAnswerMock = mock(Number.class, InvocationOnMock::callRealMethod);
Number customSettingsMock = mock(Number.class, withSettings());
Number simpleSpy = spy(Number.class);
}
}
""")
.addOutputLines(
"A.java",
"import static org.mockito.Mockito.mock;",
"import static org.mockito.Mockito.spy;",
"import static org.mockito.Mockito.withSettings;",
"",
"import org.mockito.invocation.InvocationOnMock;",
"",
"class A {",
" void m() {",
" Number simpleMock = mock();",
" Number namedMock = mock(\"name\");",
" Number customAnswerMock = mock(InvocationOnMock::callRealMethod);",
" Number customSettingsMock = mock(withSettings());",
" Number simpleSpy = spy();",
" }",
"}")
"""
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.withSettings;
import org.mockito.invocation.InvocationOnMock;
class A {
void m() {
Number simpleMock = mock();
Number namedMock = mock("name");
Number customAnswerMock = mock(InvocationOnMock::callRealMethod);
Number customSettingsMock = mock(withSettings());
Number simpleSpy = spy();
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,40 +11,42 @@ final class MockitoStubbingTest {
CompilationTestHelper.newInstance(MockitoStubbing.class, getClass())
.addSourceLines(
"A.java",
"import static org.mockito.ArgumentMatchers.eq;",
"import static org.mockito.ArgumentMatchers.notNull;",
"import static org.mockito.Mockito.doAnswer;",
"import static org.mockito.Mockito.mock;",
"",
"import java.util.function.BiConsumer;",
"import java.util.function.Consumer;",
"import org.mockito.ArgumentMatchers;",
"",
"class A {",
" void m() {",
" Runnable runnable = mock(Runnable.class);",
" doAnswer(inv -> null).when(runnable).run();",
"",
" Consumer<String> consumer = mock(Consumer.class);",
" doAnswer(inv -> null).when(consumer).accept(\"foo\");",
" doAnswer(inv -> null).when(consumer).accept(notNull());",
" // BUG: Diagnostic contains:",
" doAnswer(inv -> null).when(consumer).accept(ArgumentMatchers.eq(\"foo\"));",
" // BUG: Diagnostic contains:",
" doAnswer(inv -> null).when(consumer).accept(eq(toString()));",
"",
" BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);",
" doAnswer(inv -> null).when(biConsumer).accept(0, \"foo\");",
" doAnswer(inv -> null).when(biConsumer).accept(eq(0), notNull());",
" doAnswer(inv -> null).when(biConsumer).accept(notNull(), eq(\"foo\"));",
" doAnswer(inv -> null)",
" .when(biConsumer)",
" // BUG: Diagnostic contains:",
" .accept(ArgumentMatchers.eq(0), ArgumentMatchers.eq(\"foo\"));",
" // BUG: Diagnostic contains:",
" doAnswer(inv -> null).when(biConsumer).accept(eq(hashCode()), eq(toString()));",
" }",
"}")
"""
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.mockito.ArgumentMatchers;
class A {
void m() {
Runnable runnable = mock(Runnable.class);
doAnswer(inv -> null).when(runnable).run();
Consumer<String> consumer = mock(Consumer.class);
doAnswer(inv -> null).when(consumer).accept("foo");
doAnswer(inv -> null).when(consumer).accept(notNull());
// BUG: Diagnostic contains:
doAnswer(inv -> null).when(consumer).accept(ArgumentMatchers.eq("foo"));
// BUG: Diagnostic contains:
doAnswer(inv -> null).when(consumer).accept(eq(toString()));
BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);
doAnswer(inv -> null).when(biConsumer).accept(0, "foo");
doAnswer(inv -> null).when(biConsumer).accept(eq(0), notNull());
doAnswer(inv -> null).when(biConsumer).accept(notNull(), eq("foo"));
doAnswer(inv -> null)
.when(biConsumer)
// BUG: Diagnostic contains:
.accept(ArgumentMatchers.eq(0), ArgumentMatchers.eq("foo"));
// BUG: Diagnostic contains:
doAnswer(inv -> null).when(biConsumer).accept(eq(hashCode()), eq(toString()));
}
}
""")
.doTest();
}
@@ -53,48 +55,52 @@ final class MockitoStubbingTest {
BugCheckerRefactoringTestHelper.newInstance(MockitoStubbing.class, getClass())
.addInputLines(
"A.java",
"import static org.mockito.ArgumentMatchers.eq;",
"import static org.mockito.Mockito.doAnswer;",
"import static org.mockito.Mockito.mock;",
"",
"import java.util.function.BiConsumer;",
"import java.util.function.Consumer;",
"import org.mockito.ArgumentMatchers;",
"",
"class A {",
" void m() {",
" Consumer<String> consumer = mock(Consumer.class);",
" doAnswer(inv -> null).when(consumer).accept(ArgumentMatchers.eq(\"foo\"));",
" doAnswer(inv -> null).when(consumer).accept(eq(toString()));",
"",
" BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);",
" doAnswer(inv -> null)",
" .when(biConsumer)",
" .accept(ArgumentMatchers.eq(0), ArgumentMatchers.eq(\"foo\"));",
" doAnswer(inv -> null).when(biConsumer).accept(eq(hashCode()), eq(toString()));",
" }",
"}")
"""
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.mockito.ArgumentMatchers;
class A {
void m() {
Consumer<String> consumer = mock(Consumer.class);
doAnswer(inv -> null).when(consumer).accept(ArgumentMatchers.eq("foo"));
doAnswer(inv -> null).when(consumer).accept(eq(toString()));
BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);
doAnswer(inv -> null)
.when(biConsumer)
.accept(ArgumentMatchers.eq(0), ArgumentMatchers.eq("foo"));
doAnswer(inv -> null).when(biConsumer).accept(eq(hashCode()), eq(toString()));
}
}
""")
.addOutputLines(
"A.java",
"import static org.mockito.ArgumentMatchers.eq;",
"import static org.mockito.Mockito.doAnswer;",
"import static org.mockito.Mockito.mock;",
"",
"import java.util.function.BiConsumer;",
"import java.util.function.Consumer;",
"import org.mockito.ArgumentMatchers;",
"",
"class A {",
" void m() {",
" Consumer<String> consumer = mock(Consumer.class);",
" doAnswer(inv -> null).when(consumer).accept(\"foo\");",
" doAnswer(inv -> null).when(consumer).accept(toString());",
"",
" BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);",
" doAnswer(inv -> null).when(biConsumer).accept(0, \"foo\");",
" doAnswer(inv -> null).when(biConsumer).accept(hashCode(), toString());",
" }",
"}")
"""
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.mockito.ArgumentMatchers;
class A {
void m() {
Consumer<String> consumer = mock(Consumer.class);
doAnswer(inv -> null).when(consumer).accept("foo");
doAnswer(inv -> null).when(consumer).accept(toString());
BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);
doAnswer(inv -> null).when(biConsumer).accept(0, "foo");
doAnswer(inv -> null).when(biConsumer).accept(hashCode(), toString());
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -9,18 +9,20 @@ final class MongoDBTextFilterUsageTest {
CompilationTestHelper.newInstance(MongoDBTextFilterUsage.class, getClass())
.addSourceLines(
"A.java",
"import com.mongodb.client.model.Filters;",
"import com.mongodb.client.model.TextSearchOptions;",
"",
"class A {",
" void m() {",
" Filters.eq(\"foo\", \"bar\");",
" // BUG: Diagnostic contains:",
" Filters.text(\"foo\");",
" // BUG: Diagnostic contains:",
" Filters.text(\"foo\", new TextSearchOptions());",
" }",
"}")
"""
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.TextSearchOptions;
class A {
void m() {
Filters.eq("foo", "bar");
// BUG: Diagnostic contains:
Filters.text("foo");
// BUG: Diagnostic contains:
Filters.text("foo", new TextSearchOptions());
}
}
""")
.doTest();
}
}

View File

@@ -9,31 +9,33 @@ final class NestedOptionalsTest {
CompilationTestHelper.newInstance(NestedOptionals.class, getClass())
.addSourceLines(
"A.java",
"import java.util.Optional;",
"import java.util.stream.Stream;",
"",
"class A {",
" void m() {",
" Optional.empty();",
" Optional.of(1);",
" // BUG: Diagnostic contains:",
" Optional.of(Optional.empty());",
" // BUG: Diagnostic contains:",
" Optional.of(Optional.of(1));",
"",
" Optional.ofNullable(null);",
" // BUG: Diagnostic contains:",
" Optional.ofNullable((Optional) null);",
"",
" Optional.of(\"foo\").map(String::length);",
" // BUG: Diagnostic contains:",
" Optional.of(\"foo\").map(Optional::of);",
"",
" Stream.of(\"foo\").findFirst();",
" // BUG: Diagnostic contains:",
" Stream.of(\"foo\").map(Optional::of).findFirst();",
" }",
"}")
"""
import java.util.Optional;
import java.util.stream.Stream;
class A {
void m() {
Optional.empty();
Optional.of(1);
// BUG: Diagnostic contains:
Optional.of(Optional.empty());
// BUG: Diagnostic contains:
Optional.of(Optional.of(1));
Optional.ofNullable(null);
// BUG: Diagnostic contains:
Optional.ofNullable((Optional) null);
Optional.of("foo").map(String::length);
// BUG: Diagnostic contains:
Optional.of("foo").map(Optional::of);
Stream.of("foo").findFirst();
// BUG: Diagnostic contains:
Stream.of("foo").map(Optional::of).findFirst();
}
}
""")
.doTest();
}
}

View File

@@ -9,29 +9,31 @@ final class NestedPublishersTest {
CompilationTestHelper.newInstance(NestedPublishers.class, getClass())
.addSourceLines(
"A.java",
"import org.reactivestreams.Publisher;",
"import reactor.core.publisher.Flux;",
"import reactor.core.publisher.GroupedFlux;",
"import reactor.core.publisher.Mono;",
"",
"class A {",
" void m() {",
" Mono.empty();",
" Flux.just(1);",
" Flux.just(1, 2).groupBy(i -> i).map(groupedFlux -> (GroupedFlux) groupedFlux);",
"",
" // BUG: Diagnostic contains:",
" Mono.just(Mono.empty());",
" // BUG: Diagnostic contains:",
" Flux.just(Flux.empty());",
" // BUG: Diagnostic contains:",
" Mono.just((Flux) Flux.just(1));",
" // BUG: Diagnostic contains:",
" Flux.just((Publisher) Mono.just(1));",
" // BUG: Diagnostic contains:",
" Mono.just(1).map(Mono::just);",
" }",
"}")
"""
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.GroupedFlux;
import reactor.core.publisher.Mono;
class A {
void m() {
Mono.empty();
Flux.just(1);
Flux.just(1, 2).groupBy(i -> i).map(groupedFlux -> (GroupedFlux) groupedFlux);
// BUG: Diagnostic contains:
Mono.just(Mono.empty());
// BUG: Diagnostic contains:
Flux.just(Flux.empty());
// BUG: Diagnostic contains:
Mono.just((Flux) Flux.just(1));
// BUG: Diagnostic contains:
Flux.just((Publisher) Mono.just(1));
// BUG: Diagnostic contains:
Mono.just(1).map(Mono::just);
}
}
""")
.doTest();
}
}

View File

@@ -11,95 +11,97 @@ final class NonEmptyMonoTest {
CompilationTestHelper.newInstance(NonEmptyMono.class, getClass())
.addSourceLines(
"A.java",
"import static com.google.common.collect.ImmutableList.toImmutableList;",
"import static java.util.function.Function.identity;",
"",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableMap;",
"import java.util.ArrayList;",
"import java.util.HashMap;",
"import java.util.List;",
"import reactor.core.publisher.Flux;",
"import reactor.core.publisher.Mono;",
"",
"class A {",
" void m() {",
" Mono.just(1).defaultIfEmpty(2);",
" Mono.just(1).single();",
" Mono.just(1).switchIfEmpty(Mono.just(2));",
"",
" // BUG: Diagnostic contains:",
" Flux.just(1).all(x -> true).defaultIfEmpty(true);",
"",
" // BUG: Diagnostic contains:",
" Flux.just(1).any(x -> true).single();",
"",
" // BUG: Diagnostic contains:",
" Flux.just(1).collect(toImmutableList()).switchIfEmpty(Mono.just(ImmutableList.of()));",
" // BUG: Diagnostic contains:",
" Flux.just(1).collect(ArrayList::new, List::add).defaultIfEmpty(new ArrayList<>());",
"",
" // BUG: Diagnostic contains:",
" Flux.just(1).collectList().single();",
"",
" // BUG: Diagnostic contains:",
" Flux.just(1).collectMap(identity()).switchIfEmpty(Mono.just(ImmutableMap.of()));",
" // BUG: Diagnostic contains:",
" Flux.just(1).collectMap(identity(), identity()).defaultIfEmpty(ImmutableMap.of());",
" // BUG: Diagnostic contains:",
" Flux.just(1).collectMap(identity(), identity(), HashMap::new).single();",
"",
" // BUG: Diagnostic contains:",
" Flux.just(1).collectMultimap(identity()).switchIfEmpty(Mono.just(ImmutableMap.of()));",
" // BUG: Diagnostic contains:",
" Flux.just(1).collectMultimap(identity(), identity()).defaultIfEmpty(ImmutableMap.of());",
" // BUG: Diagnostic contains:",
" Flux.just(1).collectMultimap(identity(), identity(), HashMap::new).single();",
"",
" // BUG: Diagnostic contains:",
" Flux.just(1).collectSortedList().defaultIfEmpty(ImmutableList.of());",
" // BUG: Diagnostic contains:",
" Flux.just(1).collectSortedList((o1, o2) -> 0).single();",
"",
" // BUG: Diagnostic contains:",
" Flux.just(1).count().switchIfEmpty(Mono.just(2L));",
"",
" // BUG: Diagnostic contains:",
" Flux.just(1).elementAt(0).defaultIfEmpty(1);",
" // BUG: Diagnostic contains:",
" Flux.just(1).elementAt(0, 2).single();",
"",
" // BUG: Diagnostic contains:",
" Flux.just(1).hasElement(2).switchIfEmpty(Mono.just(true));",
"",
" // BUG: Diagnostic contains:",
" Flux.just(1).hasElements().defaultIfEmpty(true);",
"",
" // BUG: Diagnostic contains:",
" Flux.just(1).last().single();",
" // BUG: Diagnostic contains:",
" Flux.just(1).last(2).switchIfEmpty(Mono.just(3));",
"",
" // BUG: Diagnostic contains:",
" Flux.just(1).reduceWith(() -> 0, Integer::sum).defaultIfEmpty(2);",
"",
" // BUG: Diagnostic contains:",
" Flux.just(1).single().single();",
" // BUG: Diagnostic contains:",
" Flux.just(1).single(2).switchIfEmpty(Mono.just(3));",
"",
" Flux.just(1).reduce(Integer::sum).defaultIfEmpty(2);",
" // BUG: Diagnostic contains:",
" Flux.just(1).reduce(2, Integer::sum).single();",
"",
" // BUG: Diagnostic contains:",
" Mono.just(1).defaultIfEmpty(1).switchIfEmpty(Mono.just(2));",
" // BUG: Diagnostic contains:",
" Mono.just(1).hasElement().defaultIfEmpty(true);",
" // BUG: Diagnostic contains:",
" Mono.just(1).single().single();",
" }",
"}")
"""
import static com.google.common.collect.ImmutableList.toImmutableList;
import static java.util.function.Function.identity;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
class A {
void m() {
Mono.just(1).defaultIfEmpty(2);
Mono.just(1).single();
Mono.just(1).switchIfEmpty(Mono.just(2));
// BUG: Diagnostic contains:
Flux.just(1).all(x -> true).defaultIfEmpty(true);
// BUG: Diagnostic contains:
Flux.just(1).any(x -> true).single();
// BUG: Diagnostic contains:
Flux.just(1).collect(toImmutableList()).switchIfEmpty(Mono.just(ImmutableList.of()));
// BUG: Diagnostic contains:
Flux.just(1).collect(ArrayList::new, List::add).defaultIfEmpty(new ArrayList<>());
// BUG: Diagnostic contains:
Flux.just(1).collectList().single();
// BUG: Diagnostic contains:
Flux.just(1).collectMap(identity()).switchIfEmpty(Mono.just(ImmutableMap.of()));
// BUG: Diagnostic contains:
Flux.just(1).collectMap(identity(), identity()).defaultIfEmpty(ImmutableMap.of());
// BUG: Diagnostic contains:
Flux.just(1).collectMap(identity(), identity(), HashMap::new).single();
// BUG: Diagnostic contains:
Flux.just(1).collectMultimap(identity()).switchIfEmpty(Mono.just(ImmutableMap.of()));
// BUG: Diagnostic contains:
Flux.just(1).collectMultimap(identity(), identity()).defaultIfEmpty(ImmutableMap.of());
// BUG: Diagnostic contains:
Flux.just(1).collectMultimap(identity(), identity(), HashMap::new).single();
// BUG: Diagnostic contains:
Flux.just(1).collectSortedList().defaultIfEmpty(ImmutableList.of());
// BUG: Diagnostic contains:
Flux.just(1).collectSortedList((o1, o2) -> 0).single();
// BUG: Diagnostic contains:
Flux.just(1).count().switchIfEmpty(Mono.just(2L));
// BUG: Diagnostic contains:
Flux.just(1).elementAt(0).defaultIfEmpty(1);
// BUG: Diagnostic contains:
Flux.just(1).elementAt(0, 2).single();
// BUG: Diagnostic contains:
Flux.just(1).hasElement(2).switchIfEmpty(Mono.just(true));
// BUG: Diagnostic contains:
Flux.just(1).hasElements().defaultIfEmpty(true);
// BUG: Diagnostic contains:
Flux.just(1).last().single();
// BUG: Diagnostic contains:
Flux.just(1).last(2).switchIfEmpty(Mono.just(3));
// BUG: Diagnostic contains:
Flux.just(1).reduceWith(() -> 0, Integer::sum).defaultIfEmpty(2);
// BUG: Diagnostic contains:
Flux.just(1).single().single();
// BUG: Diagnostic contains:
Flux.just(1).single(2).switchIfEmpty(Mono.just(3));
Flux.just(1).reduce(Integer::sum).defaultIfEmpty(2);
// BUG: Diagnostic contains:
Flux.just(1).reduce(2, Integer::sum).single();
// BUG: Diagnostic contains:
Mono.just(1).defaultIfEmpty(1).switchIfEmpty(Mono.just(2));
// BUG: Diagnostic contains:
Mono.just(1).hasElement().defaultIfEmpty(true);
// BUG: Diagnostic contains:
Mono.just(1).single().single();
}
}
""")
.doTest();
}
@@ -108,42 +110,46 @@ final class NonEmptyMonoTest {
BugCheckerRefactoringTestHelper.newInstance(NonEmptyMono.class, getClass())
.addInputLines(
"A.java",
"import static com.google.common.collect.ImmutableList.toImmutableList;",
"",
"import com.google.common.collect.ImmutableList;",
"import reactor.core.publisher.Flux;",
"import reactor.core.publisher.Mono;",
"",
"class A {",
" void m() {",
" Flux.just(1).collect(toImmutableList()).single();",
" Flux.just(1).collect(toImmutableList()).defaultIfEmpty(ImmutableList.of());",
" Flux.just(1).collect(toImmutableList()).switchIfEmpty(Mono.just(ImmutableList.of()));",
"",
" Mono.just(2).hasElement().single();",
" Mono.just(2).hasElement().defaultIfEmpty(true);",
" Mono.just(2).hasElement().switchIfEmpty(Mono.just(true));",
" }",
"}")
"""
import static com.google.common.collect.ImmutableList.toImmutableList;
import com.google.common.collect.ImmutableList;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
class A {
void m() {
Flux.just(1).collect(toImmutableList()).single();
Flux.just(1).collect(toImmutableList()).defaultIfEmpty(ImmutableList.of());
Flux.just(1).collect(toImmutableList()).switchIfEmpty(Mono.just(ImmutableList.of()));
Mono.just(2).hasElement().single();
Mono.just(2).hasElement().defaultIfEmpty(true);
Mono.just(2).hasElement().switchIfEmpty(Mono.just(true));
}
}
""")
.addOutputLines(
"A.java",
"import static com.google.common.collect.ImmutableList.toImmutableList;",
"",
"import com.google.common.collect.ImmutableList;",
"import reactor.core.publisher.Flux;",
"import reactor.core.publisher.Mono;",
"",
"class A {",
" void m() {",
" Flux.just(1).collect(toImmutableList());",
" Flux.just(1).collect(toImmutableList());",
" Flux.just(1).collect(toImmutableList());",
"",
" Mono.just(2).hasElement();",
" Mono.just(2).hasElement();",
" Mono.just(2).hasElement();",
" }",
"}")
"""
import static com.google.common.collect.ImmutableList.toImmutableList;
import com.google.common.collect.ImmutableList;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
class A {
void m() {
Flux.just(1).collect(toImmutableList());
Flux.just(1).collect(toImmutableList());
Flux.just(1).collect(toImmutableList());
Mono.just(2).hasElement();
Mono.just(2).hasElement();
Mono.just(2).hasElement();
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -40,74 +40,76 @@ final class NonStaticImportTest {
CompilationTestHelper.newInstance(NonStaticImport.class, getClass())
.addSourceLines(
"pkg/A.java",
"package pkg;",
"",
"// BUG: Diagnostic contains:",
"import static com.google.common.base.Strings.nullToEmpty;",
"// BUG: Diagnostic contains:",
"import static com.google.common.collect.ImmutableList.copyOf;",
"// BUG: Diagnostic contains:",
"import static java.lang.Integer.MAX_VALUE;",
"// BUG: Diagnostic contains:",
"import static java.lang.Integer.MIN_VALUE;",
"// BUG: Diagnostic contains:",
"import static java.time.Clock.systemUTC;",
"// BUG: Diagnostic contains:",
"import static java.time.Instant.MIN;",
"// BUG: Diagnostic contains:",
"import static java.time.ZoneOffset.SHORT_IDS;",
"import static java.time.ZoneOffset.UTC;",
"// BUG: Diagnostic contains:",
"import static java.util.Collections.min;",
"import static java.util.Locale.ENGLISH;",
"// BUG: Diagnostic contains:",
"import static java.util.Locale.ROOT;",
"// BUG: Diagnostic contains:",
"import static java.util.Optional.empty;",
"import static pkg.A.WithMethodThatIsSelectivelyFlagged.list;",
"// BUG: Diagnostic contains:",
"import static reactor.core.publisher.Flux.just;",
"",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableSet;",
"import java.time.Instant;",
"import java.time.ZoneOffset;",
"import java.util.Locale;",
"import java.util.Map;",
"import pkg.A.Wrapper.INSTANCE;",
"",
"class A {",
" private Integer MIN_VALUE = 12;",
"",
" void m() {",
" nullToEmpty(null);",
" copyOf(ImmutableList.of());",
" int max = MAX_VALUE;",
" int min = MIN_VALUE;",
" systemUTC();",
" Instant minInstant = MIN;",
" Map<String, String> shortIds = SHORT_IDS;",
" ZoneOffset utc = UTC;",
" min(ImmutableSet.of());",
" Locale english = ENGLISH;",
" Locale root = ROOT;",
" empty();",
" just();",
"",
" list();",
" new INSTANCE();",
" }",
"",
" static final class WithMethodThatIsSelectivelyFlagged {",
" static ImmutableList<String> list() {",
" return ImmutableList.of();",
" }",
" }",
"",
" static final class Wrapper {",
" static final class INSTANCE {}",
" }",
"}")
"""
package pkg;
// BUG: Diagnostic contains:
import static com.google.common.base.Strings.nullToEmpty;
// BUG: Diagnostic contains:
import static com.google.common.collect.ImmutableList.copyOf;
// BUG: Diagnostic contains:
import static java.lang.Integer.MAX_VALUE;
// BUG: Diagnostic contains:
import static java.lang.Integer.MIN_VALUE;
// BUG: Diagnostic contains:
import static java.time.Clock.systemUTC;
// BUG: Diagnostic contains:
import static java.time.Instant.MIN;
// BUG: Diagnostic contains:
import static java.time.ZoneOffset.SHORT_IDS;
import static java.time.ZoneOffset.UTC;
// BUG: Diagnostic contains:
import static java.util.Collections.min;
import static java.util.Locale.ENGLISH;
// BUG: Diagnostic contains:
import static java.util.Locale.ROOT;
// BUG: Diagnostic contains:
import static java.util.Optional.empty;
import static pkg.A.WithMethodThatIsSelectivelyFlagged.list;
// BUG: Diagnostic contains:
import static reactor.core.publisher.Flux.just;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.Locale;
import java.util.Map;
import pkg.A.Wrapper.INSTANCE;
class A {
private Integer MIN_VALUE = 12;
void m() {
nullToEmpty(null);
copyOf(ImmutableList.of());
int max = MAX_VALUE;
int min = MIN_VALUE;
systemUTC();
Instant minInstant = MIN;
Map<String, String> shortIds = SHORT_IDS;
ZoneOffset utc = UTC;
min(ImmutableSet.of());
Locale english = ENGLISH;
Locale root = ROOT;
empty();
just();
list();
new INSTANCE();
}
static final class WithMethodThatIsSelectivelyFlagged {
static ImmutableList<String> list() {
return ImmutableList.of();
}
}
static final class Wrapper {
static final class INSTANCE {}
}
}
""")
.doTest();
}
@@ -116,84 +118,88 @@ final class NonStaticImportTest {
BugCheckerRefactoringTestHelper.newInstance(NonStaticImport.class, getClass())
.addInputLines(
"A.java",
"import static com.google.common.collect.ImmutableList.copyOf;",
"import static com.google.common.collect.ImmutableSet.of;",
"import static java.time.Clock.systemUTC;",
"import static java.time.Instant.MAX;",
"import static java.time.Instant.MIN;",
"import static java.util.Collections.min;",
"import static java.util.Locale.ROOT;",
"import static java.util.Optional.empty;",
"",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableSet;",
"import java.time.Clock;",
"import java.time.Instant;",
"import java.util.Locale;",
"import java.util.Optional;",
"",
"class A {",
" void m() {",
" systemUTC();",
" Clock.systemUTC();",
"",
" Optional<Integer> o1 = empty();",
" Optional<Integer> o2 = Optional.empty();",
"",
" Object l1 = copyOf(ImmutableList.of());",
" Object l2 = ImmutableList.copyOf(ImmutableList.of());",
"",
" Locale lo1 = ROOT;",
" Locale lo2 = Locale.ROOT;",
"",
" Instant i1 = MIN;",
" Instant i2 = MAX;",
"",
" ImmutableSet.of(min(of()));",
" }",
"",
" private static final class WithCustomConstant {",
" private static final Instant MIN = Instant.EPOCH;",
" private static final Instant OTHER = MIN;",
" private static final Instant OTHER_MAX = MAX;",
" }",
"}")
"""
import static com.google.common.collect.ImmutableList.copyOf;
import static com.google.common.collect.ImmutableSet.of;
import static java.time.Clock.systemUTC;
import static java.time.Instant.MAX;
import static java.time.Instant.MIN;
import static java.util.Collections.min;
import static java.util.Locale.ROOT;
import static java.util.Optional.empty;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.time.Clock;
import java.time.Instant;
import java.util.Locale;
import java.util.Optional;
class A {
void m() {
systemUTC();
Clock.systemUTC();
Optional<Integer> o1 = empty();
Optional<Integer> o2 = Optional.empty();
Object l1 = copyOf(ImmutableList.of());
Object l2 = ImmutableList.copyOf(ImmutableList.of());
Locale lo1 = ROOT;
Locale lo2 = Locale.ROOT;
Instant i1 = MIN;
Instant i2 = MAX;
ImmutableSet.of(min(of()));
}
private static final class WithCustomConstant {
private static final Instant MIN = Instant.EPOCH;
private static final Instant OTHER = MIN;
private static final Instant OTHER_MAX = MAX;
}
}
""")
.addOutputLines(
"A.java",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableSet;",
"import java.time.Clock;",
"import java.time.Instant;",
"import java.util.Collections;",
"import java.util.Locale;",
"import java.util.Optional;",
"",
"class A {",
" void m() {",
" Clock.systemUTC();",
" Clock.systemUTC();",
"",
" Optional<Integer> o1 = Optional.empty();",
" Optional<Integer> o2 = Optional.empty();",
"",
" Object l1 = ImmutableList.copyOf(ImmutableList.of());",
" Object l2 = ImmutableList.copyOf(ImmutableList.of());",
"",
" Locale lo1 = Locale.ROOT;",
" Locale lo2 = Locale.ROOT;",
"",
" Instant i1 = Instant.MIN;",
" Instant i2 = Instant.MAX;",
"",
" ImmutableSet.of(Collections.min(ImmutableSet.of()));",
" }",
"",
" private static final class WithCustomConstant {",
" private static final Instant MIN = Instant.EPOCH;",
" private static final Instant OTHER = MIN;",
" private static final Instant OTHER_MAX = Instant.MAX;",
" }",
"}")
"""
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.time.Clock;
import java.time.Instant;
import java.util.Collections;
import java.util.Locale;
import java.util.Optional;
class A {
void m() {
Clock.systemUTC();
Clock.systemUTC();
Optional<Integer> o1 = Optional.empty();
Optional<Integer> o2 = Optional.empty();
Object l1 = ImmutableList.copyOf(ImmutableList.of());
Object l2 = ImmutableList.copyOf(ImmutableList.of());
Locale lo1 = Locale.ROOT;
Locale lo2 = Locale.ROOT;
Instant i1 = Instant.MIN;
Instant i2 = Instant.MAX;
ImmutableSet.of(Collections.min(ImmutableSet.of()));
}
private static final class WithCustomConstant {
private static final Instant MIN = Instant.EPOCH;
private static final Instant OTHER = MIN;
private static final Instant OTHER_MAX = Instant.MAX;
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,59 +11,61 @@ final class OptionalOrElseGetTest {
CompilationTestHelper.newInstance(OptionalOrElseGet.class, getClass())
.addSourceLines(
"A.java",
"import com.google.errorprone.refaster.Refaster;",
"import java.util.Optional;",
"import java.util.function.Supplier;",
"",
"class A {",
" private final Optional<Object> optional = Optional.empty();",
" private final String string = optional.toString();",
"",
" void m() {",
" Optional.empty().orElse(null);",
" optional.orElse(null);",
" optional.orElse(\"constant\");",
" optional.orElse(\"constant\" + 0);",
" optional.orElse(Boolean.TRUE);",
" optional.orElse(string);",
" optional.orElse(this.string);",
" optional.orElse(Refaster.anyOf(\"constant\", \"another\"));",
" Optional.<Supplier<String>>empty().orElse(() -> \"constant\");",
"",
" // BUG: Diagnostic contains:",
" Optional.empty().orElse(string + \"constant\");",
" // BUG: Diagnostic contains:",
" optional.orElse(string + \"constant\");",
" // BUG: Diagnostic contains:",
" optional.orElse(\"constant\".toString());",
" // BUG: Diagnostic contains:",
" optional.orElse(string.toString());",
" // BUG: Diagnostic contains:",
" optional.orElse(this.string.toString());",
" // BUG: Diagnostic contains:",
" optional.orElse(String.valueOf(42));",
" // BUG: Diagnostic contains:",
" optional.orElse(string.toString().length());",
" // BUG: Diagnostic contains:",
" optional.orElse(\"constant\".equals(string));",
" // BUG: Diagnostic contains:",
" optional.orElse(string.equals(string));",
" // BUG: Diagnostic contains:",
" optional.orElse(this.string.equals(string));",
" // BUG: Diagnostic contains:",
" optional.orElse(foo());",
" // BUG: Diagnostic contains:",
" optional.orElse(this.foo());",
" // BUG: Diagnostic contains:",
" optional.orElse(new Object() {});",
" // BUG: Diagnostic contains:",
" optional.orElse(new int[0].length);",
" }",
"",
" private <T> T foo() {",
" return null;",
" }",
"}")
"""
import com.google.errorprone.refaster.Refaster;
import java.util.Optional;
import java.util.function.Supplier;
class A {
private final Optional<Object> optional = Optional.empty();
private final String string = optional.toString();
void m() {
Optional.empty().orElse(null);
optional.orElse(null);
optional.orElse("constant");
optional.orElse("constant" + 0);
optional.orElse(Boolean.TRUE);
optional.orElse(string);
optional.orElse(this.string);
optional.orElse(Refaster.anyOf("constant", "another"));
Optional.<Supplier<String>>empty().orElse(() -> "constant");
// BUG: Diagnostic contains:
Optional.empty().orElse(string + "constant");
// BUG: Diagnostic contains:
optional.orElse(string + "constant");
// BUG: Diagnostic contains:
optional.orElse("constant".toString());
// BUG: Diagnostic contains:
optional.orElse(string.toString());
// BUG: Diagnostic contains:
optional.orElse(this.string.toString());
// BUG: Diagnostic contains:
optional.orElse(String.valueOf(42));
// BUG: Diagnostic contains:
optional.orElse(string.toString().length());
// BUG: Diagnostic contains:
optional.orElse("constant".equals(string));
// BUG: Diagnostic contains:
optional.orElse(string.equals(string));
// BUG: Diagnostic contains:
optional.orElse(this.string.equals(string));
// BUG: Diagnostic contains:
optional.orElse(foo());
// BUG: Diagnostic contains:
optional.orElse(this.foo());
// BUG: Diagnostic contains:
optional.orElse(new Object() {});
// BUG: Diagnostic contains:
optional.orElse(new int[0].length);
}
private <T> T foo() {
return null;
}
}
""")
.doTest();
}
@@ -72,66 +74,70 @@ final class OptionalOrElseGetTest {
BugCheckerRefactoringTestHelper.newInstance(OptionalOrElseGet.class, getClass())
.addInputLines(
"A.java",
"import java.util.Optional;",
"",
"class A {",
" private final Optional<Object> optional = Optional.empty();",
" private final String string = optional.toString();",
"",
" void m() {",
" optional.orElse(string + \"constant\");",
" optional.orElse(\"constant\".toString());",
" optional.orElse(string.toString());",
" optional.orElse(this.string.toString());",
" optional.orElse(String.valueOf(42));",
" optional.orElse(string.toString().length());",
" optional.orElse(string.equals(string));",
" optional.orElse(foo());",
" optional.orElse(this.<Number>foo());",
" optional.orElse(this.<String, Integer>bar());",
" optional.orElse(new Object() {});",
" optional.orElse(new int[0].length);",
" }",
"",
" private <T> T foo() {",
" return null;",
" }",
"",
" private <S, T> T bar() {",
" return null;",
" }",
"}")
"""
import java.util.Optional;
class A {
private final Optional<Object> optional = Optional.empty();
private final String string = optional.toString();
void m() {
optional.orElse(string + "constant");
optional.orElse("constant".toString());
optional.orElse(string.toString());
optional.orElse(this.string.toString());
optional.orElse(String.valueOf(42));
optional.orElse(string.toString().length());
optional.orElse(string.equals(string));
optional.orElse(foo());
optional.orElse(this.<Number>foo());
optional.orElse(this.<String, Integer>bar());
optional.orElse(new Object() {});
optional.orElse(new int[0].length);
}
private <T> T foo() {
return null;
}
private <S, T> T bar() {
return null;
}
}
""")
.addOutputLines(
"A.java",
"import java.util.Optional;",
"",
"class A {",
" private final Optional<Object> optional = Optional.empty();",
" private final String string = optional.toString();",
"",
" void m() {",
" optional.orElseGet(() -> string + \"constant\");",
" optional.orElseGet(\"constant\"::toString);",
" optional.orElseGet(string::toString);",
" optional.orElseGet(this.string::toString);",
" optional.orElseGet(() -> String.valueOf(42));",
" optional.orElseGet(() -> string.toString().length());",
" optional.orElseGet(() -> string.equals(string));",
" optional.orElseGet(() -> foo());",
" optional.orElseGet(this::<Number>foo);",
" optional.orElseGet(this::<String, Integer>bar);",
" optional.orElseGet(() -> new Object() {});",
" optional.orElseGet(() -> new int[0].length);",
" }",
"",
" private <T> T foo() {",
" return null;",
" }",
"",
" private <S, T> T bar() {",
" return null;",
" }",
"}")
"""
import java.util.Optional;
class A {
private final Optional<Object> optional = Optional.empty();
private final String string = optional.toString();
void m() {
optional.orElseGet(() -> string + "constant");
optional.orElseGet("constant"::toString);
optional.orElseGet(string::toString);
optional.orElseGet(this.string::toString);
optional.orElseGet(() -> String.valueOf(42));
optional.orElseGet(() -> string.toString().length());
optional.orElseGet(() -> string.equals(string));
optional.orElseGet(() -> foo());
optional.orElseGet(this::<Number>foo);
optional.orElseGet(this::<String, Integer>bar);
optional.orElseGet(() -> new Object() {});
optional.orElseGet(() -> new int[0].length);
}
private <T> T foo() {
return null;
}
private <S, T> T bar() {
return null;
}
}
""")
.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;
@@ -15,21 +14,23 @@ final class RedundantStringConversionTest {
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addSourceLines(
"A.java",
"class A {",
" private final Object o = new Object();",
" private final String s = o.toString();",
"",
" String[] m() {",
" return new String[] {",
" o.toString(),",
" // BUG: Diagnostic contains:",
" s.toString(),",
" String.valueOf(o),",
" // BUG: Diagnostic contains:",
" String.valueOf(s),",
" };",
" }",
"}")
"""
class A {
private final Object o = new Object();
private final String s = o.toString();
String[] m() {
return new String[] {
o.toString(),
// BUG: Diagnostic contains:
s.toString(),
String.valueOf(o),
// BUG: Diagnostic contains:
String.valueOf(s),
};
}
}
""")
.doTest();
}
@@ -38,59 +39,61 @@ final class RedundantStringConversionTest {
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addSourceLines(
"A.java",
"import java.math.BigInteger;",
"import java.util.Objects;",
"",
"class A {",
" private final BigInteger i = BigInteger.ZERO;",
"",
" void m1() {",
" String s = i.toString();",
" // BUG: Diagnostic contains:",
" s += this.toString();",
" s += super.toString();",
" // BUG: Diagnostic contains:",
" s += i.toString();",
" s += i.toString(16);",
" // BUG: Diagnostic contains:",
" s += Objects.toString(i);",
" // BUG: Diagnostic contains:",
" s += Objects.toString(null);",
" // BUG: Diagnostic contains:",
" s += String.valueOf(i);",
" // BUG: Diagnostic contains:",
" s += String.valueOf(0);",
" // BUG: Diagnostic contains:",
" s += String.valueOf((String) null);",
" s += String.valueOf(null);",
" s += String.valueOf(new char[0]);",
" s += String.valueOf(new char[0], 0, 0);",
" // BUG: Diagnostic contains:",
" s += Boolean.toString(false);",
" // BUG: Diagnostic contains:",
" s += Byte.toString((byte) 0);",
" // BUG: Diagnostic contains:",
" s += Character.toString((char) 0);",
" // BUG: Diagnostic contains:",
" s += Short.toString((short) 0);",
" // BUG: Diagnostic contains:",
" s += Integer.toString(0);",
" // BUG: Diagnostic contains:",
" s += Long.toString(0);",
" // BUG: Diagnostic contains:",
" s += Float.toString((float) 0.0);",
" // BUG: Diagnostic contains:",
" s += Double.toString(0.0);",
" }",
"",
" void m2() {",
" int i = 0;",
" i += 1;",
" i -= 1;",
" i *= 1;",
" i /= 1;",
" }",
"}")
"""
import java.math.BigInteger;
import java.util.Objects;
class A {
private final BigInteger i = BigInteger.ZERO;
void m1() {
String s = i.toString();
// BUG: Diagnostic contains:
s += this.toString();
s += super.toString();
// BUG: Diagnostic contains:
s += i.toString();
s += i.toString(16);
// BUG: Diagnostic contains:
s += Objects.toString(i);
// BUG: Diagnostic contains:
s += Objects.toString(null);
// BUG: Diagnostic contains:
s += String.valueOf(i);
// BUG: Diagnostic contains:
s += String.valueOf(0);
// BUG: Diagnostic contains:
s += String.valueOf((String) null);
s += String.valueOf(null);
s += String.valueOf(new char[0]);
s += String.valueOf(new char[0], 0, 0);
// BUG: Diagnostic contains:
s += Boolean.toString(false);
// BUG: Diagnostic contains:
s += Byte.toString((byte) 0);
// BUG: Diagnostic contains:
s += Character.toString((char) 0);
// BUG: Diagnostic contains:
s += Short.toString((short) 0);
// BUG: Diagnostic contains:
s += Integer.toString(0);
// BUG: Diagnostic contains:
s += Long.toString(0);
// BUG: Diagnostic contains:
s += Float.toString((float) 0.0);
// BUG: Diagnostic contains:
s += Double.toString(0.0);
}
void m2() {
int i = 0;
i += 1;
i -= 1;
i *= 1;
i /= 1;
}
}
""")
.doTest();
}
@@ -99,93 +102,95 @@ final class RedundantStringConversionTest {
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addSourceLines(
"A.java",
"import java.math.BigInteger;",
"",
"class A {",
" private final BigInteger i = BigInteger.ZERO;",
" private final String s = i.toString();",
"",
" String[] m1() {",
" return new String[] {",
" // BUG: Diagnostic contains:",
" s + this.toString(),",
" s + super.toString(),",
" // BUG: Diagnostic contains:",
" s + i.toString(),",
" s + i.toString(16),",
" // BUG: Diagnostic contains:",
" s + String.valueOf(i),",
" // BUG: Diagnostic contains:",
" s + String.valueOf(0),",
" // BUG: Diagnostic contains:",
" s + String.valueOf((String) null),",
" s + String.valueOf(null),",
" s + String.valueOf(new char[0]),",
" s + String.valueOf(new char[0], 0, 0),",
" //",
" 42 + this.toString(),",
" 42 + super.toString(),",
" 42 + i.toString(),",
" 42 + i.toString(16),",
" 42 + String.valueOf(i),",
" // BUG: Diagnostic contains:",
" 42 + String.valueOf((String) null),",
" 42 + String.valueOf(null),",
" 42 + String.valueOf(new char[0]),",
" 42 + String.valueOf(new char[0], 0, 0),",
"",
" // BUG: Diagnostic contains:",
" this.toString() + s,",
" super.toString() + s,",
" // BUG: Diagnostic contains:",
" i.toString() + s,",
" i.toString(16) + s,",
" // BUG: Diagnostic contains:",
" String.valueOf(i) + s,",
" // BUG: Diagnostic contains:",
" String.valueOf(0) + s,",
" // BUG: Diagnostic contains:",
" String.valueOf((String) null) + s,",
" String.valueOf(null) + s,",
" String.valueOf(new char[0]) + s,",
" String.valueOf(new char[0], 0, 0) + s,",
" //",
" this.toString() + 42,",
" super.toString() + 42,",
" i.toString() + 42,",
" i.toString(16) + 42,",
" String.valueOf(i) + 42,",
" String.valueOf(0) + 42,",
" // BUG: Diagnostic contains:",
" String.valueOf((String) null) + 42,",
" String.valueOf(null) + 42,",
" String.valueOf(new char[0]) + 42,",
" String.valueOf(new char[0], 0, 0) + 42,",
"",
" // BUG: Diagnostic contains:",
" this.toString() + this.toString(),",
" super.toString() + super.toString(),",
" // BUG: Diagnostic contains:",
" i.toString() + i.toString(),",
" i.toString(16) + i.toString(16),",
" // BUG: Diagnostic contains:",
" String.valueOf(i) + String.valueOf(i),",
" // BUG: Diagnostic contains:",
" String.valueOf(0) + String.valueOf(0),",
" // BUG: Diagnostic contains:",
" String.valueOf((String) null) + String.valueOf((String) null),",
" String.valueOf(null) + String.valueOf(null),",
" String.valueOf(new char[0]) + String.valueOf(new char[0]),",
" String.valueOf(new char[0], 0, 0) + String.valueOf(new char[0], 0, 0),",
" };",
" }",
"",
" int[] m2() {",
" return new int[] {",
" 1 + 1, 1 - 1, 1 * 1, 1 / 1,",
" };",
" }",
"}")
"""
import java.math.BigInteger;
class A {
private final BigInteger i = BigInteger.ZERO;
private final String s = i.toString();
String[] m1() {
return new String[] {
// BUG: Diagnostic contains:
s + this.toString(),
s + super.toString(),
// BUG: Diagnostic contains:
s + i.toString(),
s + i.toString(16),
// BUG: Diagnostic contains:
s + String.valueOf(i),
// BUG: Diagnostic contains:
s + String.valueOf(0),
// BUG: Diagnostic contains:
s + String.valueOf((String) null),
s + String.valueOf(null),
s + String.valueOf(new char[0]),
s + String.valueOf(new char[0], 0, 0),
//
42 + this.toString(),
42 + super.toString(),
42 + i.toString(),
42 + i.toString(16),
42 + String.valueOf(i),
// BUG: Diagnostic contains:
42 + String.valueOf((String) null),
42 + String.valueOf(null),
42 + String.valueOf(new char[0]),
42 + String.valueOf(new char[0], 0, 0),
// BUG: Diagnostic contains:
this.toString() + s,
super.toString() + s,
// BUG: Diagnostic contains:
i.toString() + s,
i.toString(16) + s,
// BUG: Diagnostic contains:
String.valueOf(i) + s,
// BUG: Diagnostic contains:
String.valueOf(0) + s,
// BUG: Diagnostic contains:
String.valueOf((String) null) + s,
String.valueOf(null) + s,
String.valueOf(new char[0]) + s,
String.valueOf(new char[0], 0, 0) + s,
//
this.toString() + 42,
super.toString() + 42,
i.toString() + 42,
i.toString(16) + 42,
String.valueOf(i) + 42,
String.valueOf(0) + 42,
// BUG: Diagnostic contains:
String.valueOf((String) null) + 42,
String.valueOf(null) + 42,
String.valueOf(new char[0]) + 42,
String.valueOf(new char[0], 0, 0) + 42,
// BUG: Diagnostic contains:
this.toString() + this.toString(),
super.toString() + super.toString(),
// BUG: Diagnostic contains:
i.toString() + i.toString(),
i.toString(16) + i.toString(16),
// BUG: Diagnostic contains:
String.valueOf(i) + String.valueOf(i),
// BUG: Diagnostic contains:
String.valueOf(0) + String.valueOf(0),
// BUG: Diagnostic contains:
String.valueOf((String) null) + String.valueOf((String) null),
String.valueOf(null) + String.valueOf(null),
String.valueOf(new char[0]) + String.valueOf(new char[0]),
String.valueOf(new char[0], 0, 0) + String.valueOf(new char[0], 0, 0),
};
}
int[] m2() {
return new int[] {
1 + 1, 1 - 1, 1 * 1, 1 / 1,
};
}
}
""")
.doTest();
}
@@ -194,52 +199,54 @@ final class RedundantStringConversionTest {
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addSourceLines(
"A.java",
"import java.math.BigInteger;",
"",
"class A {",
" private final BigInteger i = BigInteger.ZERO;",
" private final String s = i.toString();",
"",
" void m() {",
" StringBuilder sb = new StringBuilder();",
"",
" sb.append(1);",
" sb.append(i);",
" // BUG: Diagnostic contains:",
" sb.append(i.toString());",
" sb.append(i.toString(16));",
" // BUG: Diagnostic contains:",
" sb.append(String.valueOf(i));",
" // BUG: Diagnostic contains:",
" sb.append(String.valueOf(0));",
" // BUG: Diagnostic contains:",
" sb.append(String.valueOf((String) null));",
" sb.append(String.valueOf(null));",
" sb.append(String.valueOf(new char[0]));",
" sb.append(String.valueOf(new char[0], 0, 0));",
" sb.append(s);",
" sb.append(\"constant\");",
"",
" sb.insert(0, 1);",
" sb.insert(0, i);",
" // BUG: Diagnostic contains:",
" sb.insert(0, i.toString());",
" sb.insert(0, i.toString(16));",
" // BUG: Diagnostic contains:",
" sb.insert(0, String.valueOf(i));",
" // BUG: Diagnostic contains:",
" sb.insert(0, String.valueOf(0));",
" // BUG: Diagnostic contains:",
" sb.insert(0, String.valueOf((String) null));",
" sb.insert(0, String.valueOf(null));",
" sb.insert(0, String.valueOf(new char[0]));",
" sb.insert(0, String.valueOf(new char[0], 0, 0));",
" sb.insert(0, s);",
" sb.insert(0, \"constant\");",
"",
" sb.replace(0, 1, i.toString());",
" }",
"}")
"""
import java.math.BigInteger;
class A {
private final BigInteger i = BigInteger.ZERO;
private final String s = i.toString();
void m() {
StringBuilder sb = new StringBuilder();
sb.append(1);
sb.append(i);
// BUG: Diagnostic contains:
sb.append(i.toString());
sb.append(i.toString(16));
// BUG: Diagnostic contains:
sb.append(String.valueOf(i));
// BUG: Diagnostic contains:
sb.append(String.valueOf(0));
// BUG: Diagnostic contains:
sb.append(String.valueOf((String) null));
sb.append(String.valueOf(null));
sb.append(String.valueOf(new char[0]));
sb.append(String.valueOf(new char[0], 0, 0));
sb.append(s);
sb.append("constant");
sb.insert(0, 1);
sb.insert(0, i);
// BUG: Diagnostic contains:
sb.insert(0, i.toString());
sb.insert(0, i.toString(16));
// BUG: Diagnostic contains:
sb.insert(0, String.valueOf(i));
// BUG: Diagnostic contains:
sb.insert(0, String.valueOf(0));
// BUG: Diagnostic contains:
sb.insert(0, String.valueOf((String) null));
sb.insert(0, String.valueOf(null));
sb.insert(0, String.valueOf(new char[0]));
sb.insert(0, String.valueOf(new char[0], 0, 0));
sb.insert(0, s);
sb.insert(0, "constant");
sb.replace(0, 1, i.toString());
}
}
""")
.doTest();
}
@@ -249,43 +256,45 @@ final class RedundantStringConversionTest {
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addSourceLines(
"A.java",
"import java.util.Formattable;",
"import java.util.Locale;",
"",
"class A {",
" private final Locale locale = Locale.ROOT;",
" private final Formattable f = (formatter, flags, width, precision) -> {};",
" private final Object o = new Object();",
" private final String s = o.toString();",
"",
" void m() {",
" String.format(s, f);",
" String.format(s, o);",
" String.format(s, s);",
" String.format(s, f.toString());",
" // BUG: Diagnostic contains:",
" String.format(s, o.toString());",
" // BUG: Diagnostic contains:",
" String.format(s, String.valueOf(o));",
"",
" String.format(locale, s, f);",
" String.format(locale, s, o);",
" String.format(locale, s, s);",
" String.format(locale, s, f.toString());",
" // BUG: Diagnostic contains:",
" String.format(locale, s, o.toString());",
" // BUG: Diagnostic contains:",
" String.format(locale, s, String.valueOf(o));",
"",
" String.format(o.toString(), o);",
" // BUG: Diagnostic contains:",
" String.format(s.toString(), o);",
" String.format(locale.toString(), s, o);",
" String.format(locale, o.toString(), o);",
" // BUG: Diagnostic contains:",
" String.format(locale, s.toString(), o);",
" }",
"}")
"""
import java.util.Formattable;
import java.util.Locale;
class A {
private final Locale locale = Locale.ROOT;
private final Formattable f = (formatter, flags, width, precision) -> {};
private final Object o = new Object();
private final String s = o.toString();
void m() {
String.format(s, f);
String.format(s, o);
String.format(s, s);
String.format(s, f.toString());
// BUG: Diagnostic contains:
String.format(s, o.toString());
// BUG: Diagnostic contains:
String.format(s, String.valueOf(o));
String.format(locale, s, f);
String.format(locale, s, o);
String.format(locale, s, s);
String.format(locale, s, f.toString());
// BUG: Diagnostic contains:
String.format(locale, s, o.toString());
// BUG: Diagnostic contains:
String.format(locale, s, String.valueOf(o));
String.format(o.toString(), o);
// BUG: Diagnostic contains:
String.format(s.toString(), o);
String.format(locale.toString(), s, o);
String.format(locale, o.toString(), o);
// BUG: Diagnostic contains:
String.format(locale, s.toString(), o);
}
}
""")
.doTest();
}
@@ -294,58 +303,60 @@ final class RedundantStringConversionTest {
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addSourceLines(
"A.java",
"import static com.google.common.base.Preconditions.checkArgument;",
"import static com.google.common.base.Preconditions.checkNotNull;",
"import static com.google.common.base.Preconditions.checkState;",
"import static com.google.common.base.Verify.verify;",
"import static com.google.common.base.Verify.verifyNotNull;",
"",
"import java.util.Formattable;",
"",
"class A {",
" private final Formattable f = (formatter, flags, width, precision) -> {};",
" private final Object o = new Object();",
" private final String s = o.toString();",
"",
" void m() {",
" checkState(true, s, f);",
" // BUG: Diagnostic contains:",
" checkState(true, s, f.toString());",
" checkState(true, f.toString(), f);",
" // BUG: Diagnostic contains:",
" checkState(true, s.toString(), f);",
"",
" checkArgument(true, s, f);",
" // BUG: Diagnostic contains:",
" checkArgument(true, s, f.toString());",
" checkArgument(true, f.toString(), f);",
" // BUG: Diagnostic contains:",
" checkArgument(true, s.toString(), f);",
"",
" checkNotNull(o, s, f);",
" // BUG: Diagnostic contains:",
" checkNotNull(o, s, f.toString());",
" checkNotNull(o, f.toString(), f);",
" // BUG: Diagnostic contains:",
" checkNotNull(o, s.toString(), f);",
" checkNotNull(o.toString(), s, f);",
"",
" verify(true, s, f);",
" // BUG: Diagnostic contains:",
" verify(true, s, f.toString());",
" verify(true, f.toString(), f);",
" // BUG: Diagnostic contains:",
" verify(true, s.toString(), f);",
"",
" verifyNotNull(o, s, f);",
" // BUG: Diagnostic contains:",
" verifyNotNull(o, s, f.toString());",
" verifyNotNull(o, f.toString(), f);",
" // BUG: Diagnostic contains:",
" verifyNotNull(o, s.toString(), f);",
" verifyNotNull(o.toString(), s, f);",
" }",
"}")
"""
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Verify.verify;
import static com.google.common.base.Verify.verifyNotNull;
import java.util.Formattable;
class A {
private final Formattable f = (formatter, flags, width, precision) -> {};
private final Object o = new Object();
private final String s = o.toString();
void m() {
checkState(true, s, f);
// BUG: Diagnostic contains:
checkState(true, s, f.toString());
checkState(true, f.toString(), f);
// BUG: Diagnostic contains:
checkState(true, s.toString(), f);
checkArgument(true, s, f);
// BUG: Diagnostic contains:
checkArgument(true, s, f.toString());
checkArgument(true, f.toString(), f);
// BUG: Diagnostic contains:
checkArgument(true, s.toString(), f);
checkNotNull(o, s, f);
// BUG: Diagnostic contains:
checkNotNull(o, s, f.toString());
checkNotNull(o, f.toString(), f);
// BUG: Diagnostic contains:
checkNotNull(o, s.toString(), f);
checkNotNull(o.toString(), s, f);
verify(true, s, f);
// BUG: Diagnostic contains:
verify(true, s, f.toString());
verify(true, f.toString(), f);
// BUG: Diagnostic contains:
verify(true, s.toString(), f);
verifyNotNull(o, s, f);
// BUG: Diagnostic contains:
verifyNotNull(o, s, f.toString());
verifyNotNull(o, f.toString(), f);
// BUG: Diagnostic contains:
verifyNotNull(o, s.toString(), f);
verifyNotNull(o.toString(), s, f);
}
}
""")
.doTest();
}
@@ -354,53 +365,55 @@ final class RedundantStringConversionTest {
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addSourceLines(
"A.java",
"import java.util.Formattable;",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"import org.slf4j.Marker;",
"import org.slf4j.MarkerFactory;",
"",
"class A {",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
"",
" private final Marker marker = MarkerFactory.getMarker(A.class.getName());",
" private final Formattable f = (formatter, flags, width, precision) -> {};",
" private final Object o = new Object();",
" private final String s = f.toString();",
" private final Throwable t = new Throwable();",
"",
" void m() {",
" LOG.trace(s, f);",
" // BUG: Diagnostic contains:",
" LOG.debug(s, f.toString());",
" LOG.info(s, t.toString());",
" LOG.warn(s, o, t.toString());",
" // BUG: Diagnostic contains:",
" LOG.error(s, o.toString(), t.toString());",
" // BUG: Diagnostic contains:",
" LOG.trace(s, t.toString(), o);",
"",
" LOG.trace(marker, s, f);",
" // BUG: Diagnostic contains:",
" LOG.debug(marker, s, f.toString());",
" LOG.info(marker, s, t.toString());",
" LOG.warn(marker, s, o, t.toString());",
" // BUG: Diagnostic contains:",
" LOG.error(marker, s, o.toString(), t.toString());",
" // BUG: Diagnostic contains:",
" LOG.trace(marker, s, t.toString(), o);",
"",
" LOG.trace(f.toString(), f);",
" // BUG: Diagnostic contains:",
" LOG.debug(s.toString(), f);",
" LOG.info(t.toString(), f);",
" LOG.warn(marker.toString(), s, f);",
" LOG.error(marker, o.toString(), f);",
" // BUG: Diagnostic contains:",
" LOG.trace(marker, s.toString(), f);",
" LOG.debug(marker, t.toString(), f);",
" }",
"}")
"""
import java.util.Formattable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
class A {
private static final Logger LOG = LoggerFactory.getLogger(A.class);
private final Marker marker = MarkerFactory.getMarker(A.class.getName());
private final Formattable f = (formatter, flags, width, precision) -> {};
private final Object o = new Object();
private final String s = f.toString();
private final Throwable t = new Throwable();
void m() {
LOG.trace(s, f);
// BUG: Diagnostic contains:
LOG.debug(s, f.toString());
LOG.info(s, t.toString());
LOG.warn(s, o, t.toString());
// BUG: Diagnostic contains:
LOG.error(s, o.toString(), t.toString());
// BUG: Diagnostic contains:
LOG.trace(s, t.toString(), o);
LOG.trace(marker, s, f);
// BUG: Diagnostic contains:
LOG.debug(marker, s, f.toString());
LOG.info(marker, s, t.toString());
LOG.warn(marker, s, o, t.toString());
// BUG: Diagnostic contains:
LOG.error(marker, s, o.toString(), t.toString());
// BUG: Diagnostic contains:
LOG.trace(marker, s, t.toString(), o);
LOG.trace(f.toString(), f);
// BUG: Diagnostic contains:
LOG.debug(s.toString(), f);
LOG.info(t.toString(), f);
LOG.warn(marker.toString(), s, f);
LOG.error(marker, o.toString(), f);
// BUG: Diagnostic contains:
LOG.trace(marker, s.toString(), f);
LOG.debug(marker, t.toString(), f);
}
}
""")
.doTest();
}
@@ -408,95 +421,96 @@ 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;",
"import java.util.Objects;",
"",
"class A {",
" static class B {",
" String name() {",
" return toString();",
" }",
"",
" static String toString(int i) {",
" return Integer.toString(i);",
" }",
"",
" static String toString(int i, int j) {",
" return Integer.toString(i * j);",
" }",
" }",
"",
" enum E {",
" ELEM;",
"",
" public String toString() {",
" return \"__\" + name() + \"__\";",
" }",
" }",
"",
" private final B b = new B();",
" private final String s = b.toString();",
"",
" String[] builtin() {",
" return new String[] {",
" // BUG: Diagnostic contains:",
" s + b.toString(),",
" // BUG: Diagnostic contains:",
" s + Objects.toString(b),",
" // BUG: Diagnostic contains:",
" s + String.valueOf(b),",
" // BUG: Diagnostic contains:",
" s + Boolean.toString(false),",
" // BUG: Diagnostic contains:",
" s + Byte.toString((byte) 0),",
" // BUG: Diagnostic contains:",
" s + Character.toString((char) 0),",
" // BUG: Diagnostic contains:",
" s + Short.toString((short) 0),",
" // BUG: Diagnostic contains:",
" s + Integer.toString(0),",
" s + Integer.toString(0, 16),",
" // BUG: Diagnostic contains:",
" s + Long.toString(0),",
" s + Long.toString(0, 16),",
" // BUG: Diagnostic contains:",
" s + Float.toString((float) 0.0),",
" // BUG: Diagnostic contains:",
" s + Double.toString(0.0),",
" };",
" }",
"",
" String[] custom() {",
" return new String[] {",
" s + b.name(),",
" // BUG: Diagnostic contains:",
" s + RoundingMode.UP.name(),",
" // BUG: Diagnostic contains:",
" s + mode().name(),",
" s + A.name(),",
" s + A.toString(42),",
" // BUG: Diagnostic contains:",
" s + B.toString(42),",
" s + B.toString(42, 42),",
" };",
" }",
"",
" static String name() {",
" return A.class.toString();",
" }",
"",
" RoundingMode mode() {",
" return RoundingMode.UP;",
" }",
"",
" static String toString(int i) {",
" return Integer.toString(i);",
" }",
"}")
"""
import java.math.RoundingMode;
import java.util.Objects;
class A {
static class B {
String name() {
return toString();
}
static String toString(int i) {
return Integer.toString(i);
}
static String toString(int i, int j) {
return Integer.toString(i * j);
}
}
enum E {
ELEM;
public String toString() {
return "__" + name() + "__";
}
}
private final B b = new B();
private final String s = b.toString();
String[] builtin() {
return new String[] {
// BUG: Diagnostic contains:
s + b.toString(),
// BUG: Diagnostic contains:
s + Objects.toString(b),
// BUG: Diagnostic contains:
s + String.valueOf(b),
// BUG: Diagnostic contains:
s + Boolean.toString(false),
// BUG: Diagnostic contains:
s + Byte.toString((byte) 0),
// BUG: Diagnostic contains:
s + Character.toString((char) 0),
// BUG: Diagnostic contains:
s + Short.toString((short) 0),
// BUG: Diagnostic contains:
s + Integer.toString(0),
s + Integer.toString(0, 16),
// BUG: Diagnostic contains:
s + Long.toString(0),
s + Long.toString(0, 16),
// BUG: Diagnostic contains:
s + Float.toString((float) 0.0),
// BUG: Diagnostic contains:
s + Double.toString(0.0),
};
}
String[] custom() {
return new String[] {
s + b.name(),
// BUG: Diagnostic contains:
s + RoundingMode.UP.name(),
// BUG: Diagnostic contains:
s + mode().name(),
s + A.name(),
s + A.toString(42),
// BUG: Diagnostic contains:
s + B.toString(42),
s + B.toString(42, 42),
};
}
static String name() {
return A.class.toString();
}
RoundingMode mode() {
return RoundingMode.UP;
}
static String toString(int i) {
return Integer.toString(i);
}
}
""")
.doTest();
}
@@ -505,32 +519,36 @@ final class RedundantStringConversionTest {
BugCheckerRefactoringTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addInputLines(
"A.java",
"class A {",
" private final Object o = new Object();",
" private final String s = o.toString();",
"",
" void m() {",
" String v1 = s.toString();",
" String v2 = \"foo\".toString();",
" String v3 = v2 + super.toString();",
" String v4 = 42 + String.valueOf((String) null);",
" String.format(\"%s\", o.toString());",
" }",
"}")
"""
class A {
private final Object o = new Object();
private final String s = o.toString();
void m() {
String v1 = s.toString();
String v2 = "foo".toString();
String v3 = v2 + super.toString();
String v4 = 42 + String.valueOf((String) null);
String.format("%s", o.toString());
}
}
""")
.addOutputLines(
"A.java",
"class A {",
" private final Object o = new Object();",
" private final String s = o.toString();",
"",
" void m() {",
" String v1 = s;",
" String v2 = \"foo\";",
" String v3 = v2 + super.toString();",
" String v4 = 42 + (String) null;",
" String.format(\"%s\", o);",
" }",
"}")
"""
class A {
private final Object o = new Object();
private final String s = o.toString();
void m() {
String v1 = s;
String v2 = "foo";
String v3 = v2 + super.toString();
String v4 = 42 + (String) null;
String.format("%s", o);
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -0,0 +1,96 @@
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

@@ -9,138 +9,140 @@ final class RequestMappingAnnotationTest {
CompilationTestHelper.newInstance(RequestMappingAnnotation.class, getClass())
.addSourceLines(
"A.java",
"import jakarta.servlet.http.HttpServletRequest;",
"import jakarta.servlet.http.HttpServletResponse;",
"import java.io.InputStream;",
"import java.time.ZoneId;",
"import java.util.Locale;",
"import java.util.TimeZone;",
"import org.springframework.http.HttpMethod;",
"import org.springframework.security.core.annotation.CurrentSecurityContext;",
"import org.springframework.ui.Model;",
"import org.springframework.validation.BindingResult;",
"import org.springframework.web.bind.annotation.DeleteMapping;",
"import org.springframework.web.bind.annotation.GetMapping;",
"import org.springframework.web.bind.annotation.PatchMapping;",
"import org.springframework.web.bind.annotation.PathVariable;",
"import org.springframework.web.bind.annotation.PostMapping;",
"import org.springframework.web.bind.annotation.PutMapping;",
"import org.springframework.web.bind.annotation.RequestAttribute;",
"import org.springframework.web.bind.annotation.RequestBody;",
"import org.springframework.web.bind.annotation.RequestHeader;",
"import org.springframework.web.bind.annotation.RequestMapping;",
"import org.springframework.web.bind.annotation.RequestParam;",
"import org.springframework.web.bind.annotation.RequestPart;",
"import org.springframework.web.context.request.NativeWebRequest;",
"import org.springframework.web.context.request.WebRequest;",
"import org.springframework.web.server.ServerWebExchange;",
"import org.springframework.web.util.UriBuilder;",
"import org.springframework.web.util.UriComponentsBuilder;",
"",
"interface A {",
" A noMapping();",
"",
" A noMapping(String param);",
"",
" @DeleteMapping",
" A properNoParameters();",
"",
" @GetMapping",
" A properPathVariable(@PathVariable String param);",
"",
" @PatchMapping",
" A properRequestAttribute(@RequestAttribute String attribute);",
"",
" @PostMapping",
" A properRequestBody(@RequestBody String body);",
"",
" @PutMapping",
" A properRequestHeader(@RequestHeader String header);",
"",
" @RequestMapping",
" A properRequestParam(@RequestParam String param);",
"",
" @RequestMapping",
" A properRequestPart(@RequestPart String part);",
"",
" @RequestMapping",
" A properCurrentSecurityContext(",
" @CurrentSecurityContext(expression = \"authentication.name\") String user);",
"",
" @RequestMapping",
" A properInputStream(InputStream input);",
"",
" @RequestMapping",
" A properZoneId(ZoneId zoneId);",
"",
" @RequestMapping",
" A properLocale(Locale locale);",
"",
" @RequestMapping",
" A properTimeZone(TimeZone timeZone);",
"",
" @RequestMapping",
" A properHttpServletRequest(HttpServletRequest request);",
"",
" @RequestMapping",
" A properHttpServletResponse(HttpServletResponse response);",
"",
" @RequestMapping",
" A properHttpMethod(HttpMethod method);",
"",
" @RequestMapping",
" A properModel(Model model);",
"",
" @RequestMapping",
" A properBindingResult(BindingResult result);",
"",
" @RequestMapping",
" A properNativeWebRequest(NativeWebRequest request);",
"",
" @RequestMapping",
" A properWebRequest(WebRequest request);",
"",
" @RequestMapping",
" A properServerWebExchange(ServerWebExchange exchange);",
"",
" @RequestMapping",
" A properServerUriBuilder(UriBuilder builder);",
"",
" @RequestMapping",
" A properServerUriComponentsBuilder(UriComponentsBuilder builder);",
"",
" @DeleteMapping",
" // BUG: Diagnostic contains:",
" A delete(String param);",
"",
" @GetMapping",
" // BUG: Diagnostic contains:",
" A get(String param);",
"",
" @PatchMapping",
" // BUG: Diagnostic contains:",
" A patch(String param);",
"",
" @PostMapping",
" // BUG: Diagnostic contains:",
" A post(String param);",
"",
" @PutMapping",
" // BUG: Diagnostic contains:",
" A put(String param);",
"",
" @RequestMapping",
" // BUG: Diagnostic contains:",
" A requestMultiple(String param, String param2);",
"",
" @RequestMapping",
" // BUG: Diagnostic contains:",
" A requestFirstParamViolation(String param, @PathVariable String param2);",
"",
" @RequestMapping",
" // BUG: Diagnostic contains:",
" A requestSecondParamViolation(@RequestBody String param, String param2);",
"}")
"""
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.time.ZoneId;
import java.util.Locale;
import java.util.TimeZone;
import org.springframework.http.HttpMethod;
import org.springframework.security.core.annotation.CurrentSecurityContext;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriBuilder;
import org.springframework.web.util.UriComponentsBuilder;
interface A {
A noMapping();
A noMapping(String param);
@DeleteMapping
A properNoParameters();
@GetMapping
A properPathVariable(@PathVariable String param);
@PatchMapping
A properRequestAttribute(@RequestAttribute String attribute);
@PostMapping
A properRequestBody(@RequestBody String body);
@PutMapping
A properRequestHeader(@RequestHeader String header);
@RequestMapping
A properRequestParam(@RequestParam String param);
@RequestMapping
A properRequestPart(@RequestPart String part);
@RequestMapping
A properCurrentSecurityContext(
@CurrentSecurityContext(expression = "authentication.name") String user);
@RequestMapping
A properInputStream(InputStream input);
@RequestMapping
A properZoneId(ZoneId zoneId);
@RequestMapping
A properLocale(Locale locale);
@RequestMapping
A properTimeZone(TimeZone timeZone);
@RequestMapping
A properHttpServletRequest(HttpServletRequest request);
@RequestMapping
A properHttpServletResponse(HttpServletResponse response);
@RequestMapping
A properHttpMethod(HttpMethod method);
@RequestMapping
A properModel(Model model);
@RequestMapping
A properBindingResult(BindingResult result);
@RequestMapping
A properNativeWebRequest(NativeWebRequest request);
@RequestMapping
A properWebRequest(WebRequest request);
@RequestMapping
A properServerWebExchange(ServerWebExchange exchange);
@RequestMapping
A properServerUriBuilder(UriBuilder builder);
@RequestMapping
A properServerUriComponentsBuilder(UriComponentsBuilder builder);
@DeleteMapping
// BUG: Diagnostic contains:
A delete(String param);
@GetMapping
// BUG: Diagnostic contains:
A get(String param);
@PatchMapping
// BUG: Diagnostic contains:
A patch(String param);
@PostMapping
// BUG: Diagnostic contains:
A post(String param);
@PutMapping
// BUG: Diagnostic contains:
A put(String param);
@RequestMapping
// BUG: Diagnostic contains:
A requestMultiple(String param, String param2);
@RequestMapping
// BUG: Diagnostic contains:
A requestFirstParamViolation(String param, @PathVariable String param2);
@RequestMapping
// BUG: Diagnostic contains:
A requestSecondParamViolation(@RequestBody String param, String param2);
}
""")
.doTest();
}
}

View File

@@ -9,55 +9,57 @@ final class RequestParamTypeTest {
CompilationTestHelper.newInstance(RequestParamType.class, getClass())
.addSourceLines(
"A.java",
"import com.google.common.collect.ImmutableBiMap;",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableMap;",
"import com.google.common.collect.ImmutableSet;",
"import java.util.List;",
"import java.util.Map;",
"import java.util.Set;",
"import org.jspecify.annotations.Nullable;",
"import org.springframework.web.bind.annotation.DeleteMapping;",
"import org.springframework.web.bind.annotation.GetMapping;",
"import org.springframework.web.bind.annotation.PostMapping;",
"import org.springframework.web.bind.annotation.PutMapping;",
"import org.springframework.web.bind.annotation.RequestBody;",
"import org.springframework.web.bind.annotation.RequestParam;",
"",
"interface A {",
" @PostMapping",
" A properRequestParam(@RequestBody String body);",
"",
" @GetMapping",
" A properRequestParam(@RequestParam int param);",
"",
" @GetMapping",
" A properRequestParam(@RequestParam List<String> param);",
"",
" @PostMapping",
" A properRequestParam(@RequestBody String body, @RequestParam Set<String> param);",
"",
" @PutMapping",
" A properRequestParam(@RequestBody String body, @RequestParam Map<String, String> param);",
"",
" @GetMapping",
" // BUG: Diagnostic contains:",
" A get(@RequestParam ImmutableBiMap<String, String> param);",
"",
" @PostMapping",
" // BUG: Diagnostic contains:",
" A post(@Nullable @RequestParam ImmutableList<String> param);",
"",
" @PutMapping",
" // BUG: Diagnostic contains:",
" A put(@RequestBody String body, @RequestParam ImmutableSet<String> param);",
"",
" @DeleteMapping",
" // BUG: Diagnostic contains:",
" A delete(@RequestBody String body, @RequestParam ImmutableMap<String, String> param);",
"",
" void negative(ImmutableSet<Integer> set, ImmutableMap<String, String> map);",
"}")
"""
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jspecify.annotations.Nullable;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
interface A {
@PostMapping
A properRequestParam(@RequestBody String body);
@GetMapping
A properRequestParam(@RequestParam int param);
@GetMapping
A properRequestParam(@RequestParam List<String> param);
@PostMapping
A properRequestParam(@RequestBody String body, @RequestParam Set<String> param);
@PutMapping
A properRequestParam(@RequestBody String body, @RequestParam Map<String, String> param);
@GetMapping
// BUG: Diagnostic contains:
A get(@RequestParam ImmutableBiMap<String, String> param);
@PostMapping
// BUG: Diagnostic contains:
A post(@Nullable @RequestParam ImmutableList<String> param);
@PutMapping
// BUG: Diagnostic contains:
A put(@RequestBody String body, @RequestParam ImmutableSet<String> param);
@DeleteMapping
// BUG: Diagnostic contains:
A delete(@RequestBody String body, @RequestParam ImmutableMap<String, String> param);
void negative(ImmutableSet<Integer> set, ImmutableMap<String, String> map);
}
""")
.doTest();
}
@@ -68,47 +70,49 @@ final class RequestParamTypeTest {
"-XepOpt:RequestParamType:SupportedCustomTypes=com.google.common.collect.ImmutableSet,com.google.common.collect.ImmutableSortedMultiset")
.addSourceLines(
"A.java",
"import com.google.common.collect.ImmutableBiMap;",
"import com.google.common.collect.ImmutableCollection;",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableMap;",
"import com.google.common.collect.ImmutableMultiset;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.common.collect.ImmutableSortedMultiset;",
"import com.google.common.collect.ImmutableSortedSet;",
"import org.springframework.web.bind.annotation.GetMapping;",
"import org.springframework.web.bind.annotation.RequestParam;",
"",
"interface A {",
" @GetMapping",
" // BUG: Diagnostic contains:",
" A immutableCollection(@RequestParam ImmutableCollection<String> param);",
"",
" @GetMapping",
" // BUG: Diagnostic contains:",
" A immutableList(@RequestParam ImmutableList<String> param);",
"",
" @GetMapping",
" A immutableSet(@RequestParam ImmutableSet<String> param);",
"",
" @GetMapping",
" A immutableSortedSet(@RequestParam ImmutableSortedSet<String> param);",
"",
" @GetMapping",
" // BUG: Diagnostic contains:",
" A immutableMultiset(@RequestParam ImmutableMultiset<String> param);",
"",
" @GetMapping",
" A immutableSortedMultiset(@RequestParam ImmutableSortedMultiset<String> param);",
"",
" @GetMapping",
" // BUG: Diagnostic contains:",
" A immutableMap(@RequestParam ImmutableMap<String, String> param);",
"",
" @GetMapping",
" // BUG: Diagnostic contains:",
" A immutableBiMap(@RequestParam ImmutableBiMap<String, String> param);",
"}")
"""
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMultiset;
import com.google.common.collect.ImmutableSortedSet;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
interface A {
@GetMapping
// BUG: Diagnostic contains:
A immutableCollection(@RequestParam ImmutableCollection<String> param);
@GetMapping
// BUG: Diagnostic contains:
A immutableList(@RequestParam ImmutableList<String> param);
@GetMapping
A immutableSet(@RequestParam ImmutableSet<String> param);
@GetMapping
A immutableSortedSet(@RequestParam ImmutableSortedSet<String> param);
@GetMapping
// BUG: Diagnostic contains:
A immutableMultiset(@RequestParam ImmutableMultiset<String> param);
@GetMapping
A immutableSortedMultiset(@RequestParam ImmutableSortedMultiset<String> param);
@GetMapping
// BUG: Diagnostic contains:
A immutableMap(@RequestParam ImmutableMap<String, String> param);
@GetMapping
// BUG: Diagnostic contains:
A immutableBiMap(@RequestParam ImmutableBiMap<String, String> param);
}
""")
.doTest();
}
}

View File

@@ -11,79 +11,81 @@ final class Slf4jLogStatementTest {
CompilationTestHelper.newInstance(Slf4jLogStatement.class, getClass())
.addSourceLines(
"A.java",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"import org.slf4j.Marker;",
"import org.slf4j.MarkerFactory;",
"",
"class A {",
" private static final String FMT0 = \"format-string-without-placeholders\";",
" private static final String FMT1 = \"format-string-with-{}-placeholder\";",
" private static final String FMT_ERR = \"format-string-with-%s-placeholder\";",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
"",
" private final Marker marker = MarkerFactory.getMarker(A.class.getName());",
" private final Object o = new Object();",
" private final String s = o.toString();",
" private final Throwable t = new Throwable();",
"",
" void m() {",
" LOG.trace(s);",
" LOG.debug(s, o);",
" LOG.info(s, t);",
" LOG.warn(s, o, t);",
" LOG.error(marker, s);",
" LOG.trace(marker, s, o);",
" LOG.debug(marker, s, t);",
" LOG.info(marker, s, o, t);",
"",
" LOG.warn(FMT0);",
" // BUG: Diagnostic contains: Log statement contains 0 placeholders, but specifies 1 matching",
" // argument(s)",
" LOG.error(FMT0, o);",
" LOG.trace(FMT0, t);",
" // BUG: Diagnostic contains:",
" LOG.debug(FMT0, o, t);",
" LOG.info(marker, FMT0);",
" // BUG: Diagnostic contains:",
" LOG.warn(marker, FMT0, o);",
" LOG.error(marker, FMT0, t);",
" // BUG: Diagnostic contains:",
" LOG.trace(marker, FMT0, o, t);",
"",
" // BUG: Diagnostic contains: Log statement contains 1 placeholders, but specifies 0 matching",
" // argument(s)",
" LOG.debug(FMT1);",
" LOG.info(FMT1, o);",
" // BUG: Diagnostic contains:",
" LOG.warn(FMT1, t);",
" LOG.error(FMT1, o, t);",
" // BUG: Diagnostic contains: Log statement contains 1 placeholders, but specifies 2 matching",
" // argument(s)",
" LOG.trace(FMT1, o, o);",
" // BUG: Diagnostic contains:",
" LOG.debug(FMT1, o, o, t);",
" // BUG: Diagnostic contains:",
" LOG.info(marker, FMT1);",
" LOG.warn(marker, FMT1, o);",
" // BUG: Diagnostic contains:",
" LOG.error(marker, FMT1, t);",
" LOG.trace(marker, FMT1, o, t);",
" // BUG: Diagnostic contains:",
" LOG.debug(marker, FMT1, o, o);",
" // BUG: Diagnostic contains:",
" LOG.info(marker, FMT1, o, o, t);",
"",
" // BUG: Diagnostic contains: SLF4J log statement placeholders are of the form `{}`, not `%s`",
" LOG.warn(FMT_ERR);",
" // BUG: Diagnostic contains:",
" LOG.error(FMT_ERR, t);",
" // BUG: Diagnostic contains:",
" LOG.trace(FMT_ERR, o);",
" // BUG: Diagnostic contains:",
" LOG.debug(FMT_ERR, o, t);",
" }",
"}")
"""
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
class A {
private static final String FMT0 = "format-string-without-placeholders";
private static final String FMT1 = "format-string-with-{}-placeholder";
private static final String FMT_ERR = "format-string-with-%s-placeholder";
private static final Logger LOG = LoggerFactory.getLogger(A.class);
private final Marker marker = MarkerFactory.getMarker(A.class.getName());
private final Object o = new Object();
private final String s = o.toString();
private final Throwable t = new Throwable();
void m() {
LOG.trace(s);
LOG.debug(s, o);
LOG.info(s, t);
LOG.warn(s, o, t);
LOG.error(marker, s);
LOG.trace(marker, s, o);
LOG.debug(marker, s, t);
LOG.info(marker, s, o, t);
LOG.warn(FMT0);
// BUG: Diagnostic contains: Log statement contains 0 placeholders, but specifies 1 matching
// argument(s)
LOG.error(FMT0, o);
LOG.trace(FMT0, t);
// BUG: Diagnostic contains:
LOG.debug(FMT0, o, t);
LOG.info(marker, FMT0);
// BUG: Diagnostic contains:
LOG.warn(marker, FMT0, o);
LOG.error(marker, FMT0, t);
// BUG: Diagnostic contains:
LOG.trace(marker, FMT0, o, t);
// BUG: Diagnostic contains: Log statement contains 1 placeholders, but specifies 0 matching
// argument(s)
LOG.debug(FMT1);
LOG.info(FMT1, o);
// BUG: Diagnostic contains:
LOG.warn(FMT1, t);
LOG.error(FMT1, o, t);
// BUG: Diagnostic contains: Log statement contains 1 placeholders, but specifies 2 matching
// argument(s)
LOG.trace(FMT1, o, o);
// BUG: Diagnostic contains:
LOG.debug(FMT1, o, o, t);
// BUG: Diagnostic contains:
LOG.info(marker, FMT1);
LOG.warn(marker, FMT1, o);
// BUG: Diagnostic contains:
LOG.error(marker, FMT1, t);
LOG.trace(marker, FMT1, o, t);
// BUG: Diagnostic contains:
LOG.debug(marker, FMT1, o, o);
// BUG: Diagnostic contains:
LOG.info(marker, FMT1, o, o, t);
// BUG: Diagnostic contains: SLF4J log statement placeholders are of the form `{}`, not `%s`
LOG.warn(FMT_ERR);
// BUG: Diagnostic contains:
LOG.error(FMT_ERR, t);
// BUG: Diagnostic contains:
LOG.trace(FMT_ERR, o);
// BUG: Diagnostic contains:
LOG.debug(FMT_ERR, o, t);
}
}
""")
.doTest();
}
@@ -93,50 +95,54 @@ final class Slf4jLogStatementTest {
BugCheckerRefactoringTestHelper.newInstance(Slf4jLogStatement.class, getClass())
.addInputLines(
"A.java",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"import org.slf4j.Marker;",
"import org.slf4j.MarkerFactory;",
"",
"class A {",
" private static final String FMT_ERR = \"format-string-with-%s-placeholder\";",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
"",
" private final Marker marker = MarkerFactory.getMarker(A.class.getName());",
" private final Object o = new Object();",
" private final String s = o.toString();",
" private final Throwable t = new Throwable();",
"",
" void m() {",
" LOG.error(FMT_ERR, o);",
" LOG.error(\"format-string-with-'%s'-placeholder\", o);",
" LOG.error(\"format-string-with-\\\"%s\\\"-placeholder\", o);",
" LOG.error(\"format-string-with-%s\" + \"-placeholder\", o);",
" }",
"}")
"""
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
class A {
private static final String FMT_ERR = "format-string-with-%s-placeholder";
private static final Logger LOG = LoggerFactory.getLogger(A.class);
private final Marker marker = MarkerFactory.getMarker(A.class.getName());
private final Object o = new Object();
private final String s = o.toString();
private final Throwable t = new Throwable();
void m() {
LOG.error(FMT_ERR, o);
LOG.error("format-string-with-'%s'-placeholder", o);
LOG.error("format-string-with-\\"%s\\"-placeholder", o);
LOG.error("format-string-with-%s" + "-placeholder", o);
}
}
""")
.addOutputLines(
"A.java",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"import org.slf4j.Marker;",
"import org.slf4j.MarkerFactory;",
"",
"class A {",
" private static final String FMT_ERR = \"format-string-with-%s-placeholder\";",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
"",
" private final Marker marker = MarkerFactory.getMarker(A.class.getName());",
" private final Object o = new Object();",
" private final String s = o.toString();",
" private final Throwable t = new Throwable();",
"",
" void m() {",
" LOG.error(FMT_ERR, o);",
" LOG.error(\"format-string-with-'{}'-placeholder\", o);",
" LOG.error(\"format-string-with-\\\"{}\\\"-placeholder\", o);",
" LOG.error(\"format-string-with-{}\" + \"-placeholder\", o);",
" }",
"}")
"""
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
class A {
private static final String FMT_ERR = "format-string-with-%s-placeholder";
private static final Logger LOG = LoggerFactory.getLogger(A.class);
private final Marker marker = MarkerFactory.getMarker(A.class.getName());
private final Object o = new Object();
private final String s = o.toString();
private final Throwable t = new Throwable();
void m() {
LOG.error(FMT_ERR, o);
LOG.error("format-string-with-'{}'-placeholder", o);
LOG.error("format-string-with-\\"{}\\"-placeholder", o);
LOG.error("format-string-with-{}" + "-placeholder", o);
}
}
""")
.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;
@@ -12,123 +11,125 @@ final class Slf4jLoggerDeclarationTest {
CompilationTestHelper.newInstance(Slf4jLoggerDeclaration.class, getClass())
.addSourceLines(
"A.java",
"import static java.lang.Class.forName;",
"",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"",
"class A {",
" private static final long serialVersionUID = 1L;",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
"",
" abstract static class DynamicLogger {",
" private final Logger log = LoggerFactory.getLogger(getClass());",
" }",
"",
" abstract static class DynamicLoggerWithExplicitThis {",
" private final Logger log = LoggerFactory.getLogger(this.getClass());",
" }",
"",
" static final class StaticLogger {",
" private static final Logger LOG = LoggerFactory.getLogger(StaticLogger.class);",
" }",
"",
" static final class StaticLoggerWithCustomIdentifier {",
" private static final Logger LOG = LoggerFactory.getLogger(\"custom-identifier\");",
" }",
"",
" interface StaticLoggerForInterface {",
" Logger LOG = LoggerFactory.getLogger(StaticLoggerForInterface.class);",
" }",
"",
" abstract static class DynamicLoggerForWrongTypeWithoutReceiver {",
" // BUG: Diagnostic contains:",
" private final Logger log = LoggerFactory.getLogger(forName(\"A.class\"));",
"",
" DynamicLoggerForWrongTypeWithoutReceiver() throws ClassNotFoundException {}",
" }",
"",
" abstract static class DynamicLoggerForWrongTypeWithoutSymbol {",
" // BUG: Diagnostic contains:",
" private final Logger log = LoggerFactory.getLogger(\"foo\".getClass());",
" }",
"",
" abstract static class DynamicLoggerForWrongTypeWithSymbol {",
" // BUG: Diagnostic contains:",
" private final Logger log = LoggerFactory.getLogger(new A().getClass());",
" }",
"",
" static final class NonAbstractDynamicLogger {",
" // BUG: Diagnostic contains:",
" private final Logger log = LoggerFactory.getLogger(getClass());",
" }",
"",
" abstract static class DynamicLoggerWithMissingModifier {",
" // BUG: Diagnostic contains:",
" final Logger log = LoggerFactory.getLogger(getClass());",
" }",
"",
" abstract static class DynamicLoggerWithExcessModifier {",
" // BUG: Diagnostic contains:",
" private final transient Logger log = LoggerFactory.getLogger(getClass());",
" }",
"",
" abstract static class MisnamedDynamicLogger {",
" // BUG: Diagnostic contains:",
" private final Logger LOG = LoggerFactory.getLogger(getClass());",
" }",
"",
" static final class StaticLoggerWithMissingModifier {",
" // BUG: Diagnostic contains:",
" static final Logger LOG = LoggerFactory.getLogger(StaticLoggerWithMissingModifier.class);",
" }",
"",
" static final class StaticLoggerWithExcessModifier {",
" // BUG: Diagnostic contains:",
" private static final transient Logger LOG =",
" LoggerFactory.getLogger(StaticLoggerWithExcessModifier.class);",
" }",
"",
" static final class MisnamedStaticLogger {",
" // BUG: Diagnostic contains:",
" private static final Logger log = LoggerFactory.getLogger(MisnamedStaticLogger.class);",
" }",
"",
" static final class StaticLoggerWithIncorrectIdentifier {",
" // BUG: Diagnostic contains:",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
" }",
"",
" static final class StaticLoggerWithCustomIdentifierAndMissingModifier {",
" // BUG: Diagnostic contains:",
" static final Logger LOG = LoggerFactory.getLogger(\"custom-identifier\");",
" }",
"",
" static final class StaticLoggerWithCustomIdentifierAndExcessModifier {",
" // BUG: Diagnostic contains:",
" private static final transient Logger LOG = LoggerFactory.getLogger(\"custom-identifier\");",
" }",
"",
" static final class MisnamedStaticLoggerWithCustomIdentifier {",
" // BUG: Diagnostic contains:",
" private static final Logger log = LoggerFactory.getLogger(\"custom-identifier\");",
" }",
"",
" interface StaticLoggerForInterfaceWithExcessModifier {",
" // BUG: Diagnostic contains:",
" static Logger LOG = LoggerFactory.getLogger(StaticLoggerForInterfaceWithExcessModifier.class);",
" }",
"",
" interface MisnamedStaticLoggerForInterface {",
" // BUG: Diagnostic contains:",
" Logger log = LoggerFactory.getLogger(MisnamedStaticLoggerForInterface.class);",
" }",
"",
" interface StaticLoggerForInterfaceWithIncorrectIdentifier {",
" // BUG: Diagnostic contains:",
" Logger LOG = LoggerFactory.getLogger(A.class);",
" }",
"}")
"""
import static java.lang.Class.forName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class A {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(A.class);
abstract static class DynamicLogger {
private final Logger log = LoggerFactory.getLogger(getClass());
}
abstract static class DynamicLoggerWithExplicitThis {
private final Logger log = LoggerFactory.getLogger(this.getClass());
}
static final class StaticLogger {
private static final Logger LOG = LoggerFactory.getLogger(StaticLogger.class);
}
static final class StaticLoggerWithCustomIdentifier {
private static final Logger LOG = LoggerFactory.getLogger("custom-identifier");
}
interface StaticLoggerForInterface {
Logger LOG = LoggerFactory.getLogger(StaticLoggerForInterface.class);
}
abstract static class DynamicLoggerForWrongTypeWithoutReceiver {
// BUG: Diagnostic contains:
private final Logger log = LoggerFactory.getLogger(forName("A.class"));
DynamicLoggerForWrongTypeWithoutReceiver() throws ClassNotFoundException {}
}
abstract static class DynamicLoggerForWrongTypeWithoutSymbol {
// BUG: Diagnostic contains:
private final Logger log = LoggerFactory.getLogger("foo".getClass());
}
abstract static class DynamicLoggerForWrongTypeWithSymbol {
// BUG: Diagnostic contains:
private final Logger log = LoggerFactory.getLogger(new A().getClass());
}
static final class NonAbstractDynamicLogger {
// BUG: Diagnostic contains:
private final Logger log = LoggerFactory.getLogger(getClass());
}
abstract static class DynamicLoggerWithMissingModifier {
// BUG: Diagnostic contains:
final Logger log = LoggerFactory.getLogger(getClass());
}
abstract static class DynamicLoggerWithExcessModifier {
// BUG: Diagnostic contains:
private final transient Logger log = LoggerFactory.getLogger(getClass());
}
abstract static class MisnamedDynamicLogger {
// BUG: Diagnostic contains:
private final Logger LOG = LoggerFactory.getLogger(getClass());
}
static final class StaticLoggerWithMissingModifier {
// BUG: Diagnostic contains:
static final Logger LOG = LoggerFactory.getLogger(StaticLoggerWithMissingModifier.class);
}
static final class StaticLoggerWithExcessModifier {
// BUG: Diagnostic contains:
private static final transient Logger LOG =
LoggerFactory.getLogger(StaticLoggerWithExcessModifier.class);
}
static final class MisnamedStaticLogger {
// BUG: Diagnostic contains:
private static final Logger log = LoggerFactory.getLogger(MisnamedStaticLogger.class);
}
static final class StaticLoggerWithIncorrectIdentifier {
// BUG: Diagnostic contains:
private static final Logger LOG = LoggerFactory.getLogger(A.class);
}
static final class StaticLoggerWithCustomIdentifierAndMissingModifier {
// BUG: Diagnostic contains:
static final Logger LOG = LoggerFactory.getLogger("custom-identifier");
}
static final class StaticLoggerWithCustomIdentifierAndExcessModifier {
// BUG: Diagnostic contains:
private static final transient Logger LOG = LoggerFactory.getLogger("custom-identifier");
}
static final class MisnamedStaticLoggerWithCustomIdentifier {
// BUG: Diagnostic contains:
private static final Logger log = LoggerFactory.getLogger("custom-identifier");
}
interface StaticLoggerForInterfaceWithExcessModifier {
// BUG: Diagnostic contains:
static Logger LOG = LoggerFactory.getLogger(StaticLoggerForInterfaceWithExcessModifier.class);
}
interface MisnamedStaticLoggerForInterface {
// BUG: Diagnostic contains:
Logger log = LoggerFactory.getLogger(MisnamedStaticLoggerForInterface.class);
}
interface StaticLoggerForInterfaceWithIncorrectIdentifier {
// BUG: Diagnostic contains:
Logger LOG = LoggerFactory.getLogger(A.class);
}
}
""")
.doTest();
}
@@ -137,83 +138,91 @@ final class Slf4jLoggerDeclarationTest {
BugCheckerRefactoringTestHelper.newInstance(Slf4jLoggerDeclaration.class, getClass())
.addInputLines(
"A.java",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"",
"class A {",
" static Logger foo = LoggerFactory.getLogger(Logger.class);",
"",
" abstract static class DynamicLogger {",
" transient Logger BAR = LoggerFactory.getLogger(getClass());",
" }",
"",
" static final class StaticLogger {",
" transient Logger baz = LoggerFactory.getLogger(LoggerFactory.class);",
" }",
"",
" static final class StaticLoggerWithCustomIdentifier {",
" transient Logger qux = LoggerFactory.getLogger(\"custom-identifier\");",
" }",
"",
" interface StaticLoggerForInterface {",
" public static final Logger quux = LoggerFactory.getLogger(A.class);",
" }",
"}")
"""
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class A {
static Logger foo = LoggerFactory.getLogger(Logger.class);
abstract static class DynamicLogger {
transient Logger BAR = LoggerFactory.getLogger(getClass());
}
static final class StaticLogger {
transient Logger baz = LoggerFactory.getLogger(LoggerFactory.class);
}
static final class StaticLoggerWithCustomIdentifier {
transient Logger qux = LoggerFactory.getLogger("custom-identifier");
}
interface StaticLoggerForInterface {
public static final Logger quux = LoggerFactory.getLogger(A.class);
}
}
""")
.addOutputLines(
"A.java",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"",
"class A {",
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
"",
" abstract static class DynamicLogger {",
" private final Logger log = LoggerFactory.getLogger(getClass());",
" }",
"",
" static final class StaticLogger {",
" private static final Logger LOG = LoggerFactory.getLogger(StaticLogger.class);",
" }",
"",
" static final class StaticLoggerWithCustomIdentifier {",
" private static final Logger LOG = LoggerFactory.getLogger(\"custom-identifier\");",
" }",
"",
" interface StaticLoggerForInterface {",
" Logger LOG = LoggerFactory.getLogger(StaticLoggerForInterface.class);",
" }",
"}")
"""
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class A {
private static final Logger LOG = LoggerFactory.getLogger(A.class);
abstract static class DynamicLogger {
private final Logger log = LoggerFactory.getLogger(getClass());
}
static final class StaticLogger {
private static final Logger LOG = LoggerFactory.getLogger(StaticLogger.class);
}
static final class StaticLoggerWithCustomIdentifier {
private static final Logger LOG = LoggerFactory.getLogger("custom-identifier");
}
interface StaticLoggerForInterface {
Logger LOG = LoggerFactory.getLogger(StaticLoggerForInterface.class);
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
@Test
void replacementWithCustomLoggerName() {
BugCheckerRefactoringTestHelper.newInstance(Slf4jLoggerDeclaration.class, getClass())
.setArgs(ImmutableList.of("-XepOpt:Slf4jLogDeclaration:CanonicalStaticLoggerName=FOO_BAR"))
.setArgs("-XepOpt:Slf4jLoggerDeclaration:CanonicalStaticLoggerName=FOO_BAR")
.addInputLines(
"A.java",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"",
"class A {",
" transient Logger LOG = LoggerFactory.getLogger(Logger.class);",
"",
" abstract static class DynamicLogger {",
" transient Logger log = LoggerFactory.getLogger(getClass());",
" }",
"}")
"""
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class A {
transient Logger LOG = LoggerFactory.getLogger(Logger.class);
abstract static class DynamicLogger {
transient Logger log = LoggerFactory.getLogger(getClass());
}
}
""")
.addOutputLines(
"A.java",
"import org.slf4j.Logger;",
"import org.slf4j.LoggerFactory;",
"",
"class A {",
" private static final Logger FOO_BAR = LoggerFactory.getLogger(A.class);",
"",
" abstract static class DynamicLogger {",
" private final Logger fooBar = LoggerFactory.getLogger(getClass());",
" }",
"}")
"""
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class A {
private static final Logger FOO_BAR = LoggerFactory.getLogger(A.class);
abstract static class DynamicLogger {
private final Logger fooBar = LoggerFactory.getLogger(getClass());
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -11,75 +11,77 @@ final class SpringMvcAnnotationTest {
CompilationTestHelper.newInstance(SpringMvcAnnotation.class, getClass())
.addSourceLines(
"A.java",
"import static org.springframework.web.bind.annotation.RequestMethod.DELETE;",
"import static org.springframework.web.bind.annotation.RequestMethod.GET;",
"import static org.springframework.web.bind.annotation.RequestMethod.HEAD;",
"import static org.springframework.web.bind.annotation.RequestMethod.PATCH;",
"import static org.springframework.web.bind.annotation.RequestMethod.POST;",
"import static org.springframework.web.bind.annotation.RequestMethod.PUT;",
"",
"import org.springframework.web.bind.annotation.DeleteMapping;",
"import org.springframework.web.bind.annotation.GetMapping;",
"import org.springframework.web.bind.annotation.PatchMapping;",
"import org.springframework.web.bind.annotation.PostMapping;",
"import org.springframework.web.bind.annotation.PutMapping;",
"import org.springframework.web.bind.annotation.RequestMapping;",
"import org.springframework.web.bind.annotation.RequestMethod;",
"",
"interface A {",
" @RequestMapping",
" A simple();",
"",
" @RequestMapping(method = {})",
" A explicitDefault();",
"",
" // BUG: Diagnostic contains:",
" @RequestMapping(method = RequestMethod.GET)",
" A get();",
"",
" // BUG: Diagnostic contains:",
" @RequestMapping(method = {RequestMethod.POST})",
" A post();",
"",
" // BUG: Diagnostic contains:",
" @RequestMapping(method = {PUT})",
" A put();",
"",
" // BUG: Diagnostic contains:",
" @RequestMapping(method = {DELETE})",
" A delete();",
"",
" // BUG: Diagnostic contains:",
" @RequestMapping(method = {PATCH})",
" A patch();",
"",
" @RequestMapping(method = HEAD)",
" A head();",
"",
" @RequestMapping(method = RequestMethod.OPTIONS)",
" A options();",
"",
" @RequestMapping(method = {GET, POST})",
" A simpleMix();",
"",
" @RequestMapping(method = {RequestMethod.GET, RequestMethod.POST})",
" A verboseMix();",
"",
" @DeleteMapping",
" A properDelete();",
"",
" @GetMapping",
" A properGet();",
"",
" @PatchMapping",
" A properPatch();",
"",
" @PostMapping",
" A properPost();",
"",
" @PutMapping",
" A properPut();",
"}")
"""
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.HEAD;
import static org.springframework.web.bind.annotation.RequestMethod.PATCH;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
interface A {
@RequestMapping
A simple();
@RequestMapping(method = {})
A explicitDefault();
// BUG: Diagnostic contains:
@RequestMapping(method = RequestMethod.GET)
A get();
// BUG: Diagnostic contains:
@RequestMapping(method = {RequestMethod.POST})
A post();
// BUG: Diagnostic contains:
@RequestMapping(method = {PUT})
A put();
// BUG: Diagnostic contains:
@RequestMapping(method = {DELETE})
A delete();
// BUG: Diagnostic contains:
@RequestMapping(method = {PATCH})
A patch();
@RequestMapping(method = HEAD)
A head();
@RequestMapping(method = RequestMethod.OPTIONS)
A options();
@RequestMapping(method = {GET, POST})
A simpleMix();
@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST})
A verboseMix();
@DeleteMapping
A properDelete();
@GetMapping
A properGet();
@PatchMapping
A properPatch();
@PostMapping
A properPost();
@PutMapping
A properPut();
}
""")
.doTest();
}
@@ -88,66 +90,70 @@ final class SpringMvcAnnotationTest {
BugCheckerRefactoringTestHelper.newInstance(SpringMvcAnnotation.class, getClass())
.addInputLines(
"A.java",
"import static org.springframework.web.bind.annotation.RequestMethod.PATCH;",
"import static org.springframework.web.bind.annotation.RequestMethod.POST;",
"import static org.springframework.web.bind.annotation.RequestMethod.PUT;",
"",
"import org.springframework.web.bind.annotation.RequestMapping;",
"import org.springframework.web.bind.annotation.RequestMethod;",
"",
"interface A {",
" @RequestMapping(method = RequestMethod.GET)",
" A simple();",
"",
" @RequestMapping(path = \"/foo/bar\", method = POST)",
" A prefixed();",
"",
" @RequestMapping(",
" method = {RequestMethod.DELETE},",
" path = \"/foo/bar\")",
" A suffixed();",
"",
" @RequestMapping(",
" path = \"/foo/bar\",",
" method = {PUT},",
" consumes = {\"a\", \"b\"})",
" A surrounded();",
"",
" @RequestMapping(method = {PATCH})",
" A curly();",
"}")
"""
import static org.springframework.web.bind.annotation.RequestMethod.PATCH;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
interface A {
@RequestMapping(method = RequestMethod.GET)
A simple();
@RequestMapping(path = "/foo/bar", method = POST)
A prefixed();
@RequestMapping(
method = {RequestMethod.DELETE},
path = "/foo/bar")
A suffixed();
@RequestMapping(
path = "/foo/bar",
method = {PUT},
consumes = {"a", "b"})
A surrounded();
@RequestMapping(method = {PATCH})
A curly();
}
""")
.addOutputLines(
"A.java",
"import static org.springframework.web.bind.annotation.RequestMethod.PATCH;",
"import static org.springframework.web.bind.annotation.RequestMethod.POST;",
"import static org.springframework.web.bind.annotation.RequestMethod.PUT;",
"",
"import org.springframework.web.bind.annotation.DeleteMapping;",
"import org.springframework.web.bind.annotation.GetMapping;",
"import org.springframework.web.bind.annotation.PatchMapping;",
"import org.springframework.web.bind.annotation.PostMapping;",
"import org.springframework.web.bind.annotation.PutMapping;",
"import org.springframework.web.bind.annotation.RequestMapping;",
"import org.springframework.web.bind.annotation.RequestMethod;",
"",
"interface A {",
" @GetMapping()",
" A simple();",
"",
" @PostMapping(path = \"/foo/bar\")",
" A prefixed();",
"",
" @DeleteMapping(path = \"/foo/bar\")",
" A suffixed();",
"",
" @PutMapping(",
" path = \"/foo/bar\",",
" consumes = {\"a\", \"b\"})",
" A surrounded();",
"",
" @PatchMapping()",
" A curly();",
"}")
"""
import static org.springframework.web.bind.annotation.RequestMethod.PATCH;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
interface A {
@GetMapping()
A simple();
@PostMapping(path = "/foo/bar")
A prefixed();
@DeleteMapping(path = "/foo/bar")
A suffixed();
@PutMapping(
path = "/foo/bar",
consumes = {"a", "b"})
A surrounded();
@PatchMapping()
A curly();
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -34,93 +34,95 @@ final class StaticImportTest {
CompilationTestHelper.newInstance(StaticImport.class, getClass())
.addSourceLines(
"A.java",
"import static com.google.common.collect.ImmutableMap.toImmutableMap;",
"import static com.google.common.collect.ImmutableSet.toImmutableSet;",
"import static java.nio.charset.StandardCharsets.UTF_8;",
"import static java.util.function.Predicate.not;",
"import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;",
"",
"import com.fasterxml.jackson.annotation.JsonCreator;",
"import com.google.common.base.Predicates;",
"import com.google.common.collect.ImmutableMap;",
"import com.google.common.collect.ImmutableMultiset;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.errorprone.refaster.ImportPolicy;",
"import com.google.errorprone.refaster.annotation.UseImportPolicy;",
"import com.mongodb.client.model.Filters;",
"import java.nio.charset.StandardCharsets;",
"import java.time.ZoneOffset;",
"import java.util.Optional;",
"import java.util.UUID;",
"import java.util.function.Predicate;",
"import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;",
"import org.springframework.http.MediaType;",
"",
"class A {",
" void m() {",
" // BUG: Diagnostic contains:",
" ImmutableMap.toImmutableMap(v -> v, v -> v);",
" ImmutableMap.<String, String, String>toImmutableMap(v -> v, v -> v);",
" toImmutableMap(v -> v, v -> v);",
"",
" // BUG: Diagnostic contains:",
" ImmutableSet.toImmutableSet();",
" ImmutableSet.<String>toImmutableSet();",
" toImmutableSet();",
"",
" // Not flagged because we define `#toImmutableMultiset` below.",
" ImmutableMultiset.toImmutableMultiset();",
" ImmutableMultiset.<String>toImmutableMultiset();",
" toImmutableMultiset();",
"",
" // BUG: Diagnostic contains:",
" Predicate.not(null);",
" not(null);",
"",
" // BUG: Diagnostic contains:",
" Predicates.alwaysTrue();",
" // BUG: Diagnostic contains:",
" Predicates.alwaysFalse();",
" // Not flagged because of `java.util.function.Predicate.not` import.",
" Predicates.not(null);",
"",
" // BUG: Diagnostic contains:",
" UUID uuid = UUID.randomUUID();",
"",
" // BUG: Diagnostic contains:",
" Object o1 = StandardCharsets.UTF_8;",
" Object o2 = UTF_8;",
"",
" // BUG: Diagnostic contains:",
" Object e1 = WebEnvironment.RANDOM_PORT;",
" Object e2 = RANDOM_PORT;",
"",
" // Not flagged because `MediaType.ALL` is exempted.",
" MediaType t1 = MediaType.ALL;",
" // BUG: Diagnostic contains:",
" MediaType t2 = MediaType.APPLICATION_JSON;",
"",
" // BUG: Diagnostic contains:",
" Filters.empty();",
" Optional.empty();",
"",
" // BUG: Diagnostic contains:",
" ZoneOffset zo1 = ZoneOffset.UTC;",
" ZoneOffset zo2 = ZoneOffset.MIN;",
" }",
"",
" // BUG: Diagnostic contains:",
" @JsonCreator(mode = JsonCreator.Mode.DELEGATING)",
" private static A jsonCreator(int a) {",
" return new A();",
" }",
"",
" // BUG: Diagnostic contains:",
" @UseImportPolicy(ImportPolicy.IMPORT_TOP_LEVEL)",
" void refasterAfterTemplate() {}",
"",
" void toImmutableMultiset() {}",
"}")
"""
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.function.Predicate.not;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.refaster.ImportPolicy;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import com.mongodb.client.model.Filters;
import java.nio.charset.StandardCharsets;
import java.time.ZoneOffset;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Predicate;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.http.MediaType;
class A {
void m() {
// BUG: Diagnostic contains:
ImmutableMap.toImmutableMap(v -> v, v -> v);
ImmutableMap.<String, String, String>toImmutableMap(v -> v, v -> v);
toImmutableMap(v -> v, v -> v);
// BUG: Diagnostic contains:
ImmutableSet.toImmutableSet();
ImmutableSet.<String>toImmutableSet();
toImmutableSet();
// Not flagged because we define `#toImmutableMultiset` below.
ImmutableMultiset.toImmutableMultiset();
ImmutableMultiset.<String>toImmutableMultiset();
toImmutableMultiset();
// BUG: Diagnostic contains:
Predicate.not(null);
not(null);
// BUG: Diagnostic contains:
Predicates.alwaysTrue();
// BUG: Diagnostic contains:
Predicates.alwaysFalse();
// Not flagged because of `java.util.function.Predicate.not` import.
Predicates.not(null);
// BUG: Diagnostic contains:
UUID uuid = UUID.randomUUID();
// BUG: Diagnostic contains:
Object o1 = StandardCharsets.UTF_8;
Object o2 = UTF_8;
// BUG: Diagnostic contains:
Object e1 = WebEnvironment.RANDOM_PORT;
Object e2 = RANDOM_PORT;
// Not flagged because `MediaType.ALL` is exempted.
MediaType t1 = MediaType.ALL;
// BUG: Diagnostic contains:
MediaType t2 = MediaType.APPLICATION_JSON;
// BUG: Diagnostic contains:
Filters.empty();
Optional.empty();
// BUG: Diagnostic contains:
ZoneOffset zo1 = ZoneOffset.UTC;
ZoneOffset zo2 = ZoneOffset.MIN;
}
// BUG: Diagnostic contains:
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
private static A jsonCreator(int a) {
return new A();
}
// BUG: Diagnostic contains:
@UseImportPolicy(ImportPolicy.IMPORT_TOP_LEVEL)
void refasterAfterTemplate() {}
void toImmutableMultiset() {}
}
""")
.doTest();
}
@@ -129,167 +131,171 @@ final class StaticImportTest {
BugCheckerRefactoringTestHelper.newInstance(StaticImport.class, getClass())
.addInputLines(
"A.java",
"import static java.util.function.Predicate.not;",
"",
"import com.fasterxml.jackson.annotation.JsonCreator;",
"import com.google.common.base.Predicates;",
"import com.google.common.collect.ImmutableMap;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.errorprone.BugPattern;",
"import com.google.errorprone.BugPattern.SeverityLevel;",
"import java.nio.charset.StandardCharsets;",
"import java.util.ArrayList;",
"import java.util.Collections;",
"import java.util.Objects;",
"import java.util.regex.Pattern;",
"import org.junit.jupiter.params.provider.Arguments;",
"import org.springframework.boot.test.context.SpringBootTest;",
"import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;",
"import org.springframework.format.annotation.DateTimeFormat;",
"import org.springframework.format.annotation.DateTimeFormat.ISO;",
"import org.springframework.http.MediaType;",
"",
"class A {",
" void m1() {",
" ImmutableMap.toImmutableMap(v -> v, v -> v);",
" ImmutableMap.<String, String, String>toImmutableMap(v -> v, v -> v);",
"",
" ImmutableSet.toImmutableSet();",
" ImmutableSet.<String>toImmutableSet();",
"",
" Collections.disjoint(ImmutableSet.of(), ImmutableSet.of());",
" Collections.reverse(new ArrayList<>());",
"",
" Predicates.not(null);",
" not(null);",
"",
" Arguments.arguments(\"foo\");",
"",
" Objects.requireNonNull(\"bar\");",
"",
" Object o = StandardCharsets.UTF_8;",
"",
" ImmutableSet.of(",
" MediaType.ALL,",
" MediaType.APPLICATION_XHTML_XML,",
" MediaType.TEXT_HTML,",
" MediaType.valueOf(\"image/webp\"));",
"",
" Pattern.compile(\"\", Pattern.CASE_INSENSITIVE);",
" }",
"",
" void m2(",
" @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) String date,",
" @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) String dateTime,",
" @DateTimeFormat(iso = DateTimeFormat.ISO.TIME) String time) {}",
"",
" void m3(",
" @DateTimeFormat(iso = ISO.DATE) String date,",
" @DateTimeFormat(iso = ISO.DATE_TIME) String dateTime,",
" @DateTimeFormat(iso = ISO.TIME) String time) {}",
"",
" @JsonCreator(mode = JsonCreator.Mode.DELEGATING)",
" private static A jsonCreator(int a) {",
" return new A();",
" }",
"",
" @BugPattern(",
" summary = \"\",",
" linkType = BugPattern.LinkType.NONE,",
" severity = SeverityLevel.SUGGESTION,",
" tags = BugPattern.StandardTags.SIMPLIFICATION)",
" static final class TestBugPattern {}",
"",
" @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)",
" final class Test {}",
"}")
"""
import static java.util.function.Predicate.not;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.SeverityLevel;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Objects;
import java.util.regex.Pattern;
import org.junit.jupiter.params.provider.Arguments;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.http.MediaType;
class A {
void m1() {
ImmutableMap.toImmutableMap(v -> v, v -> v);
ImmutableMap.<String, String, String>toImmutableMap(v -> v, v -> v);
ImmutableSet.toImmutableSet();
ImmutableSet.<String>toImmutableSet();
Collections.disjoint(ImmutableSet.of(), ImmutableSet.of());
Collections.reverse(new ArrayList<>());
Predicates.not(null);
not(null);
Arguments.arguments("foo");
Objects.requireNonNull("bar");
Object o = StandardCharsets.UTF_8;
ImmutableSet.of(
MediaType.ALL,
MediaType.APPLICATION_XHTML_XML,
MediaType.TEXT_HTML,
MediaType.valueOf("image/webp"));
Pattern.compile("", Pattern.CASE_INSENSITIVE);
}
void m2(
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) String date,
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) String dateTime,
@DateTimeFormat(iso = DateTimeFormat.ISO.TIME) String time) {}
void m3(
@DateTimeFormat(iso = ISO.DATE) String date,
@DateTimeFormat(iso = ISO.DATE_TIME) String dateTime,
@DateTimeFormat(iso = ISO.TIME) String time) {}
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
private static A jsonCreator(int a) {
return new A();
}
@BugPattern(
summary = "",
linkType = BugPattern.LinkType.NONE,
severity = SeverityLevel.SUGGESTION,
tags = BugPattern.StandardTags.SIMPLIFICATION)
static final class TestBugPattern {}
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
final class Test {}
}
""")
.addOutputLines(
"A.java",
"import static com.fasterxml.jackson.annotation.JsonCreator.Mode.DELEGATING;",
"import static com.google.common.collect.ImmutableMap.toImmutableMap;",
"import static com.google.common.collect.ImmutableSet.toImmutableSet;",
"import static com.google.errorprone.BugPattern.LinkType.NONE;",
"import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;",
"import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;",
"import static java.nio.charset.StandardCharsets.UTF_8;",
"import static java.util.Collections.disjoint;",
"import static java.util.Collections.reverse;",
"import static java.util.Objects.requireNonNull;",
"import static java.util.function.Predicate.not;",
"import static java.util.regex.Pattern.CASE_INSENSITIVE;",
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
"import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;",
"import static org.springframework.format.annotation.DateTimeFormat.ISO.DATE;",
"import static org.springframework.format.annotation.DateTimeFormat.ISO.DATE_TIME;",
"import static org.springframework.format.annotation.DateTimeFormat.ISO.TIME;",
"import static org.springframework.http.MediaType.APPLICATION_XHTML_XML;",
"import static org.springframework.http.MediaType.TEXT_HTML;",
"",
"import com.fasterxml.jackson.annotation.JsonCreator;",
"import com.google.common.base.Predicates;",
"import com.google.common.collect.ImmutableMap;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.errorprone.BugPattern;",
"import com.google.errorprone.BugPattern.SeverityLevel;",
"import java.nio.charset.StandardCharsets;",
"import java.util.ArrayList;",
"import java.util.Collections;",
"import java.util.Objects;",
"import java.util.regex.Pattern;",
"import org.junit.jupiter.params.provider.Arguments;",
"import org.springframework.boot.test.context.SpringBootTest;",
"import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;",
"import org.springframework.format.annotation.DateTimeFormat;",
"import org.springframework.format.annotation.DateTimeFormat.ISO;",
"import org.springframework.http.MediaType;",
"",
"class A {",
" void m1() {",
" toImmutableMap(v -> v, v -> v);",
" ImmutableMap.<String, String, String>toImmutableMap(v -> v, v -> v);",
"",
" toImmutableSet();",
" ImmutableSet.<String>toImmutableSet();",
"",
" disjoint(ImmutableSet.of(), ImmutableSet.of());",
" reverse(new ArrayList<>());",
"",
" Predicates.not(null);",
" not(null);",
"",
" arguments(\"foo\");",
"",
" requireNonNull(\"bar\");",
"",
" Object o = UTF_8;",
"",
" ImmutableSet.of(",
" MediaType.ALL, APPLICATION_XHTML_XML, TEXT_HTML, MediaType.valueOf(\"image/webp\"));",
"",
" Pattern.compile(\"\", CASE_INSENSITIVE);",
" }",
"",
" void m2(",
" @DateTimeFormat(iso = DATE) String date,",
" @DateTimeFormat(iso = DATE_TIME) String dateTime,",
" @DateTimeFormat(iso = TIME) String time) {}",
"",
" void m3(",
" @DateTimeFormat(iso = DATE) String date,",
" @DateTimeFormat(iso = DATE_TIME) String dateTime,",
" @DateTimeFormat(iso = TIME) String time) {}",
"",
" @JsonCreator(mode = DELEGATING)",
" private static A jsonCreator(int a) {",
" return new A();",
" }",
"",
" @BugPattern(summary = \"\", linkType = NONE, severity = SUGGESTION, tags = SIMPLIFICATION)",
" static final class TestBugPattern {}",
"",
" @SpringBootTest(webEnvironment = RANDOM_PORT)",
" final class Test {}",
"}")
"""
import static com.fasterxml.jackson.annotation.JsonCreator.Mode.DELEGATING;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.errorprone.BugPattern.LinkType.NONE;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.disjoint;
import static java.util.Collections.reverse;
import static java.util.Objects.requireNonNull;
import static java.util.function.Predicate.not;
import static java.util.regex.Pattern.CASE_INSENSITIVE;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
import static org.springframework.format.annotation.DateTimeFormat.ISO.DATE;
import static org.springframework.format.annotation.DateTimeFormat.ISO.DATE_TIME;
import static org.springframework.format.annotation.DateTimeFormat.ISO.TIME;
import static org.springframework.http.MediaType.APPLICATION_XHTML_XML;
import static org.springframework.http.MediaType.TEXT_HTML;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.BugPattern;
import com.google.errorprone.BugPattern.SeverityLevel;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Objects;
import java.util.regex.Pattern;
import org.junit.jupiter.params.provider.Arguments;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.http.MediaType;
class A {
void m1() {
toImmutableMap(v -> v, v -> v);
ImmutableMap.<String, String, String>toImmutableMap(v -> v, v -> v);
toImmutableSet();
ImmutableSet.<String>toImmutableSet();
disjoint(ImmutableSet.of(), ImmutableSet.of());
reverse(new ArrayList<>());
Predicates.not(null);
not(null);
arguments("foo");
requireNonNull("bar");
Object o = UTF_8;
ImmutableSet.of(
MediaType.ALL, APPLICATION_XHTML_XML, TEXT_HTML, MediaType.valueOf("image/webp"));
Pattern.compile("", CASE_INSENSITIVE);
}
void m2(
@DateTimeFormat(iso = DATE) String date,
@DateTimeFormat(iso = DATE_TIME) String dateTime,
@DateTimeFormat(iso = TIME) String time) {}
void m3(
@DateTimeFormat(iso = DATE) String date,
@DateTimeFormat(iso = DATE_TIME) String dateTime,
@DateTimeFormat(iso = TIME) String time) {}
@JsonCreator(mode = DELEGATING)
private static A jsonCreator(int a) {
return new A();
}
@BugPattern(summary = "", linkType = NONE, severity = SUGGESTION, tags = SIMPLIFICATION)
static final class TestBugPattern {}
@SpringBootTest(webEnvironment = RANDOM_PORT)
final class Test {}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -14,43 +14,45 @@ final class StringJoinTest {
.expectErrorMessage("join", m -> m.contains("Prefer `String#join` over `String#format`"))
.addSourceLines(
"A.java",
"import java.util.Formattable;",
"import java.util.Locale;",
"",
"class A {",
" void m() {",
" String.join(\"-\", getClass().getName());",
" String.format(getClass().getName(), getClass().getName());",
" String.format(Locale.ROOT, \"%s\", getClass().getName());",
" String.format(\"%20s\", getClass().getName());",
" // BUG: Diagnostic matches: valueOf",
" String.format(\"%s\", getClass().getName());",
" // BUG: Diagnostic matches: valueOf",
" String.format(\"%s\", hashCode());",
" String.format(\"%s\", (Formattable) null);",
" String.format(\"-%s\", getClass().getName());",
" String.format(\"%s-\", getClass().getName());",
" String.format(\"-%s-\", getClass().getName());",
" // BUG: Diagnostic matches: join",
" String.format(\"%s%s\", getClass().getName(), getClass().getName());",
" // BUG: Diagnostic matches: join",
" String.format(\"%s%s\", getClass().getName(), hashCode());",
" // BUG: Diagnostic matches: join",
" String.format(\"%s%s\", hashCode(), getClass().getName());",
" String.format(\"%s%s\", getClass().getName(), (Formattable) null);",
" String.format(\"%s%s\", (Formattable) null, getClass().getName());",
" String.format(\"%s%s\", getClass().getName());",
" // BUG: Diagnostic matches: join",
" String.format(\"%s-%s\", getClass().getName(), getClass().getName());",
" // BUG: Diagnostic matches: join",
" String.format(\"%saa%s\", getClass().getName(), getClass().getName());",
" String.format(\"%s%%%s\", getClass().getName(), getClass().getName());",
" // BUG: Diagnostic matches: join",
" String.format(\"%s_%s_%s\", getClass().getName(), getClass().getName(), getClass().getName());",
" String.format(\"%s_%s_%s\", getClass().getName(), getClass().getName());",
" String.format(\"%s_%s-%s\", getClass().getName(), getClass().getName(), getClass().getName());",
" }",
"}")
"""
import java.util.Formattable;
import java.util.Locale;
class A {
void m() {
String.join("-", getClass().getName());
String.format(getClass().getName(), getClass().getName());
String.format(Locale.ROOT, "%s", getClass().getName());
String.format("%20s", getClass().getName());
// BUG: Diagnostic matches: valueOf
String.format("%s", getClass().getName());
// BUG: Diagnostic matches: valueOf
String.format("%s", hashCode());
String.format("%s", (Formattable) null);
String.format("-%s", getClass().getName());
String.format("%s-", getClass().getName());
String.format("-%s-", getClass().getName());
// BUG: Diagnostic matches: join
String.format("%s%s", getClass().getName(), getClass().getName());
// BUG: Diagnostic matches: join
String.format("%s%s", getClass().getName(), hashCode());
// BUG: Diagnostic matches: join
String.format("%s%s", hashCode(), getClass().getName());
String.format("%s%s", getClass().getName(), (Formattable) null);
String.format("%s%s", (Formattable) null, getClass().getName());
String.format("%s%s", getClass().getName());
// BUG: Diagnostic matches: join
String.format("%s-%s", getClass().getName(), getClass().getName());
// BUG: Diagnostic matches: join
String.format("%saa%s", getClass().getName(), getClass().getName());
String.format("%s%%%s", getClass().getName(), getClass().getName());
// BUG: Diagnostic matches: join
String.format("%s_%s_%s", getClass().getName(), getClass().getName(), getClass().getName());
String.format("%s_%s_%s", getClass().getName(), getClass().getName());
String.format("%s_%s-%s", getClass().getName(), getClass().getName(), getClass().getName());
}
}
""")
.doTest();
}
@@ -59,32 +61,36 @@ final class StringJoinTest {
BugCheckerRefactoringTestHelper.newInstance(StringJoin.class, getClass())
.addInputLines(
"A.java",
"class A {",
" void m() {",
" String.format(\"%s\", getClass().getName());",
" String.format(\"%s%s\", getClass().getName(), getClass().getName());",
" String.format(\"%s%s\", getClass().getName(), hashCode());",
" String.format(\"%s%s\", hashCode(), getClass().getName());",
" String.format(\"%s-%s\", getClass().getName(), getClass().getName());",
" String.format(\"%saa%s\", getClass().getName(), getClass().getName());",
" String.format(\"%s\\\"%s\", getClass().getName(), getClass().getName());",
" String.format(\"%s_%s_%s\", getClass().getName(), getClass().getName(), getClass().getName());",
" }",
"}")
"""
class A {
void m() {
String.format("%s", getClass().getName());
String.format("%s%s", getClass().getName(), getClass().getName());
String.format("%s%s", getClass().getName(), hashCode());
String.format("%s%s", hashCode(), getClass().getName());
String.format("%s-%s", getClass().getName(), getClass().getName());
String.format("%saa%s", getClass().getName(), getClass().getName());
String.format("%s\\"%s", getClass().getName(), getClass().getName());
String.format("%s_%s_%s", getClass().getName(), getClass().getName(), getClass().getName());
}
}
""")
.addOutputLines(
"A.java",
"class A {",
" void m() {",
" String.valueOf(getClass().getName());",
" String.join(\"\", getClass().getName(), getClass().getName());",
" String.join(\"\", getClass().getName(), String.valueOf(hashCode()));",
" String.join(\"\", String.valueOf(hashCode()), getClass().getName());",
" String.join(\"-\", getClass().getName(), getClass().getName());",
" String.join(\"aa\", getClass().getName(), getClass().getName());",
" String.join(\"\\\"\", getClass().getName(), getClass().getName());",
" String.join(\"_\", getClass().getName(), getClass().getName(), getClass().getName());",
" }",
"}")
"""
class A {
void m() {
String.valueOf(getClass().getName());
String.join("", getClass().getName(), getClass().getName());
String.join("", getClass().getName(), String.valueOf(hashCode()));
String.join("", String.valueOf(hashCode()), getClass().getName());
String.join("-", getClass().getName(), getClass().getName());
String.join("aa", getClass().getName(), getClass().getName());
String.join("\\"", getClass().getName(), getClass().getName());
String.join("_", getClass().getName(), getClass().getName(), getClass().getName());
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -9,110 +9,112 @@ final class TimeZoneUsageTest {
CompilationTestHelper.newInstance(TimeZoneUsage.class, getClass())
.addSourceLines(
"A.java",
"import static java.time.ZoneOffset.UTC;",
"",
"import java.time.Clock;",
"import java.time.Duration;",
"import java.time.Instant;",
"import java.time.LocalDate;",
"import java.time.LocalDateTime;",
"import java.time.LocalTime;",
"import java.time.OffsetDateTime;",
"import java.time.OffsetTime;",
"import java.time.ZoneId;",
"import java.time.ZonedDateTime;",
"",
"class A {",
" void m() {",
" Clock clock = Clock.fixed(Instant.EPOCH, UTC);",
" clock.instant();",
" clock.millis();",
" Clock.offset(clock, Duration.ZERO);",
" Clock.tick(clock, Duration.ZERO);",
"",
" // BUG: Diagnostic contains:",
" Clock.systemUTC();",
" // BUG: Diagnostic contains:",
" Clock.systemDefaultZone();",
" // BUG: Diagnostic contains:",
" Clock.system(UTC);",
" // BUG: Diagnostic contains:",
" Clock.tickMillis(UTC);",
" // BUG: Diagnostic contains:",
" Clock.tickMinutes(UTC);",
" // BUG: Diagnostic contains:",
" Clock.tickSeconds(UTC);",
" // BUG: Diagnostic contains:",
" clock.getZone();",
" // BUG: Diagnostic contains:",
" clock.withZone(UTC);",
"",
" // BUG: Diagnostic contains:",
" Instant.now();",
" // This is equivalent to `clock.instant()`, which is fine.",
" Instant.now(clock);",
"",
" // BUG: Diagnostic contains:",
" LocalDate.now();",
" // BUG: Diagnostic contains:",
" LocalDate.now(clock);",
" // BUG: Diagnostic contains:",
" LocalDate.now(UTC);",
"",
" // BUG: Diagnostic contains:",
" LocalDateTime.now();",
" // BUG: Diagnostic contains:",
" LocalDateTime.now(clock);",
" // BUG: Diagnostic contains:",
" LocalDateTime.now(UTC);",
"",
" // BUG: Diagnostic contains:",
" LocalTime.now();",
" // BUG: Diagnostic contains:",
" LocalTime.now(clock);",
" // BUG: Diagnostic contains:",
" LocalTime.now(UTC);",
"",
" // BUG: Diagnostic contains:",
" OffsetDateTime.now();",
" // BUG: Diagnostic contains:",
" OffsetDateTime.now(clock);",
" // BUG: Diagnostic contains:",
" OffsetDateTime.now(UTC);",
"",
" // BUG: Diagnostic contains:",
" OffsetTime.now();",
" // BUG: Diagnostic contains:",
" OffsetTime.now(clock);",
" // BUG: Diagnostic contains:",
" OffsetTime.now(UTC);",
"",
" // BUG: Diagnostic contains:",
" ZonedDateTime.now();",
" // BUG: Diagnostic contains:",
" ZonedDateTime.now(clock);",
" // BUG: Diagnostic contains:",
" ZonedDateTime.now(UTC);",
" }",
"",
" abstract class ForwardingClock extends Clock {",
" private final Clock clock;",
"",
" ForwardingClock(Clock clock) {",
" this.clock = clock;",
" }",
"",
" @Override",
" public ZoneId getZone() {",
" return clock.getZone();",
" }",
"",
" @Override",
" public Clock withZone(ZoneId zone) {",
" return clock.withZone(zone);",
" }",
" }",
"}")
"""
import static java.time.ZoneOffset.UTC;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
class A {
void m() {
Clock clock = Clock.fixed(Instant.EPOCH, UTC);
clock.instant();
clock.millis();
Clock.offset(clock, Duration.ZERO);
Clock.tick(clock, Duration.ZERO);
// BUG: Diagnostic contains:
Clock.systemUTC();
// BUG: Diagnostic contains:
Clock.systemDefaultZone();
// BUG: Diagnostic contains:
Clock.system(UTC);
// BUG: Diagnostic contains:
Clock.tickMillis(UTC);
// BUG: Diagnostic contains:
Clock.tickMinutes(UTC);
// BUG: Diagnostic contains:
Clock.tickSeconds(UTC);
// BUG: Diagnostic contains:
clock.getZone();
// BUG: Diagnostic contains:
clock.withZone(UTC);
// BUG: Diagnostic contains:
Instant.now();
// This is equivalent to `clock.instant()`, which is fine.
Instant.now(clock);
// BUG: Diagnostic contains:
LocalDate.now();
// BUG: Diagnostic contains:
LocalDate.now(clock);
// BUG: Diagnostic contains:
LocalDate.now(UTC);
// BUG: Diagnostic contains:
LocalDateTime.now();
// BUG: Diagnostic contains:
LocalDateTime.now(clock);
// BUG: Diagnostic contains:
LocalDateTime.now(UTC);
// BUG: Diagnostic contains:
LocalTime.now();
// BUG: Diagnostic contains:
LocalTime.now(clock);
// BUG: Diagnostic contains:
LocalTime.now(UTC);
// BUG: Diagnostic contains:
OffsetDateTime.now();
// BUG: Diagnostic contains:
OffsetDateTime.now(clock);
// BUG: Diagnostic contains:
OffsetDateTime.now(UTC);
// BUG: Diagnostic contains:
OffsetTime.now();
// BUG: Diagnostic contains:
OffsetTime.now(clock);
// BUG: Diagnostic contains:
OffsetTime.now(UTC);
// BUG: Diagnostic contains:
ZonedDateTime.now();
// BUG: Diagnostic contains:
ZonedDateTime.now(clock);
// BUG: Diagnostic contains:
ZonedDateTime.now(UTC);
}
abstract class ForwardingClock extends Clock {
private final Clock clock;
ForwardingClock(Clock clock) {
this.clock = clock;
}
@Override
public ZoneId getZone() {
return clock.getZone();
}
@Override
public Clock withZone(ZoneId zone) {
return clock.withZone(zone);
}
}
}
""")
.doTest();
}
}

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

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

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

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.19.1</version>
<version>0.19.2-SNAPSHOT</version>
</parent>
<artifactId>error-prone-experimental</artifactId>

View File

@@ -11,308 +11,310 @@ final class MethodReferenceUsageTest {
CompilationTestHelper.newInstance(MethodReferenceUsage.class, getClass())
.addSourceLines(
"A.java",
"import com.google.common.collect.Streams;",
"import java.util.HashMap;",
"import java.util.Map;",
"import java.util.function.IntConsumer;",
"import java.util.function.IntFunction;",
"import java.util.stream.Stream;",
"",
"class A {",
" private final Stream<Integer> s = Stream.of(1);",
" private final Map<Integer, Integer> m = new HashMap<>();",
" private final Runnable thrower =",
" () -> {",
" throw new RuntimeException();",
" };",
"",
" void unaryExternalStaticFunctionCalls() {",
" s.forEach(String::valueOf);",
" // BUG: Diagnostic contains:",
" s.forEach(v -> String.valueOf(v));",
" s.forEach(",
" // BUG: Diagnostic contains:",
" (v) -> {",
" String.valueOf(v);",
" });",
" s.forEach(",
" // BUG: Diagnostic contains:",
" (Integer v) -> {",
" {",
" String.valueOf(v);",
" }",
" });",
" s.forEach(",
" v -> {",
" String.valueOf(v);",
" String.valueOf(v);",
" });",
"",
" s.map(String::valueOf);",
" // BUG: Diagnostic contains:",
" s.map(v -> String.valueOf(v));",
" // BUG: Diagnostic contains:",
" s.map((v) -> (String.valueOf(v)));",
" s.map(",
" // BUG: Diagnostic contains:",
" (Integer v) -> {",
" return String.valueOf(v);",
" });",
" s.map(",
" // BUG: Diagnostic contains:",
" (final Integer v) -> {",
" return (String.valueOf(v));",
" });",
" s.map(",
" v -> {",
" String.valueOf(v);",
" return String.valueOf(v);",
" });",
"",
" s.findFirst().orElseGet(() -> Integer.valueOf(\"0\"));",
" m.forEach((k, v) -> String.valueOf(v));",
" m.forEach((k, v) -> String.valueOf(k));",
" }",
"",
" void binaryExternalInstanceFunctionCalls() {",
" m.forEach(m::put);",
" // BUG: Diagnostic contains:",
" m.forEach((k, v) -> m.put(k, v));",
" m.forEach((k, v) -> m.put(v, k));",
" m.forEach(",
" // BUG: Diagnostic contains:",
" (Integer k, Integer v) -> {",
" m.put(k, v);",
" });",
" m.forEach(",
" (k, v) -> {",
" m.put(k, k);",
" });",
" m.forEach(",
" // BUG: Diagnostic contains:",
" (final Integer k, final Integer v) -> {",
" {",
" m.put(k, v);",
" }",
" });",
" m.forEach(",
" (k, v) -> {",
" {",
" m.put(v, v);",
" }",
" });",
" m.forEach((k, v) -> new HashMap<Integer, Integer>().put(k, v));",
" m.forEach(",
" (k, v) -> {",
" m.put(k, v);",
" m.put(k, v);",
" });",
"",
" Streams.zip(s, s, m::put);",
" // BUG: Diagnostic contains:",
" Streams.zip(s, s, (a, b) -> m.put(a, b));",
" Streams.zip(s, s, (a, b) -> m.put(b, a));",
" // BUG: Diagnostic contains:",
" Streams.zip(s, s, (Integer a, Integer b) -> (m.put(a, b)));",
" Streams.zip(s, s, (a, b) -> (m.put(a, a)));",
" Streams.zip(",
" s,",
" s,",
" // BUG: Diagnostic contains:",
" (final Integer a, final Integer b) -> {",
" return m.put(a, b);",
" });",
" Streams.zip(",
" s,",
" s,",
" (a, b) -> {",
" return m.put(b, b);",
" });",
" Streams.zip(",
" s,",
" s,",
" // BUG: Diagnostic contains:",
" (a, b) -> {",
" return (m.put(a, b));",
" });",
" Streams.zip(",
" s,",
" s,",
" (a, b) -> {",
" return (m.put(b, a));",
" });",
" Streams.zip(",
" s,",
" s,",
" (a, b) -> {",
" m.put(a, b);",
" return m.put(a, b);",
" });",
" }",
"",
" void nullaryExternalInstanceFunctionCalls() {",
" s.map(Integer::doubleValue);",
" // BUG: Diagnostic contains:",
" s.map(i -> i.doubleValue());",
" s.map(i -> i.toString());",
" s.map(i -> s.toString());",
"",
" // BUG: Diagnostic contains:",
" Stream.of(int.class).filter(c -> c.isEnum());",
" Stream.of((Class<?>) int.class).filter(Class::isEnum);",
" // BUG: Diagnostic contains:",
" Stream.of((Class<?>) int.class).filter(c -> c.isEnum());",
" }",
"",
" void localFunctionCalls() {",
" s.forEach(v -> ivoid0());",
" s.forEach(v -> iint0());",
" s.forEach(v -> svoid0());",
" s.forEach(v -> sint0());",
"",
" s.forEach(this::ivoid1);",
" // BUG: Diagnostic contains:",
" s.forEach(v -> ivoid1(v));",
" s.forEach(",
" // BUG: Diagnostic contains:",
" v -> {",
" ivoid1(v);",
" });",
" s.forEach(this::iint1);",
" // BUG: Diagnostic contains:",
" s.forEach(v -> iint1(v));",
" s.forEach(",
" // BUG: Diagnostic contains:",
" v -> {",
" iint1(v);",
" });",
"",
" s.forEach(A::svoid1);",
" // BUG: Diagnostic contains:",
" s.forEach(v -> svoid1(v));",
" s.forEach(",
" // BUG: Diagnostic contains:",
" v -> {",
" svoid1(v);",
" });",
" s.forEach(A::sint1);",
" // BUG: Diagnostic contains:",
" s.forEach(v -> sint1(v));",
" s.forEach(",
" // BUG: Diagnostic contains:",
" v -> {",
" sint1(v);",
" });",
"",
" s.forEach(v -> ivoid2(v, v));",
" s.forEach(v -> iint2(v, v));",
" s.forEach(v -> svoid2(v, v));",
" s.forEach(v -> sint2(v, v));",
"",
" m.forEach((k, v) -> ivoid0());",
" m.forEach((k, v) -> iint0());",
" m.forEach((k, v) -> svoid0());",
" m.forEach((k, v) -> sint0());",
"",
" m.forEach(this::ivoid2);",
" // BUG: Diagnostic contains:",
" m.forEach((k, v) -> ivoid2(k, v));",
" m.forEach(",
" // BUG: Diagnostic contains:",
" (k, v) -> {",
" ivoid2(k, v);",
" });",
" m.forEach(this::iint2);",
" // BUG: Diagnostic contains:",
" m.forEach((k, v) -> iint2(k, v));",
" m.forEach(",
" // BUG: Diagnostic contains:",
" (k, v) -> {",
" iint2(k, v);",
" });",
"",
" m.forEach(A::svoid2);",
" // BUG: Diagnostic contains:",
" m.forEach((k, v) -> svoid2(k, v));",
" m.forEach(",
" // BUG: Diagnostic contains:",
" (k, v) -> {",
" svoid2(k, v);",
" });",
" m.forEach(A::sint2);",
" // BUG: Diagnostic contains:",
" m.forEach((k, v) -> sint2(k, v));",
" m.forEach(",
" // BUG: Diagnostic contains:",
" (k, v) -> {",
" sint2(k, v);",
" });",
" }",
"",
" void functionCallsWhoseReplacementWouldBeAmbiguous() {",
" receiver(",
" i -> {",
" Integer.toString(i);",
" });",
" }",
"",
" void assortedOtherEdgeCases() {",
" s.forEach(v -> String.valueOf(v.toString()));",
" TernaryOp o1 = (a, b, c) -> String.valueOf(a);",
" TernaryOp o2 = (a, b, c) -> String.valueOf(b);",
" TernaryOp o3 = (a, b, c) -> String.valueOf(c);",
" TernaryOp o4 = (a, b, c) -> c.concat(a);",
" TernaryOp o5 = (a, b, c) -> c.concat(b);",
" TernaryOp o6 = (a, b, c) -> a.concat(c);",
" TernaryOp o7 = (a, b, c) -> b.concat(c);",
" }",
"",
" void receiver(IntFunction<?> op) {}",
"",
" void receiver(IntConsumer op) {}",
"",
" void ivoid0() {}",
"",
" void ivoid1(int a) {}",
"",
" void ivoid2(int a, int b) {}",
"",
" int iint0() {",
" return 0;",
" }",
"",
" int iint1(int a) {",
" return 0;",
" }",
"",
" int iint2(int a, int b) {",
" return 0;",
" }",
"",
" static void svoid0() {}",
"",
" static void svoid1(int a) {}",
"",
" static void svoid2(int a, int b) {}",
"",
" static void svoid3(int a, int b, int c) {}",
"",
" static int sint0() {",
" return 0;",
" }",
"",
" static int sint1(int a) {",
" return 0;",
" }",
"",
" static int sint2(int a, int b) {",
" return 0;",
" }",
"",
" interface TernaryOp {",
" String collect(String a, String b, String c);",
" }",
"}")
"""
import com.google.common.collect.Streams;
import java.util.HashMap;
import java.util.Map;
import java.util.function.IntConsumer;
import java.util.function.IntFunction;
import java.util.stream.Stream;
class A {
private final Stream<Integer> s = Stream.of(1);
private final Map<Integer, Integer> m = new HashMap<>();
private final Runnable thrower =
() -> {
throw new RuntimeException();
};
void unaryExternalStaticFunctionCalls() {
s.forEach(String::valueOf);
// BUG: Diagnostic contains:
s.forEach(v -> String.valueOf(v));
s.forEach(
// BUG: Diagnostic contains:
(v) -> {
String.valueOf(v);
});
s.forEach(
// BUG: Diagnostic contains:
(Integer v) -> {
{
String.valueOf(v);
}
});
s.forEach(
v -> {
String.valueOf(v);
String.valueOf(v);
});
s.map(String::valueOf);
// BUG: Diagnostic contains:
s.map(v -> String.valueOf(v));
// BUG: Diagnostic contains:
s.map((v) -> (String.valueOf(v)));
s.map(
// BUG: Diagnostic contains:
(Integer v) -> {
return String.valueOf(v);
});
s.map(
// BUG: Diagnostic contains:
(final Integer v) -> {
return (String.valueOf(v));
});
s.map(
v -> {
String.valueOf(v);
return String.valueOf(v);
});
s.findFirst().orElseGet(() -> Integer.valueOf("0"));
m.forEach((k, v) -> String.valueOf(v));
m.forEach((k, v) -> String.valueOf(k));
}
void binaryExternalInstanceFunctionCalls() {
m.forEach(m::put);
// BUG: Diagnostic contains:
m.forEach((k, v) -> m.put(k, v));
m.forEach((k, v) -> m.put(v, k));
m.forEach(
// BUG: Diagnostic contains:
(Integer k, Integer v) -> {
m.put(k, v);
});
m.forEach(
(k, v) -> {
m.put(k, k);
});
m.forEach(
// BUG: Diagnostic contains:
(final Integer k, final Integer v) -> {
{
m.put(k, v);
}
});
m.forEach(
(k, v) -> {
{
m.put(v, v);
}
});
m.forEach((k, v) -> new HashMap<Integer, Integer>().put(k, v));
m.forEach(
(k, v) -> {
m.put(k, v);
m.put(k, v);
});
Streams.zip(s, s, m::put);
// BUG: Diagnostic contains:
Streams.zip(s, s, (a, b) -> m.put(a, b));
Streams.zip(s, s, (a, b) -> m.put(b, a));
// BUG: Diagnostic contains:
Streams.zip(s, s, (Integer a, Integer b) -> (m.put(a, b)));
Streams.zip(s, s, (a, b) -> (m.put(a, a)));
Streams.zip(
s,
s,
// BUG: Diagnostic contains:
(final Integer a, final Integer b) -> {
return m.put(a, b);
});
Streams.zip(
s,
s,
(a, b) -> {
return m.put(b, b);
});
Streams.zip(
s,
s,
// BUG: Diagnostic contains:
(a, b) -> {
return (m.put(a, b));
});
Streams.zip(
s,
s,
(a, b) -> {
return (m.put(b, a));
});
Streams.zip(
s,
s,
(a, b) -> {
m.put(a, b);
return m.put(a, b);
});
}
void nullaryExternalInstanceFunctionCalls() {
s.map(Integer::doubleValue);
// BUG: Diagnostic contains:
s.map(i -> i.doubleValue());
s.map(i -> i.toString());
s.map(i -> s.toString());
// BUG: Diagnostic contains:
Stream.of(int.class).filter(c -> c.isEnum());
Stream.of((Class<?>) int.class).filter(Class::isEnum);
// BUG: Diagnostic contains:
Stream.of((Class<?>) int.class).filter(c -> c.isEnum());
}
void localFunctionCalls() {
s.forEach(v -> ivoid0());
s.forEach(v -> iint0());
s.forEach(v -> svoid0());
s.forEach(v -> sint0());
s.forEach(this::ivoid1);
// BUG: Diagnostic contains:
s.forEach(v -> ivoid1(v));
s.forEach(
// BUG: Diagnostic contains:
v -> {
ivoid1(v);
});
s.forEach(this::iint1);
// BUG: Diagnostic contains:
s.forEach(v -> iint1(v));
s.forEach(
// BUG: Diagnostic contains:
v -> {
iint1(v);
});
s.forEach(A::svoid1);
// BUG: Diagnostic contains:
s.forEach(v -> svoid1(v));
s.forEach(
// BUG: Diagnostic contains:
v -> {
svoid1(v);
});
s.forEach(A::sint1);
// BUG: Diagnostic contains:
s.forEach(v -> sint1(v));
s.forEach(
// BUG: Diagnostic contains:
v -> {
sint1(v);
});
s.forEach(v -> ivoid2(v, v));
s.forEach(v -> iint2(v, v));
s.forEach(v -> svoid2(v, v));
s.forEach(v -> sint2(v, v));
m.forEach((k, v) -> ivoid0());
m.forEach((k, v) -> iint0());
m.forEach((k, v) -> svoid0());
m.forEach((k, v) -> sint0());
m.forEach(this::ivoid2);
// BUG: Diagnostic contains:
m.forEach((k, v) -> ivoid2(k, v));
m.forEach(
// BUG: Diagnostic contains:
(k, v) -> {
ivoid2(k, v);
});
m.forEach(this::iint2);
// BUG: Diagnostic contains:
m.forEach((k, v) -> iint2(k, v));
m.forEach(
// BUG: Diagnostic contains:
(k, v) -> {
iint2(k, v);
});
m.forEach(A::svoid2);
// BUG: Diagnostic contains:
m.forEach((k, v) -> svoid2(k, v));
m.forEach(
// BUG: Diagnostic contains:
(k, v) -> {
svoid2(k, v);
});
m.forEach(A::sint2);
// BUG: Diagnostic contains:
m.forEach((k, v) -> sint2(k, v));
m.forEach(
// BUG: Diagnostic contains:
(k, v) -> {
sint2(k, v);
});
}
void functionCallsWhoseReplacementWouldBeAmbiguous() {
receiver(
i -> {
Integer.toString(i);
});
}
void assortedOtherEdgeCases() {
s.forEach(v -> String.valueOf(v.toString()));
TernaryOp o1 = (a, b, c) -> String.valueOf(a);
TernaryOp o2 = (a, b, c) -> String.valueOf(b);
TernaryOp o3 = (a, b, c) -> String.valueOf(c);
TernaryOp o4 = (a, b, c) -> c.concat(a);
TernaryOp o5 = (a, b, c) -> c.concat(b);
TernaryOp o6 = (a, b, c) -> a.concat(c);
TernaryOp o7 = (a, b, c) -> b.concat(c);
}
void receiver(IntFunction<?> op) {}
void receiver(IntConsumer op) {}
void ivoid0() {}
void ivoid1(int a) {}
void ivoid2(int a, int b) {}
int iint0() {
return 0;
}
int iint1(int a) {
return 0;
}
int iint2(int a, int b) {
return 0;
}
static void svoid0() {}
static void svoid1(int a) {}
static void svoid2(int a, int b) {}
static void svoid3(int a, int b, int c) {}
static int sint0() {
return 0;
}
static int sint1(int a) {
return 0;
}
static int sint2(int a, int b) {
return 0;
}
interface TernaryOp {
String collect(String a, String b, String c);
}
}
""")
.doTest();
}
@@ -321,111 +323,115 @@ final class MethodReferenceUsageTest {
BugCheckerRefactoringTestHelper.newInstance(MethodReferenceUsage.class, getClass())
.addInputLines(
"A.java",
"import static java.util.Collections.emptyList;",
"",
"import java.util.Collections;",
"import java.util.List;",
"import java.util.Map;",
"import java.util.function.IntSupplier;",
"import java.util.function.Supplier;",
"import java.util.stream.Stream;",
"",
"class A {",
" static class B extends A {",
" final A a = new B();",
" final B b = new B();",
"",
" IntSupplier intSup;",
" Supplier<List<?>> listSup;",
"",
" void m() {",
" intSup = () -> a.iint0();",
" intSup = () -> b.iint0();",
" intSup = () -> this.iint0();",
" intSup = () -> super.iint0();",
"",
" intSup = () -> a.sint0();",
" intSup = () -> b.sint0();",
" intSup = () -> this.sint0();",
" intSup = () -> super.sint0();",
" intSup = () -> A.sint0();",
" intSup = () -> B.sint0();",
"",
" listSup = () -> Collections.emptyList();",
" listSup = () -> emptyList();",
"",
" Stream.of((Class<?>) int.class).filter(c -> c.isEnum());",
" Stream.of((Map<?, ?>) null).map(Map::keySet).map(s -> s.size());",
" }",
"",
" @Override",
" int iint0() {",
" return 0;",
" }",
" }",
"",
" int iint0() {",
" return 0;",
" }",
"",
" static int sint0() {",
" return 0;",
" }",
"}")
"""
import static java.util.Collections.emptyList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.IntSupplier;
import java.util.function.Supplier;
import java.util.stream.Stream;
class A {
static class B extends A {
final A a = new B();
final B b = new B();
IntSupplier intSup;
Supplier<List<?>> listSup;
void m() {
intSup = () -> a.iint0();
intSup = () -> b.iint0();
intSup = () -> this.iint0();
intSup = () -> super.iint0();
intSup = () -> a.sint0();
intSup = () -> b.sint0();
intSup = () -> this.sint0();
intSup = () -> super.sint0();
intSup = () -> A.sint0();
intSup = () -> B.sint0();
listSup = () -> Collections.emptyList();
listSup = () -> emptyList();
Stream.of((Class<?>) int.class).filter(c -> c.isEnum());
Stream.of((Map<?, ?>) null).map(Map::keySet).map(s -> s.size());
}
@Override
int iint0() {
return 0;
}
}
int iint0() {
return 0;
}
static int sint0() {
return 0;
}
}
""")
.addOutputLines(
"A.java",
"import static java.util.Collections.emptyList;",
"",
"import java.util.Collections;",
"import java.util.List;",
"import java.util.Map;",
"import java.util.Set;",
"import java.util.function.IntSupplier;",
"import java.util.function.Supplier;",
"import java.util.stream.Stream;",
"",
"class A {",
" static class B extends A {",
" final A a = new B();",
" final B b = new B();",
"",
" IntSupplier intSup;",
" Supplier<List<?>> listSup;",
"",
" void m() {",
" intSup = a::iint0;",
" intSup = b::iint0;",
" intSup = this::iint0;",
" intSup = super::iint0;",
"",
" intSup = () -> a.sint0();",
" intSup = () -> b.sint0();",
" intSup = () -> this.sint0();",
" intSup = () -> super.sint0();",
" intSup = A::sint0;",
" intSup = B::sint0;",
"",
" listSup = Collections::emptyList;",
" listSup = Collections::emptyList;",
"",
" Stream.of((Class<?>) int.class).filter(Class::isEnum);",
" Stream.of((Map<?, ?>) null).map(Map::keySet).map(Set::size);",
" }",
"",
" @Override",
" int iint0() {",
" return 0;",
" }",
" }",
"",
" int iint0() {",
" return 0;",
" }",
"",
" static int sint0() {",
" return 0;",
" }",
"}")
"""
import static java.util.Collections.emptyList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.IntSupplier;
import java.util.function.Supplier;
import java.util.stream.Stream;
class A {
static class B extends A {
final A a = new B();
final B b = new B();
IntSupplier intSup;
Supplier<List<?>> listSup;
void m() {
intSup = a::iint0;
intSup = b::iint0;
intSup = this::iint0;
intSup = super::iint0;
intSup = () -> a.sint0();
intSup = () -> b.sint0();
intSup = () -> this.sint0();
intSup = () -> super.sint0();
intSup = A::sint0;
intSup = B::sint0;
listSup = Collections::emptyList;
listSup = Collections::emptyList;
Stream.of((Class<?>) int.class).filter(Class::isEnum);
Stream.of((Map<?, ?>) null).map(Map::keySet).map(Set::size);
}
@Override
int iint0() {
return 0;
}
}
int iint0() {
return 0;
}
static int sint0() {
return 0;
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.19.1</version>
<version>0.19.2-SNAPSHOT</version>
</parent>
<artifactId>error-prone-guidelines</artifactId>
@@ -77,6 +77,11 @@
<artifactId>guava</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>

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

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

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

@@ -0,0 +1,285 @@
package tech.picnic.errorprone.guidelines.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static com.google.errorprone.BugPattern.StandardTags.STYLE;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.instanceMethod;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.sun.tools.javac.util.Position.NOPOS;
import static java.util.stream.Collectors.joining;
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
import com.google.errorprone.BugPattern;
import com.google.errorprone.ErrorProneFlags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Supplier;
import com.google.errorprone.util.ASTHelpers;
import com.google.errorprone.util.SourceVersion;
import com.google.googlejavaformat.java.Formatter;
import com.google.googlejavaformat.java.FormatterException;
import com.google.googlejavaformat.java.ImportOrderer;
import com.google.googlejavaformat.java.JavaFormatterOptions.Style;
import com.google.googlejavaformat.java.RemoveUnusedImports;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.api.MultiTaskListener;
import com.sun.tools.javac.util.Context;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
import tech.picnic.errorprone.utils.SourceCode;
/**
* A {@link BugChecker} that flags improperly formatted Error Prone test code.
*
* <p>All test code should be formatted in accordance with Google Java Format's {@link Formatter}
* output, and imports should be ordered according to the {@link Style#GOOGLE Google} style.
*
* <p>This checker inspects inline code passed to {@code
* com.google.errorprone.CompilationTestHelper} and {@code
* com.google.errorprone.BugCheckerRefactoringTestHelper}. It requires that this code is properly
* formatted and that its imports are organized. Only code that represents the expected output of a
* refactoring operation is allowed to have unused imports, as most {@link BugChecker}s do not (and
* are not able to) remove imports that become obsolete as a result of applying their suggested
* fix(es).
*/
// XXX: The check does not flag well-formatted text blocks with insufficient or excess indentation.
// Cover this using an generic check or wait for Google Java Format support (see
// https://github.com/google/google-java-format/issues/883#issuecomment-1404336418).
@AutoService(BugChecker.class)
@BugPattern(
summary =
"""
Test code should follow the Google Java style (and when targeting JDK
15+ be specified using a single text block)""",
link = BUG_PATTERNS_BASE_URL + "TestHelperSourceFormat",
linkType = CUSTOM,
severity = SUGGESTION,
tags = STYLE)
// XXX: Drop this suppression if/when the `avoidTextBlocks` field is dropped.
@SuppressWarnings("java:S2160" /* Super class equality definition suffices. */)
public final class TestHelperSourceFormat extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final String FLAG_AVOID_TEXT_BLOCKS = "TestHelperSourceFormat:AvoidTextBlocks";
private static final Formatter FORMATTER = new Formatter();
private static final Matcher<ExpressionTree> INPUT_SOURCE_ACCEPTING_METHOD =
anyOf(
instanceMethod()
.onDescendantOf("com.google.errorprone.CompilationTestHelper")
.named("addSourceLines"),
instanceMethod()
.onDescendantOf("com.google.errorprone.BugCheckerRefactoringTestHelper")
.named("addInputLines"),
// XXX: Add tests for `Compilation.compileWithDocumentationGenerator`. Until done, make
// sure to update this matcher if that method's class or name is changed/moved.
// XXX: Alternatively, match any invocation of a method whose last argument is annotated
// `@Language("JAVA")`.
staticMethod()
.onClass("tech.picnic.errorprone.documentation.Compilation")
.named("compileWithDocumentationGenerator"));
private static final Matcher<ExpressionTree> OUTPUT_SOURCE_ACCEPTING_METHOD =
instanceMethod()
.onDescendantOf("com.google.errorprone.BugCheckerRefactoringTestHelper.ExpectOutput")
.named("addOutputLines");
private static final Supplier<Boolean> IS_JABEL_ENABLED =
VisitorState.memoize(TestHelperSourceFormat::isJabelEnabled);
private static final String DEFAULT_TEXT_BLOCK_INDENTATION = " ".repeat(12);
private static final String METHOD_SELECT_ARGUMENT_RELATIVE_INDENTATION = " ".repeat(8);
private final boolean avoidTextBlocks;
/** Instantiates a default {@link TestHelperSourceFormat} instance. */
public TestHelperSourceFormat() {
this(ErrorProneFlags.empty());
}
/**
* Instantiates a customized {@link TestHelperSourceFormat}.
*
* @param flags Any provided command line flags.
*/
@Inject
TestHelperSourceFormat(ErrorProneFlags flags) {
avoidTextBlocks = flags.getBoolean(FLAG_AVOID_TEXT_BLOCKS).orElse(Boolean.FALSE);
}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
boolean isOutputSource = OUTPUT_SOURCE_ACCEPTING_METHOD.matches(tree, state);
if (!isOutputSource && !INPUT_SOURCE_ACCEPTING_METHOD.matches(tree, state)) {
return Description.NO_MATCH;
}
List<? extends ExpressionTree> sourceLines =
tree.getArguments()
.subList(ASTHelpers.getSymbol(tree).params().size() - 1, tree.getArguments().size());
if (sourceLines.isEmpty()) {
return buildDescription(tree).setMessage("No source code provided").build();
}
/* Attempt to format the source code only if it fully consists of constant expressions. */
return SourceCode.joinConstantSourceCodeLines(sourceLines)
.map(source -> flagFormattingIssues(sourceLines, source, isOutputSource, state))
.orElse(Description.NO_MATCH);
}
private Description flagFormattingIssues(
List<? extends ExpressionTree> sourceLines,
String source,
boolean retainUnusedImports,
VisitorState state) {
MethodInvocationTree methodInvocation = (MethodInvocationTree) state.getPath().getLeaf();
String formatted;
try {
String gjfResult = formatSourceCode(source, retainUnusedImports);
formatted = canUseTextBlocks(sourceLines, state) ? gjfResult : gjfResult.stripTrailing();
} catch (
@SuppressWarnings("java:S1166" /* Stack trace not relevant. */)
FormatterException e) {
return buildDescription(methodInvocation)
.setMessage(String.format("Source code is malformed: %s", e.getMessage()))
.build();
}
boolean isFormatted = source.equals(formatted);
boolean hasStringLiteralMismatch = shouldUpdateStringLiteralFormat(sourceLines, state);
if (isFormatted && !hasStringLiteralMismatch) {
return Description.NO_MATCH;
}
int startPos = ASTHelpers.getStartPosition(sourceLines.get(0));
int endPos = state.getEndPosition(sourceLines.get(sourceLines.size() - 1));
boolean hasNewlineMismatch =
!isFormatted && source.stripTrailing().equals(formatted.stripTrailing());
/*
* The source code is not properly formatted and/or not specified using a single text block.
* Report the more salient of the violations, and suggest a fix if sufficient source information
* is available.
*/
boolean isTextBlockUsageIssue = isFormatted || (hasNewlineMismatch && hasStringLiteralMismatch);
boolean canSuggestFix = startPos != NOPOS && endPos != NOPOS;
return buildDescription(methodInvocation)
.setMessage(
isTextBlockUsageIssue
? String.format(
"Test code should %sbe specified using a single text block",
avoidTextBlocks ? "not " : "")
: String.format(
"Test code should follow the Google Java style%s",
hasNewlineMismatch ? " (pay attention to trailing newlines)" : ""))
.addFix(
canSuggestFix
? SuggestedFix.replace(
startPos,
endPos,
canUseTextBlocks(sourceLines, state)
? toTextBlockExpression(methodInvocation, formatted, state)
: toLineEnumeration(formatted, state))
: SuggestedFix.emptyFix())
.build();
}
private boolean shouldUpdateStringLiteralFormat(
List<? extends ExpressionTree> sourceLines, VisitorState state) {
return canUseTextBlocks(sourceLines, state)
? (sourceLines.size() > 1 || !SourceCode.isTextBlock(sourceLines.get(0), state))
: sourceLines.stream().anyMatch(tree -> SourceCode.isTextBlock(tree, state));
}
private boolean canUseTextBlocks(List<? extends ExpressionTree> sourceLines, VisitorState state) {
return !avoidTextBlocks
&& (SourceVersion.supportsTextBlocks(state.context)
|| IS_JABEL_ENABLED.get(state)
|| sourceLines.stream().anyMatch(line -> SourceCode.isTextBlock(line, state)));
}
private static String toTextBlockExpression(
MethodInvocationTree tree, String source, VisitorState state) {
String indentation = suggestTextBlockIndentation(tree, state);
// XXX: Verify trailing """ on new line.
return SourceCode.TEXT_BLOCK_DELIMITER
+ System.lineSeparator()
+ indentation
+ source
.replace(SourceCode.TEXT_BLOCK_LINE_SEPARATOR, System.lineSeparator() + indentation)
.replace("\\", "\\\\")
.replace(SourceCode.TEXT_BLOCK_DELIMITER, "\"\"\\\"")
+ SourceCode.TEXT_BLOCK_DELIMITER;
}
private static String toLineEnumeration(String source, VisitorState state) {
return Splitter.on(SourceCode.TEXT_BLOCK_LINE_SEPARATOR)
.splitToStream(source)
.map(state::getConstantExpression)
.collect(joining(", "));
}
// XXX: This makes certain assumptions; document these.
private static String suggestTextBlockIndentation(
MethodInvocationTree target, VisitorState state) {
CharSequence sourceCode = state.getSourceCode();
if (sourceCode == null) {
return DEFAULT_TEXT_BLOCK_INDENTATION;
}
String source = sourceCode.toString();
return getIndentation(target.getArguments().get(1), source)
.or(() -> getIndentation(target.getArguments().get(0), source))
.or(
() ->
getIndentation(target.getMethodSelect(), source)
.map(METHOD_SELECT_ARGUMENT_RELATIVE_INDENTATION::concat))
.orElse(DEFAULT_TEXT_BLOCK_INDENTATION);
}
private static Optional<String> getIndentation(Tree tree, String source) {
int startPos = ASTHelpers.getStartPosition(tree);
if (startPos == NOPOS) {
return Optional.empty();
}
int finalNewLine = source.lastIndexOf(System.lineSeparator(), startPos);
if (finalNewLine < 0) {
return Optional.empty();
}
return Optional.of(source.substring(finalNewLine + System.lineSeparator().length(), startPos))
.filter(CharMatcher.whitespace()::matchesAllOf);
}
private static String formatSourceCode(String source, boolean retainUnusedImports)
throws FormatterException {
String withReorderedImports = ImportOrderer.reorderImports(source, Style.GOOGLE);
String withOptionallyRemovedImports =
retainUnusedImports
? withReorderedImports
: RemoveUnusedImports.removeUnusedImports(withReorderedImports);
return FORMATTER.formatSource(withOptionallyRemovedImports);
}
/**
* Tells whether Jabel appears to be enabled, indicating that text blocks are supported, even if
* may <em>appear</em> that they {@link SourceVersion#supportsTextBlocks(Context) aren't}.
*
* @see <a href="https://github.com/bsideup/jabel">Jabel</a>
*/
private static boolean isJabelEnabled(VisitorState state) {
return MultiTaskListener.instance(state.context).getTaskListeners().stream()
.anyMatch(listener -> listener.toString().contains("com.github.bsideup.jabel"));
}
}

View File

@@ -11,44 +11,46 @@ final class AssociativeMethodInvocationTest {
CompilationTestHelper.newInstance(AssociativeMethodInvocation.class, getClass())
.addSourceLines(
"A.java",
"import com.google.common.collect.ImmutableList;",
"import com.google.errorprone.matchers.Matchers;",
"import com.google.errorprone.refaster.Refaster;",
"",
"class A {",
" void m() {",
" Matchers.allOf();",
" Matchers.anyOf();",
" Refaster.anyOf();",
"",
" Matchers.allOf((t, s) -> true);",
" Matchers.anyOf((t, s) -> true);",
" Refaster.anyOf(0);",
"",
" Matchers.allOf(Matchers.anyOf((t, s) -> true));",
" Matchers.anyOf(Matchers.allOf((t, s) -> true));",
" Refaster.anyOf(Matchers.allOf((t, s) -> true));",
"",
" // BUG: Diagnostic contains:",
" Matchers.allOf(Matchers.allOf((t, s) -> true));",
" // BUG: Diagnostic contains:",
" Matchers.anyOf(Matchers.anyOf((t, s) -> true));",
" // BUG: Diagnostic contains:",
" Refaster.anyOf(Refaster.anyOf(0));",
"",
" Matchers.allOf(Matchers.allOf(ImmutableList.of((t, s) -> true)));",
" Matchers.anyOf(Matchers.anyOf(ImmutableList.of((t, s) -> true)));",
"",
" // BUG: Diagnostic contains:",
" Matchers.allOf(",
" (t, s) -> true, Matchers.allOf((t, s) -> false, (t, s) -> true), (t, s) -> false);",
" // BUG: Diagnostic contains:",
" Matchers.anyOf(",
" (t, s) -> true, Matchers.anyOf((t, s) -> false, (t, s) -> true), (t, s) -> false);",
" // BUG: Diagnostic contains:",
" Refaster.anyOf(0, Refaster.anyOf(1, 2), 3);",
" }",
"}")
"""
import com.google.common.collect.ImmutableList;
import com.google.errorprone.matchers.Matchers;
import com.google.errorprone.refaster.Refaster;
class A {
void m() {
Matchers.allOf();
Matchers.anyOf();
Refaster.anyOf();
Matchers.allOf((t, s) -> true);
Matchers.anyOf((t, s) -> true);
Refaster.anyOf(0);
Matchers.allOf(Matchers.anyOf((t, s) -> true));
Matchers.anyOf(Matchers.allOf((t, s) -> true));
Refaster.anyOf(Matchers.allOf((t, s) -> true));
// BUG: Diagnostic contains:
Matchers.allOf(Matchers.allOf((t, s) -> true));
// BUG: Diagnostic contains:
Matchers.anyOf(Matchers.anyOf((t, s) -> true));
// BUG: Diagnostic contains:
Refaster.anyOf(Refaster.anyOf(0));
Matchers.allOf(Matchers.allOf(ImmutableList.of((t, s) -> true)));
Matchers.anyOf(Matchers.anyOf(ImmutableList.of((t, s) -> true)));
// BUG: Diagnostic contains:
Matchers.allOf(
(t, s) -> true, Matchers.allOf((t, s) -> false, (t, s) -> true), (t, s) -> false);
// BUG: Diagnostic contains:
Matchers.anyOf(
(t, s) -> true, Matchers.anyOf((t, s) -> false, (t, s) -> true), (t, s) -> false);
// BUG: Diagnostic contains:
Refaster.anyOf(0, Refaster.anyOf(1, 2), 3);
}
}
""")
.doTest();
}
@@ -57,54 +59,58 @@ final class AssociativeMethodInvocationTest {
BugCheckerRefactoringTestHelper.newInstance(AssociativeMethodInvocation.class, getClass())
.addInputLines(
"A.java",
"import com.google.errorprone.matchers.Matchers;",
"import com.google.errorprone.refaster.Refaster;",
"",
"class A {",
" void m() {",
" Matchers.allOf(Matchers.allOf());",
" Matchers.anyOf(Matchers.anyOf());",
" Refaster.anyOf(Refaster.anyOf());",
"",
" Matchers.allOf(Matchers.allOf((t, s) -> true));",
" Matchers.anyOf(Matchers.anyOf((t, s) -> true));",
" Refaster.anyOf(Refaster.anyOf(0));",
"",
" Matchers.allOf(",
" Matchers.anyOf(),",
" Matchers.allOf((t, s) -> false, (t, s) -> true),",
" Matchers.allOf(),",
" Matchers.anyOf((t, s) -> false));",
" Matchers.anyOf(",
" Matchers.allOf(),",
" Matchers.anyOf((t, s) -> false, (t, s) -> true),",
" Matchers.anyOf(),",
" Matchers.allOf((t, s) -> false));",
" Refaster.anyOf(Matchers.allOf(), Refaster.anyOf(1, 2), Matchers.anyOf());",
" }",
"}")
"""
import com.google.errorprone.matchers.Matchers;
import com.google.errorprone.refaster.Refaster;
class A {
void m() {
Matchers.allOf(Matchers.allOf());
Matchers.anyOf(Matchers.anyOf());
Refaster.anyOf(Refaster.anyOf());
Matchers.allOf(Matchers.allOf((t, s) -> true));
Matchers.anyOf(Matchers.anyOf((t, s) -> true));
Refaster.anyOf(Refaster.anyOf(0));
Matchers.allOf(
Matchers.anyOf(),
Matchers.allOf((t, s) -> false, (t, s) -> true),
Matchers.allOf(),
Matchers.anyOf((t, s) -> false));
Matchers.anyOf(
Matchers.allOf(),
Matchers.anyOf((t, s) -> false, (t, s) -> true),
Matchers.anyOf(),
Matchers.allOf((t, s) -> false));
Refaster.anyOf(Matchers.allOf(), Refaster.anyOf(1, 2), Matchers.anyOf());
}
}
""")
.addOutputLines(
"A.java",
"import com.google.errorprone.matchers.Matchers;",
"import com.google.errorprone.refaster.Refaster;",
"",
"class A {",
" void m() {",
" Matchers.allOf();",
" Matchers.anyOf();",
" Refaster.anyOf();",
"",
" Matchers.allOf((t, s) -> true);",
" Matchers.anyOf((t, s) -> true);",
" Refaster.anyOf(0);",
"",
" Matchers.allOf(",
" Matchers.anyOf(), (t, s) -> false, (t, s) -> true, Matchers.anyOf((t, s) -> false));",
" Matchers.anyOf(",
" Matchers.allOf(), (t, s) -> false, (t, s) -> true, Matchers.allOf((t, s) -> false));",
" Refaster.anyOf(Matchers.allOf(), 1, 2, Matchers.anyOf());",
" }",
"}")
"""
import com.google.errorprone.matchers.Matchers;
import com.google.errorprone.refaster.Refaster;
class A {
void m() {
Matchers.allOf();
Matchers.anyOf();
Refaster.anyOf();
Matchers.allOf((t, s) -> true);
Matchers.anyOf((t, s) -> true);
Refaster.anyOf(0);
Matchers.allOf(
Matchers.anyOf(), (t, s) -> false, (t, s) -> true, Matchers.anyOf((t, s) -> false));
Matchers.anyOf(
Matchers.allOf(), (t, s) -> false, (t, s) -> true, Matchers.allOf((t, s) -> false));
Refaster.anyOf(Matchers.allOf(), 1, 2, Matchers.anyOf());
}
}
""")
.doTest(TestMode.TEXT_MATCH);
}
}

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