Compare commits

...

219 Commits

Author SHA1 Message Date
Gijs de Jong
c14c7de88c Use settings.xml in jitpack build 2023-09-01 14:35:07 +02:00
Gijs de Jong
cb7f84bb79 Build with refaster speedup fork 2023-09-01 14:28:42 +02:00
Gijs de Jong
1041b7ff36 add jitpack.yml config 2023-09-01 13:37:50 +02:00
Gijs de Jong
0baedb4383 fix build 2023-08-17 13:24:15 +02:00
Gijs de Jong
12d9361e5c rebase 2023-08-17 13:12:57 +02:00
Stephan Schroevers
68b3780d4e Suggestions 2023-08-17 10:26:28 +02:00
Stephan Schroevers
539f358d17 Suggestions 2023-08-17 10:23:12 +02:00
Rick Ossendrijver
4d27038906 Revert changes in OptionalTemplates 2023-08-17 10:21:34 +02:00
Rick Ossendrijver
8dc1876414 Move AnnotatedCompositeCodeTransformer and ErrorProneFork to refaster-support 2023-08-17 10:20:31 +02:00
Stephan Schroevers
4c246c1e76 Tweaks 2023-08-17 10:18:50 +02:00
Pieter Dirk Soels
e9957e1f4e Pass null for urlLink to Description.Builder 2023-08-17 10:18:30 +02:00
Pieter Dirk Soels
6da37e206d Suggestion 2023-08-17 10:17:56 +02:00
Stephan Schroevers
390a889316 Clarify how the default Refaster hit severity comes to be
Plus other tweaks.
2023-08-17 10:17:36 +02:00
Stephan Schroevers
a9fa40804e Suggestions, introduce ErrorProneFork 2023-08-17 10:16:22 +02:00
Rick Ossendrijver
bb5fd10943 Tweak 2023-08-17 10:15:15 +02:00
Rick Ossendrijver
2a6aa41c23 Support AllSuggestionsAsWarnings and add a suggestion 2023-08-17 10:15:13 +02:00
Rick Ossendrijver
6edad4d735 Use @AutoValue for the AnnotatedCompositeCodeTransformer 2023-08-17 10:14:20 +02:00
Stephan Schroevers
d72a587ab2 Flag classpath issue 2023-08-17 10:13:07 +02:00
Stephan Schroevers
66e2542470 Expand test coverage 2023-08-17 10:13:06 +02:00
Stephan Schroevers
bdcdf7fe8e Properly document URL placeholder usage 2023-08-17 10:10:53 +02:00
Stephan Schroevers
8d79f67329 Improve logic and test coverage 2023-08-17 10:10:11 +02:00
Stephan Schroevers
9e47679822 Flag why build currently doesn't fail, while it should. 2023-08-17 10:06:02 +02:00
Stephan Schroevers
6fff10f07d Better annotation support, simplify setup 2023-08-17 10:05:22 +02:00
Stephan Schroevers
b9c7357ecc Tweaks 2023-08-17 10:03:00 +02:00
Stephan Schroevers
b9482b4c1e Another round 2023-08-17 10:01:34 +02:00
Stephan Schroevers
27139482c0 WIP: Some plumbing for annotation support
To be used for custom links, custom error messages, custom other stuff...
2023-08-14 17:08:24 +02:00
Stephan Schroevers
de091f7a87 More extensible approach 2023-08-14 17:04:52 +02:00
Stephan Schroevers
7175663bed Emit website link along with Refaster refactor suggestions 2023-08-14 17:03:57 +02:00
Stephan Schroevers
7c0b3af53b Suggestions 2023-08-14 17:02:24 +02:00
Ivan Babiankou
2ad2722b02 Suggestions 2023-08-14 17:02:23 +02:00
Rick Ossendrijver
29ad499995 Fix typo 2023-08-14 17:01:55 +02:00
Stephan Schroevers
86e8caa321 Comment style, explain both performance-only pieces of code
Since PIT correctly flags these as "redundant".

Also for JDK 11 compatibility.
2023-08-14 17:01:55 +02:00
Stephan Schroevers
53ad3aa61f Optimize code, introduce benchmark, simplify test 2023-08-14 17:01:51 +02:00
Stephan Schroevers
58dd1bf85a Apply some suggestions 2023-08-14 17:00:23 +02:00
Rick Ossendrijver
2f8d525bc8 Reorder methods in RefasterIntrospection 2023-08-14 17:00:23 +02:00
Rick Ossendrijver
8c7aee2398 Introduce getClass method to deduplicate 2023-08-14 17:00:22 +02:00
Rick Ossendrijver
3e0341591a Extract the TreeScanners to their own classes 2023-08-14 17:00:22 +02:00
Rick Ossendrijver
28493a61cd Suggestion 2023-08-14 17:00:22 +02:00
Stephan Schroevers
4ae58e77f3 Push sorting requirements into Node, minimize tree, add tests 2023-08-14 17:00:22 +02:00
Stephan Schroevers
1d1332542c Move all RefasterRuleSelector construction logic into the relevant class 2023-08-14 17:00:16 +02:00
Stephan Schroevers
693932df56 Create selector only once per Refaster instantiation 2023-08-14 16:59:53 +02:00
Stephan Schroevers
7daedc714d Merge RefasterRuleSelector type hierarchy 2023-08-14 16:59:53 +02:00
Rick Ossendrijver
b91bfc7919 Add XXXs 2023-08-14 16:59:53 +02:00
Rick Ossendrijver
ba83279aee Drop unnecessary @AutoService annotation 2023-08-14 16:59:53 +02:00
Rick Ossendrijver
a6e70b0661 Improve code and algorithm for Refaster 2023-08-14 16:59:53 +02:00
Rick Ossendrijver
923e977c4d Initial copy over of the improved algorithm 2023-08-14 16:59:49 +02:00
Stephan Schroevers
292869077e Compatibility with stock Error Prone 2023-08-14 16:58:13 +02:00
Stephan Schroevers
2f727db8ce WIP: Speed up Refaster check
This code assumes a modification of Error Prone; see the
`sschroevers/refaster-tree-tweaks` branch on the fork.
2023-08-14 16:58:07 +02:00
Giovanni Zotta
7fb0e551d4 Introduce VerifyOnlyElementInFlux Refaster rule (#617) 2023-08-14 14:05:14 +02:00
Mohamed Sameh
4af7b21bf5 Introduce NestedPublishers check (#642)
And introduce a few utility methods that simplify `Tree`- and `Type`-based
matching, allowing the existing (and similar) `NestedOptionals` check to be
simplified as well.
2023-08-14 10:30:45 +02:00
Picnic-Bot
fc5f3bd4cc Upgrade Pitest Git plugins 1.1.0 -> 1.1.1 (#750) 2023-08-14 08:52:14 +02:00
Mohamed Sameh
35a5944b81 Introduce {Flux,{Double,Int,Long,}Stream}TakeWhile Refaster rules (#727) 2023-08-12 15:36:43 +02:00
Picnic-Bot
17cc8e0c31 Upgrade CodeQL v2.21.2 -> v2.21.3 (#746)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.21.2...v2.21.3
2023-08-12 14:39:33 +02:00
Picnic-Bot
b5ba4fa208 Upgrade actions/deploy-pages v2.0.3 -> v2.0.4 (#747)
See:
- https://github.com/actions/deploy-pages/releases/tag/v2.0.4
2023-08-12 14:28:35 +02:00
Picnic-Bot
26b941bbc5 Upgrade Guava 32.1.1-jre -> 32.1.2-jre (#735)
See:
- https://github.com/google/guava/releases/tag/v32.1.2
- https://github.com/google/guava/compare/v32.1.1...v32.1.2
2023-08-12 14:18:05 +02:00
Picnic-Bot
eb3b540537 Upgrade pitest-maven-plugin 1.14.2 -> 1.14.3 (#748)
See:
- https://github.com/hcoles/pitest/releases/tag/1.14.3
- https://github.com/hcoles/pitest/compare/1.14.2...1.14.3
2023-08-12 14:05:50 +02:00
Picnic-Bot
6a11b59517 Upgrade CodeQL v2.20.3 -> v2.21.2 (#722)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.20.3...v2.21.2
2023-08-07 11:47:08 +02:00
Picnic-Bot
62abd51f4d Upgrade errorprone-slf4j 0.1.18 -> 0.1.20 (#741)
See:
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.19
- https://github.com/KengoTODA/errorprone-slf4j/releases/tag/v0.1.20
- https://github.com/KengoTODA/errorprone-slf4j/compare/v0.1.18...v0.1.20
2023-08-07 07:24:39 +02:00
Rick Ossendrijver
67a128a9b6 Fix typos in CanonicalSyntaxAnnotation source (#738) 2023-08-06 16:18:29 +02:00
Picnic-Bot
526227e8ed Upgrade Error Prone 2.21.0 -> 2.21.1 (#743)
See:
- https://github.com/google/error-prone/releases/tag/v2.21.1
- https://github.com/google/error-prone/compare/v2.21.0...v2.21.1
- https://github.com/PicnicSupermarket/error-prone/compare/v2.21.0-picnic-1...v2.21.1-picnic-1
2023-08-06 16:06:25 +02:00
Picnic-Bot
c2e837819e Upgrade Pitest Git plugins 1.0.12 -> 1.1.0 (#742) 2023-08-06 11:15:07 +02:00
Picnic-Bot
fd70be081e Upgrade Arcmutate 1.1.2 -> 1.1.3 (#739) 2023-08-05 20:13:27 +02:00
Picnic-Bot
2c47244571 Upgrade NullAway 0.10.11 -> 0.10.12 (#740)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/releases/tag/v0.10.12
- https://github.com/uber/NullAway/compare/v0.10.11...v0.10.12
2023-08-05 13:27:26 +02:00
Picnic-Bot
8375f1650f Upgrade Error Prone 2.20.0 -> 2.21.0 (#737)
See:
- https://github.com/google/error-prone/releases/tag/v2.21.0
- https://github.com/google/error-prone/compare/v2.20.0...v2.21.0
- https://github.com/PicnicSupermarket/error-prone/compare/v2.20.0-picnic-1...v2.21.0-picnic-1
2023-08-03 11:06:33 +02:00
Picnic-Bot
c4daa04ce1 Upgrade Checker Framework Annotations 3.36.0 -> 3.37.0 (#736)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.37.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.36.0...checker-framework-3.37.0
2023-08-03 10:36:41 +02:00
Picnic-Bot
08f0e52104 Upgrade sortpom-maven-plugin 3.2.1 -> 3.3.0 (#731)
See:
- https://github.com/Ekryd/sortpom/wiki/Versions
- https://github.com/Ekryd/sortpom/releases/tag/sortpom-parent-3.3.0
- https://github.com/Ekryd/sortpom/compare/sortpom-parent-3.2.1...sortpom-parent-3.3.0
2023-08-02 14:39:18 +02:00
Picnic-Bot
10070bd4c8 Upgrade JUnit 5 5.9.3 -> 5.10.0 (#729)
See:
- https://junit.org/junit5/docs/current/release-notes/
- https://github.com/junit-team/junit5/releases/tag/r5.10.0-M1
- https://github.com/junit-team/junit5/releases/tag/r5.10.0-RC1
- https://github.com/junit-team/junit5/releases/tag/r5.10.0-RC2
- https://github.com/junit-team/junit5/releases/tag/r5.10.0
- https://github.com/junit-team/junit5/compare/r5.9.3...r5.10.0
2023-08-01 15:54:26 +02:00
Picnic-Bot
3c38fd3495 Upgrade actions/setup-java v3.11.0 -> v3.12.0 (#730)
See https://github.com/actions/setup-java/releases/tag/v3.12.0
2023-08-01 09:54:17 +02:00
Picnic-Bot
d54ec83844 Upgrade New Relic Java Agent 8.4.0 -> 8.5.0 (#732)
See:
- https://github.com/newrelic/newrelic-java-agent/releases/tag/v8.5.0
- https://github.com/newrelic/newrelic-java-agent/compare/v8.4.0...v8.5.0
2023-08-01 08:12:06 +02:00
Philip Leonard
e03d0de366 Introduce MongoDBTextFilterUsage check (#649) 2023-07-31 17:19:39 +02:00
Picnic-Bot
b40c5d61b9 Upgrade Checkstyle 10.12.1 -> 10.12.2 (#734)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.12.2
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.12.1...checkstyle-10.12.2
2023-07-31 12:54:47 +02:00
Picnic-Bot
6d27e46baf Upgrade Spring 5.3.28 -> 5.3.29 (#723)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.29
- https://github.com/spring-projects/spring-framework/compare/v5.3.28...v5.3.29
2023-07-24 08:15:30 +02:00
Picnic-Bot
8f48497322 Upgrade Spring Boot 2.7.13 -> 2.7.14 (#726)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.14
- https://github.com/spring-projects/spring-boot/compare/v2.7.13...v2.7.14
2023-07-23 12:41:36 +02:00
Stephan Schroevers
38554be3d1 Upgrade Error Prone fork v2.20.0-picnic-1 -> v2.20.0-picnic-2 (#725)
This new release is a workaround for jitpack/jitpack.io#5741.

See https://github.com/PicnicSupermarket/error-prone/compare/v2.20.0-picnic-1...v2.20.0-picnic-2
2023-07-19 09:16:40 +02:00
Picnic-Bot
28cdb91913 Upgrade Project Reactor 2022.0.8 -> 2022.0.9 (#721)
See:
- https://github.com/reactor/reactor/releases/tag/2022.0.9
- https://github.com/reactor/reactor/compare/2022.0.8...2022.0.9
2023-07-13 11:19:52 +02:00
Picnic-Bot
bd6693d23e Upgrade actions/deploy-pages v2.0.2 -> v2.0.3 (#718)
See:
- https://github.com/actions/deploy-pages/releases/tag/v2.0.3
2023-07-11 12:51:40 +02:00
Picnic-Bot
a3ec76845a Upgrade actions/upload-pages-artifact v1.0.9 -> v2.0.0 (#720)
See:
- https://github.com/actions/upload-pages-artifact/releases/tag/v2.0.0
- https://github.com/actions/upload-pages-artifact/releases/tag/v1.0.10
2023-07-11 08:55:31 +02:00
Picnic-Bot
e3b310761d Upgrade Swagger 2.2.14 -> 2.2.15 (#717)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.15
- https://github.com/swagger-api/swagger-core/compare/v2.2.14...v2.2.15
2023-07-10 08:55:50 +02:00
Picnic-Bot
774052f13a Upgrade CodeQL v2.20.2 -> v2.20.3 (#715)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.20.2...v2.20.3
2023-07-07 15:11:45 +02:00
Picnic-Bot
bad7684639 Upgrade Arcmutate 1.1.1 -> 1.1.2 (#714) 2023-07-07 10:40:15 +02:00
Picnic-Bot
dd72b5a08a Upgrade Checker Framework Annotations 3.35.0 -> 3.36.0 (#711)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.36.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.35.0...checker-framework-3.36.0
2023-07-06 11:15:26 +02:00
Picnic-Bot
3eb30c5f93 Upgrade Guava 32.0.1-jre -> 32.1.1-jre (#705)
See:
- https://github.com/google/guava/releases/tag/v32.1.0
- https://github.com/google/guava/releases/tag/v32.1.1
- https://github.com/google/guava/compare/v32.0.1...v32.1.1
2023-07-06 10:22:56 +02:00
Picnic-Bot
2cc0539f8f Upgrade CodeQL v2.20.1 -> v2.20.2 (#707)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.20.1...v2.20.2
2023-07-06 09:38:52 +02:00
Picnic-Bot
9210c30a0a Upgrade Pitest JUnit 5 Accelerator 1.0.5 -> 1.0.6 (#709) 2023-07-06 08:48:05 +02:00
Picnic-Bot
ba362ed460 Upgrade license-maven-plugin 2.1.0 -> 2.2.0 (#712)
See:
- https://github.com/mojohaus/license-maven-plugin/releases/tag/2.2.0
- https://github.com/mojohaus/license-maven-plugin/compare/2.1.0...2.2.0
2023-07-05 17:59:46 +02:00
Picnic-Bot
ab33adfab8 Upgrade Arcmutate 1.1.0 -> 1.1.1 (#708) 2023-07-05 17:48:22 +02:00
Rick Ossendrijver
006665ee6d Introduce MonoSingle Refaster rule (#703) 2023-07-05 13:54:49 +02:00
Picnic-Bot
08c49b9a58 Upgrade Pitest Git plugins 1.0.11 -> 1.0.12 (#710) 2023-07-05 13:42:54 +02:00
Picnic-Bot
777aa970f1 Upgrade ruby/setup-ruby v1.126.0 -> v1.152.0 (#706)
See:
- https://github.com/ruby/setup-ruby/releases/tag/v1.152.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.151.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.150.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.149.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.148.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.147.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.146.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.145.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.144.2
- https://github.com/ruby/setup-ruby/releases/tag/v1.144.1
- https://github.com/ruby/setup-ruby/releases/tag/v1.144.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.143.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.142.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.141.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.140.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.139.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.138.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.137.2
- https://github.com/ruby/setup-ruby/releases/tag/v1.137.1
- https://github.com/ruby/setup-ruby/releases/tag/v1.137.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.136.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.135.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.134.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.133.2
- https://github.com/ruby/setup-ruby/releases/tag/v1.133.1
- https://github.com/ruby/setup-ruby/releases/tag/v1.133.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.132.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.131.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.130.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.129.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.128.0
- https://github.com/ruby/setup-ruby/releases/tag/v1.127.0
2023-07-05 12:18:29 +02:00
Picnic-Bot
a040310870 Upgrade AutoValue 1.10.1 -> 1.10.2 (#704)
See:
- https://github.com/google/auto/releases/tag/auto-value-1.10.2
- https://github.com/google/auto/compare/auto-value-1.10.1...auto-value-1.10.2
2023-06-30 12:59:26 +02:00
Picnic-Bot
d6ab366f31 Upgrade CodeQL v2.2.11 -> v2.20.1 (#670)
See:
- https://github.com/github/codeql-action/blob/main/CHANGELOG.md
- https://github.com/github/codeql-action/compare/v2.20.0...v2.20.1
- https://github.com/github/codeql-action/compare/v2.3.6...v2.20.0
- https://github.com/github/codeql-action/compare/v2.3.5...v2.3.6
- https://github.com/github/codeql-action/compare/v2.3.4...v2.3.5
- https://github.com/github/codeql-action/compare/v2.3.3...v2.3.4
- https://github.com/github/codeql-action/compare/v2.3.2...v2.3.3
- https://github.com/github/codeql-action/compare/v2.3.1...v2.3.2
- https://github.com/github/codeql-action/compare/v2.3.0...v2.3.1
- https://github.com/github/codeql-action/compare/v2.2.12...v2.3.0
- https://github.com/github/codeql-action/compare/v2.2.11...v2.2.12
2023-06-28 13:20:53 +02:00
Picnic-Bot
d9fefa6824 Upgrade Swagger 2.2.13 -> 2.2.14 (#702)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.14
- https://github.com/swagger-api/swagger-core/compare/v2.2.13...v2.2.14
2023-06-27 08:28:08 +02:00
Picnic-Bot
c8b3a6df82 Upgrade pitest-maven-plugin 1.14.1 -> 1.14.2 (#696)
See:
- https://github.com/hcoles/pitest/releases/tag/1.14.2
- https://github.com/hcoles/pitest/compare/1.14.1...1.14.2
2023-06-26 12:07:21 +02:00
Picnic-Bot
782a790def Upgrade NullAway 0.10.10 -> 0.10.11 (#695)
See:
- https://github.com/uber/NullAway/blob/master/CHANGELOG.md
- https://github.com/uber/NullAway/compare/v0.10.10...v0.10.11
2023-06-26 11:31:05 +02:00
Picnic-Bot
706b5f401f Upgrade Checkstyle 10.12.0 -> 10.12.1 (#699)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.12.1
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.12.0...checkstyle-10.12.1
2023-06-26 11:20:21 +02:00
Picnic-Bot
9f500fd5bb Upgrade ossf/scorecard-action v2.1.3 -> v2.2.0 (#697)
And link to the new scorecard report page.

See:
- https://github.com/ossf/scorecard-action/releases/tag/v2.2.0
- https://github.com/ossf/scorecard-action/compare/v2.1.3...v2.2.0
2023-06-26 09:50:25 +02:00
Picnic-Bot
f541cd2e52 Upgrade Swagger 2.2.12 -> 2.2.13 (#698)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.13
- https://github.com/swagger-api/swagger-core/compare/v2.2.12...v2.2.13
2023-06-26 09:20:25 +02:00
Picnic-Bot
fc862aad94 Upgrade maven-clean-plugin 3.2.0 -> 3.3.1 (#693)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MCLEAN%20AND%20fixVersion%20%3E%203.2.0%20AND%20fixVersion%20%3C%3D%203.3.1
- https://github.com/apache/maven-clean-plugin/compare/maven-clean-plugin-3.2.0...maven-clean-plugin-3.3.1
2023-06-23 17:47:37 +02:00
Picnic-Bot
42810bc00c Upgrade Spring Boot 2.7.12 -> 2.7.13 (#694)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.13
- https://github.com/spring-projects/spring-boot/compare/v2.7.12...v2.7.13
2023-06-23 11:11:10 +02:00
Picnic-Bot
f17d736356 Upgrade AutoCommon 1.2.1 -> 1.2.2 (#681)
See:
- https://github.com/google/auto/releases/tag/auto-common-1.2.2
- https://github.com/google/auto/compare/auto-common-1.2.1...auto-common-1.2.2
2023-06-23 10:32:40 +02:00
Picnic-Bot
705acc9164 Upgrade Spring 5.3.27 -> 5.3.28 (#687)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.28
- https://github.com/spring-projects/spring-framework/compare/v5.3.27...v5.3.28
2023-06-23 10:19:13 +02:00
Picnic-Bot
bb969a8b80 Upgrade Mockito 5.3.1 -> 5.4.0 (#689)
See:
- https://github.com/mockito/mockito/releases/tag/v5.4.0
- https://github.com/mockito/mockito/compare/v5.3.1...v5.4.0
2023-06-23 10:09:55 +02:00
Picnic-Bot
c5a700c555 Upgrade Truth 1.1.4 -> 1.1.5 (#688)
See:
- https://github.com/google/truth/releases/tag/v1.1.5
- https://github.com/google/truth/compare/v1.1.4...v1.1.5
2023-06-23 09:56:42 +02:00
Picnic-Bot
2837a04433 Upgrade New Relic Java Agent 8.3.0 -> 8.4.0 (#690)
See:
- https://github.com/newrelic/newrelic-java-agent/releases/tag/v8.4.0
- https://github.com/newrelic/newrelic-java-agent/compare/v8.3.0...v8.4.0
2023-06-22 11:55:19 +02:00
Picnic-Bot
74222e8fa5 Upgrade Arcmutate 1.0.5 -> 1.1.0 (#692) 2023-06-22 09:25:43 +02:00
Stephan Schroevers
dc36ff2c0b [maven-release-plugin] prepare for next development iteration 2023-06-21 21:15:38 +02:00
Stephan Schroevers
09208aa49a [maven-release-plugin] prepare release v0.12.0 2023-06-21 21:15:38 +02:00
Stephan Schroevers
b81ec973a1 Upgrade Error Prone 2.19.1 -> 2.20.0 (#685)
Summary of key changes:
- The `MissingRefasterAnnotation` check was contributed to Error Prone,
  and so is deleted here (multiple checks with the same name are not
  supported).
- Similarly, Error Prone now supports the `-XepAllSuggestionsAsWarnings`
  flag out of the box. So the `ErrorProneFork` class is deleted, as it
  has currently no further use.

While there, include a tweak to `run-mutation-tests.sh`.

Fixes #686.

See:
- https://github.com/google/error-prone/releases/tag/v2.20.0
- https://github.com/google/error-prone/compare/v2.19.1...v2.20.0
- https://github.com/PicnicSupermarket/error-prone/compare/v2.19.1-picnic-1...v2.20.0-picnic-1
2023-06-20 15:52:26 +02:00
Picnic-Bot
8fb57b5bab Upgrade actions/upload-artifact v3.1.1 -> v3.1.2 (#664)
See:
- https://github.com/actions/upload-artifact/releases/tag/v3.1.2
2023-06-20 09:01:33 +02:00
Picnic-Bot
f4aaa5852c Upgrade dawidd6/action-download-artifact v2.24.2 -> v2.27.0 (#669)
See:
- https://github.com/dawidd6/action-download-artifact/compare/v2.26.1...v2.27.0
- https://github.com/dawidd6/action-download-artifact/compare/v2.26.0...v2.26.1
- https://github.com/dawidd6/action-download-artifact/compare/v2.25.0...v2.26.0
- https://github.com/dawidd6/action-download-artifact/compare/v2.24.4...v2.25.0
- https://github.com/dawidd6/action-download-artifact/compare/v2.24.3...v2.24.4
- https://github.com/dawidd6/action-download-artifact/compare/v2.24.2...v2.24.3
2023-06-19 11:54:34 +02:00
Picnic-Bot
2148b7ede4 Upgrade actions/upload-pages-artifact v1.0.5 -> v1.0.9 (#665)
See:
- https://github.com/actions/upload-pages-artifact/releases/tag/v1.0.9
- https://github.com/actions/upload-pages-artifact/releases/tag/v1.0.8
- https://github.com/actions/upload-pages-artifact/releases/tag/v1.0.7
- https://github.com/actions/upload-pages-artifact/releases/tag/v1.0.6
2023-06-19 11:30:48 +02:00
Picnic-Bot
b2320779e7 Upgrade actions/configure-pages v2.1.3 -> v3.0.6 (#673)
See:
- https://github.com/actions/configure-pages/releases/tag/v3.0.6
- https://github.com/actions/configure-pages/releases/tag/v3.0.5
- https://github.com/actions/configure-pages/releases/tag/v3.0.4
- https://github.com/actions/configure-pages/releases/tag/v3.0.3
- https://github.com/actions/configure-pages/releases/tag/v3.0.2
- https://github.com/actions/configure-pages/releases/tag/v3.0.1
- https://github.com/actions/configure-pages/releases/tag/v3.0.0
2023-06-19 11:13:20 +02:00
Picnic-Bot
ef0d65d360 Upgrade actions/deploy-pages v1.2.8 -> v2.0.2 (#674)
See:
- https://github.com/actions/deploy-pages/releases/tag/v2.0.2
- https://github.com/actions/deploy-pages/releases/tag/v2.0.1
- https://github.com/actions/deploy-pages/releases/tag/v2.0.0
2023-06-19 11:01:54 +02:00
Picnic-Bot
d29fde8856 Upgrade actions/checkout v3.1.0 -> v3.5.3 (#667)
See:
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v353
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v352
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v351
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v350
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v340
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v330
- https://github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v320
2023-06-19 09:18:01 +02:00
Picnic-Bot
524c7efb48 Upgrade actions/deploy-pages v1.2.3 -> v1.2.8 (#663)
See:
- https://github.com/actions/deploy-pages/releases/tag/v1.2.8
- https://github.com/actions/deploy-pages/releases/tag/v1.2.7
- https://github.com/actions/deploy-pages/releases/tag/v1.2.6
- https://github.com/actions/deploy-pages/releases/tag/v1.2.5
- https://github.com/actions/deploy-pages/releases/tag/v1.2.4
2023-06-19 08:56:31 +02:00
Picnic-Bot
a62acfd7b5 Upgrade Project Reactor 2022.0.7 -> 2022.0.8 (#683)
See:
- https://github.com/reactor/reactor/releases/tag/2022.0.8
- https://github.com/reactor/reactor/compare/2022.0.7...2022.0.8
2023-06-16 16:16:06 +02:00
Picnic-Bot
c40e1d6691 Upgrade actions/setup-java v3.8.0 -> v3.11.0 (#668)
See:
- https://github.com/actions/setup-java/releases/tag/v3.9.0
- https://github.com/actions/setup-java/releases/tag/v3.10.0
- https://github.com/actions/setup-java/releases/tag/v3.11.0
2023-06-16 15:35:04 +02:00
Picnic-Bot
57a22bf9de Upgrade Swagger 2.2.11 -> 2.2.12 (#684)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.12
- https://github.com/swagger-api/swagger-core/compare/v2.2.11...v2.2.12
2023-06-16 15:12:15 +02:00
Picnic-Bot
ec982fe011 Upgrade AutoService 1.1.0 -> 1.1.1 (#682)
See:
- https://github.com/google/auto/releases/tag/auto-service-1.1.1
- https://github.com/google/auto/compare/auto-service-1.1.0...auto-service-1.1.1
2023-06-14 12:35:41 +02:00
Picnic-Bot
1860e24e65 Upgrade Guava 32.0.0-jre -> 32.0.1-jre (#677)
See:
- https://github.com/google/guava/releases/tag/v32.0.1
- https://github.com/google/guava/compare/v32.0.0...v32.0.1
2023-06-12 19:04:31 +02:00
Picnic-Bot
cce248c306 Upgrade Surefire 3.1.0 -> 3.1.2 (#666)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20SUREFIRE%20AND%20fixVersion%20%3E%203.1.0%20AND%20fixVersion%20%3C%3D%203.1.2
- https://github.com/apache/maven-surefire/releases/tag/surefire-3.1.2
- https://github.com/apache/maven-surefire/compare/surefire-3.1.0...surefire-3.1.2
2023-06-12 11:56:20 +02:00
Picnic-Bot
96aca8ea2b Upgrade versions-maven-plugin 2.15.0 -> 2.16.0 (#678)
See:
- https://github.com/mojohaus/versions/releases/tag/2.16.0
- https://github.com/mojohaus/versions-maven-plugin/compare/2.15.0...2.16.0
2023-06-10 14:21:16 +02:00
Picnic-Bot
70d2bf9016 Upgrade license-maven-plugin 2.0.1 -> 2.1.0 (#671)
See:
- https://github.com/mojohaus/license-maven-plugin/releases/tag/2.1.0
- https://github.com/mojohaus/license-maven-plugin/compare/2.0.1...2.1.0
2023-06-08 14:25:34 +02:00
Rick Ossendrijver
cee3c58d07 Configure Renovate to pin GitHub Action digests (#675) 2023-06-08 10:23:05 +02:00
Picnic-Bot
c141ebe05d Upgrade swagger-annotations 2.2.10 -> 2.2.11 (#657)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.11
- https://github.com/swagger-api/swagger-core/compare/v2.2.10...v2.2.11
2023-06-07 11:40:15 +02:00
Picnic-Bot
f5a8c412af Upgrade Byte Buddy 1.14.4 -> 1.14.5 (#658)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.5
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.4...byte-buddy-1.14.5
2023-06-07 10:48:54 +02:00
Picnic-Bot
93440826ed Upgrade Arcmutate 1.0.4 -> 1.0.5 (#656) 2023-06-07 08:02:44 +02:00
Picnic-Bot
80dcae319e Upgrade Jackson 2.15.1 -> 2.15.2 (#652)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.15.2
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.15.1...jackson-bom-2.15.2
2023-06-06 16:30:09 +02:00
Picnic-Bot
7371d03db8 Upgrade Truth 1.1.3 -> 1.1.4 (#653)
See:
- https://github.com/google/truth/releases/tag/v1.1.4
- https://github.com/google/truth/compare/release_1_1_3...v1.1.4
2023-06-06 09:47:09 +02:00
Picnic-Bot
c6b98e61ff Upgrade maven-release-plugin 3.0.0 -> 3.0.1 (#662)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MRELEASE%20AND%20fixVersion%20%3E%203.0.0%20AND%20fixVersion%20%3C%3D%203.0.1
- https://github.com/apache/maven-release/releases/tag/maven-release-3.0.1
- https://github.com/apache/maven-release/compare/maven-release-3.0.0...maven-release-3.0.1
2023-06-06 08:34:35 +02:00
Picnic-Bot
ce8f9f60c8 Upgrade New Relic Java Agent 8.2.0 -> 8.3.0 (#659)
See:
- https://github.com/newrelic/newrelic-java-agent/releases/tag/v8.3.0
- https://github.com/newrelic/newrelic-java-agent/compare/v8.2.0...v8.3.0
2023-06-06 07:50:01 +02:00
Picnic-Bot
cdf27acd9c Upgrade Checker Framework Annotations 3.34.0 -> 3.35.0 (#660)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.35.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.34.0...checker-framework-3.35.0
2023-06-06 07:40:05 +02:00
Picnic-Bot
49e5fd1273 Upgrade extra-enforcer-rules 1.6.2 -> 1.7.0 (#661)
See:
- https://github.com/mojohaus/extra-enforcer-rules/releases/tag/1.7.0
- https://github.com/mojohaus/extra-enforcer-rules/compare/1.6.2...1.7.0
2023-06-06 07:20:46 +02:00
Picnic-Bot
5085db25c0 Upgrade Guava 31.1-jre -> 32.0.0-jre (#650)
See:
- https://guava.dev/releases/32.0.0-jre/api/diffs/
- https://github.com/google/guava/releases/tag/v32.0.0
- https://github.com/google/guava/compare/v31.1...v32.0.0
2023-05-30 16:49:11 +02:00
Picnic-Bot
125d24bc13 Upgrade Checkstyle 10.11.0 -> 10.12.0 (#651)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.12.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.11.0...checkstyle-10.12.0
2023-05-30 08:44:15 +02:00
Picnic-Bot
ea02144bff Upgrade pitest-maven-plugin 1.14.0 -> 1.14.1 (#648)
See:
- https://github.com/hcoles/pitest/releases/tag/1.14.1
- https://github.com/hcoles/pitest/compare/1.14.0...1.14.1
2023-05-26 10:13:47 +02:00
Luke Prananta
cc2c49edc3 Introduce OptionalOrElseGet Refaster rule (#527)
While there, introduce `IsLikelyTrivialComputation` Matcher.
2023-05-26 09:19:51 +02:00
Stephan Schroevers
8bc878a05c Improve AbstractMatcherTestChecker (#599)
These changes enable testing of a wider range of `Matcher` implementations. In
a nutshell:
- The `Matcher` under test is now passed `VisitorState` instances with an
  accurate `TreePath`.
- The `Matcher` under test is no longer consulted for method select and cast
  type expressions, mirroring Refaster behavior.
2023-05-26 08:29:26 +02:00
Picnic-Bot
b399ef8910 Upgrade Spring Boot 2.7.11 -> 2.7.12 (#637)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.12
- https://github.com/spring-projects/spring-boot/compare/v2.7.11...v2.7.12
2023-05-24 19:03:38 +02:00
Picnic-Bot
7dba641a79 Upgrade pitest-junit5-plugin 1.1.2 -> 1.2.0 (#638)
See https://github.com/pitest/pitest-junit5-plugin/compare/1.1.2...1.2.0
2023-05-24 17:20:57 +02:00
Picnic-Bot
da1528129f Upgrade maven-source-plugin 3.2.1 -> 3.3.0 (#643)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MSOURCES%20AND%20fixVersion%20%3E%203.2.1%20AND%20fixVersion%20%3C%3D%203.3.0
- https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.2.1...maven-source-plugin-3.3.0
2023-05-24 17:08:20 +02:00
Picnic-Bot
d0bbc5c14b Upgrade pitest-maven-plugin 1.13.1 -> 1.14.0 (#633)
See:
- https://github.com/hcoles/pitest/releases/tag/1.13.2
- https://github.com/hcoles/pitest/releases/tag/1.14.0
- https://github.com/hcoles/pitest/compare/1.13.1...1.14.0
2023-05-24 16:30:06 +02:00
Picnic-Bot
da532c79c7 Upgrade Pitest Git plugins 1.0.10 -> 1.0.11 (#634) 2023-05-24 16:10:58 +02:00
Picnic-Bot
04e2900a48 Upgrade git-commit-id-maven-plugin 5.0.0 -> 6.0.0 (#635)
See:
- https://github.com/git-commit-id/git-commit-id-maven-plugin/releases/tag/v6.0.0
- https://github.com/git-commit-id/git-commit-id-maven-plugin/compare/v5.0.0...v6.0.0
2023-05-24 16:00:11 +02:00
Picnic-Bot
f097095398 Upgrade AutoService 1.0.1 -> 1.1.0 (#647)
See:
- https://github.com/google/auto/releases/tag/auto-service-1.0.2
- https://github.com/google/auto/releases/tag/auto-service-1.1.0
- https://github.com/google/auto/compare/auto-service-1.0.1...auto-service-1.1.0
2023-05-24 13:25:40 +02:00
Philip Leonard
c53a3f64b6 Qualify non-static TestMode imports across BugChecker test classes (#630)
Prefer non-static imports and qualification of
`BugCheckerRefactoringTestHelper#TestMode` members across bug checker test
classes.
2023-05-23 09:31:59 +02:00
Picnic-Bot
cdfcecc204 Upgrade maven-dependency-plugin 3.5.0 -> 3.6.0 (#646)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MDEP%20AND%20fixVersion%20%3E%203.5.0%20AND%20fixVersion%20%3C%3D%203.6.0
- https://github.com/apache/maven-dependency-plugin/compare/maven-dependency-plugin-3.5.0...maven-dependency-plugin-3.6.0
2023-05-23 08:43:31 +02:00
Picnic-Bot
4f4b3fb865 Upgrade maven-checkstyle-plugin 3.2.2 -> 3.3.0 (#645)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MCHECKSTYLE%20AND%20fixVersion%20%3E%203.2.2%20AND%20fixVersion%20%3C%3D%203.3.0
- https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.2.2...maven-checkstyle-plugin-3.3.0
2023-05-23 07:32:41 +02:00
Picnic-Bot
cce36d24df Upgrade TestNG 7.7.1 -> 7.8.0 (#639)
See:
- https://github.com/testng-team/testng/releases/tag/7.8.0
- https://github.com/testng-team/testng/compare/7.7.1...7.8.0
2023-05-22 08:39:36 +02:00
Picnic-Bot
3bbae43da8 Upgrade swagger-annotations 1.6.10 -> 1.6.11 (#629)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v1.6.11
- https://github.com/swagger-api/swagger-core/compare/v1.6.10...v1.6.11
2023-05-17 13:18:26 +02:00
Picnic-Bot
3217a6974d Upgrade swagger-annotations 2.2.9 -> 2.2.10 (#628)
See:
- https://github.com/swagger-api/swagger-core/releases/tag/v2.2.10
- https://github.com/swagger-api/swagger-core/compare/v2.2.9...v2.2.10
2023-05-17 12:19:30 +02:00
Picnic-Bot
7b71e4ea3e Upgrade Jackson 2.15.0 -> 2.15.1 (#631)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.15.1
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.15.0...jackson-bom-2.15.1
2023-05-17 11:28:55 +02:00
Stephan Schroevers
3df6dc957d [maven-release-plugin] prepare for next development iteration 2023-05-16 17:38:46 +02:00
Stephan Schroevers
a1ecd816ff [maven-release-plugin] prepare release v0.11.1 2023-05-16 17:38:46 +02:00
Stephan Schroevers
03af05889a Make ThirdPartyLibrary compatible with -source 8 (#627)
When targeting Java 8, `unnamedModule` is not properly initialized,
causing an NPE when trying to load a class from it. In that context
`noModule` should be used instead.

Fixes #626.
2023-05-16 09:53:52 +02:00
Stephan Schroevers
f52a93cc4e [maven-release-plugin] prepare for next development iteration 2023-05-14 17:09:09 +02:00
Stephan Schroevers
610085393c [maven-release-plugin] prepare release v0.11.0 2023-05-14 17:09:08 +02:00
Picnic-Bot
08e55fdfb6 Upgrade Error Prone 2.18.0 -> 2.19.1 (#621)
Resolves #622.

See:
- https://github.com/google/error-prone/releases/tag/v2.19.0
- https://github.com/google/error-prone/releases/tag/v2.19.1
- https://github.com/google/error-prone/compare/v2.18.0...v2.19.1
- https://github.com/PicnicSupermarket/error-prone/compare/v2.18.0-picnic-1...v2.19.1-picnic-1
2023-05-14 17:01:46 +02:00
Luke Prananta
137ec4c573 Introduce StreamsConcat Refaster rule (#619) 2023-05-14 16:48:35 +02:00
Luke Prananta
7cf569cca3 Introduce IsRefasterAsVarargs matcher for use by Refaster templates (#623) 2023-05-14 16:33:32 +02:00
Picnic-Bot
d53db2981c Upgrade build-helper-maven-plugin 3.3.0 -> 3.4.0 (#625)
See:
- https://github.com/mojohaus/build-helper-maven-plugin/releases/tag/3.4.0
- https://github.com/mojohaus/build-helper-maven-plugin/compare/build-helper-maven-plugin-3.3.0...3.4.0
2023-05-13 17:23:50 +02:00
Picnic-Bot
454e8662b1 Upgrade Servlet API 4.0.4 -> 6.0.0 (#119)
See https://github.com/eclipse-ee4j/servlet-api/compare/4.0.4-RELEASE...6.0.0
2023-05-13 17:11:29 +02:00
Picnic-Bot
c2f217f055 Upgrade Project Reactor 2022.0.6 -> 2022.0.7 (#620)
See:
- https://github.com/reactor/reactor/releases/tag/2022.0.7
- https://github.com/reactor/reactor/compare/2022.0.6...2022.0.7
2023-05-12 07:44:33 +02:00
Picnic-Bot
45ced8b9d8 Upgrade Checkstyle 10.10.0 -> 10.11.0 (#624)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.11.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.10.0...checkstyle-10.11.0
2023-05-11 21:50:41 +02:00
Picnic-Bot
666fe0d49c Upgrade license-maven-plugin 2.0.0 -> 2.0.1 (#615)
See:
- https://github.com/mojohaus/license-maven-plugin/releases/tag/2.0.1
- https://github.com/mojohaus/license-maven-plugin/compare/license-maven-plugin-2.0.0...2.0.1
2023-05-08 13:29:07 +02:00
Picnic-Bot
e50a7e1795 Upgrade Surefire 3.0.0 -> 3.1.0 (#618)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20SUREFIRE%20AND%20fixVersion%20%3E%203.0.0%20AND%20fixVersion%20%3C%3D%203.1.0
- https://github.com/apache/maven-surefire/compare/surefire-3.0.0...surefire-3.1.0
2023-05-08 09:15:24 +02:00
Picnic-Bot
f403b988d5 Upgrade maven-gpg-plugin 3.0.1 -> 3.1.0 (#616)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MGPG%20AND%20fixVersion%20%3E%203.0.1%20AND%20fixVersion%20%3C%3D%203.1.0
- https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.0.1...maven-gpg-plugin-3.1.0
2023-05-08 07:24:31 +02:00
Stephan Schroevers
3ee28f2c05 [maven-release-plugin] prepare for next development iteration 2023-05-04 12:47:28 +02:00
Stephan Schroevers
bb122388f5 [maven-release-plugin] prepare release v0.10.0 2023-05-04 10:02:03 +02:00
Picnic-Bot
760b1ddf31 Upgrade Google Java Format 1.16.0 -> 1.17.0 (#611)
See:
- https://github.com/google/google-java-format/releases/tag/v1.17.0
- https://github.com/google/google-java-format/compare/v1.16.0...v1.17.0
2023-05-04 09:53:57 +02:00
Stephan Schroevers
6229fa9245 Extend StreamRules Refaster rule collection (#605)
All changes suggested by SonarCloud's `java:s4034` rule, as well as the
examples mentioned in openrewrite/rewrite#2984 are now covered. (In a
number of cases through composition of more generic rules.)

See https://rules.sonarsource.com/java/RSPEC-4034
2023-05-04 08:08:27 +02:00
Mohamed Sameh
7d728e956e Introduce Sets{Difference,Intersection}{,Map,Multimap} and SetsUnion Refaster rules (#607) 2023-05-03 16:56:02 +02:00
Stephan Schroevers
52245c6310 Extend PrimitiveRules Refaster rule collection (#608)
Assorted methods and constants exposed by Guava's
`com.google.common.primitives.*` types are now replaced with their JDK
equivalents.

While there, also update the parameter types of some existing `@AfterTemplate`
methods, resolving an inconsistency flagged by @knutwannheden.
2023-05-03 14:39:03 +02:00
Rick Ossendrijver
4b69fe9de9 Extend AssertJThrowingCallableRules Refaster rule collection (#609) 2023-05-03 10:22:33 +02:00
Picnic-Bot
3405962703 Upgrade New Relic Java Agent 8.1.0 -> 8.2.0 (#612)
See:
- https://github.com/newrelic/newrelic-java-agent/releases/tag/v8.2.0
- https://github.com/newrelic/newrelic-java-agent/compare/v8.1.0...v8.2.0
2023-05-03 10:10:33 +02:00
Picnic-Bot
7d3d6a3cf8 Upgrade fmt-maven-plugin 2.19 -> 2.20 (#613)
See:
- https://github.com/spotify/fmt-maven-plugin/releases/tag/fmt-maven-plugin-2.20
- https://github.com/spotify/fmt-maven-plugin/compare/2.19.0...fmt-maven-plugin-2.20
2023-05-03 09:38:45 +02:00
Picnic-Bot
97fa90b64e Upgrade Checker Framework Annotations 3.33.0 -> 3.34.0 (#614)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.34.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.33.0...checker-framework-3.34.0
2023-05-03 09:11:31 +02:00
Picnic-Bot
ced1ce625d Upgrade pitest-maven-plugin 1.13.0 -> 1.13.1 (#610)
See:
- https://github.com/hcoles/pitest/releases/tag/1.13.1
- https://github.com/hcoles/pitest/compare/1.13.0...1.13.1
2023-05-03 08:43:27 +02:00
Stephan Schroevers
de224deffa Upgrade JDKs used by GitHub Actions builds (#604)
Summary of changes:
- Use JDK 11.0.19 instead of 11.0.18.
- Use JDK 17.0.7 instead of 17.0.6.
- Use JDK 20.0.1 instead of 19.0.2.
- Drop the early access build, as Error Prone is currently not compatible with JDK 21-ea.

See:
- https://www.oracle.com/java/technologies/javase/11-0-19-relnotes.html
- https://www.oracle.com/java/technologies/javase/17-0-7-relnotes.html
- https://www.oracle.com/java/technologies/javase/20-relnote-issues.html
- https://www.oracle.com/java/technologies/javase/20-0-1-relnotes.html
2023-05-02 08:51:39 +02:00
Picnic-Bot
deebd21d34 Upgrade maven-enforcer-plugin 3.2.1 -> 3.3.0 (#566)
See:
- https://github.com/apache/maven-enforcer/releases/tag/enforcer-3.3.0
- https://github.com/apache/maven-enforcer/compare/enforcer-3.2.1...enforcer-3.3.0
2023-05-01 13:43:43 +02:00
Stephan Schroevers
ab84ef4c12 Fix Gradle installation guide link in README (#606) 2023-05-01 08:13:10 +02:00
Picnic-Bot
f675cf0139 Upgrade Checkstyle 10.9.3 -> 10.10.0 (#602)
See:
- https://checkstyle.sourceforge.io/releasenotes.html
- https://github.com/checkstyle/checkstyle/releases/tag/checkstyle-10.10.0
- https://github.com/checkstyle/checkstyle/compare/checkstyle-10.9.3...checkstyle-10.10.0
2023-04-29 11:46:59 +02:00
Picnic-Bot
e7e35c7571 Upgrade JUnit 5 5.9.2 -> 5.9.3 (#600)
See:
- https://junit.org/junit5/docs/current/release-notes/
- https://github.com/junit-team/junit5/releases/tag/r5.9.3
- https://github.com/junit-team/junit5/compare/r5.9.2...r5.9.3
2023-04-28 17:06:45 +02:00
Picnic-Bot
f3c5aee7f5 Upgrade Pitest Git plugins 1.0.8 -> 1.0.10 (#601) 2023-04-28 16:48:48 +02:00
Picnic-Bot
b344d4640c Upgrade jacoco-maven-plugin 0.8.9 -> 0.8.10 (#597)
See:
- https://github.com/jacoco/jacoco/releases/tag/v0.8.10
- https://github.com/jacoco/jacoco/compare/v0.8.9...v0.8.10
2023-04-26 10:28:55 +02:00
Picnic-Bot
393aebca9f Upgrade Arcmutate 1.0.3 -> 1.0.4 (#596) 2023-04-26 09:20:42 +02:00
Mohamed Sameh
32d50ab6fe Extend StreamRules Refaster rule collection (#593)
All changes suggested by SonarCloud's java:S4266 rule are now covered.

See https://sonarcloud.io/organizations/picnic-technologies/rules?open=java%3AS4266&rule_key=java%3AS4266

Fixes #578.
2023-04-26 09:07:50 +02:00
Picnic-Bot
c807568b9c Upgrade pitest-maven-plugin 1.12.0 -> 1.13.0 (#591)
See:
- https://github.com/hcoles/pitest/releases/tag/1.13.0
- https://github.com/hcoles/pitest/compare/1.12.0...1.13.0
2023-04-26 07:59:38 +02:00
Picnic-Bot
4dd2aa12cc Upgrade Jackson 2.14.2 -> 2.15.0 (#594)
See:
- https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.15
- https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.14.2...jackson-bom-2.15.0
2023-04-25 09:52:52 +02:00
Stephan Schroevers
2f2e7e7a35 Add additional quality badges to README (#584) 2023-04-25 08:54:31 +02:00
Stephan Schroevers
e0c795d248 Introduce SonarCloud integration and resolve assorted violations (#575) 2023-04-25 08:19:11 +02:00
Picnic-Bot
554a3e634c Upgrade Mockito 5.3.0 -> 5.3.1 (#590)
See:
- https://github.com/mockito/mockito/releases/tag/v5.3.1
- https://github.com/mockito/mockito/compare/v5.3.0...v5.3.1
2023-04-22 14:39:55 +02:00
Picnic-Bot
7a3ae7c646 Upgrade Pitest Git plugins 1.0.7 -> 1.0.8 (#589) 2023-04-21 13:13:47 +02:00
Picnic-Bot
6d24540d01 Upgrade Arcmutate 1.0.2 -> 1.0.3 (#585) 2023-04-21 10:30:30 +02:00
Picnic-Bot
7637ffee24 Upgrade Pitest JUnit 5 Accelerator 1.0.4 -> 1.0.5 (#586) 2023-04-21 10:16:18 +02:00
Picnic-Bot
12d2b52e38 Upgrade Spring Boot 2.7.10 -> 2.7.11 (#588)
See:
- https://github.com/spring-projects/spring-boot/releases/tag/v2.7.11
- https://github.com/spring-projects/spring-boot/compare/v2.7.10...v2.7.11
2023-04-21 09:17:56 +02:00
Picnic-Bot
53daabe5df Upgrade maven-checkstyle-plugin 3.2.1 -> 3.2.2 (#587)
See:
- https://issues.apache.org/jira/issues/?jql=project%20%3D%20MCHECKSTYLE%20AND%20fixVersion%20%3E%203.2.1%20AND%20fixVersion%20%3C%3D%203.2.2
- https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.2.1...maven-checkstyle-plugin-3.2.2
2023-04-21 08:21:49 +02:00
Stephan Schroevers
ee0884e65f Introduce AssociativeMethodInvocation check (#560) 2023-04-19 08:55:14 +02:00
Mohamed Sameh
3af81d8b10 Introduce StringIs{,Not}EmptyPredicate Refaster rules (#577) 2023-04-18 09:04:03 +02:00
Mohamed Sameh
ebd64c1077 Introduce AssertThatMapContainsOnlyKeys Refaster rule (#576) 2023-04-18 08:09:17 +02:00
Stephan Schroevers
929f1dd1c7 Introduce OpenSSF Scorecard GitHub action (#574)
And resolve some of the issues it identified.

See https://securityscorecards.dev
2023-04-16 09:56:14 +02:00
Stephan Schroevers
9ddd91a50e Introduce CodeQL security vulnerability analysis (#573)
See https://codeql.github.com
2023-04-15 19:23:25 +02:00
Picnic-Bot
a1227ca710 Upgrade New Relic Java Agent 8.0.1 -> 8.1.0 (#583)
See:
- https://github.com/newrelic/newrelic-java-agent/releases/tag/v8.1.0
- https://github.com/newrelic/newrelic-java-agent/compare/v8.0.1...v8.1.0
2023-04-15 16:57:45 +02:00
Picnic-Bot
44e0904357 Upgrade Spring 5.3.26 -> 5.3.27 (#582)
See:
- https://github.com/spring-projects/spring-framework/releases/tag/v5.3.27
- https://github.com/spring-projects/spring-framework/compare/v5.3.26...v5.3.27
2023-04-15 13:20:18 +02:00
Stephan Schroevers
9b54c73dc0 Have DirectReturn check consider finally blocks (#568) 2023-04-14 12:56:22 +02:00
Stephan Schroevers
8ace5b7e9a Fix and enable SuggestedFixRules tests (#581) 2023-04-13 14:20:58 +02:00
Stephan Schroevers
94ffc5d495 Apply assorted test cleanup (#562)
Summary of changes:
- Inline more `CompilationTestHelper` fields.
- Move inner class to the bottom of the outer class.
- Improve test parameter name.
2023-04-13 12:54:51 +02:00
Stephan Schroevers
977019c5bf Improve contribution documentation (#572)
- Introduce a `./run-full-build.sh` script.
- Explicitly mention that users should run this script before opening a pull
  request.
- Emphasize that many build warnings can be resolved automatically.
- Introduce a `SECURITY.md` file as suggested by GitHub.
2023-04-13 09:10:56 +02:00
Luke Prananta
6514236514 Introduce FluxCollectToImmutableList Refaster rule (#570)
And extend `MonoIdentity` to simplify `mono.map(ImmutableList::copyOf)`
expressions where possible, as the new rule may introduce such cases.
2023-04-13 08:31:45 +02:00
Picnic-Bot
6d23fbdd35 Upgrade Project Reactor 2022.0.5 -> 2022.0.6 (#579)
See:
- https://github.com/reactor/reactor/releases/tag/2022.0.6
- https://github.com/reactor/reactor/compare/2022.0.5...2022.0.6
2023-04-12 14:03:31 +02:00
Picnic-Bot
b6f14c073a Upgrade Mockito 5.2.0 -> 5.3.0 (#580)
See:
- https://github.com/mockito/mockito/releases/tag/v5.3.0
- https://github.com/mockito/mockito/compare/v5.2.0...v5.3.0
2023-04-12 08:45:52 +02:00
Luke Prananta
ae22e0ec5e Introduce FluxCollectToImmutableSet Refaster rule (#571) 2023-04-08 00:41:50 +02:00
Stephan Schroevers
6e6f8d9f7b Introduce SourceCode#unwrapMethodInvocation utility method (#561) 2023-04-07 15:05:11 +02:00
Picnic-Bot
68d0bed36c Upgrade Byte Buddy 1.14.3 -> 1.14.4 (#569)
See:
- https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.14.4
- https://github.com/raphw/byte-buddy/compare/byte-buddy-1.14.3...byte-buddy-1.14.4
2023-04-07 08:43:11 +02:00
Picnic-Bot
2edbc85c28 Upgrade pitest-maven-plugin 1.11.7 -> 1.12.0 (#567)
See:
- https://github.com/hcoles/pitest/releases/tag/1.12.0
- https://github.com/hcoles/pitest/compare/1.11.7...1.12.0
2023-04-06 10:55:01 +02:00
Mohamed Sameh
0fefb6985e Introduce MonoJustOrEmptyOptional Refaster rule (#563)
While there, rename two other rules.
2023-04-05 18:12:33 +02:00
Stephan Schroevers
64f9d6b7a2 Introduce SuggestedFixRules Refaster rule collection (#559) 2023-04-05 11:25:03 +02:00
Picnic-Bot
b0f99e7c0b Upgrade jacoco-maven-plugin 0.8.8 -> 0.8.9 (#565)
See:
- https://github.com/jacoco/jacoco/releases/tag/v0.8.9
- https://github.com/jacoco/jacoco/compare/v0.8.8...v0.8.9
2023-04-05 10:43:22 +02:00
Picnic-Bot
320c4175c9 Upgrade Checker Framework Annotations 3.32.0 -> 3.33.0 (#564)
See:
- https://github.com/typetools/checker-framework/releases/tag/checker-framework-3.33.0
- https://github.com/typetools/checker-framework/compare/checker-framework-3.32.0...checker-framework-3.33.0
2023-04-04 08:09:57 +02:00
213 changed files with 5326 additions and 991 deletions

View File

@@ -42,9 +42,9 @@ Please replace this sentence with log output, if applicable.
<!-- Please complete the following information: -->
- Operating system (e.g. MacOS Monterey).
- Java version (i.e. `java --version`, e.g. `17.0.6`).
- Java version (i.e. `java --version`, e.g. `17.0.7`).
- Error Prone version (e.g. `2.18.0`).
- Error Prone Support version (e.g. `0.8.0`).
- Error Prone Support version (e.g. `0.9.0`).
### Additional context

View File

@@ -10,34 +10,32 @@ jobs:
strategy:
matrix:
os: [ ubuntu-22.04 ]
jdk: [ 11.0.18, 17.0.6, 19.0.2 ]
jdk: [ 11.0.19, 17.0.7, 20.0.1 ]
distribution: [ temurin ]
experimental: [ false ]
include:
- os: macos-12
jdk: 17.0.6
jdk: 17.0.7
distribution: temurin
experimental: false
- os: windows-2022
jdk: 17.0.6
jdk: 17.0.7
distribution: temurin
experimental: false
- os: ubuntu-22.04
jdk: 20-ea
distribution: zulu
experimental: true
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental }}
steps:
# We run the build twice for each supported JDK: once against the
# original Error Prone release, using only Error Prone checks available
# on Maven Central, and once against the Picnic Error Prone fork,
# additionally enabling all checks defined in this project and any
# Error Prone checks available only from other artifact repositories.
# We run the build twice for each supported JDK: once against the
# original Error Prone release, using only Error Prone checks available
# on Maven Central, and once against the Picnic Error Prone fork,
# additionally enabling all checks defined in this project and any Error
# Prone checks available only from other artifact repositories.
- name: Check out code
uses: actions/checkout@v3.1.0
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
with:
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@v3.8.0
uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3.12.0
with:
java-version: ${{ matrix.jdk }}
distribution: ${{ matrix.distribution }}
@@ -52,4 +50,3 @@ jobs:
run: mvn build-helper:remove-project-artifact
# XXX: Enable Codecov once we "go public".
# XXX: Enable SonarCloud once we "go public".

44
.github/workflows/codeql.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
# Analyzes the code using GitHub's default CodeQL query database.
# Identified issues are registered with GitHub's code scanning dashboard. When
# a pull request is analyzed, any offending lines are annotated. See
# https://codeql.github.com for details.
name: CodeQL analysis
on:
pull_request:
push:
branches: [ master ]
schedule:
- cron: '0 4 * * 1'
permissions:
contents: read
jobs:
analyze:
strategy:
matrix:
language: [ java, ruby ]
permissions:
contents: read
security-events: write
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
with:
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3.12.0
with:
java-version: 17.0.7
distribution: temurin
cache: maven
- name: Initialize CodeQL
uses: github/codeql-action/init@5b6282e01c62d02e720b81eb8a51204f527c3624 # v2.21.3
with:
languages: ${{ matrix.language }}
- name: Perform minimal build
if: matrix.language == 'java'
run: mvn -T1C clean install -DskipTests -Dverification.skip
- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@5b6282e01c62d02e720b81eb8a51204f527c3624 # v2.21.3
with:
category: /language:${{ matrix.language }}

View File

@@ -3,22 +3,24 @@ on:
pull_request:
push:
branches: [ master, website ]
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
build:
permissions:
contents: read
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v3.1.0
- uses: ruby/setup-ruby@v1.126.0
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
with:
persist-credentials: false
- uses: ruby/setup-ruby@250fcd6a742febb1123a77a841497ccaa8b9e939 # v1.152.0
with:
working-directory: ./website
bundler-cache: true
- name: Configure Github Pages
uses: actions/configure-pages@v2.1.3
uses: actions/configure-pages@f156874f8191504dae5b037505266ed5dda6c382 # v3.0.6
- name: Generate documentation
run: ./generate-docs.sh
- name: Build website with Jekyll
@@ -30,7 +32,7 @@ jobs:
# "Refaster rules" terminology on our website and in the code.
run: bundle exec htmlproofer --disable_external true --check-external-hash false ./_site
- name: Upload website as artifact
uses: actions/upload-pages-artifact@v1.0.5
uses: actions/upload-pages-artifact@a753861a5debcf57bf8b404356158c8e1e33150c # v2.0.0
with:
path: ./website/_site
deploy:
@@ -46,4 +48,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1.2.3
uses: actions/deploy-pages@9dbe3824824f8a1377b8e298bafde1a50ede43e5 # v2.0.4

36
.github/workflows/openssf-scorecard.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
# Analyzes the code base and GitHub project configuration for adherence to
# security best practices for open source software. Identified issues are
# registered with GitHub's code scanning dashboard. When a pull request is
# analyzed, any offending lines are annotated. See
# https://securityscorecards.dev for details.
name: OpenSSF Scorecard update
on:
pull_request:
push:
branches: [ master ]
schedule:
- cron: '0 4 * * 1'
permissions:
contents: read
jobs:
analyze:
permissions:
contents: read
security-events: write
id-token: write
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
with:
persist-credentials: false
- name: Run OpenSSF Scorecard analysis
uses: ossf/scorecard-action@08b4669551908b1024bb425080c797723083c031 # v2.2.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@5b6282e01c62d02e720b81eb8a51204f527c3624 # v2.21.3
with:
sarif_file: results.sarif

View File

@@ -12,13 +12,14 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v3.1.0
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
with:
fetch-depth: 2
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@v3.8.0
uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3.12.0
with:
java-version: 17.0.6
java-version: 17.0.7
distribution: temurin
cache: maven
- name: Run Pitest
@@ -31,7 +32,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@v3.1.1
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
with:
name: pitest-reports
path: ./target/pit-reports-ci

View File

@@ -9,24 +9,28 @@ on:
- completed
permissions:
actions: read
checks: write
contents: read
pull-requests: write
jobs:
update-pr:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
permissions:
actions: read
checks: write
contents: read
pull-requests: write
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v3.1.0
- name: Set up JDK
uses: actions/setup-java@v3.8.0
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
with:
java-version: 17.0.6
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3.12.0
with:
java-version: 17.0.7
distribution: temurin
cache: maven
- name: Download Pitest analysis artifact
uses: dawidd6/action-download-artifact@v2.24.2
uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
name: pitest-reports

36
.github/workflows/sonarcloud.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
# Analyzes the code base using SonarCloud. See
# https://sonarcloud.io/project/overview?id=PicnicSupermarket_error-prone-support.
name: SonarCloud analysis
on:
pull_request:
push:
branches: [ master ]
schedule:
- cron: '0 4 * * 1'
permissions:
contents: read
jobs:
analyze:
permissions:
contents: read
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
with:
fetch-depth: 0
persist-credentials: false
- name: Set up JDK
uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3.12.0
with:
java-version: 17.0.7
distribution: temurin
cache: maven
- name: Create missing `test` directory
# XXX: Drop this step in favour of actually having a test.
run: mkdir refaster-compiler/src/test
- name: Perform SonarCloud analysis
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: mvn -T1C jacoco:prepare-agent verify jacoco:report sonar:sonar -Dverification.skip -Dsonar.projectKey=PicnicSupermarket_error-prone-support

View File

@@ -1,5 +1,8 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"helpers:pinGitHubActionDigests"
],
"packageRules": [
{
"matchPackagePatterns": [

View File

@@ -48,6 +48,17 @@ be accepted. When in doubt, make sure to first raise an
To the extent possible, the pull request process guards our coding guidelines.
Some pointers:
- Try to make sure that the
[`./run-full-build.sh`][error-prone-support-full-build] script completes
successfully, ideally before opening a pull request. See the [development
instructions][error-prone-support-developing] for details on how to
efficiently resolve many of the errors and warnings that may be reported. (In
particular, make sure to run `mvn fmt:format` and
[`./apply-error-prone-suggestions.sh`][error-prone-support-patch].) That
said, if you feel that the build fails for invalid or debatable reasons, or
if you're unsure how to best resolve an issue, don't let that discourage you
from opening a PR with a failing build; we can have a look at the issue
together!
- Checks should be _topical_: ideally they address a single concern.
- Where possible checks should provide _fixes_, and ideally these are
completely behavior-preserving. In order for a check to be adopted by users
@@ -66,6 +77,9 @@ Some pointers:
sneak in unrelated changes; instead just open more than one pull request 😉.
[error-prone-criteria]: https://errorprone.info/docs/criteria
[error-prone-support-developing]: https://github.com/PicnicSupermarket/error-prone-support/tree/master#-developing-error-prone-support
[error-prone-support-full-build]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-full-build.sh
[error-prone-support-issues]: https://github.com/PicnicSupermarket/error-prone-support/issues
[error-prone-support-mutation-tests]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-mutation-tests.sh
[error-prone-support-patch]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/apply-error-prone-suggestions.sh
[error-prone-support-pulls]: https://github.com/PicnicSupermarket/error-prone-support/pulls

View File

@@ -21,7 +21,18 @@ code_][picnic-blog-ep-post].
[![Maven Central][maven-central-badge]][maven-central-search]
[![Reproducible Builds][reproducible-builds-badge]][reproducible-builds-report]
[![OpenSSF Best Practices][openssf-best-practices-badge]][openssf-best-practices-checklist]
[![OpenSSF Scorecard][openssf-scorecard-badge]][openssf-scorecard-report]
[![CodeQL Analysis][codeql-badge]][codeql-master]
[![GitHub Actions][github-actions-build-badge]][github-actions-build-master]
[![Mutation tested with PIT][pitest-badge]][pitest]
[![Quality Gate Status][sonarcloud-quality-badge]][sonarcloud-quality-master]
[![Maintainability Rating][sonarcloud-maintainability-badge]][sonarcloud-maintainability-master]
[![Reliability Rating][sonarcloud-reliability-badge]][sonarcloud-reliability-master]
[![Security Rating][sonarcloud-security-badge]][sonarcloud-security-master]
[![Coverage][sonarcloud-coverage-badge]][sonarcloud-coverage-master]
[![Duplicated Lines (%)][sonarcloud-duplication-badge]][sonarcloud-duplication-master]
[![Technical Debt][sonarcloud-technical-debt-badge]][sonarcloud-technical-debt-master]
[![License][license-badge]][license]
[![PRs Welcome][pr-badge]][contributing]
@@ -98,8 +109,9 @@ definition. -->
#### Gradle
1. First, follow the [installation guide]
[error-prone-gradle-installation-guide] of the `gradle-errorprone-plugin`.
1. First, follow the [installation
guide][error-prone-gradle-installation-guide] of the
`gradle-errorprone-plugin`.
2. Next, edit your `build.gradle` file to add one or more Error Prone Support
modules:
@@ -171,8 +183,15 @@ rules][refaster-rules].
## 👷 Developing Error Prone Support
This is a [Maven][maven] project, so running `mvn clean install` performs a
full clean build and installs the library to your local Maven repository. Some
relevant flags:
full clean build and installs the library to your local Maven repository.
Once you've made changes, the build may fail due to a warning or error emitted
by static code analysis. The flags and commands listed below allow you to
suppress or (in a large subset of cases) automatically fix such cases. Make
sure to carefully check the available options, as this can save you significant
amounts of development time!
Relevant Maven build parameters:
- `-Dverification.warn` makes the warnings and errors emitted by various
plugins and the Java compiler non-fatal, where possible.
@@ -189,19 +208,25 @@ relevant flags:
Pending a release of [google/error-prone#3301][error-prone-pull-3301], this
flag must currently be used in combination with `-Perror-prone-fork`.
Some other commands one may find relevant:
Other highly relevant commands:
- `mvn fmt:format` formats the code using
[`google-java-format`][google-java-format].
- `./run-mutation-tests.sh` runs mutation tests using [Pitest][pitest]. The
results can be reviewed by opening the respective
- [`./run-full-build.sh`][script-run-full-build] builds the project twice,
where the second pass validates compatbility 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
validation.)
- [`./apply-error-prone-suggestions.sh`][script-apply-error-prone-suggestions]
applies Error Prone and Error Prone Support code suggestions to this project.
Before running this command, make sure to have installed the project (`mvn
clean install`) and make sure that the current working directory does not
contain unstaged or uncommited changes.
- [`./run-mutation-tests.sh`][script-run-mutation-tests] runs mutation tests
using [Pitest][pitest]. The results can be reviewed by opening the respective
`target/pit-reports/index.html` files. For more information check the [PIT
Maven plugin][pitest-maven].
- `./apply-error-prone-suggestions.sh` applies Error Prone and Error Prone
Support code suggestions to this project. Before running this command, make
sure to have installed the project (`mvn clean install`) and make sure that
the current working directory does not contain unstaged or uncommited
changes.
When running the project's tests in IntelliJ IDEA, you might see the following
error:
@@ -228,9 +253,17 @@ Want to report or fix a bug, suggest or add a new feature, or improve the
documentation? That's awesome! Please read our [contribution
guidelines][contributing].
### Security
If you want to report a security vulnerability, please do so through a private
channel; please see our [security policy][security] for details.
[bug-checks]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/
[bug-checks-identity-conversion]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/IdentityConversion.java
[codeql-badge]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/codeql.yml/badge.svg?branch=master&event=push
[codeql-master]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/codeql.yml?query=branch:master+event:push
[contributing]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/CONTRIBUTING.md
[contributing-pull-request]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/CONTRIBUTING.md#-opening-a-pull-request
[error-prone-bugchecker]: https://github.com/google/error-prone/blob/master/check_api/src/main/java/com/google/errorprone/bugpatterns/BugChecker.java
[error-prone-fork-jitpack]: https://jitpack.io/#PicnicSupermarket/error-prone
[error-prone-fork-repo]: https://github.com/PicnicSupermarket/error-prone
@@ -239,7 +272,7 @@ guidelines][contributing].
[error-prone-orig-repo]: https://github.com/google/error-prone
[error-prone-pull-3301]: https://github.com/google/error-prone/pull/3301
[github-actions-build-badge]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yaml/badge.svg
[github-actions-build-master]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yaml?query=branch%3Amaster
[github-actions-build-master]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yaml?query=branch:master&event=push
[google-java-format]: https://github.com/google/google-java-format
[idea-288052]: https://youtrack.jetbrains.com/issue/IDEA-288052
[license-badge]: https://img.shields.io/github/license/PicnicSupermarket/error-prone-support
@@ -247,8 +280,13 @@ guidelines][contributing].
[maven-central-badge]: https://img.shields.io/maven-central/v/tech.picnic.error-prone-support/error-prone-support?color=blue
[maven-central-search]: https://search.maven.org/artifact/tech.picnic.error-prone-support/error-prone-support
[maven]: https://maven.apache.org
[picnic-blog]: https://blog.picnic.nl
[openssf-best-practices-badge]: https://bestpractices.coreinfrastructure.org/projects/7199/badge
[openssf-best-practices-checklist]: https://bestpractices.coreinfrastructure.org/projects/7199
[openssf-scorecard-badge]: https://img.shields.io/ossf-scorecard/github.com/PicnicSupermarket/error-prone-support?label=openssf%20scorecard
[openssf-scorecard-report]: https://securityscorecards.dev/viewer/?uri=github.com/PicnicSupermarket/error-prone-support
[picnic-blog-ep-post]: https://blog.picnic.nl/picnic-loves-error-prone-producing-high-quality-and-consistent-java-code-b8a566be6886
[picnic-blog]: https://blog.picnic.nl
[pitest-badge]: https://img.shields.io/badge/-Mutation%20tested%20with%20PIT-blue.svg
[pitest]: https://pitest.org
[pitest-maven]: https://pitest.org/quickstart/maven
[pr-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg
@@ -257,3 +295,21 @@ guidelines][contributing].
[refaster-rules]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/
[reproducible-builds-badge]: https://img.shields.io/badge/Reproducible_Builds-ok-success?labelColor=1e5b96
[reproducible-builds-report]: https://github.com/jvm-repo-rebuild/reproducible-central/blob/master/content/tech/picnic/error-prone-support/error-prone-support/README.md
[script-apply-error-prone-suggestions]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/apply-error-prone-suggestions.sh
[script-run-full-build]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-full-build.sh
[script-run-mutation-tests]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-mutation-tests.sh
[security]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/SECURITY.md
[sonarcloud-coverage-badge]: https://sonarcloud.io/api/project_badges/measure?project=PicnicSupermarket_error-prone-support&metric=coverage
[sonarcloud-coverage-master]: https://sonarcloud.io/component_measures?id=PicnicSupermarket_error-prone-support&metric=coverage
[sonarcloud-duplication-badge]: https://sonarcloud.io/api/project_badges/measure?project=PicnicSupermarket_error-prone-support&metric=duplicated_lines_density
[sonarcloud-duplication-master]: https://sonarcloud.io/component_measures?id=PicnicSupermarket_error-prone-support&metric=duplicated_lines_density
[sonarcloud-maintainability-badge]: https://sonarcloud.io/api/project_badges/measure?project=PicnicSupermarket_error-prone-support&metric=sqale_rating
[sonarcloud-maintainability-master]: https://sonarcloud.io/component_measures?id=PicnicSupermarket_error-prone-support&metric=sqale_rating
[sonarcloud-quality-badge]: https://sonarcloud.io/api/project_badges/measure?project=PicnicSupermarket_error-prone-support&metric=alert_status
[sonarcloud-quality-master]: https://sonarcloud.io/summary/new_code?id=PicnicSupermarket_error-prone-support
[sonarcloud-reliability-badge]: https://sonarcloud.io/api/project_badges/measure?project=PicnicSupermarket_error-prone-support&metric=reliability_rating
[sonarcloud-reliability-master]: https://sonarcloud.io/component_measures?id=PicnicSupermarket_error-prone-support&metric=reliability_rating
[sonarcloud-security-badge]: https://sonarcloud.io/api/project_badges/measure?project=PicnicSupermarket_error-prone-support&metric=security_rating
[sonarcloud-security-master]: https://sonarcloud.io/component_measures?id=PicnicSupermarket_error-prone-support&metric=security_rating
[sonarcloud-technical-debt-badge]: https://sonarcloud.io/api/project_badges/measure?project=PicnicSupermarket_error-prone-support&metric=sqale_index
[sonarcloud-technical-debt-master]: https://sonarcloud.io/component_measures?id=PicnicSupermarket_error-prone-support&metric=sqale_index

23
SECURITY.md Normal file
View File

@@ -0,0 +1,23 @@
# Security policy
We take security seriously. We are mindful of Error Prone Support's place in
the software supply chain, and the risks and responsibilities that come with
this.
## Supported versions
This project uses [semantic versioning][semantic-versioning]. In general, only
the latest version of this software is supported. That said, if users have a
compelling reason to ask for patch release of an older major release, then we
will seriously consider such a request. We do urge users to stay up-to-date and
use the latest release where feasible.
## Reporting a vulnerability
To report a vulnerability, please visit the [security
advisories][security-advisories] page and click _Report a vulnerability_. We
will take such reports seriously and work with you to resolve the issue in a
timely manner.
[security-advisories]: https://github.com/PicnicSupermarket/error-prone-support/security/advisories
[semantic-versioning]: https://semver.org

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.9.1-SNAPSHOT</version>
<version>0.13.2-SNAPSHOT</version>
</parent>
<artifactId>documentation-support</artifactId>

View File

@@ -25,6 +25,7 @@ enum ExtractorType {
return identifier;
}
@SuppressWarnings("java:S1452" /* The extractor returns data of an unspecified type. */)
Extractor<?> getExtractor() {
return extractor;
}

View File

@@ -67,10 +67,11 @@ final class DocumentationGeneratorTaskListenerTest {
@Test
void excessArguments(@TempDir Path outputDirectory) {
String actualOutputDirectory = outputDirectory.toAbsolutePath() + " extra-arg";
assertThatThrownBy(
() ->
Compilation.compileWithDocumentationGenerator(
outputDirectory.toAbsolutePath() + " extra-arg", "A.java", "package pkg;"))
actualOutputDirectory, "A.java", "package pkg;"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Precisely one path must be provided");
}

View File

@@ -24,7 +24,6 @@ project:
- Document how to apply patches.
- Document each of the checks.
- Add [SonarQube][sonarcloud] and [Codecov][codecov] integrations.
- Add non-Java file formatting support, like we have internally at Picnic.
(I.e., somehow open-source that stuff.)
- Auto-generate a website listing each of the checks, just like the Error Prone
@@ -273,7 +272,6 @@ Refaster's expressiveness:
[autorefactor]: https://autorefactor.org
[bettercodehub]: https://bettercodehub.com
[checkstyle-external-project-tests]: https://github.com/checkstyle/checkstyle/blob/master/wercker.yml
[codecov]: https://codecov.io
[error-prone-bug-patterns]: https://errorprone.info/bugpatterns
[error-prone]: https://errorprone.info
[error-prone-repo]: https://github.com/google/error-prone
@@ -283,4 +281,3 @@ Refaster's expressiveness:
[main-contributing]: ../CONTRIBUTING.md
[main-readme]: ../README.md
[modernizer-maven-plugin]: https://github.com/gaul/modernizer-maven-plugin
[sonarcloud]: https://sonarcloud.io

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>tech.picnic.error-prone-support</groupId>
<artifactId>error-prone-support</artifactId>
<version>0.9.1-SNAPSHOT</version>
<version>0.13.2-SNAPSHOT</version>
</parent>
<artifactId>error-prone-contrib</artifactId>
@@ -126,6 +126,11 @@
<artifactId>jakarta.servlet-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
@@ -171,6 +176,11 @@
<artifactId>mockito-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.reactivestreams</groupId>
<artifactId>reactive-streams</artifactId>

View File

@@ -0,0 +1,103 @@
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 com.google.errorprone.matchers.Matchers.allOf;
import static com.google.errorprone.matchers.Matchers.not;
import static com.google.errorprone.matchers.Matchers.staticMethod;
import static com.google.errorprone.matchers.Matchers.toType;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
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.matchers.Matchers;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.suppliers.Supplier;
import com.google.errorprone.suppliers.Suppliers;
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 tech.picnic.errorprone.bugpatterns.util.SourceCode;
/**
* A {@link BugChecker} that flags unnecessarily nested usage of methods that implement an
* associative operation.
*
* <p>The arguments to such methods can be flattened without affecting semantics, while making the
* code more readable.
*/
@AutoService(BugChecker.class)
@BugPattern(
summary =
"This method implements an associative operation, so the list of operands can be flattened",
link = BUG_PATTERNS_BASE_URL + "AssociativeMethodInvocation",
linkType = CUSTOM,
severity = SUGGESTION,
tags = SIMPLIFICATION)
public final class AssociativeMethodInvocation extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Supplier<Type> ITERABLE = Suppliers.typeFromClass(Iterable.class);
private static final ImmutableSet<Matcher<ExpressionTree>> ASSOCIATIVE_OPERATIONS =
ImmutableSet.of(
allOf(
staticMethod().onClass(Suppliers.typeFromClass(Matchers.class)).named("allOf"),
toType(MethodInvocationTree.class, not(hasArgumentOfType(ITERABLE)))),
allOf(
staticMethod().onClass(Suppliers.typeFromClass(Matchers.class)).named("anyOf"),
toType(MethodInvocationTree.class, not(hasArgumentOfType(ITERABLE)))),
staticMethod().onClass(Suppliers.typeFromClass(Refaster.class)).named("anyOf"));
/** Instantiates a new {@link AssociativeMethodInvocation} instance. */
public AssociativeMethodInvocation() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (tree.getArguments().isEmpty()) {
/* Absent any arguments, there is nothing to simplify. */
return Description.NO_MATCH;
}
for (Matcher<ExpressionTree> matcher : ASSOCIATIVE_OPERATIONS) {
if (matcher.matches(tree, state)) {
SuggestedFix fix = processMatchingArguments(tree, matcher, state);
return fix.isEmpty() ? Description.NO_MATCH : describeMatch(tree, fix);
}
}
return Description.NO_MATCH;
}
private static SuggestedFix processMatchingArguments(
MethodInvocationTree tree, Matcher<ExpressionTree> matcher, VisitorState state) {
SuggestedFix.Builder fix = SuggestedFix.builder();
for (ExpressionTree arg : tree.getArguments()) {
if (matcher.matches(arg, state)) {
MethodInvocationTree invocation = (MethodInvocationTree) arg;
fix.merge(
invocation.getArguments().isEmpty()
? SuggestedFixes.removeElement(invocation, tree.getArguments(), state)
: SourceCode.unwrapMethodInvocation(invocation, state));
}
}
return fix.build();
}
private static Matcher<MethodInvocationTree> hasArgumentOfType(Supplier<Type> type) {
return (tree, state) ->
tree.getArguments().stream()
.anyMatch(arg -> ASTHelpers.isSubtype(ASTHelpers.getType(arg), type.get(state), state));
}
}

View File

@@ -58,8 +58,8 @@ public final class AutowiredConstructor extends BugChecker implements ClassTreeM
/*
* This is the only `@Autowired` constructor: suggest that it be removed. Note that this likely
* means that the associated import can be removed as well. Rather than adding code for this case we
* leave flagging the unused import to Error Prone's `RemoveUnusedImports` check.
* means that the associated import can be removed as well. Rather than adding code for this
* case we leave flagging the unused import to Error Prone's `RemoveUnusedImports` check.
*/
AnnotationTree annotation = Iterables.getOnlyElement(annotations);
return describeMatch(annotation, SourceCode.deleteWithTrailingWhitespace(annotation, state));

View File

@@ -91,8 +91,8 @@ public final class CanonicalAnnotationSyntax extends BugChecker implements Annot
ExpressionTree arg = args.get(0);
if (state.getSourceForNode(arg) == null) {
/*
* The annotation argument isn't doesn't have a source representation, e.g. because `value`
* isn't assigned to explicitly.
* The annotation argument doesn't have a source representation, e.g. because `value` isn't
* assigned explicitly.
*/
return Optional.empty();
}

View File

@@ -30,7 +30,7 @@ import tech.picnic.errorprone.bugpatterns.util.ThirdPartyLibrary;
@AutoService(BugChecker.class)
@BugPattern(
summary =
"Avoid `Collectors.to{List,Map,Set}` in favour of alternatives that emphasize (im)mutability",
"Avoid `Collectors.to{List,Map,Set}` in favor of collectors that emphasize (im)mutability",
link = BUG_PATTERNS_BASE_URL + "CollectorMutability",
linkType = CUSTOM,
severity = WARNING,

View File

@@ -14,6 +14,7 @@ import static com.google.errorprone.matchers.Matchers.toType;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.Streams;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
@@ -26,14 +27,18 @@ import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.BlockTree;
import com.sun.source.tree.ExpressionStatementTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.ReturnTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.TryTree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreeScanner;
import com.sun.tools.javac.code.Symbol;
import java.util.List;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.bugpatterns.util.MoreASTHelpers;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
@@ -75,7 +80,10 @@ public final class DirectReturn extends BugChecker implements BlockTreeMatcher {
StatementTree precedingStatement = statements.get(statements.size() - 2);
return tryMatchAssignment(variableSymbol, precedingStatement)
.filter(resultExpr -> canInlineToReturnStatement(resultExpr, state))
.filter(
resultExpr ->
canInlineToReturnStatement(resultExpr, state)
&& !isIdentifierSymbolReferencedInAssociatedFinallyBlock(variableSymbol, state))
.map(
resultExpr ->
describeMatch(
@@ -113,13 +121,13 @@ public final class DirectReturn extends BugChecker implements BlockTreeMatcher {
}
/**
* Tells whether inlining the given expression to the associated return statement can be done
* safely.
* Tells whether inlining the given expression to the associated return statement can likely be
* done without changing the expression's return type.
*
* <p>Inlining is generally safe, but in rare cases the operation may have a functional impact.
* The sole case considered here is the inlining of a Mockito mock or spy construction without an
* explicit type. In such a case the type created depends on context, such as the method's return
* type.
* <p>Inlining an expression generally does not change its return type, but in rare cases the
* operation may have a functional impact. The sole case considered here is the inlining of a
* Mockito mock or spy construction without an explicit type. In such a case the type created
* depends on context, such as the method's return type.
*/
private static boolean canInlineToReturnStatement(
ExpressionTree expressionTree, VisitorState state) {
@@ -128,4 +136,40 @@ public final class DirectReturn extends BugChecker implements BlockTreeMatcher {
.filter(m -> MoreASTHelpers.areSameType(expressionTree, m.getReturnType(), state))
.isPresent();
}
/**
* Tells whether the given identifier {@link Symbol} is referenced in a {@code finally} block that
* is executed <em>after</em> control flow returns from the {@link VisitorState#getPath() current
* location}.
*/
private static boolean isIdentifierSymbolReferencedInAssociatedFinallyBlock(
Symbol symbol, VisitorState state) {
return Streams.zip(
Streams.stream(state.getPath()).skip(1),
Streams.stream(state.getPath()),
(tree, child) -> {
if (!(tree instanceof TryTree)) {
return null;
}
BlockTree finallyBlock = ((TryTree) tree).getFinallyBlock();
return !child.equals(finallyBlock) ? finallyBlock : null;
})
.anyMatch(finallyBlock -> referencesIdentifierSymbol(symbol, finallyBlock));
}
private static boolean referencesIdentifierSymbol(Symbol symbol, @Nullable BlockTree tree) {
return Boolean.TRUE.equals(
new TreeScanner<Boolean, @Nullable Void>() {
@Override
public Boolean visitIdentifier(IdentifierTree node, @Nullable Void unused) {
return symbol.equals(ASTHelpers.getSymbol(node));
}
@Override
public Boolean reduce(Boolean r1, Boolean r2) {
return Boolean.TRUE.equals(r1) || Boolean.TRUE.equals(r2);
}
}.scan(tree, null));
}
}

View File

@@ -42,6 +42,7 @@ public final class EmptyMethod extends BugChecker implements MethodTreeMatcher {
public EmptyMethod() {}
@Override
@SuppressWarnings("java:S1067" /* Chaining disjunctions like this does not impact readability. */)
public Description matchMethod(MethodTree tree, VisitorState state) {
if (tree.getBody() == null
|| !tree.getBody().getStatements().isEmpty()

View File

@@ -104,7 +104,9 @@ public final class ErrorProneTestHelperSourceFormat extends BugChecker
String formatted;
try {
formatted = formatSourceCode(source, retainUnusedImports).trim();
} catch (FormatterException e) {
} catch (
@SuppressWarnings("java:S1166" /* Stack trace not relevant. */)
FormatterException e) {
return buildDescription(methodInvocation)
.setMessage(String.format("Source code is malformed: %s", e.getMessage()))
.build();
@@ -131,7 +133,7 @@ public final class ErrorProneTestHelperSourceFormat extends BugChecker
SuggestedFix.replace(
startPos,
endPos,
Splitter.on('\n')
Splitter.on(System.lineSeparator())
.splitToStream(formatted)
.map(state::getConstantExpression)
.collect(joining(", "))));
@@ -157,7 +159,7 @@ public final class ErrorProneTestHelperSourceFormat extends BugChecker
return Optional.empty();
}
source.append(value).append('\n');
source.append(value).append(System.lineSeparator());
}
return Optional.of(source.toString());

View File

@@ -82,10 +82,8 @@ public final class FluxFlatMapUsage extends BugChecker
SuggestedFix serializationFix = SuggestedFixes.renameMethodInvocation(tree, "concatMap", state);
SuggestedFix concurrencyCapFix =
SuggestedFix.builder()
.postfixWith(
Iterables.getOnlyElement(tree.getArguments()), ", " + MAX_CONCURRENCY_ARG_NAME)
.build();
SuggestedFix.postfixWith(
Iterables.getOnlyElement(tree.getArguments()), ", " + MAX_CONCURRENCY_ARG_NAME);
Description.Builder description = buildDescription(tree);

View File

@@ -35,6 +35,8 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
// XXX: Consider detecting cases where a flagged expression is passed to a method, and where removal
// of the identity conversion would cause a different method overload to be selected. Depending on
// the target method such a modification may change the code's semantics or performance.
// XXX: Also flag `Stream#map`, `Mono#map` and `Flux#map` invocations where the given transformation
// is effectively the identity operation.
@AutoService(BugChecker.class)
@BugPattern(
summary = "Avoid or clarify identity conversions",

View File

@@ -40,6 +40,7 @@ import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import javax.inject.Inject;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.bugpatterns.util.AnnotationAttributeMatcher;
import tech.picnic.errorprone.bugpatterns.util.Flags;
@@ -58,6 +59,7 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
linkType = CUSTOM,
severity = SUGGESTION,
tags = STYLE)
@SuppressWarnings("java:S2160" /* Super class equality definition suffices. */)
public final class LexicographicalAnnotationAttributeListing extends BugChecker
implements AnnotationTreeMatcher {
private static final long serialVersionUID = 1L;
@@ -93,7 +95,8 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
*
* @param flags Any provided command line flags.
*/
public LexicographicalAnnotationAttributeListing(ErrorProneFlags flags) {
@Inject
LexicographicalAnnotationAttributeListing(ErrorProneFlags flags) {
matcher = createAnnotationAttributeMatcher(flags);
}

View File

@@ -46,9 +46,19 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
public final class LexicographicalAnnotationListing extends BugChecker
implements MethodTreeMatcher {
private static final long serialVersionUID = 1L;
/**
* A comparator that minimally reorders {@link AnnotationType}s, such that declaration annotations
* are placed before type annotations.
*/
@SuppressWarnings({
"java:S1067",
"java:S3358"
} /* Avoiding the nested ternary operator hurts readability. */)
private static final Comparator<@Nullable AnnotationType> BY_ANNOTATION_TYPE =
(a, b) ->
(a == null || a == DECLARATION) && b == TYPE ? -1 : a == TYPE && b == DECLARATION ? 1 : 0;
(a == null || a == DECLARATION) && b == TYPE
? -1
: (a == TYPE && b == DECLARATION ? 1 : 0);
/** Instantiates a new {@link LexicographicalAnnotationListing} instance. */
public LexicographicalAnnotationListing() {}

View File

@@ -118,6 +118,8 @@ public final class MethodReferenceUsage extends BugChecker implements LambdaExpr
.flatMap(expectedInstance -> constructMethodRef(lambdaExpr, subTree, expectedInstance));
}
@SuppressWarnings(
"java:S1151" /* Extracting `IDENTIFIER` case block to separate method does not improve readability. */)
private static Optional<SuggestedFix.Builder> constructMethodRef(
LambdaExpressionTree lambdaExpr,
MethodInvocationTree subTree,
@@ -130,10 +132,9 @@ public final class MethodReferenceUsage extends BugChecker implements LambdaExpr
return Optional.empty();
}
Symbol sym = ASTHelpers.getSymbol(methodSelect);
if (!ASTHelpers.isStatic(sym)) {
return constructFix(lambdaExpr, "this", methodSelect);
}
return constructFix(lambdaExpr, sym.owner, methodSelect);
return ASTHelpers.isStatic(sym)
? constructFix(lambdaExpr, sym.owner, methodSelect)
: constructFix(lambdaExpr, "this", methodSelect);
case MEMBER_SELECT:
return constructMethodRef(lambdaExpr, (MemberSelectTree) methodSelect, expectedInstance);
default:

View File

@@ -1,59 +0,0 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.LIKELY_ERROR;
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE;
import static com.google.errorprone.matchers.Matchers.annotations;
import static com.google.errorprone.matchers.Matchers.anyOf;
import static com.google.errorprone.matchers.Matchers.isType;
import static tech.picnic.errorprone.bugpatterns.util.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.ClassTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.MultiMatcher;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
/** A {@link BugChecker} that flags likely missing Refaster annotations. */
@AutoService(BugChecker.class)
@BugPattern(
summary = "The Refaster rule contains a method without any Refaster annotations",
link = BUG_PATTERNS_BASE_URL + "MissingRefasterAnnotation",
linkType = CUSTOM,
severity = WARNING,
tags = LIKELY_ERROR)
public final class MissingRefasterAnnotation extends BugChecker implements ClassTreeMatcher {
private static final long serialVersionUID = 1L;
private static final MultiMatcher<Tree, AnnotationTree> REFASTER_ANNOTATION =
annotations(
AT_LEAST_ONE,
anyOf(
isType("com.google.errorprone.refaster.annotation.Placeholder"),
isType("com.google.errorprone.refaster.annotation.BeforeTemplate"),
isType("com.google.errorprone.refaster.annotation.AfterTemplate")));
/** Instantiates a new {@link MissingRefasterAnnotation} instance. */
public MissingRefasterAnnotation() {}
@Override
public Description matchClass(ClassTree tree, VisitorState state) {
long methodTypes =
tree.getMembers().stream()
.filter(member -> member.getKind() == Tree.Kind.METHOD)
.map(MethodTree.class::cast)
.filter(method -> !ASTHelpers.isGeneratedConstructor(method))
.map(method -> REFASTER_ANNOTATION.matches(method, state))
.distinct()
.count();
return methodTypes < 2 ? Description.NO_MATCH : buildDescription(tree).build();
}
}

View File

@@ -0,0 +1,47 @@
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.PERFORMANCE;
import static com.google.errorprone.matchers.method.MethodMatchers.staticMethod;
import static tech.picnic.errorprone.bugpatterns.util.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.MethodInvocationTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
/**
* A {@link BugChecker} that flags usages of MongoDB {@code $text} filter usages.
*
* @see <a href="https://www.mongodb.com/docs/manual/text-search/">MongoDB Text Search</a>
*/
@AutoService(BugChecker.class)
@BugPattern(
summary =
"Avoid MongoDB's `$text` filter operator, as it can trigger heavy queries and even cause the server to run out of memory",
link = BUG_PATTERNS_BASE_URL + "MongoDBTextFilterUsage",
linkType = CUSTOM,
severity = SUGGESTION,
tags = PERFORMANCE)
public final class MongoDBTextFilterUsage extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> MONGO_FILTERS_TEXT_METHOD =
staticMethod().onClass("com.mongodb.client.model.Filters").named("text");
/** Instantiates a new {@link MongoDBTextFilterUsage} instance. */
public MongoDBTextFilterUsage() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
return MONGO_FILTERS_TEXT_METHOD.matches(tree, state)
? describeMatch(tree)
: Description.NO_MATCH;
}
}

View File

@@ -4,6 +4,7 @@ import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.FRAGILE_CODE;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.bugpatterns.util.MoreMatchers.isSubTypeOf;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.generic;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.raw;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.subOf;
@@ -14,14 +15,19 @@ import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Supplier;
import com.google.errorprone.suppliers.Suppliers;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Type;
import java.util.Optional;
/** A {@link BugChecker} that flags nesting of {@link Optional Optionals}. */
// XXX: Extend this checker to also flag method return types and variable/field types.
// XXX: Consider generalizing this checker and `NestedPublishers` to a single `NestedMonad` check,
// which e.g. also flags nested `Stream`s. Alternatively, combine these and other checkers into an
// even more generic `ConfusingType` checker.
@AutoService(BugChecker.class)
@BugPattern(
summary =
@@ -33,19 +39,16 @@ import java.util.Optional;
public final class NestedOptionals extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Supplier<Type> OPTIONAL = Suppliers.typeFromClass(Optional.class);
private static final Supplier<Type> OPTIONAL_OF_OPTIONAL =
VisitorState.memoize(generic(OPTIONAL, subOf(raw(OPTIONAL))));
private static final Matcher<Tree> IS_OPTIONAL_OF_OPTIONAL =
isSubTypeOf(VisitorState.memoize(generic(OPTIONAL, subOf(raw(OPTIONAL)))));
/** Instantiates a new {@link NestedOptionals} instance. */
public NestedOptionals() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
Type type = OPTIONAL_OF_OPTIONAL.get(state);
if (type == null || !state.getTypes().isSubtype(ASTHelpers.getType(tree), type)) {
return Description.NO_MATCH;
}
return describeMatch(tree);
return IS_OPTIONAL_OF_OPTIONAL.matches(tree, state)
? describeMatch(tree)
: Description.NO_MATCH;
}
}

View File

@@ -0,0 +1,63 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.FRAGILE_CODE;
import static com.google.errorprone.matchers.Matchers.typePredicateMatcher;
import static com.google.errorprone.predicates.TypePredicates.allOf;
import static com.google.errorprone.predicates.TypePredicates.not;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypePredicates.hasTypeParameter;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypePredicates.isSubTypeOf;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.generic;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.raw;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.subOf;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.type;
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.MethodInvocationTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Supplier;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Type;
/**
* A {@link BugChecker} that flags {@code Publisher<? extends Publisher>} instances, unless the
* nested {@link org.reactivestreams.Publisher} is a {@link reactor.core.publisher.GroupedFlux}.
*/
// XXX: See the `NestedOptionals` check for some ideas on how to generalize this kind of checker.
@AutoService(BugChecker.class)
@BugPattern(
summary =
"Avoid `Publisher`s that emit other `Publishers`s; "
+ "the resultant code is hard to reason about",
link = BUG_PATTERNS_BASE_URL + "NestedPublishers",
linkType = CUSTOM,
severity = WARNING,
tags = FRAGILE_CODE)
public final class NestedPublishers extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Supplier<Type> PUBLISHER = type("org.reactivestreams.Publisher");
private static final Matcher<ExpressionTree> IS_NON_GROUPED_PUBLISHER_OF_PUBLISHERS =
typePredicateMatcher(
allOf(
isSubTypeOf(generic(PUBLISHER, subOf(raw(PUBLISHER)))),
not(
hasTypeParameter(
0, isSubTypeOf(raw(type("reactor.core.publisher.GroupedFlux")))))));
/** Instantiates a new {@link NestedPublishers} instance. */
public NestedPublishers() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
return IS_NON_GROUPED_PUBLISHER_OF_PUBLISHERS.matches(tree, state)
? describeMatch(tree)
: Description.NO_MATCH;
}
}

View File

@@ -43,6 +43,7 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
// emitting a value (e.g. `Mono.empty()`, `someFlux.then()`, ...), or known not to complete normally
// (`Mono.never()`, `someFlux.repeat()`, `Mono.error(...)`, ...). The latter category could
// potentially be split out further.
@SuppressWarnings("java:S1192" /* Factoring out repeated method names impacts readability. */)
public final class NonEmptyMono extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> MONO_SIZE_CHECK =

View File

@@ -49,6 +49,7 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
linkType = CUSTOM,
severity = WARNING,
tags = PERFORMANCE)
@SuppressWarnings("java:S1192" /* Factoring out repeated method names impacts readability. */)
public final class PrimitiveComparison extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> STATIC_COMPARISON_METHOD =

View File

@@ -50,6 +50,7 @@ import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import javax.inject.Inject;
import tech.picnic.errorprone.bugpatterns.util.Flags;
import tech.picnic.errorprone.bugpatterns.util.MethodMatcherFactory;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
@@ -62,6 +63,11 @@ import tech.picnic.errorprone.bugpatterns.util.SourceCode;
linkType = CUSTOM,
severity = SUGGESTION,
tags = SIMPLIFICATION)
@SuppressWarnings({
"java:S1192" /* Factoring out repeated method names impacts readability. */,
"java:S2160" /* Super class equality definition suffices. */,
"key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict"
})
public final class RedundantStringConversion extends BugChecker
implements BinaryTreeMatcher, CompoundAssignmentTreeMatcher, MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
@@ -150,7 +156,8 @@ public final class RedundantStringConversion extends BugChecker
*
* @param flags Any provided command line flags.
*/
public RedundantStringConversion(ErrorProneFlags flags) {
@Inject
RedundantStringConversion(ErrorProneFlags flags) {
conversionMethodMatcher = createConversionMethodMatcher(flags);
}
@@ -163,7 +170,7 @@ public final class RedundantStringConversion extends BugChecker
ExpressionTree lhs = tree.getLeftOperand();
ExpressionTree rhs = tree.getRightOperand();
if (!STRING.matches(lhs, state)) {
return finalize(tree, tryFix(rhs, state, STRING));
return createDescription(tree, tryFix(rhs, state, STRING));
}
List<SuggestedFix.Builder> fixes = new ArrayList<>();
@@ -177,7 +184,7 @@ public final class RedundantStringConversion extends BugChecker
}
tryFix(rhs, state, ANY_EXPR).ifPresent(fixes::add);
return finalize(tree, fixes.stream().reduce(SuggestedFix.Builder::merge));
return createDescription(tree, fixes.stream().reduce(SuggestedFix.Builder::merge));
}
@Override
@@ -186,36 +193,36 @@ public final class RedundantStringConversion extends BugChecker
return Description.NO_MATCH;
}
return finalize(tree, tryFix(tree.getExpression(), state, ANY_EXPR));
return createDescription(tree, tryFix(tree.getExpression(), state, ANY_EXPR));
}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (STRINGBUILDER_APPEND_INVOCATION.matches(tree, state)) {
return finalize(tree, tryFixPositionalConverter(tree.getArguments(), state, 0));
return createDescription(tree, tryFixPositionalConverter(tree.getArguments(), state, 0));
}
if (STRINGBUILDER_INSERT_INVOCATION.matches(tree, state)) {
return finalize(tree, tryFixPositionalConverter(tree.getArguments(), state, 1));
return createDescription(tree, tryFixPositionalConverter(tree.getArguments(), state, 1));
}
if (FORMATTER_INVOCATION.matches(tree, state)) {
return finalize(tree, tryFixFormatter(tree.getArguments(), state));
return createDescription(tree, tryFixFormatter(tree.getArguments(), state));
}
if (GUAVA_GUARD_INVOCATION.matches(tree, state)) {
return finalize(tree, tryFixGuavaGuard(tree.getArguments(), state));
return createDescription(tree, tryFixGuavaGuard(tree.getArguments(), state));
}
if (SLF4J_LOGGER_INVOCATION.matches(tree, state)) {
return finalize(tree, tryFixSlf4jLogger(tree.getArguments(), state));
return createDescription(tree, tryFixSlf4jLogger(tree.getArguments(), state));
}
if (instanceMethod().matches(tree, state)) {
return finalize(tree, tryFix(tree, state, STRING));
return createDescription(tree, tryFix(tree, state, STRING));
}
return finalize(tree, tryFix(tree, state, NON_NULL_STRING));
return createDescription(tree, tryFix(tree, state, NON_NULL_STRING));
}
private Optional<SuggestedFix.Builder> tryFixPositionalConverter(
@@ -298,7 +305,7 @@ public final class RedundantStringConversion extends BugChecker
/* Simplify the values to be plugged into the format pattern, if possible. */
return arguments.stream()
.skip(patternIndex + 1)
.skip(patternIndex + 1L)
.map(arg -> tryFix(arg, state, remainingArgFilter))
.flatMap(Optional::stream)
.reduce(SuggestedFix.Builder::merge);
@@ -362,7 +369,7 @@ public final class RedundantStringConversion extends BugChecker
return Optional.of(Iterables.getOnlyElement(methodInvocation.getArguments()));
}
private Description finalize(Tree tree, Optional<SuggestedFix.Builder> fixes) {
private Description createDescription(Tree tree, Optional<SuggestedFix.Builder> fixes) {
return fixes
.map(SuggestedFix.Builder::build)
.map(fix -> describeMatch(tree, fix))

View File

@@ -99,8 +99,9 @@ public final class RequestMappingAnnotation extends BugChecker implements Method
&& LACKS_PARAMETER_ANNOTATION.matches(tree, state)
? buildDescription(tree)
.setMessage(
"Not all parameters of this request mapping method are annotated; this may be a mistake. "
+ "If the unannotated parameters represent query string parameters, annotate them with `@RequestParam`.")
"Not all parameters of this request mapping method are annotated; this may be a "
+ "mistake. If the unannotated parameters represent query string parameters, "
+ "annotate them with `@RequestParam`.")
.build()
: Description.NO_MATCH;
}

View File

@@ -27,6 +27,7 @@ import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Suppliers;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import javax.inject.Inject;
import tech.picnic.errorprone.bugpatterns.util.Flags;
/** A {@link BugChecker} that flags {@code @RequestParam} parameters with an unsupported type. */
@@ -38,6 +39,7 @@ import tech.picnic.errorprone.bugpatterns.util.Flags;
linkType = CUSTOM,
severity = ERROR,
tags = LIKELY_ERROR)
@SuppressWarnings("java:S2160" /* Super class equality definition suffices. */)
public final class RequestParamType extends BugChecker implements VariableTreeMatcher {
private static final long serialVersionUID = 1L;
private static final String SUPPORTED_CUSTOM_TYPES_FLAG = "RequestParamType:SupportedCustomTypes";
@@ -54,7 +56,8 @@ public final class RequestParamType extends BugChecker implements VariableTreeMa
*
* @param flags Any provided command line flags.
*/
public RequestParamType(ErrorProneFlags flags) {
@Inject
RequestParamType(ErrorProneFlags flags) {
hasUnsupportedRequestParamType = hasUnsupportedRequestParamType(flags);
}

View File

@@ -1,89 +0,0 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.BugPattern.StandardTags.FRAGILE_CODE;
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
import static com.sun.tools.javac.parser.Tokens.TokenKind.RPAREN;
import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL;
import com.google.auto.service.AutoService;
import com.google.common.collect.Streams;
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.Fix;
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.errorprone.util.ErrorProneTokens;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.util.Position;
import tech.picnic.errorprone.bugpatterns.util.SourceCode;
/**
* A {@link BugChecker} that flags calls to {@link String#toLowerCase()} and {@link
* String#toUpperCase()}, as these methods implicitly rely on the environment's default locale.
*/
// XXX: Also flag `String::toLowerCase` and `String::toUpperCase` method references. For these cases
// the suggested fix should introduce a lambda expression with a parameter of which the name does
// not coincide with the name of an existing variable name. Such functionality should likely be
// introduced in a utility class.
@AutoService(BugChecker.class)
@BugPattern(
summary = "Specify a `Locale` when calling `String#to{Lower,Upper}Case`",
link = BUG_PATTERNS_BASE_URL + "StringCaseLocaleUsage",
linkType = CUSTOM,
severity = WARNING,
tags = FRAGILE_CODE)
public final class StringCaseLocaleUsage extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> DEFAULT_LOCALE_CASE_CONVERSION =
instanceMethod()
.onExactClass(String.class.getName())
.namedAnyOf("toLowerCase", "toUpperCase")
.withNoParameters();
/** Instantiates a new {@link StringCaseLocaleUsage} instance. */
public StringCaseLocaleUsage() {}
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (!DEFAULT_LOCALE_CASE_CONVERSION.matches(tree, state)) {
return Description.NO_MATCH;
}
int closingParenPosition = getClosingParenPosition(tree, state);
if (closingParenPosition == Position.NOPOS) {
return describeMatch(tree);
}
return buildDescription(tree)
.addFix(suggestLocale(closingParenPosition, "Locale.ROOT"))
.addFix(suggestLocale(closingParenPosition, "Locale.getDefault()"))
.build();
}
private static Fix suggestLocale(int insertPosition, String locale) {
return SuggestedFix.builder()
.addImport("java.util.Locale")
.replace(insertPosition, insertPosition, locale)
.build();
}
private static int getClosingParenPosition(MethodInvocationTree tree, VisitorState state) {
int startPosition = ASTHelpers.getStartPosition(tree);
if (startPosition == Position.NOPOS) {
return Position.NOPOS;
}
return Streams.findLast(
ErrorProneTokens.getTokens(SourceCode.treeToString(tree, state), state.context).stream()
.filter(t -> t.kind() == RPAREN))
.map(token -> startPosition + token.pos())
.orElse(Position.NOPOS);
}
}

View File

@@ -103,7 +103,7 @@ public final class AnnotationAttributeMatcher implements Serializable {
* @param tree The annotation AST node to be inspected.
* @return Any matching annotation arguments.
*/
public Stream<? extends ExpressionTree> extractMatchingArguments(AnnotationTree tree) {
public Stream<ExpressionTree> extractMatchingArguments(AnnotationTree tree) {
Type type = ASTHelpers.getType(tree.getAnnotationType());
if (type == null) {
return Stream.empty();
@@ -111,6 +111,7 @@ public final class AnnotationAttributeMatcher implements Serializable {
String annotationType = type.toString();
return tree.getArguments().stream()
.map(ExpressionTree.class::cast)
.filter(a -> matches(annotationType, extractAttributeName(a)));
}

View File

@@ -114,6 +114,7 @@ public final class JavaKeywords {
* @see <a href="https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.8">JDK 17 JLS
* section 3.8: Identifiers</a>
*/
@SuppressWarnings("java:S1067" /* Chaining conjunctions like this does not impact readability. */)
public static boolean isValidIdentifier(String str) {
return !str.isEmpty()
&& !isReservedKeyword(str)

View File

@@ -18,6 +18,9 @@ import java.util.regex.Pattern;
public final class MethodMatcherFactory {
private static final Splitter ARGUMENT_TYPE_SPLITTER =
Splitter.on(',').trimResults().omitEmptyStrings();
// XXX: Check whether we can use a parser for "standard" Java signatures here. Maybe
// `sun.reflect.generics.parser.SignatureParser`?
@SuppressWarnings("java:S5998" /* In practice there will be only modest recursion. */)
private static final Pattern METHOD_SIGNATURE =
Pattern.compile("([^\\s#(,)]+)#([^\\s#(,)]+)\\(((?:[^\\s#(,)]+(?:,[^\\s#(,)]+)*)?)\\)");

View File

@@ -1,11 +1,14 @@
package tech.picnic.errorprone.bugpatterns.util;
import static com.google.errorprone.matchers.Matchers.typePredicateMatcher;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypePredicates.hasAnnotation;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.matchers.Matchers;
import com.google.errorprone.predicates.TypePredicate;
import com.google.errorprone.util.ASTHelpers;
import com.google.errorprone.suppliers.Supplier;
import com.sun.source.tree.AnnotationTree;
import com.sun.tools.javac.code.Symbol;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Type;
/**
* A collection of general-purpose {@link Matcher}s.
@@ -25,15 +28,21 @@ public final class MoreMatchers {
* @return A {@link Matcher} that matches trees with the specified meta-annotation.
*/
public static <T extends AnnotationTree> Matcher<T> hasMetaAnnotation(String annotationType) {
TypePredicate typePredicate = hasAnnotation(annotationType);
return (tree, state) -> {
Symbol sym = ASTHelpers.getSymbol(tree);
return sym != null && typePredicate.apply(sym.type, state);
};
return typePredicateMatcher(hasAnnotation(annotationType));
}
// XXX: Consider moving to a `MoreTypePredicates` utility class.
private static TypePredicate hasAnnotation(String annotationClassName) {
return (type, state) -> ASTHelpers.hasAnnotation(type.tsym, annotationClassName, state);
/**
* Returns a {@link Matcher} that determines whether the type of a given {@link Tree} is a subtype
* of the type returned by the specified {@link Supplier}.
*
* <p>This method differs from {@link Matchers#isSubtypeOf(Supplier)} in that it does not perform
* type erasure.
*
* @param <T> The type of tree to match against.
* @param type The {@link Supplier} that returns the type to match against.
* @return A {@link Matcher} that matches trees with the specified type.
*/
public static <T extends Tree> Matcher<T> isSubTypeOf(Supplier<Type> type) {
return typePredicateMatcher(MoreTypePredicates.isSubTypeOf(type));
}
}

View File

@@ -0,0 +1,63 @@
package tech.picnic.errorprone.bugpatterns.util;
import com.google.errorprone.VisitorState;
import com.google.errorprone.predicates.TypePredicate;
import com.google.errorprone.predicates.TypePredicates;
import com.google.errorprone.suppliers.Supplier;
import com.google.errorprone.util.ASTHelpers;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.util.List;
/**
* A collection of general-purpose {@link TypePredicate}s.
*
* <p>These methods are additions to the ones found in {@link TypePredicates}.
*/
// XXX: The methods in this class are tested only indirectly. Consider adding a dedicated test
// class, or make sure that each method is explicitly covered by a tested analog in `MoreMatchers`.
public final class MoreTypePredicates {
private MoreTypePredicates() {}
/**
* Returns a {@link TypePredicate} that matches types that are annotated with the indicated
* annotation type.
*
* @param annotationType The fully-qualified name of the annotation type.
* @return A {@link TypePredicate} that matches appropriate types.
*/
public static TypePredicate hasAnnotation(String annotationType) {
return (type, state) -> ASTHelpers.hasAnnotation(type.tsym, annotationType, state);
}
/**
* Returns a {@link TypePredicate} that matches subtypes of the type returned by the specified
* {@link Supplier}.
*
* @implNote This method does not use {@link ASTHelpers#isSubtype(Type, Type, VisitorState)}, as
* that method performs type erasure.
* @param bound The {@link Supplier} that returns the type to match against.
* @return A {@link TypePredicate} that matches appropriate subtypes.
*/
public static TypePredicate isSubTypeOf(Supplier<Type> bound) {
Supplier<Type> memoizedType = VisitorState.memoize(bound);
return (type, state) -> {
Type boundType = memoizedType.get(state);
return boundType != null && state.getTypes().isSubtype(type, boundType);
};
}
/**
* Returns a {@link TypePredicate} that matches generic types with a type parameter that matches
* the specified {@link TypePredicate} at the indicated index.
*
* @param index The index of the type parameter to match against.
* @param predicate The {@link TypePredicate} to match against the type parameter.
* @return A {@link TypePredicate} that matches appropriate generic types.
*/
public static TypePredicate hasTypeParameter(int index, TypePredicate predicate) {
return (type, state) -> {
List<Type> typeArguments = type.getTypeArguments();
return typeArguments.size() > index && predicate.apply(typeArguments.get(index), state);
};
}
}

View File

@@ -1,12 +1,22 @@
package tech.picnic.errorprone.bugpatterns.util;
import static com.sun.tools.javac.parser.Tokens.TokenKind.RPAREN;
import static com.sun.tools.javac.util.Position.NOPOS;
import static java.util.stream.Collectors.joining;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import com.google.errorprone.VisitorState;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.util.ErrorProneToken;
import com.google.errorprone.util.ErrorProneTokens;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.Position;
import java.util.Optional;
/**
* A collection of Error Prone utility methods for dealing with the source code representation of
@@ -59,4 +69,57 @@ public final class SourceCode {
whitespaceEndPos == -1 ? sourceCode.length() : whitespaceEndPos,
"");
}
/**
* Creates a {@link SuggestedFix} for the replacement of the given {@link MethodInvocationTree}
* with just the arguments to the method invocation, effectively "unwrapping" the method
* invocation.
*
* <p>For example, given the method invocation {@code foo.bar(1, 2, 3)}, this method will return a
* {@link SuggestedFix} that replaces the method invocation with {@code 1, 2, 3}.
*
* <p>This method aims to preserve the original formatting of the method invocation, including
* whitespace and comments.
*
* @param tree The AST node to be unwrapped.
* @param state A {@link VisitorState} describing the context in which the given {@link
* MethodInvocationTree} is found.
* @return A non-{@code null} {@link SuggestedFix}.
*/
public static SuggestedFix unwrapMethodInvocation(MethodInvocationTree tree, VisitorState state) {
CharSequence sourceCode = state.getSourceCode();
int startPosition = state.getEndPosition(tree.getMethodSelect());
int endPosition = state.getEndPosition(tree);
if (sourceCode == null || startPosition == Position.NOPOS || endPosition == Position.NOPOS) {
return unwrapMethodInvocationDroppingWhitespaceAndComments(tree, state);
}
ImmutableList<ErrorProneToken> tokens =
ErrorProneTokens.getTokens(
sourceCode.subSequence(startPosition, endPosition).toString(), state.context);
Optional<Integer> leftParenPosition =
tokens.stream().findFirst().map(t -> startPosition + t.endPos());
Optional<Integer> rightParenPosition =
Streams.findLast(tokens.stream().filter(t -> t.kind() == RPAREN))
.map(t -> startPosition + t.pos());
if (leftParenPosition.isEmpty() || rightParenPosition.isEmpty()) {
return unwrapMethodInvocationDroppingWhitespaceAndComments(tree, state);
}
return SuggestedFix.replace(
tree,
sourceCode
.subSequence(leftParenPosition.orElseThrow(), rightParenPosition.orElseThrow())
.toString());
}
@VisibleForTesting
static SuggestedFix unwrapMethodInvocationDroppingWhitespaceAndComments(
MethodInvocationTree tree, VisitorState state) {
return SuggestedFix.replace(
tree,
tree.getArguments().stream().map(arg -> treeToString(arg, state)).collect(joining(", ")));
}
}

View File

@@ -4,7 +4,10 @@ import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.suppliers.Supplier;
import com.sun.tools.javac.code.ClassFinder;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.code.Symbol.CompletionFailure;
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.util.Name;
/**
@@ -86,11 +89,19 @@ public enum ThirdPartyLibrary {
private static boolean canLoadClass(String className, VisitorState state) {
ClassFinder classFinder = ClassFinder.instance(state.context);
Symtab symtab = state.getSymtab();
// XXX: Drop support for targeting Java 8 once the oldest supported JDK drops such support.
ModuleSymbol module =
Source.instance(state.context).compareTo(Source.JDK9) < 0
? symtab.noModule
: symtab.unnamedModule;
Name binaryName = state.binaryNameFromClassname(className);
try {
classFinder.loadClass(state.getSymtab().unnamedModule, binaryName);
classFinder.loadClass(module, binaryName);
return true;
} catch (CompletionFailure e) {
} catch (
@SuppressWarnings("java:S1166" /* Not exceptional. */)
CompletionFailure e) {
return false;
}
}

View File

@@ -16,15 +16,18 @@ import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractBooleanAssert;
import org.assertj.core.api.AbstractCollectionAssert;
import org.assertj.core.api.AbstractMapAssert;
import org.assertj.core.api.MapAssert;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@@ -220,6 +223,19 @@ final class AssertJMapRules {
}
}
static final class AssertThatMapContainsOnlyKeys<K, V> {
@BeforeTemplate
AbstractCollectionAssert<?, Collection<? extends K>, K, ?> before(Map<K, V> map, Set<K> keys) {
return assertThat(map.keySet()).hasSameElementsAs(keys);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
MapAssert<K, V> after(Map<K, V> map, Set<K> keys) {
return assertThat(map).containsOnlyKeys(keys);
}
}
static final class AssertThatMapContainsValue<K, V> {
@BeforeTemplate
AbstractBooleanAssert<?> before(Map<K, V> map, V value) {

View File

@@ -23,6 +23,8 @@ final class AssertJPrimitiveRules {
}
@BeforeTemplate
@SuppressWarnings(
"java:S1244" /* The (in)equality checks are fragile, but may be seen in the wild. */)
AbstractBooleanAssert<?> before(double actual, double expected) {
return Refaster.anyOf(
assertThat(actual == expected).isTrue(), assertThat(actual != expected).isFalse());
@@ -43,6 +45,8 @@ final class AssertJPrimitiveRules {
}
@BeforeTemplate
@SuppressWarnings(
"java:S1244" /* The (in)equality checks are fragile, but may be seen in the wild. */)
AbstractBooleanAssert<?> before(double actual, double expected) {
return Refaster.anyOf(
assertThat(actual != expected).isTrue(), assertThat(actual == expected).isFalse());

View File

@@ -2024,8 +2024,8 @@ final class AssertJRules {
////////////////////////////////////////////////////////////////////////////
// Above: Generated code.
///////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Organize the code below.
// XXX: Do the "single Comparable" match shown below.

View File

@@ -47,7 +47,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByIllegalArgumentExceptionHasMessage {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalArgumentException" /* Matches strictly more specific expressions. */)
"AssertThatThrownByIllegalArgumentException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalArgumentException().isThrownBy(throwingCallable).withMessage(message);
}
@@ -64,7 +64,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByIllegalArgumentExceptionHasMessageParameters {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalArgumentException" /* Matches strictly more specific expressions. */)
"AssertThatThrownByIllegalArgumentException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
return assertThatIllegalArgumentException()
@@ -85,7 +85,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByIllegalArgumentExceptionHasMessageStartingWith {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalArgumentException" /* Matches strictly more specific expressions. */)
"AssertThatThrownByIllegalArgumentException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalArgumentException()
.isThrownBy(throwingCallable)
@@ -104,7 +104,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByIllegalArgumentExceptionHasMessageContaining {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalArgumentException" /* Matches strictly more specific expressions. */)
"AssertThatThrownByIllegalArgumentException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalArgumentException()
.isThrownBy(throwingCallable)
@@ -123,7 +123,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByIllegalArgumentExceptionHasMessageNotContainingAny {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalArgumentException" /* Matches strictly more specific expressions. */)
"AssertThatThrownByIllegalArgumentException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, @Repeated CharSequence values) {
return assertThatIllegalArgumentException()
@@ -157,7 +157,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByIllegalStateExceptionHasMessage {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalStateException" /* Matches strictly more specific expressions. */)
"AssertThatThrownByIllegalStateException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalStateException().isThrownBy(throwingCallable).withMessage(message);
}
@@ -174,7 +174,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByIllegalStateExceptionHasMessageParameters {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalStateException" /* Matches strictly more specific expressions. */)
"AssertThatThrownByIllegalStateException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
return assertThatIllegalStateException()
@@ -195,7 +195,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByIllegalStateExceptionHasMessageStartingWith {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalStateException" /* Matches strictly more specific expressions. */)
"AssertThatThrownByIllegalStateException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalStateException()
.isThrownBy(throwingCallable)
@@ -214,7 +214,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByIllegalStateExceptionHasMessageContaining {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalStateException" /* Matches strictly more specific expressions. */)
"AssertThatThrownByIllegalStateException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalStateException()
.isThrownBy(throwingCallable)
@@ -233,7 +233,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByIllegalStateExceptionHasMessageNotContaining {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIllegalStateException" /* Matches strictly more specific expressions. */)
"AssertThatThrownByIllegalStateException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIllegalStateException()
.isThrownBy(throwingCallable)
@@ -265,7 +265,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByNullPointerExceptionHasMessage {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByNullPointerException" /* Matches strictly more specific expressions. */)
"AssertThatThrownByNullPointerException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatNullPointerException().isThrownBy(throwingCallable).withMessage(message);
}
@@ -282,7 +282,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByNullPointerExceptionHasMessageParameters {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByNullPointerException" /* Matches strictly more specific expressions. */)
"AssertThatThrownByNullPointerException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
return assertThatNullPointerException()
@@ -303,7 +303,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByNullPointerExceptionHasMessageStartingWith {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByNullPointerException" /* Matches strictly more specific expressions. */)
"AssertThatThrownByNullPointerException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatNullPointerException()
.isThrownBy(throwingCallable)
@@ -319,6 +319,44 @@ final class AssertJThrowingCallableRules {
}
}
static final class AssertThatThrownByNullPointerExceptionHasMessageContaining {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByNullPointerException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatNullPointerException()
.isThrownBy(throwingCallable)
.withMessageContaining(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(NullPointerException.class)
.hasMessageContaining(message);
}
}
static final class AssertThatThrownByNullPointerExceptionHasMessageNotContaining {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByNullPointerException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatNullPointerException()
.isThrownBy(throwingCallable)
.withMessageNotContaining(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(NullPointerException.class)
.hasMessageNotContaining(message);
}
}
static final class AssertThatThrownByIOException {
@BeforeTemplate
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable) {
@@ -334,8 +372,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByIOExceptionHasMessage {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIOException" /* Matches strictly more specific expressions. */)
@SuppressWarnings("AssertThatThrownByIOException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIOException().isThrownBy(throwingCallable).withMessage(message);
}
@@ -351,8 +388,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByIOExceptionHasMessageParameters {
@BeforeTemplate
@SuppressWarnings(
"AssertThatThrownByIOException" /* Matches strictly more specific expressions. */)
@SuppressWarnings("AssertThatThrownByIOException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
ThrowingCallable throwingCallable, String message, @Repeated Object parameters) {
return assertThatIOException().isThrownBy(throwingCallable).withMessage(message, parameters);
@@ -368,6 +404,54 @@ final class AssertJThrowingCallableRules {
}
}
static final class AssertThatThrownByIOExceptionHasMessageStartingWith {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownByIOException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIOException().isThrownBy(throwingCallable).withMessageStartingWith(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IOException.class)
.hasMessageStartingWith(message);
}
}
static final class AssertThatThrownByIOExceptionHasMessageContaining {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownByIOException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIOException().isThrownBy(throwingCallable).withMessageContaining(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IOException.class)
.hasMessageContaining(message);
}
}
static final class AssertThatThrownByIOExceptionHasMessageNotContaining {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownByIOException" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
return assertThatIOException().isThrownBy(throwingCallable).withMessageNotContaining(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(IOException.class)
.hasMessageNotContaining(message);
}
}
static final class AssertThatThrownBy {
@BeforeTemplate
AbstractObjectAssert<?, ?> before(
@@ -385,7 +469,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByHasMessage {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* Matches strictly more specific expressions. */)
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
@@ -407,7 +491,7 @@ final class AssertJThrowingCallableRules {
static final class AssertThatThrownByHasMessageParameters {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* Matches strictly more specific expressions. */)
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
@@ -431,6 +515,78 @@ final class AssertJThrowingCallableRules {
}
}
static final class AssertThatThrownByHasMessageStartingWith {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
String message) {
return assertThatExceptionOfType(exceptionType)
.isThrownBy(throwingCallable)
.withMessageStartingWith(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(exceptionType)
.hasMessageStartingWith(message);
}
}
static final class AssertThatThrownByHasMessageContaining {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
String message) {
return assertThatExceptionOfType(exceptionType)
.isThrownBy(throwingCallable)
.withMessageContaining(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(exceptionType)
.hasMessageContaining(message);
}
}
static final class AssertThatThrownByHasMessageNotContaining {
@BeforeTemplate
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
AbstractObjectAssert<?, ?> before(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
String message) {
return assertThatExceptionOfType(exceptionType)
.isThrownBy(throwingCallable)
.withMessageNotContaining(message);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
AbstractObjectAssert<?, ?> after(
Class<? extends Throwable> exceptionType,
ThrowingCallable throwingCallable,
String message) {
return assertThatThrownBy(throwingCallable)
.isInstanceOf(exceptionType)
.hasMessageNotContaining(message);
}
}
// XXX: Drop this rule in favour of a generic Error Prone check that flags `String.format(...)`
// arguments to a wide range of format methods.
static final class AbstractThrowableAssertHasMessage {

View File

@@ -115,6 +115,7 @@ final class AssortedRules {
// intelligently.
static final class LogicalImplication {
@BeforeTemplate
@SuppressWarnings("java:S2589" /* This violation will be rewritten. */)
boolean before(boolean firstTest, boolean secondTest) {
return firstTest || (!firstTest && secondTest);
}

View File

@@ -56,6 +56,7 @@ final class BigDecimalRules {
// `BugChecker`.
static final class BigDecimalValueOf {
@BeforeTemplate
@SuppressWarnings("java:S2111" /* This violation will be rewritten. */)
BigDecimal before(double value) {
return new BigDecimal(value);
}

View File

@@ -3,6 +3,7 @@ package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChooser;
import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -25,6 +26,7 @@ final class BugCheckerRules {
}
@AfterTemplate
@CanIgnoreReturnValue
BugCheckerRefactoringTestHelper after(BugCheckerRefactoringTestHelper helper) {
return helper;
}

View File

@@ -35,6 +35,7 @@ final class CollectionRules {
*/
static final class CollectionIsEmpty<T> {
@BeforeTemplate
@SuppressWarnings("java:S1155" /* This violation will be rewritten. */)
boolean before(Collection<T> collection) {
return Refaster.anyOf(
collection.size() == 0,
@@ -163,6 +164,8 @@ final class CollectionRules {
}
/** Prefer {@link ArrayList#ArrayList(Collection)} over the Guava alternative. */
@SuppressWarnings(
"NonApiType" /* Matching against `List` would unnecessarily constrain the rule. */)
static final class NewArrayListFromCollection<T> {
@BeforeTemplate
ArrayList<T> before(Collection<T> collection) {

View File

@@ -12,6 +12,7 @@ import static java.util.function.Function.identity;
import com.google.common.collect.Comparators;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -78,6 +79,7 @@ final class ComparatorRules {
}
@AfterTemplate
@CanIgnoreReturnValue
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Comparator<T> after(Comparator<T> cmp) {
return cmp;
@@ -219,7 +221,6 @@ final class ComparatorRules {
*/
static final class MinOfVarargs<T> {
@BeforeTemplate
@SuppressWarnings("StreamOfArray" /* In practice individual values are provided. */)
T before(@Repeated T value, Comparator<T> cmp) {
return Stream.of(Refaster.asVarargs(value)).min(cmp).orElseThrow();
}
@@ -233,6 +234,7 @@ final class ComparatorRules {
/** Prefer {@link Comparators#min(Comparable, Comparable)}} over more verbose alternatives. */
static final class MinOfPairNaturalOrder<T extends Comparable<? super T>> {
@BeforeTemplate
@SuppressWarnings("java:S1067" /* The conditional operators are independent. */)
T before(T value1, T value2) {
return Refaster.anyOf(
value1.compareTo(value2) <= 0 ? value1 : value2,
@@ -259,6 +261,7 @@ final class ComparatorRules {
*/
static final class MinOfPairCustomOrder<T> {
@BeforeTemplate
@SuppressWarnings("java:S1067" /* The conditional operators are independent. */)
T before(T value1, T value2, Comparator<T> cmp) {
return Refaster.anyOf(
cmp.compare(value1, value2) <= 0 ? value1 : value2,
@@ -285,7 +288,6 @@ final class ComparatorRules {
*/
static final class MaxOfVarargs<T> {
@BeforeTemplate
@SuppressWarnings("StreamOfArray" /* In practice individual values are provided. */)
T before(@Repeated T value, Comparator<T> cmp) {
return Stream.of(Refaster.asVarargs(value)).max(cmp).orElseThrow();
}
@@ -299,6 +301,7 @@ final class ComparatorRules {
/** Prefer {@link Comparators#max(Comparable, Comparable)}} over more verbose alternatives. */
static final class MaxOfPairNaturalOrder<T extends Comparable<? super T>> {
@BeforeTemplate
@SuppressWarnings("java:S1067" /* The conditional operators are independent. */)
T before(T value1, T value2) {
return Refaster.anyOf(
value1.compareTo(value2) >= 0 ? value1 : value2,
@@ -325,6 +328,7 @@ final class ComparatorRules {
*/
static final class MaxOfPairCustomOrder<T> {
@BeforeTemplate
@SuppressWarnings("java:S1067" /* The conditional operators are independent. */)
T before(T value1, T value2, Comparator<T> cmp) {
return Refaster.anyOf(
cmp.compare(value1, value2) >= 0 ? value1 : value2,

View File

@@ -1,6 +1,7 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.Streams;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -27,6 +28,7 @@ final class DoubleStreamRules {
}
@AfterTemplate
@CanIgnoreReturnValue
DoubleStream after(DoubleStream stream) {
return stream;
}
@@ -237,6 +239,7 @@ final class DoubleStreamRules {
/** Prefer {@link DoubleStream#anyMatch(DoublePredicate)} over more contrived alternatives. */
static final class DoubleStreamAnyMatch {
@BeforeTemplate
@SuppressWarnings("java:S4034" /* This violation will be rewritten. */)
boolean before(DoubleStream stream, DoublePredicate predicate) {
return Refaster.anyOf(
!stream.noneMatch(predicate), stream.filter(predicate).findAny().isPresent());
@@ -274,4 +277,16 @@ final class DoubleStreamRules {
return stream.allMatch(e -> test(e));
}
}
static final class DoubleStreamTakeWhile {
@BeforeTemplate
DoubleStream before(DoubleStream stream, DoublePredicate predicate) {
return stream.takeWhile(predicate).filter(predicate);
}
@AfterTemplate
DoubleStream after(DoubleStream stream, DoublePredicate predicate) {
return stream.takeWhile(predicate);
}
}
}

View File

@@ -1,5 +1,6 @@
package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation;
@@ -30,6 +31,7 @@ final class EqualityRules {
@AfterTemplate
@AlsoNegation
@SuppressWarnings("java:S1698" /* Reference comparison is valid for enums. */)
boolean after(T a, T b) {
return a == b;
}
@@ -56,11 +58,13 @@ final class EqualityRules {
/** Avoid double negations; this is not Javascript. */
static final class DoubleNegation {
@BeforeTemplate
@SuppressWarnings("java:S2761" /* This violation will be rewritten. */)
boolean before(boolean b) {
return !!b;
}
@AfterTemplate
@CanIgnoreReturnValue
boolean after(boolean b) {
return b;
}
@@ -72,6 +76,7 @@ final class EqualityRules {
*/
// XXX: Replacing `a ? !b : b` with `a != b` changes semantics if both `a` and `b` are boxed
// booleans.
@SuppressWarnings("java:S1940" /* This violation will be rewritten. */)
static final class Negation {
@BeforeTemplate
boolean before(boolean a, boolean b) {
@@ -79,6 +84,8 @@ final class EqualityRules {
}
@BeforeTemplate
@SuppressWarnings(
"java:S1244" /* The equality check is fragile, but may be seen in the wild. */)
boolean before(double a, double b) {
return !(a == b);
}
@@ -100,6 +107,7 @@ final class EqualityRules {
*/
// XXX: Replacing `a ? b : !b` with `a == b` changes semantics if both `a` and `b` are boxed
// booleans.
@SuppressWarnings("java:S1940" /* This violation will be rewritten. */)
static final class IndirectDoubleNegation {
@BeforeTemplate
boolean before(boolean a, boolean b) {
@@ -107,6 +115,8 @@ final class EqualityRules {
}
@BeforeTemplate
@SuppressWarnings(
"java:S1244" /* The inequality check is fragile, but may be seen in the wild. */)
boolean before(double a, double b) {
return !(a != b);
}

View File

@@ -250,7 +250,8 @@ final class ImmutableMapRules {
* Prefer {@link ImmutableMap#of(Object, Object, Object, Object)} over alternatives that don't
* communicate the immutability of the resulting map at the type level.
*/
// XXX: Also rewrite the `ImmutableMap.builder()` variant?
// XXX: Consider introducing a `BugChecker` to replace these `ImmutableMapOfX` rules. That will
// also make it easier to rewrite various `ImmutableMap.builder()` variants.
static final class ImmutableMapOf2<K, V> {
@BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2) {
@@ -267,7 +268,8 @@ final class ImmutableMapRules {
* Prefer {@link ImmutableMap#of(Object, Object, Object, Object, Object, Object)} over
* alternatives that don't communicate the immutability of the resulting map at the type level.
*/
// XXX: Also rewrite the `ImmutableMap.builder()` variant?
// XXX: Consider introducing a `BugChecker` to replace these `ImmutableMapOfX` rules. That will
// also make it easier to rewrite various `ImmutableMap.builder()` variants.
static final class ImmutableMapOf3<K, V> {
@BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3) {
@@ -285,7 +287,9 @@ final class ImmutableMapRules {
* over alternatives that don't communicate the immutability of the resulting map at the type
* level.
*/
// XXX: Also rewrite the `ImmutableMap.builder()` variant?
// XXX: Consider introducing a `BugChecker` to replace these `ImmutableMapOfX` rules. That will
// also make it easier to rewrite various `ImmutableMap.builder()` variants.
@SuppressWarnings("java:S107" /* Can't avoid many method parameters here. */)
static final class ImmutableMapOf4<K, V> {
@BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
@@ -303,7 +307,9 @@ final class ImmutableMapRules {
* Object, Object)} over alternatives that don't communicate the immutability of the resulting map
* at the type level.
*/
// XXX: Also rewrite the `ImmutableMap.builder()` variant?
// XXX: Consider introducing a `BugChecker` to replace these `ImmutableMapOfX` rules. That will
// also make it easier to rewrite various `ImmutableMap.builder()` variants.
@SuppressWarnings("java:S107" /* Can't avoid many method parameters here. */)
static final class ImmutableMapOf5<K, V> {
@BeforeTemplate
Map<K, V> before(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {

View File

@@ -4,8 +4,11 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Collections.emptySet;
import static java.util.Collections.singleton;
import static java.util.function.Predicate.not;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import com.google.common.collect.Streams;
import com.google.errorprone.refaster.Refaster;
@@ -15,6 +18,7 @@ import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@@ -211,4 +215,116 @@ final class ImmutableSetRules {
return ImmutableSet.of(e1, e2, e3, e4, e5);
}
}
/**
* Prefer an immutable copy of {@link Sets#difference(Set, Set)} over more contrived alternatives.
*/
static final class SetsDifference<S, T> {
@BeforeTemplate
ImmutableSet<S> before(Set<S> set1, Set<T> set2) {
return set1.stream()
.filter(Refaster.anyOf(not(set2::contains), e -> !set2.contains(e)))
.collect(toImmutableSet());
}
@AfterTemplate
ImmutableSet<S> after(Set<S> set1, Set<T> set2) {
return Sets.difference(set1, set2).immutableCopy();
}
}
/**
* Prefer an immutable copy of {@link Sets#difference(Set, Set)} over more contrived alternatives.
*/
static final class SetsDifferenceMap<T, K, V> {
@BeforeTemplate
ImmutableSet<T> before(Set<T> set, Map<K, V> map) {
return set.stream()
.filter(Refaster.anyOf(not(map::containsKey), e -> !map.containsKey(e)))
.collect(toImmutableSet());
}
@AfterTemplate
ImmutableSet<K> after(Set<K> set, Map<K, V> map) {
return Sets.difference(set, map.keySet()).immutableCopy();
}
}
/**
* Prefer an immutable copy of {@link Sets#difference(Set, Set)} over more contrived alternatives.
*/
static final class SetsDifferenceMultimap<T, K, V> {
@BeforeTemplate
ImmutableSet<T> before(Set<T> set, Multimap<K, V> multimap) {
return set.stream()
.filter(Refaster.anyOf(not(multimap::containsKey), e -> !multimap.containsKey(e)))
.collect(toImmutableSet());
}
@AfterTemplate
ImmutableSet<T> after(Set<T> set, Multimap<K, V> multimap) {
return Sets.difference(set, multimap.keySet()).immutableCopy();
}
}
/**
* Prefer an immutable copy of {@link Sets#intersection(Set, Set)} over more contrived
* alternatives.
*/
static final class SetsIntersection<S, T> {
@BeforeTemplate
ImmutableSet<S> before(Set<S> set1, Set<T> set2) {
return set1.stream().filter(set2::contains).collect(toImmutableSet());
}
@AfterTemplate
ImmutableSet<S> after(Set<S> set1, Set<T> set2) {
return Sets.intersection(set1, set2).immutableCopy();
}
}
/**
* Prefer an immutable copy of {@link Sets#intersection(Set, Set)} over more contrived
* alternatives.
*/
static final class SetsIntersectionMap<T, K, V> {
@BeforeTemplate
ImmutableSet<T> before(Set<T> set, Map<K, V> map) {
return set.stream().filter(map::containsKey).collect(toImmutableSet());
}
@AfterTemplate
ImmutableSet<T> after(Set<T> set, Map<K, V> map) {
return Sets.intersection(set, map.keySet()).immutableCopy();
}
}
/**
* Prefer an immutable copy of {@link Sets#intersection(Set, Set)} over more contrived
* alternatives.
*/
static final class SetsIntersectionMultimap<T, K, V> {
@BeforeTemplate
ImmutableSet<T> before(Set<T> set, Multimap<K, V> multimap) {
return set.stream().filter(multimap::containsKey).collect(toImmutableSet());
}
@AfterTemplate
ImmutableSet<T> after(Set<T> set, Multimap<K, V> multimap) {
return Sets.intersection(set, multimap.keySet()).immutableCopy();
}
}
/** Prefer an immutable copy of {@link Sets#union(Set, Set)} over more contrived alternatives. */
static final class SetsUnion<S, T extends S, U extends S> {
@BeforeTemplate
ImmutableSet<S> before(Set<T> set1, Set<U> set2) {
return Stream.concat(set1.stream(), set2.stream()).collect(toImmutableSet());
}
@AfterTemplate
ImmutableSet<S> after(Set<T> set1, Set<U> set2) {
return Sets.union(set1, set2).immutableCopy();
}
}
}

View File

@@ -1,6 +1,7 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.Streams;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -40,6 +41,7 @@ final class IntStreamRules {
}
@AfterTemplate
@CanIgnoreReturnValue
IntStream after(IntStream stream) {
return stream;
}
@@ -250,6 +252,7 @@ final class IntStreamRules {
/** Prefer {@link IntStream#anyMatch(IntPredicate)} over more contrived alternatives. */
static final class IntStreamAnyMatch {
@BeforeTemplate
@SuppressWarnings("java:S4034" /* This violation will be rewritten. */)
boolean before(IntStream stream, IntPredicate predicate) {
return Refaster.anyOf(
!stream.noneMatch(predicate), stream.filter(predicate).findAny().isPresent());
@@ -287,4 +290,16 @@ final class IntStreamRules {
return stream.allMatch(e -> test(e));
}
}
static final class IntStreamTakeWhile {
@BeforeTemplate
IntStream before(IntStream stream, IntPredicate predicate) {
return stream.takeWhile(predicate).filter(predicate);
}
@AfterTemplate
IntStream after(IntStream stream, IntPredicate predicate) {
return stream.takeWhile(predicate);
}
}
}

View File

@@ -34,8 +34,7 @@ import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
* <p>Note that, while both libraries throw an {@link AssertionError} in case of an assertion
* failure, the exact subtype used generally differs.
*/
// XXX: Not all `org.assertj.core.api.Assertions` methods have an associated Refaster rule yet;
// expand this class.
// XXX: Not all JUnit `Assertions` methods have an associated Refaster rule yet; expand this class.
// XXX: Introduce a `@Matcher` on `Executable` and `ThrowingSupplier` expressions, such that they
// are only matched if they are also compatible with the `ThrowingCallable` functional interface.
// When implementing such a matcher, note that expressions with a non-void return type such as
@@ -45,7 +44,7 @@ import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
final class JUnitToAssertJRules {
private JUnitToAssertJRules() {}
public ImmutableSet<?> elidedTypesAndStaticImports() {
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(
Assertions.class,
assertDoesNotThrow(() -> null),

View File

@@ -1,6 +1,7 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.collect.Streams;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -40,6 +41,7 @@ final class LongStreamRules {
}
@AfterTemplate
@CanIgnoreReturnValue
LongStream after(LongStream stream) {
return stream;
}
@@ -250,6 +252,7 @@ final class LongStreamRules {
/** Prefer {@link LongStream#anyMatch(LongPredicate)} over more contrived alternatives. */
static final class LongStreamAnyMatch {
@BeforeTemplate
@SuppressWarnings("java:S4034" /* This violation will be rewritten. */)
boolean before(LongStream stream, LongPredicate predicate) {
return Refaster.anyOf(
!stream.noneMatch(predicate), stream.filter(predicate).findAny().isPresent());
@@ -287,4 +290,16 @@ final class LongStreamRules {
return stream.allMatch(e -> test(e));
}
}
static final class LongStreamTakeWhile {
@BeforeTemplate
LongStream before(LongStream stream, LongPredicate predicate) {
return stream.takeWhile(predicate).filter(predicate);
}
@AfterTemplate
LongStream after(LongStream stream, LongPredicate predicate) {
return stream.takeWhile(predicate);
}
}
}

View File

@@ -3,10 +3,12 @@ package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import com.google.common.collect.Streams;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.NotMatches;
import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Comparator;
@@ -18,6 +20,7 @@ import java.util.function.Supplier;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.matchers.IsLikelyTrivialComputation;
/** Refaster rules related to expressions dealing with {@link Optional}s. */
@OnlineDocumentation
@@ -68,7 +71,10 @@ final class OptionalRules {
/** Prefer {@link Optional#orElseThrow()} over the less explicit {@link Optional#get()}. */
static final class OptionalOrElseThrow<T> {
@BeforeTemplate
@SuppressWarnings("NullAway")
@SuppressWarnings({
"java:S3655" /* Matched expressions are in practice embedded in a larger context. */,
"NullAway"
})
T before(Optional<T> optional) {
return optional.get();
}
@@ -114,7 +120,7 @@ final class OptionalRules {
/** Prefer {@link Optional#filter(Predicate)} over usage of the ternary operator. */
// XXX: This rule may introduce a compilation error: the `test` expression may reference a
// non-effectively final variable, which is not allowed in the replacement lambda expression.
// Maybe our `Refaster` checker should test `compilesWithFix`?
// Review whether a `@Matcher` can be used to avoid this.
abstract static class TernaryOperatorOptionalPositiveFiltering<T> {
@Placeholder
abstract boolean test(T value);
@@ -134,7 +140,7 @@ final class OptionalRules {
/** Prefer {@link Optional#filter(Predicate)} over usage of the ternary operator. */
// XXX: This rule may introduce a compilation error: the `test` expression may reference a
// non-effectively final variable, which is not allowed in the replacement lambda expression.
// Maybe our `Refaster` checker should test `compilesWithFix`?
// Review whether a `@Matcher` can be used to avoid this.
abstract static class TernaryOperatorOptionalNegativeFiltering<T> {
@Placeholder
abstract boolean test(T value);
@@ -157,6 +163,7 @@ final class OptionalRules {
*/
static final class MapOptionalToBoolean<T> {
@BeforeTemplate
@SuppressWarnings("OptionalOrElseGet" /* Rule is confused by `Refaster#anyOf` usage. */)
boolean before(Optional<T> optional, Function<? super T, Boolean> predicate) {
return optional.map(predicate).orElse(Refaster.anyOf(false, Boolean.FALSE));
}
@@ -220,6 +227,28 @@ final class OptionalRules {
}
}
/**
* Prefer {@link Optional#orElseGet(Supplier)} over {@link Optional#orElse(Object)} if the
* fallback value is not the result of a trivial computation.
*/
// XXX: This rule may introduce a compilation error: the `value` expression may reference a
// non-effectively final variable, which is not allowed in the replacement lambda expression.
// Review whether a `@Matcher` can be used to avoid this.
// XXX: Once `MethodReferenceUsage` is "production ready", replace
// `@NotMatches(IsLikelyTrivialComputation.class)` with `@Matches(RequiresComputation.class)` (and
// reimplement the matcher accordingly).
static final class OptionalOrElseGet<T> {
@BeforeTemplate
T before(Optional<T> optional, @NotMatches(IsLikelyTrivialComputation.class) T value) {
return optional.orElse(value);
}
@AfterTemplate
T after(Optional<T> optional, T value) {
return optional.orElseGet(() -> value);
}
}
/**
* Flatten a stream of {@link Optional}s using {@link Optional#stream()}, rather than using one of
* the more verbose alternatives.
@@ -304,14 +333,12 @@ final class OptionalRules {
abstract Optional<S> toOptionalFunction(@MayOptionallyUse T element);
@BeforeTemplate
Optional<R> before(
Optional<T> optional, Function<? super S, ? extends Optional<? extends R>> function) {
Optional<R> before(Optional<T> optional, Function<? super S, Optional<? extends R>> function) {
return optional.flatMap(v -> toOptionalFunction(v).flatMap(function));
}
@AfterTemplate
Optional<R> after(
Optional<T> optional, Function<? super S, ? extends Optional<? extends R>> function) {
Optional<R> after(Optional<T> optional, Function<? super S, Optional<? extends R>> function) {
return optional.flatMap(v -> toOptionalFunction(v)).flatMap(function);
}
}
@@ -323,6 +350,9 @@ final class OptionalRules {
Optional<T> before(Optional<T> optional1, Optional<T> optional2) {
// XXX: Note that rewriting the first and third variant will change the code's behavior if
// `optional2` has side-effects.
// XXX: Note that rewriting the first and third variant will introduce a compilation error if
// `optional2` is not effectively final. Review whether a `@Matcher` can be used to avoid
// this.
return Refaster.anyOf(
optional1.map(Optional::of).orElse(optional2),
optional1.map(Optional::of).orElseGet(() -> optional2),
@@ -350,6 +380,7 @@ final class OptionalRules {
}
@AfterTemplate
@CanIgnoreReturnValue
Optional<T> after(Optional<T> optional) {
return optional;
}

View File

@@ -91,6 +91,7 @@ final class PreconditionsRules {
/** Prefer {@link Objects#requireNonNull(Object)} over more verbose alternatives. */
static final class RequireNonNullStatement<T> {
@BeforeTemplate
@SuppressWarnings("java:S1695" /* This violation will be rewritten. */)
void before(T object) {
if (object == null) {
throw new NullPointerException();
@@ -121,6 +122,7 @@ final class PreconditionsRules {
/** Prefer {@link Objects#requireNonNull(Object, String)} over more verbose alternatives. */
static final class RequireNonNullWithMessageStatement<T> {
@BeforeTemplate
@SuppressWarnings("java:S1695" /* This violation will be rewritten. */)
void before(T object, String message) {
if (object == null) {
throw new NullPointerException(message);

View File

@@ -1,6 +1,13 @@
package tech.picnic.errorprone.refasterrules;
import com.google.common.primitives.Booleans;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.Chars;
import com.google.common.primitives.Doubles;
import com.google.common.primitives.Floats;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
@@ -13,12 +20,13 @@ final class PrimitiveRules {
/** Avoid contrived ways of expressing the "less than" relationship. */
static final class LessThan {
@BeforeTemplate
@SuppressWarnings("java:S1940" /* This violation will be rewritten. */)
boolean before(double a, double b) {
return !(a >= b);
}
@AfterTemplate
boolean after(long a, long b) {
boolean after(double a, double b) {
return a < b;
}
}
@@ -26,12 +34,13 @@ final class PrimitiveRules {
/** Avoid contrived ways of expressing the "less than or equal to" relationship. */
static final class LessThanOrEqualTo {
@BeforeTemplate
@SuppressWarnings("java:S1940" /* This violation will be rewritten. */)
boolean before(double a, double b) {
return !(a > b);
}
@AfterTemplate
boolean after(long a, long b) {
boolean after(double a, double b) {
return a <= b;
}
}
@@ -39,12 +48,13 @@ final class PrimitiveRules {
/** Avoid contrived ways of expressing the "greater than" relationship. */
static final class GreaterThan {
@BeforeTemplate
@SuppressWarnings("java:S1940" /* This violation will be rewritten. */)
boolean before(double a, double b) {
return !(a <= b);
}
@AfterTemplate
boolean after(long a, long b) {
boolean after(double a, double b) {
return a > b;
}
}
@@ -52,12 +62,13 @@ final class PrimitiveRules {
/** Avoid contrived ways of expressing the "greater than or equal to" relationship. */
static final class GreaterThanOrEqualTo {
@BeforeTemplate
@SuppressWarnings("java:S1940" /* This violation will be rewritten. */)
boolean before(double a, double b) {
return !(a < b);
}
@AfterTemplate
boolean after(long a, long b) {
boolean after(double a, double b) {
return a >= b;
}
}
@@ -65,13 +76,312 @@ final class PrimitiveRules {
/** Prefer {@link Math#toIntExact(long)} over the Guava alternative. */
static final class LongToIntExact {
@BeforeTemplate
int before(long a) {
return Ints.checkedCast(a);
int before(long l) {
return Ints.checkedCast(l);
}
@AfterTemplate
int after(long a) {
return Math.toIntExact(a);
int after(long l) {
return Math.toIntExact(l);
}
}
/** Prefer {@link Boolean#hashCode(boolean)} over the Guava alternative. */
static final class BooleanHashCode {
@BeforeTemplate
int before(boolean b) {
return Booleans.hashCode(b);
}
@AfterTemplate
int after(boolean b) {
return Boolean.hashCode(b);
}
}
/** Prefer {@link Byte#hashCode(byte)} over the Guava alternative. */
static final class ByteHashCode {
@BeforeTemplate
int before(byte b) {
return Bytes.hashCode(b);
}
@AfterTemplate
int after(byte b) {
return Byte.hashCode(b);
}
}
/** Prefer {@link Character#hashCode(char)} over the Guava alternative. */
static final class CharacterHashCode {
@BeforeTemplate
int before(char c) {
return Chars.hashCode(c);
}
@AfterTemplate
int after(char c) {
return Character.hashCode(c);
}
}
/** Prefer {@link Short#hashCode(short)} over the Guava alternative. */
static final class ShortHashCode {
@BeforeTemplate
int before(short s) {
return Shorts.hashCode(s);
}
@AfterTemplate
int after(short s) {
return Short.hashCode(s);
}
}
/** Prefer {@link Integer#hashCode(int)} over the Guava alternative. */
static final class IntegerHashCode {
@BeforeTemplate
int before(int i) {
return Ints.hashCode(i);
}
@AfterTemplate
int after(int i) {
return Integer.hashCode(i);
}
}
/** Prefer {@link Long#hashCode(long)} over the Guava alternative. */
static final class LongHashCode {
@BeforeTemplate
int before(long l) {
return Longs.hashCode(l);
}
@AfterTemplate
int after(long l) {
return Long.hashCode(l);
}
}
/** Prefer {@link Float#hashCode(float)} over the Guava alternative. */
static final class FloatHashCode {
@BeforeTemplate
int before(float f) {
return Floats.hashCode(f);
}
@AfterTemplate
int after(float f) {
return Float.hashCode(f);
}
}
/** Prefer {@link Double#hashCode(double)} over the Guava alternative. */
static final class DoubleHashCode {
@BeforeTemplate
int before(double d) {
return Doubles.hashCode(d);
}
@AfterTemplate
int after(double d) {
return Double.hashCode(d);
}
}
/** Prefer {@link Boolean#compare(boolean, boolean)} over the Guava alternative. */
static final class BooleanCompare {
@BeforeTemplate
int before(boolean a, boolean b) {
return Booleans.compare(a, b);
}
@AfterTemplate
int after(boolean a, boolean b) {
return Boolean.compare(a, b);
}
}
/** Prefer {@link Character#compare(char, char)} over the Guava alternative. */
static final class CharacterCompare {
@BeforeTemplate
int before(char a, char b) {
return Chars.compare(a, b);
}
@AfterTemplate
int after(char a, char b) {
return Character.compare(a, b);
}
}
/** Prefer {@link Short#compare(short, short)} over the Guava alternative. */
static final class ShortCompare {
@BeforeTemplate
int before(short a, short b) {
return Shorts.compare(a, b);
}
@AfterTemplate
int after(short a, short b) {
return Short.compare(a, b);
}
}
/** Prefer {@link Integer#compare(int, int)} over the Guava alternative. */
static final class IntegerCompare {
@BeforeTemplate
int before(int a, int b) {
return Ints.compare(a, b);
}
@AfterTemplate
int after(int a, int b) {
return Integer.compare(a, b);
}
}
/** Prefer {@link Long#compare(long, long)} over the Guava alternative. */
static final class LongCompare {
@BeforeTemplate
int before(long a, long b) {
return Longs.compare(a, b);
}
@AfterTemplate
int after(long a, long b) {
return Long.compare(a, b);
}
}
/** Prefer {@link Float#compare(float, float)} over the Guava alternative. */
static final class FloatCompare {
@BeforeTemplate
int before(float a, float b) {
return Floats.compare(a, b);
}
@AfterTemplate
int after(float a, float b) {
return Float.compare(a, b);
}
}
/** Prefer {@link Double#compare(double, double)} over the Guava alternative. */
static final class DoubleCompare {
@BeforeTemplate
int before(double a, double b) {
return Doubles.compare(a, b);
}
@AfterTemplate
int after(double a, double b) {
return Double.compare(a, b);
}
}
/** Prefer {@link Character#BYTES} over the Guava alternative. */
static final class CharacterBytes {
@BeforeTemplate
int before() {
return Chars.BYTES;
}
@AfterTemplate
int after() {
return Character.BYTES;
}
}
/** Prefer {@link Short#BYTES} over the Guava alternative. */
static final class ShortBytes {
@BeforeTemplate
int before() {
return Shorts.BYTES;
}
@AfterTemplate
int after() {
return Short.BYTES;
}
}
/** Prefer {@link Integer#BYTES} over the Guava alternative. */
static final class IntegerBytes {
@BeforeTemplate
int before() {
return Ints.BYTES;
}
@AfterTemplate
int after() {
return Integer.BYTES;
}
}
/** Prefer {@link Long#BYTES} over the Guava alternative. */
static final class LongBytes {
@BeforeTemplate
int before() {
return Longs.BYTES;
}
@AfterTemplate
int after() {
return Long.BYTES;
}
}
/** Prefer {@link Float#BYTES} over the Guava alternative. */
static final class FloatBytes {
@BeforeTemplate
int before() {
return Floats.BYTES;
}
@AfterTemplate
int after() {
return Float.BYTES;
}
}
/** Prefer {@link Double#BYTES} over the Guava alternative. */
static final class DoubleBytes {
@BeforeTemplate
int before() {
return Doubles.BYTES;
}
@AfterTemplate
int after() {
return Double.BYTES;
}
}
/** Prefer {@link Float#isFinite(float)} over the Guava alternative. */
static final class FloatIsFinite {
@BeforeTemplate
boolean before(float f) {
return Floats.isFinite(f);
}
@AfterTemplate
boolean after(float f) {
return Float.isFinite(f);
}
}
/** Prefer {@link Double#isFinite(double)} over the Guava alternative. */
static final class DoubleIsFinite {
@BeforeTemplate
boolean before(double d) {
return Doubles.isFinite(d);
}
@AfterTemplate
boolean after(double d) {
return Double.isFinite(d);
}
}
}

View File

@@ -1,6 +1,7 @@
package tech.picnic.errorprone.refasterrules;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.MoreCollectors.toOptional;
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
@@ -12,6 +13,8 @@ import static reactor.function.TupleUtils.function;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
@@ -33,6 +36,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collector;
import org.jspecify.annotations.Nullable;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
@@ -94,7 +98,7 @@ final class ReactorRules {
}
/** Prefer {@link Mono#justOrEmpty(Object)} over more contrived alternatives. */
static final class MonoJustOrEmpty<@Nullable T> {
static final class MonoJustOrEmptyObject<@Nullable T> {
@BeforeTemplate
Mono<T> before(T value) {
return Mono.justOrEmpty(Optional.ofNullable(value));
@@ -107,9 +111,25 @@ final class ReactorRules {
}
/** Prefer {@link Mono#justOrEmpty(Optional)} over more verbose alternatives. */
static final class MonoJustOrEmptyOptional<T> {
@BeforeTemplate
Mono<T> before(Optional<T> optional) {
return Mono.just(optional).filter(Optional::isPresent).map(Optional::orElseThrow);
}
@AfterTemplate
Mono<T> after(Optional<T> optional) {
return Mono.justOrEmpty(optional);
}
}
/**
* Prefer {@link Mono#defer(Supplier) deferring} {@link Mono#justOrEmpty(Optional)} over more
* verbose alternatives.
*/
// XXX: If `optional` is a constant and effectively-final expression then the `Mono.defer` can be
// dropped. Should look into Refaster support for identifying this.
static final class MonoFromOptional<T> {
static final class MonoDeferMonoJustOrEmpty<T> {
@BeforeTemplate
@SuppressWarnings(
"MonoFromSupplier" /* `optional` may match a checked exception-throwing expression. */)
@@ -384,12 +404,33 @@ final class ReactorRules {
return mono.then();
}
// XXX: Replace this rule with an extension of the `IdentityConversion` rule, supporting
// `Stream#map`, `Mono#map` and `Flux#map`.
@BeforeTemplate
Mono<ImmutableList<T>> before3(Mono<ImmutableList<T>> mono) {
return mono.map(ImmutableList::copyOf);
}
@AfterTemplate
@CanIgnoreReturnValue
Mono<T> after(Mono<T> mono) {
return mono;
}
}
/** Don't unnecessarily transform a {@link Mono} to a {@link Flux} to expect exactly one item. */
static final class MonoSingle<T> {
@BeforeTemplate
Mono<T> before(Mono<T> mono) {
return mono.flux().single();
}
@AfterTemplate
Mono<T> after(Mono<T> mono) {
return mono.single();
}
}
/** Don't unnecessarily pass an empty publisher to {@link Flux#switchIfEmpty(Publisher)}. */
static final class FluxSwitchIfEmptyOfEmptyPublisher<T> {
@BeforeTemplate
@@ -398,6 +439,7 @@ final class ReactorRules {
}
@AfterTemplate
@CanIgnoreReturnValue
Flux<T> after(Flux<T> flux) {
return flux;
}
@@ -406,6 +448,7 @@ final class ReactorRules {
/** Prefer {@link Flux#concatMap(Function)} over more contrived alternatives. */
static final class FluxConcatMap<T, S> {
@BeforeTemplate
@SuppressWarnings("NestedPublishers")
Flux<S> before(Flux<T> flux, Function<? super T, ? extends Publisher<? extends S>> function) {
return Refaster.anyOf(
flux.flatMap(function, 1),
@@ -422,6 +465,7 @@ final class ReactorRules {
/** Prefer {@link Flux#concatMap(Function, int)} over more contrived alternatives. */
static final class FluxConcatMapWithPrefetch<T, S> {
@BeforeTemplate
@SuppressWarnings("NestedPublishers")
Flux<S> before(
Flux<T> flux,
Function<? super T, ? extends Publisher<? extends S>> function,
@@ -594,6 +638,7 @@ final class ReactorRules {
abstract S transformation(@MayOptionallyUse T value);
@BeforeTemplate
@SuppressWarnings("java:S138" /* Method is long, but not complex. */)
Publisher<S> before(Flux<T> flux, boolean delayUntilEnd, int maxConcurrency, int prefetch) {
return Refaster.anyOf(
flux.concatMap(
@@ -752,6 +797,7 @@ final class ReactorRules {
/** Prefer {@link Mono#flatMap(Function)} over more contrived alternatives. */
static final class MonoFlatMap<S, T> {
@BeforeTemplate
@SuppressWarnings("NestedPublishers")
Mono<T> before(Mono<S> mono, Function<? super S, ? extends Mono<? extends T>> function) {
return mono.map(function).flatMap(identity());
}
@@ -765,6 +811,7 @@ final class ReactorRules {
/** Prefer {@link Mono#flatMapMany(Function)} over more contrived alternatives. */
static final class MonoFlatMapMany<S, T> {
@BeforeTemplate
@SuppressWarnings("NestedPublishers")
Flux<T> before(Mono<S> mono, Function<? super S, ? extends Publisher<? extends T>> function) {
return mono.map(function).flatMapMany(identity());
}
@@ -1150,6 +1197,56 @@ final class ReactorRules {
}
}
/**
* Do not unnecessarily {@link Flux#filter(Predicate) filter} the result of {@link
* Flux#takeWhile(Predicate)} using the same {@link Predicate}.
*/
static final class FluxTakeWhile<T> {
@BeforeTemplate
Flux<T> before(Flux<T> flux, Predicate<? super T> predicate) {
return flux.takeWhile(predicate).filter(predicate);
}
@AfterTemplate
Flux<T> after(Flux<T> flux, Predicate<? super T> predicate) {
return flux.takeWhile(predicate);
}
}
/**
* Prefer {@link Flux#collect(Collector)} with {@link ImmutableList#toImmutableList()} over
* alternatives that do not explicitly return an immutable collection.
*/
static final class FluxCollectToImmutableList<T> {
@BeforeTemplate
Mono<List<T>> before(Flux<T> flux) {
return flux.collectList();
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Mono<ImmutableList<T>> after(Flux<T> flux) {
return flux.collect(toImmutableList());
}
}
/**
* Prefer {@link Flux#collect(Collector)} with {@link ImmutableSet#toImmutableSet()} over more
* contrived alternatives.
*/
static final class FluxCollectToImmutableSet<T> {
@BeforeTemplate
Mono<ImmutableSet<T>> before(Flux<T> flux) {
return flux.collect(toImmutableList()).map(ImmutableSet::copyOf);
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Mono<ImmutableSet<T>> after(Flux<T> flux) {
return flux.collect(toImmutableSet());
}
}
/** Prefer {@link reactor.util.context.Context#empty()}} over more verbose alternatives. */
// XXX: Consider introducing an `IsEmpty` matcher that identifies a wide range of guaranteed-empty
// `Collection` and `Map` expressions.
@@ -1215,6 +1312,7 @@ final class ReactorRules {
}
@AfterTemplate
@CanIgnoreReturnValue
StepVerifier.Step<T> after(StepVerifier.Step<T> step) {
return step;
}
@@ -1234,6 +1332,23 @@ final class ReactorRules {
}
}
/** Avoid list collection when verifying that a {@link Flux} emits exactly one value. */
// XXX: This rule assumes that the matched collector does not drop elements. Consider introducing
// a `@Matches(DoesNotDropElements.class)` or `@NotMatches(MayDropElements.class)` guard.
static final class FluxAsStepVerifierExpectNext<T, L extends List<T>> {
@BeforeTemplate
StepVerifier.Step<L> before(Flux<T> flux, Collector<? super T, ?, L> listCollector, T object) {
return flux.collect(listCollector)
.as(StepVerifier::create)
.assertNext(list -> assertThat(list).containsExactly(object));
}
@AfterTemplate
StepVerifier.Step<T> after(Flux<T> flux, T object) {
return flux.as(StepVerifier::create).expectNext(object);
}
}
/** Prefer {@link StepVerifier.LastStep#verifyComplete()} over more verbose alternatives. */
static final class StepVerifierLastStepVerifyComplete {
@BeforeTemplate

View File

@@ -3,21 +3,43 @@ package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.util.Comparator.naturalOrder;
import static java.util.Comparator.reverseOrder;
import static java.util.function.Function.identity;
import static java.util.function.Predicate.not;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.filtering;
import static java.util.stream.Collectors.flatMapping;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.maxBy;
import static java.util.stream.Collectors.minBy;
import static java.util.stream.Collectors.reducing;
import static java.util.stream.Collectors.summarizingDouble;
import static java.util.stream.Collectors.summarizingInt;
import static java.util.stream.Collectors.summarizingLong;
import static java.util.stream.Collectors.summingDouble;
import static java.util.stream.Collectors.summingInt;
import static java.util.stream.Collectors.summingLong;
import com.google.common.collect.Streams;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
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.Matches;
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
import com.google.errorprone.refaster.annotation.NotMatches;
import com.google.errorprone.refaster.annotation.Placeholder;
import com.google.errorprone.refaster.annotation.Repeated;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.DoubleSummaryStatistics;
import java.util.IntSummaryStatistics;
import java.util.LongSummaryStatistics;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.ToDoubleFunction;
@@ -28,6 +50,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.matchers.IsLambdaExpressionOrMethodReference;
import tech.picnic.errorprone.refaster.matchers.IsRefasterAsVarargs;
/** Refaster rules related to expressions dealing with {@link Stream}s. */
@OnlineDocumentation
@@ -82,12 +105,9 @@ final class StreamRules {
* Prefer {@link Arrays#stream(Object[])} over {@link Stream#of(Object[])}, as the former is
* clearer.
*/
// XXX: Introduce a `Matcher` that identifies `Refaster.asVarargs(...)` invocations and annotate
// the `array` parameter as `@NotMatches(IsRefasterAsVarargs.class)`. Then elsewhere
// `@SuppressWarnings("StreamOfArray")` annotations can be dropped.
static final class StreamOfArray<T> {
@BeforeTemplate
Stream<T> before(T[] array) {
Stream<T> before(@NotMatches(IsRefasterAsVarargs.class) T[] array) {
return Stream.of(array);
}
@@ -105,6 +125,7 @@ final class StreamRules {
}
@AfterTemplate
@CanIgnoreReturnValue
Stream<T> after(Stream<T> stream) {
return stream;
}
@@ -228,14 +249,18 @@ final class StreamRules {
}
/** In order to test whether a stream has any element, simply try to find one. */
// XXX: This rule assumes that any matched `Collector` does not perform any filtering.
// (Perhaps we could add a `@Matches` guard that validates that the collector expression does not
// contain a `Collectors#filtering` call. That'd still not be 100% accurate, though.)
static final class StreamIsEmpty<T> {
@BeforeTemplate
boolean before(Stream<T> stream) {
boolean before(Stream<T> stream, Collector<? super T, ?, ? extends Collection<?>> collector) {
return Refaster.anyOf(
stream.count() == 0,
stream.count() <= 0,
stream.count() < 1,
stream.findFirst().isEmpty());
stream.findFirst().isEmpty(),
stream.collect(collector).isEmpty());
}
@AfterTemplate
@@ -263,9 +288,12 @@ final class StreamRules {
static final class StreamMin<T> {
@BeforeTemplate
@SuppressWarnings("java:S4266" /* This violation will be rewritten. */)
Optional<T> before(Stream<T> stream, Comparator<? super T> comparator) {
return Refaster.anyOf(
stream.max(comparator.reversed()), stream.sorted(comparator).findFirst());
stream.max(comparator.reversed()),
stream.sorted(comparator).findFirst(),
stream.collect(minBy(comparator)));
}
@AfterTemplate
@@ -289,9 +317,12 @@ final class StreamRules {
static final class StreamMax<T> {
@BeforeTemplate
@SuppressWarnings("java:S4266" /* This violation will be rewritten. */)
Optional<T> before(Stream<T> stream, Comparator<? super T> comparator) {
return Refaster.anyOf(
stream.min(comparator.reversed()), Streams.findLast(stream.sorted(comparator)));
stream.min(comparator.reversed()),
Streams.findLast(stream.sorted(comparator)),
stream.collect(maxBy(comparator)));
}
@AfterTemplate
@@ -316,6 +347,7 @@ final class StreamRules {
/** Prefer {@link Stream#noneMatch(Predicate)} over more contrived alternatives. */
static final class StreamNoneMatch<T> {
@BeforeTemplate
@SuppressWarnings("java:S4034" /* This violation will be rewritten. */)
boolean before(Stream<T> stream, Predicate<? super T> predicate) {
return Refaster.anyOf(
!stream.anyMatch(predicate),
@@ -323,6 +355,14 @@ final class StreamRules {
stream.filter(predicate).findAny().isEmpty());
}
@BeforeTemplate
boolean before2(
Stream<T> stream,
@Matches(IsLambdaExpressionOrMethodReference.class)
Function<? super T, Boolean> predicate) {
return stream.map(predicate).noneMatch(Refaster.anyOf(Boolean::booleanValue, b -> b));
}
@AfterTemplate
boolean after(Stream<T> stream, Predicate<? super T> predicate) {
return stream.noneMatch(predicate);
@@ -347,11 +387,20 @@ final class StreamRules {
/** Prefer {@link Stream#anyMatch(Predicate)} over more contrived alternatives. */
static final class StreamAnyMatch<T> {
@BeforeTemplate
@SuppressWarnings("java:S4034" /* This violation will be rewritten. */)
boolean before(Stream<T> stream, Predicate<? super T> predicate) {
return Refaster.anyOf(
!stream.noneMatch(predicate), stream.filter(predicate).findAny().isPresent());
}
@BeforeTemplate
boolean before2(
Stream<T> stream,
@Matches(IsLambdaExpressionOrMethodReference.class)
Function<? super T, Boolean> predicate) {
return stream.map(predicate).anyMatch(Refaster.anyOf(Boolean::booleanValue, b -> b));
}
@AfterTemplate
boolean after(Stream<T> stream, Predicate<? super T> predicate) {
return stream.anyMatch(predicate);
@@ -364,6 +413,14 @@ final class StreamRules {
return stream.noneMatch(Refaster.anyOf(not(predicate), predicate.negate()));
}
@BeforeTemplate
boolean before2(
Stream<T> stream,
@Matches(IsLambdaExpressionOrMethodReference.class)
Function<? super T, Boolean> predicate) {
return stream.map(predicate).allMatch(Refaster.anyOf(Boolean::booleanValue, b -> b));
}
@AfterTemplate
boolean after(Stream<T> stream, Predicate<? super T> predicate) {
return stream.allMatch(predicate);
@@ -387,7 +444,13 @@ final class StreamRules {
static final class StreamMapToIntSum<T> {
@BeforeTemplate
int before(
@SuppressWarnings("java:S4266" /* This violation will be rewritten. */)
long before(Stream<T> stream, ToIntFunction<T> mapper) {
return stream.collect(summingInt(mapper));
}
@BeforeTemplate
int before2(
Stream<T> stream,
@Matches(IsLambdaExpressionOrMethodReference.class) Function<? super T, Integer> mapper) {
return stream.map(mapper).reduce(0, Integer::sum);
@@ -401,7 +464,13 @@ final class StreamRules {
static final class StreamMapToDoubleSum<T> {
@BeforeTemplate
double before(
@SuppressWarnings("java:S4266" /* This violation will be rewritten. */)
double before(Stream<T> stream, ToDoubleFunction<T> mapper) {
return stream.collect(summingDouble(mapper));
}
@BeforeTemplate
double before2(
Stream<T> stream,
@Matches(IsLambdaExpressionOrMethodReference.class) Function<? super T, Double> mapper) {
return stream.map(mapper).reduce(0.0, Double::sum);
@@ -415,7 +484,13 @@ final class StreamRules {
static final class StreamMapToLongSum<T> {
@BeforeTemplate
long before(
@SuppressWarnings("java:S4266" /* This violation will be rewritten. */)
long before(Stream<T> stream, ToLongFunction<T> mapper) {
return stream.collect(summingLong(mapper));
}
@BeforeTemplate
long before2(
Stream<T> stream,
@Matches(IsLambdaExpressionOrMethodReference.class) Function<? super T, Long> mapper) {
return stream.map(mapper).reduce(0L, Long::sum);
@@ -426,4 +501,154 @@ final class StreamRules {
return stream.mapToLong(mapper).sum();
}
}
static final class StreamMapToIntSummaryStatistics<T> {
@BeforeTemplate
IntSummaryStatistics before(Stream<T> stream, ToIntFunction<T> mapper) {
return stream.collect(summarizingInt(mapper));
}
@AfterTemplate
IntSummaryStatistics after(Stream<T> stream, ToIntFunction<T> mapper) {
return stream.mapToInt(mapper).summaryStatistics();
}
}
static final class StreamMapToDoubleSummaryStatistics<T> {
@BeforeTemplate
DoubleSummaryStatistics before(Stream<T> stream, ToDoubleFunction<T> mapper) {
return stream.collect(summarizingDouble(mapper));
}
@AfterTemplate
DoubleSummaryStatistics after(Stream<T> stream, ToDoubleFunction<T> mapper) {
return stream.mapToDouble(mapper).summaryStatistics();
}
}
static final class StreamMapToLongSummaryStatistics<T> {
@BeforeTemplate
LongSummaryStatistics before(Stream<T> stream, ToLongFunction<T> mapper) {
return stream.collect(summarizingLong(mapper));
}
@AfterTemplate
LongSummaryStatistics after(Stream<T> stream, ToLongFunction<T> mapper) {
return stream.mapToLong(mapper).summaryStatistics();
}
}
static final class StreamCount<T> {
@BeforeTemplate
@SuppressWarnings("java:S4266" /* This violation will be rewritten. */)
long before(Stream<T> stream) {
return stream.collect(counting());
}
@AfterTemplate
long after(Stream<T> stream) {
return stream.count();
}
}
static final class StreamReduce<T> {
@BeforeTemplate
@SuppressWarnings("java:S4266" /* This violation will be rewritten. */)
Optional<T> before(Stream<T> stream, BinaryOperator<T> accumulator) {
return stream.collect(reducing(accumulator));
}
@AfterTemplate
Optional<T> after(Stream<T> stream, BinaryOperator<T> accumulator) {
return stream.reduce(accumulator);
}
}
static final class StreamReduceWithIdentity<T> {
@BeforeTemplate
@SuppressWarnings("java:S4266" /* This violation will be rewritten. */)
T before(Stream<T> stream, T identity, BinaryOperator<T> accumulator) {
return stream.collect(reducing(identity, accumulator));
}
@AfterTemplate
T after(Stream<T> stream, T identity, BinaryOperator<T> accumulator) {
return stream.reduce(identity, accumulator);
}
}
static final class StreamFilterCollect<T, R> {
@BeforeTemplate
R before(
Stream<T> stream, Predicate<? super T> predicate, Collector<? super T, ?, R> collector) {
return stream.collect(filtering(predicate, collector));
}
@AfterTemplate
R after(
Stream<T> stream, Predicate<? super T> predicate, Collector<? super T, ?, R> collector) {
return stream.filter(predicate).collect(collector);
}
}
static final class StreamMapCollect<T, U, R> {
@BeforeTemplate
@SuppressWarnings("java:S4266" /* This violation will be rewritten. */)
R before(
Stream<T> stream,
Function<? super T, ? extends U> mapper,
Collector<? super U, ?, R> collector) {
return stream.collect(mapping(mapper, collector));
}
@AfterTemplate
R after(
Stream<T> stream,
Function<? super T, ? extends U> mapper,
Collector<? super U, ?, R> collector) {
return stream.map(mapper).collect(collector);
}
}
static final class StreamFlatMapCollect<T, U, R> {
@BeforeTemplate
R before(
Stream<T> stream,
Function<? super T, ? extends Stream<? extends U>> mapper,
Collector<? super U, ?, R> collector) {
return stream.collect(flatMapping(mapper, collector));
}
@AfterTemplate
R after(
Stream<T> stream,
Function<? super T, ? extends Stream<? extends U>> mapper,
Collector<? super U, ?, R> collector) {
return stream.flatMap(mapper).collect(collector);
}
}
static final class StreamsConcat<T> {
@BeforeTemplate
Stream<T> before(@Repeated Stream<T> stream) {
return Stream.of(Refaster.asVarargs(stream)).flatMap(Refaster.anyOf(identity(), s -> s));
}
@AfterTemplate
Stream<T> after(@Repeated Stream<T> stream) {
return Streams.concat(Refaster.asVarargs(stream));
}
}
static final class StreamTakeWhile<T> {
@BeforeTemplate
Stream<T> before(Stream<T> stream, Predicate<? super T> predicate) {
return stream.takeWhile(predicate).filter(predicate);
}
@AfterTemplate
Stream<T> after(Stream<T> stream, Predicate<? super T> predicate) {
return stream.takeWhile(predicate);
}
}
}

View File

@@ -1,6 +1,8 @@
package tech.picnic.errorprone.refasterrules;
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.function.Predicate.not;
import static java.util.stream.Collectors.joining;
import com.google.common.base.Joiner;
@@ -11,21 +13,23 @@ import com.google.errorprone.refaster.Refaster;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.AlsoNegation;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.google.errorprone.refaster.annotation.UseImportPolicy;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import org.jspecify.annotations.Nullable;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster rules related to expressions dealing with {@link String}s. */
// XXX: Should we prefer `s -> !s.isEmpty()` or `not(String::isEmpty)`?
@OnlineDocumentation
final class StringRules {
private StringRules() {}
/** Prefer {@link String#isEmpty()} over alternatives that consult the string's length. */
// XXX: Once we target JDK 15+, generalize this rule to cover all `CharSequence` subtypes.
static final class StringIsEmpty {
@BeforeTemplate
boolean before(String str) {
@@ -39,6 +43,37 @@ final class StringRules {
}
}
/** Prefer a method reference to {@link String#isEmpty()} over the equivalent lambda function. */
// XXX: Once we target JDK 15+, generalize this rule to cover all `CharSequence` subtypes.
// XXX: As it stands, this rule is a special case of what `MethodReferenceUsage` tries to achieve.
// If/when `MethodReferenceUsage` becomes production ready, we should simply drop this check.
static final class StringIsEmptyPredicate {
@BeforeTemplate
Predicate<String> before() {
return s -> s.isEmpty();
}
@AfterTemplate
Predicate<String> after() {
return String::isEmpty;
}
}
/** Prefer a method reference to {@link String#isEmpty()} over the equivalent lambda function. */
// XXX: Once we target JDK 15+, generalize this rule to cover all `CharSequence` subtypes.
static final class StringIsNotEmptyPredicate {
@BeforeTemplate
Predicate<String> before() {
return s -> !s.isEmpty();
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Predicate<String> after() {
return not(String::isEmpty);
}
}
/** Prefer {@link Strings#isNullOrEmpty(String)} over the more verbose alternative. */
static final class StringIsNullOrEmpty {
@BeforeTemplate
@@ -65,7 +100,7 @@ final class StringRules {
@AfterTemplate
Optional<String> after(String str) {
return Optional.ofNullable(str).filter(s -> !s.isEmpty());
return Optional.ofNullable(str).filter(not(String::isEmpty));
}
}
@@ -76,8 +111,9 @@ final class StringRules {
}
@AfterTemplate
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
Optional<String> after(Optional<String> optional) {
return optional.filter(s -> !s.isEmpty());
return optional.filter(not(String::isEmpty));
}
}

View File

@@ -0,0 +1,106 @@
package tech.picnic.errorprone.refasterrules;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;
import com.sun.source.tree.Tree;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
/** Refaster rules related to expressions dealing with {@link SuggestedFix}es. */
@OnlineDocumentation
final class SuggestedFixRules {
private SuggestedFixRules() {}
/** Prefer {@link SuggestedFix#delete(Tree)} over more contrived alternatives. */
static final class SuggestedFixDelete {
@BeforeTemplate
SuggestedFix before(Tree tree) {
return SuggestedFix.builder().delete(tree).build();
}
@AfterTemplate
SuggestedFix after(Tree tree) {
return SuggestedFix.delete(tree);
}
}
/** Prefer {@link SuggestedFix#replace(Tree, String)}} over more contrived alternatives. */
static final class SuggestedFixReplaceTree {
@BeforeTemplate
SuggestedFix before(Tree tree, String replaceWith) {
return SuggestedFix.builder().replace(tree, replaceWith).build();
}
@AfterTemplate
SuggestedFix after(Tree tree, String replaceWith) {
return SuggestedFix.replace(tree, replaceWith);
}
}
/** Prefer {@link SuggestedFix#replace(int, int, String)}} over more contrived alternatives. */
static final class SuggestedFixReplaceStartEnd {
@BeforeTemplate
SuggestedFix before(int start, int end, String replaceWith) {
return SuggestedFix.builder().replace(start, end, replaceWith).build();
}
@AfterTemplate
SuggestedFix after(int start, int end, String replaceWith) {
return SuggestedFix.replace(start, end, replaceWith);
}
}
/**
* Prefer {@link SuggestedFix#replace(Tree, String, int, int)}} over more contrived alternatives.
*/
static final class SuggestedFixReplaceTreeStartEnd {
@BeforeTemplate
SuggestedFix before(Tree tree, String replaceWith, int start, int end) {
return SuggestedFix.builder().replace(tree, replaceWith, start, end).build();
}
@AfterTemplate
SuggestedFix after(Tree tree, String replaceWith, int start, int end) {
return SuggestedFix.replace(tree, replaceWith, start, end);
}
}
/** Prefer {@link SuggestedFix#swap(Tree, Tree)} over more contrived alternatives. */
static final class SuggestedFixSwap {
@BeforeTemplate
SuggestedFix before(Tree tree1, Tree tree2) {
return SuggestedFix.builder().swap(tree1, tree2).build();
}
@AfterTemplate
SuggestedFix after(Tree tree1, Tree tree2) {
return SuggestedFix.swap(tree1, tree2);
}
}
/** Prefer {@link SuggestedFix#prefixWith(Tree, String)} over more contrived alternatives. */
static final class SuggestedFixPrefixWith {
@BeforeTemplate
SuggestedFix before(Tree tree, String prefix) {
return SuggestedFix.builder().prefixWith(tree, prefix).build();
}
@AfterTemplate
SuggestedFix after(Tree tree, String prefix) {
return SuggestedFix.prefixWith(tree, prefix);
}
}
/** Prefer {@link SuggestedFix#postfixWith(Tree, String)}} over more contrived alternatives. */
static final class SuggestedFixPostfixWith {
@BeforeTemplate
SuggestedFix before(Tree tree, String postfix) {
return SuggestedFix.builder().postfixWith(tree, postfix).build();
}
@AfterTemplate
SuggestedFix after(Tree tree, String postfix) {
return SuggestedFix.postfixWith(tree, postfix);
}
}
}

View File

@@ -1,8 +1,7 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode.TEXT_MATCH;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
@@ -54,6 +53,6 @@ final class AssertJIsNullTest {
" assertThat(\"foo\").isNull();",
" }",
"}")
.doTest(TEXT_MATCH);
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -0,0 +1,110 @@
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 AssociativeMethodInvocationTest {
@Test
void identification() {
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);",
" }",
"}")
.doTest();
}
@Test
void replacement() {
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());",
" }",
"}")
.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());",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -34,9 +34,11 @@ final class CanonicalAnnotationSyntaxTest {
" // BUG: Diagnostic contains:",
" @pkg.A.Foo()",
" A functional1();",
"",
" // BUG: Diagnostic contains:",
" @A.Foo()",
" A functional2();",
"",
" // BUG: Diagnostic contains:",
" @Foo()",
" A functional3();",
@@ -53,9 +55,11 @@ final class CanonicalAnnotationSyntaxTest {
" // BUG: Diagnostic contains:",
" @pkg.A.Foo({1})",
" A singleton1();",
"",
" // BUG: Diagnostic contains:",
" @A.Foo({1})",
" A singleton2();",
"",
" // BUG: Diagnostic contains:",
" @Foo({1})",
" A singleton3();",
@@ -63,9 +67,11 @@ final class CanonicalAnnotationSyntaxTest {
" // 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();",
@@ -82,9 +88,11 @@ final class CanonicalAnnotationSyntaxTest {
" // 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();",
@@ -112,11 +120,13 @@ final class CanonicalAnnotationSyntaxTest {
" 1, 1,",
" })",
" A trailingComma1();",
"",
" // BUG: Diagnostic contains:",
" @A.Foo({",
" 1, 1,",
" })",
" A trailingComma2();",
"",
" // BUG: Diagnostic contains:",
" @Foo({",
" 1, 1,",

View File

@@ -136,6 +136,58 @@ final class DirectReturnTest {
" 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();
}

View File

@@ -50,18 +50,21 @@ final class LexicographicalAnnotationAttributeListingTest {
"",
" @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();",
@@ -86,6 +89,7 @@ final class LexicographicalAnnotationAttributeListingTest {
"",
" @Foo(cls = {int.class, long.class})",
" A sortedClasses();",
"",
" // BUG: Diagnostic contains:",
" @Foo(cls = {long.class, int.class})",
" A unsortedClasses();",
@@ -98,6 +102,7 @@ final class LexicographicalAnnotationAttributeListingTest {
"",
" @Foo(enums = {DOWN, UP})",
" A sortedEnums();",
"",
" // BUG: Diagnostic contains:",
" @Foo(enums = {UP, DOWN})",
" A unsortedEnums();",
@@ -110,15 +115,18 @@ final class LexicographicalAnnotationAttributeListingTest {
"",
" @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();",
@@ -265,12 +273,14 @@ final class LexicographicalAnnotationAttributeListingTest {
" // 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();",

View File

@@ -52,6 +52,7 @@ final class LexicographicalAnnotationListingTest {
" @Foo",
" @Bar",
" A unsortedSimpleCase();",
"",
" // BUG: Diagnostic contains:",
" @Foo()",
" @Bar()",
@@ -69,6 +70,7 @@ final class LexicographicalAnnotationListingTest {
" @Baz",
" @Bar",
" A threeUnsortedAnnotationsSameInitialLetter();",
"",
" // BUG: Diagnostic contains:",
" @Bar",
" @Foo()",
@@ -84,11 +86,13 @@ final class LexicographicalAnnotationListingTest {
" @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\")})",
@@ -104,6 +108,7 @@ final class LexicographicalAnnotationListingTest {
" @Foo(ints = {1, 2})",
" @Foo({\"b\"})",
" A sortedRepeatableAnnotation();",
"",
" // BUG: Diagnostic contains:",
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
" @Bar",

View File

@@ -1,89 +0,0 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.common.base.Predicates.containsPattern;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class MissingRefasterAnnotationTest {
@Test
void identification() {
CompilationTestHelper.newInstance(MissingRefasterAnnotation.class, getClass())
.expectErrorMessage(
"X",
containsPattern("The Refaster rule contains a method without any Refaster annotations"))
.addSourceLines(
"A.java",
"import com.google.errorprone.refaster.annotation.AfterTemplate;",
"import com.google.errorprone.refaster.annotation.AlsoNegation;",
"import com.google.errorprone.refaster.annotation.BeforeTemplate;",
"import java.util.Map;",
"",
"class A {",
" // BUG: Diagnostic matches: X",
" static final class MethodLacksBeforeTemplateAnnotation {",
" @BeforeTemplate",
" boolean before1(String string) {",
" return string.equals(\"\");",
" }",
"",
" // @BeforeTemplate is missing",
" boolean before2(String string) {",
" return string.length() == 0;",
" }",
"",
" @AfterTemplate",
" @AlsoNegation",
" boolean after(String string) {",
" return string.isEmpty();",
" }",
" }",
"",
" // BUG: Diagnostic matches: X",
" static final class MethodLacksAfterTemplateAnnotation {",
" @BeforeTemplate",
" boolean before(String string) {",
" return string.equals(\"\");",
" }",
"",
" // @AfterTemplate is missing",
" boolean after(String string) {",
" return string.isEmpty();",
" }",
" }",
"",
" // BUG: Diagnostic matches: X",
" abstract class MethodLacksPlaceholderAnnotation<K, V> {",
" // @Placeholder is missing",
" abstract V function(K key);",
"",
" @BeforeTemplate",
" void before(Map<K, V> map, K key) {",
" if (!map.containsKey(key)) {",
" map.put(key, function(key));",
" }",
" }",
"",
" @AfterTemplate",
" void after(Map<K, V> map, K key) {",
" map.computeIfAbsent(key, k -> function(k));",
" }",
" }",
"",
" static final class ValidRefasterRule {",
" @BeforeTemplate",
" void unusedPureFunctionCall(Object o) {",
" o.toString();",
" }",
" }",
"",
" static final class NotARefasterRule {",
" @Override",
" public String toString() {",
" return \"This is not a Refaster rule\";",
" }",
" }",
"}")
.doTest();
}
}

View File

@@ -0,0 +1,26 @@
package tech.picnic.errorprone.bugpatterns;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class MongoDBTextFilterUsageTest {
@Test
void identification() {
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());",
" }",
"}")
.doTest();
}
}

View File

@@ -36,19 +36,4 @@ final class NestedOptionalsTest {
"}")
.doTest();
}
@Test
void identificationOptionalTypeNotLoaded() {
CompilationTestHelper.newInstance(NestedOptionals.class, getClass())
.addSourceLines(
"A.java",
"import java.time.Duration;",
"",
"class A {",
" void m() {",
" Duration.ofSeconds(1);",
" }",
"}")
.doTest();
}
}

View File

@@ -0,0 +1,37 @@
package tech.picnic.errorprone.bugpatterns;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class NestedPublishersTest {
@Test
void identification() {
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);",
" }",
"}")
.doTest();
}
}

View File

@@ -1,8 +1,7 @@
package tech.picnic.errorprone.bugpatterns;
import static com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode.TEXT_MATCH;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
@@ -145,6 +144,6 @@ final class NonEmptyMonoTest {
" Mono.just(2).hasElement();",
" }",
"}")
.doTest(TEXT_MATCH);
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -10,12 +10,9 @@ import org.junit.jupiter.api.Test;
// `String.valueOf(null)` may not. That is because the latter matches `String#valueOf(char[])`. We
// could special-case `null` arguments, but that doesn't seem worth the trouble.
final class RedundantStringConversionTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass());
@Test
void identificationOfIdentityTransformation() {
compilationTestHelper
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addSourceLines(
"A.java",
"class A {",
@@ -38,7 +35,7 @@ final class RedundantStringConversionTest {
@Test
void identificationWithinMutatingAssignment() {
compilationTestHelper
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addSourceLines(
"A.java",
"import java.math.BigInteger;",
@@ -99,7 +96,7 @@ final class RedundantStringConversionTest {
@Test
void identificationWithinBinaryOperation() {
compilationTestHelper
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addSourceLines(
"A.java",
"import java.math.BigInteger;",
@@ -194,7 +191,7 @@ final class RedundantStringConversionTest {
@Test
void identificationWithinStringBuilderMethod() {
compilationTestHelper
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addSourceLines(
"A.java",
"import java.math.BigInteger;",
@@ -249,7 +246,7 @@ final class RedundantStringConversionTest {
// XXX: Also test the other formatter methods.
@Test
void identificationWithinFormatterMethod() {
compilationTestHelper
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addSourceLines(
"A.java",
"import java.util.Formattable;",
@@ -294,7 +291,7 @@ final class RedundantStringConversionTest {
@Test
void identificationWithinGuavaGuardMethod() {
compilationTestHelper
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addSourceLines(
"A.java",
"import static com.google.common.base.Preconditions.checkArgument;",
@@ -354,7 +351,7 @@ final class RedundantStringConversionTest {
@Test
void identificationWithinSlf4jLoggerMethod() {
compilationTestHelper
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
.addSourceLines(
"A.java",
"import java.util.Formattable;",

View File

@@ -9,12 +9,12 @@ 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 javax.servlet.http.HttpServletRequest;",
"import javax.servlet.http.HttpServletResponse;",
"import org.springframework.http.HttpMethod;",
"import org.springframework.ui.Model;",
"import org.springframework.validation.BindingResult;",

View File

@@ -32,18 +32,23 @@ final class SpringMvcAnnotationTest {
"",
" @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();",

View File

@@ -1,124 +0,0 @@
package tech.picnic.errorprone.bugpatterns;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
import org.junit.jupiter.api.Test;
final class StringCaseLocaleUsageTest {
@Test
void identification() {
CompilationTestHelper.newInstance(StringCaseLocaleUsage.class, getClass())
.addSourceLines(
"A.java",
"import static java.util.Locale.ROOT;",
"",
"import java.util.Locale;",
"",
"class A {",
" void m() {",
" \"a\".toLowerCase(Locale.ROOT);",
" \"a\".toUpperCase(Locale.ROOT);",
" \"b\".toLowerCase(ROOT);",
" \"b\".toUpperCase(ROOT);",
" \"c\".toLowerCase(Locale.getDefault());",
" \"c\".toUpperCase(Locale.getDefault());",
" \"d\".toLowerCase(Locale.ENGLISH);",
" \"d\".toUpperCase(Locale.ENGLISH);",
" \"e\".toLowerCase(new Locale(\"foo\"));",
" \"e\".toUpperCase(new Locale(\"foo\"));",
"",
" // BUG: Diagnostic contains:",
" \"f\".toLowerCase();",
" // BUG: Diagnostic contains:",
" \"g\".toUpperCase();",
"",
" String h = \"h\";",
" // BUG: Diagnostic contains:",
" h.toLowerCase();",
" String i = \"i\";",
" // BUG: Diagnostic contains:",
" i.toUpperCase();",
" }",
"}")
.doTest();
}
@Test
void replacementFirstSuggestedFix() {
BugCheckerRefactoringTestHelper.newInstance(StringCaseLocaleUsage.class, getClass())
.addInputLines(
"A.java",
"class A {",
" void m() {",
" \"a\".toLowerCase(/* Comment with parens: (). */ );",
" \"b\".toUpperCase();",
" \"c\".toLowerCase().toString();",
"",
" toString().toLowerCase();",
" toString().toUpperCase /* Comment with parens: (). */();",
"",
" this.toString().toLowerCase() /* Comment with parens: (). */;",
" this.toString().toUpperCase();",
" }",
"}")
.addOutputLines(
"A.java",
"import java.util.Locale;",
"",
"class A {",
" void m() {",
" \"a\".toLowerCase(/* Comment with parens: (). */ Locale.ROOT);",
" \"b\".toUpperCase(Locale.ROOT);",
" \"c\".toLowerCase(Locale.ROOT).toString();",
"",
" toString().toLowerCase(Locale.ROOT);",
" toString().toUpperCase /* Comment with parens: (). */(Locale.ROOT);",
"",
" this.toString().toLowerCase(Locale.ROOT) /* Comment with parens: (). */;",
" this.toString().toUpperCase(Locale.ROOT);",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
@Test
void replacementSecondSuggestedFix() {
BugCheckerRefactoringTestHelper.newInstance(StringCaseLocaleUsage.class, getClass())
.setFixChooser(FixChoosers.SECOND)
.addInputLines(
"A.java",
"class A {",
" void m() {",
" \"a\".toLowerCase();",
" \"b\".toUpperCase(/* Comment with parens: (). */ );",
" \"c\".toLowerCase().toString();",
"",
" toString().toLowerCase();",
" toString().toUpperCase /* Comment with parens: (). */();",
"",
" this.toString().toLowerCase() /* Comment with parens: (). */;",
" this.toString().toUpperCase();",
" }",
"}")
.addOutputLines(
"A.java",
"import java.util.Locale;",
"",
"class A {",
" void m() {",
" \"a\".toLowerCase(Locale.getDefault());",
" \"b\".toUpperCase(/* Comment with parens: (). */ Locale.getDefault());",
" \"c\".toLowerCase(Locale.getDefault()).toString();",
"",
" toString().toLowerCase(Locale.getDefault());",
" toString().toUpperCase /* Comment with parens: (). */(Locale.getDefault());",
"",
" this.toString().toLowerCase(Locale.getDefault()) /* Comment with parens: (). */;",
" this.toString().toUpperCase(Locale.getDefault());",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
}

View File

@@ -10,7 +10,7 @@ import org.junit.jupiter.params.provider.MethodSource;
final class JavaKeywordsTest {
private static Stream<Arguments> isValidIdentifierTestCases() {
/* { str, expected } */
/* { string, expected } */
return Stream.of(
arguments("", false),
arguments("public", false),
@@ -28,7 +28,7 @@ final class JavaKeywordsTest {
@MethodSource("isValidIdentifierTestCases")
@ParameterizedTest
void isValidIdentifier(String str, boolean expected) {
assertThat(JavaKeywords.isValidIdentifier(str)).isEqualTo(expected);
void isValidIdentifier(String string, boolean expected) {
assertThat(JavaKeywords.isValidIdentifier(string)).isEqualTo(expected);
}
}

View File

@@ -2,6 +2,7 @@ package tech.picnic.errorprone.bugpatterns.util;
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugPattern;
@@ -13,25 +14,13 @@ import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
final class MethodMatcherFactoryTest {
/** A {@link BugChecker} that flags method invocations matched by {@link #TEST_MATCHER}. */
@BugPattern(severity = SUGGESTION, summary = "Flags methods matched by the test matcher.")
public static final class MatchedMethodsFlagger extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (TEST_MATCHER.matches(tree, state)) {
return buildDescription(tree).build();
}
return Description.NO_MATCH;
}
}
private static final Matcher<ExpressionTree> TEST_MATCHER =
new MethodMatcherFactory()
.create(
@@ -40,16 +29,20 @@ final class MethodMatcherFactoryTest {
"com.example.A#m2(java.lang.String)",
"com.example.sub.B#m3(int,int)"));
@Test
void createWithMalformedSignatures() {
private static Stream<Arguments> createWithMalformedSignaturesTestCases() {
/* { signatures } */
return Stream.of(
arguments(ImmutableList.of("foo.bar")),
arguments(ImmutableList.of("foo.bar#baz")),
arguments(ImmutableList.of("a", "foo.bar#baz()")),
arguments(ImmutableList.of("foo.bar#baz()", "a")));
}
@MethodSource("createWithMalformedSignaturesTestCases")
@ParameterizedTest
void createWithMalformedSignatures(ImmutableList<String> signatures) {
MethodMatcherFactory factory = new MethodMatcherFactory();
assertThatThrownBy(() -> factory.create(ImmutableList.of("foo.bar")))
.isInstanceOf(IllegalArgumentException.class);
assertThatThrownBy(() -> factory.create(ImmutableList.of("foo.bar#baz")))
.isInstanceOf(IllegalArgumentException.class);
assertThatThrownBy(() -> factory.create(ImmutableList.of("a", "foo.bar#baz()")))
.isInstanceOf(IllegalArgumentException.class);
assertThatThrownBy(() -> factory.create(ImmutableList.of("foo.bar#baz()", "a")))
assertThatThrownBy(() -> factory.create(signatures))
.isInstanceOf(IllegalArgumentException.class);
}
@@ -207,4 +200,20 @@ final class MethodMatcherFactoryTest {
"}")
.doTest();
}
/** A {@link BugChecker} that flags method invocations matched by {@link #TEST_MATCHER}. */
@BugPattern(severity = SUGGESTION, summary = "Flags methods matched by the test matcher.")
public static final class MatchedMethodsFlagger extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (TEST_MATCHER.matches(tree, state)) {
return buildDescription(tree).build();
}
return Description.NO_MATCH;
}
}
}

View File

@@ -1,21 +1,29 @@
package tech.picnic.errorprone.bugpatterns.util;
import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.generic;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.subOf;
import static tech.picnic.errorprone.bugpatterns.util.MoreTypes.type;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.BugPattern;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Supplier;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;
import org.junit.jupiter.api.Test;
final class MoreMatchersTest {
@Test
void hasMetaAnnotation() {
CompilationTestHelper.newInstance(TestMatcher.class, getClass())
CompilationTestHelper.newInstance(HasMetaAnnotationTestChecker.class, getClass())
.addSourceLines(
"A.java",
"import org.junit.jupiter.api.AfterAll;",
@@ -47,9 +55,59 @@ final class MoreMatchersTest {
.doTest();
}
/** A {@link BugChecker} that delegates to {@link MoreMatchers#hasMetaAnnotation(String)} . */
@Test
void isSubTypeOf() {
CompilationTestHelper.newInstance(IsSubTypeOfTestChecker.class, getClass())
.addSourceLines(
"A.java",
"import com.google.common.collect.ImmutableList;",
"import com.google.common.collect.ImmutableSet;",
"import com.google.common.collect.ImmutableSortedSet;",
"",
"class A {",
" void m() {",
" ImmutableSet.of(\"foo\");",
" ImmutableSortedSet.of(\"foo\");",
" ImmutableList.of(\"foo\");",
" ImmutableList.of(1);",
" ImmutableList.of(1.0);",
" ImmutableList.of((Number) 1);",
"",
" // BUG: Diagnostic contains:",
" ImmutableSet.of(1);",
" // BUG: Diagnostic contains:",
" ImmutableSet.of(1.0);",
" // BUG: Diagnostic contains:",
" ImmutableSet.of((Number) 1);",
" // BUG: Diagnostic contains:",
" ImmutableSortedSet.of(1);",
" // BUG: Diagnostic contains:",
" ImmutableSortedSet.of(1.0);",
" // BUG: Diagnostic contains:",
" ImmutableSortedSet.of((Number) 1);",
" }",
"}")
.doTest();
}
@Test
void isSubTypeOfBoundTypeUnknown() {
CompilationTestHelper.newInstance(IsSubTypeOfTestChecker.class, getClass())
.withClasspath()
.addSourceLines(
"A.java",
"class A {",
" void m() {",
" System.out.println(toString());",
" }",
"}")
.doTest();
}
/** A {@link BugChecker} that delegates to {@link MoreMatchers#hasMetaAnnotation(String)}. */
@BugPattern(summary = "Interacts with `MoreMatchers` for testing purposes", severity = ERROR)
public static final class TestMatcher extends BugChecker implements AnnotationTreeMatcher {
public static final class HasMetaAnnotationTestChecker extends BugChecker
implements AnnotationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<AnnotationTree> DELEGATE =
MoreMatchers.hasMetaAnnotation("org.junit.jupiter.api.TestTemplate");
@@ -59,4 +117,19 @@ final class MoreMatchersTest {
return DELEGATE.matches(tree, state) ? describeMatch(tree) : Description.NO_MATCH;
}
}
/** A {@link BugChecker} that delegates to {@link MoreMatchers#isSubTypeOf(Supplier)}. */
@BugPattern(summary = "Interacts with `MoreMatchers` for testing purposes", severity = ERROR)
public static final class IsSubTypeOfTestChecker extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<Tree> DELEGATE =
MoreMatchers.isSubTypeOf(
generic(type(ImmutableSet.class.getName()), subOf(type(Number.class.getName()))));
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
return DELEGATE.matches(tree, state) ? describeMatch(tree) : Description.NO_MATCH;
}
}
}

View File

@@ -8,22 +8,22 @@ import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import javax.lang.model.element.Name;
import org.junit.jupiter.api.Test;
final class SourceCodeTest {
private final BugCheckerRefactoringTestHelper refactoringTestHelper =
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass());
@Test
void deleteWithTrailingWhitespaceAnnotations() {
refactoringTestHelper
BugCheckerRefactoringTestHelper.newInstance(
DeleteWithTrailingWhitespaceTestChecker.class, getClass())
.addInputLines("AnnotationToBeDeleted.java", "@interface AnnotationToBeDeleted {}")
.expectUnchanged()
.addInputLines(
@@ -96,7 +96,8 @@ final class SourceCodeTest {
@Test
void deleteWithTrailingWhitespaceMethods() {
refactoringTestHelper
BugCheckerRefactoringTestHelper.newInstance(
DeleteWithTrailingWhitespaceTestChecker.class, getClass())
.addInputLines(
"MethodDeletions.java",
"interface MethodDeletions {",
@@ -162,13 +163,78 @@ final class SourceCodeTest {
.doTest(TestMode.TEXT_MATCH);
}
@Test
void unwrapMethodInvocation() {
BugCheckerRefactoringTestHelper.newInstance(UnwrapMethodInvocationTestChecker.class, getClass())
.addInputLines(
"A.java",
"import com.google.common.collect.ImmutableList;",
"",
"class A {",
" Object[] m() {",
" return new Object[][] {",
" {ImmutableList.of()},",
" {ImmutableList.of(1)},",
" {com.google.common.collect.ImmutableList.of(1, 2)},",
" {",
" 0, /*a*/",
" ImmutableList /*b*/./*c*/ <Integer> /*d*/of /*e*/(/*f*/ 1 /*g*/, /*h*/ 2 /*i*/) /*j*/",
" }",
" };",
" }",
"}")
.addOutputLines(
"A.java",
"import com.google.common.collect.ImmutableList;",
"",
"class A {",
" Object[] m() {",
" return new Object[][] {{}, {1}, {1, 2}, {0, /*a*/ /*f*/ 1 /*g*/, /*h*/ 2 /*i*/ /*j*/}};",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
@Test
void unwrapMethodInvocationDroppingWhitespaceAndComments() {
BugCheckerRefactoringTestHelper.newInstance(
UnwrapMethodInvocationDroppingWhitespaceAndCommentsTestChecker.class, getClass())
.addInputLines(
"A.java",
"import com.google.common.collect.ImmutableList;",
"",
"class A {",
" Object[] m() {",
" return new Object[][] {",
" {ImmutableList.of()},",
" {ImmutableList.of(1)},",
" {com.google.common.collect.ImmutableList.of(1, 2)},",
" {",
" 0, /*a*/",
" ImmutableList /*b*/./*c*/ <Integer> /*d*/of /*e*/(/*f*/ 1 /*g*/, /*h*/ 2 /*i*/) /*j*/",
" }",
" };",
" }",
"}")
.addOutputLines(
"A.java",
"import com.google.common.collect.ImmutableList;",
"",
"class A {",
" Object[] m() {",
" return new Object[][] {{}, {1}, {1, 2}, {0, /*a*/ 1, 2 /*j*/}};",
" }",
"}")
.doTest(TestMode.TEXT_MATCH);
}
/**
* A {@link BugChecker} that uses {@link SourceCode#deleteWithTrailingWhitespace(Tree,
* VisitorState)} to suggest the deletion of annotations and methods with a name containing
* {@value DELETION_MARKER}.
*/
@BugPattern(severity = ERROR, summary = "Interacts with `SourceCode` for testing purposes")
public static final class TestChecker extends BugChecker
public static final class DeleteWithTrailingWhitespaceTestChecker extends BugChecker
implements AnnotationTreeMatcher, MethodTreeMatcher {
private static final long serialVersionUID = 1L;
private static final String DELETION_MARKER = "ToBeDeleted";
@@ -192,4 +258,37 @@ final class SourceCodeTest {
: Description.NO_MATCH;
}
}
/**
* A {@link BugChecker} that applies {@link
* SourceCode#unwrapMethodInvocation(MethodInvocationTree, VisitorState)} to all method
* invocations.
*/
@BugPattern(severity = ERROR, summary = "Interacts with `SourceCode` for testing purposes")
public static final class UnwrapMethodInvocationTestChecker extends BugChecker
implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
return describeMatch(tree, SourceCode.unwrapMethodInvocation(tree, state));
}
}
/**
* A {@link BugChecker} that applies {@link
* SourceCode#unwrapMethodInvocationDroppingWhitespaceAndComments(MethodInvocationTree,
* VisitorState)} to all method invocations.
*/
@BugPattern(severity = ERROR, summary = "Interacts with `SourceCode` for testing purposes")
public static final class UnwrapMethodInvocationDroppingWhitespaceAndCommentsTestChecker
extends BugChecker implements MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
return describeMatch(
tree, SourceCode.unwrapMethodInvocationDroppingWhitespaceAndComments(tree, state));
}
}
}

View File

@@ -18,12 +18,9 @@ import org.junit.jupiter.params.provider.ValueSource;
import reactor.core.publisher.Flux;
final class ThirdPartyLibraryTest {
private final CompilationTestHelper compilationTestHelper =
CompilationTestHelper.newInstance(TestChecker.class, getClass());
@Test
void isIntroductionAllowed() {
compilationTestHelper
CompilationTestHelper.newInstance(TestChecker.class, getClass())
.addSourceLines(
"A.java",
"// BUG: Diagnostic contains: ASSERTJ: true, GUAVA: true, NEW_RELIC_AGENT_API: true, REACTOR: true",
@@ -33,7 +30,7 @@ final class ThirdPartyLibraryTest {
@Test
void isIntroductionAllowedWitnessClassesInSymtab() {
compilationTestHelper
CompilationTestHelper.newInstance(TestChecker.class, getClass())
.addSourceLines(
"A.java",
"import com.google.common.collect.ImmutableList;",
@@ -55,7 +52,7 @@ final class ThirdPartyLibraryTest {
@Test
void isIntroductionAllowedWitnessClassesPartiallyOnClassPath() {
compilationTestHelper
CompilationTestHelper.newInstance(TestChecker.class, getClass())
.withClasspath(ImmutableList.class, Flux.class)
.addSourceLines(
"A.java",
@@ -66,7 +63,7 @@ final class ThirdPartyLibraryTest {
@Test
void isIntroductionAllowedWitnessClassesNotOnClassPath() {
compilationTestHelper
CompilationTestHelper.newInstance(TestChecker.class, getClass())
.withClasspath()
.addSourceLines(
"A.java",
@@ -79,7 +76,7 @@ final class ThirdPartyLibraryTest {
@ParameterizedTest
@ValueSource(booleans = {true, false})
void isIntroductionAllowedIgnoreClasspathCompat(boolean ignoreClassPath) {
compilationTestHelper
CompilationTestHelper.newInstance(TestChecker.class, getClass())
.setArgs("-XepOpt:ErrorProneSupport:IgnoreClasspathCompat=" + ignoreClassPath)
.withClasspath(ImmutableList.class, Flux.class)
.addSourceLines(

View File

@@ -13,7 +13,6 @@ final class RefasterRulesTest {
/** The names of all Refaster rule groups defined in this module. */
private static final ImmutableSet<Class<?>> RULE_COLLECTIONS =
ImmutableSet.of(
AssertJRules.class,
AssertJBigDecimalRules.class,
AssertJBigIntegerRules.class,
AssertJBooleanRules.class,
@@ -25,11 +24,12 @@ final class RefasterRulesTest {
AssertJFloatRules.class,
AssertJIntegerRules.class,
AssertJLongRules.class,
AssertJNumberRules.class,
AssertJMapRules.class,
AssertJNumberRules.class,
AssertJObjectRules.class,
AssertJOptionalRules.class,
AssertJPrimitiveRules.class,
AssertJRules.class,
AssertJShortRules.class,
AssertJStringRules.class,
AssertJThrowingCallableRules.class,
@@ -65,6 +65,7 @@ final class RefasterRulesTest {
RxJava2AdapterRules.class,
StreamRules.class,
StringRules.class,
SuggestedFixRules.class,
TestNGToAssertJRules.class,
TimeRules.class,
WebClientRules.class);

View File

@@ -11,7 +11,7 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJBigDecimalRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(offset(0), withPercentage(0));
}

View File

@@ -11,7 +11,7 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJBigDecimalRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(offset(0), withPercentage(0));
}

View File

@@ -11,7 +11,7 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJBigIntegerRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(offset(0), withPercentage(0));
}

View File

@@ -11,7 +11,7 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJBigIntegerRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(offset(0), withPercentage(0));
}

View File

@@ -10,7 +10,7 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJByteRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(offset(0), withPercentage(0));
}

View File

@@ -10,7 +10,7 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJByteRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(offset(0), withPercentage(0));
}

View File

@@ -10,7 +10,7 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJDoubleRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(withPercentage(0));
}

View File

@@ -10,7 +10,7 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJDoubleRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(withPercentage(0));
}

View File

@@ -9,7 +9,7 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJEnumerableRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(Iterables.class);
}

View File

@@ -9,7 +9,7 @@ import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
final class AssertJEnumerableRulesTest implements RefasterRuleCollectionTestCase {
@Override
public ImmutableSet<?> elidedTypesAndStaticImports() {
public ImmutableSet<Object> elidedTypesAndStaticImports() {
return ImmutableSet.of(Iterables.class);
}

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