mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
Compare commits
395 Commits
v0.16.1
...
sschroever
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2437c66793 | ||
|
|
3f566f8028 | ||
|
|
83f3f8bedc | ||
|
|
12585a8969 | ||
|
|
72b701cae3 | ||
|
|
24e3251eb0 | ||
|
|
f124749a4f | ||
|
|
2a3d9c8dd5 | ||
|
|
0fa59a5cec | ||
|
|
d316e8ac70 | ||
|
|
53fe15c356 | ||
|
|
acb8b651b7 | ||
|
|
ace6bc2813 | ||
|
|
f69fef2f52 | ||
|
|
d033b84b5b | ||
|
|
3e702733bc | ||
|
|
f212e9476d | ||
|
|
da00863e34 | ||
|
|
476916f381 | ||
|
|
67bf5b98a8 | ||
|
|
db7757c556 | ||
|
|
bfd309800b | ||
|
|
0121f7b33c | ||
|
|
8dbff50a8b | ||
|
|
aec56ce025 | ||
|
|
1b8ffd86b9 | ||
|
|
ee7be7e3b2 | ||
|
|
57825decf0 | ||
|
|
2b3e11bd24 | ||
|
|
23cb29b6fc | ||
|
|
ba1dd2cd08 | ||
|
|
75a9786f8f | ||
|
|
0b4fd8ddd1 | ||
|
|
2eda393c03 | ||
|
|
512a3bebad | ||
|
|
db18d6a1fc | ||
|
|
75ca3030f7 | ||
|
|
f484c3f10b | ||
|
|
0753de05d1 | ||
|
|
ab0847e49f | ||
|
|
f9383e4e94 | ||
|
|
50b6c31675 | ||
|
|
63e78933ac | ||
|
|
cd0e962ef7 | ||
|
|
107d135894 | ||
|
|
0bc43a32b9 | ||
|
|
1024f0e671 | ||
|
|
3eb7cf740f | ||
|
|
2713a7ed67 | ||
|
|
8ba75245b4 | ||
|
|
b3d391c80d | ||
|
|
43a1ea1d6c | ||
|
|
c4fd4871fc | ||
|
|
23bbb34fb7 | ||
|
|
56a82e56c0 | ||
|
|
8f0d870fff | ||
|
|
d531ceb9c6 | ||
|
|
dc87aeda6c | ||
|
|
1668546450 | ||
|
|
fc9c20062a | ||
|
|
27e9fe79a5 | ||
|
|
e37280b752 | ||
|
|
fff368c80a | ||
|
|
37cbee0f0a | ||
|
|
141822b614 | ||
|
|
b1bfc1fd36 | ||
|
|
13684ec59d | ||
|
|
a51ff4de4e | ||
|
|
da9b313ff7 | ||
|
|
6a50fe2d9c | ||
|
|
ed32cbae06 | ||
|
|
00549a3ba6 | ||
|
|
13f1fa3167 | ||
|
|
6396def588 | ||
|
|
7599b0f22f | ||
|
|
08eb7e7699 | ||
|
|
89f918c23e | ||
|
|
f08fc344f5 | ||
|
|
99aa656a1e | ||
|
|
86fbaf7403 | ||
|
|
563012549a | ||
|
|
4f46eb30d2 | ||
|
|
2f30082127 | ||
|
|
548506fbbb | ||
|
|
bdef83bce5 | ||
|
|
f7f665681d | ||
|
|
7c0d544cf8 | ||
|
|
9390b6f571 | ||
|
|
176a833d89 | ||
|
|
3cacd27248 | ||
|
|
f06a2e4d43 | ||
|
|
cd06288f5b | ||
|
|
4b458e01bd | ||
|
|
eccfc34c78 | ||
|
|
0317cb73d6 | ||
|
|
ce6931cc36 | ||
|
|
9940576ea8 | ||
|
|
caf2a86922 | ||
|
|
507d759d02 | ||
|
|
8ec4936980 | ||
|
|
0f0b27abb7 | ||
|
|
2b1dbd98cd | ||
|
|
e0583a8f0a | ||
|
|
21437a43aa | ||
|
|
cf8af8c5cf | ||
|
|
07bd4b0b54 | ||
|
|
d1765fea0e | ||
|
|
5922c5b032 | ||
|
|
56b60f5cf6 | ||
|
|
be6b17b7dc | ||
|
|
f782ec2d8f | ||
|
|
6e88e3cea8 | ||
|
|
09fb21358a | ||
|
|
c27a626042 | ||
|
|
da33e800fa | ||
|
|
bc13976cc7 | ||
|
|
7f1f0656fd | ||
|
|
4e99382f42 | ||
|
|
9aa03aa842 | ||
|
|
71cc09a7e7 | ||
|
|
9b4cbfb84d | ||
|
|
f2238c779c | ||
|
|
6e893e9869 | ||
|
|
7ee8826e96 | ||
|
|
a0689f62b4 | ||
|
|
1b00c87b2f | ||
|
|
0bce1a0e29 | ||
|
|
ce18b0c058 | ||
|
|
4f2c143b9c | ||
|
|
f4740e0e64 | ||
|
|
3a155169ef | ||
|
|
13847f6d2c | ||
|
|
6a81b92e11 | ||
|
|
5794b404f2 | ||
|
|
b2d7ed4dc7 | ||
|
|
0fdc102aa5 | ||
|
|
ce3cf6a2d0 | ||
|
|
0f657f8835 | ||
|
|
5f56f43c40 | ||
|
|
ef6faf518a | ||
|
|
aa08d954a0 | ||
|
|
e4d1818ed0 | ||
|
|
beb96f0f4b | ||
|
|
4d1eeb2be1 | ||
|
|
9cbc6f875c | ||
|
|
5583630fb4 | ||
|
|
91e841ce12 | ||
|
|
3956a82cd5 | ||
|
|
c57debdc25 | ||
|
|
6a13efded8 | ||
|
|
432cf4560d | ||
|
|
966fb36ac9 | ||
|
|
c63d9350d2 | ||
|
|
e74874b04c | ||
|
|
f821d3775b | ||
|
|
3d5ee10d93 | ||
|
|
26da67d1f5 | ||
|
|
b3ca01a6c7 | ||
|
|
9f222e9efe | ||
|
|
097af51a3e | ||
|
|
c62e6c1127 | ||
|
|
5960423c4e | ||
|
|
188715c3c0 | ||
|
|
fb45bb00ed | ||
|
|
fd5fc913ce | ||
|
|
ae20c6069d | ||
|
|
8457bd5026 | ||
|
|
fcfb97b0e0 | ||
|
|
15680b4cb3 | ||
|
|
afebfbf478 | ||
|
|
fe2ac938f3 | ||
|
|
078d8c16fa | ||
|
|
c679a3fc0c | ||
|
|
de54b4bf64 | ||
|
|
ea60241782 | ||
|
|
e4f928addb | ||
|
|
059cc9e2db | ||
|
|
1e43c28c95 | ||
|
|
a07e9b3115 | ||
|
|
aec38d2e33 | ||
|
|
5b77663288 | ||
|
|
97c2bbd4b1 | ||
|
|
9c8fbfd36a | ||
|
|
38e6c3fdb5 | ||
|
|
5b1d82cfeb | ||
|
|
0821a95fcc | ||
|
|
f4afe457cb | ||
|
|
fd56ca8b6e | ||
|
|
882794d63b | ||
|
|
73ed6e32c7 | ||
|
|
ca5c3dd3b4 | ||
|
|
f6e9dbb996 | ||
|
|
260021c961 | ||
|
|
ec54e79f3e | ||
|
|
4cbfdba521 | ||
|
|
d94f65a1f0 | ||
|
|
9afdf2ddf3 | ||
|
|
060c901479 | ||
|
|
1feee4f64a | ||
|
|
552ddf6a7d | ||
|
|
5d92c6c6ce | ||
|
|
fa8ca80040 | ||
|
|
b733179cd0 | ||
|
|
3d9aab7c5b | ||
|
|
366cdda3d8 | ||
|
|
5b6dd147ef | ||
|
|
a868b03130 | ||
|
|
fdf9bb5d25 | ||
|
|
363b0c22c7 | ||
|
|
32ec35a354 | ||
|
|
635fe280f8 | ||
|
|
aac9b6bf10 | ||
|
|
c322ea1bbc | ||
|
|
a433a90673 | ||
|
|
5a37d65632 | ||
|
|
77d183f8fd | ||
|
|
2eb4e853c5 | ||
|
|
45a7242cf5 | ||
|
|
c85070ba23 | ||
|
|
a687f09bf0 | ||
|
|
2e4fdcb0db | ||
|
|
1005d93b7e | ||
|
|
136123f6b4 | ||
|
|
4cb5f0079d | ||
|
|
290ddf1972 | ||
|
|
5a163ce2e9 | ||
|
|
4eb0aae452 | ||
|
|
b5b98d899b | ||
|
|
bbf3d79d9a | ||
|
|
1164270589 | ||
|
|
f03d72388a | ||
|
|
2e5d1f1e87 | ||
|
|
4b1c892f04 | ||
|
|
2b6b8de150 | ||
|
|
b275a33eb8 | ||
|
|
7a9aeca248 | ||
|
|
bd5cdefea9 | ||
|
|
a265a450f9 | ||
|
|
5fbb0636aa | ||
|
|
6eb22da201 | ||
|
|
781b4d0c57 | ||
|
|
5234fca96d | ||
|
|
8daedccaea | ||
|
|
886e65d7ac | ||
|
|
ec502cef20 | ||
|
|
f3ff515271 | ||
|
|
d662eb1cbc | ||
|
|
c40b73186b | ||
|
|
6734af6742 | ||
|
|
c5ec2a552d | ||
|
|
a3e3a32332 | ||
|
|
8c3756c4f7 | ||
|
|
c472225f9c | ||
|
|
7a8538a87a | ||
|
|
dba37a3f23 | ||
|
|
e89cfe0aef | ||
|
|
9c1993e5a7 | ||
|
|
d586014379 | ||
|
|
3a441487a3 | ||
|
|
6f6a4c481e | ||
|
|
56f0cc81c9 | ||
|
|
6c58d4cc01 | ||
|
|
a1e47542e7 | ||
|
|
eff958d4c1 | ||
|
|
81704c6534 | ||
|
|
1e229949fc | ||
|
|
28a93e949e | ||
|
|
40ad38bc2a | ||
|
|
e125c6b7e2 | ||
|
|
5596c4530d | ||
|
|
d81fe19836 | ||
|
|
d6838ec947 | ||
|
|
b36a69aa5f | ||
|
|
831b757bb1 | ||
|
|
527fc5785b | ||
|
|
8c8055d381 | ||
|
|
b658c19c03 | ||
|
|
85976e199f | ||
|
|
f6a392e118 | ||
|
|
539fcae745 | ||
|
|
29f1a3d2a6 | ||
|
|
01f139b6a4 | ||
|
|
c61980721e | ||
|
|
471a1ebff1 | ||
|
|
b8d9ff0971 | ||
|
|
e02d836c12 | ||
|
|
abd47eb269 | ||
|
|
5219fd8f6c | ||
|
|
588fc38f81 | ||
|
|
e3aa8a5d12 | ||
|
|
3255c0b6eb | ||
|
|
d2dbd88f25 | ||
|
|
ff824cfa20 | ||
|
|
43303e770a | ||
|
|
cfadbca32a | ||
|
|
e7ca4a5325 | ||
|
|
7bab1eb7fd | ||
|
|
072e39da32 | ||
|
|
ec7e84ac45 | ||
|
|
4228a63ad1 | ||
|
|
6093e6f322 | ||
|
|
ee103a99f6 | ||
|
|
c34065beab | ||
|
|
d9e1f3ad5d | ||
|
|
8a8290587a | ||
|
|
162aa0d458 | ||
|
|
0fb37c45b5 | ||
|
|
0c2ce44742 | ||
|
|
f089157443 | ||
|
|
e192dacdfb | ||
|
|
8418652de0 | ||
|
|
1d8ac35660 | ||
|
|
913cd2ee3a | ||
|
|
6adaa6c4f6 | ||
|
|
08dbb8c298 | ||
|
|
e7bc0e113c | ||
|
|
6d2c926b0e | ||
|
|
60e15cb569 | ||
|
|
22f61d3032 | ||
|
|
5d2a726aec | ||
|
|
192322a982 | ||
|
|
ddf5d803bd | ||
|
|
02fb6d468a | ||
|
|
e7d50c247d | ||
|
|
85cfb4b4b7 | ||
|
|
0684c577ac | ||
|
|
32778edc74 | ||
|
|
1e6780afc1 | ||
|
|
ef4e004141 | ||
|
|
72c5a42feb | ||
|
|
271e01a02c | ||
|
|
d47549d68f | ||
|
|
01687c7f3e | ||
|
|
85cb7ffdb1 | ||
|
|
0367037f0a | ||
|
|
6669a2e1ec | ||
|
|
eb36c1e493 | ||
|
|
8f5faf0f6a | ||
|
|
5fad0ea04f | ||
|
|
4558f8affb | ||
|
|
7be27614da | ||
|
|
7118d6bf03 | ||
|
|
eb84ddf500 | ||
|
|
032109756d | ||
|
|
9e230302e9 | ||
|
|
4708fec201 | ||
|
|
d102d6acbb | ||
|
|
bc67883579 | ||
|
|
069d6ff2f4 | ||
|
|
6fbf4d81f0 | ||
|
|
3d51acd613 | ||
|
|
d2fb576ecc | ||
|
|
d658901231 | ||
|
|
76d1ca7bdf | ||
|
|
341977b227 | ||
|
|
75872dc2f5 | ||
|
|
b609537a52 | ||
|
|
1469d1e157 | ||
|
|
111b7d04f2 | ||
|
|
9e297df1c7 | ||
|
|
7babb48751 | ||
|
|
dfaffacbb5 | ||
|
|
769779cf21 | ||
|
|
9d8a5af44a | ||
|
|
8a84acca7b | ||
|
|
b551f90d38 | ||
|
|
789a9cc0aa | ||
|
|
13e35338af | ||
|
|
281a003dd7 | ||
|
|
e40df7e1b8 | ||
|
|
bb2b1e6034 | ||
|
|
f8cac19330 | ||
|
|
52fe79c343 | ||
|
|
0b696b95b6 | ||
|
|
63bc903f83 | ||
|
|
b166d0daea | ||
|
|
6914dae822 | ||
|
|
c5fb53d725 | ||
|
|
d36d20da08 | ||
|
|
502281f4d3 | ||
|
|
daa4f19c57 | ||
|
|
02f726f43c | ||
|
|
b9e8186159 | ||
|
|
85baadd5df | ||
|
|
ab871ec9bb | ||
|
|
753928f4da | ||
|
|
fe84bada33 | ||
|
|
5b8d6ed9c5 | ||
|
|
2ad2fdfb0f | ||
|
|
a10558a044 | ||
|
|
7316d05c22 | ||
|
|
3177db55b8 | ||
|
|
a6a63f9553 | ||
|
|
df0eb9ee2f | ||
|
|
e3cda3ea49 |
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -42,9 +42,9 @@ Please replace this sentence with log output, if applicable.
|
||||
<!-- Please complete the following information: -->
|
||||
|
||||
- Operating system (e.g. MacOS Monterey).
|
||||
- Java version (i.e. `java --version`, e.g. `17.0.10`).
|
||||
- Error Prone version (e.g. `2.25.0`).
|
||||
- Error Prone Support version (e.g. `0.15.0`).
|
||||
- Java version (i.e. `java --version`, e.g. `17.0.13`).
|
||||
- Error Prone version (e.g. `2.35.1`).
|
||||
- Error Prone Support version (e.g. `0.19.0`).
|
||||
|
||||
### Additional context
|
||||
|
||||
|
||||
8
.github/release.yml
vendored
8
.github/release.yml
vendored
@@ -3,16 +3,16 @@ changelog:
|
||||
labels:
|
||||
- "ignore-changelog"
|
||||
categories:
|
||||
- title: ":warning: Update considerations and deprecations"
|
||||
labels:
|
||||
- "breaking change"
|
||||
- "deprecation"
|
||||
- title: ":rocket: New Error Prone checks and Refaster rules"
|
||||
labels:
|
||||
- "new feature"
|
||||
- title: ":sparkles: Improvements"
|
||||
labels:
|
||||
- "improvement"
|
||||
- title: ":warning: Update considerations and deprecations"
|
||||
labels:
|
||||
- "breaking change"
|
||||
- "deprecation"
|
||||
- title: ":bug: Bug fixes"
|
||||
labels:
|
||||
- "bug"
|
||||
|
||||
18
.github/workflows/build.yml
vendored
18
.github/workflows/build.yml
vendored
@@ -9,30 +9,32 @@ jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-22.04 ]
|
||||
jdk: [ 17.0.10, 21.0.2 ]
|
||||
os: [ ubuntu-24.04 ]
|
||||
jdk: [ 17.0.13, 21.0.5, 23.0.1 ]
|
||||
distribution: [ temurin ]
|
||||
experimental: [ false ]
|
||||
include:
|
||||
- os: macos-14
|
||||
jdk: 17.0.10
|
||||
jdk: 17.0.13
|
||||
distribution: temurin
|
||||
experimental: false
|
||||
- os: windows-2022
|
||||
jdk: 17.0.10
|
||||
jdk: 17.0.13
|
||||
distribution: temurin
|
||||
experimental: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.experimental }}
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
github.com:443
|
||||
jitpack.io:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
# We run the build twice for each supported JDK: once against the
|
||||
# original Error Prone release, using only Error Prone checks available
|
||||
@@ -40,11 +42,11 @@ jobs:
|
||||
# additionally enabling all checks defined in this project and any Error
|
||||
# Prone checks available only from other artifact repositories.
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
|
||||
with:
|
||||
java-version: ${{ matrix.jdk }}
|
||||
java-distribution: ${{ matrix.distribution }}
|
||||
maven-version: 3.9.6
|
||||
maven-version: 3.9.9
|
||||
- name: Display build environment details
|
||||
run: mvn --version
|
||||
- name: Build project against vanilla Error Prone, compile Javadoc
|
||||
@@ -52,6 +54,6 @@ jobs:
|
||||
- name: Build project with self-check against Error Prone fork
|
||||
run: mvn -T1C clean verify -Perror-prone-fork -Pnon-maven-central -Pself-check -s settings.xml
|
||||
- name: Remove installed project artifacts
|
||||
run: mvn build-helper:remove-project-artifact
|
||||
run: mvn dependency:purge-local-repository -DmanualInclude='${project.groupId}' -DresolutionFuzziness=groupId
|
||||
|
||||
# XXX: Enable Codecov once we "go public".
|
||||
|
||||
15
.github/workflows/codeql.yml
vendored
15
.github/workflows/codeql.yml
vendored
@@ -19,33 +19,34 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
api.github.com:443
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
uploads.github.com:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
|
||||
with:
|
||||
java-version: 17.0.10
|
||||
java-version: 17.0.13
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
maven-version: 3.9.9
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
|
||||
uses: github/codeql-action/init@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Perform minimal build
|
||||
if: matrix.language == 'java'
|
||||
run: mvn -T1C clean package -DskipTests -Dverification.skip
|
||||
- name: Perform CodeQL analysis
|
||||
uses: github/codeql-action/analyze@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
|
||||
uses: github/codeql-action/analyze@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
|
||||
with:
|
||||
category: /language:${{ matrix.language }}
|
||||
|
||||
16
.github/workflows/deploy-website.yml
vendored
16
.github/workflows/deploy-website.yml
vendored
@@ -9,10 +9,10 @@ concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -39,15 +39,15 @@ jobs:
|
||||
www.youtube.com:443
|
||||
youtrack.jetbrains.com:443
|
||||
- name: Check out code
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 # v1.172.0
|
||||
- uses: ruby/setup-ruby@a2bbe5b1b236842c1cb7dd11e8e3b51e0a616acc # v1.202.0
|
||||
with:
|
||||
working-directory: ./website
|
||||
bundler-cache: true
|
||||
- name: Configure Github Pages
|
||||
uses: actions/configure-pages@1f0c5cde4bc74cd7e1254d0cb4de8d49e9068c7d # v4.0.0
|
||||
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0
|
||||
- name: Generate documentation
|
||||
run: ./generate-docs.sh
|
||||
- name: Build website with Jekyll
|
||||
@@ -68,13 +68,13 @@ jobs:
|
||||
permissions:
|
||||
id-token: write
|
||||
pages: write
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -82,4 +82,4 @@ jobs:
|
||||
api.github.com:443
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@decdde0ac072f6dcbe43649d82d9c635fff5b4e4 # v4.0.4
|
||||
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5
|
||||
|
||||
18
.github/workflows/openssf-scorecard.yml
vendored
18
.github/workflows/openssf-scorecard.yml
vendored
@@ -18,34 +18,36 @@ jobs:
|
||||
contents: read
|
||||
security-events: write
|
||||
id-token: write
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.deps.dev:443
|
||||
api.github.com:443
|
||||
api.osv.dev:443
|
||||
api.scorecard.dev:443
|
||||
api.securityscorecards.dev:443
|
||||
fulcio.sigstore.dev:443
|
||||
github.com:443
|
||||
index.docker.io:443
|
||||
oss-fuzz-build-logs.storage.googleapis.com:443
|
||||
rekor.sigstore.dev:443
|
||||
tuf-repo-cdn.sigstore.dev:443
|
||||
repo.maven.apache.org:443
|
||||
*.sigstore.dev:443
|
||||
www.bestpractices.dev:443
|
||||
- name: Check out code
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run OpenSSF Scorecard analysis
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
|
||||
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
publish_results: ${{ github.ref == 'refs/heads/master' }}
|
||||
- name: Update GitHub's code scanning dashboard
|
||||
uses: github/codeql-action/upload-sarif@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
|
||||
uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
14
.github/workflows/pitest-analyze-pr.yml
vendored
14
.github/workflows/pitest-analyze-pr.yml
vendored
@@ -9,23 +9,25 @@ permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
analyze-pr:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
|
||||
with:
|
||||
checkout-fetch-depth: 2
|
||||
java-version: 17.0.10
|
||||
java-version: 17.0.13
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
maven-version: 3.9.9
|
||||
- name: Run Pitest
|
||||
# By running with features `+GIT(from[HEAD~1]), +gitci`, Pitest only
|
||||
# analyzes lines changed in the associated pull request, as GitHub
|
||||
@@ -36,7 +38,7 @@ jobs:
|
||||
- name: Aggregate Pitest reports
|
||||
run: mvn pitest-git:aggregate -DkilledEmoji=":tada:" -DmutantEmoji=":zombie:" -DtrailingText="Mutation testing report by [Pitest](https://pitest.org/). Review any surviving mutants by inspecting the line comments under [_Files changed_](${{ github.event.number }}/files)."
|
||||
- name: Upload Pitest reports as artifact
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
|
||||
with:
|
||||
name: pitest-reports
|
||||
path: ./target/pit-reports-ci
|
||||
|
||||
14
.github/workflows/pitest-update-pr.yml
vendored
14
.github/workflows/pitest-update-pr.yml
vendored
@@ -17,25 +17,27 @@ jobs:
|
||||
checks: write
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
api.adoptium.net:443
|
||||
api.github.com:443
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
|
||||
with:
|
||||
java-version: 17.0.10
|
||||
java-version: 17.0.13
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
maven-version: 3.9.9
|
||||
- name: Download Pitest analysis artifact
|
||||
uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2
|
||||
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
|
||||
with:
|
||||
workflow: ${{ github.event.workflow_run.workflow_id }}
|
||||
name: pitest-reports
|
||||
|
||||
38
.github/workflows/run-integration-tests.yml
vendored
38
.github/workflows/run-integration-tests.yml
vendored
@@ -1,9 +1,9 @@
|
||||
# If requested by means of a pull request comment, runs integration tests
|
||||
# against the project, using the code found on the pull request branch.
|
||||
# XXX: Generalize this to a matrix build of multiple integration tests,
|
||||
# possibly using multiple JDK or OS versions.
|
||||
# XXX: Investigate whether the comment can specify which integration tests run
|
||||
# run. See this example of a dynamic build matrix:
|
||||
# XXX: Review whether then build matrix should also vary JDK or OS versions.
|
||||
# XXX: Support `/integration-test [name...]` comment syntax to specify the
|
||||
# subset of integration tests to run.
|
||||
# See this example of a dynamic build matrix:
|
||||
# https://docs.github.com/en/actions/learn-github-actions/expressions#example-returning-a-json-object
|
||||
name: "Integration tests"
|
||||
on:
|
||||
@@ -16,36 +16,48 @@ jobs:
|
||||
name: On-demand integration test
|
||||
if: |
|
||||
github.event.issue.pull_request && contains(github.event.comment.body, '/integration-test')
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
integration-test: [ "checkstyle", "metrics", "prometheus-java-client" ]
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
# XXX: After updating the validation build flags in
|
||||
# `integration-tests/prometheus-java-client.sh`, review whether the
|
||||
# Docker domains specified here can be dropped.
|
||||
api.adoptium.net:443
|
||||
auth.docker.io:443
|
||||
checkstyle.org:443
|
||||
example.com:80
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
oss.sonatype.org:443
|
||||
production.cloudflare.docker.com:443
|
||||
raw.githubusercontent.com:443
|
||||
registry-1.docker.io:443
|
||||
repo.maven.apache.org:443
|
||||
repository.sonatype.org:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
|
||||
with:
|
||||
checkout-ref: "refs/pull/${{ github.event.issue.number }}/head"
|
||||
java-version: 17.0.10
|
||||
java-version: 17.0.13
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
maven-version: 3.9.9
|
||||
- name: Install project to local Maven repository
|
||||
run: mvn -T1C install -DskipTests -Dverification.skip
|
||||
- name: Run integration test
|
||||
run: xvfb-run ./integration-tests/checkstyle.sh "${{ runner.temp }}/artifacts"
|
||||
run: xvfb-run "./integration-tests/${{ matrix.integration-test }}.sh" "${{ runner.temp }}/artifacts"
|
||||
- name: Upload artifacts on failure
|
||||
if: ${{ failure() }}
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
|
||||
with:
|
||||
name: integration-test-checkstyle
|
||||
name: "integration-test-${{ matrix.integration-test }}"
|
||||
path: "${{ runner.temp }}/artifacts"
|
||||
- name: Remove installed project artifacts
|
||||
run: mvn build-helper:remove-project-artifact
|
||||
run: mvn dependency:purge-local-repository -DmanualInclude='${project.groupId}' -DresolutionFuzziness=groupId
|
||||
|
||||
16
.github/workflows/sonarcloud.yml
vendored
16
.github/workflows/sonarcloud.yml
vendored
@@ -16,27 +16,31 @@ jobs:
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
allowed-endpoints: >
|
||||
analysis-sensorcache-eu-central-1-prod.s3.amazonaws.com:443
|
||||
api.adoptium.net:443
|
||||
api.nuget.org:443
|
||||
ea6ne4j2sb.execute-api.eu-central-1.amazonaws.com:443
|
||||
github.com:443
|
||||
objects.githubusercontent.com:443
|
||||
repo.maven.apache.org:443
|
||||
sc-cleancode-sensorcache-eu-central-1-prod.s3.amazonaws.com:443
|
||||
scanner.sonarcloud.io:443
|
||||
*.sonarcloud.io:443
|
||||
sonarcloud.io:443
|
||||
- name: Check out code and set up JDK and Maven
|
||||
uses: s4u/setup-maven-action@6d44c18d67d9e1549907b8815efa5e4dada1801b # v1.12.0
|
||||
uses: s4u/setup-maven-action@9a27433d289dd99d73851f653607c39d3444e8ba # v1.17.0
|
||||
with:
|
||||
checkout-fetch-depth: 0
|
||||
java-version: 17.0.10
|
||||
java-version: 17.0.13
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
maven-version: 3.9.9
|
||||
- name: Create missing `test` directory
|
||||
# XXX: Drop this step in favour of actually having a test.
|
||||
run: mkdir refaster-compiler/src/test
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,6 +4,7 @@
|
||||
.DS_Store
|
||||
.factorypath
|
||||
.idea
|
||||
!.idea/icon.svg
|
||||
.project
|
||||
.settings
|
||||
target
|
||||
|
||||
65
.idea/icon.svg
generated
Normal file
65
.idea/icon.svg
generated
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 1259 1199" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1,0,0,1,-624.154,-988.431)">
|
||||
<g transform="matrix(1,0,0,1,-70.1122,-35.0561)">
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1227.03,1988.79C1237.78,2070.45 1225.83,2190.1 1192.24,2194.53C1158.65,2198.95 1116.14,2086.46 1105.39,2004.81C1094.64,1923.16 1128.44,1902.11 1153.32,1898.84C1178.18,1895.56 1216.28,1907.14 1227.03,1988.79Z" style="fill:rgb(219,220,211);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1151.08,1881.86C1134.93,1883.99 1114.77,1892.69 1101.6,1913.17C1088.42,1933.64 1082.71,1963.73 1088.42,2007.04C1094.04,2049.75 1107.59,2099.16 1124.51,2138.68C1132.97,2158.45 1142.15,2175.68 1152.59,2188.86C1163.04,2202.05 1176.31,2213.89 1194.48,2211.5C1212.65,2209.11 1222.39,2194.23 1229.07,2178.8C1235.75,2163.36 1240.15,2144.34 1243.21,2123.05C1249.32,2080.5 1249.63,2029.27 1244,1986.56C1238.3,1943.24 1225,1915.66 1206.98,1899.29C1188.95,1882.93 1167.22,1879.74 1151.08,1881.86ZM1155.55,1915.81C1164.27,1914.66 1174.03,1915.62 1183.96,1924.64C1193.89,1933.66 1205.01,1952.69 1210.06,1991.03C1215.18,2029.97 1214.89,2079.4 1209.32,2118.19C1206.53,2137.58 1202.32,2154.4 1197.65,2165.2C1194.14,2173.29 1190.82,2176.3 1189.96,2177.22C1188.89,2176.55 1184.91,2174.51 1179.43,2167.6C1172.12,2158.38 1163.7,2143.22 1155.99,2125.21C1140.57,2089.18 1127.49,2041.51 1122.36,2002.57C1117.32,1964.24 1123.13,1942.97 1130.39,1931.69C1137.65,1920.42 1146.82,1916.96 1155.55,1915.81Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1516.33,1963.1C1466.19,1897.75 1427.4,1906.77 1407.5,1922.05C1387.59,1937.32 1368.84,1972.45 1418.98,2037.8C1431.75,2054.44 1447.26,2071.84 1463.69,2088.19C1495.18,2119.52 1534.33,2139.39 1582.98,2126.14C1606.4,2119.76 1622.19,2110.46 1623.75,2098.64C1625.79,2083.16 1603,2065.78 1569.69,2050.47C1554.75,2019.83 1535.59,1988.2 1516.33,1963.1Z" style="fill:rgb(219,220,211);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1397.07,1908.46C1409.99,1898.55 1430.41,1890.44 1454.2,1895.61C1478,1900.77 1503.31,1918 1529.91,1952.67C1548.92,1977.44 1567.3,2007.65 1582.28,2037.56C1597.47,2044.87 1610.74,2052.64 1621.09,2061.47C1632.68,2071.35 1642.93,2084.12 1640.73,2100.88C1639.05,2113.64 1630.31,2122.66 1620.9,2128.78C1611.49,2134.9 1600.29,2139.17 1587.48,2142.66C1532.39,2157.66 1485.57,2134.11 1451.61,2100.32C1434.7,2083.49 1418.73,2065.6 1405.39,2048.22C1378.79,2013.56 1368.69,1984.64 1369.86,1960.32C1371.04,1936 1384.15,1918.38 1397.07,1908.46ZM1417.92,1935.63C1410.94,1940.99 1404.71,1948.57 1404.07,1961.97C1403.43,1975.37 1409.02,1996.69 1432.56,2027.38C1444.76,2043.27 1459.82,2060.18 1475.77,2076.05C1504.8,2104.93 1536.26,2121.12 1578.48,2109.62C1589.1,2106.73 1597.5,2103.16 1602.23,2100.08C1605.14,2098.18 1606.16,2096.97 1606.54,2096.46C1606.07,2095.66 1604.57,2092.39 1598.86,2087.52C1591.24,2081.02 1578.31,2073.28 1562.54,2066.03L1556.98,2063.47L1554.29,2057.97C1539.86,2028.35 1521.12,1997.46 1502.75,1973.52C1479.2,1942.84 1460.05,1931.91 1446.94,1929.07C1433.84,1926.23 1424.9,1930.27 1417.92,1935.63Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M917.121,1633.14C845.801,1674.32 730.68,1709.07 713.738,1679.73C696.797,1650.39 784.453,1568.07 855.777,1526.89C927.102,1485.71 959.48,1508.89 972.02,1530.62C984.562,1552.34 988.445,1591.97 917.121,1633.14Z" style="fill:rgb(219,220,211);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M986.848,1522.06C978.707,1507.95 962.949,1492.66 938.992,1488.32C915.031,1483.98 885.055,1490.22 847.219,1512.07C809.906,1533.61 769.453,1565.03 739.41,1595.79C724.391,1611.17 711.977,1626.24 703.797,1640.94C695.617,1655.64 689.746,1672.42 698.914,1688.29C708.078,1704.17 725.547,1707.48 742.363,1707.74C759.184,1708.01 778.445,1704.79 799.273,1699.47C840.934,1688.83 888.375,1669.51 925.684,1647.97C963.52,1626.12 983.91,1603.29 992.137,1580.37C1000.36,1557.45 994.988,1536.16 986.848,1522.06ZM957.195,1539.18C961.594,1546.79 964.438,1556.18 959.906,1568.8C955.379,1581.43 942.047,1598.98 908.562,1618.32C874.551,1637.96 828.77,1656.6 790.801,1666.3C771.816,1671.14 754.664,1673.69 742.902,1673.5C734.082,1673.37 730.035,1671.45 728.859,1671C729.062,1669.76 729.426,1665.3 733.715,1657.59C739.434,1647.31 750.215,1633.73 763.906,1619.72C791.285,1591.68 830.324,1561.36 864.336,1541.72C897.824,1522.38 919.695,1519.62 932.895,1522.01C946.09,1524.4 952.797,1531.56 957.195,1539.18Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1791.57,1526.89C1862.89,1568.07 1950.54,1650.39 1933.61,1679.74C1916.66,1709.08 1801.54,1674.33 1730.22,1633.15C1658.9,1591.97 1662.78,1552.34 1675.32,1530.62C1687.86,1508.89 1720.24,1485.72 1791.57,1526.89Z" style="fill:rgb(219,220,211);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1660.5,1522.06C1652.35,1536.16 1646.98,1557.45 1655.21,1580.37C1663.43,1603.29 1683.82,1626.13 1721.66,1647.97C1758.97,1669.52 1806.41,1688.84 1848.07,1699.48C1868.9,1704.79 1888.16,1708.01 1904.98,1707.75C1921.79,1707.48 1939.27,1704.17 1948.43,1688.3C1957.59,1672.42 1951.73,1655.64 1943.55,1640.94C1935.37,1626.25 1922.95,1611.17 1907.93,1595.79C1877.89,1565.04 1837.43,1533.61 1800.12,1512.07C1762.29,1490.22 1732.31,1483.98 1708.35,1488.32C1684.39,1492.66 1668.64,1507.95 1660.5,1522.06ZM1690.15,1539.18C1694.55,1531.56 1701.25,1524.4 1714.45,1522.02C1727.64,1519.62 1749.52,1522.39 1783,1541.72C1817.02,1561.36 1856.06,1591.68 1883.44,1619.72C1897.12,1633.73 1907.91,1647.32 1913.63,1657.59C1917.92,1665.3 1918.28,1669.77 1918.48,1671.01C1917.31,1671.45 1913.26,1673.37 1904.44,1673.51C1892.68,1673.69 1875.52,1671.15 1856.54,1666.3C1818.57,1656.61 1772.79,1637.96 1738.78,1618.32C1705.29,1598.99 1691.97,1581.43 1687.43,1568.81C1682.91,1556.18 1685.75,1546.8 1690.15,1539.18Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1322.81,1013.67C1058.16,1014.17 843.293,1229.45 843.297,1494.11L843.223,1862.19C843.223,1955.32 919.055,2031.16 1012.19,2031.16C1054.55,2031.16 1093.39,2015.51 1123.09,1989.7C1169.54,2049.44 1242.17,2087.79 1323.7,2087.79C1405.22,2087.79 1477.84,2049.45 1524.28,1989.73C1553.98,2015.52 1592.81,2031.16 1635.15,2031.16C1728.29,2031.16 1804.12,1955.32 1804.12,1862.19L1804.12,1494.1C1804.12,1229.09 1588.7,1013.67 1323.69,1013.67L1322.84,1013.67L1322.81,1013.67ZM1322.92,1068.46L1323.69,1068.46C1559.09,1068.46 1749.33,1258.7 1749.33,1494.11L1749.33,1862.19C1749.33,1925.92 1698.88,1976.37 1635.15,1976.37C1596.91,1976.37 1563.67,1958.03 1542.94,1929.68L1517.91,1895.48L1497,1932.34C1462.85,1992.53 1398.48,2033 1323.7,2033C1248.9,2033 1184.52,1992.51 1150.38,1932.3L1129.45,1895.41L1104.43,1929.65C1083.69,1958.02 1050.44,1976.37 1012.19,1976.37C948.461,1976.37 898.016,1925.93 898.012,1862.2L898.086,1494.11C898.086,1259.03 1087.84,1068.92 1322.92,1068.47L1322.92,1068.46Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1322.86,1041.07C1072.99,1041.54 870.684,1244.23 870.688,1494.11L870.648,1862.19C870.648,1940.62 933.789,2003.77 1012.22,2003.77C1073.65,2003.77 1125.69,1965.03 1145.37,1910.56C1201.73,1934.69 1262.41,1947.14 1323.72,1947.14C1385.02,1947.14 1445.69,1934.69 1502.04,1910.57C1521.72,1965.04 1573.76,2003.77 1635.19,2003.77C1713.62,2003.77 1776.76,1940.62 1776.76,1862.19L1776.76,1494.11C1776.76,1243.9 1573.93,1041.07 1323.72,1041.07L1322.86,1041.07Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1323.7,1494.1C1449.2,1494.1 1550.24,1595.14 1550.24,1720.64L1550.24,1833.86C1550.24,1959.36 1449.2,2060.4 1323.7,2060.4C1198.2,2060.4 1097.16,1959.36 1097.16,1833.86L1097.16,1720.64C1097.16,1595.14 1198.2,1494.1 1323.7,1494.1Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1322.86,1041.07C1262.14,1041.18 1204.25,1053.27 1151.36,1075.05C1316.07,1142.87 1432.03,1304.93 1432.03,1494.11L1432.03,1811.95C1432.03,2003.63 1209.62,2024.85 1126.54,1945.82C1177.52,2034.1 1254.55,2060.4 1323.7,2060.4C1408.4,2060.4 1481.95,2014.37 1520.82,1945.86C1546.53,1981.01 1588.08,2003.77 1635.15,2003.77C1713.58,2003.77 1776.72,1940.62 1776.72,1862.19L1776.72,1494.11C1776.72,1243.9 1573.89,1041.07 1323.68,1041.07L1322.86,1041.07Z" style="fill:rgb(219,220,211);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1322.86,1041.07C1304.33,1041.1 1286.06,1042.28 1268.11,1044.48C1492.04,1071.93 1665.46,1262.75 1665.46,1494.11L1665.46,1862.19C1665.46,1920.85 1630.14,1970.94 1579.54,1992.48C1596.59,1999.74 1615.38,2003.77 1635.15,2003.77C1713.58,2003.77 1776.72,1940.62 1776.72,1862.19L1776.72,1494.11C1776.72,1243.9 1573.89,1041.07 1323.68,1041.07L1322.86,1041.07Z" style="fill:rgb(189,191,175);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1322.85,1034.22C1069.29,1034.69 863.84,1240.54 863.84,1494.11L863.766,1862.19C863.766,1944.3 930.078,2010.61 1012.19,2010.61C1057.88,2010.61 1098.53,1989.94 1125.71,1957.58C1166.88,2023.5 1240.02,2067.25 1323.7,2067.25C1407.36,2067.25 1480.48,2023.52 1521.66,1957.62C1548.84,1989.96 1589.47,2010.61 1635.15,2010.61C1717.25,2010.61 1783.57,1944.3 1783.57,1862.19L1783.57,1494.11C1783.57,1240.2 1577.59,1034.21 1323.68,1034.22L1322.85,1034.22ZM1322.86,1047.92L1323.68,1047.92C1570.19,1047.92 1769.87,1247.6 1769.87,1494.11L1769.87,1862.19C1769.87,1936.95 1709.91,1996.92 1635.15,1996.92C1590.29,1996.92 1550.82,1975.26 1526.36,1941.82L1520.1,1933.27L1514.87,1942.48C1477.18,2008.91 1405.92,2053.55 1323.7,2053.55C1241.46,2053.55 1170.19,2008.89 1132.5,1942.44L1127.27,1933.21L1121.02,1941.77C1096.56,1975.24 1057.07,1996.92 1012.19,1996.92C937.43,1996.92 877.469,1936.95 877.465,1862.19L877.539,1494.11C877.539,1247.94 1076.7,1048.39 1322.86,1047.92Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1576.29,1470.72C1576.29,1481.36 1568.75,1491.56 1555.31,1499.08C1541.88,1506.6 1523.67,1510.83 1504.68,1510.83C1465.12,1510.83 1433.06,1492.87 1433.06,1470.72C1433.06,1448.57 1465.12,1430.62 1504.68,1430.62C1523.67,1430.62 1541.88,1434.84 1555.31,1442.36C1568.75,1449.89 1576.29,1460.09 1576.29,1470.72Z" style="fill:rgb(255,155,173);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1214.28,1470.72C1214.28,1481.36 1206.73,1491.56 1193.31,1499.08C1179.87,1506.6 1161.66,1510.83 1142.66,1510.83C1103.11,1510.83 1071.05,1492.87 1071.05,1470.72C1071.05,1448.57 1103.11,1430.62 1142.66,1430.62C1161.66,1430.62 1179.87,1434.84 1193.31,1442.36C1206.73,1449.89 1214.28,1460.09 1214.28,1470.72Z" style="fill:rgb(255,155,173);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1104.39,1401.46C1104.39,1375.15 1118.45,1350.79 1141.24,1337.63C1164.03,1324.48 1192.16,1324.48 1214.95,1337.63C1237.74,1350.79 1251.81,1375.15 1251.81,1401.46L1224.41,1401.46C1224.41,1384.9 1215.6,1369.64 1201.25,1361.36C1186.9,1353.07 1169.29,1353.07 1154.94,1361.36C1140.59,1369.64 1131.78,1384.9 1131.78,1401.46L1104.39,1401.46Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1395.54,1401.46C1395.54,1375.15 1409.61,1350.79 1432.39,1337.63C1455.18,1324.48 1483.32,1324.48 1506.11,1337.63C1528.89,1350.79 1542.96,1375.15 1542.96,1401.46L1515.56,1401.46C1515.56,1384.9 1506.75,1369.64 1492.41,1361.36C1478.06,1353.07 1460.44,1353.07 1446.09,1361.36C1431.74,1369.64 1422.93,1384.9 1422.93,1401.46L1395.54,1401.46Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,9.81959)">
|
||||
<path d="M1256.81,1448.61C1256.81,1472.48 1269.56,1494.57 1290.24,1506.51C1310.92,1518.45 1336.42,1518.45 1357.1,1506.51C1377.78,1494.57 1390.53,1472.48 1390.53,1448.61L1376.83,1448.61C1376.83,1467.61 1366.71,1485.15 1350.25,1494.65C1333.79,1504.15 1313.55,1504.15 1297.09,1494.65C1280.63,1485.15 1270.51,1467.61 1270.51,1448.61L1256.81,1448.61Z" style="fill:rgb(26,26,26);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 13 KiB |
@@ -3,16 +3,29 @@
|
||||
"extends": [
|
||||
"helpers:pinGitHubActionDigests"
|
||||
],
|
||||
"customManagers": [
|
||||
{
|
||||
"customType": "regex",
|
||||
"fileMatch": [
|
||||
"^integration-tests/.*(-init\\.patch|\\.sh)$"
|
||||
],
|
||||
"matchStrings": [
|
||||
"\\b(?<packageName>[a-z0-9_.-]+?:[a-z0-9_.-]+?):(?<currentValue>[^:]+?):[a-zA-Z0-9_-]+\\b",
|
||||
"<version>(?<currentValue>.*?)<!-- Renovate: (?<packageName>.*?) --></version>"
|
||||
],
|
||||
"datasourceTemplate": "maven"
|
||||
}
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchPackagePatterns": [
|
||||
"^org\\.springframework:spring-framework-bom$",
|
||||
"^org\\.springframework\\.boot:spring-boot[a-z-]*$"
|
||||
"matchPackageNames": [
|
||||
"/^org\\.springframework:spring-framework-bom$/",
|
||||
"/^org\\.springframework\\.boot:spring-boot[a-z-]*$/"
|
||||
],
|
||||
"separateMinorPatch": true
|
||||
},
|
||||
{
|
||||
"matchDepNames": [
|
||||
"matchPackageNames": [
|
||||
"dawidd6/action-download-artifact",
|
||||
"github/codeql-action",
|
||||
"ruby/setup-ruby"
|
||||
|
||||
11
README.md
11
README.md
@@ -217,7 +217,7 @@ Other highly relevant commands:
|
||||
- `mvn fmt:format` formats the code using
|
||||
[`google-java-format`][google-java-format].
|
||||
- [`./run-full-build.sh`][script-run-full-build] builds the project twice,
|
||||
where the second pass validates compatbility with Picnic's [Error Prone
|
||||
where the second pass validates compatibility with Picnic's [Error Prone
|
||||
fork][error-prone-fork-repo] and compliance of the code with any rules
|
||||
defined within this project. (Consider running this before [opening a pull
|
||||
request][contributing-pull-request], as the PR checks also perform this
|
||||
@@ -247,6 +247,12 @@ Java Compiler_ and deselect the option _Use '--release' option for
|
||||
cross-compilation (Java 9 and later)_. See [IDEA-288052][idea-288052] for
|
||||
details.
|
||||
|
||||
The `BugChecker` implementations provided by this project are tested using
|
||||
Error Prone's `CompilationTestHelper` and `BugCheckerRefactoringTestHelper`
|
||||
classes. These utilities accept text blocks containing inline Java source code.
|
||||
To ease modification of this inline source code, consider using IntelliJ IDEA's
|
||||
[language injection][idea-language-injection] feature.
|
||||
|
||||
## 💡 How it works
|
||||
|
||||
This project provides additional [`BugChecker`][error-prone-bugchecker]
|
||||
@@ -284,6 +290,7 @@ channel; please see our [security policy][security] for details.
|
||||
[github-actions-build-master]: https://github.com/PicnicSupermarket/error-prone-support/actions/workflows/build.yml?query=branch:master&event=push
|
||||
[google-java-format]: https://github.com/google/google-java-format
|
||||
[idea-288052]: https://youtrack.jetbrains.com/issue/IDEA-288052
|
||||
[idea-language-injection]: https://www.jetbrains.com/help/idea/using-language-injections.html
|
||||
[license-badge]: https://img.shields.io/github/license/PicnicSupermarket/error-prone-support
|
||||
[license]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/LICENSE.md
|
||||
[maven-central-badge]: https://img.shields.io/maven-central/v/tech.picnic.error-prone-support/error-prone-support?color=blue
|
||||
@@ -302,7 +309,7 @@ channel; please see our [security policy][security] for details.
|
||||
[refaster]: https://errorprone.info/docs/refaster
|
||||
[refaster-rules-bigdecimal]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/BigDecimalRules.java
|
||||
[refaster-rules]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/
|
||||
[reproducible-builds-badge]: https://img.shields.io/badge/Reproducible_Builds-ok-success?labelColor=1e5b96
|
||||
[reproducible-builds-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/jvm-repo-rebuild/reproducible-central/master/content/tech/picnic/error-prone-support/error-prone-support/badge.json
|
||||
[reproducible-builds-report]: https://github.com/jvm-repo-rebuild/reproducible-central/blob/master/content/tech/picnic/error-prone-support/error-prone-support/README.md
|
||||
[script-apply-error-prone-suggestions]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/apply-error-prone-suggestions.sh
|
||||
[script-run-branch-mutation-tests]: https://github.com/PicnicSupermarket/error-prone-support/blob/master/run-branch-mutation-tests.sh
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.19.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>documentation-support</artifactId>
|
||||
@@ -33,6 +33,15 @@
|
||||
<artifactId>error_prone_test_helpers</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>error-prone-utils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>refaster-test-support</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
@@ -72,6 +81,11 @@
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jspecify</groupId>
|
||||
<artifactId>jspecify</artifactId>
|
||||
|
||||
@@ -27,7 +27,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.TestCases;
|
||||
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.BugPatternTestCases;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/**
|
||||
* An {@link Extractor} that describes how to extract data from classes that test a {@code
|
||||
@@ -40,7 +41,7 @@ import tech.picnic.errorprone.documentation.BugPatternTestExtractor.TestCases;
|
||||
@Immutable
|
||||
@AutoService(Extractor.class)
|
||||
@SuppressWarnings("rawtypes" /* See https://github.com/google/auto/issues/870. */)
|
||||
public final class BugPatternTestExtractor implements Extractor<TestCases> {
|
||||
public final class BugPatternTestExtractor implements Extractor<BugPatternTestCases> {
|
||||
/** Instantiates a new {@link BugPatternTestExtractor} instance. */
|
||||
public BugPatternTestExtractor() {}
|
||||
|
||||
@@ -50,7 +51,7 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TestCases> tryExtract(ClassTree tree, VisitorState state) {
|
||||
public Optional<BugPatternTestCases> tryExtract(ClassTree tree, VisitorState state) {
|
||||
BugPatternTestCollector collector = new BugPatternTestCollector();
|
||||
|
||||
collector.scan(tree, state);
|
||||
@@ -59,7 +60,7 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
|
||||
.filter(not(ImmutableList::isEmpty))
|
||||
.map(
|
||||
tests ->
|
||||
new AutoValue_BugPatternTestExtractor_TestCases(
|
||||
new AutoValue_BugPatternTestExtractor_BugPatternTestCases(
|
||||
state.getPath().getCompilationUnit().getSourceFile().toUri(),
|
||||
ASTHelpers.getSymbol(tree).className(),
|
||||
tests));
|
||||
@@ -95,10 +96,10 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
|
||||
.onDescendantOf("com.google.errorprone.BugCheckerRefactoringTestHelper.ExpectOutput")
|
||||
.namedAnyOf("addOutputLines", "expectUnchanged");
|
||||
|
||||
private final List<TestCase> collectedTestCases = new ArrayList<>();
|
||||
private final List<BugPatternTestCase> collectedBugPatternTestCases = new ArrayList<>();
|
||||
|
||||
private ImmutableList<TestCase> getCollectedTests() {
|
||||
return ImmutableList.copyOf(collectedTestCases);
|
||||
private ImmutableList<BugPatternTestCase> getCollectedTests() {
|
||||
return ImmutableList.copyOf(collectedBugPatternTestCases);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,14 +111,14 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
|
||||
classUnderTest -> {
|
||||
List<TestEntry> entries = new ArrayList<>();
|
||||
if (isReplacementTest) {
|
||||
extractReplacementTestCases(node, entries, state);
|
||||
extractReplacementBugPatternTestCases(node, entries, state);
|
||||
} else {
|
||||
extractIdentificationTestCases(node, entries, state);
|
||||
extractIdentificationBugPatternTestCases(node, entries, state);
|
||||
}
|
||||
|
||||
if (!entries.isEmpty()) {
|
||||
collectedTestCases.add(
|
||||
new AutoValue_BugPatternTestExtractor_TestCase(
|
||||
collectedBugPatternTestCases.add(
|
||||
new AutoValue_BugPatternTestExtractor_BugPatternTestCase(
|
||||
classUnderTest, ImmutableList.copyOf(entries).reverse()));
|
||||
}
|
||||
});
|
||||
@@ -140,7 +141,7 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
|
||||
: Optional.empty();
|
||||
}
|
||||
|
||||
private static void extractIdentificationTestCases(
|
||||
private static void extractIdentificationBugPatternTestCases(
|
||||
MethodInvocationTree tree, List<TestEntry> sink, VisitorState state) {
|
||||
if (IDENTIFICATION_SOURCE_LINES.matches(tree, state)) {
|
||||
String path = ASTHelpers.constValue(tree.getArguments().get(0), String.class);
|
||||
@@ -155,11 +156,11 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
|
||||
|
||||
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
|
||||
if (receiver instanceof MethodInvocationTree methodInvocation) {
|
||||
extractIdentificationTestCases(methodInvocation, sink, state);
|
||||
extractIdentificationBugPatternTestCases(methodInvocation, sink, state);
|
||||
}
|
||||
}
|
||||
|
||||
private static void extractReplacementTestCases(
|
||||
private static void extractReplacementBugPatternTestCases(
|
||||
MethodInvocationTree tree, List<TestEntry> sink, VisitorState state) {
|
||||
if (REPLACEMENT_OUTPUT_SOURCE_LINES.matches(tree, state)) {
|
||||
/*
|
||||
@@ -185,47 +186,38 @@ public final class BugPatternTestExtractor implements Extractor<TestCases> {
|
||||
|
||||
ExpressionTree receiver = ASTHelpers.getReceiver(tree);
|
||||
if (receiver instanceof MethodInvocationTree methodInvocation) {
|
||||
extractReplacementTestCases(methodInvocation, sink, state);
|
||||
extractReplacementBugPatternTestCases(methodInvocation, sink, state);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: This logic is duplicated in `ErrorProneTestSourceFormat`. Can we do better?
|
||||
private static Optional<String> getSourceCode(MethodInvocationTree tree) {
|
||||
List<? extends ExpressionTree> sourceLines =
|
||||
tree.getArguments().subList(1, tree.getArguments().size());
|
||||
StringBuilder source = new StringBuilder();
|
||||
|
||||
for (ExpressionTree sourceLine : sourceLines) {
|
||||
String value = ASTHelpers.constValue(sourceLine, String.class);
|
||||
if (value == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
source.append(value).append('\n');
|
||||
}
|
||||
|
||||
return Optional.of(source.toString());
|
||||
return SourceCode.joinConstantSourceCodeLines(
|
||||
tree.getArguments().subList(1, tree.getArguments().size()))
|
||||
.map(s -> s + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
@JsonDeserialize(as = AutoValue_BugPatternTestExtractor_TestCases.class)
|
||||
abstract static class TestCases {
|
||||
static TestCases create(URI source, String testClass, ImmutableList<TestCase> testCases) {
|
||||
return new AutoValue_BugPatternTestExtractor_TestCases(source, testClass, testCases);
|
||||
@JsonDeserialize(as = AutoValue_BugPatternTestExtractor_BugPatternTestCases.class)
|
||||
abstract static class BugPatternTestCases {
|
||||
static BugPatternTestCases create(
|
||||
URI source, String testClass, ImmutableList<BugPatternTestCase> testCases) {
|
||||
return new AutoValue_BugPatternTestExtractor_BugPatternTestCases(
|
||||
source, testClass, testCases);
|
||||
}
|
||||
|
||||
abstract URI source();
|
||||
|
||||
abstract String testClass();
|
||||
|
||||
abstract ImmutableList<TestCase> testCases();
|
||||
abstract ImmutableList<BugPatternTestCase> testCases();
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
@JsonDeserialize(as = AutoValue_BugPatternTestExtractor_TestCase.class)
|
||||
abstract static class TestCase {
|
||||
static TestCase create(String classUnderTest, ImmutableList<TestEntry> entries) {
|
||||
return new AutoValue_BugPatternTestExtractor_TestCase(classUnderTest, entries);
|
||||
@JsonDeserialize(as = AutoValue_BugPatternTestExtractor_BugPatternTestCase.class)
|
||||
abstract static class BugPatternTestCase {
|
||||
static BugPatternTestCase create(String classUnderTest, ImmutableList<TestEntry> entries) {
|
||||
return new AutoValue_BugPatternTestExtractor_BugPatternTestCase(classUnderTest, entries);
|
||||
}
|
||||
|
||||
abstract String classUnderTest();
|
||||
|
||||
@@ -14,7 +14,6 @@ import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ServiceLoader;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
@@ -87,6 +86,6 @@ final class DocumentationGeneratorTaskListener implements TaskListener {
|
||||
}
|
||||
|
||||
private static String getSimpleClassName(URI path) {
|
||||
return Paths.get(path).getFileName().toString().replace(".java", "");
|
||||
return Path.of(path).getFileName().toString().replace(".java", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
package tech.picnic.errorprone.documentation;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.VerifyException;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.annotations.FormatMethod;
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import java.net.URI;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
import tech.picnic.errorprone.documentation.RefasterRuleCollectionTestExtractor.RefasterTestCases;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/**
|
||||
* An {@link Extractor} that describes how to extract data from Refaster rule input and output test
|
||||
* classes.
|
||||
*/
|
||||
// XXX: Drop this extractor if/when the Refaster test framework is reimplemented such that tests can
|
||||
// be located alongside rules, rather than in two additional resource files as currently required by
|
||||
// `RefasterRuleCollection`.
|
||||
@Immutable
|
||||
@AutoService(Extractor.class)
|
||||
@SuppressWarnings("rawtypes" /* See https://github.com/google/auto/issues/870. */)
|
||||
public final class RefasterRuleCollectionTestExtractor implements Extractor<RefasterTestCases> {
|
||||
private static final Matcher<ClassTree> IS_REFASTER_RULE_COLLECTION_TEST_CASE =
|
||||
isSubtypeOf("tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase");
|
||||
private static final Pattern TEST_CLASS_NAME_PATTERN = Pattern.compile("(.*)Test");
|
||||
private static final Pattern TEST_CLASS_FILE_NAME_PATTERN =
|
||||
Pattern.compile(".*(Input|Output)\\.java");
|
||||
private static final Pattern TEST_METHOD_NAME_PATTERN = Pattern.compile("test(.*)");
|
||||
private static final String LINE_SEPARATOR = "\n";
|
||||
private static final Splitter LINE_SPLITTER = Splitter.on(LINE_SEPARATOR);
|
||||
|
||||
/** Instantiates a new {@link RefasterRuleCollectionTestExtractor} instance. */
|
||||
public RefasterRuleCollectionTestExtractor() {}
|
||||
|
||||
@Override
|
||||
public String identifier() {
|
||||
return "refaster-rule-collection-test";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<RefasterTestCases> tryExtract(ClassTree tree, VisitorState state) {
|
||||
if (!IS_REFASTER_RULE_COLLECTION_TEST_CASE.matches(tree, state)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
URI sourceFile = state.getPath().getCompilationUnit().getSourceFile().toUri();
|
||||
return Optional.of(
|
||||
RefasterTestCases.create(
|
||||
sourceFile,
|
||||
getRuleCollectionName(tree),
|
||||
isInputFile(sourceFile),
|
||||
getRefasterTestCases(tree, state)));
|
||||
}
|
||||
|
||||
private static String getRuleCollectionName(ClassTree tree) {
|
||||
String className = tree.getSimpleName().toString();
|
||||
|
||||
// XXX: Instead of throwing an error here, it'd be nicer to have a bug checker validate key
|
||||
// aspects of `RefasterRuleCollectionTestCase` subtypes.
|
||||
return tryExtractPatternGroup(className, TEST_CLASS_NAME_PATTERN)
|
||||
.orElseThrow(
|
||||
violation(
|
||||
"Refaster rule collection test class name '%s' does not match '%s'",
|
||||
className, TEST_CLASS_NAME_PATTERN));
|
||||
}
|
||||
|
||||
private static boolean isInputFile(URI sourceFile) {
|
||||
String path = sourceFile.getPath();
|
||||
|
||||
// XXX: Instead of throwing an error here, it'd be nicer to have a bug checker validate key
|
||||
// aspects of `RefasterRuleCollectionTestCase` subtypes.
|
||||
return "Input"
|
||||
.equals(
|
||||
tryExtractPatternGroup(path, TEST_CLASS_FILE_NAME_PATTERN)
|
||||
.orElseThrow(
|
||||
violation(
|
||||
"Refaster rule collection test file name '%s' does not match '%s'",
|
||||
path, TEST_CLASS_FILE_NAME_PATTERN)));
|
||||
}
|
||||
|
||||
private static ImmutableList<RefasterTestCase> getRefasterTestCases(
|
||||
ClassTree tree, VisitorState state) {
|
||||
return tree.getMembers().stream()
|
||||
.filter(MethodTree.class::isInstance)
|
||||
.map(MethodTree.class::cast)
|
||||
.flatMap(m -> tryExtractRefasterTestCase(m, state).stream())
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
private static Optional<RefasterTestCase> tryExtractRefasterTestCase(
|
||||
MethodTree method, VisitorState state) {
|
||||
return tryExtractPatternGroup(method.getName().toString(), TEST_METHOD_NAME_PATTERN)
|
||||
.map(name -> RefasterTestCase.create(name, getFormattedSource(method, state)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source code for the specified method.
|
||||
*
|
||||
* @implNote This operation attempts to trim leading whitespace, such that the start and end of
|
||||
* the method declaration are aligned. The implemented heuristic assumes that the code is
|
||||
* formatted using Google Java Format.
|
||||
*/
|
||||
// XXX: Leading Javadoc and other comments are currently not extracted. Consider fixing this.
|
||||
private static String getFormattedSource(MethodTree method, VisitorState state) {
|
||||
String source = SourceCode.treeToString(method, state);
|
||||
int finalNewline = source.lastIndexOf(LINE_SEPARATOR);
|
||||
if (finalNewline < 0) {
|
||||
return source;
|
||||
}
|
||||
|
||||
int indentation = Math.max(0, source.lastIndexOf(' ') - finalNewline);
|
||||
String prefixToStrip = " ".repeat(indentation);
|
||||
|
||||
return LINE_SPLITTER
|
||||
.splitToStream(source)
|
||||
.map(line -> line.startsWith(prefixToStrip) ? line.substring(indentation) : line)
|
||||
.collect(joining(LINE_SEPARATOR));
|
||||
}
|
||||
|
||||
private static Optional<String> tryExtractPatternGroup(String input, Pattern pattern) {
|
||||
java.util.regex.Matcher matcher = pattern.matcher(input);
|
||||
return matcher.matches() ? Optional.of(matcher.group(1)) : Optional.empty();
|
||||
}
|
||||
|
||||
@FormatMethod
|
||||
private static Supplier<VerifyException> violation(String format, Object... args) {
|
||||
return () -> new VerifyException(String.format(format, args));
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
@JsonDeserialize(as = AutoValue_RefasterRuleCollectionTestExtractor_RefasterTestCases.class)
|
||||
abstract static class RefasterTestCases {
|
||||
static RefasterTestCases create(
|
||||
URI source,
|
||||
String ruleCollection,
|
||||
boolean isInput,
|
||||
ImmutableList<RefasterTestCase> testCases) {
|
||||
return new AutoValue_RefasterRuleCollectionTestExtractor_RefasterTestCases(
|
||||
source, ruleCollection, isInput, testCases);
|
||||
}
|
||||
|
||||
abstract URI source();
|
||||
|
||||
abstract String ruleCollection();
|
||||
|
||||
abstract boolean isInput();
|
||||
|
||||
abstract ImmutableList<RefasterTestCase> testCases();
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
@JsonDeserialize(as = AutoValue_RefasterRuleCollectionTestExtractor_RefasterTestCase.class)
|
||||
abstract static class RefasterTestCase {
|
||||
static RefasterTestCase create(String name, String content) {
|
||||
return new AutoValue_RefasterRuleCollectionTestExtractor_RefasterTestCase(name, content);
|
||||
}
|
||||
|
||||
abstract String name();
|
||||
|
||||
abstract String content();
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,11 @@ final class BugPatternExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerWithoutAnnotation.java",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"public final class TestCheckerWithoutAnnotation extends BugChecker {}");
|
||||
"""
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
public final class TestCheckerWithoutAnnotation extends BugChecker {}
|
||||
""");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
@@ -31,14 +33,16 @@ final class BugPatternExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"MinimalBugChecker.java",
|
||||
"package pkg;",
|
||||
"",
|
||||
"import com.google.errorprone.BugPattern;",
|
||||
"import com.google.errorprone.BugPattern.SeverityLevel;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"@BugPattern(summary = \"MinimalBugChecker summary\", severity = SeverityLevel.ERROR)",
|
||||
"public final class MinimalBugChecker extends BugChecker {}");
|
||||
"""
|
||||
package pkg;
|
||||
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.BugPattern.SeverityLevel;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
@BugPattern(summary = "MinimalBugChecker summary", severity = SeverityLevel.ERROR)
|
||||
public final class MinimalBugChecker extends BugChecker {}
|
||||
""");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
@@ -62,25 +66,27 @@ final class BugPatternExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"CompleteBugChecker.java",
|
||||
"package pkg;",
|
||||
"",
|
||||
"import com.google.errorprone.BugPattern;",
|
||||
"import com.google.errorprone.BugPattern.SeverityLevel;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"",
|
||||
"@BugPattern(",
|
||||
" name = \"OtherName\",",
|
||||
" summary = \"CompleteBugChecker summary\",",
|
||||
" linkType = BugPattern.LinkType.CUSTOM,",
|
||||
" link = \"https://error-prone.picnic.tech\",",
|
||||
" explanation = \"Example explanation\",",
|
||||
" severity = SeverityLevel.SUGGESTION,",
|
||||
" altNames = \"Check\",",
|
||||
" tags = BugPattern.StandardTags.SIMPLIFICATION,",
|
||||
" disableable = false,",
|
||||
" suppressionAnnotations = {BugPattern.class, Test.class})",
|
||||
"public final class CompleteBugChecker extends BugChecker {}");
|
||||
"""
|
||||
package pkg;
|
||||
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.BugPattern.SeverityLevel;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@BugPattern(
|
||||
name = "OtherName",
|
||||
summary = "CompleteBugChecker summary",
|
||||
linkType = BugPattern.LinkType.CUSTOM,
|
||||
link = "https://error-prone.picnic.tech",
|
||||
explanation = "Example explanation",
|
||||
severity = SeverityLevel.SUGGESTION,
|
||||
altNames = "Check",
|
||||
tags = BugPattern.StandardTags.SIMPLIFICATION,
|
||||
disableable = false,
|
||||
suppressionAnnotations = {BugPattern.class, Test.class})
|
||||
public final class CompleteBugChecker extends BugChecker {}
|
||||
""");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
@@ -104,17 +110,19 @@ final class BugPatternExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"UndocumentedSuppressionBugPattern.java",
|
||||
"package pkg;",
|
||||
"",
|
||||
"import com.google.errorprone.BugPattern;",
|
||||
"import com.google.errorprone.BugPattern.SeverityLevel;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"@BugPattern(",
|
||||
" summary = \"UndocumentedSuppressionBugPattern summary\",",
|
||||
" severity = SeverityLevel.WARNING,",
|
||||
" documentSuppression = false)",
|
||||
"public final class UndocumentedSuppressionBugPattern extends BugChecker {}");
|
||||
"""
|
||||
package pkg;
|
||||
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.BugPattern.SeverityLevel;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
@BugPattern(
|
||||
summary = "UndocumentedSuppressionBugPattern summary",
|
||||
severity = SeverityLevel.WARNING,
|
||||
documentSuppression = false)
|
||||
public final class UndocumentedSuppressionBugPattern extends BugChecker {}
|
||||
""");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
|
||||
@@ -7,10 +7,10 @@ import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.BugPatternTestCase;
|
||||
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.BugPatternTestCases;
|
||||
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.IdentificationTestEntry;
|
||||
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.ReplacementTestEntry;
|
||||
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.TestCase;
|
||||
import tech.picnic.errorprone.documentation.BugPatternTestExtractor.TestCases;
|
||||
|
||||
final class BugPatternTestExtractorTest {
|
||||
@Test
|
||||
@@ -18,9 +18,11 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerWithoutAnnotation.java",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"public final class TestCheckerWithoutAnnotation extends BugChecker {}");
|
||||
"""
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
public final class TestCheckerWithoutAnnotation extends BugChecker {}
|
||||
""");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
@@ -30,22 +32,24 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\");",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\");",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class TestCheckerTest {
|
||||
private static class TestChecker extends BugChecker {}
|
||||
|
||||
void m() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}");
|
||||
|
||||
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addInputLines("A.java", "class A {}")
|
||||
.addOutputLines("A.java", "class A { /* This is a change. */ }");
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
@@ -55,22 +59,24 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance((Class<BugChecker>) null, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance((Class<BugChecker>) null, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class TestCheckerTest {
|
||||
void m() {
|
||||
CompilationTestHelper.newInstance((Class<BugChecker>) null, getClass())
|
||||
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
|
||||
.doTest();
|
||||
|
||||
BugCheckerRefactoringTestHelper.newInstance((Class<BugChecker>) null, getClass())
|
||||
.addInputLines("A.java", "class A {}")
|
||||
.addOutputLines("A.java", "class A { /* This is a change. */ }")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
@@ -80,28 +86,30 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" @SuppressWarnings(\"unchecked\")",
|
||||
" void m() {",
|
||||
" @SuppressWarnings(\"rawtypes\")",
|
||||
" Class bugChecker = TestChecker.class;",
|
||||
"",
|
||||
" CompilationTestHelper.newInstance(bugChecker, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(bugChecker, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class TestCheckerTest {
|
||||
private static class TestChecker extends BugChecker {}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void m() {
|
||||
@SuppressWarnings("rawtypes")
|
||||
Class bugChecker = TestChecker.class;
|
||||
|
||||
CompilationTestHelper.newInstance(bugChecker, getClass())
|
||||
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
|
||||
.doTest();
|
||||
|
||||
BugCheckerRefactoringTestHelper.newInstance(bugChecker, getClass())
|
||||
.addInputLines("A.java", "class A {}")
|
||||
.addOutputLines("A.java", "class A { /* This is a change. */ }")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
@@ -111,27 +119,29 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"import com.google.errorprone.scanner.ScannerSupplier;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(",
|
||||
" ScannerSupplier.fromBugCheckerClasses(TestChecker.class), getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(",
|
||||
" ScannerSupplier.fromBugCheckerClasses(TestChecker.class), getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.scanner.ScannerSupplier;
|
||||
|
||||
final class TestCheckerTest {
|
||||
private static class TestChecker extends BugChecker {}
|
||||
|
||||
void m() {
|
||||
CompilationTestHelper.newInstance(
|
||||
ScannerSupplier.fromBugCheckerClasses(TestChecker.class), getClass())
|
||||
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
|
||||
.doTest();
|
||||
|
||||
BugCheckerRefactoringTestHelper.newInstance(
|
||||
ScannerSupplier.fromBugCheckerClasses(TestChecker.class), getClass())
|
||||
.addInputLines("A.java", "class A {}")
|
||||
.addOutputLines("A.java", "class A { /* This is a change. */ }")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
@@ -141,29 +151,31 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addSourceLines(toString() + \"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .addSourceLines(\"B.java\", \"// BUG: Diagnostic contains:\", \"class B {}\", toString())",
|
||||
" .doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addInputLines(toString() + \"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .addInputLines(\"B.java\", \"class B {}\", toString())",
|
||||
" .addOutputLines(\"B.java\", \"class B { /* This is a change. */ }\")",
|
||||
" .addInputLines(\"C.java\", \"class C {}\")",
|
||||
" .addOutputLines(\"C.java\", \"class C { /* This is a change. */ }\", toString())",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class TestCheckerTest {
|
||||
private static class TestChecker extends BugChecker {}
|
||||
|
||||
void m() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines(toString() + "A.java", "// BUG: Diagnostic contains:", "class A {}")
|
||||
.addSourceLines("B.java", "// BUG: Diagnostic contains:", "class B {}", toString())
|
||||
.doTest();
|
||||
|
||||
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addInputLines(toString() + "A.java", "class A {}")
|
||||
.addOutputLines("A.java", "class A { /* This is a change. */ }")
|
||||
.addInputLines("B.java", "class B {}", toString())
|
||||
.addOutputLines("B.java", "class B { /* This is a change. */ }")
|
||||
.addInputLines("C.java", "class C {}")
|
||||
.addOutputLines("C.java", "class C { /* This is a change. */ }", toString())
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
@@ -173,26 +185,28 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper testHelper =",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"class A {}\");",
|
||||
" testHelper.doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.ExpectOutput expectedOutput =",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\");",
|
||||
" expectedOutput.addOutputLines(\"A.java\", \"class A {}\").doTest();",
|
||||
" expectedOutput.expectUnchanged().doTest();",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class TestCheckerTest {
|
||||
private static class TestChecker extends BugChecker {}
|
||||
|
||||
void m() {
|
||||
CompilationTestHelper testHelper =
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines("A.java", "class A {}");
|
||||
testHelper.doTest();
|
||||
|
||||
BugCheckerRefactoringTestHelper.ExpectOutput expectedOutput =
|
||||
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addInputLines("A.java", "class A {}");
|
||||
expectedOutput.addOutputLines("A.java", "class A {}").doTest();
|
||||
expectedOutput.expectUnchanged().doTest();
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
@@ -202,19 +216,21 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass()).doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass()).doTest();",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class TestCheckerTest {
|
||||
private static class TestChecker extends BugChecker {}
|
||||
|
||||
void m() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass()).doTest();
|
||||
|
||||
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass()).doTest();
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
@@ -224,26 +240,28 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class TestCheckerTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A {}\")",
|
||||
" .addInputLines(\"B.java\", \"class B {}\")",
|
||||
" .expectUnchanged()",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class TestCheckerTest {
|
||||
private static class TestChecker extends BugChecker {}
|
||||
|
||||
void m() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines("A.java", "class A {}")
|
||||
.doTest();
|
||||
|
||||
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addInputLines("A.java", "class A {}")
|
||||
.addOutputLines("A.java", "class A {}")
|
||||
.addInputLines("B.java", "class B {}")
|
||||
.expectUnchanged()
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
@@ -253,27 +271,29 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"SingleFileCompilationTestHelperTest.java",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class SingleFileCompilationTestHelperTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class SingleFileCompilationTestHelperTest {
|
||||
private static class TestChecker extends BugChecker {}
|
||||
|
||||
void m() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
"SingleFileCompilationTestHelperTest",
|
||||
TestCases.create(
|
||||
BugPatternTestCases.create(
|
||||
URI.create("file:///SingleFileCompilationTestHelperTest.java"),
|
||||
"SingleFileCompilationTestHelperTest",
|
||||
ImmutableList.of(
|
||||
TestCase.create(
|
||||
BugPatternTestCase.create(
|
||||
"SingleFileCompilationTestHelperTest.TestChecker",
|
||||
ImmutableList.of(
|
||||
IdentificationTestEntry.create(
|
||||
@@ -285,28 +305,30 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"SingleFileCompilationTestHelperWithSetArgsTest.java",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class SingleFileCompilationTestHelperWithSetArgsTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .setArgs(\"-XepAllSuggestionsAsWarnings\")",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class SingleFileCompilationTestHelperWithSetArgsTest {
|
||||
private static class TestChecker extends BugChecker {}
|
||||
|
||||
void m() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.setArgs("-XepAllSuggestionsAsWarnings")
|
||||
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
"SingleFileCompilationTestHelperWithSetArgsTest",
|
||||
TestCases.create(
|
||||
BugPatternTestCases.create(
|
||||
URI.create("file:///SingleFileCompilationTestHelperWithSetArgsTest.java"),
|
||||
"SingleFileCompilationTestHelperWithSetArgsTest",
|
||||
ImmutableList.of(
|
||||
TestCase.create(
|
||||
BugPatternTestCase.create(
|
||||
"SingleFileCompilationTestHelperWithSetArgsTest.TestChecker",
|
||||
ImmutableList.of(
|
||||
IdentificationTestEntry.create(
|
||||
@@ -318,28 +340,30 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"MultiFileCompilationTestHelperTest.java",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class MultiFileCompilationTestHelperTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .addSourceLines(\"B.java\", \"// BUG: Diagnostic contains:\", \"class B {}\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class MultiFileCompilationTestHelperTest {
|
||||
private static class TestChecker extends BugChecker {}
|
||||
|
||||
void m() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
|
||||
.addSourceLines("B.java", "// BUG: Diagnostic contains:", "class B {}")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
"MultiFileCompilationTestHelperTest",
|
||||
TestCases.create(
|
||||
BugPatternTestCases.create(
|
||||
URI.create("file:///MultiFileCompilationTestHelperTest.java"),
|
||||
"MultiFileCompilationTestHelperTest",
|
||||
ImmutableList.of(
|
||||
TestCase.create(
|
||||
BugPatternTestCase.create(
|
||||
"MultiFileCompilationTestHelperTest.TestChecker",
|
||||
ImmutableList.of(
|
||||
IdentificationTestEntry.create(
|
||||
@@ -353,28 +377,30 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"SingleFileBugCheckerRefactoringTestHelperTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class SingleFileBugCheckerRefactoringTestHelperTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class SingleFileBugCheckerRefactoringTestHelperTest {
|
||||
private static class TestChecker extends BugChecker {}
|
||||
|
||||
void m() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addInputLines("A.java", "class A {}")
|
||||
.addOutputLines("A.java", "class A { /* This is a change. */ }")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
"SingleFileBugCheckerRefactoringTestHelperTest",
|
||||
TestCases.create(
|
||||
BugPatternTestCases.create(
|
||||
URI.create("file:///SingleFileBugCheckerRefactoringTestHelperTest.java"),
|
||||
"SingleFileBugCheckerRefactoringTestHelperTest",
|
||||
ImmutableList.of(
|
||||
TestCase.create(
|
||||
BugPatternTestCase.create(
|
||||
"SingleFileBugCheckerRefactoringTestHelperTest.TestChecker",
|
||||
ImmutableList.of(
|
||||
ReplacementTestEntry.create(
|
||||
@@ -387,33 +413,35 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .setArgs(\"-XepAllSuggestionsAsWarnings\")",
|
||||
" .setFixChooser(FixChoosers.SECOND)",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .doTest(TestMode.TEXT_MATCH);",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.FixChoosers;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest {
|
||||
private static class TestChecker extends BugChecker {}
|
||||
|
||||
void m() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.setArgs("-XepAllSuggestionsAsWarnings")
|
||||
.setFixChooser(FixChoosers.SECOND)
|
||||
.addInputLines("A.java", "class A {}")
|
||||
.addOutputLines("A.java", "class A { /* This is a change. */ }")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest",
|
||||
TestCases.create(
|
||||
BugPatternTestCases.create(
|
||||
URI.create(
|
||||
"file:///SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest.java"),
|
||||
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest",
|
||||
ImmutableList.of(
|
||||
TestCase.create(
|
||||
BugPatternTestCase.create(
|
||||
"SingleFileBugCheckerRefactoringTestHelperWithSetArgsFixChooserAndCustomTestModeTest.TestChecker",
|
||||
ImmutableList.of(
|
||||
ReplacementTestEntry.create(
|
||||
@@ -425,30 +453,32 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"MultiFileBugCheckerRefactoringTestHelperTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class MultiFileBugCheckerRefactoringTestHelperTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .addInputLines(\"B.java\", \"class B {}\")",
|
||||
" .addOutputLines(\"B.java\", \"class B { /* This is a change. */ }\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class MultiFileBugCheckerRefactoringTestHelperTest {
|
||||
private static class TestChecker extends BugChecker {}
|
||||
|
||||
void m() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addInputLines("A.java", "class A {}")
|
||||
.addOutputLines("A.java", "class A { /* This is a change. */ }")
|
||||
.addInputLines("B.java", "class B {}")
|
||||
.addOutputLines("B.java", "class B { /* This is a change. */ }")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
"MultiFileBugCheckerRefactoringTestHelperTest",
|
||||
TestCases.create(
|
||||
BugPatternTestCases.create(
|
||||
URI.create("file:///MultiFileBugCheckerRefactoringTestHelperTest.java"),
|
||||
"MultiFileBugCheckerRefactoringTestHelperTest",
|
||||
ImmutableList.of(
|
||||
TestCase.create(
|
||||
BugPatternTestCase.create(
|
||||
"MultiFileBugCheckerRefactoringTestHelperTest.TestChecker",
|
||||
ImmutableList.of(
|
||||
ReplacementTestEntry.create(
|
||||
@@ -462,38 +492,40 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"CompilationAndBugCheckerRefactoringTestHelpersTest.java",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class CompilationAndBugCheckerRefactoringTestHelpersTest {",
|
||||
" private static class TestChecker extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class CompilationAndBugCheckerRefactoringTestHelpersTest {
|
||||
private static class TestChecker extends BugChecker {}
|
||||
|
||||
void m() {
|
||||
CompilationTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
|
||||
.doTest();
|
||||
|
||||
BugCheckerRefactoringTestHelper.newInstance(TestChecker.class, getClass())
|
||||
.addInputLines("A.java", "class A {}")
|
||||
.addOutputLines("A.java", "class A { /* This is a change. */ }")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
"CompilationAndBugCheckerRefactoringTestHelpersTest",
|
||||
TestCases.create(
|
||||
BugPatternTestCases.create(
|
||||
URI.create("file:///CompilationAndBugCheckerRefactoringTestHelpersTest.java"),
|
||||
"CompilationAndBugCheckerRefactoringTestHelpersTest",
|
||||
ImmutableList.of(
|
||||
TestCase.create(
|
||||
BugPatternTestCase.create(
|
||||
"CompilationAndBugCheckerRefactoringTestHelpersTest.TestChecker",
|
||||
ImmutableList.of(
|
||||
IdentificationTestEntry.create(
|
||||
"A.java", "// BUG: Diagnostic contains:\nclass A {}\n"))),
|
||||
TestCase.create(
|
||||
BugPatternTestCase.create(
|
||||
"CompilationAndBugCheckerRefactoringTestHelpersTest.TestChecker",
|
||||
ImmutableList.of(
|
||||
ReplacementTestEntry.create(
|
||||
@@ -506,43 +538,45 @@ final class BugPatternTestExtractorTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.java",
|
||||
"package pkg;",
|
||||
"",
|
||||
"import com.google.errorprone.BugCheckerRefactoringTestHelper;",
|
||||
"import com.google.errorprone.CompilationTestHelper;",
|
||||
"import com.google.errorprone.bugpatterns.BugChecker;",
|
||||
"",
|
||||
"final class CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest {",
|
||||
" private static class CustomTestChecker extends BugChecker {}",
|
||||
"",
|
||||
" private static class CustomTestChecker2 extends BugChecker {}",
|
||||
"",
|
||||
" void m() {",
|
||||
" CompilationTestHelper.newInstance(CustomTestChecker.class, getClass())",
|
||||
" .addSourceLines(\"A.java\", \"// BUG: Diagnostic contains:\", \"class A {}\")",
|
||||
" .doTest();",
|
||||
"",
|
||||
" BugCheckerRefactoringTestHelper.newInstance(CustomTestChecker2.class, getClass())",
|
||||
" .addInputLines(\"A.java\", \"class A {}\")",
|
||||
" .addOutputLines(\"A.java\", \"class A { /* This is a change. */ }\")",
|
||||
" .doTest();",
|
||||
" }",
|
||||
"}");
|
||||
"""
|
||||
package pkg;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
|
||||
final class CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest {
|
||||
private static class CustomTestChecker extends BugChecker {}
|
||||
|
||||
private static class CustomTestChecker2 extends BugChecker {}
|
||||
|
||||
void m() {
|
||||
CompilationTestHelper.newInstance(CustomTestChecker.class, getClass())
|
||||
.addSourceLines("A.java", "// BUG: Diagnostic contains:", "class A {}")
|
||||
.doTest();
|
||||
|
||||
BugCheckerRefactoringTestHelper.newInstance(CustomTestChecker2.class, getClass())
|
||||
.addInputLines("A.java", "class A {}")
|
||||
.addOutputLines("A.java", "class A { /* This is a change. */ }")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
"CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest",
|
||||
TestCases.create(
|
||||
BugPatternTestCases.create(
|
||||
URI.create(
|
||||
"file:///CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.java"),
|
||||
"pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest",
|
||||
ImmutableList.of(
|
||||
TestCase.create(
|
||||
BugPatternTestCase.create(
|
||||
"pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.CustomTestChecker",
|
||||
ImmutableList.of(
|
||||
IdentificationTestEntry.create(
|
||||
"A.java", "// BUG: Diagnostic contains:\nclass A {}\n"))),
|
||||
TestCase.create(
|
||||
BugPatternTestCase.create(
|
||||
"pkg.CompilationAndBugCheckerRefactoringTestHelpersWithCustomCheckerPackageAndNamesTest.CustomTestChecker2",
|
||||
ImmutableList.of(
|
||||
ReplacementTestEntry.create(
|
||||
@@ -550,9 +584,9 @@ final class BugPatternTestExtractorTest {
|
||||
}
|
||||
|
||||
private static void verifyGeneratedFileContent(
|
||||
Path outputDirectory, String testClass, TestCases expected) {
|
||||
Path outputDirectory, String testClass, BugPatternTestCases expected) {
|
||||
assertThat(outputDirectory.resolve(String.format("bugpattern-test-%s.json", testClass)))
|
||||
.exists()
|
||||
.returns(expected, path -> Json.read(path, TestCases.class));
|
||||
.returns(expected, path -> Json.read(path, BugPatternTestCases.class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,21 +14,29 @@ import java.util.List;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileObject;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
|
||||
// XXX: Generalize and move this class so that it can also be used by `refaster-compiler`.
|
||||
// XXX: This class is supported by the `ErrorProneTestHelperSourceFormat` check, but until that
|
||||
// support is covered by unit tests, make sure to update that logic if this class or its methods are
|
||||
// XXX: This class is supported by the `TestHelperSourceFormat` check, but until that support is
|
||||
// covered by unit tests, make sure to update that logic if this class or its methods are
|
||||
// moved/renamed.
|
||||
public final class Compilation {
|
||||
private Compilation() {}
|
||||
|
||||
// XXX: Drop this method in favour of only supporting the text block-accepting variant.
|
||||
public static void compileWithDocumentationGenerator(
|
||||
Path outputDirectory, String path, String... lines) {
|
||||
compileWithDocumentationGenerator(outputDirectory.toAbsolutePath().toString(), path, lines);
|
||||
Path outputDirectory, String path, @Language("JAVA") String... source) {
|
||||
compileWithDocumentationGenerator(
|
||||
outputDirectory.toAbsolutePath().toString(), path, String.join("\n", source));
|
||||
}
|
||||
|
||||
public static void compileWithDocumentationGenerator(
|
||||
String outputDirectory, String path, String... lines) {
|
||||
Path outputDirectory, String path, @Language("JAVA") String source) {
|
||||
compileWithDocumentationGenerator(outputDirectory.toAbsolutePath().toString(), path, source);
|
||||
}
|
||||
|
||||
public static void compileWithDocumentationGenerator(
|
||||
String outputDirectory, String path, @Language("JAVA") String source) {
|
||||
/*
|
||||
* The compiler options specified here largely match those used by Error Prone's
|
||||
* `CompilationTestHelper`. A key difference is the stricter linting configuration. When
|
||||
@@ -49,7 +57,7 @@ public final class Compilation {
|
||||
"-Xplugin:DocumentationGenerator -XoutputDirectory=" + outputDirectory,
|
||||
"-XDdev",
|
||||
"-XDcompilePolicy=simple"),
|
||||
FileObjects.forSourceLines(path, lines));
|
||||
FileObjects.forSourceLines(path, source));
|
||||
}
|
||||
|
||||
private static void compile(ImmutableList<String> options, JavaFileObject javaFileObject) {
|
||||
|
||||
@@ -10,7 +10,6 @@ import static org.junit.jupiter.api.condition.OS.WINDOWS;
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.errorprone.VisitorState;
|
||||
@@ -41,7 +40,8 @@ final class DocumentationGeneratorTaskListenerTest {
|
||||
entry ->
|
||||
AclEntry.newBuilder(entry)
|
||||
.setPermissions(
|
||||
Sets.difference(entry.permissions(), ImmutableSet.of(ADD_SUBDIRECTORY)))
|
||||
Sets.difference(
|
||||
entry.permissions(), Sets.immutableEnumSet(ADD_SUBDIRECTORY)))
|
||||
.build())
|
||||
.collect(toImmutableList()));
|
||||
|
||||
@@ -62,15 +62,26 @@ final class DocumentationGeneratorTaskListenerTest {
|
||||
assertThatThrownBy(
|
||||
() ->
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory, "A.java", "class A {}"))
|
||||
outputDirectory,
|
||||
"A.java",
|
||||
"""
|
||||
class A {}
|
||||
"""))
|
||||
.hasRootCauseInstanceOf(FileSystemException.class)
|
||||
.hasCauseInstanceOf(IllegalStateException.class)
|
||||
.hasMessageEndingWith("Error while creating directory with path '%s'", outputDirectory);
|
||||
}
|
||||
|
||||
// XXX: For this case the text block conversion introduces too much indentation. (Possibly i.c.w.
|
||||
// post-processing by GJF; TBD.)
|
||||
@Test
|
||||
void noClassNoOutput(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(outputDirectory, "A.java", "package pkg;");
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"A.java",
|
||||
"""
|
||||
package pkg;
|
||||
""");
|
||||
|
||||
assertThat(outputDirectory).isEmptyDirectory();
|
||||
}
|
||||
@@ -81,7 +92,11 @@ final class DocumentationGeneratorTaskListenerTest {
|
||||
assertThatThrownBy(
|
||||
() ->
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
actualOutputDirectory, "A.java", "package pkg;"))
|
||||
actualOutputDirectory,
|
||||
"A.java",
|
||||
"""
|
||||
package pkg;
|
||||
"""))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("Precisely one path must be provided");
|
||||
}
|
||||
@@ -91,7 +106,9 @@ final class DocumentationGeneratorTaskListenerTest {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"DocumentationGeneratorTaskListenerTestClass.java",
|
||||
"class DocumentationGeneratorTaskListenerTestClass {}");
|
||||
"""
|
||||
class DocumentationGeneratorTaskListenerTestClass {}
|
||||
""");
|
||||
|
||||
assertThat(
|
||||
outputDirectory.resolve(
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
package tech.picnic.errorprone.documentation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import com.google.common.base.VerifyException;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import tech.picnic.errorprone.documentation.RefasterRuleCollectionTestExtractor.RefasterTestCase;
|
||||
import tech.picnic.errorprone.documentation.RefasterRuleCollectionTestExtractor.RefasterTestCases;
|
||||
|
||||
final class RefasterRuleCollectionTestExtractorTest {
|
||||
@Test
|
||||
void noRefasterRuleTest(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"NoRefasterRuleTest.java",
|
||||
"""
|
||||
public final class NoRefasterRuleTest {}
|
||||
""");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidTestClassName(@TempDir Path outputDirectory) {
|
||||
assertThatThrownBy(
|
||||
() ->
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"InvalidTestClassNameInput.java",
|
||||
"""
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class InvalidTestClassName implements RefasterRuleCollectionTestCase {}
|
||||
"""))
|
||||
.cause()
|
||||
.isInstanceOf(VerifyException.class)
|
||||
.hasMessage(
|
||||
"Refaster rule collection test class name 'InvalidTestClassName' does not match '(.*)Test'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidFileName(@TempDir Path outputDirectory) {
|
||||
assertThatThrownBy(
|
||||
() ->
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"InvalidFileNameTest.java",
|
||||
"""
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class InvalidFileNameTest implements RefasterRuleCollectionTestCase {}
|
||||
"""))
|
||||
.cause()
|
||||
.isInstanceOf(VerifyException.class)
|
||||
.hasMessage(
|
||||
"Refaster rule collection test file name '/InvalidFileNameTest.java' does not match '.*(Input|Output)\\.java'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void emptyRefasterRuleCollectionTestInput(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"EmptyRefasterRuleCollectionTestInput.java",
|
||||
"""
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class EmptyRefasterRuleCollectionTest implements RefasterRuleCollectionTestCase {}
|
||||
""");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
"EmptyRefasterRuleCollectionTestInput",
|
||||
RefasterTestCases.create(
|
||||
URI.create("file:///EmptyRefasterRuleCollectionTestInput.java"),
|
||||
"EmptyRefasterRuleCollection",
|
||||
/* isInput= */ true,
|
||||
ImmutableList.of()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void singletonRefasterRuleCollectionTestOutput(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"SingletonRefasterRuleCollectionTestOutput.java",
|
||||
"""
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class SingletonRefasterRuleCollectionTest implements RefasterRuleCollectionTestCase {
|
||||
int testMyRule() {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
"SingletonRefasterRuleCollectionTestOutput",
|
||||
RefasterTestCases.create(
|
||||
URI.create("file:///SingletonRefasterRuleCollectionTestOutput.java"),
|
||||
"SingletonRefasterRuleCollection",
|
||||
/* isInput= */ false,
|
||||
ImmutableList.of(
|
||||
RefasterTestCase.create(
|
||||
"MyRule",
|
||||
"""
|
||||
int testMyRule() {
|
||||
return 42;
|
||||
}"""))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void complexRefasterRuleCollectionTestOutput(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithDocumentationGenerator(
|
||||
outputDirectory,
|
||||
"pkg/ComplexRefasterRuleCollectionTestInput.java",
|
||||
"""
|
||||
package pkg;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase;
|
||||
|
||||
final class ComplexRefasterRuleCollectionTest implements RefasterRuleCollectionTestCase {
|
||||
private static final String IGNORED_CONSTANT = "constant";
|
||||
|
||||
@Override
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
/** Javadoc. */
|
||||
String testFirstRule() {
|
||||
return "Don't panic";
|
||||
}
|
||||
|
||||
// Comment.
|
||||
String testSecondRule() {
|
||||
return "Carry a towel";
|
||||
}
|
||||
|
||||
void testEmptyRule() {}
|
||||
}
|
||||
""");
|
||||
|
||||
verifyGeneratedFileContent(
|
||||
outputDirectory,
|
||||
"ComplexRefasterRuleCollectionTestInput",
|
||||
RefasterTestCases.create(
|
||||
URI.create("file:///pkg/ComplexRefasterRuleCollectionTestInput.java"),
|
||||
"ComplexRefasterRuleCollection",
|
||||
/* isInput= */ true,
|
||||
ImmutableList.of(
|
||||
RefasterTestCase.create(
|
||||
"FirstRule",
|
||||
"""
|
||||
String testFirstRule() {
|
||||
return "Don't panic";
|
||||
}"""),
|
||||
RefasterTestCase.create(
|
||||
"SecondRule",
|
||||
"""
|
||||
String testSecondRule() {
|
||||
return "Carry a towel";
|
||||
}"""),
|
||||
RefasterTestCase.create("EmptyRule", "void testEmptyRule() {}"))));
|
||||
}
|
||||
|
||||
private static void verifyGeneratedFileContent(
|
||||
Path outputDirectory, String testIdentifier, RefasterTestCases expected) {
|
||||
assertThat(
|
||||
outputDirectory.resolve(
|
||||
String.format("refaster-rule-collection-test-%s.json", testIdentifier)))
|
||||
.exists()
|
||||
.returns(expected, path -> Json.read(path, RefasterTestCases.class));
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.19.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-contrib</artifactId>
|
||||
@@ -55,7 +55,12 @@
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>refaster-support</artifactId>
|
||||
<scope>provided</scope>
|
||||
<!-- XXX: One would expect this to be a `provided` dependency (as
|
||||
Refaster rules are interpreted by the `refaster-runner` module),
|
||||
but the `OptionalOrElseGet` bug checker defined by this module
|
||||
depends on the `RequiresComputation` matcher that
|
||||
`refaster-support` primarily exposes for use by Refaster rules.
|
||||
Review this setup. (Should the matchers be moved elsewhere?) -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
@@ -67,6 +72,11 @@
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.service</groupId>
|
||||
<artifactId>auto-service-annotations</artifactId>
|
||||
@@ -82,6 +92,11 @@
|
||||
<artifactId>guava</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
@@ -122,6 +137,11 @@
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
@@ -147,6 +167,11 @@
|
||||
<artifactId>value-annotations</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jooq</groupId>
|
||||
<artifactId>jooq</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jspecify</groupId>
|
||||
<artifactId>jspecify</artifactId>
|
||||
@@ -191,7 +216,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openrewrite</groupId>
|
||||
<artifactId>rewrite-java-11</artifactId>
|
||||
<artifactId>rewrite-java-17</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -282,6 +307,55 @@
|
||||
<arg>-Xplugin:DocumentationGenerator -XoutputDirectory=${project.build.directory}/docs</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<!-- The Refaster input/output test classes used by
|
||||
`RefasterRuleCollection` are modelled as classpath
|
||||
resources, and thus not subject to the default test
|
||||
compilation step. These two custom compilation steps
|
||||
serve two purposes:
|
||||
- To provide early feedback in case of syntax errors.
|
||||
- To enable the `DocumentationGenerator` compiler
|
||||
plugin to extract documentation metadata from them.
|
||||
Note that the input and output files must be compiled
|
||||
separately and to distinct output directories, as they
|
||||
define the same set of class names. -->
|
||||
<!-- XXX: Drop these executions if/when the Refaster
|
||||
test framework is reimplemented such that tests can be
|
||||
located alongside rules, rather than in two additional
|
||||
resource files. -->
|
||||
<execution>
|
||||
<id>compile-refaster-test-input</id>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
<phase>process-test-resources</phase>
|
||||
<configuration>
|
||||
<compileSourceRoots>
|
||||
<compileSourceRoot>${project.basedir}/src/test/resources</compileSourceRoot>
|
||||
</compileSourceRoots>
|
||||
<testIncludes>
|
||||
<testInclude>**/*Input.java</testInclude>
|
||||
</testIncludes>
|
||||
<outputDirectory>${project.build.directory}/refaster-test-input</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>compile-refaster-test-output</id>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
<phase>process-test-resources</phase>
|
||||
<configuration>
|
||||
<compileSourceRoots>
|
||||
<compileSourceRoot>${project.basedir}/src/test/resources</compileSourceRoot>
|
||||
</compileSourceRoots>
|
||||
<testIncludes>
|
||||
<testInclude>**/*Output.java</testInclude>
|
||||
</testIncludes>
|
||||
<outputDirectory>${project.build.directory}/refaster-test-output</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
|
||||
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.LambdaExpressionTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.LambdaExpressionTree;
|
||||
import com.sun.source.tree.TypeCastTree;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags lambda expressions that can be replaced with a method reference
|
||||
* of the form {@code T.class::cast}.
|
||||
*/
|
||||
// XXX: Consider folding this logic into the `MethodReferenceUsage` check of the
|
||||
// `error-prone-experimental` module.
|
||||
// XXX: This check and its tests are structurally nearly identical to `IsInstanceLambdaUsage`.
|
||||
// Unless folded into `MethodReferenceUsage`, consider merging the two.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Prefer `Class::cast` method reference over equivalent lambda expression",
|
||||
link = BUG_PATTERNS_BASE_URL + "ClassCastLambdaUsage",
|
||||
linkType = CUSTOM,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class ClassCastLambdaUsage extends BugChecker implements LambdaExpressionTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Instantiates a new {@link ClassCastLambdaUsage} instance. */
|
||||
public ClassCastLambdaUsage() {}
|
||||
|
||||
@Override
|
||||
public Description matchLambdaExpression(LambdaExpressionTree tree, VisitorState state) {
|
||||
if (tree.getParameters().size() != 1 || !(tree.getBody() instanceof TypeCastTree typeCast)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
Type type = ASTHelpers.getType(typeCast);
|
||||
if (type == null
|
||||
|| type.isParameterized()
|
||||
|| type.isPrimitive()
|
||||
|| type.getKind() == TypeKind.TYPEVAR) {
|
||||
/*
|
||||
* The method reference syntax does not support casting to parameterized types, and type
|
||||
* variables aren't supported either. Additionally, `Class#cast` does not support the same
|
||||
* range of type conversions between (boxed) primitive types as the cast operator.
|
||||
*/
|
||||
// XXX: Depending on the declared type of the value being cast, in some cases we _can_ rewrite
|
||||
// primitive casts. Add support for this.
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
VariableTree param = Iterables.getOnlyElement(tree.getParameters());
|
||||
if (!ASTHelpers.getSymbol(param).equals(ASTHelpers.getSymbol(typeCast.getExpression()))) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
return describeMatch(
|
||||
tree,
|
||||
SuggestedFix.replace(
|
||||
tree, SourceCode.treeToString(typeCast.getType(), state) + ".class::cast"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.STYLE;
|
||||
import static com.google.errorprone.matchers.Matchers.allOf;
|
||||
import static com.google.errorprone.matchers.Matchers.hasModifier;
|
||||
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.ErrorProneFlags;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFixes;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.inject.Inject;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.picnic.errorprone.utils.Flags;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags static constants that do not follow the upper snake case naming
|
||||
* convention.
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Constant variables should adhere to the `UPPER_SNAKE_CASE` naming convention",
|
||||
link = BUG_PATTERNS_BASE_URL + "ConstantNaming",
|
||||
linkType = CUSTOM,
|
||||
severity = WARNING,
|
||||
tags = STYLE)
|
||||
@SuppressWarnings("java:S2160" /* Super class equality definition suffices. */)
|
||||
public final class ConstantNaming extends BugChecker implements VariableTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<VariableTree> IS_CONSTANT =
|
||||
allOf(hasModifier(Modifier.STATIC), hasModifier(Modifier.FINAL));
|
||||
private static final Matcher<VariableTree> IS_PRIVATE = hasModifier(Modifier.PRIVATE);
|
||||
private static final Pattern SNAKE_CASE = Pattern.compile("([a-z])([A-Z])");
|
||||
private static final ImmutableSet<String> DEFAULT_EXEMPTED_NAMES =
|
||||
ImmutableSet.of("serialVersionUID");
|
||||
|
||||
/**
|
||||
* Flag using which constant names that must not be flagged (in addition to those defined by
|
||||
* {@link #DEFAULT_EXEMPTED_NAMES}) can be specified.
|
||||
*/
|
||||
private static final String ADDITIONAL_EXEMPTED_NAMES_FLAG =
|
||||
"CanonicalConstantNaming:ExemptedNames";
|
||||
|
||||
private final ImmutableSet<String> exemptedNames;
|
||||
|
||||
/** Instantiates a default {@link ConstantNaming} instance. */
|
||||
public ConstantNaming() {
|
||||
this(ErrorProneFlags.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a customized {@link ConstantNaming}.
|
||||
*
|
||||
* @param flags Any provided command line flags.
|
||||
*/
|
||||
@Inject
|
||||
ConstantNaming(ErrorProneFlags flags) {
|
||||
exemptedNames =
|
||||
Sets.union(DEFAULT_EXEMPTED_NAMES, Flags.getSet(flags, ADDITIONAL_EXEMPTED_NAMES_FLAG))
|
||||
.immutableCopy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Description matchVariable(VariableTree tree, VisitorState state) {
|
||||
String variableName = tree.getName().toString();
|
||||
if (!IS_CONSTANT.matches(tree, state) || exemptedNames.contains(variableName)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
String replacement = toUpperSnakeCase(variableName);
|
||||
if (replacement.equals(variableName)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
Description.Builder description = buildDescription(tree);
|
||||
if (!IS_PRIVATE.matches(tree, state)) {
|
||||
description.setMessage(
|
||||
"%s; consider renaming to '%s', though note that this is not a private constant"
|
||||
.formatted(message(), replacement));
|
||||
} else if (isVariableNameInUse(replacement, state)) {
|
||||
description.setMessage(
|
||||
"%s; consider renaming to '%s', though note that a variable with this name is already declared"
|
||||
.formatted(message(), replacement));
|
||||
} else {
|
||||
description.addFix(SuggestedFixes.renameVariable(tree, replacement, state));
|
||||
}
|
||||
|
||||
return description.build();
|
||||
}
|
||||
|
||||
private static String toUpperSnakeCase(String variableName) {
|
||||
return SNAKE_CASE.matcher(variableName).replaceAll("$1_$2").toUpperCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
private static boolean isVariableNameInUse(String name, VisitorState state) {
|
||||
return Boolean.TRUE.equals(
|
||||
new TreeScanner<Boolean, @Nullable Void>() {
|
||||
@Override
|
||||
public Boolean visitVariable(VariableTree tree, @Nullable Void unused) {
|
||||
return ASTHelpers.getSymbol(tree).getSimpleName().contentEquals(name)
|
||||
|| super.visitVariable(tree, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean reduce(Boolean r1, Boolean r2) {
|
||||
return Boolean.TRUE.equals(r1) || Boolean.TRUE.equals(r2);
|
||||
}
|
||||
}.scan(state.getPath().getCompilationUnit(), null));
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,7 @@ public final class EmptyMethod extends BugChecker implements MethodTreeMatcher {
|
||||
}
|
||||
|
||||
private static boolean isInPossibleTestHelperClass(VisitorState state) {
|
||||
return Optional.ofNullable(ASTHelpers.findEnclosingNode(state.getPath(), ClassTree.class))
|
||||
return Optional.ofNullable(state.findEnclosing(ClassTree.class))
|
||||
.map(ClassTree::getSimpleName)
|
||||
.filter(name -> name.toString().contains("Test"))
|
||||
.isPresent();
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.PERFORMANCE;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
|
||||
import static com.google.errorprone.matchers.Matchers.allOf;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.symbolMatcher;
|
||||
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultiset;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.fixes.SuggestedFixes;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.google.errorprone.util.Visibility;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.VarSymbol;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.lang.model.element.Element;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags single-argument method invocations with an iterable of explicitly
|
||||
* enumerated values, for which a semantically equivalent varargs variant (appears to) exists as
|
||||
* well.
|
||||
*
|
||||
* <p>This check drops selected {@link ImmutableSet#of} and {@link Set#of} invocations, with the
|
||||
* assumption that these operations do not deduplicate the collection of explicitly enumerated
|
||||
* values. It also drops {@link ImmutableMultiset#of} and {@link Set#of} invocations, with the
|
||||
* assumption that these do not materially impact iteration order.
|
||||
*
|
||||
* <p>This checker attempts to identify {@link Iterable}-accepting methods for which a varargs
|
||||
* overload exists, and suggests calling the varargs overload instead. This is an imperfect
|
||||
* heuristic, but it e.g. allows invocations of <a
|
||||
* href="https://immutables.github.io/immutable.html#copy-methods">Immutables-generated {@code
|
||||
* with*}</a> methods to be simplified.
|
||||
*/
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Iterable creation can be avoided by using a varargs alternative method",
|
||||
link = BUG_PATTERNS_BASE_URL + "ExplicitArgumentEnumeration",
|
||||
linkType = CUSTOM,
|
||||
severity = SUGGESTION,
|
||||
tags = {PERFORMANCE, SIMPLIFICATION})
|
||||
public final class ExplicitArgumentEnumeration extends BugChecker
|
||||
implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> EXPLICIT_ITERABLE_CREATOR =
|
||||
anyOf(
|
||||
staticMethod()
|
||||
.onClassAny(
|
||||
ImmutableList.class.getCanonicalName(),
|
||||
ImmutableMultiset.class.getCanonicalName(),
|
||||
ImmutableSet.class.getCanonicalName(),
|
||||
List.class.getCanonicalName(),
|
||||
Set.class.getCanonicalName())
|
||||
.named("of"),
|
||||
allOf(
|
||||
staticMethod()
|
||||
.onClassAny(
|
||||
ImmutableList.class.getCanonicalName(),
|
||||
ImmutableMultiset.class.getCanonicalName(),
|
||||
ImmutableSet.class.getCanonicalName())
|
||||
.named("copyOf"),
|
||||
symbolMatcher(
|
||||
(symbol, state) ->
|
||||
state
|
||||
.getSymtab()
|
||||
.arrayClass
|
||||
.equals(((MethodSymbol) symbol).params().get(0).type.tsym))),
|
||||
staticMethod().onClass(Arrays.class.getCanonicalName()).named("asList"));
|
||||
private static final Matcher<ExpressionTree> IMMUTABLE_COLLECTION_BUILDER =
|
||||
instanceMethod().onDescendantOf(ImmutableCollection.Builder.class.getCanonicalName());
|
||||
private static final Matcher<ExpressionTree> OBJECT_ENUMERABLE_ASSERT =
|
||||
instanceMethod().onDescendantOf("org.assertj.core.api.ObjectEnumerableAssert");
|
||||
private static final Matcher<ExpressionTree> STEP_VERIFIER_STEP =
|
||||
instanceMethod().onDescendantOf("reactor.test.StepVerifier.Step");
|
||||
private static final ImmutableTable<Matcher<ExpressionTree>, String, String> ALTERNATIVE_METHODS =
|
||||
ImmutableTable.<Matcher<ExpressionTree>, String, String>builder()
|
||||
.put(IMMUTABLE_COLLECTION_BUILDER, "addAll", "add")
|
||||
.put(OBJECT_ENUMERABLE_ASSERT, "containsAnyElementsOf", "containsAnyOf")
|
||||
.put(OBJECT_ENUMERABLE_ASSERT, "containsAll", "contains")
|
||||
.put(OBJECT_ENUMERABLE_ASSERT, "containsExactlyElementsOf", "containsExactly")
|
||||
.put(
|
||||
OBJECT_ENUMERABLE_ASSERT,
|
||||
"containsExactlyInAnyOrderElementsOf",
|
||||
"containsExactlyInAnyOrder")
|
||||
.put(OBJECT_ENUMERABLE_ASSERT, "containsOnlyElementsOf", "containsOnly")
|
||||
.put(OBJECT_ENUMERABLE_ASSERT, "containsOnlyOnceElementsOf", "containsOnlyOnce")
|
||||
.put(OBJECT_ENUMERABLE_ASSERT, "doesNotContainAnyElementsOf", "doesNotContain")
|
||||
.put(OBJECT_ENUMERABLE_ASSERT, "hasSameElementsAs", "containsOnly")
|
||||
.put(STEP_VERIFIER_STEP, "expectNextSequence", "expectNext")
|
||||
.build();
|
||||
|
||||
/** Instantiates a new {@link ExplicitArgumentEnumeration} instance. */
|
||||
public ExplicitArgumentEnumeration() {}
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
if (tree.getArguments().size() != 1) {
|
||||
/* Performance optimization: non-unary method invocations cannot be simplified. */
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
MethodSymbol method = ASTHelpers.getSymbol(tree);
|
||||
if (!isUnaryIterableAcceptingMethod(method, state) || isLocalOverload(method, state)) {
|
||||
/*
|
||||
* This isn't a method invocation we can simplify, or it's an invocation of a local overload.
|
||||
* The latter type of invocation we do not suggest replacing, as this is fairly likely to
|
||||
* introduce an unbounded recursive call chain.
|
||||
*/
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
ExpressionTree argument = tree.getArguments().get(0);
|
||||
if (!EXPLICIT_ITERABLE_CREATOR.matches(argument, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
return trySuggestCallingVarargsOverload(method, (MethodInvocationTree) argument, state)
|
||||
.or(() -> trySuggestCallingCustomAlternative(tree, (MethodInvocationTree) argument, state))
|
||||
.map(fix -> describeMatch(tree, fix))
|
||||
.orElse(Description.NO_MATCH);
|
||||
}
|
||||
|
||||
private static boolean isUnaryIterableAcceptingMethod(MethodSymbol method, VisitorState state) {
|
||||
List<VarSymbol> params = method.params();
|
||||
return !method.isVarArgs()
|
||||
&& params.size() == 1
|
||||
&& ASTHelpers.isSubtype(params.get(0).type, state.getSymtab().iterableType, state);
|
||||
}
|
||||
|
||||
private static boolean isLocalOverload(MethodSymbol calledMethod, VisitorState state) {
|
||||
MethodTree enclosingMethod = state.findEnclosing(MethodTree.class);
|
||||
if (enclosingMethod == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MethodSymbol callingMethod = ASTHelpers.getSymbol(enclosingMethod);
|
||||
return Objects.equals(callingMethod.getEnclosingElement(), calledMethod.getEnclosingElement())
|
||||
&& callingMethod.getSimpleName().equals(calledMethod.getSimpleName());
|
||||
}
|
||||
|
||||
private static Optional<SuggestedFix> trySuggestCallingVarargsOverload(
|
||||
MethodSymbol method, MethodInvocationTree argument, VisitorState state) {
|
||||
/*
|
||||
* Collect all overloads of the given method that we are sure to be able to call. Note that the
|
||||
* `isAtLeastAsVisible` check is conservative heuristic.
|
||||
*/
|
||||
ImmutableList<MethodSymbol> overloads =
|
||||
ASTHelpers.matchingMethods(
|
||||
method.getSimpleName(),
|
||||
m -> isAtLeastAsVisible(m, method),
|
||||
method.enclClass().type,
|
||||
state.getTypes())
|
||||
.collect(toImmutableList());
|
||||
|
||||
/*
|
||||
* If all overloads have a single parameter, and at least one of them is a varargs method, then
|
||||
* we assume that unwrapping the iterable argument will cause a suitable overload to be invoked.
|
||||
* (Note that there may be multiple varargs overloads, either with different parameter types, or
|
||||
* due to method overriding; this check does not attempt to determine which exact method or
|
||||
* overload will be invoked as a result of the suggested simplification.)
|
||||
*
|
||||
* Note that this is a (highly!) imperfect heuristic, but it is sufficient to prevent e.g.
|
||||
* unwrapping of arguments to `org.jooq.impl.DSL#row`, which can cause the expression's return
|
||||
* type to change from `RowN` to (e.g.) `Row2`.
|
||||
*/
|
||||
// XXX: There are certainly cases where it _would_ be nice to unwrap the arguments to
|
||||
// `org.jooq.impl.DSL#row(Collection<?>)`. Look into this.
|
||||
// XXX: Ideally we do check that one of the overloads accepts the unwrapped arguments.
|
||||
// XXX: Ideally we validate that eligible overloads have compatible return types.
|
||||
boolean hasLikelySuitableVarargsOverload =
|
||||
overloads.stream().allMatch(m -> m.params().size() == 1)
|
||||
&& overloads.stream().anyMatch(MethodSymbol::isVarArgs);
|
||||
|
||||
return hasLikelySuitableVarargsOverload
|
||||
? Optional.of(SourceCode.unwrapMethodInvocation(argument, state))
|
||||
: Optional.empty();
|
||||
}
|
||||
|
||||
private static Optional<SuggestedFix> trySuggestCallingCustomAlternative(
|
||||
MethodInvocationTree tree, MethodInvocationTree argument, VisitorState state) {
|
||||
return ALTERNATIVE_METHODS.rowMap().entrySet().stream()
|
||||
.filter(e -> e.getKey().matches(tree, state))
|
||||
.findFirst()
|
||||
.flatMap(e -> trySuggestCallingCustomAlternative(tree, argument, state, e.getValue()));
|
||||
}
|
||||
|
||||
private static Optional<SuggestedFix> trySuggestCallingCustomAlternative(
|
||||
MethodInvocationTree tree,
|
||||
MethodInvocationTree argument,
|
||||
VisitorState state,
|
||||
Map<String, String> alternatives) {
|
||||
return Optional.ofNullable(
|
||||
alternatives.get(ASTHelpers.getSymbol(tree).getSimpleName().toString()))
|
||||
.map(
|
||||
replacement ->
|
||||
SuggestedFix.builder()
|
||||
.merge(SuggestedFixes.renameMethodInvocation(tree, replacement, state))
|
||||
.merge(SourceCode.unwrapMethodInvocation(argument, state))
|
||||
.build());
|
||||
}
|
||||
|
||||
private static boolean isAtLeastAsVisible(Element symbol, Element reference) {
|
||||
return Visibility.fromModifiers(symbol.getModifiers())
|
||||
.compareTo(Visibility.fromModifiers(reference.getModifiers()))
|
||||
>= 0;
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ import java.util.Formatter;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.picnic.errorprone.utils.MoreASTHelpers;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/**
|
||||
@@ -203,14 +204,10 @@ public final class FormatStringConcatenation extends BugChecker
|
||||
|
||||
ExpressionTree argument = ASTHelpers.stripParentheses(arguments.get(argPosition));
|
||||
return argument instanceof BinaryTree
|
||||
&& isStringTyped(argument, state)
|
||||
&& MoreASTHelpers.isStringTyped(argument, state)
|
||||
&& ASTHelpers.constValue(argument, String.class) == null;
|
||||
}
|
||||
|
||||
private static boolean isStringTyped(ExpressionTree tree, VisitorState state) {
|
||||
return ASTHelpers.isSameType(ASTHelpers.getType(tree), state.getSymtab().stringType, state);
|
||||
}
|
||||
|
||||
private static class ReplacementArgumentsConstructor
|
||||
extends SimpleTreeVisitor<@Nullable Void, VisitorState> {
|
||||
private final StringBuilder formatString = new StringBuilder();
|
||||
@@ -223,7 +220,7 @@ public final class FormatStringConcatenation extends BugChecker
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitBinary(BinaryTree tree, VisitorState state) {
|
||||
if (tree.getKind() == Kind.PLUS && isStringTyped(tree, state)) {
|
||||
if (tree.getKind() == Kind.PLUS && MoreASTHelpers.isStringTyped(tree, state)) {
|
||||
tree.getLeftOperand().accept(this, state);
|
||||
tree.getRightOperand().accept(this, state);
|
||||
} else {
|
||||
|
||||
@@ -39,6 +39,7 @@ import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
@@ -51,6 +52,7 @@ import tech.picnic.errorprone.utils.SourceCode;
|
||||
// is effectively the identity operation.
|
||||
// XXX: Also flag nullary instance method invocations that represent an identity conversion, such as
|
||||
// `Boolean#booleanValue()`, `Byte#byteValue()` and friends.
|
||||
// XXX: Also flag redundant round-trip conversions such as `path.toFile().toPath()`.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Avoid or clarify identity conversions",
|
||||
@@ -83,6 +85,7 @@ public final class IdentityConversion extends BugChecker implements MethodInvoca
|
||||
ImmutableSetMultimap.class.getCanonicalName(),
|
||||
ImmutableTable.class.getCanonicalName())
|
||||
.named("copyOf"),
|
||||
staticMethod().onClass(Instant.class.getCanonicalName()).namedAnyOf("from"),
|
||||
staticMethod().onClass(Matchers.class.getCanonicalName()).namedAnyOf("allOf", "anyOf"),
|
||||
staticMethod().onClass("reactor.adapter.rxjava.RxJava2Adapter"),
|
||||
staticMethod()
|
||||
|
||||
@@ -25,6 +25,8 @@ import tech.picnic.errorprone.utils.SourceCode;
|
||||
*/
|
||||
// XXX: Consider folding this logic into the `MethodReferenceUsage` check of the
|
||||
// `error-prone-experimental` module.
|
||||
// XXX: This check and its tests are structurally nearly identical to `ClassCastLambdaUsage`. Unless
|
||||
// folded into `MethodReferenceUsage`, consider merging the two.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Prefer `Class::isInstance` method reference over equivalent lambda expression",
|
||||
|
||||
@@ -16,7 +16,7 @@ import static tech.picnic.errorprone.utils.MoreJUnitMatchers.TEST_METHOD;
|
||||
import static tech.picnic.errorprone.utils.MoreMatchers.hasMetaAnnotation;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
@@ -70,7 +70,7 @@ public final class JUnitClassModifiers extends BugChecker implements ClassTreeMa
|
||||
SuggestedFixes.removeModifiers(
|
||||
tree.getModifiers(),
|
||||
state,
|
||||
ImmutableSet.of(Modifier.PRIVATE, Modifier.PROTECTED, Modifier.PUBLIC))
|
||||
Sets.immutableEnumSet(Modifier.PRIVATE, Modifier.PROTECTED, Modifier.PUBLIC))
|
||||
.ifPresent(fixBuilder::merge);
|
||||
|
||||
if (!HAS_SPRING_CONFIGURATION_ANNOTATION.matches(tree, state)) {
|
||||
|
||||
@@ -101,6 +101,8 @@ public final class JUnitMethodDeclaration extends BugChecker implements MethodTr
|
||||
.build());
|
||||
}
|
||||
|
||||
// XXX: Consider dropping leading underscores that otherwise result when canonicalizing
|
||||
// `test_some_method_name`.
|
||||
private static Optional<String> tryCanonicalizeMethodName(MethodSymbol symbol) {
|
||||
return Optional.of(symbol.getQualifiedName().toString())
|
||||
.filter(name -> name.startsWith(TEST_PREFIX))
|
||||
|
||||
@@ -232,7 +232,7 @@ public final class JUnitValueSource extends BugChecker implements MethodTreeMatc
|
||||
@Override
|
||||
public @Nullable Void visitReturn(ReturnTree node, @Nullable Void unused) {
|
||||
returnExpressions.add(node.getExpression());
|
||||
return super.visitReturn(node, unused);
|
||||
return super.visitReturn(node, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Comparators;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.ErrorProneFlags;
|
||||
import com.google.errorprone.VisitorState;
|
||||
@@ -34,10 +35,8 @@ import com.sun.source.tree.Tree;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import javax.inject.Inject;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@@ -163,7 +162,12 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
|
||||
|
||||
/* For now we don't force sorting on numeric types. */
|
||||
return Stream.of(
|
||||
symtab.annotationType, symtab.classType, symtab.enumSym.type, symtab.stringType)
|
||||
symtab.annotationType,
|
||||
symtab.booleanType,
|
||||
symtab.charType,
|
||||
symtab.classType,
|
||||
symtab.enumSym.type,
|
||||
symtab.stringType)
|
||||
.anyMatch(t -> ASTHelpers.isSubtype(elemType, t, state));
|
||||
}
|
||||
|
||||
@@ -192,7 +196,7 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
|
||||
@Override
|
||||
public @Nullable Void visitIdentifier(IdentifierTree node, @Nullable Void unused) {
|
||||
nodes.add(ImmutableList.of(node.getName().toString()));
|
||||
return super.visitIdentifier(node, unused);
|
||||
return super.visitIdentifier(node, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -203,13 +207,13 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
|
||||
? STRING_ARGUMENT_SPLITTER.splitToStream(str).collect(toImmutableList())
|
||||
: ImmutableList.of(String.valueOf(value)));
|
||||
|
||||
return super.visitLiteral(node, unused);
|
||||
return super.visitLiteral(node, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitPrimitiveType(PrimitiveTypeTree node, @Nullable Void unused) {
|
||||
nodes.add(ImmutableList.of(node.getPrimitiveTypeKind().toString()));
|
||||
return super.visitPrimitiveType(node, unused);
|
||||
return super.visitPrimitiveType(node, null);
|
||||
}
|
||||
}.scan(array, null);
|
||||
|
||||
@@ -225,10 +229,8 @@ public final class LexicographicalAnnotationAttributeListing extends BugChecker
|
||||
excludedAnnotations(flags));
|
||||
}
|
||||
|
||||
private static ImmutableList<String> excludedAnnotations(ErrorProneFlags flags) {
|
||||
Set<String> exclusions = new HashSet<>();
|
||||
exclusions.addAll(Flags.getList(flags, EXCLUDED_ANNOTATIONS_FLAG));
|
||||
exclusions.addAll(BLACKLISTED_ANNOTATIONS);
|
||||
return ImmutableList.copyOf(exclusions);
|
||||
private static ImmutableSet<String> excludedAnnotations(ErrorProneFlags flags) {
|
||||
return Sets.union(BLACKLISTED_ANNOTATIONS, Flags.getSet(flags, EXCLUDED_ANNOTATIONS_FLAG))
|
||||
.immutableCopy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ public final class NonStaticImport extends BugChecker implements CompilationUnit
|
||||
}
|
||||
}
|
||||
|
||||
return super.visitIdentifier(node, unused);
|
||||
return super.visitIdentifier(node, null);
|
||||
}
|
||||
}.scan(tree, null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.NONE;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.PERFORMANCE;
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.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.refaster.Refaster;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import tech.picnic.errorprone.refaster.matchers.RequiresComputation;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that flags arguments to {@link Optional#orElse(Object)} that should be
|
||||
* deferred using {@link Optional#orElseGet(Supplier)}.
|
||||
*
|
||||
* <p>The suggested fix assumes that the argument to {@code orElse} does not have side effects. If
|
||||
* it does, the suggested fix changes the program's semantics. Such fragile code must instead be
|
||||
* refactored such that the side-effectful code does not appear accidental.
|
||||
*/
|
||||
// XXX: This rule may introduce a compilation error: the `value` expression may reference a
|
||||
// non-effectively final variable, which is not allowed in the replacement lambda expression.
|
||||
// Review whether a `@Matcher` can be used to avoid this.
|
||||
// XXX: Once the `MethodReferenceUsageCheck` bug checker becomes generally usable, consider leaving
|
||||
// the method reference cleanup to that check, and express the remainder of the logic in this class
|
||||
// using a Refaster template, i.c.w. a `@NotMatches(RequiresComputation.class)` constraint.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary =
|
||||
"""
|
||||
Prefer `Optional#orElseGet` over `Optional#orElse` if the fallback requires additional \
|
||||
computation""",
|
||||
linkType = NONE,
|
||||
severity = WARNING,
|
||||
tags = PERFORMANCE)
|
||||
public final class OptionalOrElseGet extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> REQUIRES_COMPUTATION = new RequiresComputation();
|
||||
private static final Matcher<ExpressionTree> OPTIONAL_OR_ELSE_METHOD =
|
||||
instanceMethod().onExactClass(Optional.class.getCanonicalName()).namedAnyOf("orElse");
|
||||
// XXX: Also exclude invocations of `@Placeholder`-annotated methods.
|
||||
private static final Matcher<ExpressionTree> REFASTER_METHOD =
|
||||
staticMethod().onClass(Refaster.class.getCanonicalName());
|
||||
|
||||
/** Instantiates a new {@link OptionalOrElseGet} instance. */
|
||||
public OptionalOrElseGet() {}
|
||||
|
||||
@Override
|
||||
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
|
||||
if (!OPTIONAL_OR_ELSE_METHOD.matches(tree, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
ExpressionTree argument = Iterables.getOnlyElement(tree.getArguments());
|
||||
if (!REQUIRES_COMPUTATION.matches(argument, state)
|
||||
|| REFASTER_METHOD.matches(argument, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a match. Construct the method reference or lambda expression to be passed to the
|
||||
* replacement `#orElseGet` invocation.
|
||||
*/
|
||||
String newArgument =
|
||||
tryMethodReferenceConversion(argument, state)
|
||||
.orElseGet(() -> "() -> " + SourceCode.treeToString(argument, state));
|
||||
|
||||
/* Construct the suggested fix, replacing the method invocation and its argument. */
|
||||
SuggestedFix fix =
|
||||
SuggestedFix.builder()
|
||||
.merge(SuggestedFixes.renameMethodInvocation(tree, "orElseGet", state))
|
||||
.replace(argument, newArgument)
|
||||
.build();
|
||||
|
||||
return describeMatch(tree, fix);
|
||||
}
|
||||
|
||||
/** Returns the nullary method reference matching the given expression, if any. */
|
||||
private static Optional<String> tryMethodReferenceConversion(
|
||||
ExpressionTree tree, VisitorState state) {
|
||||
if (!(tree instanceof MethodInvocationTree methodInvocation)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (!methodInvocation.getArguments().isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (!(methodInvocation.getMethodSelect() instanceof MemberSelectTree memberSelect)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (REQUIRES_COMPUTATION.matches(memberSelect.getExpression(), state)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(
|
||||
SourceCode.treeToString(memberSelect.getExpression(), state)
|
||||
+ "::"
|
||||
+ (methodInvocation.getTypeArguments().isEmpty()
|
||||
? ""
|
||||
: methodInvocation.getTypeArguments().stream()
|
||||
.map(arg -> SourceCode.treeToString(arg, state))
|
||||
.collect(joining(",", "<", ">")))
|
||||
+ memberSelect.getIdentifier());
|
||||
}
|
||||
}
|
||||
@@ -378,11 +378,11 @@ public final class RedundantStringConversion extends BugChecker
|
||||
|
||||
private static Matcher<MethodInvocationTree> createConversionMethodMatcher(
|
||||
ErrorProneFlags flags) {
|
||||
// XXX: ErrorProneFlags#getList splits by comma, but method signatures may also contain commas.
|
||||
// For this class methods accepting more than one argument are not valid, but still: not nice.
|
||||
// XXX: `Flags#getSet` splits by comma, but method signatures may also contain commas. For this
|
||||
// class methods accepting more than one argument are not valid, but still: not nice.
|
||||
return anyOf(
|
||||
WELL_KNOWN_STRING_CONVERSION_METHODS,
|
||||
new MethodMatcherFactory()
|
||||
.create(Flags.getList(flags, EXTRA_STRING_CONVERSION_METHODS_FLAG)));
|
||||
.create(Flags.getSet(flags, EXTRA_STRING_CONVERSION_METHODS_FLAG)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION;
|
||||
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.LiteralTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.LiteralTree;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/** A {@link BugChecker} that flags string constants with extraneous escaping. */
|
||||
// XXX: Also cover `\"` sequences inside text blocks. Note that this requires a more subtle
|
||||
// approach, as double-quote characters will need to remain escaped if removing the backslash would
|
||||
// create a new sequence of three or more double-quotes. (TBD whether we'd like to enforce a
|
||||
// "preferred" approach to escaping, e.g. by always escaping the last of a triplet, such that the
|
||||
// over-all number of escaped characters is minimized.)
|
||||
// XXX: Also flag `'\"'` char literals.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Inside string expressions single quotes do not need to be escaped",
|
||||
link = BUG_PATTERNS_BASE_URL + "RedundantStringEscape",
|
||||
linkType = CUSTOM,
|
||||
severity = SUGGESTION,
|
||||
tags = SIMPLIFICATION)
|
||||
public final class RedundantStringEscape extends BugChecker implements LiteralTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Instantiates a new {@link RedundantStringEscape} instance. */
|
||||
public RedundantStringEscape() {}
|
||||
|
||||
@Override
|
||||
public Description matchLiteral(LiteralTree tree, VisitorState state) {
|
||||
String constant = ASTHelpers.constValue(tree, String.class);
|
||||
if (constant == null || constant.indexOf('\'') < 0) {
|
||||
/* Fast path: this isn't a string constant with a single quote. */
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
String source = SourceCode.treeToString(tree, state);
|
||||
if (!containsBannedEscapeSequence(source)) {
|
||||
/* Semi-fast path: this expression doesn't contain an escaped single quote. */
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
/* Slow path: suggest dropping the escape characters. */
|
||||
return describeMatch(tree, SuggestedFix.replace(tree, dropRedundantEscapeSequences(source)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given string constant source expression contains an escaped single quote.
|
||||
*
|
||||
* @implNote As the input is a literal Java string expression, it will start and end with a double
|
||||
* quote; as such any found backslash will not be the string's final character.
|
||||
*/
|
||||
private static boolean containsBannedEscapeSequence(String source) {
|
||||
for (int p = source.indexOf('\\'); p != -1; p = source.indexOf('\\', p + 2)) {
|
||||
if (source.charAt(p + 1) == '\'') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplifies the given string constant source expression by dropping the backslash preceding an
|
||||
* escaped single quote.
|
||||
*
|
||||
* @implNote Note that this method does not delegate to {@link
|
||||
* SourceCode#toStringConstantExpression}, as that operation may replace other Unicode
|
||||
* characters with their associated escape sequence.
|
||||
* @implNote As the input is a literal Java string expression, it will start and end with a double
|
||||
* quote; as such any found backslash will not be the string's final character.
|
||||
*/
|
||||
private static String dropRedundantEscapeSequences(String source) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
for (int p = 0; p < source.length(); p++) {
|
||||
char c = source.charAt(p);
|
||||
if (c != '\\' || source.charAt(p + 1) != '\'') {
|
||||
result.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,8 @@ import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.ErrorProneFlags;
|
||||
import com.google.errorprone.VisitorState;
|
||||
@@ -74,10 +74,10 @@ public final class RequestParamType extends BugChecker implements VariableTreeMa
|
||||
return allOf(
|
||||
annotations(AT_LEAST_ONE, isType("org.springframework.web.bind.annotation.RequestParam")),
|
||||
anyOf(isSubtypeOf(ImmutableCollection.class), isSubtypeOf(ImmutableMap.class)),
|
||||
not(isSubtypeOfAny(Flags.getList(flags, SUPPORTED_CUSTOM_TYPES_FLAG))));
|
||||
not(isSubtypeOfAny(Flags.getSet(flags, SUPPORTED_CUSTOM_TYPES_FLAG))));
|
||||
}
|
||||
|
||||
private static Matcher<Tree> isSubtypeOfAny(ImmutableList<String> inclusions) {
|
||||
private static Matcher<Tree> isSubtypeOfAny(ImmutableSet<String> inclusions) {
|
||||
return anyOf(
|
||||
inclusions.stream()
|
||||
.map(inclusion -> isSubtypeOf(Suppliers.typeFromString(inclusion)))
|
||||
|
||||
@@ -41,7 +41,7 @@ import tech.picnic.errorprone.utils.SourceCode;
|
||||
tags = LIKELY_ERROR)
|
||||
public final class Slf4jLogStatement extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> MARKER = isSubtypeOf("org.slf4j.Marker");
|
||||
private static final Matcher<ExpressionTree> SLF4J_MARKER = isSubtypeOf("org.slf4j.Marker");
|
||||
private static final Matcher<ExpressionTree> THROWABLE = isSubtypeOf(Throwable.class);
|
||||
private static final Matcher<ExpressionTree> SLF4J_LOGGER_INVOCATION =
|
||||
instanceMethod()
|
||||
@@ -71,7 +71,7 @@ public final class Slf4jLogStatement extends BugChecker implements MethodInvocat
|
||||
* SLF4J log statements may accept a "marker" as a first argument, before the format string.
|
||||
* We ignore such markers.
|
||||
*/
|
||||
int lTrim = MARKER.matches(args.get(0), state) ? 1 : 0;
|
||||
int lTrim = SLF4J_MARKER.matches(args.get(0), state) ? 1 : 0;
|
||||
/*
|
||||
* SLF4J treats the final argument to a log statement specially if it is a `Throwabe`: it
|
||||
* will always choose to render the associated stacktrace, even if the argument has a
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import static com.google.common.base.Verify.verify;
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.STYLE;
|
||||
import static com.google.errorprone.matchers.Matchers.allOf;
|
||||
import static com.google.errorprone.matchers.Matchers.classLiteral;
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.toType;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.ErrorProneFlags;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFix;
|
||||
import com.google.errorprone.fixes.SuggestedFixes;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.ModifiersTree;
|
||||
import com.sun.source.tree.Tree.Kind;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import java.util.EnumSet;
|
||||
import javax.inject.Inject;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import tech.picnic.errorprone.utils.MoreASTHelpers;
|
||||
|
||||
/** A {@link BugChecker} that flags non-canonical SLF4J logger declarations. */
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "SLF4J logger declarations should follow established best-practices",
|
||||
link = BUG_PATTERNS_BASE_URL + "Slf4jLoggerDeclaration",
|
||||
linkType = CUSTOM,
|
||||
severity = WARNING,
|
||||
tags = STYLE)
|
||||
@SuppressWarnings("java:S2160" /* Super class equality definition suffices. */)
|
||||
public final class Slf4jLoggerDeclaration extends BugChecker implements VariableTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> IS_GET_LOGGER =
|
||||
staticMethod().onDescendantOf("org.slf4j.LoggerFactory").named("getLogger");
|
||||
private static final String CANONICAL_STATIC_LOGGER_NAME_FLAG =
|
||||
"Slf4jLoggerDeclaration:CanonicalStaticLoggerName";
|
||||
private static final String DEFAULT_CANONICAL_LOGGER_NAME = "LOG";
|
||||
private static final Matcher<ExpressionTree> IS_STATIC_ENCLOSING_CLASS_REFERENCE =
|
||||
classLiteral(Slf4jLoggerDeclaration::isEnclosingClassReference);
|
||||
private static final Matcher<ExpressionTree> IS_DYNAMIC_ENCLOSING_CLASS_REFERENCE =
|
||||
toType(
|
||||
MethodInvocationTree.class,
|
||||
allOf(
|
||||
instanceMethod().anyClass().named("getClass").withNoParameters(),
|
||||
Slf4jLoggerDeclaration::getClassReceiverIsEnclosingClassInstance));
|
||||
private static final ImmutableSet<Modifier> INSTANCE_DECLARATION_MODIFIERS =
|
||||
Sets.immutableEnumSet(Modifier.PRIVATE, Modifier.FINAL);
|
||||
private static final ImmutableSet<Modifier> STATIC_DECLARATION_MODIFIERS =
|
||||
Sets.immutableEnumSet(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL);
|
||||
|
||||
private final String canonicalStaticFieldName;
|
||||
private final String canonicalInstanceFieldName;
|
||||
|
||||
/** Instantiates a default {@link Slf4jLoggerDeclaration} instance. */
|
||||
public Slf4jLoggerDeclaration() {
|
||||
this(ErrorProneFlags.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a customized {@link Slf4jLoggerDeclaration}.
|
||||
*
|
||||
* @param flags Any provided command line flags.
|
||||
*/
|
||||
@Inject
|
||||
Slf4jLoggerDeclaration(ErrorProneFlags flags) {
|
||||
canonicalStaticFieldName =
|
||||
flags.get(CANONICAL_STATIC_LOGGER_NAME_FLAG).orElse(DEFAULT_CANONICAL_LOGGER_NAME);
|
||||
canonicalInstanceFieldName =
|
||||
CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, canonicalStaticFieldName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Description matchVariable(VariableTree tree, VisitorState state) {
|
||||
ExpressionTree initializer = tree.getInitializer();
|
||||
if (!IS_GET_LOGGER.matches(initializer, state)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
ClassTree clazz = getEnclosingClass(state);
|
||||
ExpressionTree factoryArg =
|
||||
Iterables.getOnlyElement(((MethodInvocationTree) initializer).getArguments());
|
||||
|
||||
SuggestedFix.Builder fix = SuggestedFix.builder();
|
||||
|
||||
if (clazz.getModifiers().getFlags().contains(Modifier.ABSTRACT)
|
||||
&& IS_DYNAMIC_ENCLOSING_CLASS_REFERENCE.matches(factoryArg, state)) {
|
||||
/*
|
||||
* While generally we prefer `Logger` declarations to be static and named after their
|
||||
* enclosing class, we allow one exception: loggers in abstract classes with a name derived
|
||||
* from `getClass()`.
|
||||
*/
|
||||
suggestModifiers(tree, INSTANCE_DECLARATION_MODIFIERS, fix, state);
|
||||
suggestRename(tree, canonicalInstanceFieldName, fix, state);
|
||||
} else {
|
||||
suggestModifiers(
|
||||
tree,
|
||||
clazz.getKind() == Kind.INTERFACE ? ImmutableSet.of() : STATIC_DECLARATION_MODIFIERS,
|
||||
fix,
|
||||
state);
|
||||
suggestRename(tree, canonicalStaticFieldName, fix, state);
|
||||
|
||||
if (!MoreASTHelpers.isStringTyped(factoryArg, state)
|
||||
&& !IS_STATIC_ENCLOSING_CLASS_REFERENCE.matches(factoryArg, state)) {
|
||||
/*
|
||||
* Loggers with a custom string name are generally "special", but those with a name derived
|
||||
* from a class other than the one that encloses it are likely in error.
|
||||
*/
|
||||
fix.merge(SuggestedFix.replace(factoryArg, clazz.getSimpleName() + ".class"));
|
||||
}
|
||||
}
|
||||
|
||||
return fix.isEmpty() ? Description.NO_MATCH : describeMatch(tree, fix.build());
|
||||
}
|
||||
|
||||
private static void suggestModifiers(
|
||||
VariableTree tree,
|
||||
ImmutableSet<Modifier> modifiers,
|
||||
SuggestedFix.Builder fixBuilder,
|
||||
VisitorState state) {
|
||||
ModifiersTree modifiersTree =
|
||||
requireNonNull(ASTHelpers.getModifiers(tree), "`VariableTree` must have modifiers");
|
||||
SuggestedFixes.addModifiers(tree, modifiersTree, state, modifiers).ifPresent(fixBuilder::merge);
|
||||
SuggestedFixes.removeModifiers(
|
||||
modifiersTree, state, Sets.difference(EnumSet.allOf(Modifier.class), modifiers))
|
||||
.ifPresent(fixBuilder::merge);
|
||||
}
|
||||
|
||||
private static void suggestRename(
|
||||
VariableTree variableTree, String name, SuggestedFix.Builder fixBuilder, VisitorState state) {
|
||||
if (!variableTree.getName().contentEquals(name)) {
|
||||
fixBuilder.merge(SuggestedFixes.renameVariable(variableTree, name, state));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isEnclosingClassReference(ExpressionTree tree, VisitorState state) {
|
||||
return ASTHelpers.getSymbol(getEnclosingClass(state)).equals(ASTHelpers.getSymbol(tree));
|
||||
}
|
||||
|
||||
private static boolean getClassReceiverIsEnclosingClassInstance(
|
||||
MethodInvocationTree getClassInvocationTree, VisitorState state) {
|
||||
ExpressionTree receiver = ASTHelpers.getReceiver(getClassInvocationTree);
|
||||
if (receiver == null) {
|
||||
/*
|
||||
* Method invocations without an explicit receiver either involve static methods (possibly
|
||||
* statically imported), or instance methods invoked on the enclosing class. As the given
|
||||
* `getClassInvocationTree` is guaranteed to be a nullary `#getClass()` invocation, the latter
|
||||
* must be the case.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
Symbol symbol = ASTHelpers.getSymbol(receiver);
|
||||
return symbol != null
|
||||
&& symbol.asType().tsym.equals(ASTHelpers.getSymbol(getEnclosingClass(state)));
|
||||
}
|
||||
|
||||
private static ClassTree getEnclosingClass(VisitorState state) {
|
||||
ClassTree clazz = state.findEnclosing(ClassTree.class);
|
||||
// XXX: Review whether we should relax this constraint in the face of so-called anonymous
|
||||
// classes. See
|
||||
// https://docs.oracle.com/en/java/javase/23/language/implicitly-declared-classes-and-instance-main-methods.html
|
||||
verify(clazz != null, "Variable not defined inside class");
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import com.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.util.Constants;
|
||||
import java.util.Formattable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -37,7 +36,9 @@ import tech.picnic.errorprone.utils.SourceCode;
|
||||
*/
|
||||
// XXX: What about `v1 + "sep" + v2` and similar expressions? Do we want to rewrite those to
|
||||
// `String.join`, or should some `String.join` invocations be rewritten to use the `+` operator?
|
||||
// (The latter suggestion would conflict with the `FormatStringConcatenation` check.)
|
||||
// (The latter suggestion would conflict with the `FormatStringConcatenation` check, but does make
|
||||
// more sense when `"sep"` is a long string. Similarly for `String.format("%s some long text %s",
|
||||
// arg1, arg2)`.)
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Prefer `String#join` over `String#format`",
|
||||
@@ -150,7 +151,7 @@ public final class StringJoin extends BugChecker implements MethodInvocationTree
|
||||
SuggestedFix.Builder fix =
|
||||
SuggestedFix.builder()
|
||||
.replace(tree.getMethodSelect(), "String.join")
|
||||
.replace(arguments.next(), Constants.format(separator));
|
||||
.replace(arguments.next(), SourceCode.toStringConstantExpression(separator, state));
|
||||
|
||||
while (arguments.hasNext()) {
|
||||
ExpressionTree argument = arguments.next();
|
||||
|
||||
@@ -3,9 +3,6 @@ package tech.picnic.errorprone.refasterrules;
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultiset;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Multiset;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
@@ -15,7 +12,6 @@ import com.google.errorprone.refaster.annotation.Matches;
|
||||
import com.google.errorprone.refaster.annotation.NotMatches;
|
||||
import com.google.errorprone.refaster.annotation.Repeated;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -204,32 +200,8 @@ final class AssertJRules {
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T element) {
|
||||
return Refaster.anyOf(
|
||||
iterAssert.containsAnyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(element),
|
||||
Arrays.asList(element),
|
||||
ImmutableSet.of(element),
|
||||
ImmutableMultiset.of(element))),
|
||||
iterAssert.containsAnyOf(element),
|
||||
iterAssert.containsAll(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(element),
|
||||
Arrays.asList(element),
|
||||
ImmutableSet.of(element),
|
||||
ImmutableMultiset.of(element))),
|
||||
iterAssert.containsSequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(element),
|
||||
Arrays.asList(element),
|
||||
ImmutableSet.of(element),
|
||||
ImmutableMultiset.of(element))),
|
||||
iterAssert.containsSequence(element),
|
||||
iterAssert.containsSubsequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(element),
|
||||
Arrays.asList(element),
|
||||
ImmutableSet.of(element),
|
||||
ImmutableMultiset.of(element))),
|
||||
iterAssert.containsSubsequence(element));
|
||||
}
|
||||
|
||||
@@ -244,20 +216,7 @@ final class AssertJRules {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T element) {
|
||||
return Refaster.anyOf(
|
||||
iterAssert.doesNotContainAnyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(element),
|
||||
Arrays.asList(element),
|
||||
ImmutableSet.of(element),
|
||||
ImmutableMultiset.of(element))),
|
||||
iterAssert.doesNotContainSequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(element),
|
||||
Arrays.asList(element),
|
||||
ImmutableSet.of(element),
|
||||
ImmutableMultiset.of(element))),
|
||||
iterAssert.doesNotContainSequence(element));
|
||||
return iterAssert.doesNotContainSequence(element);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -270,25 +229,7 @@ final class AssertJRules {
|
||||
static final class ObjectEnumerableContainsExactlyOneElement<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T element) {
|
||||
return Refaster.anyOf(
|
||||
iterAssert.containsExactlyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(element),
|
||||
Arrays.asList(element),
|
||||
ImmutableSet.of(element),
|
||||
ImmutableMultiset.of(element))),
|
||||
iterAssert.containsExactlyInAnyOrderElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(element),
|
||||
Arrays.asList(element),
|
||||
ImmutableSet.of(element),
|
||||
ImmutableMultiset.of(element))));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> before2(
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, @NotMatches(IsArray.class) T element) {
|
||||
return iterAssert.containsExactlyInAnyOrder(element);
|
||||
}
|
||||
@@ -313,42 +254,6 @@ final class AssertJRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsOneDistinctElement<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T element) {
|
||||
return iterAssert.hasSameElementsAs(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(element),
|
||||
Arrays.asList(element),
|
||||
ImmutableSet.of(element),
|
||||
ImmutableMultiset.of(element)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T element) {
|
||||
return iterAssert.containsOnly(element);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableIsSubsetOfOneElement<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T element) {
|
||||
return iterAssert.isSubsetOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(element),
|
||||
Arrays.asList(element),
|
||||
ImmutableSet.of(element),
|
||||
ImmutableMultiset.of(element)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T element) {
|
||||
return iterAssert.isSubsetOf(element);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Iterable
|
||||
//
|
||||
@@ -359,6 +264,7 @@ final class AssertJRules {
|
||||
Refaster.anyOf(
|
||||
assertThat(iterable).hasSize(0),
|
||||
assertThat(iterable.iterator().hasNext()).isFalse(),
|
||||
assertThat(iterable.iterator()).isExhausted(),
|
||||
assertThat(Iterables.size(iterable)).isEqualTo(0L),
|
||||
assertThat(Iterables.size(iterable)).isNotPositive());
|
||||
}
|
||||
@@ -1155,824 +1061,6 @@ final class AssertJRules {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// BELOW: Generated code.
|
||||
|
||||
//
|
||||
// ObjectEnumerableAssert: containsAnyOf
|
||||
//
|
||||
|
||||
static final class ObjectEnumerableContainsAnyOfTwoElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.containsAnyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2),
|
||||
Arrays.asList(e1, e2),
|
||||
ImmutableSet.of(e1, e2),
|
||||
ImmutableMultiset.of(e1, e2)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.containsAnyOf(e1, e2);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsAnyOfThreeElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.containsAnyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3),
|
||||
Arrays.asList(e1, e2, e3),
|
||||
ImmutableSet.of(e1, e2, e3),
|
||||
ImmutableMultiset.of(e1, e2, e3)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.containsAnyOf(e1, e2, e3);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsAnyOfFourElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.containsAnyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4),
|
||||
Arrays.asList(e1, e2, e3, e4),
|
||||
ImmutableSet.of(e1, e2, e3, e4),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.containsAnyOf(e1, e2, e3, e4);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Add variants for 6+ elements?
|
||||
static final class ObjectEnumerableContainsAnyOfFiveElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.containsAnyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4, e5),
|
||||
Arrays.asList(e1, e2, e3, e4, e5),
|
||||
ImmutableSet.of(e1, e2, e3, e4, e5),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.containsAnyOf(e1, e2, e3, e4, e5);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ObjectEnumerableAssert: contains
|
||||
//
|
||||
|
||||
static final class ObjectEnumerableContainsTwoElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.containsAll(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2),
|
||||
Arrays.asList(e1, e2),
|
||||
ImmutableSet.of(e1, e2),
|
||||
ImmutableMultiset.of(e1, e2)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.contains(e1, e2);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsThreeElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.containsAll(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3),
|
||||
Arrays.asList(e1, e2, e3),
|
||||
ImmutableSet.of(e1, e2, e3),
|
||||
ImmutableMultiset.of(e1, e2, e3)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.contains(e1, e2, e3);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsFourElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.containsAll(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4),
|
||||
Arrays.asList(e1, e2, e3, e4),
|
||||
ImmutableSet.of(e1, e2, e3, e4),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.contains(e1, e2, e3, e4);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Add variants for 6+ elements?
|
||||
static final class ObjectEnumerableContainsFiveElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.containsAll(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4, e5),
|
||||
Arrays.asList(e1, e2, e3, e4, e5),
|
||||
ImmutableSet.of(e1, e2, e3, e4, e5),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.contains(e1, e2, e3, e4, e5);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ObjectEnumerableAssert: containsExactly
|
||||
//
|
||||
|
||||
static final class ObjectEnumerableContainsExactlyTwoElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.containsExactlyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2),
|
||||
Arrays.asList(e1, e2),
|
||||
ImmutableSet.of(e1, e2),
|
||||
ImmutableMultiset.of(e1, e2)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.containsExactly(e1, e2);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsExactlyThreeElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.containsExactlyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3),
|
||||
Arrays.asList(e1, e2, e3),
|
||||
ImmutableSet.of(e1, e2, e3),
|
||||
ImmutableMultiset.of(e1, e2, e3)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.containsExactly(e1, e2, e3);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsExactlyFourElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.containsExactlyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4),
|
||||
Arrays.asList(e1, e2, e3, e4),
|
||||
ImmutableSet.of(e1, e2, e3, e4),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.containsExactly(e1, e2, e3, e4);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Add variants for 6+ elements?
|
||||
static final class ObjectEnumerableContainsExactlyFiveElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.containsExactlyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4, e5),
|
||||
Arrays.asList(e1, e2, e3, e4, e5),
|
||||
ImmutableSet.of(e1, e2, e3, e4, e5),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.containsExactly(e1, e2, e3, e4, e5);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ObjectEnumerableAssert: containsExactlyInAnyOrder
|
||||
//
|
||||
|
||||
static final class ObjectEnumerableContainsExactlyInAnyOrderTwoElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.containsExactlyInAnyOrderElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2),
|
||||
Arrays.asList(e1, e2),
|
||||
ImmutableSet.of(e1, e2),
|
||||
ImmutableMultiset.of(e1, e2)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.containsExactlyInAnyOrder(e1, e2);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsExactlyInAnyOrderThreeElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.containsExactlyInAnyOrderElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3),
|
||||
Arrays.asList(e1, e2, e3),
|
||||
ImmutableSet.of(e1, e2, e3),
|
||||
ImmutableMultiset.of(e1, e2, e3)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.containsExactlyInAnyOrder(e1, e2, e3);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsExactlyInAnyOrderFourElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.containsExactlyInAnyOrderElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4),
|
||||
Arrays.asList(e1, e2, e3, e4),
|
||||
ImmutableSet.of(e1, e2, e3, e4),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.containsExactlyInAnyOrder(e1, e2, e3, e4);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Add variants for 6+ elements?
|
||||
static final class ObjectEnumerableContainsExactlyInAnyOrderFiveElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.containsExactlyInAnyOrderElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4, e5),
|
||||
Arrays.asList(e1, e2, e3, e4, e5),
|
||||
ImmutableSet.of(e1, e2, e3, e4, e5),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.containsExactlyInAnyOrder(e1, e2, e3, e4, e5);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ObjectEnumerableAssert: containsSequence
|
||||
//
|
||||
|
||||
static final class ObjectEnumerableContainsSequenceTwoElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.containsSequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2),
|
||||
Arrays.asList(e1, e2),
|
||||
ImmutableSet.of(e1, e2),
|
||||
ImmutableMultiset.of(e1, e2)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.containsSequence(e1, e2);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsSequenceThreeElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.containsSequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3),
|
||||
Arrays.asList(e1, e2, e3),
|
||||
ImmutableSet.of(e1, e2, e3),
|
||||
ImmutableMultiset.of(e1, e2, e3)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.containsSequence(e1, e2, e3);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsSequenceFourElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.containsSequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4),
|
||||
Arrays.asList(e1, e2, e3, e4),
|
||||
ImmutableSet.of(e1, e2, e3, e4),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.containsSequence(e1, e2, e3, e4);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Add variants for 6+ elements?
|
||||
static final class ObjectEnumerableContainsSequenceFiveElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.containsSequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4, e5),
|
||||
Arrays.asList(e1, e2, e3, e4, e5),
|
||||
ImmutableSet.of(e1, e2, e3, e4, e5),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.containsSequence(e1, e2, e3, e4, e5);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ObjectEnumerableAssert: containsSubsequence
|
||||
//
|
||||
|
||||
static final class ObjectEnumerableContainsSubsequenceTwoElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.containsSubsequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2),
|
||||
Arrays.asList(e1, e2),
|
||||
ImmutableSet.of(e1, e2),
|
||||
ImmutableMultiset.of(e1, e2)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.containsSubsequence(e1, e2);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsSubsequenceThreeElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.containsSubsequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3),
|
||||
Arrays.asList(e1, e2, e3),
|
||||
ImmutableSet.of(e1, e2, e3),
|
||||
ImmutableMultiset.of(e1, e2, e3)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.containsSubsequence(e1, e2, e3);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsSubsequenceFourElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.containsSubsequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4),
|
||||
Arrays.asList(e1, e2, e3, e4),
|
||||
ImmutableSet.of(e1, e2, e3, e4),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.containsSubsequence(e1, e2, e3, e4);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Add variants for 6+ elements?
|
||||
static final class ObjectEnumerableContainsSubsequenceFiveElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.containsSubsequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4, e5),
|
||||
Arrays.asList(e1, e2, e3, e4, e5),
|
||||
ImmutableSet.of(e1, e2, e3, e4, e5),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.containsSubsequence(e1, e2, e3, e4, e5);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ObjectEnumerableAssert: doesNotContain
|
||||
//
|
||||
|
||||
static final class ObjectEnumerableDoesNotContainTwoElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.doesNotContainAnyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2),
|
||||
Arrays.asList(e1, e2),
|
||||
ImmutableSet.of(e1, e2),
|
||||
ImmutableMultiset.of(e1, e2)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.doesNotContain(e1, e2);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableDoesNotContainThreeElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.doesNotContainAnyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3),
|
||||
Arrays.asList(e1, e2, e3),
|
||||
ImmutableSet.of(e1, e2, e3),
|
||||
ImmutableMultiset.of(e1, e2, e3)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.doesNotContain(e1, e2, e3);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableDoesNotContainFourElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.doesNotContainAnyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4),
|
||||
Arrays.asList(e1, e2, e3, e4),
|
||||
ImmutableSet.of(e1, e2, e3, e4),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.doesNotContain(e1, e2, e3, e4);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Add variants for 6+ elements?
|
||||
static final class ObjectEnumerableDoesNotContainFiveElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.doesNotContainAnyElementsOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4, e5),
|
||||
Arrays.asList(e1, e2, e3, e4, e5),
|
||||
ImmutableSet.of(e1, e2, e3, e4, e5),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.doesNotContain(e1, e2, e3, e4, e5);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ObjectEnumerableAssert: doesNotContainSequence
|
||||
//
|
||||
|
||||
static final class ObjectEnumerableDoesNotContainSequenceTwoElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.doesNotContainSequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2),
|
||||
Arrays.asList(e1, e2),
|
||||
ImmutableSet.of(e1, e2),
|
||||
ImmutableMultiset.of(e1, e2)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.doesNotContainSequence(e1, e2);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableDoesNotContainSequenceThreeElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.doesNotContainSequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3),
|
||||
Arrays.asList(e1, e2, e3),
|
||||
ImmutableSet.of(e1, e2, e3),
|
||||
ImmutableMultiset.of(e1, e2, e3)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.doesNotContainSequence(e1, e2, e3);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableDoesNotContainSequenceFourElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.doesNotContainSequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4),
|
||||
Arrays.asList(e1, e2, e3, e4),
|
||||
ImmutableSet.of(e1, e2, e3, e4),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.doesNotContainSequence(e1, e2, e3, e4);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Add variants for 6+ elements?
|
||||
static final class ObjectEnumerableDoesNotContainSequenceFiveElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.doesNotContainSequence(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4, e5),
|
||||
Arrays.asList(e1, e2, e3, e4, e5),
|
||||
ImmutableSet.of(e1, e2, e3, e4, e5),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.doesNotContainSequence(e1, e2, e3, e4, e5);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ObjectEnumerableAssert: containsOnly
|
||||
//
|
||||
|
||||
static final class ObjectEnumerableContainsOnlyTwoElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.hasSameElementsAs(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2),
|
||||
Arrays.asList(e1, e2),
|
||||
ImmutableSet.of(e1, e2),
|
||||
ImmutableMultiset.of(e1, e2)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.containsOnly(e1, e2);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsOnlyThreeElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.hasSameElementsAs(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3),
|
||||
Arrays.asList(e1, e2, e3),
|
||||
ImmutableSet.of(e1, e2, e3),
|
||||
ImmutableMultiset.of(e1, e2, e3)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.containsOnly(e1, e2, e3);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableContainsOnlyFourElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.hasSameElementsAs(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4),
|
||||
Arrays.asList(e1, e2, e3, e4),
|
||||
ImmutableSet.of(e1, e2, e3, e4),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.containsOnly(e1, e2, e3, e4);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Add variants for 6+ elements?
|
||||
static final class ObjectEnumerableContainsOnlyFiveElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.hasSameElementsAs(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4, e5),
|
||||
Arrays.asList(e1, e2, e3, e4, e5),
|
||||
ImmutableSet.of(e1, e2, e3, e4, e5),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.containsOnly(e1, e2, e3, e4, e5);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ObjectEnumerableAssert: isSubsetOf
|
||||
//
|
||||
|
||||
static final class ObjectEnumerableIsSubsetOfTwoElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.isSubsetOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2),
|
||||
Arrays.asList(e1, e2),
|
||||
ImmutableSet.of(e1, e2),
|
||||
ImmutableMultiset.of(e1, e2)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2) {
|
||||
return iterAssert.isSubsetOf(e1, e2);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableIsSubsetOfThreeElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.isSubsetOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3),
|
||||
Arrays.asList(e1, e2, e3),
|
||||
ImmutableSet.of(e1, e2, e3),
|
||||
ImmutableMultiset.of(e1, e2, e3)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3) {
|
||||
return iterAssert.isSubsetOf(e1, e2, e3);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ObjectEnumerableIsSubsetOfFourElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.isSubsetOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4),
|
||||
Arrays.asList(e1, e2, e3, e4),
|
||||
ImmutableSet.of(e1, e2, e3, e4),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4) {
|
||||
return iterAssert.isSubsetOf(e1, e2, e3, e4);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Add variants for 6+ elements?
|
||||
static final class ObjectEnumerableIsSubsetOfFiveElements<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
ObjectEnumerableAssert<?, S> before(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.isSubsetOf(
|
||||
Refaster.anyOf(
|
||||
ImmutableList.of(e1, e2, e3, e4, e5),
|
||||
Arrays.asList(e1, e2, e3, e4, e5),
|
||||
ImmutableSet.of(e1, e2, e3, e4, e5),
|
||||
ImmutableMultiset.of(e1, e2, e3, e4, e5)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ObjectEnumerableAssert<?, S> after(
|
||||
ObjectEnumerableAssert<?, S> iterAssert, T e1, T e2, T e3, T e4, T e5) {
|
||||
return iterAssert.isSubsetOf(e1, e2, e3, e4, e5);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Above: Generated code.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Organize the code below.
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.AbstractBooleanAssert;
|
||||
import org.assertj.core.api.AbstractStringAssert;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
@@ -69,6 +70,32 @@ final class AssertJStringRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatStringContains {
|
||||
@BeforeTemplate
|
||||
AbstractBooleanAssert<?> before(String string, String substring) {
|
||||
return assertThat(string.contains(substring)).isTrue();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractStringAssert<?> after(String string, String substring) {
|
||||
return assertThat(string).contains(substring);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatStringDoesNotContain {
|
||||
@BeforeTemplate
|
||||
AbstractBooleanAssert<?> before(String string, String substring) {
|
||||
return assertThat(string.contains(substring)).isFalse();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractStringAssert<?> after(String string, String substring) {
|
||||
return assertThat(string).doesNotContain(substring);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatMatches {
|
||||
@BeforeTemplate
|
||||
AbstractAssert<?, ?> before(String string, String regex) {
|
||||
|
||||
@@ -7,7 +7,10 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatNullPointerException;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.throwable;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.type;
|
||||
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Repeated;
|
||||
@@ -16,6 +19,7 @@ import java.io.IOException;
|
||||
import org.assertj.core.api.AbstractObjectAssert;
|
||||
import org.assertj.core.api.AbstractThrowableAssert;
|
||||
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
|
||||
import org.assertj.core.api.ThrowableAssertAlternative;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/**
|
||||
@@ -31,6 +35,21 @@ import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
final class AssertJThrowingCallableRules {
|
||||
private AssertJThrowingCallableRules() {}
|
||||
|
||||
static final class AssertThatThrownByIsInstanceOf<T extends Throwable> {
|
||||
@BeforeTemplate
|
||||
void before(ThrowingCallable throwingCallable, Class<T> exceptionType) {
|
||||
Refaster.anyOf(
|
||||
assertThatThrownBy(throwingCallable).asInstanceOf(throwable(exceptionType)),
|
||||
assertThatThrownBy(throwingCallable).asInstanceOf(type(exceptionType)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after(ThrowingCallable throwingCallable, Class<T> exceptionType) {
|
||||
assertThatThrownBy(throwingCallable).isInstanceOf(exceptionType);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIllegalArgumentException {
|
||||
@BeforeTemplate
|
||||
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable) {
|
||||
@@ -61,6 +80,27 @@ final class AssertJThrowingCallableRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIllegalArgumentExceptionRootCauseHasMessage {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByIllegalArgumentException" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatIllegalArgumentException()
|
||||
.isThrownBy(throwingCallable)
|
||||
.havingRootCause()
|
||||
.withMessage(message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.rootCause()
|
||||
.hasMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIllegalArgumentExceptionHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
@@ -171,6 +211,27 @@ final class AssertJThrowingCallableRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIllegalStateExceptionRootCauseHasMessage {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByIllegalStateException" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatIllegalStateException()
|
||||
.isThrownBy(throwingCallable)
|
||||
.havingRootCause()
|
||||
.withMessage(message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.rootCause()
|
||||
.hasMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIllegalStateExceptionHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
@@ -279,6 +340,27 @@ final class AssertJThrowingCallableRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByNullPointerExceptionRootCauseHasMessage {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByNullPointerException" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatNullPointerException()
|
||||
.isThrownBy(throwingCallable)
|
||||
.havingRootCause()
|
||||
.withMessage(message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(NullPointerException.class)
|
||||
.rootCause()
|
||||
.hasMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByNullPointerExceptionHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
@@ -386,6 +468,26 @@ final class AssertJThrowingCallableRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIOExceptionRootCauseHasMessage {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownByIOException" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatIOException()
|
||||
.isThrownBy(throwingCallable)
|
||||
.havingRootCause()
|
||||
.withMessage(message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(ThrowingCallable throwingCallable, String message) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(IOException.class)
|
||||
.rootCause()
|
||||
.hasMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByIOExceptionHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownByIOException" /* This is a more specific template. */)
|
||||
@@ -452,24 +554,24 @@ final class AssertJThrowingCallableRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownBy {
|
||||
static final class AssertThatThrownByAsInstanceOfThrowable<T extends Throwable> {
|
||||
@BeforeTemplate
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable, Class<? extends Throwable> exceptionType) {
|
||||
ThrowableAssertAlternative<T> before(
|
||||
ThrowingCallable throwingCallable, Class<T> exceptionType) {
|
||||
return assertThatExceptionOfType(exceptionType).isThrownBy(throwingCallable);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(
|
||||
ThrowingCallable throwingCallable, Class<? extends Throwable> exceptionType) {
|
||||
return assertThatThrownBy(throwingCallable).isInstanceOf(exceptionType);
|
||||
AbstractThrowableAssert<?, T> after(ThrowingCallable throwingCallable, Class<T> exceptionType) {
|
||||
return assertThatThrownBy(throwingCallable).asInstanceOf(throwable(exceptionType));
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByHasMessage {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable,
|
||||
Class<? extends Throwable> exceptionType,
|
||||
@@ -489,9 +591,37 @@ final class AssertJThrowingCallableRules {
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByRootCauseHasMessage {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable,
|
||||
Class<? extends Throwable> exceptionType,
|
||||
String message) {
|
||||
return assertThatExceptionOfType(exceptionType)
|
||||
.isThrownBy(throwingCallable)
|
||||
.havingRootCause()
|
||||
.withMessage(message);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
AbstractObjectAssert<?, ?> after(
|
||||
ThrowingCallable throwingCallable,
|
||||
Class<? extends Throwable> exceptionType,
|
||||
String message) {
|
||||
return assertThatThrownBy(throwingCallable)
|
||||
.isInstanceOf(exceptionType)
|
||||
.rootCause()
|
||||
.hasMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
static final class AssertThatThrownByHasMessageParameters {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable,
|
||||
Class<? extends Throwable> exceptionType,
|
||||
@@ -517,7 +647,8 @@ final class AssertJThrowingCallableRules {
|
||||
|
||||
static final class AssertThatThrownByHasMessageStartingWith {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable,
|
||||
Class<? extends Throwable> exceptionType,
|
||||
@@ -541,7 +672,8 @@ final class AssertJThrowingCallableRules {
|
||||
|
||||
static final class AssertThatThrownByHasMessageContaining {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable,
|
||||
Class<? extends Throwable> exceptionType,
|
||||
@@ -565,7 +697,8 @@ final class AssertJThrowingCallableRules {
|
||||
|
||||
static final class AssertThatThrownByHasMessageNotContaining {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("AssertThatThrownBy" /* This is a more specific template. */)
|
||||
@SuppressWarnings(
|
||||
"AssertThatThrownByAsInstanceOfThrowable" /* This is a more specific template. */)
|
||||
AbstractObjectAssert<?, ?> before(
|
||||
ThrowingCallable throwingCallable,
|
||||
Class<? extends Throwable> exceptionType,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkElementIndex;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.Sets.toImmutableEnumSet;
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static java.util.Collections.disjoint;
|
||||
import static java.util.Objects.checkIndex;
|
||||
@@ -70,28 +68,6 @@ final class AssortedRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use {@link Sets#toImmutableEnumSet()} when possible, as it is more efficient than {@link
|
||||
* ImmutableSet#toImmutableSet()} and produces a more compact object.
|
||||
*
|
||||
* <p><strong>Warning:</strong> this rewrite rule is not completely behavior preserving: while the
|
||||
* original code produces a set that iterates over the elements in encounter order, the
|
||||
* replacement code iterates over the elements in enum definition order.
|
||||
*/
|
||||
// XXX: ^ Consider emitting a comment warning about this fact?
|
||||
static final class StreamToImmutableEnumSet<T extends Enum<T>> {
|
||||
@BeforeTemplate
|
||||
ImmutableSet<T> before(Stream<T> stream) {
|
||||
return stream.collect(toImmutableSet());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
ImmutableSet<T> after(Stream<T> stream) {
|
||||
return stream.collect(toImmutableEnumSet());
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Iterators#getNext(Iterator, Object)} over more contrived alternatives. */
|
||||
static final class IteratorGetNextOrDefault<T> {
|
||||
@BeforeTemplate
|
||||
|
||||
@@ -9,7 +9,9 @@ import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.sun.tools.javac.util.Constants;
|
||||
import com.sun.tools.javac.util.Convert;
|
||||
import javax.lang.model.element.Name;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.utils.SourceCode;
|
||||
|
||||
/** Refaster rules related to {@link com.google.errorprone.bugpatterns.BugChecker} classes. */
|
||||
@OnlineDocumentation
|
||||
@@ -55,16 +57,44 @@ final class BugCheckerRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer using the {@link Constants} API over more verbose alternatives. */
|
||||
/**
|
||||
* Prefer {@link SourceCode#toStringConstantExpression(Object,
|
||||
* com.google.errorprone.VisitorState)} over alternatives that unnecessarily escape single quote
|
||||
* characters.
|
||||
*/
|
||||
static final class ConstantsFormat {
|
||||
@BeforeTemplate
|
||||
String before(CharSequence value) {
|
||||
return Constants.format(value);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
String before(String value) {
|
||||
return String.format("\"%s\"", Convert.quote(value));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(String value) {
|
||||
return Constants.format(value);
|
||||
String after(CharSequence value) {
|
||||
return SourceCode.toStringConstantExpression(
|
||||
value, Refaster.emitCommentBefore("REPLACEME", null));
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Name#contentEquals(CharSequence)} over more verbose alternatives. */
|
||||
static final class NameContentEquals {
|
||||
@BeforeTemplate
|
||||
boolean before(Name name, CharSequence string) {
|
||||
return name.toString().equals(string.toString());
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
boolean before(Name name, String string) {
|
||||
return name.toString().equals(string);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
boolean after(Name name, CharSequence string) {
|
||||
return name.contentEquals(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package tech.picnic.errorprone.refasterrules;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
@@ -37,7 +38,12 @@ final class ClassRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Class#isInstance(Object)} method references over more verbose alternatives. */
|
||||
/**
|
||||
* Prefer {@link Class#isInstance(Object)} method references over lambda expressions that require
|
||||
* naming a variable.
|
||||
*/
|
||||
// XXX: Once the `ClassReferenceIsInstancePredicate` rule is dropped, rename this rule to just
|
||||
// `ClassIsInstancePredicate`.
|
||||
static final class ClassLiteralIsInstancePredicate<T, S> {
|
||||
@BeforeTemplate
|
||||
Predicate<S> before() {
|
||||
@@ -50,7 +56,11 @@ final class ClassRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Class#isInstance(Object)} method references over more verbose alternatives. */
|
||||
/**
|
||||
* Prefer {@link Class#isInstance(Object)} method references over lambda expressions that require
|
||||
* naming a variable.
|
||||
*/
|
||||
// XXX: Drop this rule once the `MethodReferenceUsage` rule is enabled by default.
|
||||
static final class ClassReferenceIsInstancePredicate<T, S> {
|
||||
@BeforeTemplate
|
||||
Predicate<S> before(Class<T> clazz) {
|
||||
@@ -62,4 +72,21 @@ final class ClassRules {
|
||||
return clazz::isInstance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Class#cast(Object)} method references over lambda expressions that require naming
|
||||
* a variable.
|
||||
*/
|
||||
// XXX: Drop this rule once the `MethodReferenceUsage` rule is enabled by default.
|
||||
static final class ClassReferenceCast<T, S> {
|
||||
@BeforeTemplate
|
||||
Function<T, S> before(Class<? extends S> clazz) {
|
||||
return o -> clazz.cast(o);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Function<T, S> after(Class<? extends S> clazz) {
|
||||
return clazz::cast;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.AlsoNegation;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.NotMatches;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -21,6 +23,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsRefasterAsVarargs;
|
||||
|
||||
/** Refaster rules related to expressions dealing with (arbitrary) collections. */
|
||||
// XXX: There are other Guava `Iterables` methods that should not be called if the input is known to
|
||||
@@ -39,7 +42,7 @@ final class CollectionRules {
|
||||
"java:S1155" /* This violation will be rewritten. */,
|
||||
"LexicographicalAnnotationAttributeListing" /* `key-*` entry must remain last. */,
|
||||
"OptionalFirstCollectionElement" /* This is a more specific template. */,
|
||||
"StreamIsEmpty" /* This is a more specific template. */,
|
||||
"StreamFindAnyIsEmpty" /* This is a more specific template. */,
|
||||
"key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict"
|
||||
})
|
||||
boolean before(Collection<T> collection) {
|
||||
@@ -184,6 +187,24 @@ final class CollectionRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily call {@link Stream#distinct()} on an already-unique stream of elements. */
|
||||
// XXX: This rule assumes that the `Set` relies on `Object#equals`, rather than a custom
|
||||
// equivalence relation.
|
||||
// XXX: Expressions that drop or reorder elements from the stream, such as `.filter`, `.skip` and
|
||||
// `sorted`, can similarly be simplified. Covering all cases is better done using an Error Prone
|
||||
// check.
|
||||
static final class SetStream<T> {
|
||||
@BeforeTemplate
|
||||
Stream<?> before(Set<T> set) {
|
||||
return set.stream().distinct();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Stream<?> after(Set<T> set) {
|
||||
return set.stream();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link ArrayList#ArrayList(Collection)} over the Guava alternative. */
|
||||
@SuppressWarnings(
|
||||
"NonApiType" /* Matching against `List` would unnecessarily constrain the rule. */)
|
||||
@@ -276,6 +297,23 @@ final class CollectionRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Arrays#asList(Object[])} over more contrived alternatives. */
|
||||
// XXX: Consider moving this rule to `ImmutableListRules` and having it suggest
|
||||
// `ImmutableList#copyOf`. That would retain immutability, at the cost of no longer handling
|
||||
// `null`s.
|
||||
static final class ArraysAsList<T> {
|
||||
// XXX: This expression produces an unmodifiable list, while the alternative doesn't.
|
||||
@BeforeTemplate
|
||||
List<T> before(@NotMatches(IsRefasterAsVarargs.class) T[] array) {
|
||||
return Arrays.stream(array).toList();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
List<T> after(T[] array) {
|
||||
return Arrays.asList(array);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer calling {@link Collection#toArray()} over more contrived alternatives. */
|
||||
static final class CollectionToArray<T> {
|
||||
@BeforeTemplate
|
||||
@@ -327,18 +365,20 @@ final class CollectionRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't call {@link ImmutableCollection#asList()} if {@link ImmutableCollection#iterator()} is
|
||||
* called on the result; call it directly.
|
||||
*/
|
||||
static final class ImmutableCollectionIterator<T> {
|
||||
/** Prefer {@link Collection#iterator()} over more contrived or less efficient alternatives. */
|
||||
static final class CollectionIterator<T> {
|
||||
@BeforeTemplate
|
||||
Iterator<T> before(Collection<T> collection) {
|
||||
return collection.stream().iterator();
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
Iterator<T> before(ImmutableCollection<T> collection) {
|
||||
return collection.asList().iterator();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Iterator<T> after(ImmutableCollection<T> collection) {
|
||||
Iterator<T> after(Collection<T> collection) {
|
||||
return collection.iterator();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,18 @@ 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.AlsoNegation;
|
||||
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.Placeholder;
|
||||
import com.google.errorprone.refaster.annotation.Repeated;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
@@ -92,6 +97,24 @@ final class ComparatorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't explicitly compare enums by their ordinal. */
|
||||
abstract static class ComparingEnum<E extends Enum<E>, T> {
|
||||
@Placeholder(allowsIdentity = true)
|
||||
abstract E toEnumFunction(@MayOptionallyUse T value);
|
||||
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("EnumOrdinal" /* This violation will be rewritten. */)
|
||||
Comparator<T> before() {
|
||||
return comparingInt(v -> toEnumFunction(v).ordinal());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
Comparator<T> after() {
|
||||
return comparing(v -> toEnumFunction(v));
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't explicitly create {@link Comparator}s unnecessarily. */
|
||||
static final class ThenComparing<S, T extends Comparable<? super T>> {
|
||||
@BeforeTemplate
|
||||
@@ -222,18 +245,77 @@ final class ComparatorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Collections#sort(List)} over more verbose alternatives. */
|
||||
static final class CollectionsSort<T extends Comparable<? super T>> {
|
||||
@BeforeTemplate
|
||||
void before(List<T> collection) {
|
||||
Collections.sort(collection, naturalOrder());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(List<T> collection) {
|
||||
Collections.sort(collection);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Collections#min(Collection)} over more verbose alternatives. */
|
||||
static final class CollectionsMin<T extends Comparable<? super T>> {
|
||||
@BeforeTemplate
|
||||
T before(Collection<T> collection) {
|
||||
return Refaster.anyOf(
|
||||
Collections.min(collection, naturalOrder()), Collections.max(collection, reverseOrder()));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(Collection<T> collection) {
|
||||
return Collections.min(collection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary creation of a {@link Stream} to determine the minimum of a known collection
|
||||
* of values.
|
||||
*/
|
||||
static final class MinOfVarargs<T> {
|
||||
static final class MinOfArray<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
T before(@Repeated T value, Comparator<T> cmp) {
|
||||
T before(T[] array, Comparator<S> cmp) {
|
||||
return Arrays.stream(array).min(cmp).orElseThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(T[] array, Comparator<S> cmp) {
|
||||
return Collections.min(Arrays.asList(array), cmp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary creation of a {@link Stream} to determine the minimum of a known collection
|
||||
* of values.
|
||||
*/
|
||||
static final class CollectionsMinWithComparator<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
T before(Collection<T> collection, Comparator<S> cmp) {
|
||||
return collection.stream().min(cmp).orElseThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(Collection<T> collection, Comparator<S> cmp) {
|
||||
return Collections.min(collection, cmp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary creation of a {@link Stream} to determine the minimum of a known collection
|
||||
* of values.
|
||||
*/
|
||||
static final class MinOfVarargs<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
T before(@Repeated T value, Comparator<S> cmp) {
|
||||
return Stream.of(Refaster.asVarargs(value)).min(cmp).orElseThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(@Repeated T value, Comparator<T> cmp) {
|
||||
T after(@Repeated T value, Comparator<S> cmp) {
|
||||
return Collections.min(Arrays.asList(value), cmp);
|
||||
}
|
||||
}
|
||||
@@ -269,7 +351,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) {
|
||||
T before(T value1, T value2, Comparator<? super T> cmp) {
|
||||
return Refaster.anyOf(
|
||||
cmp.compare(value1, value2) <= 0 ? value1 : value2,
|
||||
cmp.compare(value1, value2) > 0 ? value2 : value1,
|
||||
@@ -284,23 +366,69 @@ final class ComparatorRules {
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(T value1, T value2, Comparator<T> cmp) {
|
||||
T after(T value1, T value2, Comparator<? super T> cmp) {
|
||||
return Comparators.min(value1, value2, cmp);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Collections#max(Collection)} over more verbose alternatives. */
|
||||
static final class CollectionsMax<T extends Comparable<? super T>> {
|
||||
@BeforeTemplate
|
||||
T before(Collection<T> collection) {
|
||||
return Refaster.anyOf(
|
||||
Collections.max(collection, naturalOrder()), Collections.min(collection, reverseOrder()));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(Collection<T> collection) {
|
||||
return Collections.max(collection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary creation of a {@link Stream} to determine the maximum of a known collection
|
||||
* of values.
|
||||
*/
|
||||
static final class MaxOfVarargs<T> {
|
||||
static final class MaxOfArray<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
T before(@Repeated T value, Comparator<T> cmp) {
|
||||
T before(T[] array, Comparator<S> cmp) {
|
||||
return Arrays.stream(array).max(cmp).orElseThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(T[] array, Comparator<S> cmp) {
|
||||
return Collections.max(Arrays.asList(array), cmp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary creation of a {@link Stream} to determine the maximum of a known collection
|
||||
* of values.
|
||||
*/
|
||||
static final class CollectionsMaxWithComparator<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
T before(Collection<T> collection, Comparator<S> cmp) {
|
||||
return collection.stream().max(cmp).orElseThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(Collection<T> collection, Comparator<S> cmp) {
|
||||
return Collections.max(collection, cmp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary creation of a {@link Stream} to determine the maximum of a known collection
|
||||
* of values.
|
||||
*/
|
||||
static final class MaxOfVarargs<S, T extends S> {
|
||||
@BeforeTemplate
|
||||
T before(@Repeated T value, Comparator<S> cmp) {
|
||||
return Stream.of(Refaster.asVarargs(value)).max(cmp).orElseThrow();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(@Repeated T value, Comparator<T> cmp) {
|
||||
T after(@Repeated T value, Comparator<S> cmp) {
|
||||
return Collections.max(Arrays.asList(value), cmp);
|
||||
}
|
||||
}
|
||||
@@ -336,7 +464,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) {
|
||||
T before(T value1, T value2, Comparator<? super T> cmp) {
|
||||
return Refaster.anyOf(
|
||||
cmp.compare(value1, value2) >= 0 ? value1 : value2,
|
||||
cmp.compare(value1, value2) < 0 ? value2 : value1,
|
||||
@@ -351,7 +479,7 @@ final class ComparatorRules {
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(T value1, T value2, Comparator<T> cmp) {
|
||||
T after(T value1, T value2, Comparator<? super T> cmp) {
|
||||
return Comparators.max(value1, value2, cmp);
|
||||
}
|
||||
}
|
||||
@@ -419,4 +547,34 @@ final class ComparatorRules {
|
||||
return maxBy(naturalOrder());
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't explicitly compare enums by their ordinal. */
|
||||
static final class IsLessThan<E extends Enum<E>> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("EnumOrdinal" /* This violation will be rewritten. */)
|
||||
boolean before(E value1, E value2) {
|
||||
return value1.ordinal() < value2.ordinal();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(E value1, E value2) {
|
||||
return value1.compareTo(value2) < 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't explicitly compare enums by their ordinal. */
|
||||
static final class IsLessThanOrEqualTo<E extends Enum<E>> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("EnumOrdinal" /* This violation will be rewritten. */)
|
||||
boolean before(E value1, E value2) {
|
||||
return value1.ordinal() <= value2.ordinal();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(E value1, E value2) {
|
||||
return value1.compareTo(value2) <= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.util.function.Predicate.isEqual;
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
@@ -19,9 +20,9 @@ import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
final class EqualityRules {
|
||||
private EqualityRules() {}
|
||||
|
||||
/** Prefer reference-based quality for enums. */
|
||||
// Primitive value comparisons are not listed, because Error Prone flags those out of the box.
|
||||
static final class PrimitiveOrReferenceEquality<T extends Enum<T>> {
|
||||
/** Prefer reference-based equality for enums. */
|
||||
// Primitive value comparisons are not matched, because Error Prone flags those out of the box.
|
||||
static final class EnumReferenceEquality<T extends Enum<T>> {
|
||||
/**
|
||||
* Enums can be compared by reference. It is safe to do so even in the face of refactorings,
|
||||
* because if the type is ever converted to a non-enum, then Error-Prone will complain about any
|
||||
@@ -30,8 +31,9 @@ final class EqualityRules {
|
||||
// XXX: This Refaster rule is the topic of https://github.com/google/error-prone/issues/559. We
|
||||
// work around the issue by selecting the "largest replacements". See the `Refaster` check.
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("EnumOrdinal" /* This violation will be rewritten. */)
|
||||
boolean before(T a, T b) {
|
||||
return Refaster.anyOf(a.equals(b), Objects.equals(a, b));
|
||||
return Refaster.anyOf(a.equals(b), Objects.equals(a, b), a.ordinal() == b.ordinal());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -42,6 +44,20 @@ final class EqualityRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer reference-based equality for enums. */
|
||||
static final class EnumReferenceEqualityLambda<T extends Enum<T>> {
|
||||
@BeforeTemplate
|
||||
Predicate<T> before(T e) {
|
||||
return Refaster.anyOf(isEqual(e), e::equals);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("java:S1698" /* Reference comparison is valid for enums. */)
|
||||
Predicate<T> after(T e) {
|
||||
return v -> v == e;
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Object#equals(Object)} over the equivalent lambda function. */
|
||||
// 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.
|
||||
|
||||
@@ -2,12 +2,18 @@ package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Repeated;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with files. */
|
||||
@@ -15,6 +21,49 @@ import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
final class FileRules {
|
||||
private FileRules() {}
|
||||
|
||||
/** Prefer the more idiomatic {@link Path#of(URI)} over {@link Paths#get(URI)}. */
|
||||
static final class PathOfUri {
|
||||
@BeforeTemplate
|
||||
Path before(URI uri) {
|
||||
return Paths.get(uri);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Path after(URI uri) {
|
||||
return Path.of(uri);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer the more idiomatic {@link Path#of(String, String...)} over {@link Paths#get(String,
|
||||
* String...)}.
|
||||
*/
|
||||
static final class PathOfString {
|
||||
@BeforeTemplate
|
||||
Path before(String first, @Repeated String more) {
|
||||
return Paths.get(first, more);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Path after(String first, @Repeated String more) {
|
||||
return Path.of(first, more);
|
||||
}
|
||||
}
|
||||
|
||||
/** Avoid redundant conversions from {@link Path} to {@link File}. */
|
||||
// XXX: Review whether a rule such as this one is better handled by the `IdentityConversion` rule.
|
||||
static final class PathInstance {
|
||||
@BeforeTemplate
|
||||
Path before(Path path) {
|
||||
return path.toFile().toPath();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Path after(Path path) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Files#readString(Path, Charset)} over more contrived alternatives. */
|
||||
static final class FilesReadStringWithCharset {
|
||||
@BeforeTemplate
|
||||
@@ -40,4 +89,56 @@ final class FileRules {
|
||||
return Files.readString(path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Files#createTempFile(String, String, FileAttribute[])} over alternatives that
|
||||
* create files with more liberal permissions.
|
||||
*
|
||||
* <p>Note that {@link File#createTempFile} treats the given prefix as a path, and ignores all but
|
||||
* its file name. That is, the actual prefix used is derived from all characters following the
|
||||
* final file separator (if any). This is not the case with {@link Files#createTempFile}, which
|
||||
* will instead throw an {@link IllegalArgumentException} if the prefix contains any file
|
||||
* separators.
|
||||
*/
|
||||
static final class FilesCreateTempFileToFile {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings({
|
||||
"FilesCreateTempFileInCustomDirectoryToFile" /* This is a more specific template. */,
|
||||
"java:S5443" /* This violation will be rewritten. */,
|
||||
"key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict"
|
||||
})
|
||||
File before(String prefix, String suffix) throws IOException {
|
||||
return Refaster.anyOf(
|
||||
File.createTempFile(prefix, suffix), File.createTempFile(prefix, suffix, null));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings(
|
||||
"java:S5443" /* On POSIX systems the file will only have user read-write permissions. */)
|
||||
File after(String prefix, String suffix) throws IOException {
|
||||
return Files.createTempFile(prefix, suffix).toFile();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Files#createTempFile(Path, String, String, FileAttribute[])} over alternatives
|
||||
* that create files with more liberal permissions.
|
||||
*
|
||||
* <p>Note that {@link File#createTempFile} treats the given prefix as a path, and ignores all but
|
||||
* its file name. That is, the actual prefix used is derived from all characters following the
|
||||
* final file separator (if any). This is not the case with {@link Files#createTempFile}, which
|
||||
* will instead throw an {@link IllegalArgumentException} if the prefix contains any file
|
||||
* separators.
|
||||
*/
|
||||
static final class FilesCreateTempFileInCustomDirectoryToFile {
|
||||
@BeforeTemplate
|
||||
File before(File directory, String prefix, String suffix) throws IOException {
|
||||
return File.createTempFile(prefix, suffix, directory);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
File after(File directory, String prefix, String suffix) throws IOException {
|
||||
return Files.createTempFile(directory.toPath(), prefix, suffix).toFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.Sets.toImmutableEnumSet;
|
||||
import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Repeated;
|
||||
import com.google.errorprone.refaster.annotation.UseImportPolicy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.stream.Stream;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/**
|
||||
* Refaster rules related to expressions dealing with {@code
|
||||
* com.google.common.collect.ImmutableEnumSet}s.
|
||||
*/
|
||||
// XXX: Some of the rules defined here impact iteration order. That's a rather subtle change. Should
|
||||
// we emit a comment warning about this fact? (This may produce a lot of noise. A bug checker could
|
||||
// in some cases determine whether iteration order is important.)
|
||||
// XXX: Consider replacing the `SetsImmutableEnumSet[N]` Refaster rules with a bug checker, such
|
||||
// that call to `ImmutableSet#of(Object, Object, Object, Object, Object, Object, Object[])` with
|
||||
// enum-typed values can also be rewritten.
|
||||
@OnlineDocumentation
|
||||
final class ImmutableEnumSetRules {
|
||||
private ImmutableEnumSetRules() {}
|
||||
|
||||
/**
|
||||
* Prefer {@link Sets#immutableEnumSet(Iterable)} for enum collections to take advantage of the
|
||||
* internally used {@link EnumSet}.
|
||||
*
|
||||
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the
|
||||
* original code produces a set that iterates over its elements in the same order as the input
|
||||
* {@link Iterable}, the replacement code iterates over the elements in enum definition order.
|
||||
*/
|
||||
static final class SetsImmutableEnumSetIterable<T extends Enum<T>> {
|
||||
@BeforeTemplate
|
||||
ImmutableSet<T> before(Iterable<T> elements) {
|
||||
return ImmutableSet.copyOf(elements);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
ImmutableSet<T> before(Collection<T> elements) {
|
||||
return ImmutableSet.copyOf(elements);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
ImmutableSet<T> after(Iterable<T> elements) {
|
||||
return Sets.immutableEnumSet(elements);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Sets#immutableEnumSet(Iterable)} for enum collections to take advantage of the
|
||||
* internally used {@link EnumSet}.
|
||||
*
|
||||
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the
|
||||
* original code produces a set that iterates over its elements in the same order as defined in
|
||||
* the array, the replacement code iterates over the elements in enum definition order.
|
||||
*/
|
||||
static final class SetsImmutableEnumSetArraysAsList<T extends Enum<T>> {
|
||||
@BeforeTemplate
|
||||
ImmutableSet<T> before(T[] elements) {
|
||||
return ImmutableSet.copyOf(elements);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
ImmutableSet<T> after(T[] elements) {
|
||||
return Sets.immutableEnumSet(Arrays.asList(elements));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
|
||||
* the internally used {@link EnumSet}.
|
||||
*/
|
||||
static final class SetsImmutableEnumSet1<T extends Enum<T>> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
|
||||
ImmutableSet<T> before(T e1) {
|
||||
return Refaster.anyOf(ImmutableSet.of(e1), ImmutableSet.copyOf(EnumSet.of(e1)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ImmutableSet<T> after(T e1) {
|
||||
return Sets.immutableEnumSet(e1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
|
||||
* the internally used {@link EnumSet}.
|
||||
*
|
||||
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the {@link
|
||||
* ImmutableSet#of} expression produces a set that iterates over its elements in the listed order,
|
||||
* the replacement code iterates over the elements in enum definition order.
|
||||
*/
|
||||
static final class SetsImmutableEnumSet2<T extends Enum<T>> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
|
||||
ImmutableSet<T> before(T e1, T e2) {
|
||||
return Refaster.anyOf(ImmutableSet.of(e1, e2), ImmutableSet.copyOf(EnumSet.of(e1, e2)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ImmutableSet<T> after(T e1, T e2) {
|
||||
return Sets.immutableEnumSet(e1, e2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
|
||||
* the internally used {@link EnumSet}.
|
||||
*
|
||||
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the {@link
|
||||
* ImmutableSet#of} expression produces a set that iterates over its elements in the listed order,
|
||||
* the replacement code iterates over the elements in enum definition order.
|
||||
*/
|
||||
static final class SetsImmutableEnumSet3<T extends Enum<T>> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
|
||||
ImmutableSet<T> before(T e1, T e2, T e3) {
|
||||
return Refaster.anyOf(
|
||||
ImmutableSet.of(e1, e2, e3), ImmutableSet.copyOf(EnumSet.of(e1, e2, e3)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ImmutableSet<T> after(T e1, T e2, T e3) {
|
||||
return Sets.immutableEnumSet(e1, e2, e3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
|
||||
* the internally used {@link EnumSet}.
|
||||
*
|
||||
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the {@link
|
||||
* ImmutableSet#of} expression produces a set that iterates over its elements in the listed order,
|
||||
* the replacement code iterates over the elements in enum definition order.
|
||||
*/
|
||||
static final class SetsImmutableEnumSet4<T extends Enum<T>> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
|
||||
ImmutableSet<T> before(T e1, T e2, T e3, T e4) {
|
||||
return Refaster.anyOf(
|
||||
ImmutableSet.of(e1, e2, e3, e4), ImmutableSet.copyOf(EnumSet.of(e1, e2, e3, e4)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ImmutableSet<T> after(T e1, T e2, T e3, T e4) {
|
||||
return Sets.immutableEnumSet(e1, e2, e3, e4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
|
||||
* the internally used {@link EnumSet}.
|
||||
*
|
||||
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the {@link
|
||||
* ImmutableSet#of} expression produces a set that iterates over its elements in the listed order,
|
||||
* the replacement code iterates over the elements in enum definition order.
|
||||
*/
|
||||
static final class SetsImmutableEnumSet5<T extends Enum<T>> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
|
||||
ImmutableSet<T> before(T e1, T e2, T e3, T e4, T e5) {
|
||||
return Refaster.anyOf(
|
||||
ImmutableSet.of(e1, e2, e3, e4, e5), ImmutableSet.copyOf(EnumSet.of(e1, e2, e3, e4, e5)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ImmutableSet<T> after(T e1, T e2, T e3, T e4, T e5) {
|
||||
return Sets.immutableEnumSet(e1, e2, e3, e4, e5);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
|
||||
* the internally used {@link EnumSet}.
|
||||
*
|
||||
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the
|
||||
* original code produces a set that iterates over its elements in the listed order, the
|
||||
* replacement code iterates over the elements in enum definition order.
|
||||
*/
|
||||
static final class SetsImmutableEnumSet6<T extends Enum<T>> {
|
||||
@BeforeTemplate
|
||||
ImmutableSet<T> before(T e1, T e2, T e3, T e4, T e5, T e6) {
|
||||
return ImmutableSet.of(e1, e2, e3, e4, e5, e6);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@SuppressWarnings("unchecked")
|
||||
ImmutableSet<T> after(T e1, T e2, T e3, T e4, T e5, T e6) {
|
||||
return Sets.immutableEnumSet(e1, e2, e3, e4, e5, e6);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
|
||||
* the internally used {@link EnumSet}.
|
||||
*/
|
||||
static final class SetsImmutableEnumSetVarArgs<T extends Enum<T>> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
|
||||
ImmutableSet<T> before(T e1, @Repeated T elements) {
|
||||
return ImmutableSet.copyOf(EnumSet.of(e1, Refaster.asVarargs(elements)));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
ImmutableSet<T> after(T e1, @Repeated T elements) {
|
||||
return Sets.immutableEnumSet(e1, Refaster.asVarargs(elements));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use {@link Sets#toImmutableEnumSet()} when possible, as it is more efficient than {@link
|
||||
* ImmutableSet#toImmutableSet()} and produces a more compact object.
|
||||
*
|
||||
* <p><strong>Warning:</strong> this rule is not completely behavior preserving: while the
|
||||
* original code produces a set that iterates over its elements in encounter order, the
|
||||
* replacement code iterates over the elements in enum definition order.
|
||||
*/
|
||||
static final class StreamToImmutableEnumSet<T extends Enum<T>> {
|
||||
@BeforeTemplate
|
||||
ImmutableSet<T> before(Stream<T> stream) {
|
||||
return stream.collect(toImmutableSet());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
ImmutableSet<T> after(Stream<T> stream) {
|
||||
return stream.collect(toImmutableEnumSet());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -302,16 +302,22 @@ import tech.picnic.errorprone.refaster.annotation.TypeMigration;
|
||||
final class JUnitToAssertJRules {
|
||||
private JUnitToAssertJRules() {}
|
||||
|
||||
static final class ThrowNewAssertionError {
|
||||
static final class Fail<T> {
|
||||
@BeforeTemplate
|
||||
void before() {
|
||||
Assertions.fail();
|
||||
T before() {
|
||||
return Assertions.fail();
|
||||
}
|
||||
|
||||
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)` once
|
||||
// https://github.com/google/error-prone/pull/3584 is resolved. Until that time, statically
|
||||
// importing AssertJ's `fail` is likely to clash with an existing static import of JUnit's
|
||||
// `fail`. Note that combining Error Prone's `RemoveUnusedImports` and
|
||||
// `UnnecessarilyFullyQualified` checks and our `StaticImport` check will anyway cause the
|
||||
// method to be imported statically if possible; just in a less efficient manner.
|
||||
@AfterTemplate
|
||||
@DoNotCall
|
||||
void after() {
|
||||
throw new AssertionError();
|
||||
T after() {
|
||||
return fail();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,12 +327,7 @@ final class JUnitToAssertJRules {
|
||||
return Assertions.fail(message);
|
||||
}
|
||||
|
||||
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)` once
|
||||
// https://github.com/google/error-prone/pull/3584 is resolved. Until that time, statically
|
||||
// importing AssertJ's `fail` is likely to clash with an existing static import of JUnit's
|
||||
// `fail`. Note that combining Error Prone's `RemoveUnusedImports` and
|
||||
// `UnnecessarilyFullyQualified` checks and our `StaticImport` check will anyway cause the
|
||||
// method to be imported statically if possible; just in a less efficient manner.
|
||||
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)`. See `Fail` comment.
|
||||
@AfterTemplate
|
||||
T after(String message) {
|
||||
return fail(message);
|
||||
@@ -339,28 +340,24 @@ final class JUnitToAssertJRules {
|
||||
return Assertions.fail(message, throwable);
|
||||
}
|
||||
|
||||
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)` once
|
||||
// https://github.com/google/error-prone/pull/3584 is resolved. Until that time, statically
|
||||
// importing AssertJ's `fail` is likely to clash with an existing static import of JUnit's
|
||||
// `fail`. Note that combining Error Prone's `RemoveUnusedImports` and
|
||||
// `UnnecessarilyFullyQualified` checks and our `StaticImport` check will anyway cause the
|
||||
// method to be imported statically if possible; just in a less efficient manner.
|
||||
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)`. See `Fail` comment.
|
||||
@AfterTemplate
|
||||
T after(String message, Throwable throwable) {
|
||||
return fail(message, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
static final class FailWithThrowable {
|
||||
static final class FailWithThrowable<T> {
|
||||
@BeforeTemplate
|
||||
void before(Throwable throwable) {
|
||||
Assertions.fail(throwable);
|
||||
T before(Throwable throwable) {
|
||||
return Assertions.fail(throwable);
|
||||
}
|
||||
|
||||
// XXX: Add `@UseImportPolicy(STATIC_IMPORT_ALWAYS)`. See `Fail` comment.
|
||||
@AfterTemplate
|
||||
@DoNotCall
|
||||
void after(Throwable throwable) {
|
||||
throw new AssertionError(throwable);
|
||||
T after(Throwable throwable) {
|
||||
return fail(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with Micrometer. */
|
||||
// XXX: Consider replacing the `TagsOf[N]` rules with a bug checker, so that various other
|
||||
// expressions (e.g. those creating other collection types, those passing in tags some other way, or
|
||||
// those passing in more tags) can be replaced as wel.
|
||||
@OnlineDocumentation
|
||||
final class MicrometerRules {
|
||||
private MicrometerRules() {}
|
||||
|
||||
/** Prefer using {@link Tags} over other immutable collections. */
|
||||
static final class TagsOf1 {
|
||||
@BeforeTemplate
|
||||
ImmutableCollection<Tag> before(Tag tag) {
|
||||
return Refaster.anyOf(ImmutableSet.of(tag), ImmutableList.of(tag));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Iterable<Tag> after(Tag tag) {
|
||||
return Tags.of(tag);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer using {@link Tags} over other immutable collections. */
|
||||
static final class TagsOf2 {
|
||||
@BeforeTemplate
|
||||
ImmutableCollection<Tag> before(Tag tag1, Tag tag2) {
|
||||
return Refaster.anyOf(ImmutableSet.of(tag1, tag2), ImmutableList.of(tag1, tag2));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Iterable<Tag> after(Tag tag1, Tag tag2) {
|
||||
return Tags.of(tag1, tag2);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer using {@link Tags} over other immutable collections. */
|
||||
static final class TagsOf3 {
|
||||
@BeforeTemplate
|
||||
ImmutableCollection<Tag> before(Tag tag1, Tag tag2, Tag tag3) {
|
||||
return Refaster.anyOf(ImmutableSet.of(tag1, tag2, tag3), ImmutableList.of(tag1, tag2, tag3));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Iterable<Tag> after(Tag tag1, Tag tag2, Tag tag3) {
|
||||
return Tags.of(tag1, tag2, tag3);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer using {@link Tags} over other immutable collections. */
|
||||
static final class TagsOf4 {
|
||||
@BeforeTemplate
|
||||
ImmutableCollection<Tag> before(Tag tag1, Tag tag2, Tag tag3, Tag tag4) {
|
||||
return Refaster.anyOf(
|
||||
ImmutableSet.of(tag1, tag2, tag3, tag4), ImmutableList.of(tag1, tag2, tag3, tag4));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Iterable<Tag> after(Tag tag1, Tag tag2, Tag tag3, Tag tag4) {
|
||||
return Tags.of(tag1, tag2, tag3, tag4);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer using {@link Tags} over other immutable collections. */
|
||||
static final class TagsOf5 {
|
||||
@BeforeTemplate
|
||||
ImmutableCollection<Tag> before(Tag tag1, Tag tag2, Tag tag3, Tag tag4, Tag tag5) {
|
||||
return Refaster.anyOf(
|
||||
ImmutableSet.of(tag1, tag2, tag3, tag4, tag5),
|
||||
ImmutableList.of(tag1, tag2, tag3, tag4, tag5));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Iterable<Tag> after(Tag tag1, Tag tag2, Tag tag3, Tag tag4, Tag tag5) {
|
||||
return Tags.of(tag1, tag2, tag3, tag4, tag5);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,13 +20,26 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsLikelyTrivialComputation;
|
||||
import tech.picnic.errorprone.refaster.matchers.RequiresComputation;
|
||||
|
||||
/** Refaster rules related to expressions dealing with {@link Optional}s. */
|
||||
@OnlineDocumentation
|
||||
final class OptionalRules {
|
||||
private OptionalRules() {}
|
||||
|
||||
/** Prefer {@link Optional#empty()} over the more contrived alternative. */
|
||||
static final class OptionalEmpty<T> {
|
||||
@BeforeTemplate
|
||||
Optional<T> before() {
|
||||
return Optional.ofNullable(null);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Optional<T> after() {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
static final class OptionalOfNullable<T> {
|
||||
// XXX: Refaster should be smart enough to also rewrite occurrences in which there are
|
||||
// parentheses around the null check, but that's currently not the case. Try to fix that.
|
||||
@@ -242,24 +255,21 @@ final class OptionalRules {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Optional#orElseGet(Supplier)} over {@link Optional#orElse(Object)} if the
|
||||
* fallback value is not the result of a trivial computation.
|
||||
* Prefer {@link Optional#orElse(Object)} over {@link Optional#orElseGet(Supplier)} if the
|
||||
* fallback value does not require non-trivial computation.
|
||||
*/
|
||||
// XXX: This rule may introduce a compilation error: the `value` expression may reference a
|
||||
// non-effectively final variable, which is not allowed in the replacement lambda expression.
|
||||
// Review whether a `@Matcher` can be used to avoid this.
|
||||
// XXX: Once `MethodReferenceUsage` is "production ready", replace
|
||||
// `@NotMatches(IsLikelyTrivialComputation.class)` with `@Matches(RequiresComputation.class)` (and
|
||||
// reimplement the matcher accordingly).
|
||||
static final class OptionalOrElseGet<T> {
|
||||
// XXX: This rule is the counterpart to the `OptionalOrElseGet` bug checker. Once the
|
||||
// `MethodReferenceUsage` bug checker is "production ready", that bug checker may similarly be
|
||||
// replaced with a Refaster rule.
|
||||
static final class OptionalOrElse<T> {
|
||||
@BeforeTemplate
|
||||
T before(Optional<T> optional, @NotMatches(IsLikelyTrivialComputation.class) T value) {
|
||||
return optional.orElse(value);
|
||||
T before(Optional<T> optional, @NotMatches(RequiresComputation.class) T value) {
|
||||
return optional.orElseGet(() -> value);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
T after(Optional<T> optional, T value) {
|
||||
return optional.orElseGet(() -> value);
|
||||
return optional.orElse(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,6 +279,9 @@ final class OptionalRules {
|
||||
*/
|
||||
// XXX: Do we need the `.filter(Optional::isPresent)`? If it's absent the caller probably assumed
|
||||
// that the values are present. (If we drop it, we should rewrite vacuous filter steps.)
|
||||
// XXX: The rewritten `filter`/`map` expression may be more performant than its replacement. See
|
||||
// https://github.com/palantir/gradle-baseline/pull/2946. (There are plans to pair Refaster rules
|
||||
// with JMH benchmarks; this would be a great use case.)
|
||||
static final class StreamFlatMapOptional<T> {
|
||||
@BeforeTemplate
|
||||
Stream<T> before(Stream<Optional<T>> stream) {
|
||||
@@ -360,7 +373,12 @@ final class OptionalRules {
|
||||
/** Prefer {@link Optional#or(Supplier)} over more verbose alternatives. */
|
||||
static final class OptionalOrOtherOptional<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedOptionals" /* Auto-fix for the `NestedOptionals` check. */)
|
||||
@SuppressWarnings({
|
||||
"LexicographicalAnnotationAttributeListing" /* `key-*` entry must remain last. */,
|
||||
"NestedOptionals" /* This violation will be rewritten. */,
|
||||
"OptionalOrElse" /* Parameters represent expressions that may require computation. */,
|
||||
"key-to-resolve-AnnotationUseStyle-and-TrailingComment-check-conflict"
|
||||
})
|
||||
Optional<T> before(Optional<T> optional1, Optional<T> optional2) {
|
||||
// XXX: Note that rewriting the first and third variant will change the code's behavior if
|
||||
// `optional2` has side-effects.
|
||||
@@ -380,15 +398,16 @@ final class OptionalRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid unnecessary operations on an {@link Optional} that ultimately result in that very same
|
||||
* {@link Optional}.
|
||||
*/
|
||||
/** Don't unnecessarily transform an {@link Optional} to an equivalent instance. */
|
||||
static final class OptionalIdentity<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("NestedOptionals")
|
||||
Optional<T> before(Optional<T> optional, Comparator<? super T> comparator) {
|
||||
return Refaster.anyOf(
|
||||
optional.or(Refaster.anyOf(() -> Optional.empty(), Optional::empty)),
|
||||
optional
|
||||
.map(Optional::of)
|
||||
.orElseGet(Refaster.anyOf(() -> Optional.empty(), Optional::empty)),
|
||||
optional.stream().findFirst(),
|
||||
optional.stream().findAny(),
|
||||
optional.stream().min(comparator),
|
||||
@@ -442,9 +461,7 @@ final class OptionalRules {
|
||||
static final class OptionalStream<T> {
|
||||
@BeforeTemplate
|
||||
Stream<T> before(Optional<T> optional) {
|
||||
return Refaster.anyOf(
|
||||
optional.map(Stream::of).orElse(Stream.empty()),
|
||||
optional.map(Stream::of).orElseGet(Stream::empty));
|
||||
return optional.map(Stream::of).orElseGet(Stream::empty);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
|
||||
@@ -8,6 +8,8 @@ import com.google.common.primitives.Floats;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
import com.google.common.primitives.Shorts;
|
||||
import com.google.common.primitives.UnsignedInts;
|
||||
import com.google.common.primitives.UnsignedLongs;
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.AlsoNegation;
|
||||
@@ -76,6 +78,8 @@ final class PrimitiveRules {
|
||||
}
|
||||
|
||||
/** Prefer {@link Math#toIntExact(long)} over the Guava alternative. */
|
||||
// XXX: This rule changes the exception possibly thrown from `IllegalArgumentException` to
|
||||
// `ArithmeticException`.
|
||||
static final class LongToIntExact {
|
||||
@BeforeTemplate
|
||||
int before(long l) {
|
||||
@@ -192,97 +196,6 @@ final class PrimitiveRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Boolean#compare(boolean, boolean)} over the Guava alternative. */
|
||||
static final class BooleanCompare {
|
||||
@BeforeTemplate
|
||||
int before(boolean a, boolean b) {
|
||||
return Booleans.compare(a, b);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(boolean a, boolean b) {
|
||||
return Boolean.compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Character#compare(char, char)} over the Guava alternative. */
|
||||
static final class CharacterCompare {
|
||||
@BeforeTemplate
|
||||
int before(char a, char b) {
|
||||
return Chars.compare(a, b);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(char a, char b) {
|
||||
return Character.compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Short#compare(short, short)} over the Guava alternative. */
|
||||
static final class ShortCompare {
|
||||
@BeforeTemplate
|
||||
int before(short a, short b) {
|
||||
return Shorts.compare(a, b);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(short a, short b) {
|
||||
return Short.compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Integer#compare(int, int)} over the Guava alternative. */
|
||||
static final class IntegerCompare {
|
||||
@BeforeTemplate
|
||||
int before(int a, int b) {
|
||||
return Ints.compare(a, b);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(int a, int b) {
|
||||
return Integer.compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Long#compare(long, long)} over the Guava alternative. */
|
||||
static final class LongCompare {
|
||||
@BeforeTemplate
|
||||
int before(long a, long b) {
|
||||
return Longs.compare(a, b);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(long a, long b) {
|
||||
return Long.compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Float#compare(float, float)} over the Guava alternative. */
|
||||
static final class FloatCompare {
|
||||
@BeforeTemplate
|
||||
int before(float a, float b) {
|
||||
return Floats.compare(a, b);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(float a, float b) {
|
||||
return Float.compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Double#compare(double, double)} over the Guava alternative. */
|
||||
static final class DoubleCompare {
|
||||
@BeforeTemplate
|
||||
int before(double a, double b) {
|
||||
return Doubles.compare(a, b);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(double a, double b) {
|
||||
return Double.compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Character#BYTES} over the Guava alternative. */
|
||||
static final class CharacterBytes {
|
||||
@BeforeTemplate
|
||||
@@ -442,4 +355,205 @@ final class PrimitiveRules {
|
||||
return Long.signum(l) == -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Integer#compareUnsigned(int, int)} over third-party alternatives. */
|
||||
static final class IntegerCompareUnsigned {
|
||||
@BeforeTemplate
|
||||
int before(int x, int y) {
|
||||
return UnsignedInts.compare(x, y);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(int x, int y) {
|
||||
return Integer.compareUnsigned(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Long#compareUnsigned(long, long)} over third-party alternatives. */
|
||||
static final class LongCompareUnsigned {
|
||||
@BeforeTemplate
|
||||
long before(long x, long y) {
|
||||
return UnsignedLongs.compare(x, y);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
long after(long x, long y) {
|
||||
return Long.compareUnsigned(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Integer#divideUnsigned(int, int)} over third-party alternatives. */
|
||||
static final class IntegerDivideUnsigned {
|
||||
@BeforeTemplate
|
||||
int before(int x, int y) {
|
||||
return UnsignedInts.divide(x, y);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(int x, int y) {
|
||||
return Integer.divideUnsigned(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Long#divideUnsigned(long, long)} over third-party alternatives. */
|
||||
static final class LongDivideUnsigned {
|
||||
@BeforeTemplate
|
||||
long before(long x, long y) {
|
||||
return UnsignedLongs.divide(x, y);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
long after(long x, long y) {
|
||||
return Long.divideUnsigned(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Integer#remainderUnsigned(int, int)} over third-party alternatives. */
|
||||
static final class IntegerRemainderUnsigned {
|
||||
@BeforeTemplate
|
||||
int before(int x, int y) {
|
||||
return UnsignedInts.remainder(x, y);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(int x, int y) {
|
||||
return Integer.remainderUnsigned(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Long#remainderUnsigned(long, long)} over third-party alternatives. */
|
||||
static final class LongRemainderUnsigned {
|
||||
@BeforeTemplate
|
||||
long before(long x, long y) {
|
||||
return UnsignedLongs.remainder(x, y);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
long after(long x, long y) {
|
||||
return Long.remainderUnsigned(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer JDK's {@link Integer#parseUnsignedInt(String)} over third-party or more verbose
|
||||
* alternatives.
|
||||
*/
|
||||
static final class IntegerParseUnsignedInt {
|
||||
@BeforeTemplate
|
||||
int before(String string) {
|
||||
return Refaster.anyOf(
|
||||
UnsignedInts.parseUnsignedInt(string), Integer.parseUnsignedInt(string, 10));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(String string) {
|
||||
return Integer.parseUnsignedInt(string);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer JDK's {@link Long#parseUnsignedLong(String)} over third-party or more verbose
|
||||
* alternatives.
|
||||
*/
|
||||
static final class LongParseUnsignedLong {
|
||||
@BeforeTemplate
|
||||
long before(String string) {
|
||||
return Refaster.anyOf(
|
||||
UnsignedLongs.parseUnsignedLong(string), Long.parseUnsignedLong(string, 10));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
long after(String string) {
|
||||
return Long.parseUnsignedLong(string);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Integer#parseUnsignedInt(String, int)} over third-party alternatives. */
|
||||
static final class IntegerParseUnsignedIntWithRadix {
|
||||
@BeforeTemplate
|
||||
int before(String string, int radix) {
|
||||
return UnsignedInts.parseUnsignedInt(string, radix);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(String string, int radix) {
|
||||
return Integer.parseUnsignedInt(string, radix);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer JDK's {@link Long#parseUnsignedLong(String, int)} over third-party alternatives. */
|
||||
static final class LongParseUnsignedLongWithRadix {
|
||||
@BeforeTemplate
|
||||
long before(String string, int radix) {
|
||||
return UnsignedLongs.parseUnsignedLong(string, radix);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
long after(String string, int radix) {
|
||||
return Long.parseUnsignedLong(string, radix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer JDK's {@link Integer#toUnsignedString(int)} over third-party or more verbose
|
||||
* alternatives.
|
||||
*/
|
||||
static final class IntegerToUnsignedString {
|
||||
@BeforeTemplate
|
||||
String before(int i) {
|
||||
return Refaster.anyOf(UnsignedInts.toString(i), Integer.toUnsignedString(i, 10));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(int i) {
|
||||
return Integer.toUnsignedString(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer JDK's {@link Long#toUnsignedString(long)} over third-party or more verbose alternatives.
|
||||
*/
|
||||
static final class LongToUnsignedString {
|
||||
@BeforeTemplate
|
||||
String before(long i) {
|
||||
return Refaster.anyOf(UnsignedLongs.toString(i), Long.toUnsignedString(i, 10));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(long i) {
|
||||
return Long.toUnsignedString(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer JDK's {@link Integer#toUnsignedString(int,int)} over third-party or more verbose
|
||||
* alternatives.
|
||||
*/
|
||||
static final class IntegerToUnsignedStringWithRadix {
|
||||
@BeforeTemplate
|
||||
String before(int i, int radix) {
|
||||
return UnsignedInts.toString(i, radix);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(int i, int radix) {
|
||||
return Integer.toUnsignedString(i, radix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer JDK's {@link Long#toUnsignedString(long,int)} over third-party or more verbose
|
||||
* alternatives.
|
||||
*/
|
||||
static final class LongToUnsignedStringWithRadix {
|
||||
@BeforeTemplate
|
||||
String before(long i, int radix) {
|
||||
return UnsignedLongs.toString(i, radix);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(long i, int radix) {
|
||||
return Long.toUnsignedString(i, radix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ 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;
|
||||
import static java.util.Comparator.naturalOrder;
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
@@ -14,6 +13,7 @@ import static java.util.stream.Collectors.toCollection;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static reactor.function.TupleUtils.function;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -34,6 +34,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
@@ -41,6 +42,7 @@ import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.Stream;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
@@ -52,7 +54,6 @@ import reactor.util.context.Context;
|
||||
import reactor.util.function.Tuple2;
|
||||
import tech.picnic.errorprone.refaster.annotation.Description;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.annotation.Severity;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsEmpty;
|
||||
import tech.picnic.errorprone.refaster.matchers.IsIdentityOperation;
|
||||
import tech.picnic.errorprone.refaster.matchers.ThrowsCheckedException;
|
||||
@@ -380,30 +381,23 @@ final class ReactorRules {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Flux#take(long, boolean)} over {@link Flux#take(long)}.
|
||||
* Prefer {@link Flux#take(long)} over {@link Flux#take(long, boolean)} where relevant.
|
||||
*
|
||||
* <p>In Reactor versions prior to 3.5.0, {@code Flux#take(long)} makes an unbounded request
|
||||
* upstream, and is equivalent to {@code Flux#take(long, false)}. In 3.5.0, the behavior of {@code
|
||||
* Flux#take(long)} will change to that of {@code Flux#take(long, true)}.
|
||||
*
|
||||
* <p>The intent with this Refaster rule is to get the new behavior before upgrading to Reactor
|
||||
* 3.5.0.
|
||||
* upstream, and is equivalent to {@code Flux#take(long, false)}. From version 3.5.0 onwards, the
|
||||
* behavior of {@code Flux#take(long)} instead matches {@code Flux#take(long, true)}.
|
||||
*/
|
||||
// XXX: Drop this rule some time after upgrading to Reactor 3.6.0, or introduce a way to apply
|
||||
// this rule only when an older version of Reactor is on the classpath.
|
||||
// XXX: Once Reactor 3.6.0 is out, introduce a rule that rewrites code in the opposite direction.
|
||||
@Description(
|
||||
"Prior to Reactor 3.5.0, `take(n)` requests and unbounded number of elements upstream.")
|
||||
@Severity(WARNING)
|
||||
"From Reactor 3.5.0 onwards, `take(n)` no longer requests an unbounded number of elements upstream.")
|
||||
static final class FluxTake<T> {
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Flux<T> flux, long n) {
|
||||
return flux.take(n);
|
||||
return flux.take(n, /* limitRequest= */ true);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<T> after(Flux<T> flux, long n) {
|
||||
return flux.take(n, /* limitRequest= */ true);
|
||||
return flux.take(n);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,15 +483,20 @@ final class ReactorRules {
|
||||
}
|
||||
|
||||
/** Prefer {@link Flux#just(Object)} over more contrived alternatives. */
|
||||
static final class FluxJust {
|
||||
static final class FluxJust<T> {
|
||||
@BeforeTemplate
|
||||
Flux<Integer> before(int start) {
|
||||
return Flux.range(start, 1);
|
||||
Flux<Integer> before(int value) {
|
||||
return Flux.range(value, 1);
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
Flux<T> before(T value) {
|
||||
return Mono.just(value).repeat().take(1);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<Integer> after(int start) {
|
||||
return Flux.just(start);
|
||||
Flux<T> after(T value) {
|
||||
return Flux.just(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,6 +565,7 @@ final class ReactorRules {
|
||||
@Matches(IsIdentityOperation.class)
|
||||
Function<? super P, ? extends Publisher<? extends S>> identityOperation) {
|
||||
return Refaster.anyOf(
|
||||
flux.concatMap(function, 0),
|
||||
flux.flatMap(function, 1),
|
||||
flux.flatMapSequential(function, 1),
|
||||
flux.map(function).concatMap(identityOperation));
|
||||
@@ -1206,10 +1206,17 @@ final class ReactorRules {
|
||||
}
|
||||
|
||||
/** Prefer {@link Flux#fromIterable(Iterable)} over less efficient alternatives. */
|
||||
// XXX: Once the `FluxFromStreamSupplier` rule is constrained using
|
||||
// `@NotMatches(IsIdentityOperation.class)`, this rule should also cover
|
||||
// `Flux.fromStream(collection.stream())`.
|
||||
static final class FluxFromIterable<T> {
|
||||
// XXX: Once the `MethodReferenceUsage` check is generally enabled, drop the second
|
||||
// `Refaster.anyOf` variant.
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Collection<T> collection) {
|
||||
return Flux.fromStream(collection.stream());
|
||||
return Flux.fromStream(
|
||||
Refaster.<Supplier<Stream<? extends T>>>anyOf(
|
||||
collection::stream, () -> collection.stream()));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -1735,6 +1742,91 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link PublisherProbe#assertWasSubscribed()} over more verbose alternatives. */
|
||||
static final class PublisherProbeAssertWasSubscribed<T> {
|
||||
@BeforeTemplate
|
||||
void before(PublisherProbe<T> probe) {
|
||||
Refaster.anyOf(
|
||||
assertThat(probe.wasSubscribed()).isTrue(),
|
||||
assertThat(probe.subscribeCount()).isNotNegative(),
|
||||
assertThat(probe.subscribeCount()).isNotEqualTo(0),
|
||||
assertThat(probe.subscribeCount()).isPositive());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(PublisherProbe<T> probe) {
|
||||
probe.assertWasSubscribed();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link PublisherProbe#assertWasNotSubscribed()} over more verbose alternatives. */
|
||||
static final class PublisherProbeAssertWasNotSubscribed<T> {
|
||||
@BeforeTemplate
|
||||
void before(PublisherProbe<T> probe) {
|
||||
Refaster.anyOf(
|
||||
assertThat(probe.wasSubscribed()).isFalse(),
|
||||
assertThat(probe.subscribeCount()).isEqualTo(0),
|
||||
assertThat(probe.subscribeCount()).isNotPositive());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(PublisherProbe<T> probe) {
|
||||
probe.assertWasNotSubscribed();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link PublisherProbe#assertWasCancelled()} over more verbose alternatives. */
|
||||
static final class PublisherProbeAssertWasCancelled<T> {
|
||||
@BeforeTemplate
|
||||
void before(PublisherProbe<T> probe) {
|
||||
assertThat(probe.wasCancelled()).isTrue();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(PublisherProbe<T> probe) {
|
||||
probe.assertWasCancelled();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link PublisherProbe#assertWasNotCancelled()} over more verbose alternatives. */
|
||||
static final class PublisherProbeAssertWasNotCancelled<T> {
|
||||
@BeforeTemplate
|
||||
void before(PublisherProbe<T> probe) {
|
||||
assertThat(probe.wasCancelled()).isFalse();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(PublisherProbe<T> probe) {
|
||||
probe.assertWasNotCancelled();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link PublisherProbe#assertWasRequested()} over more verbose alternatives. */
|
||||
static final class PublisherProbeAssertWasRequested<T> {
|
||||
@BeforeTemplate
|
||||
void before(PublisherProbe<T> probe) {
|
||||
assertThat(probe.wasRequested()).isTrue();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(PublisherProbe<T> probe) {
|
||||
probe.assertWasRequested();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link PublisherProbe#assertWasNotRequested()} over more verbose alternatives. */
|
||||
static final class PublisherProbeAssertWasNotRequested<T> {
|
||||
@BeforeTemplate
|
||||
void before(PublisherProbe<T> probe) {
|
||||
assertThat(probe.wasRequested()).isFalse();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
void after(PublisherProbe<T> probe) {
|
||||
probe.assertWasNotRequested();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Mono#as(Function)} when creating a {@link StepVerifier}. */
|
||||
static final class StepVerifierFromMono<T> {
|
||||
@BeforeTemplate
|
||||
@@ -1761,6 +1853,60 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link StepVerifier#verify()} over a dangling {@link
|
||||
* StepVerifier#verifyThenAssertThat()}.
|
||||
*/
|
||||
// XXX: Application of this rule (and several others in this class) will cause invalid code if the
|
||||
// result of the rewritten expression is dereferenced. Consider introducing a bug checker that
|
||||
// identifies rules that change the return type of an expression and annotates them accordingly.
|
||||
// The associated annotation can then be used to instruct an annotation processor to generate
|
||||
// corresponding `void` rules that match only statements. This would allow the `Refaster` check to
|
||||
// conditionally skip "not fully safe" rules. This allows conditionally flagging more dubious
|
||||
// code, at the risk of compilation failures. With this rule, for example, we want to explicitly
|
||||
// nudge users towards `StepVerifier.Step#assertNext(Consumer)` or
|
||||
// `StepVerifier.Step#expectNext(Object)`, together with `Step#verifyComplete()`.
|
||||
static final class StepVerifierVerify {
|
||||
@BeforeTemplate
|
||||
StepVerifier.Assertions before(StepVerifier stepVerifier) {
|
||||
return stepVerifier.verifyThenAssertThat();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Duration after(StepVerifier stepVerifier) {
|
||||
return stepVerifier.verify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link StepVerifier#verify(Duration)} over a dangling {@link
|
||||
* StepVerifier#verifyThenAssertThat(Duration)}.
|
||||
*/
|
||||
static final class StepVerifierVerifyDuration {
|
||||
@BeforeTemplate
|
||||
StepVerifier.Assertions before(StepVerifier stepVerifier, Duration duration) {
|
||||
return stepVerifier.verifyThenAssertThat(duration);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Duration after(StepVerifier stepVerifier, Duration duration) {
|
||||
return stepVerifier.verify(duration);
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily invoke {@link StepVerifier#verifyLater()} multiple times. */
|
||||
static final class StepVerifierVerifyLater {
|
||||
@BeforeTemplate
|
||||
StepVerifier before(StepVerifier stepVerifier) {
|
||||
return stepVerifier.verifyLater().verifyLater();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
StepVerifier after(StepVerifier stepVerifier) {
|
||||
return stepVerifier.verifyLater();
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily have {@link StepVerifier.Step} expect no elements. */
|
||||
static final class StepVerifierStepIdentity<T> {
|
||||
@BeforeTemplate
|
||||
@@ -1861,6 +2007,12 @@ final class ReactorRules {
|
||||
return step.expectErrorMatches(predicate).verify();
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("StepVerifierVerify" /* This is a more specific template. */)
|
||||
StepVerifier.Assertions before2(StepVerifier.LastStep step, Predicate<Throwable> predicate) {
|
||||
return step.expectError().verifyThenAssertThat().hasOperatorErrorMatching(predicate);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Duration after(StepVerifier.LastStep step, Predicate<Throwable> predicate) {
|
||||
return step.verifyErrorMatches(predicate);
|
||||
@@ -1883,6 +2035,30 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link StepVerifier.LastStep#verifyErrorSatisfies(Consumer)} with AssertJ over more
|
||||
* contrived alternatives.
|
||||
*/
|
||||
static final class StepVerifierLastStepVerifyErrorSatisfiesAssertJ<T extends Throwable> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("StepVerifierVerify" /* This is a more specific template. */)
|
||||
StepVerifier.Assertions before(StepVerifier.LastStep step, Class<T> clazz, String message) {
|
||||
return Refaster.anyOf(
|
||||
step.expectError()
|
||||
.verifyThenAssertThat()
|
||||
.hasOperatorErrorOfType(clazz)
|
||||
.hasOperatorErrorWithMessage(message),
|
||||
step.expectError(clazz).verifyThenAssertThat().hasOperatorErrorWithMessage(message),
|
||||
step.expectErrorMessage(message).verifyThenAssertThat().hasOperatorErrorOfType(clazz));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
Duration after(StepVerifier.LastStep step, Class<T> clazz, String message) {
|
||||
return step.verifyErrorSatisfies(t -> assertThat(t).isInstanceOf(clazz).hasMessage(message));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link StepVerifier.LastStep#verifyErrorMessage(String)} over more verbose alternatives.
|
||||
*/
|
||||
@@ -1912,4 +2088,76 @@ final class ReactorRules {
|
||||
return step.verifyTimeout(duration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Mono#fromFuture(Supplier)} over {@link Mono#fromFuture(CompletableFuture)}, as
|
||||
* the former may defer initiation of the asynchronous computation until subscription.
|
||||
*/
|
||||
static final class MonoFromFutureSupplier<T> {
|
||||
// XXX: Constrain the `future` parameter using `@NotMatches(IsIdentityOperation.class)` once
|
||||
// `IsIdentityOperation` no longer matches nullary method invocations.
|
||||
@BeforeTemplate
|
||||
Mono<T> before(CompletableFuture<T> future) {
|
||||
return Mono.fromFuture(future);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(CompletableFuture<T> future) {
|
||||
return Mono.fromFuture(() -> future);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Mono#fromFuture(Supplier, boolean)} over {@link
|
||||
* Mono#fromFuture(CompletableFuture, boolean)}, as the former may defer initiation of the
|
||||
* asynchronous computation until subscription.
|
||||
*/
|
||||
static final class MonoFromFutureSupplierBoolean<T> {
|
||||
// XXX: Constrain the `future` parameter using `@NotMatches(IsIdentityOperation.class)` once
|
||||
// `IsIdentityOperation` no longer matches nullary method invocations.
|
||||
@BeforeTemplate
|
||||
Mono<T> before(CompletableFuture<T> future, boolean suppressCancel) {
|
||||
return Mono.fromFuture(future, suppressCancel);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(CompletableFuture<T> future, boolean suppressCancel) {
|
||||
return Mono.fromFuture(() -> future, suppressCancel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't propagate {@link Mono} cancellations to an upstream cache value computation, as
|
||||
* completion of such computations may benefit concurrent or subsequent cache usages.
|
||||
*/
|
||||
static final class MonoFromFutureAsyncLoadingCacheGet<K, V> {
|
||||
@BeforeTemplate
|
||||
Mono<V> before(AsyncLoadingCache<K, V> cache, K key) {
|
||||
return Mono.fromFuture(() -> cache.get(key));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<V> after(AsyncLoadingCache<K, V> cache, K key) {
|
||||
return Mono.fromFuture(() -> cache.get(key), /* suppressCancel= */ true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Flux#fromStream(Supplier)} over {@link Flux#fromStream(Stream)}, as the former
|
||||
* yields a {@link Flux} that is more likely to behave as expected when subscribed to more than
|
||||
* once.
|
||||
*/
|
||||
static final class FluxFromStreamSupplier<T> {
|
||||
// XXX: Constrain the `stream` parameter using `@NotMatches(IsIdentityOperation.class)` once
|
||||
// `IsIdentityOperation` no longer matches nullary method invocations.
|
||||
@BeforeTemplate
|
||||
Flux<T> before(Stream<T> stream) {
|
||||
return Flux.fromStream(stream);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<T> after(Stream<T> stream) {
|
||||
return Flux.fromStream(() -> stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ 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.AlsoNegation;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.refaster.annotation.Matches;
|
||||
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
|
||||
@@ -256,7 +257,7 @@ final class StreamRules {
|
||||
// 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, K, V, C extends Collection<K>, M extends Map<K, V>> {
|
||||
static final class StreamFindAnyIsEmpty<T, K, V, C extends Collection<K>, M extends Map<K, V>> {
|
||||
@BeforeTemplate
|
||||
boolean before(Stream<T> stream, Collector<? super T, ?, ? extends C> collector) {
|
||||
return Refaster.anyOf(
|
||||
@@ -274,20 +275,20 @@ final class StreamRules {
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@AlsoNegation
|
||||
boolean after(Stream<T> stream) {
|
||||
return stream.findAny().isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
/** In order to test whether a stream has any element, simply try to find one. */
|
||||
static final class StreamIsNotEmpty<T> {
|
||||
/**
|
||||
* Prefer {@link Stream#findAny()} over {@link Stream#findFirst()} if one only cares whether the
|
||||
* stream is nonempty.
|
||||
*/
|
||||
static final class StreamFindAnyIsPresent<T> {
|
||||
@BeforeTemplate
|
||||
boolean before(Stream<T> stream) {
|
||||
return Refaster.anyOf(
|
||||
stream.count() != 0,
|
||||
stream.count() > 0,
|
||||
stream.count() >= 1,
|
||||
stream.findFirst().isPresent());
|
||||
return stream.findFirst().isPresent();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
@@ -296,6 +297,22 @@ final class StreamRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer an unconditional {@link Map#get(Object)} call followed by a {@code null} check over a
|
||||
* call to {@link Map#containsKey(Object)}, as the former avoids a second lookup operation.
|
||||
*/
|
||||
static final class StreamMapFilter<T, K, V> {
|
||||
@BeforeTemplate
|
||||
Stream<V> before(Stream<T> stream, Map<K, V> map) {
|
||||
return stream.filter(map::containsKey).map(map::get);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Stream<V> after(Stream<T> stream, Map<K, V> map) {
|
||||
return stream.map(map::get).filter(Objects::nonNull);
|
||||
}
|
||||
}
|
||||
|
||||
static final class StreamMin<T> {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("java:S4266" /* This violation will be rewritten. */)
|
||||
|
||||
@@ -244,4 +244,105 @@ final class StringRules {
|
||||
return Utf8.encodedLength(str);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link String#indexOf(int, int)} over less efficient alternatives. */
|
||||
static final class StringIndexOfChar {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("java:S4635" /* This violation will be rewritten. */)
|
||||
int before(String string, int ch, int fromIndex) {
|
||||
return string.substring(fromIndex).indexOf(ch);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(String string, int ch, int fromIndex) {
|
||||
return Math.max(-1, string.indexOf(ch, fromIndex) - fromIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link String#indexOf(String, int)} over less efficient alternatives. */
|
||||
static final class StringIndexOfString {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("java:S4635" /* This violation will be rewritten. */)
|
||||
int before(String string, String substring, int fromIndex) {
|
||||
return string.substring(fromIndex).indexOf(substring);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(String string, String substring, int fromIndex) {
|
||||
return Math.max(-1, string.indexOf(substring, fromIndex) - fromIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Once we compile Refaster templates with JDK 21 also suggest `String#indexOf(int, int,
|
||||
// int)` and `String#indexOf(String, int, int)`.
|
||||
|
||||
/** Prefer {@link String#lastIndexOf(int, int)} over less efficient alternatives. */
|
||||
static final class StringLastIndexOfChar {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("java:S4635" /* This violation will be rewritten. */)
|
||||
int before(String string, int ch, int fromIndex) {
|
||||
return string.substring(fromIndex).lastIndexOf(ch);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(String string, int ch, int fromIndex) {
|
||||
return Math.max(-1, string.lastIndexOf(ch) - fromIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link String#lastIndexOf(String, int)} over less efficient alternatives. */
|
||||
static final class StringLastIndexOfString {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("java:S4635" /* This violation will be rewritten. */)
|
||||
int before(String string, String substring, int fromIndex) {
|
||||
return string.substring(fromIndex).lastIndexOf(substring);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(String string, String substring, int fromIndex) {
|
||||
return Math.max(-1, string.lastIndexOf(substring) - fromIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link String#lastIndexOf(int, int)} over less efficient alternatives. */
|
||||
static final class StringLastIndexOfCharWithIndex {
|
||||
@BeforeTemplate
|
||||
int before(String string, int ch, int fromIndex) {
|
||||
return string.substring(0, fromIndex).lastIndexOf(ch);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(String string, int ch, int fromIndex) {
|
||||
return string.lastIndexOf(ch, fromIndex - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link String#lastIndexOf(String, int)} over less efficient alternatives. */
|
||||
// XXX: The replacement expression isn't fully equivalent: in case `substring` is empty, then
|
||||
// the replacement yields `fromIndex - 1` rather than `fromIndex`.
|
||||
static final class StringLastIndexOfStringWithIndex {
|
||||
@BeforeTemplate
|
||||
int before(String string, String substring, int fromIndex) {
|
||||
return string.substring(0, fromIndex).lastIndexOf(substring);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
int after(String string, String substring, int fromIndex) {
|
||||
return string.lastIndexOf(substring, fromIndex - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link String#startsWith(String, int)} over less efficient alternatives. */
|
||||
static final class StringStartsWith {
|
||||
@BeforeTemplate
|
||||
@SuppressWarnings("java:S4635" /* This violation will be rewritten. */)
|
||||
boolean before(String string, String prefix, int fromIndex) {
|
||||
return string.substring(fromIndex).startsWith(prefix);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
boolean after(String string, String prefix, int fromIndex) {
|
||||
return string.startsWith(prefix, fromIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,8 +161,9 @@ final class TestNGToAssertJRules {
|
||||
|
||||
@AfterTemplate
|
||||
@DoNotCall
|
||||
@UseImportPolicy(STATIC_IMPORT_ALWAYS)
|
||||
void after() {
|
||||
throw new AssertionError();
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +142,63 @@ final class TimeRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily transform an {@link Instant} to an equivalent instance. */
|
||||
static final class InstantIdentity {
|
||||
@BeforeTemplate
|
||||
Instant before(Instant instant, TemporalUnit temporalUnit) {
|
||||
return Refaster.anyOf(
|
||||
instant.plus(Duration.ZERO),
|
||||
instant.plus(0, temporalUnit),
|
||||
instant.plusNanos(0),
|
||||
instant.plusMillis(0),
|
||||
instant.plusSeconds(0),
|
||||
instant.minus(Duration.ZERO),
|
||||
instant.minus(0, temporalUnit),
|
||||
instant.minusNanos(0),
|
||||
instant.minusMillis(0),
|
||||
instant.minusSeconds(0),
|
||||
Instant.parse(instant.toString()),
|
||||
instant.truncatedTo(ChronoUnit.NANOS),
|
||||
Instant.ofEpochSecond(instant.getEpochSecond(), instant.getNano()));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Instant after(Instant instant) {
|
||||
return instant;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Instant#truncatedTo(TemporalUnit)} over less obvious alternatives.
|
||||
*
|
||||
* <p>Note that {@link Instant#toEpochMilli()} throws an {@link ArithmeticException} for dates
|
||||
* very far in the past or future, while the suggested alternative doesn't.
|
||||
*/
|
||||
static final class InstantTruncatedToMilliseconds {
|
||||
@BeforeTemplate
|
||||
Instant before(Instant instant) {
|
||||
return Instant.ofEpochMilli(instant.toEpochMilli());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Instant after(Instant instant) {
|
||||
return instant.truncatedTo(ChronoUnit.MILLIS);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Instant#truncatedTo(TemporalUnit)} over less obvious alternatives. */
|
||||
static final class InstantTruncatedToSeconds {
|
||||
@BeforeTemplate
|
||||
Instant before(Instant instant) {
|
||||
return Instant.ofEpochSecond(instant.getEpochSecond());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Instant after(Instant instant) {
|
||||
return instant.truncatedTo(ChronoUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Instant#atOffset(ZoneOffset)} over more verbose alternatives. */
|
||||
static final class InstantAtOffset {
|
||||
@BeforeTemplate
|
||||
|
||||
@@ -13,99 +13,101 @@ final class AmbiguousJsonCreatorTest {
|
||||
"X", m -> m.contains("`JsonCreator.Mode` should be set for single-argument creators"))
|
||||
.addSourceLines(
|
||||
"Container.java",
|
||||
"import com.fasterxml.jackson.annotation.JsonCreator;",
|
||||
"import com.fasterxml.jackson.annotation.JsonValue;",
|
||||
"",
|
||||
"interface Container {",
|
||||
" enum A {",
|
||||
" FOO(1);",
|
||||
"",
|
||||
" private final int i;",
|
||||
"",
|
||||
" A(int i) {",
|
||||
" this.i = i;",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" @JsonCreator",
|
||||
" public static A of(int i) {",
|
||||
" return FOO;",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" enum B {",
|
||||
" FOO(1);",
|
||||
"",
|
||||
" private final int i;",
|
||||
"",
|
||||
" B(int i) {",
|
||||
" this.i = i;",
|
||||
" }",
|
||||
"",
|
||||
" @JsonCreator(mode = JsonCreator.Mode.DELEGATING)",
|
||||
" public static B of(int i) {",
|
||||
" return FOO;",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" enum C {",
|
||||
" FOO(1, \"s\");",
|
||||
"",
|
||||
" @JsonValue private final int i;",
|
||||
" private final String s;",
|
||||
"",
|
||||
" C(int i, String s) {",
|
||||
" this.i = i;",
|
||||
" this.s = s;",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" @JsonCreator",
|
||||
" public static C of(int i) {",
|
||||
" return FOO;",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" enum D {",
|
||||
" FOO(1, \"s\");",
|
||||
"",
|
||||
" private final int i;",
|
||||
" private final String s;",
|
||||
"",
|
||||
" D(int i, String s) {",
|
||||
" this.i = i;",
|
||||
" this.s = s;",
|
||||
" }",
|
||||
"",
|
||||
" @JsonCreator",
|
||||
" public static D of(int i, String s) {",
|
||||
" return FOO;",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" enum E {",
|
||||
" FOO;",
|
||||
"",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" @JsonCreator",
|
||||
" public static E of(String s) {",
|
||||
" return FOO;",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" class F {",
|
||||
" private final String s;",
|
||||
"",
|
||||
" F(String s) {",
|
||||
" this.s = s;",
|
||||
" }",
|
||||
"",
|
||||
" @JsonCreator",
|
||||
" public static F of(String s) {",
|
||||
" return new F(s);",
|
||||
" }",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
|
||||
interface Container {
|
||||
enum A {
|
||||
FOO(1);
|
||||
|
||||
private final int i;
|
||||
|
||||
A(int i) {
|
||||
this.i = i;
|
||||
}
|
||||
|
||||
// BUG: Diagnostic matches: X
|
||||
@JsonCreator
|
||||
public static A of(int i) {
|
||||
return FOO;
|
||||
}
|
||||
}
|
||||
|
||||
enum B {
|
||||
FOO(1);
|
||||
|
||||
private final int i;
|
||||
|
||||
B(int i) {
|
||||
this.i = i;
|
||||
}
|
||||
|
||||
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
|
||||
public static B of(int i) {
|
||||
return FOO;
|
||||
}
|
||||
}
|
||||
|
||||
enum C {
|
||||
FOO(1, "s");
|
||||
|
||||
@JsonValue private final int i;
|
||||
private final String s;
|
||||
|
||||
C(int i, String s) {
|
||||
this.i = i;
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
// BUG: Diagnostic matches: X
|
||||
@JsonCreator
|
||||
public static C of(int i) {
|
||||
return FOO;
|
||||
}
|
||||
}
|
||||
|
||||
enum D {
|
||||
FOO(1, "s");
|
||||
|
||||
private final int i;
|
||||
private final String s;
|
||||
|
||||
D(int i, String s) {
|
||||
this.i = i;
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public static D of(int i, String s) {
|
||||
return FOO;
|
||||
}
|
||||
}
|
||||
|
||||
enum E {
|
||||
FOO;
|
||||
|
||||
// BUG: Diagnostic matches: X
|
||||
@JsonCreator
|
||||
public static E of(String s) {
|
||||
return FOO;
|
||||
}
|
||||
}
|
||||
|
||||
class F {
|
||||
private final String s;
|
||||
|
||||
F(String s) {
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public static F of(String s) {
|
||||
return new F(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -114,28 +116,32 @@ final class AmbiguousJsonCreatorTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(AmbiguousJsonCreator.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import com.fasterxml.jackson.annotation.JsonCreator;",
|
||||
"",
|
||||
"enum A {",
|
||||
" FOO;",
|
||||
"",
|
||||
" @JsonCreator",
|
||||
" public static A of(String s) {",
|
||||
" return FOO;",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
|
||||
enum A {
|
||||
FOO;
|
||||
|
||||
@JsonCreator
|
||||
public static A of(String s) {
|
||||
return FOO;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import com.fasterxml.jackson.annotation.JsonCreator;",
|
||||
"",
|
||||
"enum A {",
|
||||
" FOO;",
|
||||
"",
|
||||
" @JsonCreator(mode = JsonCreator.Mode.DELEGATING)",
|
||||
" public static A of(String s) {",
|
||||
" return FOO;",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
|
||||
enum A {
|
||||
FOO;
|
||||
|
||||
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
|
||||
public static A of(String s) {
|
||||
return FOO;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,22 +11,24 @@ final class AssertJIsNullTest {
|
||||
CompilationTestHelper.newInstance(AssertJIsNull.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static org.assertj.core.api.Assertions.assertThat;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" assertThat(1).isEqualTo(1);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(1).isEqualTo(null);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(\"foo\").isEqualTo(null);",
|
||||
" isEqualTo(null);",
|
||||
" }",
|
||||
"",
|
||||
" private boolean isEqualTo(Object value) {",
|
||||
" return value.equals(\"bar\");",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
assertThat(1).isEqualTo(1);
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(1).isEqualTo(null);
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat("foo").isEqualTo(null);
|
||||
isEqualTo(null);
|
||||
}
|
||||
|
||||
private boolean isEqualTo(Object value) {
|
||||
return value.equals("bar");
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -35,24 +37,28 @@ final class AssertJIsNullTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(AssertJIsNull.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static org.assertj.core.api.Assertions.assertThat;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" assertThat(1).isEqualTo(null);",
|
||||
" assertThat(\"foo\").isEqualTo(null);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
assertThat(1).isEqualTo(null);
|
||||
assertThat("foo").isEqualTo(null);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static org.assertj.core.api.Assertions.assertThat;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" assertThat(1).isNull();",
|
||||
" assertThat(\"foo\").isNull();",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
assertThat(1).isNull();
|
||||
assertThat("foo").isNull();
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,56 +11,58 @@ final class AutowiredConstructorTest {
|
||||
CompilationTestHelper.newInstance(AutowiredConstructor.class, getClass())
|
||||
.addSourceLines(
|
||||
"Container.java",
|
||||
"import com.google.errorprone.annotations.Immutable;",
|
||||
"import java.util.List;",
|
||||
"import org.springframework.beans.factory.annotation.Autowired;",
|
||||
"",
|
||||
"interface Container {",
|
||||
" @Immutable",
|
||||
" class A {",
|
||||
" A() {}",
|
||||
" }",
|
||||
"",
|
||||
" class B {",
|
||||
" @Autowired",
|
||||
" void setProperty(Object o) {}",
|
||||
" }",
|
||||
"",
|
||||
" class C {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Autowired",
|
||||
" C() {}",
|
||||
" }",
|
||||
"",
|
||||
" class D {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Autowired",
|
||||
" D(String x) {}",
|
||||
" }",
|
||||
"",
|
||||
" class E {",
|
||||
" @Autowired",
|
||||
" E() {}",
|
||||
"",
|
||||
" E(String x) {}",
|
||||
" }",
|
||||
"",
|
||||
" class F {",
|
||||
" F() {}",
|
||||
"",
|
||||
" @Autowired",
|
||||
" F(String x) {}",
|
||||
" }",
|
||||
"",
|
||||
" class G {",
|
||||
" @Autowired private Object o;",
|
||||
" }",
|
||||
"",
|
||||
" class H {",
|
||||
" @SafeVarargs",
|
||||
" H(List<String>... lists) {}",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
interface Container {
|
||||
@Immutable
|
||||
class A {
|
||||
A() {}
|
||||
}
|
||||
|
||||
class B {
|
||||
@Autowired
|
||||
void setProperty(Object o) {}
|
||||
}
|
||||
|
||||
class C {
|
||||
// BUG: Diagnostic contains:
|
||||
@Autowired
|
||||
C() {}
|
||||
}
|
||||
|
||||
class D {
|
||||
// BUG: Diagnostic contains:
|
||||
@Autowired
|
||||
D(String x) {}
|
||||
}
|
||||
|
||||
class E {
|
||||
@Autowired
|
||||
E() {}
|
||||
|
||||
E(String x) {}
|
||||
}
|
||||
|
||||
class F {
|
||||
F() {}
|
||||
|
||||
@Autowired
|
||||
F(String x) {}
|
||||
}
|
||||
|
||||
class G {
|
||||
@Autowired private Object o;
|
||||
}
|
||||
|
||||
class H {
|
||||
@SafeVarargs
|
||||
H(List<String>... lists) {}
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -69,34 +71,38 @@ final class AutowiredConstructorTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(AutowiredConstructor.class, getClass())
|
||||
.addInputLines(
|
||||
"Container.java",
|
||||
"import org.springframework.beans.factory.annotation.Autowired;",
|
||||
"",
|
||||
"interface Container {",
|
||||
" class A {",
|
||||
" @Autowired",
|
||||
" @Deprecated",
|
||||
" A() {}",
|
||||
" }",
|
||||
"",
|
||||
" class B {",
|
||||
" @Autowired",
|
||||
" B(String x) {}",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
interface Container {
|
||||
class A {
|
||||
@Autowired
|
||||
@Deprecated
|
||||
A() {}
|
||||
}
|
||||
|
||||
class B {
|
||||
@Autowired
|
||||
B(String x) {}
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"Container.java",
|
||||
"import org.springframework.beans.factory.annotation.Autowired;",
|
||||
"",
|
||||
"interface Container {",
|
||||
" class A {",
|
||||
" @Deprecated",
|
||||
" A() {}",
|
||||
" }",
|
||||
"",
|
||||
" class B {",
|
||||
" B(String x) {}",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
interface Container {
|
||||
class A {
|
||||
@Deprecated
|
||||
A() {}
|
||||
}
|
||||
|
||||
class B {
|
||||
B(String x) {}
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,128 +11,130 @@ final class CanonicalAnnotationSyntaxTest {
|
||||
CompilationTestHelper.newInstance(CanonicalAnnotationSyntax.class, getClass())
|
||||
.addSourceLines(
|
||||
"pkg/A.java",
|
||||
"package pkg;",
|
||||
"",
|
||||
"import pkg.A.Foo;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @interface Foo {",
|
||||
" int[] value() default {};",
|
||||
"",
|
||||
" int[] value2() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @pkg.A.Foo",
|
||||
" A minimal1();",
|
||||
"",
|
||||
" @A.Foo",
|
||||
" A minimal2();",
|
||||
"",
|
||||
" @Foo",
|
||||
" A minimal3();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @pkg.A.Foo()",
|
||||
" A functional1();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @A.Foo()",
|
||||
" A functional2();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo()",
|
||||
" A functional3();",
|
||||
"",
|
||||
" @pkg.A.Foo(1)",
|
||||
" A simple1();",
|
||||
"",
|
||||
" @A.Foo(1)",
|
||||
" A simple2();",
|
||||
"",
|
||||
" @Foo(1)",
|
||||
" A simple3();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @pkg.A.Foo({1})",
|
||||
" A singleton1();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @A.Foo({1})",
|
||||
" A singleton2();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo({1})",
|
||||
" A singleton3();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @pkg.A.Foo(value = 1)",
|
||||
" A verbose1();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @A.Foo(value = 1)",
|
||||
" A verbose2();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo(value = 1)",
|
||||
" A verbose3();",
|
||||
"",
|
||||
" @pkg.A.Foo(value2 = 2)",
|
||||
" A custom1();",
|
||||
"",
|
||||
" @A.Foo(value2 = 2)",
|
||||
" A custom2();",
|
||||
"",
|
||||
" @Foo(value2 = 2)",
|
||||
" A custom3();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @pkg.A.Foo(value2 = {2})",
|
||||
" A customSingleton1();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @A.Foo(value2 = {2})",
|
||||
" A customSingleton2();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo(value2 = {2})",
|
||||
" A customSingleton3();",
|
||||
"",
|
||||
" @pkg.A.Foo(value2 = {2, 2})",
|
||||
" A customPair1();",
|
||||
"",
|
||||
" @A.Foo(value2 = {2, 2})",
|
||||
" A customPair2();",
|
||||
"",
|
||||
" @Foo(value2 = {2, 2})",
|
||||
" A customPair3();",
|
||||
"",
|
||||
" @pkg.A.Foo(value = 1, value2 = 2)",
|
||||
" A extended1();",
|
||||
"",
|
||||
" @A.Foo(value = 1, value2 = 2)",
|
||||
" A extended2();",
|
||||
"",
|
||||
" @Foo(value = 1, value2 = 2)",
|
||||
" A extended3();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @pkg.A.Foo({",
|
||||
" 1, 1,",
|
||||
" })",
|
||||
" A trailingComma1();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @A.Foo({",
|
||||
" 1, 1,",
|
||||
" })",
|
||||
" A trailingComma2();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo({",
|
||||
" 1, 1,",
|
||||
" })",
|
||||
" A trailingComma3();",
|
||||
"}")
|
||||
"""
|
||||
package pkg;
|
||||
|
||||
import pkg.A.Foo;
|
||||
|
||||
interface A {
|
||||
@interface Foo {
|
||||
int[] value() default {};
|
||||
|
||||
int[] value2() default {};
|
||||
}
|
||||
|
||||
@pkg.A.Foo
|
||||
A minimal1();
|
||||
|
||||
@A.Foo
|
||||
A minimal2();
|
||||
|
||||
@Foo
|
||||
A minimal3();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@pkg.A.Foo()
|
||||
A functional1();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@A.Foo()
|
||||
A functional2();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo()
|
||||
A functional3();
|
||||
|
||||
@pkg.A.Foo(1)
|
||||
A simple1();
|
||||
|
||||
@A.Foo(1)
|
||||
A simple2();
|
||||
|
||||
@Foo(1)
|
||||
A simple3();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@pkg.A.Foo({1})
|
||||
A singleton1();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@A.Foo({1})
|
||||
A singleton2();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo({1})
|
||||
A singleton3();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@pkg.A.Foo(value = 1)
|
||||
A verbose1();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@A.Foo(value = 1)
|
||||
A verbose2();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo(value = 1)
|
||||
A verbose3();
|
||||
|
||||
@pkg.A.Foo(value2 = 2)
|
||||
A custom1();
|
||||
|
||||
@A.Foo(value2 = 2)
|
||||
A custom2();
|
||||
|
||||
@Foo(value2 = 2)
|
||||
A custom3();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@pkg.A.Foo(value2 = {2})
|
||||
A customSingleton1();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@A.Foo(value2 = {2})
|
||||
A customSingleton2();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo(value2 = {2})
|
||||
A customSingleton3();
|
||||
|
||||
@pkg.A.Foo(value2 = {2, 2})
|
||||
A customPair1();
|
||||
|
||||
@A.Foo(value2 = {2, 2})
|
||||
A customPair2();
|
||||
|
||||
@Foo(value2 = {2, 2})
|
||||
A customPair3();
|
||||
|
||||
@pkg.A.Foo(value = 1, value2 = 2)
|
||||
A extended1();
|
||||
|
||||
@A.Foo(value = 1, value2 = 2)
|
||||
A extended2();
|
||||
|
||||
@Foo(value = 1, value2 = 2)
|
||||
A extended3();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@pkg.A.Foo({
|
||||
1, 1,
|
||||
})
|
||||
A trailingComma1();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@A.Foo({
|
||||
1, 1,
|
||||
})
|
||||
A trailingComma2();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo({
|
||||
1, 1,
|
||||
})
|
||||
A trailingComma3();
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -141,139 +143,143 @@ final class CanonicalAnnotationSyntaxTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(CanonicalAnnotationSyntax.class, getClass())
|
||||
.addInputLines(
|
||||
"pkg/A.java",
|
||||
"package pkg;",
|
||||
"",
|
||||
"import pkg.A.Foo;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @interface Foo {",
|
||||
" String[] value() default {};",
|
||||
"",
|
||||
" int[] value2() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @pkg.A.Foo()",
|
||||
" A functional1();",
|
||||
"",
|
||||
" @A.Foo()",
|
||||
" A functional2();",
|
||||
"",
|
||||
" @Foo()",
|
||||
" A functional3();",
|
||||
"",
|
||||
" @pkg.A.Foo(value = \"foo\")",
|
||||
" A verbose1();",
|
||||
"",
|
||||
" @A.Foo(value = \"a'b\")",
|
||||
" A verbose2();",
|
||||
"",
|
||||
" @Foo(value = \"a\" + \"\\nb\")",
|
||||
" A verbose3();",
|
||||
"",
|
||||
" @pkg.A.Foo(value = {\"foo\"})",
|
||||
" A moreVerbose1();",
|
||||
"",
|
||||
" @A.Foo(value = {\"a'b\"})",
|
||||
" A moreVerbose2();",
|
||||
"",
|
||||
" @Foo(value = {\"a\" + \"\\nb\"})",
|
||||
" A moreVerbose3();",
|
||||
"",
|
||||
" @pkg.A.Foo(",
|
||||
" value = {\"foo\", \"bar\"},",
|
||||
" value2 = {2})",
|
||||
" A extended1();",
|
||||
"",
|
||||
" @A.Foo(",
|
||||
" value = {\"a'b\", \"c'd\"},",
|
||||
" value2 = {2})",
|
||||
" A extended2();",
|
||||
"",
|
||||
" @Foo(",
|
||||
" value = {\"a\" + \"\\nb\", \"c\" + \"\\nd\"},",
|
||||
" value2 = {2})",
|
||||
" A extended3();",
|
||||
"",
|
||||
" @pkg.A.Foo({",
|
||||
" \"foo\", \"bar\",",
|
||||
" })",
|
||||
" A trailingComma1();",
|
||||
"",
|
||||
" @A.Foo({",
|
||||
" \"a'b\", \"c'd\",",
|
||||
" })",
|
||||
" A trailingComma2();",
|
||||
"",
|
||||
" @Foo({",
|
||||
" \"a\" + \"\\nb\",",
|
||||
" \"c\" + \"\\nd\",",
|
||||
" })",
|
||||
" A trailingComma3();",
|
||||
"}")
|
||||
"""
|
||||
package pkg;
|
||||
|
||||
import pkg.A.Foo;
|
||||
|
||||
interface A {
|
||||
@interface Foo {
|
||||
String[] value() default {};
|
||||
|
||||
int[] value2() default {};
|
||||
}
|
||||
|
||||
@pkg.A.Foo()
|
||||
A functional1();
|
||||
|
||||
@A.Foo()
|
||||
A functional2();
|
||||
|
||||
@Foo()
|
||||
A functional3();
|
||||
|
||||
@pkg.A.Foo(value = "foo")
|
||||
A verbose1();
|
||||
|
||||
@A.Foo(value = "a'b")
|
||||
A verbose2();
|
||||
|
||||
@Foo(value = "a" + "\\nb")
|
||||
A verbose3();
|
||||
|
||||
@pkg.A.Foo(value = {"foo"})
|
||||
A moreVerbose1();
|
||||
|
||||
@A.Foo(value = {"a'b"})
|
||||
A moreVerbose2();
|
||||
|
||||
@Foo(value = {"a" + "\\nb"})
|
||||
A moreVerbose3();
|
||||
|
||||
@pkg.A.Foo(
|
||||
value = {"foo", "bar"},
|
||||
value2 = {2})
|
||||
A extended1();
|
||||
|
||||
@A.Foo(
|
||||
value = {"a'b", "c'd"},
|
||||
value2 = {2})
|
||||
A extended2();
|
||||
|
||||
@Foo(
|
||||
value = {"a" + "\\nb", "c" + "\\nd"},
|
||||
value2 = {2})
|
||||
A extended3();
|
||||
|
||||
@pkg.A.Foo({
|
||||
"foo", "bar",
|
||||
})
|
||||
A trailingComma1();
|
||||
|
||||
@A.Foo({
|
||||
"a'b", "c'd",
|
||||
})
|
||||
A trailingComma2();
|
||||
|
||||
@Foo({
|
||||
"a" + "\\nb",
|
||||
"c" + "\\nd",
|
||||
})
|
||||
A trailingComma3();
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"pkg/A.java",
|
||||
"package pkg;",
|
||||
"",
|
||||
"import pkg.A.Foo;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @interface Foo {",
|
||||
" String[] value() default {};",
|
||||
"",
|
||||
" int[] value2() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @pkg.A.Foo",
|
||||
" A functional1();",
|
||||
"",
|
||||
" @A.Foo",
|
||||
" A functional2();",
|
||||
"",
|
||||
" @Foo",
|
||||
" A functional3();",
|
||||
"",
|
||||
" @pkg.A.Foo(\"foo\")",
|
||||
" A verbose1();",
|
||||
"",
|
||||
" @A.Foo(\"a'b\")",
|
||||
" A verbose2();",
|
||||
"",
|
||||
" @Foo(\"a\" + \"\\nb\")",
|
||||
" A verbose3();",
|
||||
"",
|
||||
" @pkg.A.Foo(\"foo\")",
|
||||
" A moreVerbose1();",
|
||||
"",
|
||||
" @A.Foo(\"a'b\")",
|
||||
" A moreVerbose2();",
|
||||
"",
|
||||
" @Foo(\"a\" + \"\\nb\")",
|
||||
" A moreVerbose3();",
|
||||
"",
|
||||
" @pkg.A.Foo(",
|
||||
" value = {\"foo\", \"bar\"},",
|
||||
" value2 = 2)",
|
||||
" A extended1();",
|
||||
"",
|
||||
" @A.Foo(",
|
||||
" value = {\"a'b\", \"c'd\"},",
|
||||
" value2 = 2)",
|
||||
" A extended2();",
|
||||
"",
|
||||
" @Foo(",
|
||||
" value = {\"a\" + \"\\nb\", \"c\" + \"\\nd\"},",
|
||||
" value2 = 2)",
|
||||
" A extended3();",
|
||||
"",
|
||||
" @pkg.A.Foo({\"foo\", \"bar\"})",
|
||||
" A trailingComma1();",
|
||||
"",
|
||||
" @A.Foo({\"a'b\", \"c'd\"})",
|
||||
" A trailingComma2();",
|
||||
"",
|
||||
" @Foo({\"a\" + \"\\nb\", \"c\" + \"\\nd\"})",
|
||||
" A trailingComma3();",
|
||||
"}")
|
||||
"""
|
||||
package pkg;
|
||||
|
||||
import pkg.A.Foo;
|
||||
|
||||
interface A {
|
||||
@interface Foo {
|
||||
String[] value() default {};
|
||||
|
||||
int[] value2() default {};
|
||||
}
|
||||
|
||||
@pkg.A.Foo
|
||||
A functional1();
|
||||
|
||||
@A.Foo
|
||||
A functional2();
|
||||
|
||||
@Foo
|
||||
A functional3();
|
||||
|
||||
@pkg.A.Foo("foo")
|
||||
A verbose1();
|
||||
|
||||
@A.Foo("a'b")
|
||||
A verbose2();
|
||||
|
||||
@Foo("a" + "\\nb")
|
||||
A verbose3();
|
||||
|
||||
@pkg.A.Foo("foo")
|
||||
A moreVerbose1();
|
||||
|
||||
@A.Foo("a'b")
|
||||
A moreVerbose2();
|
||||
|
||||
@Foo("a" + "\\nb")
|
||||
A moreVerbose3();
|
||||
|
||||
@pkg.A.Foo(
|
||||
value = {"foo", "bar"},
|
||||
value2 = 2)
|
||||
A extended1();
|
||||
|
||||
@A.Foo(
|
||||
value = {"a'b", "c'd"},
|
||||
value2 = 2)
|
||||
A extended2();
|
||||
|
||||
@Foo(
|
||||
value = {"a" + "\\nb", "c" + "\\nd"},
|
||||
value2 = 2)
|
||||
A extended3();
|
||||
|
||||
@pkg.A.Foo({"foo", "bar"})
|
||||
A trailingComma1();
|
||||
|
||||
@A.Foo({"a'b", "c'd"})
|
||||
A trailingComma2();
|
||||
|
||||
@Foo({"a" + "\\nb", "c" + "\\nd"})
|
||||
A trailingComma3();
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,35 +14,37 @@ final class CanonicalClassNameUsageTest {
|
||||
"--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED")
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static com.google.errorprone.matchers.Matchers.instanceMethod;",
|
||||
"",
|
||||
"import com.google.errorprone.VisitorState;",
|
||||
"import tech.picnic.errorprone.utils.MoreTypes;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m(VisitorState state) {",
|
||||
" String a = A.class.getName();",
|
||||
" String b = getClass().getName();",
|
||||
" A.class.getName().toString();",
|
||||
" System.out.println(A.class.getName());",
|
||||
" methodInUnnamedPackage(A.class.getName());",
|
||||
" instanceMethod().onExactClass(A.class.getCanonicalName());",
|
||||
" MoreTypes.type(A.class.getCanonicalName());",
|
||||
" MoreTypes.type(A.class.getCanonicalName() + \".SubType\");",
|
||||
" instanceMethod().onExactClass(new Object() {}.getClass().getName());",
|
||||
" instanceMethod().onExactClass(methodInUnnamedPackage(A.class.getName()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" instanceMethod().onExactClass(A.class.getName());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" MoreTypes.type(A.class.getName());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" state.binaryNameFromClassname(A.class.getName() + \".SubType\");",
|
||||
" }",
|
||||
"",
|
||||
" String methodInUnnamedPackage(String str) {",
|
||||
" return str;",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
|
||||
import com.google.errorprone.VisitorState;
|
||||
import tech.picnic.errorprone.utils.MoreTypes;
|
||||
|
||||
class A {
|
||||
void m(VisitorState state) {
|
||||
String a = A.class.getName();
|
||||
String b = getClass().getName();
|
||||
A.class.getName().toString();
|
||||
System.out.println(A.class.getName());
|
||||
methodInUnnamedPackage(A.class.getName());
|
||||
instanceMethod().onExactClass(A.class.getCanonicalName());
|
||||
MoreTypes.type(A.class.getCanonicalName());
|
||||
MoreTypes.type(A.class.getCanonicalName() + ".SubType");
|
||||
instanceMethod().onExactClass(new Object() {}.getClass().getName());
|
||||
instanceMethod().onExactClass(methodInUnnamedPackage(A.class.getName()));
|
||||
// BUG: Diagnostic contains:
|
||||
instanceMethod().onExactClass(A.class.getName());
|
||||
// BUG: Diagnostic contains:
|
||||
MoreTypes.type(A.class.getName());
|
||||
// BUG: Diagnostic contains:
|
||||
state.binaryNameFromClassname(A.class.getName() + ".SubType");
|
||||
}
|
||||
|
||||
String methodInUnnamedPackage(String str) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -51,32 +53,36 @@ final class CanonicalClassNameUsageTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(CanonicalClassNameUsage.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static com.google.errorprone.matchers.Matchers.instanceMethod;",
|
||||
"",
|
||||
"import com.google.errorprone.BugPattern;",
|
||||
"import tech.picnic.errorprone.utils.MoreTypes;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" instanceMethod().onDescendantOfAny(A.class.getName(), BugPattern.LinkType.class.getName());",
|
||||
" MoreTypes.type(String.class.getName());",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
|
||||
import com.google.errorprone.BugPattern;
|
||||
import tech.picnic.errorprone.utils.MoreTypes;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
instanceMethod().onDescendantOfAny(A.class.getName(), BugPattern.LinkType.class.getName());
|
||||
MoreTypes.type(String.class.getName());
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static com.google.errorprone.matchers.Matchers.instanceMethod;",
|
||||
"",
|
||||
"import com.google.errorprone.BugPattern;",
|
||||
"import tech.picnic.errorprone.utils.MoreTypes;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" instanceMethod()",
|
||||
" .onDescendantOfAny(",
|
||||
" A.class.getCanonicalName(), BugPattern.LinkType.class.getCanonicalName());",
|
||||
" MoreTypes.type(String.class.getCanonicalName());",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
|
||||
import com.google.errorprone.BugPattern;
|
||||
import tech.picnic.errorprone.utils.MoreTypes;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
instanceMethod()
|
||||
.onDescendantOfAny(
|
||||
A.class.getCanonicalName(), BugPattern.LinkType.class.getCanonicalName());
|
||||
MoreTypes.type(String.class.getCanonicalName());
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class ClassCastLambdaUsageTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(ClassCastLambdaUsage.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"""
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class A {
|
||||
<T> void m() {
|
||||
Number localVariable = 0;
|
||||
|
||||
Stream.of(0).map(i -> i);
|
||||
Stream.of(1).map(i -> i + 1);
|
||||
Stream.of(2).map(Integer.class::cast);
|
||||
Stream.of(3).map(i -> (Integer) 2);
|
||||
Stream.of(4).map(i -> (Integer) localVariable);
|
||||
// XXX: Ideally this case is also flagged. Pick this up in the context of merging the
|
||||
// `ClassCastLambdaUsage` and `MethodReferenceUsage` checks, or introduce a separate check that
|
||||
// simplifies unnecessary block lambda expressions.
|
||||
Stream.of(5)
|
||||
.map(
|
||||
i -> {
|
||||
return (Integer) i;
|
||||
});
|
||||
Stream.<ImmutableSet>of(ImmutableSet.of(6)).map(s -> (ImmutableSet<Number>) s);
|
||||
Stream.of(ImmutableSet.of(7)).map(s -> (ImmutableSet<?>) s);
|
||||
Stream.of(8).reduce((a, b) -> (Integer) a);
|
||||
IntStream.of(9).mapToObj(i -> (char) i);
|
||||
Stream.of(10).map(i -> (T) i);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Stream.of(11).map(i -> (Integer) i);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(ClassCastLambdaUsage.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"""
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Stream.of(1).map(i -> (Integer) i);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"""
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Stream.of(1).map(Integer.class::cast);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -13,50 +13,52 @@ final class CollectorMutabilityTest {
|
||||
CompilationTestHelper.newInstance(CollectorMutability.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static com.google.common.collect.ImmutableList.toImmutableList;",
|
||||
"import static com.google.common.collect.ImmutableMap.toImmutableMap;",
|
||||
"import static com.google.common.collect.ImmutableSet.toImmutableSet;",
|
||||
"import static java.util.stream.Collectors.toCollection;",
|
||||
"import static java.util.stream.Collectors.toList;",
|
||||
"import static java.util.stream.Collectors.toMap;",
|
||||
"import static java.util.stream.Collectors.toSet;",
|
||||
"",
|
||||
"import java.util.ArrayList;",
|
||||
"import java.util.HashMap;",
|
||||
"import java.util.HashSet;",
|
||||
"import java.util.stream.Collectors;",
|
||||
"import java.util.stream.Stream;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collect(Collectors.toList());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(2).collect(toList());",
|
||||
" Flux.just(3).collect(toImmutableList());",
|
||||
" Flux.just(4).collect(toCollection(ArrayList::new));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(\"foo\").collect(Collectors.toMap(String::getBytes, String::length));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(\"bar\").collect(toMap(String::getBytes, String::length));",
|
||||
" Flux.just(\"baz\").collect(toImmutableMap(String::getBytes, String::length));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(\"qux\").collect(toMap(String::getBytes, String::length, (a, b) -> a));",
|
||||
" Flux.just(\"quux\").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> a));",
|
||||
" Flux.just(\"quuz\").collect(toMap(String::getBytes, String::length, (a, b) -> a, HashMap::new));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Stream.of(1).collect(Collectors.toSet());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Stream.of(2).collect(toSet());",
|
||||
" Stream.of(3).collect(toImmutableSet());",
|
||||
" Stream.of(4).collect(toCollection(HashSet::new));",
|
||||
"",
|
||||
" Flux.just(\"foo\").collect(Collectors.joining());",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static java.util.stream.Collectors.toCollection;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).collect(Collectors.toList());
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(2).collect(toList());
|
||||
Flux.just(3).collect(toImmutableList());
|
||||
Flux.just(4).collect(toCollection(ArrayList::new));
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just("foo").collect(Collectors.toMap(String::getBytes, String::length));
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just("bar").collect(toMap(String::getBytes, String::length));
|
||||
Flux.just("baz").collect(toImmutableMap(String::getBytes, String::length));
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just("qux").collect(toMap(String::getBytes, String::length, (a, b) -> a));
|
||||
Flux.just("quux").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> a));
|
||||
Flux.just("quuz").collect(toMap(String::getBytes, String::length, (a, b) -> a, HashMap::new));
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Stream.of(1).collect(Collectors.toSet());
|
||||
// BUG: Diagnostic contains:
|
||||
Stream.of(2).collect(toSet());
|
||||
Stream.of(3).collect(toImmutableSet());
|
||||
Stream.of(4).collect(toCollection(HashSet::new));
|
||||
|
||||
Flux.just("foo").collect(Collectors.joining());
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -66,14 +68,16 @@ final class CollectorMutabilityTest {
|
||||
.withClasspath()
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.stream.Collectors;",
|
||||
"import java.util.stream.Stream;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Stream.empty().collect(Collectors.toList());",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Stream.empty().collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -82,55 +86,59 @@ final class CollectorMutabilityTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(CollectorMutability.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static java.util.stream.Collectors.toList;",
|
||||
"import static java.util.stream.Collectors.toMap;",
|
||||
"import static java.util.stream.Collectors.toSet;",
|
||||
"",
|
||||
"import java.util.stream.Collectors;",
|
||||
"import java.util.stream.Stream;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Flux.just(1).collect(Collectors.toList());",
|
||||
" Flux.just(2).collect(toList());",
|
||||
"",
|
||||
" Stream.of(\"foo\").collect(Collectors.toMap(String::getBytes, String::length));",
|
||||
" Stream.of(\"bar\").collect(toMap(String::getBytes, String::length));",
|
||||
" Flux.just(\"baz\").collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b));",
|
||||
" Flux.just(\"qux\").collect(toMap(String::getBytes, String::length, (a, b) -> b));",
|
||||
"",
|
||||
" Stream.of(1).collect(Collectors.toSet());",
|
||||
" Stream.of(2).collect(toSet());",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Flux.just(1).collect(Collectors.toList());
|
||||
Flux.just(2).collect(toList());
|
||||
|
||||
Stream.of("foo").collect(Collectors.toMap(String::getBytes, String::length));
|
||||
Stream.of("bar").collect(toMap(String::getBytes, String::length));
|
||||
Flux.just("baz").collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b));
|
||||
Flux.just("qux").collect(toMap(String::getBytes, String::length, (a, b) -> b));
|
||||
|
||||
Stream.of(1).collect(Collectors.toSet());
|
||||
Stream.of(2).collect(toSet());
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static com.google.common.collect.ImmutableList.toImmutableList;",
|
||||
"import static com.google.common.collect.ImmutableMap.toImmutableMap;",
|
||||
"import static com.google.common.collect.ImmutableSet.toImmutableSet;",
|
||||
"import static java.util.stream.Collectors.toList;",
|
||||
"import static java.util.stream.Collectors.toMap;",
|
||||
"import static java.util.stream.Collectors.toSet;",
|
||||
"",
|
||||
"import java.util.stream.Collectors;",
|
||||
"import java.util.stream.Stream;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Flux.just(1).collect(toImmutableList());",
|
||||
" Flux.just(2).collect(toImmutableList());",
|
||||
"",
|
||||
" Stream.of(\"foo\").collect(toImmutableMap(String::getBytes, String::length));",
|
||||
" Stream.of(\"bar\").collect(toImmutableMap(String::getBytes, String::length));",
|
||||
" Flux.just(\"baz\").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> b));",
|
||||
" Flux.just(\"qux\").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> b));",
|
||||
"",
|
||||
" Stream.of(1).collect(toImmutableSet());",
|
||||
" Stream.of(2).collect(toImmutableSet());",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Flux.just(1).collect(toImmutableList());
|
||||
Flux.just(2).collect(toImmutableList());
|
||||
|
||||
Stream.of("foo").collect(toImmutableMap(String::getBytes, String::length));
|
||||
Stream.of("bar").collect(toImmutableMap(String::getBytes, String::length));
|
||||
Flux.just("baz").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> b));
|
||||
Flux.just("qux").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> b));
|
||||
|
||||
Stream.of(1).collect(toImmutableSet());
|
||||
Stream.of(2).collect(toImmutableSet());
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@@ -140,73 +148,77 @@ final class CollectorMutabilityTest {
|
||||
.setFixChooser(SECOND)
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static java.util.stream.Collectors.toList;",
|
||||
"import static java.util.stream.Collectors.toMap;",
|
||||
"import static java.util.stream.Collectors.toSet;",
|
||||
"",
|
||||
"import java.util.stream.Collectors;",
|
||||
"import java.util.stream.Stream;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Flux.just(1).collect(Collectors.toList());",
|
||||
" Flux.just(2).collect(toList());",
|
||||
"",
|
||||
" Stream.of(\"foo\").collect(Collectors.toMap(String::getBytes, String::length));",
|
||||
" Stream.of(\"bar\").collect(toMap(String::getBytes, String::length));",
|
||||
" Flux.just(\"baz\").collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b));",
|
||||
" Flux.just(\"qux\").collect(toMap(String::getBytes, String::length, (a, b) -> b));",
|
||||
"",
|
||||
" Stream.of(1).collect(Collectors.toSet());",
|
||||
" Stream.of(2).collect(toSet());",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Flux.just(1).collect(Collectors.toList());
|
||||
Flux.just(2).collect(toList());
|
||||
|
||||
Stream.of("foo").collect(Collectors.toMap(String::getBytes, String::length));
|
||||
Stream.of("bar").collect(toMap(String::getBytes, String::length));
|
||||
Flux.just("baz").collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b));
|
||||
Flux.just("qux").collect(toMap(String::getBytes, String::length, (a, b) -> b));
|
||||
|
||||
Stream.of(1).collect(Collectors.toSet());
|
||||
Stream.of(2).collect(toSet());
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static java.util.stream.Collectors.toCollection;",
|
||||
"import static java.util.stream.Collectors.toList;",
|
||||
"import static java.util.stream.Collectors.toMap;",
|
||||
"import static java.util.stream.Collectors.toSet;",
|
||||
"",
|
||||
"import java.util.ArrayList;",
|
||||
"import java.util.HashMap;",
|
||||
"import java.util.HashSet;",
|
||||
"import java.util.stream.Collectors;",
|
||||
"import java.util.stream.Stream;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Flux.just(1).collect(toCollection(ArrayList::new));",
|
||||
" Flux.just(2).collect(toCollection(ArrayList::new));",
|
||||
"",
|
||||
" Stream.of(\"foo\")",
|
||||
" .collect(",
|
||||
" Collectors.toMap(",
|
||||
" String::getBytes,",
|
||||
" String::length,",
|
||||
" (a, b) -> {",
|
||||
" throw new IllegalStateException();",
|
||||
" },",
|
||||
" HashMap::new));",
|
||||
" Stream.of(\"bar\")",
|
||||
" .collect(",
|
||||
" toMap(",
|
||||
" String::getBytes,",
|
||||
" String::length,",
|
||||
" (a, b) -> {",
|
||||
" throw new IllegalStateException();",
|
||||
" },",
|
||||
" HashMap::new));",
|
||||
" Flux.just(\"baz\")",
|
||||
" .collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b, HashMap::new));",
|
||||
" Flux.just(\"qux\").collect(toMap(String::getBytes, String::length, (a, b) -> b, HashMap::new));",
|
||||
"",
|
||||
" Stream.of(1).collect(toCollection(HashSet::new));",
|
||||
" Stream.of(2).collect(toCollection(HashSet::new));",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static java.util.stream.Collectors.toCollection;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Flux.just(1).collect(toCollection(ArrayList::new));
|
||||
Flux.just(2).collect(toCollection(ArrayList::new));
|
||||
|
||||
Stream.of("foo")
|
||||
.collect(
|
||||
Collectors.toMap(
|
||||
String::getBytes,
|
||||
String::length,
|
||||
(a, b) -> {
|
||||
throw new IllegalStateException();
|
||||
},
|
||||
HashMap::new));
|
||||
Stream.of("bar")
|
||||
.collect(
|
||||
toMap(
|
||||
String::getBytes,
|
||||
String::length,
|
||||
(a, b) -> {
|
||||
throw new IllegalStateException();
|
||||
},
|
||||
HashMap::new));
|
||||
Flux.just("baz")
|
||||
.collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b, HashMap::new));
|
||||
Flux.just("qux").collect(toMap(String::getBytes, String::length, (a, b) -> b, HashMap::new));
|
||||
|
||||
Stream.of(1).collect(toCollection(HashSet::new));
|
||||
Stream.of(2).collect(toCollection(HashSet::new));
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class ConstantNamingTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(ConstantNaming.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"""
|
||||
class A {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final int FOO = 1;
|
||||
// BUG: Diagnostic contains: consider renaming to 'BAR', though note that this is not a private
|
||||
// constant
|
||||
static final int bar = 2;
|
||||
// BUG: Diagnostic contains:
|
||||
private static final int baz = 3;
|
||||
// BUG: Diagnostic contains: consider renaming to 'QUX_QUUX', though note that a variable with
|
||||
// this name is already declared
|
||||
private static final int qux_QUUX = 4;
|
||||
// BUG: Diagnostic contains: consider renaming to 'QUUZ', though note that a variable with
|
||||
// this name is already declared
|
||||
private static final int quuz = 3;
|
||||
|
||||
private final int foo = 4;
|
||||
private final Runnable QUX_QUUX =
|
||||
new Runnable() {
|
||||
private static final int QUUZ = 1;
|
||||
|
||||
@Override
|
||||
public void run() {}
|
||||
};
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void identificationWithCustomExemption() {
|
||||
CompilationTestHelper.newInstance(ConstantNaming.class, getClass())
|
||||
.setArgs("-XepOpt:CanonicalConstantNaming:ExemptedNames=foo,baz")
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"""
|
||||
class A {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final int foo = 1;
|
||||
// BUG: Diagnostic contains:
|
||||
private static final int bar = 2;
|
||||
private static final int baz = 3;
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(ConstantNaming.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"""
|
||||
class A {
|
||||
static final int foo = 1;
|
||||
private static final int bar = 2;
|
||||
private static final int baz = 3;
|
||||
private static final int BAZ = 4;
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"""
|
||||
class A {
|
||||
static final int foo = 1;
|
||||
private static final int BAR = 2;
|
||||
private static final int baz = 3;
|
||||
private static final int BAZ = 4;
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -11,184 +11,186 @@ final class DirectReturnTest {
|
||||
CompilationTestHelper.newInstance(DirectReturn.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static org.mockito.Mockito.mock;",
|
||||
"import static org.mockito.Mockito.spy;",
|
||||
"",
|
||||
"import java.util.function.Supplier;",
|
||||
"",
|
||||
"class A {",
|
||||
" private String field;",
|
||||
"",
|
||||
" void emptyMethod() {}",
|
||||
"",
|
||||
" void voidMethod() {",
|
||||
" toString();",
|
||||
" return;",
|
||||
" }",
|
||||
"",
|
||||
" String directReturnOfParam(String param) {",
|
||||
" return param;",
|
||||
" }",
|
||||
"",
|
||||
" String assignmentToField() {",
|
||||
" field = toString();",
|
||||
" return field;",
|
||||
" }",
|
||||
"",
|
||||
" Object redundantAssignmentToParam(String param) {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" param = toString();",
|
||||
" return param;",
|
||||
" }",
|
||||
"",
|
||||
" String redundantMockAssignmentToParam(String param) {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" param = mock();",
|
||||
" return param;",
|
||||
" }",
|
||||
"",
|
||||
" Object redundantMockWithExplicitTypeAssignmentToParam(String param) {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" param = mock(String.class);",
|
||||
" return param;",
|
||||
" }",
|
||||
"",
|
||||
" Object salientMockAssignmentToParam(String param) {",
|
||||
" param = mock();",
|
||||
" return param;",
|
||||
" }",
|
||||
"",
|
||||
" String redundantAssignmentToLocalVariable() {",
|
||||
" String variable = null;",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" variable = toString();",
|
||||
" return variable;",
|
||||
" }",
|
||||
"",
|
||||
" String unusedAssignmentToLocalVariable(String param) {",
|
||||
" String variable = null;",
|
||||
" variable = toString();",
|
||||
" return param;",
|
||||
" }",
|
||||
"",
|
||||
" String redundantVariableDeclaration() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String variable = toString();",
|
||||
" return variable;",
|
||||
" }",
|
||||
"",
|
||||
" String redundantSpyVariableDeclaration() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String variable = spy();",
|
||||
" return variable;",
|
||||
" }",
|
||||
"",
|
||||
" Object redundantSpyWithExplicitTypeVariableDeclaration() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String variable = spy(String.class);",
|
||||
" return variable;",
|
||||
" }",
|
||||
"",
|
||||
" Object salientSpyTypeVariableDeclaration() {",
|
||||
" String variable = spy(\"name\");",
|
||||
" return variable;",
|
||||
" }",
|
||||
"",
|
||||
" String unusedVariableDeclaration(String param) {",
|
||||
" String variable = toString();",
|
||||
" return param;",
|
||||
" }",
|
||||
"",
|
||||
" String assignmentToAnnotatedVariable() {",
|
||||
" @SuppressWarnings(\"HereBeDragons\")",
|
||||
" String variable = toString();",
|
||||
" return variable;",
|
||||
" }",
|
||||
"",
|
||||
" String complexReturnStatement() {",
|
||||
" String variable = toString();",
|
||||
" return variable + toString();",
|
||||
" }",
|
||||
"",
|
||||
" String assignmentInsideIfClause() {",
|
||||
" String variable = null;",
|
||||
" if (true) {",
|
||||
" variable = toString();",
|
||||
" }",
|
||||
" return variable;",
|
||||
" }",
|
||||
"",
|
||||
" String redundantAssignmentInsideElseClause() {",
|
||||
" String variable = toString();",
|
||||
" if (true) {",
|
||||
" return variable;",
|
||||
" } else {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" variable = \"foo\";",
|
||||
" return variable;",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" Supplier<String> redundantAssignmentInsideLambda() {",
|
||||
" return () -> {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String variable = toString();",
|
||||
" return variable;",
|
||||
" };",
|
||||
" }",
|
||||
"",
|
||||
" String redundantAssignmentInsideTryBlock(AutoCloseable closeable) throws Exception {",
|
||||
" try (closeable) {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String variable = toString();",
|
||||
" return variable;",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" String redundantAssignmentsInsideTryAndFinallyBlocks() {",
|
||||
" String variable = toString();",
|
||||
" try {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" variable = \"foo\";",
|
||||
" return variable;",
|
||||
" } finally {",
|
||||
" String variable2 = toString();",
|
||||
" if (true) {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String variable3 = toString();",
|
||||
" return variable3;",
|
||||
" }",
|
||||
" return variable2;",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" String assignmentUsedInsideFinallyBlock() {",
|
||||
" String variable = toString();",
|
||||
" try {",
|
||||
" variable = \"foo\";",
|
||||
" return variable;",
|
||||
" } finally {",
|
||||
" String variable2 = toString();",
|
||||
" return variable + variable2;",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" String redundantAssignmentToVariableUsedInsideUnexecutedFinallyBlock(AutoCloseable closeable)",
|
||||
" throws Exception {",
|
||||
" String variable = toString();",
|
||||
" try (closeable) {",
|
||||
" if (true) {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" variable = \"foo\";",
|
||||
" return variable;",
|
||||
" }",
|
||||
" }",
|
||||
" try {",
|
||||
" } finally {",
|
||||
" return variable;",
|
||||
" }",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class A {
|
||||
private String field;
|
||||
|
||||
void emptyMethod() {}
|
||||
|
||||
void voidMethod() {
|
||||
toString();
|
||||
return;
|
||||
}
|
||||
|
||||
String directReturnOfParam(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
String assignmentToField() {
|
||||
field = toString();
|
||||
return field;
|
||||
}
|
||||
|
||||
Object redundantAssignmentToParam(String param) {
|
||||
// BUG: Diagnostic contains:
|
||||
param = toString();
|
||||
return param;
|
||||
}
|
||||
|
||||
String redundantMockAssignmentToParam(String param) {
|
||||
// BUG: Diagnostic contains:
|
||||
param = mock();
|
||||
return param;
|
||||
}
|
||||
|
||||
Object redundantMockWithExplicitTypeAssignmentToParam(String param) {
|
||||
// BUG: Diagnostic contains:
|
||||
param = mock(String.class);
|
||||
return param;
|
||||
}
|
||||
|
||||
Object salientMockAssignmentToParam(String param) {
|
||||
param = mock();
|
||||
return param;
|
||||
}
|
||||
|
||||
String redundantAssignmentToLocalVariable() {
|
||||
String variable = null;
|
||||
// BUG: Diagnostic contains:
|
||||
variable = toString();
|
||||
return variable;
|
||||
}
|
||||
|
||||
String unusedAssignmentToLocalVariable(String param) {
|
||||
String variable = null;
|
||||
variable = toString();
|
||||
return param;
|
||||
}
|
||||
|
||||
String redundantVariableDeclaration() {
|
||||
// BUG: Diagnostic contains:
|
||||
String variable = toString();
|
||||
return variable;
|
||||
}
|
||||
|
||||
String redundantSpyVariableDeclaration() {
|
||||
// BUG: Diagnostic contains:
|
||||
String variable = spy();
|
||||
return variable;
|
||||
}
|
||||
|
||||
Object redundantSpyWithExplicitTypeVariableDeclaration() {
|
||||
// BUG: Diagnostic contains:
|
||||
String variable = spy(String.class);
|
||||
return variable;
|
||||
}
|
||||
|
||||
Object salientSpyTypeVariableDeclaration() {
|
||||
String variable = spy("name");
|
||||
return variable;
|
||||
}
|
||||
|
||||
String unusedVariableDeclaration(String param) {
|
||||
String variable = toString();
|
||||
return param;
|
||||
}
|
||||
|
||||
String assignmentToAnnotatedVariable() {
|
||||
@SuppressWarnings("HereBeDragons")
|
||||
String variable = toString();
|
||||
return variable;
|
||||
}
|
||||
|
||||
String complexReturnStatement() {
|
||||
String variable = toString();
|
||||
return variable + toString();
|
||||
}
|
||||
|
||||
String assignmentInsideIfClause() {
|
||||
String variable = null;
|
||||
if (true) {
|
||||
variable = toString();
|
||||
}
|
||||
return variable;
|
||||
}
|
||||
|
||||
String redundantAssignmentInsideElseClause() {
|
||||
String variable = toString();
|
||||
if (true) {
|
||||
return variable;
|
||||
} else {
|
||||
// BUG: Diagnostic contains:
|
||||
variable = "foo";
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
|
||||
Supplier<String> redundantAssignmentInsideLambda() {
|
||||
return () -> {
|
||||
// BUG: Diagnostic contains:
|
||||
String variable = toString();
|
||||
return variable;
|
||||
};
|
||||
}
|
||||
|
||||
String redundantAssignmentInsideTryBlock(AutoCloseable closeable) throws Exception {
|
||||
try (closeable) {
|
||||
// BUG: Diagnostic contains:
|
||||
String variable = toString();
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
|
||||
String redundantAssignmentsInsideTryAndFinallyBlocks() {
|
||||
String variable = toString();
|
||||
try {
|
||||
// BUG: Diagnostic contains:
|
||||
variable = "foo";
|
||||
return variable;
|
||||
} finally {
|
||||
String variable2 = toString();
|
||||
if (true) {
|
||||
// BUG: Diagnostic contains:
|
||||
String variable3 = toString();
|
||||
return variable3;
|
||||
}
|
||||
return variable2;
|
||||
}
|
||||
}
|
||||
|
||||
String assignmentUsedInsideFinallyBlock() {
|
||||
String variable = toString();
|
||||
try {
|
||||
variable = "foo";
|
||||
return variable;
|
||||
} finally {
|
||||
String variable2 = toString();
|
||||
return variable + variable2;
|
||||
}
|
||||
}
|
||||
|
||||
String redundantAssignmentToVariableUsedInsideUnexecutedFinallyBlock(AutoCloseable closeable)
|
||||
throws Exception {
|
||||
String variable = toString();
|
||||
try (closeable) {
|
||||
if (true) {
|
||||
// BUG: Diagnostic contains:
|
||||
variable = "foo";
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
try {
|
||||
} finally {
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -197,30 +199,34 @@ final class DirectReturnTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(DirectReturn.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" String m1() {",
|
||||
" String variable = null;",
|
||||
" variable = toString();",
|
||||
" return variable;",
|
||||
" }",
|
||||
"",
|
||||
" String m2() {",
|
||||
" String variable = toString();",
|
||||
" return variable;",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
class A {
|
||||
String m1() {
|
||||
String variable = null;
|
||||
variable = toString();
|
||||
return variable;
|
||||
}
|
||||
|
||||
String m2() {
|
||||
String variable = toString();
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" String m1() {",
|
||||
" String variable = null;",
|
||||
" return toString();",
|
||||
" }",
|
||||
"",
|
||||
" String m2() {",
|
||||
" return toString();",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
class A {
|
||||
String m1() {
|
||||
String variable = null;
|
||||
return toString();
|
||||
}
|
||||
|
||||
String m2() {
|
||||
return toString();
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,54 +11,58 @@ final class EmptyMethodTest {
|
||||
CompilationTestHelper.newInstance(EmptyMethod.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" Object m1() {",
|
||||
" return null;",
|
||||
" }",
|
||||
"",
|
||||
" void m2() {",
|
||||
" System.out.println(42);",
|
||||
" }",
|
||||
"",
|
||||
" void m3() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" static void m4() {}",
|
||||
"",
|
||||
" interface F {",
|
||||
" void fun();",
|
||||
" }",
|
||||
"",
|
||||
" final class MyTestClass {",
|
||||
" void helperMethod() {}",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
class A {
|
||||
Object m1() {
|
||||
return null;
|
||||
}
|
||||
|
||||
void m2() {
|
||||
System.out.println(42);
|
||||
}
|
||||
|
||||
void m3() {}
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
static void m4() {}
|
||||
|
||||
interface F {
|
||||
void fun();
|
||||
}
|
||||
|
||||
final class MyTestClass {
|
||||
void helperMethod() {}
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addSourceLines(
|
||||
"B.java",
|
||||
"import org.aspectj.lang.annotation.Pointcut;",
|
||||
"",
|
||||
"final class B implements A.F {",
|
||||
" @Override",
|
||||
" public void fun() {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" void m3() {}",
|
||||
"",
|
||||
" /** Javadoc. */",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" void m4() {}",
|
||||
"",
|
||||
" void m5() {",
|
||||
" // Single-line comment.",
|
||||
" }",
|
||||
"",
|
||||
" void m6() {",
|
||||
" /* Multi-line comment. */",
|
||||
" }",
|
||||
"",
|
||||
" @Pointcut",
|
||||
" void m7() {}",
|
||||
"}")
|
||||
"""
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
|
||||
final class B implements A.F {
|
||||
@Override
|
||||
public void fun() {}
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
void m3() {}
|
||||
|
||||
/** Javadoc. */
|
||||
// BUG: Diagnostic contains:
|
||||
void m4() {}
|
||||
|
||||
void m5() {
|
||||
// Single-line comment.
|
||||
}
|
||||
|
||||
void m6() {
|
||||
/* Multi-line comment. */
|
||||
}
|
||||
|
||||
@Pointcut
|
||||
void m7() {}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -67,22 +71,26 @@ final class EmptyMethodTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(EmptyMethod.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"final class A {",
|
||||
" void instanceMethod() {}",
|
||||
"",
|
||||
" static void staticMethod() {}",
|
||||
"",
|
||||
" static void staticMethodWithComment() {",
|
||||
" /* Foo. */",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
final class A {
|
||||
void instanceMethod() {}
|
||||
|
||||
static void staticMethod() {}
|
||||
|
||||
static void staticMethodWithComment() {
|
||||
/* Foo. */
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"final class A {",
|
||||
" static void staticMethodWithComment() {",
|
||||
" /* Foo. */",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
final class A {
|
||||
static void staticMethodWithComment() {
|
||||
/* Foo. */
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,62 +19,64 @@ final class EmptyMonoZipTest {
|
||||
"Invoking `Mono#zipWith` on `Mono#empty()` or a `Mono<Void>` is a no-op"))
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static reactor.core.publisher.Mono.zip;",
|
||||
"",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Flux.just(1).zip(Mono.empty(), Flux.just(2));",
|
||||
"",
|
||||
" Mono<Void> voidMono = Mono.empty();",
|
||||
" Mono<Integer> integerMono = Mono.empty();",
|
||||
"",
|
||||
" zip(Mono.just(1), Mono.just(2));",
|
||||
" Mono.zip(Mono.just(1), Mono.just(2));",
|
||||
" Mono.zip(Mono.just(1), Mono.just(2), Mono.just(3));",
|
||||
" Mono.zip(integerMono, integerMono);",
|
||||
"",
|
||||
" // BUG: Diagnostic matches: ARGUMENT",
|
||||
" zip(Mono.empty(), Mono.empty());",
|
||||
" // BUG: Diagnostic matches: ARGUMENT",
|
||||
" Mono.zip(Mono.empty(), Mono.empty());",
|
||||
" // BUG: Diagnostic matches: ARGUMENT",
|
||||
" Mono.zip(voidMono, Mono.just(1));",
|
||||
" // BUG: Diagnostic matches: ARGUMENT",
|
||||
" Mono.zip(voidMono, voidMono);",
|
||||
" // BUG: Diagnostic matches: ARGUMENT",
|
||||
" Mono.zip(Mono.just(1).then(), Mono.just(2));",
|
||||
" // BUG: Diagnostic matches: ARGUMENT",
|
||||
" Mono.zip(Mono.just(1), Mono.just(2), voidMono);",
|
||||
"",
|
||||
" Mono.just(1).zipWith(Mono.just(2));",
|
||||
" Mono.just(1).zipWith(integerMono);",
|
||||
" Mono.just(1).zipWith(integerMono, (a, b) -> a + b);",
|
||||
"",
|
||||
" // BUG: Diagnostic matches: ARGUMENT",
|
||||
" Mono.just(1).zipWith(Mono.empty());",
|
||||
" // BUG: Diagnostic matches: ARGUMENT",
|
||||
" Mono.just(1).zipWith(voidMono);",
|
||||
" // BUG: Diagnostic matches: RECEIVER",
|
||||
" Mono.empty().zipWith(Mono.just(1));",
|
||||
" // BUG: Diagnostic matches: RECEIVER",
|
||||
" voidMono.zipWith(Mono.just(1));",
|
||||
" }",
|
||||
"",
|
||||
" abstract class MyMono extends Mono<Object> {",
|
||||
" void m() {",
|
||||
" zip(Mono.just(1), Mono.just(2));",
|
||||
" // BUG: Diagnostic matches: ARGUMENT",
|
||||
" zip(Mono.empty(), Mono.empty());",
|
||||
"",
|
||||
" zipWith(Mono.just(1));",
|
||||
" // BUG: Diagnostic matches: ARGUMENT",
|
||||
" zipWith(Mono.empty());",
|
||||
" }",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static reactor.core.publisher.Mono.zip;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Flux.just(1).zip(Mono.empty(), Flux.just(2));
|
||||
|
||||
Mono<Void> voidMono = Mono.empty();
|
||||
Mono<Integer> integerMono = Mono.empty();
|
||||
|
||||
zip(Mono.just(1), Mono.just(2));
|
||||
Mono.zip(Mono.just(1), Mono.just(2));
|
||||
Mono.zip(Mono.just(1), Mono.just(2), Mono.just(3));
|
||||
Mono.zip(integerMono, integerMono);
|
||||
|
||||
// BUG: Diagnostic matches: ARGUMENT
|
||||
zip(Mono.empty(), Mono.empty());
|
||||
// BUG: Diagnostic matches: ARGUMENT
|
||||
Mono.zip(Mono.empty(), Mono.empty());
|
||||
// BUG: Diagnostic matches: ARGUMENT
|
||||
Mono.zip(voidMono, Mono.just(1));
|
||||
// BUG: Diagnostic matches: ARGUMENT
|
||||
Mono.zip(voidMono, voidMono);
|
||||
// BUG: Diagnostic matches: ARGUMENT
|
||||
Mono.zip(Mono.just(1).then(), Mono.just(2));
|
||||
// BUG: Diagnostic matches: ARGUMENT
|
||||
Mono.zip(Mono.just(1), Mono.just(2), voidMono);
|
||||
|
||||
Mono.just(1).zipWith(Mono.just(2));
|
||||
Mono.just(1).zipWith(integerMono);
|
||||
Mono.just(1).zipWith(integerMono, (a, b) -> a + b);
|
||||
|
||||
// BUG: Diagnostic matches: ARGUMENT
|
||||
Mono.just(1).zipWith(Mono.empty());
|
||||
// BUG: Diagnostic matches: ARGUMENT
|
||||
Mono.just(1).zipWith(voidMono);
|
||||
// BUG: Diagnostic matches: RECEIVER
|
||||
Mono.empty().zipWith(Mono.just(1));
|
||||
// BUG: Diagnostic matches: RECEIVER
|
||||
voidMono.zipWith(Mono.just(1));
|
||||
}
|
||||
|
||||
abstract class MyMono extends Mono<Object> {
|
||||
void m() {
|
||||
zip(Mono.just(1), Mono.just(2));
|
||||
// BUG: Diagnostic matches: ARGUMENT
|
||||
zip(Mono.empty(), Mono.empty());
|
||||
|
||||
zipWith(Mono.just(1));
|
||||
// BUG: Diagnostic matches: ARGUMENT
|
||||
zipWith(Mono.empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class ExplicitArgumentEnumerationTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(ExplicitArgumentEnumeration.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"""
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import org.jooq.impl.DSL;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
class A {
|
||||
// BUG: Diagnostic contains:
|
||||
private final int value = unaryMethod(ImmutableList.of(1, 2));
|
||||
|
||||
void m() {
|
||||
ImmutableList<String> list = ImmutableList.of();
|
||||
assertThat(ImmutableList.of()).containsAnyElementsOf(list);
|
||||
|
||||
ImmutableList.<ImmutableList<String>>builder().add(ImmutableList.of());
|
||||
|
||||
DSL.row(ImmutableList.of(1, 2));
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
unaryMethod(ImmutableList.of(1, 2));
|
||||
unaryMethodWithLessVisibleOverload(ImmutableList.of(1, 2));
|
||||
binaryMethod(ImmutableList.of(1, 2), 3);
|
||||
|
||||
ImmutableList.builder()
|
||||
// BUG: Diagnostic contains:
|
||||
.addAll(ImmutableList.of())
|
||||
// BUG: Diagnostic contains:
|
||||
.addAll(ImmutableList.copyOf(new String[0]))
|
||||
.addAll(ImmutableList.copyOf(ImmutableList.of()))
|
||||
.build();
|
||||
|
||||
assertThat(ImmutableList.of(1))
|
||||
// BUG: Diagnostic contains:
|
||||
.containsAnyElementsOf(ImmutableList.of(1))
|
||||
// BUG: Diagnostic contains:
|
||||
.isSubsetOf(ImmutableList.of(1));
|
||||
|
||||
Flux.just(1, 2)
|
||||
.as(StepVerifier::create)
|
||||
// BUG: Diagnostic contains:
|
||||
.expectNextSequence(ImmutableList.of(1, 2))
|
||||
.verifyComplete();
|
||||
|
||||
CompilationTestHelper.newInstance(BugChecker.class, getClass())
|
||||
// BUG: Diagnostic contains:
|
||||
.setArgs(ImmutableList.of("foo"))
|
||||
.withClasspath();
|
||||
}
|
||||
|
||||
private int unaryMethod(ImmutableList<Integer> args) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int unaryMethod(Integer... args) {
|
||||
return unaryMethod(ImmutableList.copyOf(args));
|
||||
}
|
||||
|
||||
void unaryMethodWithLessVisibleOverload(ImmutableList<Integer> args) {}
|
||||
|
||||
private void unaryMethodWithLessVisibleOverload(Integer... args) {
|
||||
unaryMethodWithLessVisibleOverload(ImmutableList.copyOf(args));
|
||||
}
|
||||
|
||||
private void binaryMethod(ImmutableList<Integer> args, int extraArg) {}
|
||||
|
||||
private void binaryMethod(Integer... args) {
|
||||
binaryMethod(ImmutableList.copyOf(args), 0);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(ExplicitArgumentEnumeration.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"""
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultiset;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
ImmutableList.builder().addAll(ImmutableList.of()).build();
|
||||
|
||||
assertThat(ImmutableList.of()).containsAnyElementsOf(ImmutableMultiset.of());
|
||||
assertThat(ImmutableList.of()).containsAll(ImmutableSet.of());
|
||||
assertThat(ImmutableList.of()).containsExactlyElementsOf(List.of());
|
||||
assertThat(ImmutableList.of()).containsExactlyInAnyOrderElementsOf(Set.of());
|
||||
assertThat(ImmutableList.of()).containsSequence(Arrays.asList());
|
||||
assertThat(ImmutableList.of()).containsSubsequence(ImmutableList.of(1));
|
||||
assertThat(ImmutableList.of()).doesNotContainAnyElementsOf(ImmutableMultiset.of(2));
|
||||
assertThat(ImmutableList.of()).doesNotContainSequence(ImmutableSet.of(3));
|
||||
assertThat(ImmutableList.of()).doesNotContainSubsequence(List.of(4));
|
||||
assertThat(ImmutableList.of()).hasSameElementsAs(Set.of(5));
|
||||
assertThat(ImmutableList.of()).isSubsetOf(Arrays.asList(6));
|
||||
|
||||
Flux.empty()
|
||||
.as(StepVerifier::create)
|
||||
.expectNextSequence(ImmutableList.of(1, 2))
|
||||
.verifyComplete();
|
||||
|
||||
BugCheckerRefactoringTestHelper.newInstance(BugChecker.class, getClass())
|
||||
.setArgs(ImmutableList.of("foo", "bar"));
|
||||
CompilationTestHelper.newInstance(BugChecker.class, getClass())
|
||||
.setArgs(ImmutableList.of("foo", "bar"));
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"""
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultiset;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
ImmutableList.builder().add().build();
|
||||
|
||||
assertThat(ImmutableList.of()).containsAnyOf();
|
||||
assertThat(ImmutableList.of()).contains();
|
||||
assertThat(ImmutableList.of()).containsExactly();
|
||||
assertThat(ImmutableList.of()).containsExactlyInAnyOrder();
|
||||
assertThat(ImmutableList.of()).containsSequence();
|
||||
assertThat(ImmutableList.of()).containsSubsequence(1);
|
||||
assertThat(ImmutableList.of()).doesNotContain(2);
|
||||
assertThat(ImmutableList.of()).doesNotContainSequence(3);
|
||||
assertThat(ImmutableList.of()).doesNotContainSubsequence(4);
|
||||
assertThat(ImmutableList.of()).containsOnly(5);
|
||||
assertThat(ImmutableList.of()).isSubsetOf(6);
|
||||
|
||||
Flux.empty().as(StepVerifier::create).expectNext(1, 2).verifyComplete();
|
||||
|
||||
BugCheckerRefactoringTestHelper.newInstance(BugChecker.class, getClass()).setArgs("foo", "bar");
|
||||
CompilationTestHelper.newInstance(BugChecker.class, getClass()).setArgs("foo", "bar");
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -9,76 +9,78 @@ final class ExplicitEnumOrderingTest {
|
||||
CompilationTestHelper.newInstance(ExplicitEnumOrdering.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static java.lang.annotation.RetentionPolicy.CLASS;",
|
||||
"import static java.lang.annotation.RetentionPolicy.RUNTIME;",
|
||||
"import static java.lang.annotation.RetentionPolicy.SOURCE;",
|
||||
"import static java.time.chrono.IsoEra.BCE;",
|
||||
"import static java.time.chrono.IsoEra.CE;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.Ordering;",
|
||||
"import java.lang.annotation.RetentionPolicy;",
|
||||
"import java.time.chrono.IsoEra;",
|
||||
"",
|
||||
"class A {",
|
||||
" {",
|
||||
" // The `List`-accepting overload is currently ignored.",
|
||||
" Ordering.explicit(ImmutableList.of(RetentionPolicy.SOURCE, RetentionPolicy.CLASS));",
|
||||
"",
|
||||
" Ordering.explicit(IsoEra.BCE, IsoEra.CE);",
|
||||
" // BUG: Diagnostic contains: IsoEra.CE",
|
||||
" Ordering.explicit(IsoEra.BCE);",
|
||||
" // BUG: Diagnostic contains: IsoEra.BCE",
|
||||
" Ordering.explicit(IsoEra.CE);",
|
||||
"",
|
||||
" Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.CLASS, RetentionPolicy.RUNTIME);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.CLASS, RetentionPolicy.RUNTIME",
|
||||
" Ordering.explicit(RetentionPolicy.SOURCE);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME",
|
||||
" Ordering.explicit(RetentionPolicy.CLASS);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.CLASS",
|
||||
" Ordering.explicit(RetentionPolicy.RUNTIME);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.RUNTIME",
|
||||
" Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.CLASS);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.CLASS",
|
||||
" Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE",
|
||||
" Ordering.explicit(RetentionPolicy.CLASS, RetentionPolicy.RUNTIME);",
|
||||
"",
|
||||
" Ordering.explicit(BCE, CE);",
|
||||
" // BUG: Diagnostic contains: IsoEra.CE",
|
||||
" Ordering.explicit(BCE);",
|
||||
" // BUG: Diagnostic contains: IsoEra.BCE",
|
||||
" Ordering.explicit(CE);",
|
||||
"",
|
||||
" Ordering.explicit(SOURCE, CLASS, RUNTIME);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.CLASS, RetentionPolicy.RUNTIME",
|
||||
" Ordering.explicit(SOURCE);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME",
|
||||
" Ordering.explicit(CLASS);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.CLASS",
|
||||
" Ordering.explicit(RUNTIME);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.RUNTIME",
|
||||
" Ordering.explicit(SOURCE, CLASS);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.CLASS",
|
||||
" Ordering.explicit(SOURCE, RUNTIME);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE",
|
||||
" Ordering.explicit(CLASS, RUNTIME);",
|
||||
"",
|
||||
" Ordering.explicit(RetentionPolicy.SOURCE, BCE, RetentionPolicy.CLASS, CE, RUNTIME);",
|
||||
" Ordering.explicit(SOURCE, IsoEra.BCE, CLASS, IsoEra.CE, RetentionPolicy.RUNTIME);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.CLASS",
|
||||
" Ordering.explicit(RetentionPolicy.SOURCE, BCE, CE, RUNTIME);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.CLASS",
|
||||
" Ordering.explicit(IsoEra.BCE, SOURCE, IsoEra.CE, RetentionPolicy.RUNTIME);",
|
||||
" // BUG: Diagnostic contains: IsoEra.CE, RetentionPolicy.RUNTIME",
|
||||
" Ordering.explicit(IsoEra.BCE, SOURCE, RetentionPolicy.CLASS);",
|
||||
" // BUG: Diagnostic contains: RetentionPolicy.SOURCE, IsoEra.BCE",
|
||||
" Ordering.explicit(CLASS, RUNTIME, CE);",
|
||||
"",
|
||||
" Ordering.explicit(BCE, null, CE);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static java.lang.annotation.RetentionPolicy.CLASS;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
import static java.time.chrono.IsoEra.BCE;
|
||||
import static java.time.chrono.IsoEra.CE;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Ordering;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.time.chrono.IsoEra;
|
||||
|
||||
class A {
|
||||
{
|
||||
// The `List`-accepting overload is currently ignored.
|
||||
Ordering.explicit(ImmutableList.of(RetentionPolicy.SOURCE, RetentionPolicy.CLASS));
|
||||
|
||||
Ordering.explicit(IsoEra.BCE, IsoEra.CE);
|
||||
// BUG: Diagnostic contains: IsoEra.CE
|
||||
Ordering.explicit(IsoEra.BCE);
|
||||
// BUG: Diagnostic contains: IsoEra.BCE
|
||||
Ordering.explicit(IsoEra.CE);
|
||||
|
||||
Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.CLASS, RetentionPolicy.RUNTIME);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.CLASS, RetentionPolicy.RUNTIME
|
||||
Ordering.explicit(RetentionPolicy.SOURCE);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME
|
||||
Ordering.explicit(RetentionPolicy.CLASS);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.CLASS
|
||||
Ordering.explicit(RetentionPolicy.RUNTIME);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.RUNTIME
|
||||
Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.CLASS);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.CLASS
|
||||
Ordering.explicit(RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.SOURCE
|
||||
Ordering.explicit(RetentionPolicy.CLASS, RetentionPolicy.RUNTIME);
|
||||
|
||||
Ordering.explicit(BCE, CE);
|
||||
// BUG: Diagnostic contains: IsoEra.CE
|
||||
Ordering.explicit(BCE);
|
||||
// BUG: Diagnostic contains: IsoEra.BCE
|
||||
Ordering.explicit(CE);
|
||||
|
||||
Ordering.explicit(SOURCE, CLASS, RUNTIME);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.CLASS, RetentionPolicy.RUNTIME
|
||||
Ordering.explicit(SOURCE);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.RUNTIME
|
||||
Ordering.explicit(CLASS);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.SOURCE, RetentionPolicy.CLASS
|
||||
Ordering.explicit(RUNTIME);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.RUNTIME
|
||||
Ordering.explicit(SOURCE, CLASS);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.CLASS
|
||||
Ordering.explicit(SOURCE, RUNTIME);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.SOURCE
|
||||
Ordering.explicit(CLASS, RUNTIME);
|
||||
|
||||
Ordering.explicit(RetentionPolicy.SOURCE, BCE, RetentionPolicy.CLASS, CE, RUNTIME);
|
||||
Ordering.explicit(SOURCE, IsoEra.BCE, CLASS, IsoEra.CE, RetentionPolicy.RUNTIME);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.CLASS
|
||||
Ordering.explicit(RetentionPolicy.SOURCE, BCE, CE, RUNTIME);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.CLASS
|
||||
Ordering.explicit(IsoEra.BCE, SOURCE, IsoEra.CE, RetentionPolicy.RUNTIME);
|
||||
// BUG: Diagnostic contains: IsoEra.CE, RetentionPolicy.RUNTIME
|
||||
Ordering.explicit(IsoEra.BCE, SOURCE, RetentionPolicy.CLASS);
|
||||
// BUG: Diagnostic contains: RetentionPolicy.SOURCE, IsoEra.BCE
|
||||
Ordering.explicit(CLASS, RUNTIME, CE);
|
||||
|
||||
Ordering.explicit(BCE, null, CE);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,55 +12,57 @@ final class FluxFlatMapUsageTest {
|
||||
CompilationTestHelper.newInstance(FluxFlatMapUsage.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.function.BiFunction;",
|
||||
"import java.util.function.Function;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).flatMap(Flux::just);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).<String>flatMap(i -> Flux.just(String.valueOf(i)));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).flatMapSequential(Flux::just);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).<String>flatMapSequential(i -> Flux.just(String.valueOf(i)));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1, 2).groupBy(i -> i).<String>flatMap(i -> Flux.just(String.valueOf(i)));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1, 2).groupBy(i -> i).<String>flatMapSequential(i -> Flux.just(String.valueOf(i)));",
|
||||
"",
|
||||
" Mono.just(1).flatMap(Mono::just);",
|
||||
" Flux.just(1).concatMap(Flux::just);",
|
||||
"",
|
||||
" Flux.just(1).flatMap(Flux::just, 1);",
|
||||
" Flux.just(1).flatMap(Flux::just, 1, 1);",
|
||||
" Flux.just(1).flatMap(Flux::just, throwable -> Flux.empty(), Flux::empty);",
|
||||
"",
|
||||
" Flux.just(1).flatMapSequential(Flux::just, 1);",
|
||||
" Flux.just(1).flatMapSequential(Flux::just, 1, 1);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" this.<String, Flux<String>>sink(Flux::flatMap);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" this.<Integer, Flux<Integer>>sink(Flux::<Integer>flatMap);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" this.<String, Flux<String>>sink(Flux::flatMapSequential);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" this.<Integer, Flux<Integer>>sink(Flux::<Integer>flatMapSequential);",
|
||||
"",
|
||||
" this.<String, Mono<String>>sink(Mono::flatMap);",
|
||||
" }",
|
||||
"",
|
||||
" private <T, P> void sink(BiFunction<P, Function<T, P>, P> fun) {}",
|
||||
"}")
|
||||
"""
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).flatMap(Flux::just);
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).<String>flatMap(i -> Flux.just(String.valueOf(i)));
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).flatMapSequential(Flux::just);
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).<String>flatMapSequential(i -> Flux.just(String.valueOf(i)));
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just);
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1, 2).groupBy(i -> i).<String>flatMap(i -> Flux.just(String.valueOf(i)));
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just);
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1, 2).groupBy(i -> i).<String>flatMapSequential(i -> Flux.just(String.valueOf(i)));
|
||||
|
||||
Mono.just(1).flatMap(Mono::just);
|
||||
Flux.just(1).concatMap(Flux::just);
|
||||
|
||||
Flux.just(1).flatMap(Flux::just, 1);
|
||||
Flux.just(1).flatMap(Flux::just, 1, 1);
|
||||
Flux.just(1).flatMap(Flux::just, throwable -> Flux.empty(), Flux::empty);
|
||||
|
||||
Flux.just(1).flatMapSequential(Flux::just, 1);
|
||||
Flux.just(1).flatMapSequential(Flux::just, 1, 1);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
this.<String, Flux<String>>sink(Flux::flatMap);
|
||||
// BUG: Diagnostic contains:
|
||||
this.<Integer, Flux<Integer>>sink(Flux::<Integer>flatMap);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
this.<String, Flux<String>>sink(Flux::flatMapSequential);
|
||||
// BUG: Diagnostic contains:
|
||||
this.<Integer, Flux<Integer>>sink(Flux::<Integer>flatMapSequential);
|
||||
|
||||
this.<String, Mono<String>>sink(Mono::flatMap);
|
||||
}
|
||||
|
||||
private <T, P> void sink(BiFunction<P, Function<T, P>, P> fun) {}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -69,32 +71,36 @@ final class FluxFlatMapUsageTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(FluxFlatMapUsage.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final int MAX_CONCURRENCY = 8;",
|
||||
"",
|
||||
" void m() {",
|
||||
" Flux.just(1).flatMap(Flux::just);",
|
||||
" Flux.just(1).flatMapSequential(Flux::just);",
|
||||
" Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just);",
|
||||
" Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
private static final int MAX_CONCURRENCY = 8;
|
||||
|
||||
void m() {
|
||||
Flux.just(1).flatMap(Flux::just);
|
||||
Flux.just(1).flatMapSequential(Flux::just);
|
||||
Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just);
|
||||
Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final int MAX_CONCURRENCY = 8;",
|
||||
"",
|
||||
" void m() {",
|
||||
" Flux.just(1).concatMap(Flux::just);",
|
||||
" Flux.just(1).concatMap(Flux::just);",
|
||||
" Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just, MAX_CONCURRENCY);",
|
||||
" Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just, MAX_CONCURRENCY);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
private static final int MAX_CONCURRENCY = 8;
|
||||
|
||||
void m() {
|
||||
Flux.just(1).concatMap(Flux::just);
|
||||
Flux.just(1).concatMap(Flux::just);
|
||||
Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just, MAX_CONCURRENCY);
|
||||
Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just, MAX_CONCURRENCY);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@@ -104,32 +110,36 @@ final class FluxFlatMapUsageTest {
|
||||
.setFixChooser(FixChoosers.SECOND)
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final int MAX_CONCURRENCY = 8;",
|
||||
"",
|
||||
" void m() {",
|
||||
" Flux.just(1).flatMap(Flux::just);",
|
||||
" Flux.just(1).flatMapSequential(Flux::just);",
|
||||
" Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just);",
|
||||
" Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
private static final int MAX_CONCURRENCY = 8;
|
||||
|
||||
void m() {
|
||||
Flux.just(1).flatMap(Flux::just);
|
||||
Flux.just(1).flatMapSequential(Flux::just);
|
||||
Flux.just(1, 2).groupBy(i -> i).flatMap(Flux::just);
|
||||
Flux.just(1, 2).groupBy(i -> i).flatMapSequential(Flux::just);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final int MAX_CONCURRENCY = 8;",
|
||||
"",
|
||||
" void m() {",
|
||||
" Flux.just(1).flatMap(Flux::just, MAX_CONCURRENCY);",
|
||||
" Flux.just(1).flatMapSequential(Flux::just, MAX_CONCURRENCY);",
|
||||
" Flux.just(1, 2).groupBy(i -> i).concatMap(Flux::just);",
|
||||
" Flux.just(1, 2).groupBy(i -> i).concatMap(Flux::just);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
private static final int MAX_CONCURRENCY = 8;
|
||||
|
||||
void m() {
|
||||
Flux.just(1).flatMap(Flux::just, MAX_CONCURRENCY);
|
||||
Flux.just(1).flatMapSequential(Flux::just, MAX_CONCURRENCY);
|
||||
Flux.just(1, 2).groupBy(i -> i).concatMap(Flux::just);
|
||||
Flux.just(1, 2).groupBy(i -> i).concatMap(Flux::just);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,36 +21,38 @@ final class FluxImplicitBlockTest {
|
||||
m -> Stream.of("SuppressWarnings", "toImmutableList", "toList").allMatch(m::contains))
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import java.util.stream.Stream;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" Flux.just(1).toIterable();",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" Flux.just(2).toStream();",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" long count = Flux.just(3).toStream().count();",
|
||||
"",
|
||||
" Flux.just(4).toIterable(1);",
|
||||
" Flux.just(5).toIterable(2, null);",
|
||||
" Flux.just(6).toStream(3);",
|
||||
" new Foo().toIterable();",
|
||||
" new Foo().toStream();",
|
||||
" }",
|
||||
"",
|
||||
" class Foo<T> {",
|
||||
" Iterable<T> toIterable() {",
|
||||
" return ImmutableList.of();",
|
||||
" }",
|
||||
"",
|
||||
" Stream<T> toStream() {",
|
||||
" return Stream.empty();",
|
||||
" }",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.stream.Stream;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
// BUG: Diagnostic matches: X
|
||||
Flux.just(1).toIterable();
|
||||
// BUG: Diagnostic matches: X
|
||||
Flux.just(2).toStream();
|
||||
// BUG: Diagnostic matches: X
|
||||
long count = Flux.just(3).toStream().count();
|
||||
|
||||
Flux.just(4).toIterable(1);
|
||||
Flux.just(5).toIterable(2, null);
|
||||
Flux.just(6).toStream(3);
|
||||
new Foo().toIterable();
|
||||
new Foo().toStream();
|
||||
}
|
||||
|
||||
class Foo<T> {
|
||||
Iterable<T> toIterable() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
Stream<T> toStream() {
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -61,16 +63,18 @@ final class FluxImplicitBlockTest {
|
||||
.expectErrorMessage("X", m -> !m.contains("toImmutableList"))
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" Flux.just(1).toIterable();",
|
||||
" // BUG: Diagnostic matches: X",
|
||||
" Flux.just(2).toStream();",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
// BUG: Diagnostic matches: X
|
||||
Flux.just(1).toIterable();
|
||||
// BUG: Diagnostic matches: X
|
||||
Flux.just(2).toStream();
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -79,25 +83,29 @@ final class FluxImplicitBlockTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(FluxImplicitBlock.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Flux.just(1).toIterable();",
|
||||
" Flux.just(2).toStream();",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Flux.just(1).toIterable();
|
||||
Flux.just(2).toStream();
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" @SuppressWarnings(\"FluxImplicitBlock\")",
|
||||
" void m() {",
|
||||
" Flux.just(1).toIterable();",
|
||||
" Flux.just(2).toStream();",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
@SuppressWarnings("FluxImplicitBlock")
|
||||
void m() {
|
||||
Flux.just(1).toIterable();
|
||||
Flux.just(2).toStream();
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@@ -107,34 +115,38 @@ final class FluxImplicitBlockTest {
|
||||
.setFixChooser(SECOND)
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Flux.just(1).toIterable();",
|
||||
" Flux.just(2).toStream();",
|
||||
" Flux.just(3).toIterable().iterator();",
|
||||
" Flux.just(4).toStream().count();",
|
||||
" Flux.just(5) /* a */./* b */ toIterable /* c */(/* d */ ) /* e */;",
|
||||
" Flux.just(6) /* a */./* b */ toStream /* c */(/* d */ ) /* e */;",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Flux.just(1).toIterable();
|
||||
Flux.just(2).toStream();
|
||||
Flux.just(3).toIterable().iterator();
|
||||
Flux.just(4).toStream().count();
|
||||
Flux.just(5) /* a */./* b */ toIterable /* c */(/* d */ ) /* e */;
|
||||
Flux.just(6) /* a */./* b */ toStream /* c */(/* d */ ) /* e */;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static com.google.common.collect.ImmutableList.toImmutableList;",
|
||||
"",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Flux.just(1).collect(toImmutableList()).block();",
|
||||
" Flux.just(2).collect(toImmutableList()).block().stream();",
|
||||
" Flux.just(3).collect(toImmutableList()).block().iterator();",
|
||||
" Flux.just(4).collect(toImmutableList()).block().stream().count();",
|
||||
" Flux.just(5).collect(toImmutableList()).block() /* e */;",
|
||||
" Flux.just(6).collect(toImmutableList()).block().stream() /* e */;",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Flux.just(1).collect(toImmutableList()).block();
|
||||
Flux.just(2).collect(toImmutableList()).block().stream();
|
||||
Flux.just(3).collect(toImmutableList()).block().iterator();
|
||||
Flux.just(4).collect(toImmutableList()).block().stream().count();
|
||||
Flux.just(5).collect(toImmutableList()).block() /* e */;
|
||||
Flux.just(6).collect(toImmutableList()).block().stream() /* e */;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@@ -144,34 +156,38 @@ final class FluxImplicitBlockTest {
|
||||
.setFixChooser(THIRD)
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Flux.just(1).toIterable();",
|
||||
" Flux.just(2).toStream();",
|
||||
" Flux.just(3).toIterable().iterator();",
|
||||
" Flux.just(4).toStream().count();",
|
||||
" Flux.just(5) /* a */./* b */ toIterable /* c */(/* d */ ) /* e */;",
|
||||
" Flux.just(6) /* a */./* b */ toStream /* c */(/* d */ ) /* e */;",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Flux.just(1).toIterable();
|
||||
Flux.just(2).toStream();
|
||||
Flux.just(3).toIterable().iterator();
|
||||
Flux.just(4).toStream().count();
|
||||
Flux.just(5) /* a */./* b */ toIterable /* c */(/* d */ ) /* e */;
|
||||
Flux.just(6) /* a */./* b */ toStream /* c */(/* d */ ) /* e */;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static java.util.stream.Collectors.toList;",
|
||||
"",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Flux.just(1).collect(toList()).block();",
|
||||
" Flux.just(2).collect(toList()).block().stream();",
|
||||
" Flux.just(3).collect(toList()).block().iterator();",
|
||||
" Flux.just(4).collect(toList()).block().stream().count();",
|
||||
" Flux.just(5).collect(toList()).block() /* e */;",
|
||||
" Flux.just(6).collect(toList()).block().stream() /* e */;",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Flux.just(1).collect(toList()).block();
|
||||
Flux.just(2).collect(toList()).block().stream();
|
||||
Flux.just(3).collect(toList()).block().iterator();
|
||||
Flux.just(4).collect(toList()).block().stream().count();
|
||||
Flux.just(5).collect(toList()).block() /* e */;
|
||||
Flux.just(6).collect(toList()).block().stream() /* e */;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,294 +11,296 @@ final class FormatStringConcatenationTest {
|
||||
CompilationTestHelper.newInstance(FormatStringConcatenation.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static com.google.common.base.Preconditions.checkArgument;",
|
||||
"import static com.google.common.base.Preconditions.checkNotNull;",
|
||||
"import static com.google.common.base.Preconditions.checkState;",
|
||||
"import static com.google.common.base.Verify.verify;",
|
||||
"import static org.assertj.core.api.Assertions.assertThat;",
|
||||
"import static org.assertj.core.api.SoftAssertions.assertSoftly;",
|
||||
"",
|
||||
"import java.util.Formatter;",
|
||||
"import java.util.Locale;",
|
||||
"import org.assertj.core.api.Assertions;",
|
||||
"import org.assertj.core.api.BDDAssertions;",
|
||||
"import org.assertj.core.api.Fail;",
|
||||
"import org.assertj.core.api.ThrowableAssertAlternative;",
|
||||
"import org.assertj.core.api.WithAssertions;",
|
||||
"import org.slf4j.Logger;",
|
||||
"import org.slf4j.LoggerFactory;",
|
||||
"import org.slf4j.Marker;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
|
||||
"",
|
||||
" void negative() {",
|
||||
" hashCode();",
|
||||
" equals(new A());",
|
||||
" equals(toString());",
|
||||
" equals(0);",
|
||||
" equals(\"str\");",
|
||||
" equals(\"str\" + 0);",
|
||||
" equals(0 + 0);",
|
||||
" equals(0 - 0);",
|
||||
" equals(\"str \" + toString());",
|
||||
" }",
|
||||
"",
|
||||
" void assertj() {",
|
||||
" assertThat(0).overridingErrorMessage(toString());",
|
||||
" assertThat(0).overridingErrorMessage(\"str\");",
|
||||
" assertThat(0).overridingErrorMessage(\"str \" + 0);",
|
||||
" assertThat(0).overridingErrorMessage(\"str %s\", 2 * 3);",
|
||||
" assertThat(0).overridingErrorMessage(\"str %s\", toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).overridingErrorMessage(\"str \" + hashCode() / 2);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).overridingErrorMessage((\"str \" + toString()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).overridingErrorMessage(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).overridingErrorMessage(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).withFailMessage(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).withFailMessage(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertSoftly(softly -> softly.fail(\"str \" + toString()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertSoftly(softly -> softly.fail(\"%s \" + toString(), \"arg\"));",
|
||||
" assertSoftly(softly -> softly.fail(\"str \" + toString(), new Throwable()));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(\"\").isEqualTo(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(\"\").isEqualTo(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessage(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessage(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessageContaining(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessageContaining(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessageEndingWith(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessageEndingWith(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessageStartingWith(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasMessageStartingWith(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasRootCauseMessage(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasRootCauseMessage(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasStackTraceContaining(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(new Error()).hasStackTraceContaining(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).as(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).as(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).describedAs(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" assertThat(0).describedAs(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessage(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessage(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessageContaining(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessageContaining(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessageEndingWith(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessageEndingWith(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessageStartingWith(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withMessageStartingWith(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withStackTraceContaining(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((ThrowableAssertAlternative) null).withStackTraceContaining(\"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((WithAssertions) null).fail(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ((WithAssertions) null).fail(\"%s \" + toString(), \"arg\");",
|
||||
" ((WithAssertions) null).fail(\"str \" + toString(), new Throwable());",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Assertions.fail(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Assertions.fail(\"%s \" + toString(), \"arg\");",
|
||||
" Assertions.fail(\"str \" + toString(), new Throwable());",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" BDDAssertions.fail(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" BDDAssertions.fail(\"%s \" + toString(), \"arg\");",
|
||||
" BDDAssertions.fail(\"str \" + toString(), new Throwable());",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Fail.fail(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Fail.fail(\"%s \" + toString(), \"arg\");",
|
||||
" Fail.fail(\"str \" + toString(), new Throwable());",
|
||||
" }",
|
||||
"",
|
||||
" void guava() {",
|
||||
" checkArgument(true);",
|
||||
" checkArgument(true, toString());",
|
||||
" checkArgument(true, \"str\");",
|
||||
" checkArgument(true, \"str \" + 0);",
|
||||
" checkArgument(true, \"str %s\", 2 * 3);",
|
||||
" checkArgument(true, \"str %s\", toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkArgument(true, \"str \" + hashCode() / 2);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkArgument(true, (\"str \" + toString()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkArgument(true, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkArgument(true, \"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkNotNull(true, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkNotNull(true, \"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkState(true, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkState(true, \"%s \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" verify(true, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" verify(true, \"%s \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void jdk() {",
|
||||
" String.format(\"str\");",
|
||||
" String.format(\"str \" + 0);",
|
||||
" String.format(\"str {}\", 2 * 3);",
|
||||
" String.format(\"str {}\", toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(\"str \" + hashCode() / 2);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format((\"str \" + toString()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" String.format(Locale.ROOT, \"str\");",
|
||||
" String.format(Locale.ROOT, \"str \" + 0);",
|
||||
" String.format(Locale.ROOT, \"str {}\", 2 * 3);",
|
||||
" String.format(Locale.ROOT, \"str {}\", toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(Locale.ROOT, (\"str \" + toString()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(Locale.ROOT, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(Locale.ROOT, \"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" new Formatter().format(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" new Formatter().format(\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" new Formatter().format(Locale.ROOT, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" new Formatter().format(Locale.ROOT, \"{} \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void slf4j() {",
|
||||
" LOG.debug(\"str\");",
|
||||
" LOG.debug(\"str \" + 0);",
|
||||
" LOG.debug(\"str {}\", 2 * 3);",
|
||||
" LOG.debug(\"str {}\", toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug(\"str \" + hashCode() / 2);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug((\"str \" + toString()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug(\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" LOG.debug((Marker) null, \"str\");",
|
||||
" LOG.debug((Marker) null, \"str \" + 0);",
|
||||
" LOG.debug((Marker) null, \"str {}\", 2 * 3);",
|
||||
" LOG.debug((Marker) null, \"str {}\", toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug((Marker) null, (\"str \" + toString()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug((Marker) null, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug((Marker) null, \"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.error(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.error(\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.error((Marker) null, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.error((Marker) null, \"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.info(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.info(\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.info((Marker) null, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.info((Marker) null, \"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.trace(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.trace(\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.trace((Marker) null, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.trace((Marker) null, \"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.warn(\"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.warn(\"{} \" + toString(), \"arg\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.warn((Marker) null, \"str \" + toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.warn((Marker) null, \"{} \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.base.Verify.verify;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.SoftAssertions.assertSoftly;
|
||||
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.assertj.core.api.Fail;
|
||||
import org.assertj.core.api.ThrowableAssertAlternative;
|
||||
import org.assertj.core.api.WithAssertions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.Marker;
|
||||
|
||||
class A {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(A.class);
|
||||
|
||||
void negative() {
|
||||
hashCode();
|
||||
equals(new A());
|
||||
equals(toString());
|
||||
equals(0);
|
||||
equals("str");
|
||||
equals("str" + 0);
|
||||
equals(0 + 0);
|
||||
equals(0 - 0);
|
||||
equals("str " + toString());
|
||||
}
|
||||
|
||||
void assertj() {
|
||||
assertThat(0).overridingErrorMessage(toString());
|
||||
assertThat(0).overridingErrorMessage("str");
|
||||
assertThat(0).overridingErrorMessage("str " + 0);
|
||||
assertThat(0).overridingErrorMessage("str %s", 2 * 3);
|
||||
assertThat(0).overridingErrorMessage("str %s", toString());
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(0).overridingErrorMessage("str " + hashCode() / 2);
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(0).overridingErrorMessage(("str " + toString()));
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(0).overridingErrorMessage("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(0).overridingErrorMessage("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(0).withFailMessage("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(0).withFailMessage("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
assertSoftly(softly -> softly.fail("str " + toString()));
|
||||
// BUG: Diagnostic contains:
|
||||
assertSoftly(softly -> softly.fail("%s " + toString(), "arg"));
|
||||
assertSoftly(softly -> softly.fail("str " + toString(), new Throwable()));
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat("").isEqualTo("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat("").isEqualTo("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(new Error()).hasMessage("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(new Error()).hasMessage("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(new Error()).hasMessageContaining("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(new Error()).hasMessageContaining("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(new Error()).hasMessageEndingWith("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(new Error()).hasMessageEndingWith("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(new Error()).hasMessageStartingWith("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(new Error()).hasMessageStartingWith("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(new Error()).hasRootCauseMessage("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(new Error()).hasRootCauseMessage("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(new Error()).hasStackTraceContaining("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(new Error()).hasStackTraceContaining("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(0).as("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(0).as("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(0).describedAs("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
assertThat(0).describedAs("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
((ThrowableAssertAlternative) null).withMessage("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
((ThrowableAssertAlternative) null).withMessage("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
((ThrowableAssertAlternative) null).withMessageContaining("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
((ThrowableAssertAlternative) null).withMessageContaining("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
((ThrowableAssertAlternative) null).withMessageEndingWith("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
((ThrowableAssertAlternative) null).withMessageEndingWith("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
((ThrowableAssertAlternative) null).withMessageStartingWith("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
((ThrowableAssertAlternative) null).withMessageStartingWith("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
((ThrowableAssertAlternative) null).withStackTraceContaining("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
((ThrowableAssertAlternative) null).withStackTraceContaining("%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
((WithAssertions) null).fail("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
((WithAssertions) null).fail("%s " + toString(), "arg");
|
||||
((WithAssertions) null).fail("str " + toString(), new Throwable());
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Assertions.fail("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
Assertions.fail("%s " + toString(), "arg");
|
||||
Assertions.fail("str " + toString(), new Throwable());
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
BDDAssertions.fail("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
BDDAssertions.fail("%s " + toString(), "arg");
|
||||
BDDAssertions.fail("str " + toString(), new Throwable());
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Fail.fail("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
Fail.fail("%s " + toString(), "arg");
|
||||
Fail.fail("str " + toString(), new Throwable());
|
||||
}
|
||||
|
||||
void guava() {
|
||||
checkArgument(true);
|
||||
checkArgument(true, toString());
|
||||
checkArgument(true, "str");
|
||||
checkArgument(true, "str " + 0);
|
||||
checkArgument(true, "str %s", 2 * 3);
|
||||
checkArgument(true, "str %s", toString());
|
||||
// BUG: Diagnostic contains:
|
||||
checkArgument(true, "str " + hashCode() / 2);
|
||||
// BUG: Diagnostic contains:
|
||||
checkArgument(true, ("str " + toString()));
|
||||
// BUG: Diagnostic contains:
|
||||
checkArgument(true, "str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
checkArgument(true, "%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
checkNotNull(true, "str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
checkNotNull(true, "%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
checkState(true, "str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
checkState(true, "%s " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
verify(true, "str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
verify(true, "%s " + toString(), "arg");
|
||||
}
|
||||
|
||||
void jdk() {
|
||||
String.format("str");
|
||||
String.format("str " + 0);
|
||||
String.format("str {}", 2 * 3);
|
||||
String.format("str {}", toString());
|
||||
// BUG: Diagnostic contains:
|
||||
String.format("str " + hashCode() / 2);
|
||||
// BUG: Diagnostic contains:
|
||||
String.format(("str " + toString()));
|
||||
// BUG: Diagnostic contains:
|
||||
String.format("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
String.format("{} " + toString(), "arg");
|
||||
|
||||
String.format(Locale.ROOT, "str");
|
||||
String.format(Locale.ROOT, "str " + 0);
|
||||
String.format(Locale.ROOT, "str {}", 2 * 3);
|
||||
String.format(Locale.ROOT, "str {}", toString());
|
||||
// BUG: Diagnostic contains:
|
||||
String.format(Locale.ROOT, ("str " + toString()));
|
||||
// BUG: Diagnostic contains:
|
||||
String.format(Locale.ROOT, "str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
String.format(Locale.ROOT, "{} " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
new Formatter().format("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
new Formatter().format("{} " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
new Formatter().format(Locale.ROOT, "str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
new Formatter().format(Locale.ROOT, "{} " + toString(), "arg");
|
||||
}
|
||||
|
||||
void slf4j() {
|
||||
LOG.debug("str");
|
||||
LOG.debug("str " + 0);
|
||||
LOG.debug("str {}", 2 * 3);
|
||||
LOG.debug("str {}", toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.debug("str " + hashCode() / 2);
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.debug(("str " + toString()));
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.debug("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.debug("{} " + toString(), "arg");
|
||||
|
||||
LOG.debug((Marker) null, "str");
|
||||
LOG.debug((Marker) null, "str " + 0);
|
||||
LOG.debug((Marker) null, "str {}", 2 * 3);
|
||||
LOG.debug((Marker) null, "str {}", toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.debug((Marker) null, ("str " + toString()));
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.debug((Marker) null, "str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.debug((Marker) null, "{} " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.error("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.error("{} " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.error((Marker) null, "str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.error((Marker) null, "{} " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.info("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.info("{} " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.info((Marker) null, "str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.info((Marker) null, "{} " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.trace("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.trace("{} " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.trace((Marker) null, "str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.trace((Marker) null, "{} " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.warn("str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.warn("{} " + toString(), "arg");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.warn((Marker) null, "str " + toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.warn((Marker) null, "{} " + toString(), "arg");
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -307,102 +309,106 @@ final class FormatStringConcatenationTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(FormatStringConcatenation.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static com.google.common.base.Preconditions.checkArgument;",
|
||||
"import static org.assertj.core.api.Assertions.assertThat;",
|
||||
"",
|
||||
"import java.util.Locale;",
|
||||
"import org.slf4j.Logger;",
|
||||
"import org.slf4j.LoggerFactory;",
|
||||
"import org.slf4j.Marker;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
|
||||
"",
|
||||
" void assertj() {",
|
||||
" assertThat(0).overridingErrorMessage(toString() + \" str\");",
|
||||
" assertThat(0).overridingErrorMessage(\"str \" + toString());",
|
||||
" assertThat(0).overridingErrorMessage(toString() + toString());",
|
||||
" assertThat(0).overridingErrorMessage(\"str \" + toString() + \" word \" + new A().hashCode());",
|
||||
" assertThat(0).overridingErrorMessage(\"str \" + (toString() + \" word \") + (hashCode() / 2));",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" assertThat(0).overridingErrorMessage(\"%s \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void guava() {",
|
||||
" checkArgument(true, \"str \" + toString());",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" checkArgument(true, \"%s \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void jdk() {",
|
||||
" String.format(\"str \" + toString());",
|
||||
" String.format(Locale.ROOT, \"str \" + toString());",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" String.format(\"{} \" + toString(), \"arg\");",
|
||||
" String.format(Locale.ROOT, \"{} \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void slf4j() {",
|
||||
" LOG.debug(\"str \" + toString());",
|
||||
" LOG.debug((Marker) null, \"str \" + toString());",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" LOG.debug(\"{} \" + toString(), \"arg\");",
|
||||
" LOG.debug((Marker) null, \"{} \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Locale;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.Marker;
|
||||
|
||||
class A {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(A.class);
|
||||
|
||||
void assertj() {
|
||||
assertThat(0).overridingErrorMessage(toString() + " str");
|
||||
assertThat(0).overridingErrorMessage("str " + toString());
|
||||
assertThat(0).overridingErrorMessage(toString() + toString());
|
||||
assertThat(0).overridingErrorMessage("str " + toString() + " word " + new A().hashCode());
|
||||
assertThat(0).overridingErrorMessage("str " + (toString() + " word ") + (hashCode() / 2));
|
||||
|
||||
// Flagged but not auto-fixed.
|
||||
assertThat(0).overridingErrorMessage("%s " + toString(), "arg");
|
||||
}
|
||||
|
||||
void guava() {
|
||||
checkArgument(true, "str " + toString());
|
||||
|
||||
// Flagged but not auto-fixed.
|
||||
checkArgument(true, "%s " + toString(), "arg");
|
||||
}
|
||||
|
||||
void jdk() {
|
||||
String.format("str " + toString());
|
||||
String.format(Locale.ROOT, "str " + toString());
|
||||
|
||||
// Flagged but not auto-fixed.
|
||||
String.format("{} " + toString(), "arg");
|
||||
String.format(Locale.ROOT, "{} " + toString(), "arg");
|
||||
}
|
||||
|
||||
void slf4j() {
|
||||
LOG.debug("str " + toString());
|
||||
LOG.debug((Marker) null, "str " + toString());
|
||||
|
||||
// Flagged but not auto-fixed.
|
||||
LOG.debug("{} " + toString(), "arg");
|
||||
LOG.debug((Marker) null, "{} " + toString(), "arg");
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static com.google.common.base.Preconditions.checkArgument;",
|
||||
"import static org.assertj.core.api.Assertions.assertThat;",
|
||||
"",
|
||||
"import java.util.Locale;",
|
||||
"import org.slf4j.Logger;",
|
||||
"import org.slf4j.LoggerFactory;",
|
||||
"import org.slf4j.Marker;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
|
||||
"",
|
||||
" void assertj() {",
|
||||
" assertThat(0).overridingErrorMessage(\"%s str\", toString());",
|
||||
" assertThat(0).overridingErrorMessage(\"str %s\", toString());",
|
||||
" assertThat(0).overridingErrorMessage(\"%s%s\", toString(), toString());",
|
||||
" assertThat(0).overridingErrorMessage(\"str %s word %s\", toString(), new A().hashCode());",
|
||||
" assertThat(0).overridingErrorMessage(\"str %s word %s\", toString(), hashCode() / 2);",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" assertThat(0).overridingErrorMessage(\"%s \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void guava() {",
|
||||
" checkArgument(true, \"str %s\", toString());",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" checkArgument(true, \"%s \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void jdk() {",
|
||||
" String.format(\"str %s\", toString());",
|
||||
" String.format(Locale.ROOT, \"str %s\", toString());",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" String.format(\"{} \" + toString(), \"arg\");",
|
||||
" String.format(Locale.ROOT, \"{} \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"",
|
||||
" void slf4j() {",
|
||||
" LOG.debug(\"str {}\", toString());",
|
||||
" LOG.debug((Marker) null, \"str {}\", toString());",
|
||||
"",
|
||||
" // Flagged but not auto-fixed.",
|
||||
" LOG.debug(\"{} \" + toString(), \"arg\");",
|
||||
" LOG.debug((Marker) null, \"{} \" + toString(), \"arg\");",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Locale;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.Marker;
|
||||
|
||||
class A {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(A.class);
|
||||
|
||||
void assertj() {
|
||||
assertThat(0).overridingErrorMessage("%s str", toString());
|
||||
assertThat(0).overridingErrorMessage("str %s", toString());
|
||||
assertThat(0).overridingErrorMessage("%s%s", toString(), toString());
|
||||
assertThat(0).overridingErrorMessage("str %s word %s", toString(), new A().hashCode());
|
||||
assertThat(0).overridingErrorMessage("str %s word %s", toString(), hashCode() / 2);
|
||||
|
||||
// Flagged but not auto-fixed.
|
||||
assertThat(0).overridingErrorMessage("%s " + toString(), "arg");
|
||||
}
|
||||
|
||||
void guava() {
|
||||
checkArgument(true, "str %s", toString());
|
||||
|
||||
// Flagged but not auto-fixed.
|
||||
checkArgument(true, "%s " + toString(), "arg");
|
||||
}
|
||||
|
||||
void jdk() {
|
||||
String.format("str %s", toString());
|
||||
String.format(Locale.ROOT, "str %s", toString());
|
||||
|
||||
// Flagged but not auto-fixed.
|
||||
String.format("{} " + toString(), "arg");
|
||||
String.format(Locale.ROOT, "{} " + toString(), "arg");
|
||||
}
|
||||
|
||||
void slf4j() {
|
||||
LOG.debug("str {}", toString());
|
||||
LOG.debug((Marker) null, "str {}", toString());
|
||||
|
||||
// Flagged but not auto-fixed.
|
||||
LOG.debug("{} " + toString(), "arg");
|
||||
LOG.debug((Marker) null, "{} " + toString(), "arg");
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,168 +12,176 @@ final class IdentityConversionTest {
|
||||
CompilationTestHelper.newInstance(IdentityConversion.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static com.google.errorprone.matchers.Matchers.instanceMethod;",
|
||||
"import static com.google.errorprone.matchers.Matchers.staticMethod;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableBiMap;",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableListMultimap;",
|
||||
"import com.google.common.collect.ImmutableMap;",
|
||||
"import com.google.common.collect.ImmutableMultimap;",
|
||||
"import com.google.common.collect.ImmutableMultiset;",
|
||||
"import com.google.common.collect.ImmutableRangeMap;",
|
||||
"import com.google.common.collect.ImmutableRangeSet;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import com.google.common.collect.ImmutableSetMultimap;",
|
||||
"import com.google.common.collect.ImmutableTable;",
|
||||
"import com.google.errorprone.matchers.Matcher;",
|
||||
"import com.google.errorprone.matchers.Matchers;",
|
||||
"import reactor.adapter.rxjava.RxJava2Adapter;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"public final class A {",
|
||||
" public void m() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Boolean b1 = Boolean.valueOf(Boolean.FALSE);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Boolean b2 = Boolean.valueOf(false);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" boolean b3 = Boolean.valueOf(Boolean.FALSE);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" boolean b4 = Boolean.valueOf(false);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Byte byte1 = Byte.valueOf((Byte) Byte.MIN_VALUE);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Byte byte2 = Byte.valueOf(Byte.MIN_VALUE);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" byte byte3 = Byte.valueOf((Byte) Byte.MIN_VALUE);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" byte byte4 = Byte.valueOf(Byte.MIN_VALUE);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Character c1 = Character.valueOf((Character) 'a');",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Character c2 = Character.valueOf('a');",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" char c3 = Character.valueOf((Character) 'a');",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" char c4 = Character.valueOf('a');",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Double d1 = Double.valueOf((Double) 0.0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Double d2 = Double.valueOf(0.0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" double d3 = Double.valueOf((Double) 0.0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" double d4 = Double.valueOf(0.0);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Float f1 = Float.valueOf((Float) 0.0F);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Float f2 = Float.valueOf(0.0F);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" float f3 = Float.valueOf((Float) 0.0F);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" float f4 = Float.valueOf(0.0F);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Integer i1 = Integer.valueOf((Integer) 1);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Integer i2 = Integer.valueOf(1);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" int i3 = Integer.valueOf((Integer) 1);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" int i4 = Integer.valueOf(1);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Long l1 = Long.valueOf((Long) 1L);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Long l2 = Long.valueOf(1L);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" long l3 = Long.valueOf((Long) 1L);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" long l4 = Long.valueOf(1L);",
|
||||
"",
|
||||
" Long l5 = Long.valueOf((Integer) 1);",
|
||||
" Long l6 = Long.valueOf(1);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" long l7 = Long.valueOf((Integer) 1);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" long l8 = Long.valueOf(1);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Short s1 = Short.valueOf((Short) Short.MIN_VALUE);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Short s2 = Short.valueOf(Short.MIN_VALUE);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" short s3 = Short.valueOf((Short) Short.MIN_VALUE);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" short s4 = Short.valueOf(Short.MIN_VALUE);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String boolStr = Boolean.valueOf(Boolean.FALSE).toString();",
|
||||
" int boolHash = Boolean.valueOf(false).hashCode();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" int byteHash = Byte.valueOf((Byte) Byte.MIN_VALUE).hashCode();",
|
||||
" String byteStr = Byte.valueOf(Byte.MIN_VALUE).toString();",
|
||||
"",
|
||||
" String str1 = String.valueOf(0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String str2 = String.valueOf(\"1\");",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableBiMap<Object, Object> o1 = ImmutableBiMap.copyOf(ImmutableBiMap.of());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableList<Object> o2 = ImmutableList.copyOf(ImmutableList.of());",
|
||||
" ImmutableListMultimap<Object, Object> o3 =",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableListMultimap.copyOf(ImmutableListMultimap.of());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableMap<Object, Object> o4 = ImmutableMap.copyOf(ImmutableMap.of());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableMultimap<Object, Object> o5 = ImmutableMultimap.copyOf(ImmutableMultimap.of());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableMultiset<Object> o6 = ImmutableMultiset.copyOf(ImmutableMultiset.of());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableRangeMap<String, Object> o7 = ImmutableRangeMap.copyOf(ImmutableRangeMap.of());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableRangeSet<String> o8 = ImmutableRangeSet.copyOf(ImmutableRangeSet.of());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableSet<Object> o9 = ImmutableSet.copyOf(ImmutableSet.of());",
|
||||
" ImmutableSetMultimap<Object, Object> o10 =",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableSetMultimap.copyOf(ImmutableSetMultimap.of());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableTable<Object, Object, Object> o11 = ImmutableTable.copyOf(ImmutableTable.of());",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Matcher allOf1 = Matchers.allOf(instanceMethod());",
|
||||
" Matcher allOf2 = Matchers.allOf(instanceMethod(), staticMethod());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Matcher anyOf1 = Matchers.anyOf(staticMethod());",
|
||||
" Matcher anyOf2 = Matchers.anyOf(instanceMethod(), staticMethod());",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux<Integer> flux1 = Flux.just(1).flatMap(e -> RxJava2Adapter.fluxToFlowable(Flux.just(2)));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux<Integer> flux2 = Flux.concat(Flux.just(1));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux<Integer> flux3 = Flux.firstWithSignal(Flux.just(1));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux<Integer> flux4 = Flux.from(Flux.just(1));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux<Integer> flux5 = Flux.merge(Flux.just(1));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono<Integer> mono1 = Mono.from(Mono.just(1));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono<Integer> mono2 = Mono.fromDirect(Mono.just(1));",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.errorprone.matchers.Matchers.instanceMethod;
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableMultiset;
|
||||
import com.google.common.collect.ImmutableRangeMap;
|
||||
import com.google.common.collect.ImmutableRangeSet;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSetMultimap;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.matchers.Matchers;
|
||||
import java.time.Instant;
|
||||
import java.time.ZonedDateTime;
|
||||
import reactor.adapter.rxjava.RxJava2Adapter;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public final class A {
|
||||
public void m() {
|
||||
// BUG: Diagnostic contains:
|
||||
Boolean b1 = Boolean.valueOf(Boolean.FALSE);
|
||||
// BUG: Diagnostic contains:
|
||||
Boolean b2 = Boolean.valueOf(false);
|
||||
// BUG: Diagnostic contains:
|
||||
boolean b3 = Boolean.valueOf(Boolean.FALSE);
|
||||
// BUG: Diagnostic contains:
|
||||
boolean b4 = Boolean.valueOf(false);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Byte byte1 = Byte.valueOf((Byte) Byte.MIN_VALUE);
|
||||
// BUG: Diagnostic contains:
|
||||
Byte byte2 = Byte.valueOf(Byte.MIN_VALUE);
|
||||
// BUG: Diagnostic contains:
|
||||
byte byte3 = Byte.valueOf((Byte) Byte.MIN_VALUE);
|
||||
// BUG: Diagnostic contains:
|
||||
byte byte4 = Byte.valueOf(Byte.MIN_VALUE);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Character c1 = Character.valueOf((Character) 'a');
|
||||
// BUG: Diagnostic contains:
|
||||
Character c2 = Character.valueOf('a');
|
||||
// BUG: Diagnostic contains:
|
||||
char c3 = Character.valueOf((Character) 'a');
|
||||
// BUG: Diagnostic contains:
|
||||
char c4 = Character.valueOf('a');
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Double d1 = Double.valueOf((Double) 0.0);
|
||||
// BUG: Diagnostic contains:
|
||||
Double d2 = Double.valueOf(0.0);
|
||||
// BUG: Diagnostic contains:
|
||||
double d3 = Double.valueOf((Double) 0.0);
|
||||
// BUG: Diagnostic contains:
|
||||
double d4 = Double.valueOf(0.0);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Float f1 = Float.valueOf((Float) 0.0F);
|
||||
// BUG: Diagnostic contains:
|
||||
Float f2 = Float.valueOf(0.0F);
|
||||
// BUG: Diagnostic contains:
|
||||
float f3 = Float.valueOf((Float) 0.0F);
|
||||
// BUG: Diagnostic contains:
|
||||
float f4 = Float.valueOf(0.0F);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Integer i1 = Integer.valueOf((Integer) 1);
|
||||
// BUG: Diagnostic contains:
|
||||
Integer i2 = Integer.valueOf(1);
|
||||
// BUG: Diagnostic contains:
|
||||
int i3 = Integer.valueOf((Integer) 1);
|
||||
// BUG: Diagnostic contains:
|
||||
int i4 = Integer.valueOf(1);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Long l1 = Long.valueOf((Long) 1L);
|
||||
// BUG: Diagnostic contains:
|
||||
Long l2 = Long.valueOf(1L);
|
||||
// BUG: Diagnostic contains:
|
||||
long l3 = Long.valueOf((Long) 1L);
|
||||
// BUG: Diagnostic contains:
|
||||
long l4 = Long.valueOf(1L);
|
||||
|
||||
Long l5 = Long.valueOf((Integer) 1);
|
||||
Long l6 = Long.valueOf(1);
|
||||
// BUG: Diagnostic contains:
|
||||
long l7 = Long.valueOf((Integer) 1);
|
||||
// BUG: Diagnostic contains:
|
||||
long l8 = Long.valueOf(1);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Short s1 = Short.valueOf((Short) Short.MIN_VALUE);
|
||||
// BUG: Diagnostic contains:
|
||||
Short s2 = Short.valueOf(Short.MIN_VALUE);
|
||||
// BUG: Diagnostic contains:
|
||||
short s3 = Short.valueOf((Short) Short.MIN_VALUE);
|
||||
// BUG: Diagnostic contains:
|
||||
short s4 = Short.valueOf(Short.MIN_VALUE);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
String boolStr = Boolean.valueOf(Boolean.FALSE).toString();
|
||||
int boolHash = Boolean.valueOf(false).hashCode();
|
||||
// BUG: Diagnostic contains:
|
||||
int byteHash = Byte.valueOf((Byte) Byte.MIN_VALUE).hashCode();
|
||||
String byteStr = Byte.valueOf(Byte.MIN_VALUE).toString();
|
||||
|
||||
String str1 = String.valueOf(0);
|
||||
// BUG: Diagnostic contains:
|
||||
String str2 = String.valueOf("1");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
ImmutableBiMap<Object, Object> o1 = ImmutableBiMap.copyOf(ImmutableBiMap.of());
|
||||
// BUG: Diagnostic contains:
|
||||
ImmutableList<Object> o2 = ImmutableList.copyOf(ImmutableList.of());
|
||||
ImmutableListMultimap<Object, Object> o3 =
|
||||
// BUG: Diagnostic contains:
|
||||
ImmutableListMultimap.copyOf(ImmutableListMultimap.of());
|
||||
// BUG: Diagnostic contains:
|
||||
ImmutableMap<Object, Object> o4 = ImmutableMap.copyOf(ImmutableMap.of());
|
||||
// BUG: Diagnostic contains:
|
||||
ImmutableMultimap<Object, Object> o5 = ImmutableMultimap.copyOf(ImmutableMultimap.of());
|
||||
// BUG: Diagnostic contains:
|
||||
ImmutableMultiset<Object> o6 = ImmutableMultiset.copyOf(ImmutableMultiset.of());
|
||||
// BUG: Diagnostic contains:
|
||||
ImmutableRangeMap<String, Object> o7 = ImmutableRangeMap.copyOf(ImmutableRangeMap.of());
|
||||
// BUG: Diagnostic contains:
|
||||
ImmutableRangeSet<String> o8 = ImmutableRangeSet.copyOf(ImmutableRangeSet.of());
|
||||
// BUG: Diagnostic contains:
|
||||
ImmutableSet<Object> o9 = ImmutableSet.copyOf(ImmutableSet.of());
|
||||
ImmutableSetMultimap<Object, Object> o10 =
|
||||
// BUG: Diagnostic contains:
|
||||
ImmutableSetMultimap.copyOf(ImmutableSetMultimap.of());
|
||||
// BUG: Diagnostic contains:
|
||||
ImmutableTable<Object, Object, Object> o11 = ImmutableTable.copyOf(ImmutableTable.of());
|
||||
|
||||
Instant instant1 = Instant.from(ZonedDateTime.now());
|
||||
// BUG: Diagnostic contains:
|
||||
Instant instant2 = Instant.from(Instant.now());
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Matcher allOf1 = Matchers.allOf(instanceMethod());
|
||||
Matcher allOf2 = Matchers.allOf(instanceMethod(), staticMethod());
|
||||
// BUG: Diagnostic contains:
|
||||
Matcher anyOf1 = Matchers.anyOf(staticMethod());
|
||||
Matcher anyOf2 = Matchers.anyOf(instanceMethod(), staticMethod());
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux<Integer> flux1 = Flux.just(1).flatMap(e -> RxJava2Adapter.fluxToFlowable(Flux.just(2)));
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux<Integer> flux2 = Flux.concat(Flux.just(1));
|
||||
// BUG: Diagnostic contains:
|
||||
Flux<Integer> flux3 = Flux.firstWithSignal(Flux.just(1));
|
||||
// BUG: Diagnostic contains:
|
||||
Flux<Integer> flux4 = Flux.from(Flux.just(1));
|
||||
// BUG: Diagnostic contains:
|
||||
Flux<Integer> flux5 = Flux.merge(Flux.just(1));
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Mono<Integer> mono1 = Mono.from(Mono.just(1));
|
||||
// BUG: Diagnostic contains:
|
||||
Mono<Integer> mono2 = Mono.fromDirect(Mono.just(1));
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -182,104 +190,108 @@ final class IdentityConversionTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(IdentityConversion.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static com.google.errorprone.matchers.Matchers.staticMethod;",
|
||||
"import static org.mockito.Mockito.when;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableCollection;",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import com.google.errorprone.matchers.Matcher;",
|
||||
"import com.google.errorprone.matchers.Matchers;",
|
||||
"import java.util.ArrayList;",
|
||||
"import java.util.Collection;",
|
||||
"import org.reactivestreams.Publisher;",
|
||||
"import reactor.adapter.rxjava.RxJava2Adapter;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"public final class A {",
|
||||
" public void m() {",
|
||||
" ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());",
|
||||
" ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());",
|
||||
"",
|
||||
" ImmutableCollection<Integer> list1 = ImmutableList.copyOf(ImmutableList.of(1));",
|
||||
" ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));",
|
||||
"",
|
||||
" Collection<Integer> c1 = ImmutableSet.copyOf(ImmutableSet.of(1));",
|
||||
" Collection<Integer> c2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));",
|
||||
"",
|
||||
" Flux<Integer> f1 = Flux.just(1).flatMap(e -> RxJava2Adapter.fluxToFlowable(Flux.just(2)));",
|
||||
" Flux<Integer> f2 = Flux.concat(Flux.just(3));",
|
||||
" Publisher<Integer> f3 = Flux.firstWithSignal(Flux.just(4));",
|
||||
" Publisher<Integer> f4 = Flux.from(Flux.just(5));",
|
||||
" Publisher<Integer> f5 = Flux.merge(Flux.just(6));",
|
||||
"",
|
||||
" Mono<Integer> m1 = Mono.from(Mono.just(7));",
|
||||
" Publisher<Integer> m2 = Mono.fromDirect(Mono.just(8));",
|
||||
"",
|
||||
" bar(Flux.concat(Flux.just(9)));",
|
||||
" bar(Mono.from(Mono.just(10)));",
|
||||
"",
|
||||
" Object o1 = ImmutableSet.copyOf(ImmutableList.of());",
|
||||
" Object o2 = ImmutableSet.copyOf(ImmutableSet.of());",
|
||||
"",
|
||||
" Matcher matcher = Matchers.allOf(staticMethod());",
|
||||
"",
|
||||
" when(\"foo\".contains(\"f\")).thenAnswer(inv -> ImmutableSet.copyOf(ImmutableList.of(1)));",
|
||||
" }",
|
||||
"",
|
||||
" void bar(Publisher<Integer> publisher) {}",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.matchers.Matchers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.adapter.rxjava.RxJava2Adapter;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public final class A {
|
||||
public void m() {
|
||||
ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());
|
||||
ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());
|
||||
|
||||
ImmutableCollection<Integer> list1 = ImmutableList.copyOf(ImmutableList.of(1));
|
||||
ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));
|
||||
|
||||
Collection<Integer> c1 = ImmutableSet.copyOf(ImmutableSet.of(1));
|
||||
Collection<Integer> c2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));
|
||||
|
||||
Flux<Integer> f1 = Flux.just(1).flatMap(e -> RxJava2Adapter.fluxToFlowable(Flux.just(2)));
|
||||
Flux<Integer> f2 = Flux.concat(Flux.just(3));
|
||||
Publisher<Integer> f3 = Flux.firstWithSignal(Flux.just(4));
|
||||
Publisher<Integer> f4 = Flux.from(Flux.just(5));
|
||||
Publisher<Integer> f5 = Flux.merge(Flux.just(6));
|
||||
|
||||
Mono<Integer> m1 = Mono.from(Mono.just(7));
|
||||
Publisher<Integer> m2 = Mono.fromDirect(Mono.just(8));
|
||||
|
||||
bar(Flux.concat(Flux.just(9)));
|
||||
bar(Mono.from(Mono.just(10)));
|
||||
|
||||
Object o1 = ImmutableSet.copyOf(ImmutableList.of());
|
||||
Object o2 = ImmutableSet.copyOf(ImmutableSet.of());
|
||||
|
||||
Matcher matcher = Matchers.allOf(staticMethod());
|
||||
|
||||
when("foo".contains("f")).thenAnswer(inv -> ImmutableSet.copyOf(ImmutableList.of(1)));
|
||||
}
|
||||
|
||||
void bar(Publisher<Integer> publisher) {}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static com.google.errorprone.matchers.Matchers.staticMethod;",
|
||||
"import static org.mockito.Mockito.when;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableCollection;",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import com.google.errorprone.matchers.Matcher;",
|
||||
"import com.google.errorprone.matchers.Matchers;",
|
||||
"import java.util.ArrayList;",
|
||||
"import java.util.Collection;",
|
||||
"import org.reactivestreams.Publisher;",
|
||||
"import reactor.adapter.rxjava.RxJava2Adapter;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"public final class A {",
|
||||
" public void m() {",
|
||||
" ImmutableSet<Object> set1 = ImmutableSet.of();",
|
||||
" ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());",
|
||||
"",
|
||||
" ImmutableCollection<Integer> list1 = ImmutableList.of(1);",
|
||||
" ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));",
|
||||
"",
|
||||
" Collection<Integer> c1 = ImmutableSet.of(1);",
|
||||
" Collection<Integer> c2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));",
|
||||
"",
|
||||
" Flux<Integer> f1 = Flux.just(1).flatMap(e -> Flux.just(2));",
|
||||
" Flux<Integer> f2 = Flux.just(3);",
|
||||
" Publisher<Integer> f3 = Flux.just(4);",
|
||||
" Publisher<Integer> f4 = Flux.just(5);",
|
||||
" Publisher<Integer> f5 = Flux.just(6);",
|
||||
"",
|
||||
" Mono<Integer> m1 = Mono.just(7);",
|
||||
" Publisher<Integer> m2 = Mono.just(8);",
|
||||
"",
|
||||
" bar(Flux.just(9));",
|
||||
" bar(Mono.just(10));",
|
||||
"",
|
||||
" Object o1 = ImmutableSet.copyOf(ImmutableList.of());",
|
||||
" Object o2 = ImmutableSet.of();",
|
||||
"",
|
||||
" Matcher matcher = staticMethod();",
|
||||
"",
|
||||
" when(\"foo\".contains(\"f\")).thenAnswer(inv -> ImmutableSet.copyOf(ImmutableList.of(1)));",
|
||||
" }",
|
||||
"",
|
||||
" void bar(Publisher<Integer> publisher) {}",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.errorprone.matchers.Matchers.staticMethod;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.matchers.Matchers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.adapter.rxjava.RxJava2Adapter;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public final class A {
|
||||
public void m() {
|
||||
ImmutableSet<Object> set1 = ImmutableSet.of();
|
||||
ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());
|
||||
|
||||
ImmutableCollection<Integer> list1 = ImmutableList.of(1);
|
||||
ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));
|
||||
|
||||
Collection<Integer> c1 = ImmutableSet.of(1);
|
||||
Collection<Integer> c2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));
|
||||
|
||||
Flux<Integer> f1 = Flux.just(1).flatMap(e -> Flux.just(2));
|
||||
Flux<Integer> f2 = Flux.just(3);
|
||||
Publisher<Integer> f3 = Flux.just(4);
|
||||
Publisher<Integer> f4 = Flux.just(5);
|
||||
Publisher<Integer> f5 = Flux.just(6);
|
||||
|
||||
Mono<Integer> m1 = Mono.just(7);
|
||||
Publisher<Integer> m2 = Mono.just(8);
|
||||
|
||||
bar(Flux.just(9));
|
||||
bar(Mono.just(10));
|
||||
|
||||
Object o1 = ImmutableSet.copyOf(ImmutableList.of());
|
||||
Object o2 = ImmutableSet.of();
|
||||
|
||||
Matcher matcher = staticMethod();
|
||||
|
||||
when("foo".contains("f")).thenAnswer(inv -> ImmutableSet.copyOf(ImmutableList.of(1)));
|
||||
}
|
||||
|
||||
void bar(Publisher<Integer> publisher) {}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@@ -289,38 +301,42 @@ final class IdentityConversionTest {
|
||||
.setFixChooser(FixChoosers.SECOND)
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ImmutableCollection;",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.util.ArrayList;",
|
||||
"",
|
||||
"public final class A {",
|
||||
" public void m() {",
|
||||
" ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());",
|
||||
" ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());",
|
||||
"",
|
||||
" ImmutableCollection<Integer> list1 = ImmutableList.copyOf(ImmutableList.of(1));",
|
||||
" ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public final class A {
|
||||
public void m() {
|
||||
ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());
|
||||
ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());
|
||||
|
||||
ImmutableCollection<Integer> list1 = ImmutableList.copyOf(ImmutableList.of(1));
|
||||
ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ImmutableCollection;",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.util.ArrayList;",
|
||||
"",
|
||||
"public final class A {",
|
||||
" public void m() {",
|
||||
" @SuppressWarnings(\"IdentityConversion\")",
|
||||
" ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());",
|
||||
" ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());",
|
||||
"",
|
||||
" @SuppressWarnings(\"IdentityConversion\")",
|
||||
" ImmutableCollection<Integer> list1 = ImmutableList.copyOf(ImmutableList.of(1));",
|
||||
" ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public final class A {
|
||||
public void m() {
|
||||
@SuppressWarnings("IdentityConversion")
|
||||
ImmutableSet<Object> set1 = ImmutableSet.copyOf(ImmutableSet.of());
|
||||
ImmutableSet<Object> set2 = ImmutableSet.copyOf(ImmutableList.of());
|
||||
|
||||
@SuppressWarnings("IdentityConversion")
|
||||
ImmutableCollection<Integer> list1 = ImmutableList.copyOf(ImmutableList.of(1));
|
||||
ImmutableCollection<Integer> list2 = ImmutableList.copyOf(new ArrayList<>(ImmutableList.of(1)));
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,94 +11,96 @@ final class ImmutablesSortedSetComparatorTest {
|
||||
CompilationTestHelper.newInstance(ImmutablesSortedSetComparator.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ContiguousSet;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import com.google.common.collect.ImmutableSortedSet;",
|
||||
"import java.util.NavigableSet;",
|
||||
"import java.util.Set;",
|
||||
"import java.util.SortedSet;",
|
||||
"import java.util.TreeSet;",
|
||||
"import org.immutables.value.Value;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @Value.Immutable",
|
||||
" interface ImmutableInterface {",
|
||||
" Set<String> set();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" SortedSet<String> sortedSet();",
|
||||
"",
|
||||
" @Value.NaturalOrder",
|
||||
" SortedSet<String> sortedSet2();",
|
||||
" }",
|
||||
"",
|
||||
" @Value.Modifiable",
|
||||
" interface ModifiableInterfaceWithDefaults {",
|
||||
" @Value.Default",
|
||||
" default Set<Integer> set() {",
|
||||
" return new TreeSet<>();",
|
||||
" }",
|
||||
"",
|
||||
" @Value.Default",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" default NavigableSet<Integer> navigableSet() {",
|
||||
" return new TreeSet<>();",
|
||||
" }",
|
||||
"",
|
||||
" @Value.Default",
|
||||
" @Value.ReverseOrder",
|
||||
" default NavigableSet<Integer> navigableSet2() {",
|
||||
" return new TreeSet<>();",
|
||||
" }",
|
||||
"",
|
||||
" default NavigableSet<Integer> nonPropertyNavigableSet() {",
|
||||
" return new TreeSet<>();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" interface NonImmutablesInterface {",
|
||||
" SortedSet<String> sortedSet();",
|
||||
" }",
|
||||
"",
|
||||
" @Value.Immutable",
|
||||
" abstract class AbstractImmutableWithDefaults {",
|
||||
" @Value.Default",
|
||||
" ImmutableSet<Integer> immutableSet() {",
|
||||
" return ImmutableSet.of();",
|
||||
" }",
|
||||
"",
|
||||
" @Value.Default",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" ImmutableSortedSet<String> immutableSortedSet() {",
|
||||
" return ImmutableSortedSet.of();",
|
||||
" }",
|
||||
"",
|
||||
" @Value.Default",
|
||||
" @Value.NaturalOrder",
|
||||
" ImmutableSortedSet<String> immutableSortedSet2() {",
|
||||
" return ImmutableSortedSet.of();",
|
||||
" }",
|
||||
"",
|
||||
" ImmutableSortedSet<String> nonPropertyImmutableSortedSet() {",
|
||||
" return ImmutableSortedSet.of();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" @Value.Modifiable",
|
||||
" abstract class AbstractModifiable {",
|
||||
" abstract ImmutableSet<Integer> immutableSet();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" abstract ContiguousSet<Integer> contiguousSet();",
|
||||
"",
|
||||
" @Value.ReverseOrder",
|
||||
" abstract ContiguousSet<Integer> contiguousSet2();",
|
||||
" }",
|
||||
"",
|
||||
" abstract class AbstractNonImmutables {",
|
||||
" abstract SortedSet<Integer> sortedSet();",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import com.google.common.collect.ContiguousSet;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import org.immutables.value.Value;
|
||||
|
||||
interface A {
|
||||
@Value.Immutable
|
||||
interface ImmutableInterface {
|
||||
Set<String> set();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
SortedSet<String> sortedSet();
|
||||
|
||||
@Value.NaturalOrder
|
||||
SortedSet<String> sortedSet2();
|
||||
}
|
||||
|
||||
@Value.Modifiable
|
||||
interface ModifiableInterfaceWithDefaults {
|
||||
@Value.Default
|
||||
default Set<Integer> set() {
|
||||
return new TreeSet<>();
|
||||
}
|
||||
|
||||
@Value.Default
|
||||
// BUG: Diagnostic contains:
|
||||
default NavigableSet<Integer> navigableSet() {
|
||||
return new TreeSet<>();
|
||||
}
|
||||
|
||||
@Value.Default
|
||||
@Value.ReverseOrder
|
||||
default NavigableSet<Integer> navigableSet2() {
|
||||
return new TreeSet<>();
|
||||
}
|
||||
|
||||
default NavigableSet<Integer> nonPropertyNavigableSet() {
|
||||
return new TreeSet<>();
|
||||
}
|
||||
}
|
||||
|
||||
interface NonImmutablesInterface {
|
||||
SortedSet<String> sortedSet();
|
||||
}
|
||||
|
||||
@Value.Immutable
|
||||
abstract class AbstractImmutableWithDefaults {
|
||||
@Value.Default
|
||||
ImmutableSet<Integer> immutableSet() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
@Value.Default
|
||||
// BUG: Diagnostic contains:
|
||||
ImmutableSortedSet<String> immutableSortedSet() {
|
||||
return ImmutableSortedSet.of();
|
||||
}
|
||||
|
||||
@Value.Default
|
||||
@Value.NaturalOrder
|
||||
ImmutableSortedSet<String> immutableSortedSet2() {
|
||||
return ImmutableSortedSet.of();
|
||||
}
|
||||
|
||||
ImmutableSortedSet<String> nonPropertyImmutableSortedSet() {
|
||||
return ImmutableSortedSet.of();
|
||||
}
|
||||
}
|
||||
|
||||
@Value.Modifiable
|
||||
abstract class AbstractModifiable {
|
||||
abstract ImmutableSet<Integer> immutableSet();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
abstract ContiguousSet<Integer> contiguousSet();
|
||||
|
||||
@Value.ReverseOrder
|
||||
abstract ContiguousSet<Integer> contiguousSet2();
|
||||
}
|
||||
|
||||
abstract class AbstractNonImmutables {
|
||||
abstract SortedSet<Integer> sortedSet();
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -107,36 +109,40 @@ final class ImmutablesSortedSetComparatorTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(ImmutablesSortedSetComparator.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ImmutableSortedSet;",
|
||||
"import java.util.SortedSet;",
|
||||
"import org.immutables.value.Value;",
|
||||
"",
|
||||
"@Value.Immutable",
|
||||
"abstract class A {",
|
||||
" abstract ImmutableSortedSet<String> sortedSet();",
|
||||
"",
|
||||
" @Value.Modifiable",
|
||||
" interface B {",
|
||||
" SortedSet<String> sortedSet();",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import java.util.SortedSet;
|
||||
import org.immutables.value.Value;
|
||||
|
||||
@Value.Immutable
|
||||
abstract class A {
|
||||
abstract ImmutableSortedSet<String> sortedSet();
|
||||
|
||||
@Value.Modifiable
|
||||
interface B {
|
||||
SortedSet<String> sortedSet();
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ImmutableSortedSet;",
|
||||
"import java.util.SortedSet;",
|
||||
"import org.immutables.value.Value;",
|
||||
"",
|
||||
"@Value.Immutable",
|
||||
"abstract class A {",
|
||||
" @Value.NaturalOrder",
|
||||
" abstract ImmutableSortedSet<String> sortedSet();",
|
||||
"",
|
||||
" @Value.Modifiable",
|
||||
" interface B {",
|
||||
" @Value.NaturalOrder",
|
||||
" SortedSet<String> sortedSet();",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import java.util.SortedSet;
|
||||
import org.immutables.value.Value;
|
||||
|
||||
@Value.Immutable
|
||||
abstract class A {
|
||||
@Value.NaturalOrder
|
||||
abstract ImmutableSortedSet<String> sortedSet();
|
||||
|
||||
@Value.Modifiable
|
||||
interface B {
|
||||
@Value.NaturalOrder
|
||||
SortedSet<String> sortedSet();
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@@ -145,33 +151,37 @@ final class ImmutablesSortedSetComparatorTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(ImmutablesSortedSetComparator.class, getClass())
|
||||
.addInputLines(
|
||||
"MySpringService.java",
|
||||
"import com.google.common.collect.ImmutableSortedSet;",
|
||||
"import org.springframework.beans.factory.annotation.Value;",
|
||||
"",
|
||||
"class MySpringService {",
|
||||
" MySpringService(@Value(\"${someProperty}\") String prop) {}",
|
||||
" ;",
|
||||
"",
|
||||
" @org.immutables.value.Value.Immutable",
|
||||
" interface A {",
|
||||
" ImmutableSortedSet<String> sortedSet();",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
class MySpringService {
|
||||
MySpringService(@Value("${someProperty}") String prop) {}
|
||||
;
|
||||
|
||||
@org.immutables.value.Value.Immutable
|
||||
interface A {
|
||||
ImmutableSortedSet<String> sortedSet();
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"MySpringService.java",
|
||||
"import com.google.common.collect.ImmutableSortedSet;",
|
||||
"import org.springframework.beans.factory.annotation.Value;",
|
||||
"",
|
||||
"class MySpringService {",
|
||||
" MySpringService(@Value(\"${someProperty}\") String prop) {}",
|
||||
" ;",
|
||||
"",
|
||||
" @org.immutables.value.Value.Immutable",
|
||||
" interface A {",
|
||||
" @org.immutables.value.Value.NaturalOrder",
|
||||
" ImmutableSortedSet<String> sortedSet();",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
class MySpringService {
|
||||
MySpringService(@Value("${someProperty}") String prop) {}
|
||||
;
|
||||
|
||||
@org.immutables.value.Value.Immutable
|
||||
interface A {
|
||||
@org.immutables.value.Value.NaturalOrder
|
||||
ImmutableSortedSet<String> sortedSet();
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,31 +11,34 @@ final class IsInstanceLambdaUsageTest {
|
||||
CompilationTestHelper.newInstance(IsInstanceLambdaUsage.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.stream.Stream;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Integer localVariable = 0;",
|
||||
"",
|
||||
" Stream.of(0).map(i -> i + 1);",
|
||||
" Stream.of(1).filter(Integer.class::isInstance);",
|
||||
" Stream.of(2).filter(i -> i.getClass() instanceof Class);",
|
||||
" Stream.of(3).filter(i -> localVariable instanceof Integer);",
|
||||
" // XXX: Ideally this case is also flagged. Pick this up in the context of merging the",
|
||||
" // `IsInstanceLambdaUsage` and `MethodReferenceUsage` checks, or introduce a separate check that",
|
||||
" // simplifies unnecessary block lambda expressions.",
|
||||
" Stream.of(4)",
|
||||
" .filter(",
|
||||
" i -> {",
|
||||
" return localVariable instanceof Integer;",
|
||||
" });",
|
||||
" Flux.just(5, \"foo\").distinctUntilChanged(v -> v, (a, b) -> a instanceof Integer);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Stream.of(6).filter(i -> i instanceof Integer);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import java.util.stream.Stream;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Integer localVariable = 0;
|
||||
|
||||
Stream.of(0).map(i -> i);
|
||||
Stream.of(1).map(i -> i + 1);
|
||||
Stream.of(2).filter(Integer.class::isInstance);
|
||||
Stream.of(3).filter(i -> i.getClass() instanceof Class);
|
||||
Stream.of(4).filter(i -> localVariable instanceof Integer);
|
||||
// XXX: Ideally this case is also flagged. Pick this up in the context of merging the
|
||||
// `IsInstanceLambdaUsage` and `MethodReferenceUsage` checks, or introduce a separate check that
|
||||
// simplifies unnecessary block lambda expressions.
|
||||
Stream.of(5)
|
||||
.filter(
|
||||
i -> {
|
||||
return i instanceof Integer;
|
||||
});
|
||||
Flux.just(6, "foo").distinctUntilChanged(v -> v, (a, b) -> a instanceof Integer);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Stream.of(7).filter(i -> i instanceof Integer);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -44,22 +47,26 @@ final class IsInstanceLambdaUsageTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(IsInstanceLambdaUsage.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import java.util.stream.Stream;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Stream.of(1).filter(i -> i instanceof Integer);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Stream.of(1).filter(i -> i instanceof Integer);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import java.util.stream.Stream;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Stream.of(1).filter(Integer.class::isInstance);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Stream.of(1).filter(Integer.class::isInstance);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,83 +11,85 @@ final class JUnitClassModifiersTest {
|
||||
CompilationTestHelper.newInstance(JUnitClassModifiers.class, getClass())
|
||||
.addSourceLines(
|
||||
"Container.java",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"import org.springframework.boot.test.context.TestConfiguration;",
|
||||
"import org.springframework.context.annotation.Configuration;",
|
||||
"",
|
||||
"class Container {",
|
||||
" final class FinalAndPackagePrivate {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" final class FinalAndPackagePrivateWithCustomTestMethod {",
|
||||
" @ParameterizedTest",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" public abstract class Abstract {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" @Configuration",
|
||||
" class WithConfigurationAnnotation {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" @TestConfiguration",
|
||||
" class WithConfigurationMetaAnnotation {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" private final class Private {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" protected final class Protected {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public final class Public {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" class NonFinal {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" class NonFinalWithCustomTestMethod {",
|
||||
" @ParameterizedTest",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" @Configuration",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public class PublicWithConfigurationAnnotation {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"",
|
||||
" @TestConfiguration",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" protected class ProtectedWithConfigurationMetaAnnotation {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
class Container {
|
||||
final class FinalAndPackagePrivate {
|
||||
@Test
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
final class FinalAndPackagePrivateWithCustomTestMethod {
|
||||
@ParameterizedTest
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
public abstract class Abstract {
|
||||
@Test
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
class WithConfigurationAnnotation {
|
||||
@Test
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
@TestConfiguration
|
||||
class WithConfigurationMetaAnnotation {
|
||||
@Test
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
private final class Private {
|
||||
@Test
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
protected final class Protected {
|
||||
@Test
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
public final class Public {
|
||||
@Test
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
class NonFinal {
|
||||
@Test
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
class NonFinalWithCustomTestMethod {
|
||||
@ParameterizedTest
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
// BUG: Diagnostic contains:
|
||||
public class PublicWithConfigurationAnnotation {
|
||||
@Test
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
@TestConfiguration
|
||||
// BUG: Diagnostic contains:
|
||||
protected class ProtectedWithConfigurationMetaAnnotation {
|
||||
@Test
|
||||
void foo() {}
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -96,34 +98,38 @@ final class JUnitClassModifiersTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(JUnitClassModifiers.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.springframework.context.annotation.Configuration;",
|
||||
"",
|
||||
"public class A {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
"",
|
||||
" @Configuration",
|
||||
" private static class B {",
|
||||
" @Test",
|
||||
" void bar() {}",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
public class A {
|
||||
@Test
|
||||
void foo() {}
|
||||
|
||||
@Configuration
|
||||
private static class B {
|
||||
@Test
|
||||
void bar() {}
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.springframework.context.annotation.Configuration;",
|
||||
"",
|
||||
"final class A {",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
"",
|
||||
" @Configuration",
|
||||
" static class B {",
|
||||
" @Test",
|
||||
" void bar() {}",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
final class A {
|
||||
@Test
|
||||
void foo() {}
|
||||
|
||||
@Configuration
|
||||
static class B {
|
||||
@Test
|
||||
void bar() {}
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,330 +11,338 @@ final class JUnitMethodDeclarationTest {
|
||||
CompilationTestHelper.newInstance(JUnitMethodDeclaration.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
|
||||
"",
|
||||
"import org.junit.jupiter.api.AfterAll;",
|
||||
"import org.junit.jupiter.api.AfterEach;",
|
||||
"import org.junit.jupiter.api.BeforeAll;",
|
||||
"import org.junit.jupiter.api.BeforeEach;",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"",
|
||||
"class A {",
|
||||
" {",
|
||||
" arguments();",
|
||||
" }",
|
||||
"",
|
||||
" @BeforeAll",
|
||||
" void setUp1() {}",
|
||||
"",
|
||||
" @BeforeAll",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void setUp2() {}",
|
||||
"",
|
||||
" @BeforeAll",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" protected void setUp3() {}",
|
||||
"",
|
||||
" @BeforeAll",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" private void setUp4() {}",
|
||||
"",
|
||||
" @BeforeEach",
|
||||
" void setup5() {}",
|
||||
"",
|
||||
" @BeforeEach",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void setUp6() {}",
|
||||
"",
|
||||
" @BeforeEach",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" protected void setUp7() {}",
|
||||
"",
|
||||
" @BeforeEach",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" private void setUp8() {}",
|
||||
"",
|
||||
" @AfterEach",
|
||||
" void tearDown1() {}",
|
||||
"",
|
||||
" @AfterEach",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void tearDown2() {}",
|
||||
"",
|
||||
" @AfterEach",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" protected void tearDown3() {}",
|
||||
"",
|
||||
" @AfterEach",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" private void tearDown4() {}",
|
||||
"",
|
||||
" @AfterAll",
|
||||
" void tearDown5() {}",
|
||||
"",
|
||||
" @AfterAll",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void tearDown6() {}",
|
||||
"",
|
||||
" @AfterAll",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" protected void tearDown7() {}",
|
||||
"",
|
||||
" @AfterAll",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" private void tearDown8() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void test() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void method1() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" void testMethod2() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void method3() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" protected void method4() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" private void method5() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" void method6() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" void testMethod7() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" public void method8() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" protected void method9() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" private void method10() {}",
|
||||
"",
|
||||
" @BeforeEach",
|
||||
" @BeforeAll",
|
||||
" @AfterEach",
|
||||
" @AfterAll",
|
||||
" void testNonTestMethod1() {}",
|
||||
"",
|
||||
" public void testNonTestMethod2() {}",
|
||||
"",
|
||||
" protected void testNonTestMethod3() {}",
|
||||
"",
|
||||
" private void testNonTestMethod4() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void test5() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains: (but note that a method named `toString` is already defined in this",
|
||||
" // class or a supertype)",
|
||||
" void testToString() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains: (but note that a method named `overload` is already defined in this",
|
||||
" // class or a supertype)",
|
||||
" void testOverload() {}",
|
||||
"",
|
||||
" void overload() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains: (but note that `arguments` is already statically imported)",
|
||||
" void testArguments() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains: (but note that `public` is not a valid identifier)",
|
||||
" void testPublic() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains: (but note that `null` is not a valid identifier)",
|
||||
" void testNull() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" void testRecord() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" void testMethodThatIsOverriddenWithoutOverrideAnnotation() {}",
|
||||
"}")
|
||||
"""
|
||||
import static org.junit.jupiter.params.provider.Arguments.*;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
|
||||
class A {
|
||||
{
|
||||
arguments();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
void setUp1() {}
|
||||
|
||||
@BeforeAll
|
||||
// BUG: Diagnostic contains:
|
||||
public void setUp2() {}
|
||||
|
||||
@BeforeAll
|
||||
// BUG: Diagnostic contains:
|
||||
protected void setUp3() {}
|
||||
|
||||
@BeforeAll
|
||||
// BUG: Diagnostic contains:
|
||||
private void setUp4() {}
|
||||
|
||||
@BeforeEach
|
||||
void setup5() {}
|
||||
|
||||
@BeforeEach
|
||||
// BUG: Diagnostic contains:
|
||||
public void setUp6() {}
|
||||
|
||||
@BeforeEach
|
||||
// BUG: Diagnostic contains:
|
||||
protected void setUp7() {}
|
||||
|
||||
@BeforeEach
|
||||
// BUG: Diagnostic contains:
|
||||
private void setUp8() {}
|
||||
|
||||
@AfterEach
|
||||
void tearDown1() {}
|
||||
|
||||
@AfterEach
|
||||
// BUG: Diagnostic contains:
|
||||
public void tearDown2() {}
|
||||
|
||||
@AfterEach
|
||||
// BUG: Diagnostic contains:
|
||||
protected void tearDown3() {}
|
||||
|
||||
@AfterEach
|
||||
// BUG: Diagnostic contains:
|
||||
private void tearDown4() {}
|
||||
|
||||
@AfterAll
|
||||
void tearDown5() {}
|
||||
|
||||
@AfterAll
|
||||
// BUG: Diagnostic contains:
|
||||
public void tearDown6() {}
|
||||
|
||||
@AfterAll
|
||||
// BUG: Diagnostic contains:
|
||||
protected void tearDown7() {}
|
||||
|
||||
@AfterAll
|
||||
// BUG: Diagnostic contains:
|
||||
private void tearDown8() {}
|
||||
|
||||
@Test
|
||||
void test() {}
|
||||
|
||||
@Test
|
||||
void method1() {}
|
||||
|
||||
@Test
|
||||
// BUG: Diagnostic contains:
|
||||
void testMethod2() {}
|
||||
|
||||
@Test
|
||||
// BUG: Diagnostic contains:
|
||||
public void method3() {}
|
||||
|
||||
@Test
|
||||
// BUG: Diagnostic contains:
|
||||
protected void method4() {}
|
||||
|
||||
@Test
|
||||
// BUG: Diagnostic contains:
|
||||
private void method5() {}
|
||||
|
||||
@ParameterizedTest
|
||||
void method6() {}
|
||||
|
||||
@ParameterizedTest
|
||||
// BUG: Diagnostic contains:
|
||||
void testMethod7() {}
|
||||
|
||||
@ParameterizedTest
|
||||
// BUG: Diagnostic contains:
|
||||
public void method8() {}
|
||||
|
||||
@ParameterizedTest
|
||||
// BUG: Diagnostic contains:
|
||||
protected void method9() {}
|
||||
|
||||
@ParameterizedTest
|
||||
// BUG: Diagnostic contains:
|
||||
private void method10() {}
|
||||
|
||||
@BeforeEach
|
||||
@BeforeAll
|
||||
@AfterEach
|
||||
@AfterAll
|
||||
void testNonTestMethod1() {}
|
||||
|
||||
public void testNonTestMethod2() {}
|
||||
|
||||
protected void testNonTestMethod3() {}
|
||||
|
||||
private void testNonTestMethod4() {}
|
||||
|
||||
@Test
|
||||
void test5() {}
|
||||
|
||||
@Test
|
||||
// BUG: Diagnostic contains: (but note that a method named `toString` is already defined in this
|
||||
// class or a supertype)
|
||||
void testToString() {}
|
||||
|
||||
@Test
|
||||
// BUG: Diagnostic contains: (but note that a method named `overload` is already defined in this
|
||||
// class or a supertype)
|
||||
void testOverload() {}
|
||||
|
||||
void overload() {}
|
||||
|
||||
@Test
|
||||
// BUG: Diagnostic contains: (but note that another method named `arguments` is in scope)
|
||||
void testArguments() {
|
||||
arguments();
|
||||
}
|
||||
|
||||
@Test
|
||||
// BUG: Diagnostic contains: (but note that `public` is not a valid identifier)
|
||||
void testPublic() {}
|
||||
|
||||
@Test
|
||||
// BUG: Diagnostic contains: (but note that `null` is not a valid identifier)
|
||||
void testNull() {}
|
||||
|
||||
@Test
|
||||
// BUG: Diagnostic contains:
|
||||
void testRecord() {}
|
||||
|
||||
@Test
|
||||
// BUG: Diagnostic contains:
|
||||
void testMethodThatIsOverriddenWithoutOverrideAnnotation() {}
|
||||
}
|
||||
""")
|
||||
.addSourceLines(
|
||||
"B.java",
|
||||
"import org.junit.jupiter.api.AfterAll;",
|
||||
"import org.junit.jupiter.api.AfterEach;",
|
||||
"import org.junit.jupiter.api.BeforeAll;",
|
||||
"import org.junit.jupiter.api.BeforeEach;",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"",
|
||||
"class B extends A {",
|
||||
" @Override",
|
||||
" @BeforeAll",
|
||||
" void setUp1() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @BeforeAll",
|
||||
" public void setUp2() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @BeforeAll",
|
||||
" protected void setUp3() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @BeforeEach",
|
||||
" void setup5() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @BeforeEach",
|
||||
" public void setUp6() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @BeforeEach",
|
||||
" protected void setUp7() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @AfterEach",
|
||||
" void tearDown1() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @AfterEach",
|
||||
" public void tearDown2() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @AfterEach",
|
||||
" protected void tearDown3() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @AfterAll",
|
||||
" void tearDown5() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @AfterAll",
|
||||
" public void tearDown6() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @AfterAll",
|
||||
" protected void tearDown7() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void test() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void method1() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void testMethod2() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" public void method3() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" protected void method4() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @ParameterizedTest",
|
||||
" void method6() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @ParameterizedTest",
|
||||
" void testMethod7() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @ParameterizedTest",
|
||||
" public void method8() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @ParameterizedTest",
|
||||
" protected void method9() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @BeforeEach",
|
||||
" @BeforeAll",
|
||||
" @AfterEach",
|
||||
" @AfterAll",
|
||||
" void testNonTestMethod1() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" public void testNonTestMethod2() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" protected void testNonTestMethod3() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void test5() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void testToString() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void testOverload() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" void overload() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void testArguments() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void testPublic() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void testNull() {}",
|
||||
"",
|
||||
" @Override",
|
||||
" @Test",
|
||||
" void testRecord() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void testMethodThatIsOverriddenWithoutOverrideAnnotation() {}",
|
||||
"}")
|
||||
"""
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
|
||||
class B extends A {
|
||||
@Override
|
||||
@BeforeAll
|
||||
void setUp1() {}
|
||||
|
||||
@Override
|
||||
@BeforeAll
|
||||
public void setUp2() {}
|
||||
|
||||
@Override
|
||||
@BeforeAll
|
||||
protected void setUp3() {}
|
||||
|
||||
@Override
|
||||
@BeforeEach
|
||||
void setup5() {}
|
||||
|
||||
@Override
|
||||
@BeforeEach
|
||||
public void setUp6() {}
|
||||
|
||||
@Override
|
||||
@BeforeEach
|
||||
protected void setUp7() {}
|
||||
|
||||
@Override
|
||||
@AfterEach
|
||||
void tearDown1() {}
|
||||
|
||||
@Override
|
||||
@AfterEach
|
||||
public void tearDown2() {}
|
||||
|
||||
@Override
|
||||
@AfterEach
|
||||
protected void tearDown3() {}
|
||||
|
||||
@Override
|
||||
@AfterAll
|
||||
void tearDown5() {}
|
||||
|
||||
@Override
|
||||
@AfterAll
|
||||
public void tearDown6() {}
|
||||
|
||||
@Override
|
||||
@AfterAll
|
||||
protected void tearDown7() {}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
void test() {}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
void method1() {}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
void testMethod2() {}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void method3() {}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
protected void method4() {}
|
||||
|
||||
@Override
|
||||
@ParameterizedTest
|
||||
void method6() {}
|
||||
|
||||
@Override
|
||||
@ParameterizedTest
|
||||
void testMethod7() {}
|
||||
|
||||
@Override
|
||||
@ParameterizedTest
|
||||
public void method8() {}
|
||||
|
||||
@Override
|
||||
@ParameterizedTest
|
||||
protected void method9() {}
|
||||
|
||||
@Override
|
||||
@BeforeEach
|
||||
@BeforeAll
|
||||
@AfterEach
|
||||
@AfterAll
|
||||
void testNonTestMethod1() {}
|
||||
|
||||
@Override
|
||||
public void testNonTestMethod2() {}
|
||||
|
||||
@Override
|
||||
protected void testNonTestMethod3() {}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
void test5() {}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
void testToString() {}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
void testOverload() {}
|
||||
|
||||
@Override
|
||||
void overload() {}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
void testArguments() {}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
void testPublic() {}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
void testNull() {}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
void testRecord() {}
|
||||
|
||||
@Test
|
||||
void testMethodThatIsOverriddenWithoutOverrideAnnotation() {}
|
||||
}
|
||||
""")
|
||||
.addSourceLines(
|
||||
"C.java",
|
||||
"import org.junit.jupiter.api.AfterAll;",
|
||||
"import org.junit.jupiter.api.BeforeAll;",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"",
|
||||
"abstract class C {",
|
||||
" @BeforeAll",
|
||||
" public void setUp() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void testMethod1() {}",
|
||||
"",
|
||||
" @AfterAll",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" private void tearDown() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" final void testMethod2() {}",
|
||||
"}")
|
||||
"""
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
abstract class C {
|
||||
@BeforeAll
|
||||
public void setUp() {}
|
||||
|
||||
@Test
|
||||
void testMethod1() {}
|
||||
|
||||
@AfterAll
|
||||
// BUG: Diagnostic contains:
|
||||
private void tearDown() {}
|
||||
|
||||
@Test
|
||||
// BUG: Diagnostic contains:
|
||||
final void testMethod2() {}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -343,126 +351,130 @@ final class JUnitMethodDeclarationTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(JUnitMethodDeclaration.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
|
||||
"",
|
||||
"import org.junit.jupiter.api.AfterAll;",
|
||||
"import org.junit.jupiter.api.AfterEach;",
|
||||
"import org.junit.jupiter.api.BeforeAll;",
|
||||
"import org.junit.jupiter.api.BeforeEach;",
|
||||
"import org.junit.jupiter.api.RepeatedTest;",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"",
|
||||
"class A {",
|
||||
" {",
|
||||
" arguments();",
|
||||
" }",
|
||||
"",
|
||||
" @BeforeAll",
|
||||
" public void setUp1() {}",
|
||||
"",
|
||||
" @BeforeEach",
|
||||
" protected void setUp2() {}",
|
||||
"",
|
||||
" @AfterEach",
|
||||
" private void setUp3() {}",
|
||||
"",
|
||||
" @AfterAll",
|
||||
" private void setUp4() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void testFoo() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" void testBar() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" public void baz() {}",
|
||||
"",
|
||||
" @RepeatedTest(2)",
|
||||
" private void qux() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" protected void quux() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" public void testToString() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" public void testOverload() {}",
|
||||
"",
|
||||
" void overload() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" protected void testArguments() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" private void testClass() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" private void testTrue() {}",
|
||||
"}")
|
||||
"""
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.RepeatedTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
|
||||
class A {
|
||||
{
|
||||
arguments();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public void setUp1() {}
|
||||
|
||||
@BeforeEach
|
||||
protected void setUp2() {}
|
||||
|
||||
@AfterEach
|
||||
private void setUp3() {}
|
||||
|
||||
@AfterAll
|
||||
private void setUp4() {}
|
||||
|
||||
@Test
|
||||
void testFoo() {}
|
||||
|
||||
@ParameterizedTest
|
||||
void testBar() {}
|
||||
|
||||
@Test
|
||||
public void baz() {}
|
||||
|
||||
@RepeatedTest(2)
|
||||
private void qux() {}
|
||||
|
||||
@ParameterizedTest
|
||||
protected void quux() {}
|
||||
|
||||
@Test
|
||||
public void testToString() {}
|
||||
|
||||
@Test
|
||||
public void testOverload() {}
|
||||
|
||||
void overload() {}
|
||||
|
||||
@Test
|
||||
protected void testArguments() {}
|
||||
|
||||
@Test
|
||||
private void testClass() {}
|
||||
|
||||
@Test
|
||||
private void testTrue() {}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
|
||||
"",
|
||||
"import org.junit.jupiter.api.AfterAll;",
|
||||
"import org.junit.jupiter.api.AfterEach;",
|
||||
"import org.junit.jupiter.api.BeforeAll;",
|
||||
"import org.junit.jupiter.api.BeforeEach;",
|
||||
"import org.junit.jupiter.api.RepeatedTest;",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"",
|
||||
"class A {",
|
||||
" {",
|
||||
" arguments();",
|
||||
" }",
|
||||
"",
|
||||
" @BeforeAll",
|
||||
" void setUp1() {}",
|
||||
"",
|
||||
" @BeforeEach",
|
||||
" void setUp2() {}",
|
||||
"",
|
||||
" @AfterEach",
|
||||
" void setUp3() {}",
|
||||
"",
|
||||
" @AfterAll",
|
||||
" void setUp4() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void foo() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" void bar() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void baz() {}",
|
||||
"",
|
||||
" @RepeatedTest(2)",
|
||||
" void qux() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" void quux() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void testToString() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void testOverload() {}",
|
||||
"",
|
||||
" void overload() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void testArguments() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void testClass() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void testTrue() {}",
|
||||
"}")
|
||||
"""
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.RepeatedTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
|
||||
class A {
|
||||
{
|
||||
arguments();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
void setUp1() {}
|
||||
|
||||
@BeforeEach
|
||||
void setUp2() {}
|
||||
|
||||
@AfterEach
|
||||
void setUp3() {}
|
||||
|
||||
@AfterAll
|
||||
void setUp4() {}
|
||||
|
||||
@Test
|
||||
void foo() {}
|
||||
|
||||
@ParameterizedTest
|
||||
void bar() {}
|
||||
|
||||
@Test
|
||||
void baz() {}
|
||||
|
||||
@RepeatedTest(2)
|
||||
void qux() {}
|
||||
|
||||
@ParameterizedTest
|
||||
void quux() {}
|
||||
|
||||
@Test
|
||||
void testToString() {}
|
||||
|
||||
@Test
|
||||
void testOverload() {}
|
||||
|
||||
void overload() {}
|
||||
|
||||
@Test
|
||||
void testArguments() {}
|
||||
|
||||
@Test
|
||||
void testClass() {}
|
||||
|
||||
@Test
|
||||
void testTrue() {}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,25 +11,27 @@ final class JUnitNullaryParameterizedTestDeclarationTest {
|
||||
CompilationTestHelper.newInstance(JUnitNullaryParameterizedTestDeclaration.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"import org.junit.jupiter.params.provider.ValueSource;",
|
||||
"",
|
||||
"class A {",
|
||||
" void nonTest() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void nonParameterizedTest() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(ints = {0, 1})",
|
||||
" void goodParameterizedTest(int someInt) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(ints = {0, 1})",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" void nullaryParameterizedTest() {}",
|
||||
"}")
|
||||
"""
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
class A {
|
||||
void nonTest() {}
|
||||
|
||||
@Test
|
||||
void nonParameterizedTest() {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {0, 1})
|
||||
void goodParameterizedTest(int someInt) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {0, 1})
|
||||
// BUG: Diagnostic contains:
|
||||
void nullaryParameterizedTest() {}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -39,117 +41,125 @@ final class JUnitNullaryParameterizedTestDeclarationTest {
|
||||
JUnitNullaryParameterizedTestDeclaration.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"import org.junit.jupiter.params.provider.ArgumentsProvider;",
|
||||
"import org.junit.jupiter.params.provider.ArgumentsSource;",
|
||||
"import org.junit.jupiter.params.provider.ArgumentsSources;",
|
||||
"import org.junit.jupiter.params.provider.MethodSource;",
|
||||
"import org.junit.jupiter.params.provider.ValueSource;",
|
||||
"",
|
||||
"class A {",
|
||||
" @ParameterizedTest",
|
||||
" void withoutArgumentSource() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ArgumentsSource(ArgumentsProvider.class)",
|
||||
" void withCustomArgumentSource() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ArgumentsSources({",
|
||||
" @ArgumentsSource(ArgumentsProvider.class),",
|
||||
" @ArgumentsSource(ArgumentsProvider.class)",
|
||||
" })",
|
||||
" void withCustomerArgumentSources() {}",
|
||||
"",
|
||||
" /** Foo. */",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(ints = {0, 1})",
|
||||
" void withValueSourceAndJavadoc() {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"nonexistentMethod\")",
|
||||
" @SuppressWarnings(\"foo\")",
|
||||
" void withMethodSourceAndUnrelatedAnnotation() {}",
|
||||
"",
|
||||
" @org.junit.jupiter.params.ParameterizedTest",
|
||||
" @ArgumentsSource(ArgumentsProvider.class)",
|
||||
" @ValueSource(ints = {0, 1})",
|
||||
" @MethodSource(\"nonexistentMethod\")",
|
||||
" void withMultipleArgumentSourcesAndFullyQualifiedImport() {}",
|
||||
"",
|
||||
" class NestedWithTestAnnotationFirst {",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(ints = {0, 1})",
|
||||
" void withValueSource() {}",
|
||||
" }",
|
||||
"",
|
||||
" class NestedWithTestAnnotationSecond {",
|
||||
" @ValueSource(ints = {0, 1})",
|
||||
" @ParameterizedTest",
|
||||
" void withValueSource() {}",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ArgumentsProvider;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSources;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
class A {
|
||||
@ParameterizedTest
|
||||
void withoutArgumentSource() {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(ArgumentsProvider.class)
|
||||
void withCustomArgumentSource() {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ArgumentsSources({
|
||||
@ArgumentsSource(ArgumentsProvider.class),
|
||||
@ArgumentsSource(ArgumentsProvider.class)
|
||||
})
|
||||
void withCustomerArgumentSources() {}
|
||||
|
||||
/** Foo. */
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {0, 1})
|
||||
void withValueSourceAndJavadoc() {}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("nonexistentMethod")
|
||||
@SuppressWarnings("foo")
|
||||
void withMethodSourceAndUnrelatedAnnotation() {}
|
||||
|
||||
@org.junit.jupiter.params.ParameterizedTest
|
||||
@ArgumentsSource(ArgumentsProvider.class)
|
||||
@ValueSource(ints = {0, 1})
|
||||
@MethodSource("nonexistentMethod")
|
||||
void withMultipleArgumentSourcesAndFullyQualifiedImport() {}
|
||||
|
||||
class NestedWithTestAnnotationFirst {
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {0, 1})
|
||||
void withValueSource() {}
|
||||
}
|
||||
|
||||
class NestedWithTestAnnotationSecond {
|
||||
@ValueSource(ints = {0, 1})
|
||||
@ParameterizedTest
|
||||
void withValueSource() {}
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import org.junit.jupiter.api.Test;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"import org.junit.jupiter.params.provider.ArgumentsProvider;",
|
||||
"import org.junit.jupiter.params.provider.ArgumentsSource;",
|
||||
"import org.junit.jupiter.params.provider.ArgumentsSources;",
|
||||
"import org.junit.jupiter.params.provider.MethodSource;",
|
||||
"import org.junit.jupiter.params.provider.ValueSource;",
|
||||
"",
|
||||
"class A {",
|
||||
" @Test",
|
||||
" void withoutArgumentSource() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void withCustomArgumentSource() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void withCustomerArgumentSources() {}",
|
||||
"",
|
||||
" /** Foo. */",
|
||||
" @Test",
|
||||
" void withValueSourceAndJavadoc() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" @SuppressWarnings(\"foo\")",
|
||||
" void withMethodSourceAndUnrelatedAnnotation() {}",
|
||||
"",
|
||||
" @Test",
|
||||
" void withMultipleArgumentSourcesAndFullyQualifiedImport() {}",
|
||||
"",
|
||||
" class NestedWithTestAnnotationFirst {",
|
||||
" @Test",
|
||||
" void withValueSource() {}",
|
||||
" }",
|
||||
"",
|
||||
" class NestedWithTestAnnotationSecond {",
|
||||
" @Test",
|
||||
" void withValueSource() {}",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ArgumentsProvider;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSources;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
class A {
|
||||
@Test
|
||||
void withoutArgumentSource() {}
|
||||
|
||||
@Test
|
||||
void withCustomArgumentSource() {}
|
||||
|
||||
@Test
|
||||
void withCustomerArgumentSources() {}
|
||||
|
||||
/** Foo. */
|
||||
@Test
|
||||
void withValueSourceAndJavadoc() {}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("foo")
|
||||
void withMethodSourceAndUnrelatedAnnotation() {}
|
||||
|
||||
@Test
|
||||
void withMultipleArgumentSourcesAndFullyQualifiedImport() {}
|
||||
|
||||
class NestedWithTestAnnotationFirst {
|
||||
@Test
|
||||
void withValueSource() {}
|
||||
}
|
||||
|
||||
class NestedWithTestAnnotationSecond {
|
||||
@Test
|
||||
void withValueSource() {}
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addInputLines(
|
||||
"B.java",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"",
|
||||
"class B {",
|
||||
" @ParameterizedTest",
|
||||
" void scopeInWhichIdentifierTestIsAlreadyDeclared() {}",
|
||||
"",
|
||||
" class Test {}",
|
||||
"}")
|
||||
"""
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
|
||||
class B {
|
||||
@ParameterizedTest
|
||||
void scopeInWhichIdentifierTestIsAlreadyDeclared() {}
|
||||
|
||||
class Test {}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"B.java",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"",
|
||||
"class B {",
|
||||
" @org.junit.jupiter.api.Test",
|
||||
" void scopeInWhichIdentifierTestIsAlreadyDeclared() {}",
|
||||
"",
|
||||
" class Test {}",
|
||||
"}")
|
||||
"""
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
|
||||
class B {
|
||||
@org.junit.jupiter.api.Test
|
||||
void scopeInWhichIdentifierTestIsAlreadyDeclared() {}
|
||||
|
||||
class Test {}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,189 +11,191 @@ final class JUnitValueSourceTest {
|
||||
CompilationTestHelper.newInstance(JUnitValueSource.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
|
||||
"",
|
||||
"import java.util.Optional;",
|
||||
"import java.util.stream.Stream;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"import org.junit.jupiter.params.provider.Arguments;",
|
||||
"import org.junit.jupiter.params.provider.MethodSource;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static Stream<Arguments> identificationTestCases() {",
|
||||
" return Stream.of(arguments(1), Arguments.of(2));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @MethodSource(\"identificationTestCases\")",
|
||||
" void identification(int foo) {}",
|
||||
"",
|
||||
" private static int[] identificationWithParensTestCases() {",
|
||||
" return new int[] {1, 2};",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @MethodSource(\"identificationWithParensTestCases()\")",
|
||||
" void identificationWithParens(int foo) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"valueFactoryMissingTestCases\")",
|
||||
" void valueFactoryMissing(int foo) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> multipleUsagesTestCases() {",
|
||||
" return Stream.of(arguments(1), Arguments.of(2));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"multipleUsagesTestCases\")",
|
||||
" void multipleUsages1(int foo) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"multipleUsagesTestCases()\")",
|
||||
" void multipleUsages2(int bar) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> valueFactoryRepeatedTestCases() {",
|
||||
" return Stream.of(arguments(1), arguments(2));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource({\"valueFactoryRepeatedTestCases\", \"valueFactoryRepeatedTestCases\"})",
|
||||
" void valueFactoryRepeated(int foo) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> multipleParametersTestCases() {",
|
||||
" return Stream.of(arguments(1, 2), arguments(3, 4));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"multipleParametersTestCases\")",
|
||||
" void multipleParameters(int first, int second) {}",
|
||||
"",
|
||||
" private static int[] arrayWithoutInitializersTestCases() {",
|
||||
" return new int[1];",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"arrayWithoutInitializersTestCases\")",
|
||||
" void arrayWithoutInitializers(int foo) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> runtimeValueTestCases() {",
|
||||
" int second = 2;",
|
||||
" return Stream.of(arguments(1), arguments(second));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"runtimeValueTestCases\")",
|
||||
" void runtimeValue(int foo) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> streamChainTestCases() {",
|
||||
" return Stream.of(1, 2).map(Arguments::arguments);",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"streamChainTestCases\")",
|
||||
" void streamChain(int number) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> multipleReturnsTestCases() {",
|
||||
" if (true) {",
|
||||
" return Stream.of(arguments(1), arguments(2));",
|
||||
" } else {",
|
||||
" return Stream.of(arguments(3), arguments(4));",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"multipleReturnsTestCases\")",
|
||||
" void multipleReturns(int number) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> multipleFactoriesFooTestCases() {",
|
||||
" return Stream.of(arguments(1));",
|
||||
" }",
|
||||
"",
|
||||
" private static Stream<Arguments> multipleFactoriesBarTestCases() {",
|
||||
" return Stream.of(arguments(1));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource({\"multipleFactoriesFooTestCases\", \"multipleFactoriesBarTestCases\"})",
|
||||
" void multipleFactories(int i) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> extraArgsTestCases() {",
|
||||
" return Stream.of(arguments(1), arguments(1, 2));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"extraArgsTestCases\")",
|
||||
" void extraArgs(int... i) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> localClassTestCases() {",
|
||||
" class Foo {",
|
||||
" Stream<Arguments> foo() {",
|
||||
" return Stream.of(arguments(1), arguments(2));",
|
||||
" }",
|
||||
" }",
|
||||
" return Stream.of(arguments(1), arguments(2));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @MethodSource(\"localClassTestCases\")",
|
||||
" void localClass(int i) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> lambdaReturnTestCases() {",
|
||||
" int foo =",
|
||||
" Optional.of(10)",
|
||||
" .map(",
|
||||
" i -> {",
|
||||
" return i / 2;",
|
||||
" })",
|
||||
" .orElse(0);",
|
||||
" return Stream.of(arguments(1), arguments(1));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @MethodSource(\"lambdaReturnTestCases\")",
|
||||
" void lambdaReturn(int i) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"tech.picnic.errorprone.Foo#fooTestCases\")",
|
||||
" void staticMethodReference(int foo) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> valueFactoryWithArgumentTestCases(int amount) {",
|
||||
" return Stream.of(arguments(1), arguments(2));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @MethodSource(\"valueFactoryWithArgumentTestCases\")",
|
||||
" void valueFactoryWithArgument(int foo) {}",
|
||||
"",
|
||||
" private static Arguments[] emptyArrayValueFactoryTestCases() {",
|
||||
" return new Arguments[] {};",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"emptyArrayValueFactoryTestCases\")",
|
||||
" void emptyArrayValueFactory(int foo) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> emptyStreamValueFactoryTestCases() {",
|
||||
" return Stream.of();",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"emptyStreamValueFactoryTestCases\")",
|
||||
" void emptyStreamValueFactory(int foo) {}",
|
||||
"",
|
||||
" private static Arguments[] invalidValueFactoryArgumentsTestCases() {",
|
||||
" return new Arguments[] {arguments(1), arguments(new Object() {})};",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"invalidValueFactoryArgumentsTestCases\")",
|
||||
" void invalidValueFactoryArguments(int foo) {}",
|
||||
"}")
|
||||
"""
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
class A {
|
||||
private static Stream<Arguments> identificationTestCases() {
|
||||
return Stream.of(arguments(1), Arguments.of(2));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
// BUG: Diagnostic contains:
|
||||
@MethodSource("identificationTestCases")
|
||||
void identification(int foo) {}
|
||||
|
||||
private static int[] identificationWithParensTestCases() {
|
||||
return new int[] {1, 2};
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
// BUG: Diagnostic contains:
|
||||
@MethodSource("identificationWithParensTestCases()")
|
||||
void identificationWithParens(int foo) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("valueFactoryMissingTestCases")
|
||||
void valueFactoryMissing(int foo) {}
|
||||
|
||||
private static Stream<Arguments> multipleUsagesTestCases() {
|
||||
return Stream.of(arguments(1), Arguments.of(2));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("multipleUsagesTestCases")
|
||||
void multipleUsages1(int foo) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("multipleUsagesTestCases()")
|
||||
void multipleUsages2(int bar) {}
|
||||
|
||||
private static Stream<Arguments> valueFactoryRepeatedTestCases() {
|
||||
return Stream.of(arguments(1), arguments(2));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource({"valueFactoryRepeatedTestCases", "valueFactoryRepeatedTestCases"})
|
||||
void valueFactoryRepeated(int foo) {}
|
||||
|
||||
private static Stream<Arguments> multipleParametersTestCases() {
|
||||
return Stream.of(arguments(1, 2), arguments(3, 4));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("multipleParametersTestCases")
|
||||
void multipleParameters(int first, int second) {}
|
||||
|
||||
private static int[] arrayWithoutInitializersTestCases() {
|
||||
return new int[1];
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("arrayWithoutInitializersTestCases")
|
||||
void arrayWithoutInitializers(int foo) {}
|
||||
|
||||
private static Stream<Arguments> runtimeValueTestCases() {
|
||||
int second = 2;
|
||||
return Stream.of(arguments(1), arguments(second));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("runtimeValueTestCases")
|
||||
void runtimeValue(int foo) {}
|
||||
|
||||
private static Stream<Arguments> streamChainTestCases() {
|
||||
return Stream.of(1, 2).map(Arguments::arguments);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("streamChainTestCases")
|
||||
void streamChain(int number) {}
|
||||
|
||||
private static Stream<Arguments> multipleReturnsTestCases() {
|
||||
if (true) {
|
||||
return Stream.of(arguments(1), arguments(2));
|
||||
} else {
|
||||
return Stream.of(arguments(3), arguments(4));
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("multipleReturnsTestCases")
|
||||
void multipleReturns(int number) {}
|
||||
|
||||
private static Stream<Arguments> multipleFactoriesFooTestCases() {
|
||||
return Stream.of(arguments(1));
|
||||
}
|
||||
|
||||
private static Stream<Arguments> multipleFactoriesBarTestCases() {
|
||||
return Stream.of(arguments(1));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource({"multipleFactoriesFooTestCases", "multipleFactoriesBarTestCases"})
|
||||
void multipleFactories(int i) {}
|
||||
|
||||
private static Stream<Arguments> extraArgsTestCases() {
|
||||
return Stream.of(arguments(1), arguments(1, 2));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("extraArgsTestCases")
|
||||
void extraArgs(int... i) {}
|
||||
|
||||
private static Stream<Arguments> localClassTestCases() {
|
||||
class Foo {
|
||||
Stream<Arguments> foo() {
|
||||
return Stream.of(arguments(1), arguments(2));
|
||||
}
|
||||
}
|
||||
return Stream.of(arguments(1), arguments(2));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
// BUG: Diagnostic contains:
|
||||
@MethodSource("localClassTestCases")
|
||||
void localClass(int i) {}
|
||||
|
||||
private static Stream<Arguments> lambdaReturnTestCases() {
|
||||
int foo =
|
||||
Optional.of(10)
|
||||
.map(
|
||||
i -> {
|
||||
return i / 2;
|
||||
})
|
||||
.orElse(0);
|
||||
return Stream.of(arguments(1), arguments(1));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
// BUG: Diagnostic contains:
|
||||
@MethodSource("lambdaReturnTestCases")
|
||||
void lambdaReturn(int i) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("tech.picnic.errorprone.Foo#fooTestCases")
|
||||
void staticMethodReference(int foo) {}
|
||||
|
||||
private static Stream<Arguments> valueFactoryWithArgumentTestCases(int amount) {
|
||||
return Stream.of(arguments(1), arguments(2));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
// BUG: Diagnostic contains:
|
||||
@MethodSource("valueFactoryWithArgumentTestCases")
|
||||
void valueFactoryWithArgument(int foo) {}
|
||||
|
||||
private static Arguments[] emptyArrayValueFactoryTestCases() {
|
||||
return new Arguments[] {};
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("emptyArrayValueFactoryTestCases")
|
||||
void emptyArrayValueFactory(int foo) {}
|
||||
|
||||
private static Stream<Arguments> emptyStreamValueFactoryTestCases() {
|
||||
return Stream.of();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("emptyStreamValueFactoryTestCases")
|
||||
void emptyStreamValueFactory(int foo) {}
|
||||
|
||||
private static Arguments[] invalidValueFactoryArgumentsTestCases() {
|
||||
return new Arguments[] {arguments(1), arguments(new Object() {})};
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("invalidValueFactoryArgumentsTestCases")
|
||||
void invalidValueFactoryArguments(int foo) {}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -202,295 +204,299 @@ final class JUnitValueSourceTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(JUnitValueSource.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.util.List;",
|
||||
"import java.util.Set;",
|
||||
"import java.util.stream.DoubleStream;",
|
||||
"import java.util.stream.IntStream;",
|
||||
"import java.util.stream.LongStream;",
|
||||
"import java.util.stream.Stream;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"import org.junit.jupiter.params.provider.Arguments;",
|
||||
"import org.junit.jupiter.params.provider.MethodSource;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final boolean CONST_BOOLEAN = false;",
|
||||
" private static final byte CONST_BYTE = 42;",
|
||||
" private static final char CONST_CHARACTER = 'a';",
|
||||
" private static final short CONST_SHORT = 42;",
|
||||
" private static final int CONST_INTEGER = 42;",
|
||||
" private static final long CONST_LONG = 42;",
|
||||
" private static final float CONST_FLOAT = 42;",
|
||||
" private static final double CONST_DOUBLE = 42;",
|
||||
" private static final String CONST_STRING = \"foo\";",
|
||||
"",
|
||||
" private static Stream<Arguments> streamOfBooleanArguments() {",
|
||||
" return Stream.of(arguments(false), arguments(true), arguments(CONST_BOOLEAN));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"streamOfBooleanArguments\")",
|
||||
" void primitiveBoolean(boolean b) {}",
|
||||
"",
|
||||
" private static Stream<Object> streamOfBooleansAndBooleanArguments() {",
|
||||
" return Stream.of(false, arguments(true), CONST_BOOLEAN);",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"streamOfBooleansAndBooleanArguments\")",
|
||||
" void boxedBoolean(Boolean b) {}",
|
||||
"",
|
||||
" private static List<Arguments> listOfByteArguments() {",
|
||||
" return List.of(arguments((byte) 0), arguments((byte) 1), arguments(CONST_BYTE));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"listOfByteArguments\")",
|
||||
" void primitiveByte(byte b) {}",
|
||||
"",
|
||||
" private static List<Object> listOfBytesAndByteArguments() {",
|
||||
" return List.of((byte) 0, arguments((byte) 1), CONST_BYTE);",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"listOfBytesAndByteArguments\")",
|
||||
" void boxedByte(Byte b) {}",
|
||||
"",
|
||||
" private static Set<Arguments> setOfCharacterArguments() {",
|
||||
" return Set.of(arguments((char) 0), arguments((char) 1), arguments(CONST_CHARACTER));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"setOfCharacterArguments\")",
|
||||
" void primitiveCharacter(char c) {}",
|
||||
"",
|
||||
" private static Set<Object> setOfCharactersAndCharacterArguments() {",
|
||||
" return Set.of((char) 0, arguments((char) 1), CONST_CHARACTER);",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"setOfCharactersAndCharacterArguments\")",
|
||||
" void boxedCharacter(Character c) {}",
|
||||
"",
|
||||
" private static Arguments[] arrayOfShortArguments() {",
|
||||
" return new Arguments[] {arguments((short) 0), arguments((short) 1), arguments(CONST_SHORT)};",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"arrayOfShortArguments\")",
|
||||
" void primitiveShort(short s) {}",
|
||||
"",
|
||||
" private static Object[] arrayOfShortsAndShortArguments() {",
|
||||
" return new Object[] {(short) 0, arguments((short) 1), CONST_SHORT};",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"arrayOfShortsAndShortArguments\")",
|
||||
" void boxedShort(Short s) {}",
|
||||
"",
|
||||
" private static IntStream intStream() {",
|
||||
" return IntStream.of(0, 1, CONST_INTEGER);",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"intStream\")",
|
||||
" void primitiveInteger(int i) {}",
|
||||
"",
|
||||
" private static int[] intArray() {",
|
||||
" return new int[] {0, 1, CONST_INTEGER};",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"intArray\")",
|
||||
" void boxedInteger(Integer i) {}",
|
||||
"",
|
||||
" private static LongStream longStream() {",
|
||||
" return LongStream.of(0, 1, CONST_LONG);",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"longStream\")",
|
||||
" void primitiveLong(long l) {}",
|
||||
"",
|
||||
" private static long[] longArray() {",
|
||||
" return new long[] {0, 1, CONST_LONG};",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"longArray\")",
|
||||
" void boxedLong(Long l) {}",
|
||||
"",
|
||||
" private static ImmutableList<Arguments> immutableListOfFloatArguments() {",
|
||||
" return ImmutableList.of(arguments(0.0F), arguments(1.0F), arguments(CONST_FLOAT));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"immutableListOfFloatArguments\")",
|
||||
" void primitiveFloat(float f) {}",
|
||||
"",
|
||||
" private static Stream<Object> streamOfFloatsAndFloatArguments() {",
|
||||
" return Stream.of(0.0F, arguments(1.0F), CONST_FLOAT);",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"streamOfFloatsAndFloatArguments\")",
|
||||
" void boxedFloat(Float f) {}",
|
||||
"",
|
||||
" private static DoubleStream doubleStream() {",
|
||||
" return DoubleStream.of(0, 1, CONST_DOUBLE);",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"doubleStream\")",
|
||||
" void primitiveDouble(double d) {}",
|
||||
"",
|
||||
" private static double[] doubleArray() {",
|
||||
" return new double[] {0, 1, CONST_DOUBLE};",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"doubleArray\")",
|
||||
" void boxedDouble(Double d) {}",
|
||||
"",
|
||||
" private static ImmutableSet<Arguments> immutableSetOfStringArguments() {",
|
||||
" return ImmutableSet.of(arguments(\"foo\"), arguments(\"bar\"), arguments(CONST_STRING));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"immutableSetOfStringArguments\")",
|
||||
" void string(String s) {}",
|
||||
"",
|
||||
" private static Stream<Class<?>> streamOfClasses() {",
|
||||
" return Stream.of(Stream.class, java.util.Map.class);",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"streamOfClasses\")",
|
||||
" void clazz(Class<?> c) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> sameNameFactoryTestCases() {",
|
||||
" return Stream.of(arguments(1));",
|
||||
" }",
|
||||
"",
|
||||
" private static Stream<Arguments> sameNameFactoryTestCases(int overload) {",
|
||||
" return Stream.of(arguments(overload));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @MethodSource(\"sameNameFactoryTestCases\")",
|
||||
" void sameNameFactory(int i) {}",
|
||||
"}")
|
||||
"""
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.DoubleStream;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.LongStream;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
class A {
|
||||
private static final boolean CONST_BOOLEAN = false;
|
||||
private static final byte CONST_BYTE = 42;
|
||||
private static final char CONST_CHARACTER = 'a';
|
||||
private static final short CONST_SHORT = 42;
|
||||
private static final int CONST_INTEGER = 42;
|
||||
private static final long CONST_LONG = 42;
|
||||
private static final float CONST_FLOAT = 42;
|
||||
private static final double CONST_DOUBLE = 42;
|
||||
private static final String CONST_STRING = "foo";
|
||||
|
||||
private static Stream<Arguments> streamOfBooleanArguments() {
|
||||
return Stream.of(arguments(false), arguments(true), arguments(CONST_BOOLEAN));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("streamOfBooleanArguments")
|
||||
void primitiveBoolean(boolean b) {}
|
||||
|
||||
private static Stream<Object> streamOfBooleansAndBooleanArguments() {
|
||||
return Stream.of(false, arguments(true), CONST_BOOLEAN);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("streamOfBooleansAndBooleanArguments")
|
||||
void boxedBoolean(Boolean b) {}
|
||||
|
||||
private static List<Arguments> listOfByteArguments() {
|
||||
return List.of(arguments((byte) 0), arguments((byte) 1), arguments(CONST_BYTE));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("listOfByteArguments")
|
||||
void primitiveByte(byte b) {}
|
||||
|
||||
private static List<Object> listOfBytesAndByteArguments() {
|
||||
return List.of((byte) 0, arguments((byte) 1), CONST_BYTE);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("listOfBytesAndByteArguments")
|
||||
void boxedByte(Byte b) {}
|
||||
|
||||
private static Set<Arguments> setOfCharacterArguments() {
|
||||
return Set.of(arguments((char) 0), arguments((char) 1), arguments(CONST_CHARACTER));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("setOfCharacterArguments")
|
||||
void primitiveCharacter(char c) {}
|
||||
|
||||
private static Set<Object> setOfCharactersAndCharacterArguments() {
|
||||
return Set.of((char) 0, arguments((char) 1), CONST_CHARACTER);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("setOfCharactersAndCharacterArguments")
|
||||
void boxedCharacter(Character c) {}
|
||||
|
||||
private static Arguments[] arrayOfShortArguments() {
|
||||
return new Arguments[] {arguments((short) 0), arguments((short) 1), arguments(CONST_SHORT)};
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("arrayOfShortArguments")
|
||||
void primitiveShort(short s) {}
|
||||
|
||||
private static Object[] arrayOfShortsAndShortArguments() {
|
||||
return new Object[] {(short) 0, arguments((short) 1), CONST_SHORT};
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("arrayOfShortsAndShortArguments")
|
||||
void boxedShort(Short s) {}
|
||||
|
||||
private static IntStream intStream() {
|
||||
return IntStream.of(0, 1, CONST_INTEGER);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("intStream")
|
||||
void primitiveInteger(int i) {}
|
||||
|
||||
private static int[] intArray() {
|
||||
return new int[] {0, 1, CONST_INTEGER};
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("intArray")
|
||||
void boxedInteger(Integer i) {}
|
||||
|
||||
private static LongStream longStream() {
|
||||
return LongStream.of(0, 1, CONST_LONG);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("longStream")
|
||||
void primitiveLong(long l) {}
|
||||
|
||||
private static long[] longArray() {
|
||||
return new long[] {0, 1, CONST_LONG};
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("longArray")
|
||||
void boxedLong(Long l) {}
|
||||
|
||||
private static ImmutableList<Arguments> immutableListOfFloatArguments() {
|
||||
return ImmutableList.of(arguments(0.0F), arguments(1.0F), arguments(CONST_FLOAT));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("immutableListOfFloatArguments")
|
||||
void primitiveFloat(float f) {}
|
||||
|
||||
private static Stream<Object> streamOfFloatsAndFloatArguments() {
|
||||
return Stream.of(0.0F, arguments(1.0F), CONST_FLOAT);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("streamOfFloatsAndFloatArguments")
|
||||
void boxedFloat(Float f) {}
|
||||
|
||||
private static DoubleStream doubleStream() {
|
||||
return DoubleStream.of(0, 1, CONST_DOUBLE);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("doubleStream")
|
||||
void primitiveDouble(double d) {}
|
||||
|
||||
private static double[] doubleArray() {
|
||||
return new double[] {0, 1, CONST_DOUBLE};
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("doubleArray")
|
||||
void boxedDouble(Double d) {}
|
||||
|
||||
private static ImmutableSet<Arguments> immutableSetOfStringArguments() {
|
||||
return ImmutableSet.of(arguments("foo"), arguments("bar"), arguments(CONST_STRING));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("immutableSetOfStringArguments")
|
||||
void string(String s) {}
|
||||
|
||||
private static Stream<Class<?>> streamOfClasses() {
|
||||
return Stream.of(Stream.class, java.util.Map.class);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("streamOfClasses")
|
||||
void clazz(Class<?> c) {}
|
||||
|
||||
private static Stream<Arguments> sameNameFactoryTestCases() {
|
||||
return Stream.of(arguments(1));
|
||||
}
|
||||
|
||||
private static Stream<Arguments> sameNameFactoryTestCases(int overload) {
|
||||
return Stream.of(arguments(overload));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("sameNameFactoryTestCases")
|
||||
void sameNameFactory(int i) {}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static org.junit.jupiter.params.provider.Arguments.arguments;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.util.List;",
|
||||
"import java.util.Set;",
|
||||
"import java.util.stream.DoubleStream;",
|
||||
"import java.util.stream.IntStream;",
|
||||
"import java.util.stream.LongStream;",
|
||||
"import java.util.stream.Stream;",
|
||||
"import org.junit.jupiter.params.ParameterizedTest;",
|
||||
"import org.junit.jupiter.params.provider.Arguments;",
|
||||
"import org.junit.jupiter.params.provider.MethodSource;",
|
||||
"import org.junit.jupiter.params.provider.ValueSource;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final boolean CONST_BOOLEAN = false;",
|
||||
" private static final byte CONST_BYTE = 42;",
|
||||
" private static final char CONST_CHARACTER = 'a';",
|
||||
" private static final short CONST_SHORT = 42;",
|
||||
" private static final int CONST_INTEGER = 42;",
|
||||
" private static final long CONST_LONG = 42;",
|
||||
" private static final float CONST_FLOAT = 42;",
|
||||
" private static final double CONST_DOUBLE = 42;",
|
||||
" private static final String CONST_STRING = \"foo\";",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(booleans = {false, true, CONST_BOOLEAN})",
|
||||
" void primitiveBoolean(boolean b) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(booleans = {false, true, CONST_BOOLEAN})",
|
||||
" void boxedBoolean(Boolean b) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(bytes = {(byte) 0, (byte) 1, CONST_BYTE})",
|
||||
" void primitiveByte(byte b) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(bytes = {(byte) 0, (byte) 1, CONST_BYTE})",
|
||||
" void boxedByte(Byte b) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(chars = {(char) 0, (char) 1, CONST_CHARACTER})",
|
||||
" void primitiveCharacter(char c) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(chars = {(char) 0, (char) 1, CONST_CHARACTER})",
|
||||
" void boxedCharacter(Character c) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(shorts = {(short) 0, (short) 1, CONST_SHORT})",
|
||||
" void primitiveShort(short s) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(shorts = {(short) 0, (short) 1, CONST_SHORT})",
|
||||
" void boxedShort(Short s) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(ints = {0, 1, CONST_INTEGER})",
|
||||
" void primitiveInteger(int i) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(ints = {0, 1, CONST_INTEGER})",
|
||||
" void boxedInteger(Integer i) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(longs = {0, 1, CONST_LONG})",
|
||||
" void primitiveLong(long l) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(longs = {0, 1, CONST_LONG})",
|
||||
" void boxedLong(Long l) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(floats = {0.0F, 1.0F, CONST_FLOAT})",
|
||||
" void primitiveFloat(float f) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(floats = {0.0F, 1.0F, CONST_FLOAT})",
|
||||
" void boxedFloat(Float f) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(doubles = {0, 1, CONST_DOUBLE})",
|
||||
" void primitiveDouble(double d) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(doubles = {0, 1, CONST_DOUBLE})",
|
||||
" void boxedDouble(Double d) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(strings = {\"foo\", \"bar\", CONST_STRING})",
|
||||
" void string(String s) {}",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(classes = {Stream.class, java.util.Map.class})",
|
||||
" void clazz(Class<?> c) {}",
|
||||
"",
|
||||
" private static Stream<Arguments> sameNameFactoryTestCases(int overload) {",
|
||||
" return Stream.of(arguments(overload));",
|
||||
" }",
|
||||
"",
|
||||
" @ParameterizedTest",
|
||||
" @ValueSource(ints = 1)",
|
||||
" void sameNameFactory(int i) {}",
|
||||
"}")
|
||||
"""
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.DoubleStream;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.LongStream;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
class A {
|
||||
private static final boolean CONST_BOOLEAN = false;
|
||||
private static final byte CONST_BYTE = 42;
|
||||
private static final char CONST_CHARACTER = 'a';
|
||||
private static final short CONST_SHORT = 42;
|
||||
private static final int CONST_INTEGER = 42;
|
||||
private static final long CONST_LONG = 42;
|
||||
private static final float CONST_FLOAT = 42;
|
||||
private static final double CONST_DOUBLE = 42;
|
||||
private static final String CONST_STRING = "foo";
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {false, true, CONST_BOOLEAN})
|
||||
void primitiveBoolean(boolean b) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = {false, true, CONST_BOOLEAN})
|
||||
void boxedBoolean(Boolean b) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(bytes = {(byte) 0, (byte) 1, CONST_BYTE})
|
||||
void primitiveByte(byte b) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(bytes = {(byte) 0, (byte) 1, CONST_BYTE})
|
||||
void boxedByte(Byte b) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(chars = {(char) 0, (char) 1, CONST_CHARACTER})
|
||||
void primitiveCharacter(char c) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(chars = {(char) 0, (char) 1, CONST_CHARACTER})
|
||||
void boxedCharacter(Character c) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(shorts = {(short) 0, (short) 1, CONST_SHORT})
|
||||
void primitiveShort(short s) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(shorts = {(short) 0, (short) 1, CONST_SHORT})
|
||||
void boxedShort(Short s) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {0, 1, CONST_INTEGER})
|
||||
void primitiveInteger(int i) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {0, 1, CONST_INTEGER})
|
||||
void boxedInteger(Integer i) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(longs = {0, 1, CONST_LONG})
|
||||
void primitiveLong(long l) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(longs = {0, 1, CONST_LONG})
|
||||
void boxedLong(Long l) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(floats = {0.0F, 1.0F, CONST_FLOAT})
|
||||
void primitiveFloat(float f) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(floats = {0.0F, 1.0F, CONST_FLOAT})
|
||||
void boxedFloat(Float f) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(doubles = {0, 1, CONST_DOUBLE})
|
||||
void primitiveDouble(double d) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(doubles = {0, 1, CONST_DOUBLE})
|
||||
void boxedDouble(Double d) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"foo", "bar", CONST_STRING})
|
||||
void string(String s) {}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(classes = {Stream.class, java.util.Map.class})
|
||||
void clazz(Class<?> c) {}
|
||||
|
||||
private static Stream<Arguments> sameNameFactoryTestCases(int overload) {
|
||||
return Stream.of(arguments(overload));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = 1)
|
||||
void sameNameFactory(int i) {}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
@@ -12,146 +11,178 @@ final class LexicographicalAnnotationAttributeListingTest {
|
||||
CompilationTestHelper.newInstance(LexicographicalAnnotationAttributeListing.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static java.math.RoundingMode.DOWN;",
|
||||
"import static java.math.RoundingMode.UP;",
|
||||
"",
|
||||
"import com.fasterxml.jackson.annotation.JsonPropertyOrder;",
|
||||
"import io.swagger.annotations.ApiImplicitParam;",
|
||||
"import io.swagger.annotations.ApiImplicitParams;",
|
||||
"import io.swagger.v3.oas.annotations.Parameter;",
|
||||
"import io.swagger.v3.oas.annotations.Parameters;",
|
||||
"import java.math.RoundingMode;",
|
||||
"import javax.xml.bind.annotation.XmlType;",
|
||||
"import org.springframework.context.annotation.PropertySource;",
|
||||
"import org.springframework.test.context.TestPropertySource;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @interface Foo {",
|
||||
" String[] value() default {};",
|
||||
"",
|
||||
" int[] ints() default {};",
|
||||
"",
|
||||
" Class<?>[] cls() default {};",
|
||||
"",
|
||||
" RoundingMode[] enums() default {};",
|
||||
"",
|
||||
" Bar[] anns() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @interface Bar {",
|
||||
" String[] value() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @Foo({})",
|
||||
" A noString();",
|
||||
"",
|
||||
" @Foo({\"a\"})",
|
||||
" A oneString();",
|
||||
"",
|
||||
" @Foo({\"a\", \"b\"})",
|
||||
" A sortedStrings();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo({\"b\", \"a\"})",
|
||||
" A unsortedString();",
|
||||
"",
|
||||
" @Foo({\"ab\", \"Ac\"})",
|
||||
" A sortedStringCaseInsensitive();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo({\"ac\", \"Ab\"})",
|
||||
" A unsortedStringCaseInsensitive();",
|
||||
"",
|
||||
" @Foo({\"A\", \"a\"})",
|
||||
" A sortedStringCaseInsensitiveWithTotalOrderFallback();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo({\"a\", \"A\"})",
|
||||
" A unsortedStringCaseInsensitiveWithTotalOrderFallback();",
|
||||
"",
|
||||
" @Foo(ints = {})",
|
||||
" A noInts();",
|
||||
"",
|
||||
" @Foo(ints = {0})",
|
||||
" A oneInt();",
|
||||
"",
|
||||
" @Foo(ints = {0, 1})",
|
||||
" A sortedInts();",
|
||||
"",
|
||||
" @Foo(ints = {1, 0})",
|
||||
" A unsortedInts();",
|
||||
"",
|
||||
" @Foo(cls = {})",
|
||||
" A noClasses();",
|
||||
"",
|
||||
" @Foo(cls = {int.class})",
|
||||
" A oneClass();",
|
||||
"",
|
||||
" @Foo(cls = {int.class, long.class})",
|
||||
" A sortedClasses();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo(cls = {long.class, int.class})",
|
||||
" A unsortedClasses();",
|
||||
"",
|
||||
" @Foo(enums = {})",
|
||||
" A noEnums();",
|
||||
"",
|
||||
" @Foo(enums = {DOWN})",
|
||||
" A oneEnum();",
|
||||
"",
|
||||
" @Foo(enums = {DOWN, UP})",
|
||||
" A sortedEnums();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo(enums = {UP, DOWN})",
|
||||
" A unsortedEnums();",
|
||||
"",
|
||||
" @Foo(anns = {})",
|
||||
" A noAnns();",
|
||||
"",
|
||||
" @Foo(anns = {@Bar(\"a\")})",
|
||||
" A oneAnn();",
|
||||
"",
|
||||
" @Foo(anns = {@Bar(\"a\"), @Bar(\"b\")})",
|
||||
" A sortedAnns();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
|
||||
" A unsortedAnns();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo(anns = {@Bar(\"a\"), @Bar({\"b\", \"a\"})})",
|
||||
" A unsortedInnderAnns();",
|
||||
"",
|
||||
" @Foo({\"a=foo\", \"a.b=bar\", \"a.c=baz\"})",
|
||||
" A hierarchicallySorted();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo({\"a.b=bar\", \"a.c=baz\", \"a=foo\"})",
|
||||
" A hierarchicallyUnsorted();",
|
||||
"",
|
||||
" @JsonPropertyOrder({\"field2\", \"field1\"})",
|
||||
" A dto();",
|
||||
"",
|
||||
" @ApiImplicitParams({@ApiImplicitParam(\"p2\"), @ApiImplicitParam(\"p1\")})",
|
||||
" A firstEndpoint();",
|
||||
"",
|
||||
" @Parameters({@Parameter(name = \"p2\"), @Parameter(name = \"p1\")})",
|
||||
" A secondEndpoint();",
|
||||
"",
|
||||
" @XmlType(propOrder = {\"field2\", \"field1\"})",
|
||||
" class XmlTypeDummy {}",
|
||||
"",
|
||||
" @PropertySource({\"field2\", \"field1\"})",
|
||||
" class PropertySourceDummy {}",
|
||||
"",
|
||||
" @TestPropertySource(locations = {\"field2\", \"field1\"})",
|
||||
" class FirstTestPropertySourceDummy {}",
|
||||
"",
|
||||
" @TestPropertySource({\"field2\", \"field1\"})",
|
||||
" class SecondTestPropertySourceDummy {}",
|
||||
"}")
|
||||
"""
|
||||
import static java.math.RoundingMode.DOWN;
|
||||
import static java.math.RoundingMode.UP;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import java.math.RoundingMode;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
interface A {
|
||||
@interface Foo {
|
||||
String[] value() default {};
|
||||
|
||||
boolean[] bools() default {};
|
||||
|
||||
char[] chars() default {};
|
||||
|
||||
int[] ints() default {};
|
||||
|
||||
Class<?>[] cls() default {};
|
||||
|
||||
RoundingMode[] enums() default {};
|
||||
|
||||
Bar[] anns() default {};
|
||||
}
|
||||
|
||||
@interface Bar {
|
||||
String[] value() default {};
|
||||
}
|
||||
|
||||
@Foo({})
|
||||
A noString();
|
||||
|
||||
@Foo({"a"})
|
||||
A oneString();
|
||||
|
||||
@Foo({"a", "b"})
|
||||
A sortedStrings();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo({"b", "a"})
|
||||
A unsortedString();
|
||||
|
||||
@Foo({"ab", "Ac"})
|
||||
A sortedStringCaseInsensitive();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo({"ac", "Ab"})
|
||||
A unsortedStringCaseInsensitive();
|
||||
|
||||
@Foo({"A", "a"})
|
||||
A sortedStringCaseInsensitiveWithTotalOrderFallback();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo({"a", "A"})
|
||||
A unsortedStringCaseInsensitiveWithTotalOrderFallback();
|
||||
|
||||
@Foo(bools = {})
|
||||
A noBools();
|
||||
|
||||
@Foo(bools = {false})
|
||||
A oneBool();
|
||||
|
||||
@Foo(bools = {false, true})
|
||||
A sortedBools();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo(bools = {true, false})
|
||||
A unsortedBools();
|
||||
|
||||
@Foo(chars = {})
|
||||
A noChars();
|
||||
|
||||
@Foo(chars = {'a'})
|
||||
A oneChar();
|
||||
|
||||
@Foo(chars = {'a', 'b'})
|
||||
A sortedChars();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo(chars = {'b', 'a'})
|
||||
A unsortedChars();
|
||||
|
||||
@Foo(ints = {})
|
||||
A noInts();
|
||||
|
||||
@Foo(ints = {0})
|
||||
A oneInt();
|
||||
|
||||
@Foo(ints = {0, 1})
|
||||
A sortedInts();
|
||||
|
||||
@Foo(ints = {1, 0})
|
||||
A unsortedInts();
|
||||
|
||||
@Foo(cls = {})
|
||||
A noClasses();
|
||||
|
||||
@Foo(cls = {int.class})
|
||||
A oneClass();
|
||||
|
||||
@Foo(cls = {int.class, long.class})
|
||||
A sortedClasses();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo(cls = {long.class, int.class})
|
||||
A unsortedClasses();
|
||||
|
||||
@Foo(enums = {})
|
||||
A noEnums();
|
||||
|
||||
@Foo(enums = {DOWN})
|
||||
A oneEnum();
|
||||
|
||||
@Foo(enums = {DOWN, UP})
|
||||
A sortedEnums();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo(enums = {UP, DOWN})
|
||||
A unsortedEnums();
|
||||
|
||||
@Foo(anns = {})
|
||||
A noAnns();
|
||||
|
||||
@Foo(anns = {@Bar("a")})
|
||||
A oneAnn();
|
||||
|
||||
@Foo(anns = {@Bar("a"), @Bar("b")})
|
||||
A sortedAnns();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo(anns = {@Bar("b"), @Bar("a")})
|
||||
A unsortedAnns();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo(anns = {@Bar("a"), @Bar({"b", "a"})})
|
||||
A unsortedInnderAnns();
|
||||
|
||||
@Foo({"a=foo", "a.b=bar", "a.c=baz"})
|
||||
A hierarchicallySorted();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo({"a.b=bar", "a.c=baz", "a=foo"})
|
||||
A hierarchicallyUnsorted();
|
||||
|
||||
@JsonPropertyOrder({"field2", "field1"})
|
||||
A dto();
|
||||
|
||||
@ApiImplicitParams({@ApiImplicitParam("p2"), @ApiImplicitParam("p1")})
|
||||
A firstEndpoint();
|
||||
|
||||
@Parameters({@Parameter(name = "p2"), @Parameter(name = "p1")})
|
||||
A secondEndpoint();
|
||||
|
||||
@XmlType(propOrder = {"field2", "field1"})
|
||||
class XmlTypeDummy {}
|
||||
|
||||
@PropertySource({"field2", "field1"})
|
||||
class PropertySourceDummy {}
|
||||
|
||||
@TestPropertySource(locations = {"field2", "field1"})
|
||||
class FirstTestPropertySourceDummy {}
|
||||
|
||||
@TestPropertySource({"field2", "field1"})
|
||||
class SecondTestPropertySourceDummy {}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -164,78 +195,102 @@ final class LexicographicalAnnotationAttributeListingTest {
|
||||
LexicographicalAnnotationAttributeListing.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static java.math.RoundingMode.DOWN;",
|
||||
"import static java.math.RoundingMode.UP;",
|
||||
"",
|
||||
"import java.math.RoundingMode;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @interface Foo {",
|
||||
" String[] value() default {};",
|
||||
"",
|
||||
" Class<?>[] cls() default {};",
|
||||
"",
|
||||
" RoundingMode[] enums() default {};",
|
||||
"",
|
||||
" Bar[] anns() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @interface Bar {",
|
||||
" String[] value() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @Foo({\" \", \"\", \"b\", \"a\"})",
|
||||
" A unsortedString();",
|
||||
"",
|
||||
" @Foo(cls = {long.class, int.class})",
|
||||
" A unsortedClasses();",
|
||||
"",
|
||||
" @Foo(enums = {UP, DOWN})",
|
||||
" A unsortedEnums();",
|
||||
"",
|
||||
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
|
||||
" A unsortedAnns();",
|
||||
"",
|
||||
" @Foo(anns = {@Bar(\"a\"), @Bar({\"b\", \"a\"})})",
|
||||
" A unsortedInnderAnns();",
|
||||
"}")
|
||||
"""
|
||||
import static java.math.RoundingMode.DOWN;
|
||||
import static java.math.RoundingMode.UP;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
|
||||
interface A {
|
||||
@interface Foo {
|
||||
String[] value() default {};
|
||||
|
||||
boolean[] bools() default {};
|
||||
|
||||
char[] chars() default {};
|
||||
|
||||
Class<?>[] cls() default {};
|
||||
|
||||
RoundingMode[] enums() default {};
|
||||
|
||||
Bar[] anns() default {};
|
||||
}
|
||||
|
||||
@interface Bar {
|
||||
String[] value() default {};
|
||||
}
|
||||
|
||||
@Foo({" ", "", "b", "a"})
|
||||
A unsortedStrings();
|
||||
|
||||
@Foo(bools = {true, false})
|
||||
A unsortedBooleans();
|
||||
|
||||
@Foo(chars = {'b', 'a'})
|
||||
A unsortedChars();
|
||||
|
||||
@Foo(cls = {long.class, int.class})
|
||||
A unsortedClasses();
|
||||
|
||||
@Foo(enums = {UP, DOWN})
|
||||
A unsortedEnums();
|
||||
|
||||
@Foo(anns = {@Bar("b"), @Bar("a")})
|
||||
A unsortedAnns();
|
||||
|
||||
@Foo(anns = {@Bar("a"), @Bar({"b", "a"})})
|
||||
A unsortedInnderAnns();
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static java.math.RoundingMode.DOWN;",
|
||||
"import static java.math.RoundingMode.UP;",
|
||||
"",
|
||||
"import java.math.RoundingMode;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @interface Foo {",
|
||||
" String[] value() default {};",
|
||||
"",
|
||||
" Class<?>[] cls() default {};",
|
||||
"",
|
||||
" RoundingMode[] enums() default {};",
|
||||
"",
|
||||
" Bar[] anns() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @interface Bar {",
|
||||
" String[] value() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @Foo({\"\", \" \", \"a\", \"b\"})",
|
||||
" A unsortedString();",
|
||||
"",
|
||||
" @Foo(cls = {int.class, long.class})",
|
||||
" A unsortedClasses();",
|
||||
"",
|
||||
" @Foo(enums = {DOWN, UP})",
|
||||
" A unsortedEnums();",
|
||||
"",
|
||||
" @Foo(anns = {@Bar(\"a\"), @Bar(\"b\")})",
|
||||
" A unsortedAnns();",
|
||||
"",
|
||||
" @Foo(anns = {@Bar(\"a\"), @Bar({\"a\", \"b\"})})",
|
||||
" A unsortedInnderAnns();",
|
||||
"}")
|
||||
"""
|
||||
import static java.math.RoundingMode.DOWN;
|
||||
import static java.math.RoundingMode.UP;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
|
||||
interface A {
|
||||
@interface Foo {
|
||||
String[] value() default {};
|
||||
|
||||
boolean[] bools() default {};
|
||||
|
||||
char[] chars() default {};
|
||||
|
||||
Class<?>[] cls() default {};
|
||||
|
||||
RoundingMode[] enums() default {};
|
||||
|
||||
Bar[] anns() default {};
|
||||
}
|
||||
|
||||
@interface Bar {
|
||||
String[] value() default {};
|
||||
}
|
||||
|
||||
@Foo({"", " ", "a", "b"})
|
||||
A unsortedStrings();
|
||||
|
||||
@Foo(bools = {false, true})
|
||||
A unsortedBooleans();
|
||||
|
||||
@Foo(chars = {'a', 'b'})
|
||||
A unsortedChars();
|
||||
|
||||
@Foo(cls = {int.class, long.class})
|
||||
A unsortedClasses();
|
||||
|
||||
@Foo(enums = {DOWN, UP})
|
||||
A unsortedEnums();
|
||||
|
||||
@Foo(anns = {@Bar("a"), @Bar("b")})
|
||||
A unsortedAnns();
|
||||
|
||||
@Foo(anns = {@Bar("a"), @Bar({"a", "b"})})
|
||||
A unsortedInnderAnns();
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
|
||||
@@ -244,53 +299,54 @@ final class LexicographicalAnnotationAttributeListingTest {
|
||||
/* Some violations are not flagged because they are not in- or excluded. */
|
||||
CompilationTestHelper.newInstance(LexicographicalAnnotationAttributeListing.class, getClass())
|
||||
.setArgs(
|
||||
ImmutableList.of(
|
||||
"-XepOpt:LexicographicalAnnotationAttributeListing:Includes=pkg.A.Foo,pkg.A.Bar",
|
||||
"-XepOpt:LexicographicalAnnotationAttributeListing:Excludes=pkg.A.Bar#value"))
|
||||
"-XepOpt:LexicographicalAnnotationAttributeListing:Includes=pkg.A.Foo,pkg.A.Bar",
|
||||
"-XepOpt:LexicographicalAnnotationAttributeListing:Excludes=pkg.A.Bar#value")
|
||||
.addSourceLines(
|
||||
"pkg/A.java",
|
||||
"package pkg;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @interface Foo {",
|
||||
" String[] value() default {};",
|
||||
"",
|
||||
" String[] value2() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @interface Bar {",
|
||||
" String[] value() default {};",
|
||||
"",
|
||||
" String[] value2() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @interface Baz {",
|
||||
" String[] value() default {};",
|
||||
"",
|
||||
" String[] value2() default {};",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo({\"b\", \"a\"})",
|
||||
" A fooValue();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo(value2 = {\"b\", \"a\"})",
|
||||
" A fooValue2();",
|
||||
"",
|
||||
" @Bar({\"b\", \"a\"})",
|
||||
" A barValue();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Bar(value2 = {\"b\", \"a\"})",
|
||||
" A barValue2();",
|
||||
"",
|
||||
" @Baz({\"b\", \"a\"})",
|
||||
" A bazValue();",
|
||||
"",
|
||||
" @Baz(value2 = {\"b\", \"a\"})",
|
||||
" A bazValue2();",
|
||||
"}")
|
||||
"""
|
||||
package pkg;
|
||||
|
||||
interface A {
|
||||
@interface Foo {
|
||||
String[] value() default {};
|
||||
|
||||
String[] value2() default {};
|
||||
}
|
||||
|
||||
@interface Bar {
|
||||
String[] value() default {};
|
||||
|
||||
String[] value2() default {};
|
||||
}
|
||||
|
||||
@interface Baz {
|
||||
String[] value() default {};
|
||||
|
||||
String[] value2() default {};
|
||||
}
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo({"b", "a"})
|
||||
A fooValue();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo(value2 = {"b", "a"})
|
||||
A fooValue2();
|
||||
|
||||
@Bar({"b", "a"})
|
||||
A barValue();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Bar(value2 = {"b", "a"})
|
||||
A barValue2();
|
||||
|
||||
@Baz({"b", "a"})
|
||||
A bazValue();
|
||||
|
||||
@Baz(value2 = {"b", "a"})
|
||||
A bazValue2();
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,122 +11,124 @@ final class LexicographicalAnnotationListingTest {
|
||||
CompilationTestHelper.newInstance(LexicographicalAnnotationListing.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.lang.annotation.ElementType;",
|
||||
"import java.lang.annotation.Repeatable;",
|
||||
"import java.lang.annotation.Target;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @Repeatable(Foos.class)",
|
||||
" @interface Foo {",
|
||||
" String[] value() default {};",
|
||||
"",
|
||||
" int[] ints() default {};",
|
||||
"",
|
||||
" Bar[] anns() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @Target(ElementType.METHOD)",
|
||||
" @interface Bar {",
|
||||
" String[] value() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @interface Baz {",
|
||||
" String[] str() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @interface Foos {",
|
||||
" Foo[] value();",
|
||||
" }",
|
||||
"",
|
||||
" @Target(ElementType.TYPE_USE)",
|
||||
" @interface FooTypeUse {",
|
||||
" String[] value() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @Target(ElementType.TYPE_USE)",
|
||||
" @interface BarTypeUse {",
|
||||
" String[] value() default {};",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo",
|
||||
" @Bar",
|
||||
" A unsortedSimpleCase();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo()",
|
||||
" @Bar()",
|
||||
" A unsortedWithParens();",
|
||||
"",
|
||||
" @Foo()",
|
||||
" A onlyOneAnnotation();",
|
||||
"",
|
||||
" @Bar",
|
||||
" @Foo()",
|
||||
" A sortedAnnotationsOneWithParens();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo",
|
||||
" @Baz",
|
||||
" @Bar",
|
||||
" A threeUnsortedAnnotationsSameInitialLetter();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Bar",
|
||||
" @Foo()",
|
||||
" @Baz",
|
||||
" A firstOrderedWithTwoUnsortedAnnotations();",
|
||||
"",
|
||||
" @Bar",
|
||||
" @Baz",
|
||||
" @Foo()",
|
||||
" A threeSortedAnnotations();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo({\"b\"})",
|
||||
" @Bar({\"a\"})",
|
||||
" A unsortedWithStringAttributes();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Baz(str = {\"a\", \"b\"})",
|
||||
" @Foo(ints = {1, 0})",
|
||||
" @Bar",
|
||||
" A unsortedWithAttributes();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Bar",
|
||||
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
|
||||
" @Baz",
|
||||
" A unsortedWithNestedBar();",
|
||||
"",
|
||||
" @Bar",
|
||||
" @Baz",
|
||||
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
|
||||
" A sortedWithNestedBar();",
|
||||
"",
|
||||
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
|
||||
" @Foo(ints = {1, 2})",
|
||||
" @Foo({\"b\"})",
|
||||
" A sortedRepeatableAnnotation();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
|
||||
" @Bar",
|
||||
" @Foo(ints = {1, 2})",
|
||||
" A unsortedRepeatableAnnotation();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" default @FooTypeUse @BarTypeUse A unsortedTypeAnnotations() {",
|
||||
" return null;",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" @Baz",
|
||||
" @Bar",
|
||||
" default @FooTypeUse @BarTypeUse A unsortedTypeUseAndOtherAnnotations() {",
|
||||
" return null;",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
interface A {
|
||||
@Repeatable(Foos.class)
|
||||
@interface Foo {
|
||||
String[] value() default {};
|
||||
|
||||
int[] ints() default {};
|
||||
|
||||
Bar[] anns() default {};
|
||||
}
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@interface Bar {
|
||||
String[] value() default {};
|
||||
}
|
||||
|
||||
@interface Baz {
|
||||
String[] str() default {};
|
||||
}
|
||||
|
||||
@interface Foos {
|
||||
Foo[] value();
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface FooTypeUse {
|
||||
String[] value() default {};
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface BarTypeUse {
|
||||
String[] value() default {};
|
||||
}
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo
|
||||
@Bar
|
||||
A unsortedSimpleCase();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo()
|
||||
@Bar()
|
||||
A unsortedWithParens();
|
||||
|
||||
@Foo()
|
||||
A onlyOneAnnotation();
|
||||
|
||||
@Bar
|
||||
@Foo()
|
||||
A sortedAnnotationsOneWithParens();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo
|
||||
@Baz
|
||||
@Bar
|
||||
A threeUnsortedAnnotationsSameInitialLetter();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Bar
|
||||
@Foo()
|
||||
@Baz
|
||||
A firstOrderedWithTwoUnsortedAnnotations();
|
||||
|
||||
@Bar
|
||||
@Baz
|
||||
@Foo()
|
||||
A threeSortedAnnotations();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo({"b"})
|
||||
@Bar({"a"})
|
||||
A unsortedWithStringAttributes();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Baz(str = {"a", "b"})
|
||||
@Foo(ints = {1, 0})
|
||||
@Bar
|
||||
A unsortedWithAttributes();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Bar
|
||||
@Foo(anns = {@Bar("b"), @Bar("a")})
|
||||
@Baz
|
||||
A unsortedWithNestedBar();
|
||||
|
||||
@Bar
|
||||
@Baz
|
||||
@Foo(anns = {@Bar("b"), @Bar("a")})
|
||||
A sortedWithNestedBar();
|
||||
|
||||
@Foo(anns = {@Bar("b"), @Bar("a")})
|
||||
@Foo(ints = {1, 2})
|
||||
@Foo({"b"})
|
||||
A sortedRepeatableAnnotation();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Foo(anns = {@Bar("b"), @Bar("a")})
|
||||
@Bar
|
||||
@Foo(ints = {1, 2})
|
||||
A unsortedRepeatableAnnotation();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
default @FooTypeUse @BarTypeUse A unsortedTypeAnnotations() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
@Baz
|
||||
@Bar
|
||||
default @FooTypeUse @BarTypeUse A unsortedTypeUseAndOtherAnnotations() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -135,166 +137,170 @@ final class LexicographicalAnnotationListingTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(LexicographicalAnnotationListing.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import java.lang.annotation.ElementType;",
|
||||
"import java.lang.annotation.Repeatable;",
|
||||
"import java.lang.annotation.Target;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @Repeatable(Foos.class)",
|
||||
" @interface Foo {",
|
||||
" String[] value() default {};",
|
||||
"",
|
||||
" int[] ints() default {};",
|
||||
"",
|
||||
" Bar[] anns() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @Target(ElementType.METHOD)",
|
||||
" @interface Bar {",
|
||||
" String[] value() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @interface Baz {",
|
||||
" String[] str() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @interface Foos {",
|
||||
" Foo[] value();",
|
||||
" }",
|
||||
"",
|
||||
" @Target(ElementType.TYPE_USE)",
|
||||
" @interface FooTypeUse {",
|
||||
" String[] value() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @Target(ElementType.TYPE_USE)",
|
||||
" @interface BarTypeUse {",
|
||||
" String[] value() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @Bar",
|
||||
" A singleAnnotation();",
|
||||
"",
|
||||
" @Bar",
|
||||
" @Foo",
|
||||
" A sortedAnnotations();",
|
||||
"",
|
||||
" @Foo",
|
||||
" @Bar",
|
||||
" A unsortedAnnotations();",
|
||||
"",
|
||||
" @Foo()",
|
||||
" @Baz()",
|
||||
" @Bar",
|
||||
" A unsortedAnnotationsWithSomeParens();",
|
||||
"",
|
||||
" @Bar",
|
||||
" @Baz(str = {\"a\", \"b\"})",
|
||||
" @Foo()",
|
||||
" A unsortedAnnotationsOneContainingAttributes();",
|
||||
"",
|
||||
" @Baz(str = {\"a\", \"b\"})",
|
||||
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
|
||||
" @Bar({\"b\"})",
|
||||
" A unsortedAnnotationsWithAttributes();",
|
||||
"",
|
||||
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
|
||||
" @Foo(ints = {1, 2})",
|
||||
" @Foo({\"b\"})",
|
||||
" A sortedRepeatableAnnotation();",
|
||||
"",
|
||||
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
|
||||
" @Bar",
|
||||
" @Foo(ints = {1, 2})",
|
||||
" A unsortedRepeatableAnnotation();",
|
||||
"",
|
||||
" @Baz",
|
||||
" @Bar",
|
||||
" default @FooTypeUse @BarTypeUse A unsortedWithTypeUseAnnotations() {",
|
||||
" return null;",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
interface A {
|
||||
@Repeatable(Foos.class)
|
||||
@interface Foo {
|
||||
String[] value() default {};
|
||||
|
||||
int[] ints() default {};
|
||||
|
||||
Bar[] anns() default {};
|
||||
}
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@interface Bar {
|
||||
String[] value() default {};
|
||||
}
|
||||
|
||||
@interface Baz {
|
||||
String[] str() default {};
|
||||
}
|
||||
|
||||
@interface Foos {
|
||||
Foo[] value();
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface FooTypeUse {
|
||||
String[] value() default {};
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface BarTypeUse {
|
||||
String[] value() default {};
|
||||
}
|
||||
|
||||
@Bar
|
||||
A singleAnnotation();
|
||||
|
||||
@Bar
|
||||
@Foo
|
||||
A sortedAnnotations();
|
||||
|
||||
@Foo
|
||||
@Bar
|
||||
A unsortedAnnotations();
|
||||
|
||||
@Foo()
|
||||
@Baz()
|
||||
@Bar
|
||||
A unsortedAnnotationsWithSomeParens();
|
||||
|
||||
@Bar
|
||||
@Baz(str = {"a", "b"})
|
||||
@Foo()
|
||||
A unsortedAnnotationsOneContainingAttributes();
|
||||
|
||||
@Baz(str = {"a", "b"})
|
||||
@Foo(anns = {@Bar("b"), @Bar("a")})
|
||||
@Bar({"b"})
|
||||
A unsortedAnnotationsWithAttributes();
|
||||
|
||||
@Foo(anns = {@Bar("b"), @Bar("a")})
|
||||
@Foo(ints = {1, 2})
|
||||
@Foo({"b"})
|
||||
A sortedRepeatableAnnotation();
|
||||
|
||||
@Foo(anns = {@Bar("b"), @Bar("a")})
|
||||
@Bar
|
||||
@Foo(ints = {1, 2})
|
||||
A unsortedRepeatableAnnotation();
|
||||
|
||||
@Baz
|
||||
@Bar
|
||||
default @FooTypeUse @BarTypeUse A unsortedWithTypeUseAnnotations() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import java.lang.annotation.ElementType;",
|
||||
"import java.lang.annotation.Repeatable;",
|
||||
"import java.lang.annotation.Target;",
|
||||
"",
|
||||
"interface A {",
|
||||
" @Repeatable(Foos.class)",
|
||||
" @interface Foo {",
|
||||
" String[] value() default {};",
|
||||
"",
|
||||
" int[] ints() default {};",
|
||||
"",
|
||||
" Bar[] anns() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @Target(ElementType.METHOD)",
|
||||
" @interface Bar {",
|
||||
" String[] value() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @interface Baz {",
|
||||
" String[] str() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @interface Foos {",
|
||||
" Foo[] value();",
|
||||
" }",
|
||||
"",
|
||||
" @Target(ElementType.TYPE_USE)",
|
||||
" @interface FooTypeUse {",
|
||||
" String[] value() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @Target(ElementType.TYPE_USE)",
|
||||
" @interface BarTypeUse {",
|
||||
" String[] value() default {};",
|
||||
" }",
|
||||
"",
|
||||
" @Bar",
|
||||
" A singleAnnotation();",
|
||||
"",
|
||||
" @Bar",
|
||||
" @Foo",
|
||||
" A sortedAnnotations();",
|
||||
"",
|
||||
" @Bar",
|
||||
" @Foo",
|
||||
" A unsortedAnnotations();",
|
||||
"",
|
||||
" @Bar",
|
||||
" @Baz()",
|
||||
" @Foo()",
|
||||
" A unsortedAnnotationsWithSomeParens();",
|
||||
"",
|
||||
" @Bar",
|
||||
" @Baz(str = {\"a\", \"b\"})",
|
||||
" @Foo()",
|
||||
" A unsortedAnnotationsOneContainingAttributes();",
|
||||
"",
|
||||
" @Bar({\"b\"})",
|
||||
" @Baz(str = {\"a\", \"b\"})",
|
||||
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
|
||||
" A unsortedAnnotationsWithAttributes();",
|
||||
"",
|
||||
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
|
||||
" @Foo(ints = {1, 2})",
|
||||
" @Foo({\"b\"})",
|
||||
" A sortedRepeatableAnnotation();",
|
||||
"",
|
||||
" @Bar",
|
||||
" @Foo(anns = {@Bar(\"b\"), @Bar(\"a\")})",
|
||||
" @Foo(ints = {1, 2})",
|
||||
" A unsortedRepeatableAnnotation();",
|
||||
"",
|
||||
" @Bar",
|
||||
" @Baz",
|
||||
" default @BarTypeUse @FooTypeUse A unsortedWithTypeUseAnnotations() {",
|
||||
" return null;",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
interface A {
|
||||
@Repeatable(Foos.class)
|
||||
@interface Foo {
|
||||
String[] value() default {};
|
||||
|
||||
int[] ints() default {};
|
||||
|
||||
Bar[] anns() default {};
|
||||
}
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@interface Bar {
|
||||
String[] value() default {};
|
||||
}
|
||||
|
||||
@interface Baz {
|
||||
String[] str() default {};
|
||||
}
|
||||
|
||||
@interface Foos {
|
||||
Foo[] value();
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface FooTypeUse {
|
||||
String[] value() default {};
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface BarTypeUse {
|
||||
String[] value() default {};
|
||||
}
|
||||
|
||||
@Bar
|
||||
A singleAnnotation();
|
||||
|
||||
@Bar
|
||||
@Foo
|
||||
A sortedAnnotations();
|
||||
|
||||
@Bar
|
||||
@Foo
|
||||
A unsortedAnnotations();
|
||||
|
||||
@Bar
|
||||
@Baz()
|
||||
@Foo()
|
||||
A unsortedAnnotationsWithSomeParens();
|
||||
|
||||
@Bar
|
||||
@Baz(str = {"a", "b"})
|
||||
@Foo()
|
||||
A unsortedAnnotationsOneContainingAttributes();
|
||||
|
||||
@Bar({"b"})
|
||||
@Baz(str = {"a", "b"})
|
||||
@Foo(anns = {@Bar("b"), @Bar("a")})
|
||||
A unsortedAnnotationsWithAttributes();
|
||||
|
||||
@Foo(anns = {@Bar("b"), @Bar("a")})
|
||||
@Foo(ints = {1, 2})
|
||||
@Foo({"b"})
|
||||
A sortedRepeatableAnnotation();
|
||||
|
||||
@Bar
|
||||
@Foo(anns = {@Bar("b"), @Bar("a")})
|
||||
@Foo(ints = {1, 2})
|
||||
A unsortedRepeatableAnnotation();
|
||||
|
||||
@Bar
|
||||
@Baz
|
||||
default @BarTypeUse @FooTypeUse A unsortedWithTypeUseAnnotations() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,86 +11,88 @@ final class MockitoMockClassReferenceTest {
|
||||
CompilationTestHelper.newInstance(MockitoMockClassReference.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static org.mockito.Mockito.mock;",
|
||||
"import static org.mockito.Mockito.spy;",
|
||||
"import static org.mockito.Mockito.withSettings;",
|
||||
"",
|
||||
"import java.util.List;",
|
||||
"import java.util.Objects;",
|
||||
"import org.mockito.invocation.InvocationOnMock;",
|
||||
"",
|
||||
"class A {",
|
||||
" {",
|
||||
" Double d = Objects.requireNonNullElseGet(null, () -> mock(Double.class));",
|
||||
" Double d2 =",
|
||||
" Objects.requireNonNullElseGet(",
|
||||
" null,",
|
||||
" () -> {",
|
||||
" return mock(Double.class);",
|
||||
" });",
|
||||
" }",
|
||||
"",
|
||||
" void m() {",
|
||||
" Number variableMock = 42;",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" variableMock = mock(Number.class);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" variableMock = mock(Number.class, \"name\");",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" variableMock = mock(Number.class, InvocationOnMock::callRealMethod);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" variableMock = mock(Number.class, withSettings());",
|
||||
" variableMock = mock(Integer.class);",
|
||||
" variableMock = 42;",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" List rawMock = mock(List.class);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" List<String> genericMock = mock(List.class);",
|
||||
" var varMock = mock(Integer.class);",
|
||||
" Class<? extends Number> numberType = Integer.class;",
|
||||
" Number variableTypeMock = mock(numberType);",
|
||||
" Object subtypeMock = mock(Integer.class);",
|
||||
"",
|
||||
" Number variableSpy = 42;",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" variableSpy = spy(Number.class);",
|
||||
" variableSpy = spy(Integer.class);",
|
||||
" variableSpy = 42;",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" List rawSpy = spy(List.class);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" List<String> genericSpy = spy(List.class);",
|
||||
" var varSpy = spy(Integer.class);",
|
||||
" Number variableTypeSpy = spy(numberType);",
|
||||
" Object subtypeSpy = spy(Integer.class);",
|
||||
" Object objectSpy = spy(new Object());",
|
||||
"",
|
||||
" Objects.hash(mock(Integer.class));",
|
||||
" Integer i = mock(mock(Integer.class));",
|
||||
" String s = new String(mock(String.class));",
|
||||
" }",
|
||||
"",
|
||||
" Double getDoubleMock() {",
|
||||
" return Objects.requireNonNullElseGet(",
|
||||
" null,",
|
||||
" () -> {",
|
||||
" return mock(Double.class);",
|
||||
" });",
|
||||
" }",
|
||||
"",
|
||||
" Integer getIntegerMock() {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" return mock(Integer.class);",
|
||||
" }",
|
||||
"",
|
||||
" <T> T getGenericMock(Class<T> clazz) {",
|
||||
" return mock(clazz);",
|
||||
" }",
|
||||
"",
|
||||
" Number getSubTypeMock() {",
|
||||
" return mock(Integer.class);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
|
||||
class A {
|
||||
{
|
||||
Double d = Objects.requireNonNullElseGet(null, () -> mock(Double.class));
|
||||
Double d2 =
|
||||
Objects.requireNonNullElseGet(
|
||||
null,
|
||||
() -> {
|
||||
return mock(Double.class);
|
||||
});
|
||||
}
|
||||
|
||||
void m() {
|
||||
Number variableMock = 42;
|
||||
// BUG: Diagnostic contains:
|
||||
variableMock = mock(Number.class);
|
||||
// BUG: Diagnostic contains:
|
||||
variableMock = mock(Number.class, "name");
|
||||
// BUG: Diagnostic contains:
|
||||
variableMock = mock(Number.class, InvocationOnMock::callRealMethod);
|
||||
// BUG: Diagnostic contains:
|
||||
variableMock = mock(Number.class, withSettings());
|
||||
variableMock = mock(Integer.class);
|
||||
variableMock = 42;
|
||||
// BUG: Diagnostic contains:
|
||||
List rawMock = mock(List.class);
|
||||
// BUG: Diagnostic contains:
|
||||
List<String> genericMock = mock(List.class);
|
||||
var varMock = mock(Integer.class);
|
||||
Class<? extends Number> numberType = Integer.class;
|
||||
Number variableTypeMock = mock(numberType);
|
||||
Object subtypeMock = mock(Integer.class);
|
||||
|
||||
Number variableSpy = 42;
|
||||
// BUG: Diagnostic contains:
|
||||
variableSpy = spy(Number.class);
|
||||
variableSpy = spy(Integer.class);
|
||||
variableSpy = 42;
|
||||
// BUG: Diagnostic contains:
|
||||
List rawSpy = spy(List.class);
|
||||
// BUG: Diagnostic contains:
|
||||
List<String> genericSpy = spy(List.class);
|
||||
var varSpy = spy(Integer.class);
|
||||
Number variableTypeSpy = spy(numberType);
|
||||
Object subtypeSpy = spy(Integer.class);
|
||||
Object objectSpy = spy(new Object());
|
||||
|
||||
Objects.hash(mock(Integer.class));
|
||||
Integer i = mock(mock(Integer.class));
|
||||
String s = new String(mock(String.class));
|
||||
}
|
||||
|
||||
Double getDoubleMock() {
|
||||
return Objects.requireNonNullElseGet(
|
||||
null,
|
||||
() -> {
|
||||
return mock(Double.class);
|
||||
});
|
||||
}
|
||||
|
||||
Integer getIntegerMock() {
|
||||
// BUG: Diagnostic contains:
|
||||
return mock(Integer.class);
|
||||
}
|
||||
|
||||
<T> T getGenericMock(Class<T> clazz) {
|
||||
return mock(clazz);
|
||||
}
|
||||
|
||||
Number getSubTypeMock() {
|
||||
return mock(Integer.class);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -99,38 +101,42 @@ final class MockitoMockClassReferenceTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(MockitoMockClassReference.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static org.mockito.Mockito.mock;",
|
||||
"import static org.mockito.Mockito.spy;",
|
||||
"import static org.mockito.Mockito.withSettings;",
|
||||
"",
|
||||
"import org.mockito.invocation.InvocationOnMock;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Number simpleMock = mock(Number.class);",
|
||||
" Number namedMock = mock(Number.class, \"name\");",
|
||||
" Number customAnswerMock = mock(Number.class, InvocationOnMock::callRealMethod);",
|
||||
" Number customSettingsMock = mock(Number.class, withSettings());",
|
||||
" Number simpleSpy = spy(Number.class);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Number simpleMock = mock(Number.class);
|
||||
Number namedMock = mock(Number.class, "name");
|
||||
Number customAnswerMock = mock(Number.class, InvocationOnMock::callRealMethod);
|
||||
Number customSettingsMock = mock(Number.class, withSettings());
|
||||
Number simpleSpy = spy(Number.class);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static org.mockito.Mockito.mock;",
|
||||
"import static org.mockito.Mockito.spy;",
|
||||
"import static org.mockito.Mockito.withSettings;",
|
||||
"",
|
||||
"import org.mockito.invocation.InvocationOnMock;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Number simpleMock = mock();",
|
||||
" Number namedMock = mock(\"name\");",
|
||||
" Number customAnswerMock = mock(InvocationOnMock::callRealMethod);",
|
||||
" Number customSettingsMock = mock(withSettings());",
|
||||
" Number simpleSpy = spy();",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Number simpleMock = mock();
|
||||
Number namedMock = mock("name");
|
||||
Number customAnswerMock = mock(InvocationOnMock::callRealMethod);
|
||||
Number customSettingsMock = mock(withSettings());
|
||||
Number simpleSpy = spy();
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,40 +11,42 @@ final class MockitoStubbingTest {
|
||||
CompilationTestHelper.newInstance(MockitoStubbing.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static org.mockito.ArgumentMatchers.eq;",
|
||||
"import static org.mockito.ArgumentMatchers.notNull;",
|
||||
"import static org.mockito.Mockito.doAnswer;",
|
||||
"import static org.mockito.Mockito.mock;",
|
||||
"",
|
||||
"import java.util.function.BiConsumer;",
|
||||
"import java.util.function.Consumer;",
|
||||
"import org.mockito.ArgumentMatchers;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Runnable runnable = mock(Runnable.class);",
|
||||
" doAnswer(inv -> null).when(runnable).run();",
|
||||
"",
|
||||
" Consumer<String> consumer = mock(Consumer.class);",
|
||||
" doAnswer(inv -> null).when(consumer).accept(\"foo\");",
|
||||
" doAnswer(inv -> null).when(consumer).accept(notNull());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" doAnswer(inv -> null).when(consumer).accept(ArgumentMatchers.eq(\"foo\"));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" doAnswer(inv -> null).when(consumer).accept(eq(toString()));",
|
||||
"",
|
||||
" BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(0, \"foo\");",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(eq(0), notNull());",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(notNull(), eq(\"foo\"));",
|
||||
" doAnswer(inv -> null)",
|
||||
" .when(biConsumer)",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" .accept(ArgumentMatchers.eq(0), ArgumentMatchers.eq(\"foo\"));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(eq(hashCode()), eq(toString()));",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.notNull;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Runnable runnable = mock(Runnable.class);
|
||||
doAnswer(inv -> null).when(runnable).run();
|
||||
|
||||
Consumer<String> consumer = mock(Consumer.class);
|
||||
doAnswer(inv -> null).when(consumer).accept("foo");
|
||||
doAnswer(inv -> null).when(consumer).accept(notNull());
|
||||
// BUG: Diagnostic contains:
|
||||
doAnswer(inv -> null).when(consumer).accept(ArgumentMatchers.eq("foo"));
|
||||
// BUG: Diagnostic contains:
|
||||
doAnswer(inv -> null).when(consumer).accept(eq(toString()));
|
||||
|
||||
BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);
|
||||
doAnswer(inv -> null).when(biConsumer).accept(0, "foo");
|
||||
doAnswer(inv -> null).when(biConsumer).accept(eq(0), notNull());
|
||||
doAnswer(inv -> null).when(biConsumer).accept(notNull(), eq("foo"));
|
||||
doAnswer(inv -> null)
|
||||
.when(biConsumer)
|
||||
// BUG: Diagnostic contains:
|
||||
.accept(ArgumentMatchers.eq(0), ArgumentMatchers.eq("foo"));
|
||||
// BUG: Diagnostic contains:
|
||||
doAnswer(inv -> null).when(biConsumer).accept(eq(hashCode()), eq(toString()));
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -53,48 +55,52 @@ final class MockitoStubbingTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(MockitoStubbing.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static org.mockito.ArgumentMatchers.eq;",
|
||||
"import static org.mockito.Mockito.doAnswer;",
|
||||
"import static org.mockito.Mockito.mock;",
|
||||
"",
|
||||
"import java.util.function.BiConsumer;",
|
||||
"import java.util.function.Consumer;",
|
||||
"import org.mockito.ArgumentMatchers;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Consumer<String> consumer = mock(Consumer.class);",
|
||||
" doAnswer(inv -> null).when(consumer).accept(ArgumentMatchers.eq(\"foo\"));",
|
||||
" doAnswer(inv -> null).when(consumer).accept(eq(toString()));",
|
||||
"",
|
||||
" BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);",
|
||||
" doAnswer(inv -> null)",
|
||||
" .when(biConsumer)",
|
||||
" .accept(ArgumentMatchers.eq(0), ArgumentMatchers.eq(\"foo\"));",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(eq(hashCode()), eq(toString()));",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Consumer<String> consumer = mock(Consumer.class);
|
||||
doAnswer(inv -> null).when(consumer).accept(ArgumentMatchers.eq("foo"));
|
||||
doAnswer(inv -> null).when(consumer).accept(eq(toString()));
|
||||
|
||||
BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);
|
||||
doAnswer(inv -> null)
|
||||
.when(biConsumer)
|
||||
.accept(ArgumentMatchers.eq(0), ArgumentMatchers.eq("foo"));
|
||||
doAnswer(inv -> null).when(biConsumer).accept(eq(hashCode()), eq(toString()));
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static org.mockito.ArgumentMatchers.eq;",
|
||||
"import static org.mockito.Mockito.doAnswer;",
|
||||
"import static org.mockito.Mockito.mock;",
|
||||
"",
|
||||
"import java.util.function.BiConsumer;",
|
||||
"import java.util.function.Consumer;",
|
||||
"import org.mockito.ArgumentMatchers;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Consumer<String> consumer = mock(Consumer.class);",
|
||||
" doAnswer(inv -> null).when(consumer).accept(\"foo\");",
|
||||
" doAnswer(inv -> null).when(consumer).accept(toString());",
|
||||
"",
|
||||
" BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(0, \"foo\");",
|
||||
" doAnswer(inv -> null).when(biConsumer).accept(hashCode(), toString());",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Consumer<String> consumer = mock(Consumer.class);
|
||||
doAnswer(inv -> null).when(consumer).accept("foo");
|
||||
doAnswer(inv -> null).when(consumer).accept(toString());
|
||||
|
||||
BiConsumer<Integer, String> biConsumer = mock(BiConsumer.class);
|
||||
doAnswer(inv -> null).when(biConsumer).accept(0, "foo");
|
||||
doAnswer(inv -> null).when(biConsumer).accept(hashCode(), toString());
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,18 +9,20 @@ final class MongoDBTextFilterUsageTest {
|
||||
CompilationTestHelper.newInstance(MongoDBTextFilterUsage.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.mongodb.client.model.Filters;",
|
||||
"import com.mongodb.client.model.TextSearchOptions;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Filters.eq(\"foo\", \"bar\");",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Filters.text(\"foo\");",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Filters.text(\"foo\", new TextSearchOptions());",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import com.mongodb.client.model.Filters;
|
||||
import com.mongodb.client.model.TextSearchOptions;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Filters.eq("foo", "bar");
|
||||
// BUG: Diagnostic contains:
|
||||
Filters.text("foo");
|
||||
// BUG: Diagnostic contains:
|
||||
Filters.text("foo", new TextSearchOptions());
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,31 +9,33 @@ final class NestedOptionalsTest {
|
||||
CompilationTestHelper.newInstance(NestedOptionals.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.Optional;",
|
||||
"import java.util.stream.Stream;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Optional.empty();",
|
||||
" Optional.of(1);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Optional.of(Optional.empty());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Optional.of(Optional.of(1));",
|
||||
"",
|
||||
" Optional.ofNullable(null);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Optional.ofNullable((Optional) null);",
|
||||
"",
|
||||
" Optional.of(\"foo\").map(String::length);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Optional.of(\"foo\").map(Optional::of);",
|
||||
"",
|
||||
" Stream.of(\"foo\").findFirst();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Stream.of(\"foo\").map(Optional::of).findFirst();",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Optional.empty();
|
||||
Optional.of(1);
|
||||
// BUG: Diagnostic contains:
|
||||
Optional.of(Optional.empty());
|
||||
// BUG: Diagnostic contains:
|
||||
Optional.of(Optional.of(1));
|
||||
|
||||
Optional.ofNullable(null);
|
||||
// BUG: Diagnostic contains:
|
||||
Optional.ofNullable((Optional) null);
|
||||
|
||||
Optional.of("foo").map(String::length);
|
||||
// BUG: Diagnostic contains:
|
||||
Optional.of("foo").map(Optional::of);
|
||||
|
||||
Stream.of("foo").findFirst();
|
||||
// BUG: Diagnostic contains:
|
||||
Stream.of("foo").map(Optional::of).findFirst();
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,29 +9,31 @@ final class NestedPublishersTest {
|
||||
CompilationTestHelper.newInstance(NestedPublishers.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import org.reactivestreams.Publisher;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.GroupedFlux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Mono.empty();",
|
||||
" Flux.just(1);",
|
||||
" Flux.just(1, 2).groupBy(i -> i).map(groupedFlux -> (GroupedFlux) groupedFlux);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.just(Mono.empty());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(Flux.empty());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.just((Flux) Flux.just(1));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just((Publisher) Mono.just(1));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.just(1).map(Mono::just);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.GroupedFlux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Mono.empty();
|
||||
Flux.just(1);
|
||||
Flux.just(1, 2).groupBy(i -> i).map(groupedFlux -> (GroupedFlux) groupedFlux);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Mono.just(Mono.empty());
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(Flux.empty());
|
||||
// BUG: Diagnostic contains:
|
||||
Mono.just((Flux) Flux.just(1));
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just((Publisher) Mono.just(1));
|
||||
// BUG: Diagnostic contains:
|
||||
Mono.just(1).map(Mono::just);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,95 +11,97 @@ final class NonEmptyMonoTest {
|
||||
CompilationTestHelper.newInstance(NonEmptyMono.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static com.google.common.collect.ImmutableList.toImmutableList;",
|
||||
"import static java.util.function.Function.identity;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableMap;",
|
||||
"import java.util.ArrayList;",
|
||||
"import java.util.HashMap;",
|
||||
"import java.util.List;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Mono.just(1).defaultIfEmpty(2);",
|
||||
" Mono.just(1).single();",
|
||||
" Mono.just(1).switchIfEmpty(Mono.just(2));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).all(x -> true).defaultIfEmpty(true);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).any(x -> true).single();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collect(toImmutableList()).switchIfEmpty(Mono.just(ImmutableList.of()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collect(ArrayList::new, List::add).defaultIfEmpty(new ArrayList<>());",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectList().single();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectMap(identity()).switchIfEmpty(Mono.just(ImmutableMap.of()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectMap(identity(), identity()).defaultIfEmpty(ImmutableMap.of());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectMap(identity(), identity(), HashMap::new).single();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectMultimap(identity()).switchIfEmpty(Mono.just(ImmutableMap.of()));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectMultimap(identity(), identity()).defaultIfEmpty(ImmutableMap.of());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectMultimap(identity(), identity(), HashMap::new).single();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectSortedList().defaultIfEmpty(ImmutableList.of());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).collectSortedList((o1, o2) -> 0).single();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).count().switchIfEmpty(Mono.just(2L));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).elementAt(0).defaultIfEmpty(1);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).elementAt(0, 2).single();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).hasElement(2).switchIfEmpty(Mono.just(true));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).hasElements().defaultIfEmpty(true);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).last().single();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).last(2).switchIfEmpty(Mono.just(3));",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).reduceWith(() -> 0, Integer::sum).defaultIfEmpty(2);",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).single().single();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).single(2).switchIfEmpty(Mono.just(3));",
|
||||
"",
|
||||
" Flux.just(1).reduce(Integer::sum).defaultIfEmpty(2);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Flux.just(1).reduce(2, Integer::sum).single();",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.just(1).defaultIfEmpty(1).switchIfEmpty(Mono.just(2));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.just(1).hasElement().defaultIfEmpty(true);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" Mono.just(1).single().single();",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static java.util.function.Function.identity;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Mono.just(1).defaultIfEmpty(2);
|
||||
Mono.just(1).single();
|
||||
Mono.just(1).switchIfEmpty(Mono.just(2));
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).all(x -> true).defaultIfEmpty(true);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).any(x -> true).single();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).collect(toImmutableList()).switchIfEmpty(Mono.just(ImmutableList.of()));
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).collect(ArrayList::new, List::add).defaultIfEmpty(new ArrayList<>());
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).collectList().single();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).collectMap(identity()).switchIfEmpty(Mono.just(ImmutableMap.of()));
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).collectMap(identity(), identity()).defaultIfEmpty(ImmutableMap.of());
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).collectMap(identity(), identity(), HashMap::new).single();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).collectMultimap(identity()).switchIfEmpty(Mono.just(ImmutableMap.of()));
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).collectMultimap(identity(), identity()).defaultIfEmpty(ImmutableMap.of());
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).collectMultimap(identity(), identity(), HashMap::new).single();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).collectSortedList().defaultIfEmpty(ImmutableList.of());
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).collectSortedList((o1, o2) -> 0).single();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).count().switchIfEmpty(Mono.just(2L));
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).elementAt(0).defaultIfEmpty(1);
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).elementAt(0, 2).single();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).hasElement(2).switchIfEmpty(Mono.just(true));
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).hasElements().defaultIfEmpty(true);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).last().single();
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).last(2).switchIfEmpty(Mono.just(3));
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).reduceWith(() -> 0, Integer::sum).defaultIfEmpty(2);
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).single().single();
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).single(2).switchIfEmpty(Mono.just(3));
|
||||
|
||||
Flux.just(1).reduce(Integer::sum).defaultIfEmpty(2);
|
||||
// BUG: Diagnostic contains:
|
||||
Flux.just(1).reduce(2, Integer::sum).single();
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Mono.just(1).defaultIfEmpty(1).switchIfEmpty(Mono.just(2));
|
||||
// BUG: Diagnostic contains:
|
||||
Mono.just(1).hasElement().defaultIfEmpty(true);
|
||||
// BUG: Diagnostic contains:
|
||||
Mono.just(1).single().single();
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -108,42 +110,46 @@ final class NonEmptyMonoTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(NonEmptyMono.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static com.google.common.collect.ImmutableList.toImmutableList;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Flux.just(1).collect(toImmutableList()).single();",
|
||||
" Flux.just(1).collect(toImmutableList()).defaultIfEmpty(ImmutableList.of());",
|
||||
" Flux.just(1).collect(toImmutableList()).switchIfEmpty(Mono.just(ImmutableList.of()));",
|
||||
"",
|
||||
" Mono.just(2).hasElement().single();",
|
||||
" Mono.just(2).hasElement().defaultIfEmpty(true);",
|
||||
" Mono.just(2).hasElement().switchIfEmpty(Mono.just(true));",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Flux.just(1).collect(toImmutableList()).single();
|
||||
Flux.just(1).collect(toImmutableList()).defaultIfEmpty(ImmutableList.of());
|
||||
Flux.just(1).collect(toImmutableList()).switchIfEmpty(Mono.just(ImmutableList.of()));
|
||||
|
||||
Mono.just(2).hasElement().single();
|
||||
Mono.just(2).hasElement().defaultIfEmpty(true);
|
||||
Mono.just(2).hasElement().switchIfEmpty(Mono.just(true));
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import static com.google.common.collect.ImmutableList.toImmutableList;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import reactor.core.publisher.Flux;",
|
||||
"import reactor.core.publisher.Mono;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Flux.just(1).collect(toImmutableList());",
|
||||
" Flux.just(1).collect(toImmutableList());",
|
||||
" Flux.just(1).collect(toImmutableList());",
|
||||
"",
|
||||
" Mono.just(2).hasElement();",
|
||||
" Mono.just(2).hasElement();",
|
||||
" Mono.just(2).hasElement();",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Flux.just(1).collect(toImmutableList());
|
||||
Flux.just(1).collect(toImmutableList());
|
||||
Flux.just(1).collect(toImmutableList());
|
||||
|
||||
Mono.just(2).hasElement();
|
||||
Mono.just(2).hasElement();
|
||||
Mono.just(2).hasElement();
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,74 +40,76 @@ final class NonStaticImportTest {
|
||||
CompilationTestHelper.newInstance(NonStaticImport.class, getClass())
|
||||
.addSourceLines(
|
||||
"pkg/A.java",
|
||||
"package pkg;",
|
||||
"",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static com.google.common.base.Strings.nullToEmpty;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static com.google.common.collect.ImmutableList.copyOf;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.lang.Integer.MAX_VALUE;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.lang.Integer.MIN_VALUE;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.time.Clock.systemUTC;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.time.Instant.MIN;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.time.ZoneOffset.SHORT_IDS;",
|
||||
"import static java.time.ZoneOffset.UTC;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.util.Collections.min;",
|
||||
"import static java.util.Locale.ENGLISH;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.util.Locale.ROOT;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static java.util.Optional.empty;",
|
||||
"import static pkg.A.WithMethodThatIsSelectivelyFlagged.list;",
|
||||
"// BUG: Diagnostic contains:",
|
||||
"import static reactor.core.publisher.Flux.just;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.time.Instant;",
|
||||
"import java.time.ZoneOffset;",
|
||||
"import java.util.Locale;",
|
||||
"import java.util.Map;",
|
||||
"import pkg.A.Wrapper.INSTANCE;",
|
||||
"",
|
||||
"class A {",
|
||||
" private Integer MIN_VALUE = 12;",
|
||||
"",
|
||||
" void m() {",
|
||||
" nullToEmpty(null);",
|
||||
" copyOf(ImmutableList.of());",
|
||||
" int max = MAX_VALUE;",
|
||||
" int min = MIN_VALUE;",
|
||||
" systemUTC();",
|
||||
" Instant minInstant = MIN;",
|
||||
" Map<String, String> shortIds = SHORT_IDS;",
|
||||
" ZoneOffset utc = UTC;",
|
||||
" min(ImmutableSet.of());",
|
||||
" Locale english = ENGLISH;",
|
||||
" Locale root = ROOT;",
|
||||
" empty();",
|
||||
" just();",
|
||||
"",
|
||||
" list();",
|
||||
" new INSTANCE();",
|
||||
" }",
|
||||
"",
|
||||
" static final class WithMethodThatIsSelectivelyFlagged {",
|
||||
" static ImmutableList<String> list() {",
|
||||
" return ImmutableList.of();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" static final class Wrapper {",
|
||||
" static final class INSTANCE {}",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
package pkg;
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
import static com.google.common.base.Strings.nullToEmpty;
|
||||
// BUG: Diagnostic contains:
|
||||
import static com.google.common.collect.ImmutableList.copyOf;
|
||||
// BUG: Diagnostic contains:
|
||||
import static java.lang.Integer.MAX_VALUE;
|
||||
// BUG: Diagnostic contains:
|
||||
import static java.lang.Integer.MIN_VALUE;
|
||||
// BUG: Diagnostic contains:
|
||||
import static java.time.Clock.systemUTC;
|
||||
// BUG: Diagnostic contains:
|
||||
import static java.time.Instant.MIN;
|
||||
// BUG: Diagnostic contains:
|
||||
import static java.time.ZoneOffset.SHORT_IDS;
|
||||
import static java.time.ZoneOffset.UTC;
|
||||
// BUG: Diagnostic contains:
|
||||
import static java.util.Collections.min;
|
||||
import static java.util.Locale.ENGLISH;
|
||||
// BUG: Diagnostic contains:
|
||||
import static java.util.Locale.ROOT;
|
||||
// BUG: Diagnostic contains:
|
||||
import static java.util.Optional.empty;
|
||||
import static pkg.A.WithMethodThatIsSelectivelyFlagged.list;
|
||||
// BUG: Diagnostic contains:
|
||||
import static reactor.core.publisher.Flux.just;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import pkg.A.Wrapper.INSTANCE;
|
||||
|
||||
class A {
|
||||
private Integer MIN_VALUE = 12;
|
||||
|
||||
void m() {
|
||||
nullToEmpty(null);
|
||||
copyOf(ImmutableList.of());
|
||||
int max = MAX_VALUE;
|
||||
int min = MIN_VALUE;
|
||||
systemUTC();
|
||||
Instant minInstant = MIN;
|
||||
Map<String, String> shortIds = SHORT_IDS;
|
||||
ZoneOffset utc = UTC;
|
||||
min(ImmutableSet.of());
|
||||
Locale english = ENGLISH;
|
||||
Locale root = ROOT;
|
||||
empty();
|
||||
just();
|
||||
|
||||
list();
|
||||
new INSTANCE();
|
||||
}
|
||||
|
||||
static final class WithMethodThatIsSelectivelyFlagged {
|
||||
static ImmutableList<String> list() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
}
|
||||
|
||||
static final class Wrapper {
|
||||
static final class INSTANCE {}
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -116,84 +118,88 @@ final class NonStaticImportTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(NonStaticImport.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import static com.google.common.collect.ImmutableList.copyOf;",
|
||||
"import static com.google.common.collect.ImmutableSet.of;",
|
||||
"import static java.time.Clock.systemUTC;",
|
||||
"import static java.time.Instant.MAX;",
|
||||
"import static java.time.Instant.MIN;",
|
||||
"import static java.util.Collections.min;",
|
||||
"import static java.util.Locale.ROOT;",
|
||||
"import static java.util.Optional.empty;",
|
||||
"",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.time.Clock;",
|
||||
"import java.time.Instant;",
|
||||
"import java.util.Locale;",
|
||||
"import java.util.Optional;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" systemUTC();",
|
||||
" Clock.systemUTC();",
|
||||
"",
|
||||
" Optional<Integer> o1 = empty();",
|
||||
" Optional<Integer> o2 = Optional.empty();",
|
||||
"",
|
||||
" Object l1 = copyOf(ImmutableList.of());",
|
||||
" Object l2 = ImmutableList.copyOf(ImmutableList.of());",
|
||||
"",
|
||||
" Locale lo1 = ROOT;",
|
||||
" Locale lo2 = Locale.ROOT;",
|
||||
"",
|
||||
" Instant i1 = MIN;",
|
||||
" Instant i2 = MAX;",
|
||||
"",
|
||||
" ImmutableSet.of(min(of()));",
|
||||
" }",
|
||||
"",
|
||||
" private static final class WithCustomConstant {",
|
||||
" private static final Instant MIN = Instant.EPOCH;",
|
||||
" private static final Instant OTHER = MIN;",
|
||||
" private static final Instant OTHER_MAX = MAX;",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.common.collect.ImmutableList.copyOf;
|
||||
import static com.google.common.collect.ImmutableSet.of;
|
||||
import static java.time.Clock.systemUTC;
|
||||
import static java.time.Instant.MAX;
|
||||
import static java.time.Instant.MIN;
|
||||
import static java.util.Collections.min;
|
||||
import static java.util.Locale.ROOT;
|
||||
import static java.util.Optional.empty;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
systemUTC();
|
||||
Clock.systemUTC();
|
||||
|
||||
Optional<Integer> o1 = empty();
|
||||
Optional<Integer> o2 = Optional.empty();
|
||||
|
||||
Object l1 = copyOf(ImmutableList.of());
|
||||
Object l2 = ImmutableList.copyOf(ImmutableList.of());
|
||||
|
||||
Locale lo1 = ROOT;
|
||||
Locale lo2 = Locale.ROOT;
|
||||
|
||||
Instant i1 = MIN;
|
||||
Instant i2 = MAX;
|
||||
|
||||
ImmutableSet.of(min(of()));
|
||||
}
|
||||
|
||||
private static final class WithCustomConstant {
|
||||
private static final Instant MIN = Instant.EPOCH;
|
||||
private static final Instant OTHER = MIN;
|
||||
private static final Instant OTHER_MAX = MAX;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import com.google.common.collect.ImmutableList;",
|
||||
"import com.google.common.collect.ImmutableSet;",
|
||||
"import java.time.Clock;",
|
||||
"import java.time.Instant;",
|
||||
"import java.util.Collections;",
|
||||
"import java.util.Locale;",
|
||||
"import java.util.Optional;",
|
||||
"",
|
||||
"class A {",
|
||||
" void m() {",
|
||||
" Clock.systemUTC();",
|
||||
" Clock.systemUTC();",
|
||||
"",
|
||||
" Optional<Integer> o1 = Optional.empty();",
|
||||
" Optional<Integer> o2 = Optional.empty();",
|
||||
"",
|
||||
" Object l1 = ImmutableList.copyOf(ImmutableList.of());",
|
||||
" Object l2 = ImmutableList.copyOf(ImmutableList.of());",
|
||||
"",
|
||||
" Locale lo1 = Locale.ROOT;",
|
||||
" Locale lo2 = Locale.ROOT;",
|
||||
"",
|
||||
" Instant i1 = Instant.MIN;",
|
||||
" Instant i2 = Instant.MAX;",
|
||||
"",
|
||||
" ImmutableSet.of(Collections.min(ImmutableSet.of()));",
|
||||
" }",
|
||||
"",
|
||||
" private static final class WithCustomConstant {",
|
||||
" private static final Instant MIN = Instant.EPOCH;",
|
||||
" private static final Instant OTHER = MIN;",
|
||||
" private static final Instant OTHER_MAX = Instant.MAX;",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
Clock.systemUTC();
|
||||
Clock.systemUTC();
|
||||
|
||||
Optional<Integer> o1 = Optional.empty();
|
||||
Optional<Integer> o2 = Optional.empty();
|
||||
|
||||
Object l1 = ImmutableList.copyOf(ImmutableList.of());
|
||||
Object l2 = ImmutableList.copyOf(ImmutableList.of());
|
||||
|
||||
Locale lo1 = Locale.ROOT;
|
||||
Locale lo2 = Locale.ROOT;
|
||||
|
||||
Instant i1 = Instant.MIN;
|
||||
Instant i2 = Instant.MAX;
|
||||
|
||||
ImmutableSet.of(Collections.min(ImmutableSet.of()));
|
||||
}
|
||||
|
||||
private static final class WithCustomConstant {
|
||||
private static final Instant MIN = Instant.EPOCH;
|
||||
private static final Instant OTHER = MIN;
|
||||
private static final Instant OTHER_MAX = Instant.MAX;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
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 OptionalOrElseGetTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(OptionalOrElseGet.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"""
|
||||
import com.google.errorprone.refaster.Refaster;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class A {
|
||||
private final Optional<Object> optional = Optional.empty();
|
||||
private final String string = optional.toString();
|
||||
|
||||
void m() {
|
||||
Optional.empty().orElse(null);
|
||||
optional.orElse(null);
|
||||
optional.orElse("constant");
|
||||
optional.orElse("constant" + 0);
|
||||
optional.orElse(Boolean.TRUE);
|
||||
optional.orElse(string);
|
||||
optional.orElse(this.string);
|
||||
optional.orElse(Refaster.anyOf("constant", "another"));
|
||||
Optional.<Supplier<String>>empty().orElse(() -> "constant");
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
Optional.empty().orElse(string + "constant");
|
||||
// BUG: Diagnostic contains:
|
||||
optional.orElse(string + "constant");
|
||||
// BUG: Diagnostic contains:
|
||||
optional.orElse("constant".toString());
|
||||
// BUG: Diagnostic contains:
|
||||
optional.orElse(string.toString());
|
||||
// BUG: Diagnostic contains:
|
||||
optional.orElse(this.string.toString());
|
||||
// BUG: Diagnostic contains:
|
||||
optional.orElse(String.valueOf(42));
|
||||
// BUG: Diagnostic contains:
|
||||
optional.orElse(string.toString().length());
|
||||
// BUG: Diagnostic contains:
|
||||
optional.orElse("constant".equals(string));
|
||||
// BUG: Diagnostic contains:
|
||||
optional.orElse(string.equals(string));
|
||||
// BUG: Diagnostic contains:
|
||||
optional.orElse(this.string.equals(string));
|
||||
// BUG: Diagnostic contains:
|
||||
optional.orElse(foo());
|
||||
// BUG: Diagnostic contains:
|
||||
optional.orElse(this.foo());
|
||||
// BUG: Diagnostic contains:
|
||||
optional.orElse(new Object() {});
|
||||
// BUG: Diagnostic contains:
|
||||
optional.orElse(new int[0].length);
|
||||
}
|
||||
|
||||
private <T> T foo() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(OptionalOrElseGet.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"""
|
||||
import java.util.Optional;
|
||||
|
||||
class A {
|
||||
private final Optional<Object> optional = Optional.empty();
|
||||
private final String string = optional.toString();
|
||||
|
||||
void m() {
|
||||
optional.orElse(string + "constant");
|
||||
optional.orElse("constant".toString());
|
||||
optional.orElse(string.toString());
|
||||
optional.orElse(this.string.toString());
|
||||
optional.orElse(String.valueOf(42));
|
||||
optional.orElse(string.toString().length());
|
||||
optional.orElse(string.equals(string));
|
||||
optional.orElse(foo());
|
||||
optional.orElse(this.<Number>foo());
|
||||
optional.orElse(this.<String, Integer>bar());
|
||||
optional.orElse(new Object() {});
|
||||
optional.orElse(new int[0].length);
|
||||
}
|
||||
|
||||
private <T> T foo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private <S, T> T bar() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"""
|
||||
import java.util.Optional;
|
||||
|
||||
class A {
|
||||
private final Optional<Object> optional = Optional.empty();
|
||||
private final String string = optional.toString();
|
||||
|
||||
void m() {
|
||||
optional.orElseGet(() -> string + "constant");
|
||||
optional.orElseGet("constant"::toString);
|
||||
optional.orElseGet(string::toString);
|
||||
optional.orElseGet(this.string::toString);
|
||||
optional.orElseGet(() -> String.valueOf(42));
|
||||
optional.orElseGet(() -> string.toString().length());
|
||||
optional.orElseGet(() -> string.equals(string));
|
||||
optional.orElseGet(() -> foo());
|
||||
optional.orElseGet(this::<Number>foo);
|
||||
optional.orElseGet(this::<String, Integer>bar);
|
||||
optional.orElseGet(() -> new Object() {});
|
||||
optional.orElseGet(() -> new int[0].length);
|
||||
}
|
||||
|
||||
private <T> T foo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private <S, T> T bar() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
@@ -15,21 +14,23 @@ final class RedundantStringConversionTest {
|
||||
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" private final Object o = new Object();",
|
||||
" private final String s = o.toString();",
|
||||
"",
|
||||
" String[] m() {",
|
||||
" return new String[] {",
|
||||
" o.toString(),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s.toString(),",
|
||||
" String.valueOf(o),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.valueOf(s),",
|
||||
" };",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
class A {
|
||||
private final Object o = new Object();
|
||||
private final String s = o.toString();
|
||||
|
||||
String[] m() {
|
||||
return new String[] {
|
||||
o.toString(),
|
||||
// BUG: Diagnostic contains:
|
||||
s.toString(),
|
||||
String.valueOf(o),
|
||||
// BUG: Diagnostic contains:
|
||||
String.valueOf(s),
|
||||
};
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -38,59 +39,61 @@ final class RedundantStringConversionTest {
|
||||
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.math.BigInteger;",
|
||||
"import java.util.Objects;",
|
||||
"",
|
||||
"class A {",
|
||||
" private final BigInteger i = BigInteger.ZERO;",
|
||||
"",
|
||||
" void m1() {",
|
||||
" String s = i.toString();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += this.toString();",
|
||||
" s += super.toString();",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += i.toString();",
|
||||
" s += i.toString(16);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += Objects.toString(i);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += Objects.toString(null);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += String.valueOf(i);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += String.valueOf(0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += String.valueOf((String) null);",
|
||||
" s += String.valueOf(null);",
|
||||
" s += String.valueOf(new char[0]);",
|
||||
" s += String.valueOf(new char[0], 0, 0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += Boolean.toString(false);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += Byte.toString((byte) 0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += Character.toString((char) 0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += Short.toString((short) 0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += Integer.toString(0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += Long.toString(0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += Float.toString((float) 0.0);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s += Double.toString(0.0);",
|
||||
" }",
|
||||
"",
|
||||
" void m2() {",
|
||||
" int i = 0;",
|
||||
" i += 1;",
|
||||
" i -= 1;",
|
||||
" i *= 1;",
|
||||
" i /= 1;",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import java.math.BigInteger;
|
||||
import java.util.Objects;
|
||||
|
||||
class A {
|
||||
private final BigInteger i = BigInteger.ZERO;
|
||||
|
||||
void m1() {
|
||||
String s = i.toString();
|
||||
// BUG: Diagnostic contains:
|
||||
s += this.toString();
|
||||
s += super.toString();
|
||||
// BUG: Diagnostic contains:
|
||||
s += i.toString();
|
||||
s += i.toString(16);
|
||||
// BUG: Diagnostic contains:
|
||||
s += Objects.toString(i);
|
||||
// BUG: Diagnostic contains:
|
||||
s += Objects.toString(null);
|
||||
// BUG: Diagnostic contains:
|
||||
s += String.valueOf(i);
|
||||
// BUG: Diagnostic contains:
|
||||
s += String.valueOf(0);
|
||||
// BUG: Diagnostic contains:
|
||||
s += String.valueOf((String) null);
|
||||
s += String.valueOf(null);
|
||||
s += String.valueOf(new char[0]);
|
||||
s += String.valueOf(new char[0], 0, 0);
|
||||
// BUG: Diagnostic contains:
|
||||
s += Boolean.toString(false);
|
||||
// BUG: Diagnostic contains:
|
||||
s += Byte.toString((byte) 0);
|
||||
// BUG: Diagnostic contains:
|
||||
s += Character.toString((char) 0);
|
||||
// BUG: Diagnostic contains:
|
||||
s += Short.toString((short) 0);
|
||||
// BUG: Diagnostic contains:
|
||||
s += Integer.toString(0);
|
||||
// BUG: Diagnostic contains:
|
||||
s += Long.toString(0);
|
||||
// BUG: Diagnostic contains:
|
||||
s += Float.toString((float) 0.0);
|
||||
// BUG: Diagnostic contains:
|
||||
s += Double.toString(0.0);
|
||||
}
|
||||
|
||||
void m2() {
|
||||
int i = 0;
|
||||
i += 1;
|
||||
i -= 1;
|
||||
i *= 1;
|
||||
i /= 1;
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -99,93 +102,95 @@ final class RedundantStringConversionTest {
|
||||
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.math.BigInteger;",
|
||||
"",
|
||||
"class A {",
|
||||
" private final BigInteger i = BigInteger.ZERO;",
|
||||
" private final String s = i.toString();",
|
||||
"",
|
||||
" String[] m1() {",
|
||||
" return new String[] {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + this.toString(),",
|
||||
" s + super.toString(),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + i.toString(),",
|
||||
" s + i.toString(16),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + String.valueOf(i),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + String.valueOf(0),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + String.valueOf((String) null),",
|
||||
" s + String.valueOf(null),",
|
||||
" s + String.valueOf(new char[0]),",
|
||||
" s + String.valueOf(new char[0], 0, 0),",
|
||||
" //",
|
||||
" 42 + this.toString(),",
|
||||
" 42 + super.toString(),",
|
||||
" 42 + i.toString(),",
|
||||
" 42 + i.toString(16),",
|
||||
" 42 + String.valueOf(i),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" 42 + String.valueOf((String) null),",
|
||||
" 42 + String.valueOf(null),",
|
||||
" 42 + String.valueOf(new char[0]),",
|
||||
" 42 + String.valueOf(new char[0], 0, 0),",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" this.toString() + s,",
|
||||
" super.toString() + s,",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" i.toString() + s,",
|
||||
" i.toString(16) + s,",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.valueOf(i) + s,",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.valueOf(0) + s,",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.valueOf((String) null) + s,",
|
||||
" String.valueOf(null) + s,",
|
||||
" String.valueOf(new char[0]) + s,",
|
||||
" String.valueOf(new char[0], 0, 0) + s,",
|
||||
" //",
|
||||
" this.toString() + 42,",
|
||||
" super.toString() + 42,",
|
||||
" i.toString() + 42,",
|
||||
" i.toString(16) + 42,",
|
||||
" String.valueOf(i) + 42,",
|
||||
" String.valueOf(0) + 42,",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.valueOf((String) null) + 42,",
|
||||
" String.valueOf(null) + 42,",
|
||||
" String.valueOf(new char[0]) + 42,",
|
||||
" String.valueOf(new char[0], 0, 0) + 42,",
|
||||
"",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" this.toString() + this.toString(),",
|
||||
" super.toString() + super.toString(),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" i.toString() + i.toString(),",
|
||||
" i.toString(16) + i.toString(16),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.valueOf(i) + String.valueOf(i),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.valueOf(0) + String.valueOf(0),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.valueOf((String) null) + String.valueOf((String) null),",
|
||||
" String.valueOf(null) + String.valueOf(null),",
|
||||
" String.valueOf(new char[0]) + String.valueOf(new char[0]),",
|
||||
" String.valueOf(new char[0], 0, 0) + String.valueOf(new char[0], 0, 0),",
|
||||
" };",
|
||||
" }",
|
||||
"",
|
||||
" int[] m2() {",
|
||||
" return new int[] {",
|
||||
" 1 + 1, 1 - 1, 1 * 1, 1 / 1,",
|
||||
" };",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import java.math.BigInteger;
|
||||
|
||||
class A {
|
||||
private final BigInteger i = BigInteger.ZERO;
|
||||
private final String s = i.toString();
|
||||
|
||||
String[] m1() {
|
||||
return new String[] {
|
||||
// BUG: Diagnostic contains:
|
||||
s + this.toString(),
|
||||
s + super.toString(),
|
||||
// BUG: Diagnostic contains:
|
||||
s + i.toString(),
|
||||
s + i.toString(16),
|
||||
// BUG: Diagnostic contains:
|
||||
s + String.valueOf(i),
|
||||
// BUG: Diagnostic contains:
|
||||
s + String.valueOf(0),
|
||||
// BUG: Diagnostic contains:
|
||||
s + String.valueOf((String) null),
|
||||
s + String.valueOf(null),
|
||||
s + String.valueOf(new char[0]),
|
||||
s + String.valueOf(new char[0], 0, 0),
|
||||
//
|
||||
42 + this.toString(),
|
||||
42 + super.toString(),
|
||||
42 + i.toString(),
|
||||
42 + i.toString(16),
|
||||
42 + String.valueOf(i),
|
||||
// BUG: Diagnostic contains:
|
||||
42 + String.valueOf((String) null),
|
||||
42 + String.valueOf(null),
|
||||
42 + String.valueOf(new char[0]),
|
||||
42 + String.valueOf(new char[0], 0, 0),
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
this.toString() + s,
|
||||
super.toString() + s,
|
||||
// BUG: Diagnostic contains:
|
||||
i.toString() + s,
|
||||
i.toString(16) + s,
|
||||
// BUG: Diagnostic contains:
|
||||
String.valueOf(i) + s,
|
||||
// BUG: Diagnostic contains:
|
||||
String.valueOf(0) + s,
|
||||
// BUG: Diagnostic contains:
|
||||
String.valueOf((String) null) + s,
|
||||
String.valueOf(null) + s,
|
||||
String.valueOf(new char[0]) + s,
|
||||
String.valueOf(new char[0], 0, 0) + s,
|
||||
//
|
||||
this.toString() + 42,
|
||||
super.toString() + 42,
|
||||
i.toString() + 42,
|
||||
i.toString(16) + 42,
|
||||
String.valueOf(i) + 42,
|
||||
String.valueOf(0) + 42,
|
||||
// BUG: Diagnostic contains:
|
||||
String.valueOf((String) null) + 42,
|
||||
String.valueOf(null) + 42,
|
||||
String.valueOf(new char[0]) + 42,
|
||||
String.valueOf(new char[0], 0, 0) + 42,
|
||||
|
||||
// BUG: Diagnostic contains:
|
||||
this.toString() + this.toString(),
|
||||
super.toString() + super.toString(),
|
||||
// BUG: Diagnostic contains:
|
||||
i.toString() + i.toString(),
|
||||
i.toString(16) + i.toString(16),
|
||||
// BUG: Diagnostic contains:
|
||||
String.valueOf(i) + String.valueOf(i),
|
||||
// BUG: Diagnostic contains:
|
||||
String.valueOf(0) + String.valueOf(0),
|
||||
// BUG: Diagnostic contains:
|
||||
String.valueOf((String) null) + String.valueOf((String) null),
|
||||
String.valueOf(null) + String.valueOf(null),
|
||||
String.valueOf(new char[0]) + String.valueOf(new char[0]),
|
||||
String.valueOf(new char[0], 0, 0) + String.valueOf(new char[0], 0, 0),
|
||||
};
|
||||
}
|
||||
|
||||
int[] m2() {
|
||||
return new int[] {
|
||||
1 + 1, 1 - 1, 1 * 1, 1 / 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -194,52 +199,54 @@ final class RedundantStringConversionTest {
|
||||
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.math.BigInteger;",
|
||||
"",
|
||||
"class A {",
|
||||
" private final BigInteger i = BigInteger.ZERO;",
|
||||
" private final String s = i.toString();",
|
||||
"",
|
||||
" void m() {",
|
||||
" StringBuilder sb = new StringBuilder();",
|
||||
"",
|
||||
" sb.append(1);",
|
||||
" sb.append(i);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" sb.append(i.toString());",
|
||||
" sb.append(i.toString(16));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" sb.append(String.valueOf(i));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" sb.append(String.valueOf(0));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" sb.append(String.valueOf((String) null));",
|
||||
" sb.append(String.valueOf(null));",
|
||||
" sb.append(String.valueOf(new char[0]));",
|
||||
" sb.append(String.valueOf(new char[0], 0, 0));",
|
||||
" sb.append(s);",
|
||||
" sb.append(\"constant\");",
|
||||
"",
|
||||
" sb.insert(0, 1);",
|
||||
" sb.insert(0, i);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" sb.insert(0, i.toString());",
|
||||
" sb.insert(0, i.toString(16));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" sb.insert(0, String.valueOf(i));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" sb.insert(0, String.valueOf(0));",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" sb.insert(0, String.valueOf((String) null));",
|
||||
" sb.insert(0, String.valueOf(null));",
|
||||
" sb.insert(0, String.valueOf(new char[0]));",
|
||||
" sb.insert(0, String.valueOf(new char[0], 0, 0));",
|
||||
" sb.insert(0, s);",
|
||||
" sb.insert(0, \"constant\");",
|
||||
"",
|
||||
" sb.replace(0, 1, i.toString());",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import java.math.BigInteger;
|
||||
|
||||
class A {
|
||||
private final BigInteger i = BigInteger.ZERO;
|
||||
private final String s = i.toString();
|
||||
|
||||
void m() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(1);
|
||||
sb.append(i);
|
||||
// BUG: Diagnostic contains:
|
||||
sb.append(i.toString());
|
||||
sb.append(i.toString(16));
|
||||
// BUG: Diagnostic contains:
|
||||
sb.append(String.valueOf(i));
|
||||
// BUG: Diagnostic contains:
|
||||
sb.append(String.valueOf(0));
|
||||
// BUG: Diagnostic contains:
|
||||
sb.append(String.valueOf((String) null));
|
||||
sb.append(String.valueOf(null));
|
||||
sb.append(String.valueOf(new char[0]));
|
||||
sb.append(String.valueOf(new char[0], 0, 0));
|
||||
sb.append(s);
|
||||
sb.append("constant");
|
||||
|
||||
sb.insert(0, 1);
|
||||
sb.insert(0, i);
|
||||
// BUG: Diagnostic contains:
|
||||
sb.insert(0, i.toString());
|
||||
sb.insert(0, i.toString(16));
|
||||
// BUG: Diagnostic contains:
|
||||
sb.insert(0, String.valueOf(i));
|
||||
// BUG: Diagnostic contains:
|
||||
sb.insert(0, String.valueOf(0));
|
||||
// BUG: Diagnostic contains:
|
||||
sb.insert(0, String.valueOf((String) null));
|
||||
sb.insert(0, String.valueOf(null));
|
||||
sb.insert(0, String.valueOf(new char[0]));
|
||||
sb.insert(0, String.valueOf(new char[0], 0, 0));
|
||||
sb.insert(0, s);
|
||||
sb.insert(0, "constant");
|
||||
|
||||
sb.replace(0, 1, i.toString());
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -249,43 +256,45 @@ final class RedundantStringConversionTest {
|
||||
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.Formattable;",
|
||||
"import java.util.Locale;",
|
||||
"",
|
||||
"class A {",
|
||||
" private final Locale locale = Locale.ROOT;",
|
||||
" private final Formattable f = (formatter, flags, width, precision) -> {};",
|
||||
" private final Object o = new Object();",
|
||||
" private final String s = o.toString();",
|
||||
"",
|
||||
" void m() {",
|
||||
" String.format(s, f);",
|
||||
" String.format(s, o);",
|
||||
" String.format(s, s);",
|
||||
" String.format(s, f.toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(s, o.toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(s, String.valueOf(o));",
|
||||
"",
|
||||
" String.format(locale, s, f);",
|
||||
" String.format(locale, s, o);",
|
||||
" String.format(locale, s, s);",
|
||||
" String.format(locale, s, f.toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(locale, s, o.toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(locale, s, String.valueOf(o));",
|
||||
"",
|
||||
" String.format(o.toString(), o);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(s.toString(), o);",
|
||||
" String.format(locale.toString(), s, o);",
|
||||
" String.format(locale, o.toString(), o);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" String.format(locale, s.toString(), o);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import java.util.Formattable;
|
||||
import java.util.Locale;
|
||||
|
||||
class A {
|
||||
private final Locale locale = Locale.ROOT;
|
||||
private final Formattable f = (formatter, flags, width, precision) -> {};
|
||||
private final Object o = new Object();
|
||||
private final String s = o.toString();
|
||||
|
||||
void m() {
|
||||
String.format(s, f);
|
||||
String.format(s, o);
|
||||
String.format(s, s);
|
||||
String.format(s, f.toString());
|
||||
// BUG: Diagnostic contains:
|
||||
String.format(s, o.toString());
|
||||
// BUG: Diagnostic contains:
|
||||
String.format(s, String.valueOf(o));
|
||||
|
||||
String.format(locale, s, f);
|
||||
String.format(locale, s, o);
|
||||
String.format(locale, s, s);
|
||||
String.format(locale, s, f.toString());
|
||||
// BUG: Diagnostic contains:
|
||||
String.format(locale, s, o.toString());
|
||||
// BUG: Diagnostic contains:
|
||||
String.format(locale, s, String.valueOf(o));
|
||||
|
||||
String.format(o.toString(), o);
|
||||
// BUG: Diagnostic contains:
|
||||
String.format(s.toString(), o);
|
||||
String.format(locale.toString(), s, o);
|
||||
String.format(locale, o.toString(), o);
|
||||
// BUG: Diagnostic contains:
|
||||
String.format(locale, s.toString(), o);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -294,58 +303,60 @@ final class RedundantStringConversionTest {
|
||||
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import static com.google.common.base.Preconditions.checkArgument;",
|
||||
"import static com.google.common.base.Preconditions.checkNotNull;",
|
||||
"import static com.google.common.base.Preconditions.checkState;",
|
||||
"import static com.google.common.base.Verify.verify;",
|
||||
"import static com.google.common.base.Verify.verifyNotNull;",
|
||||
"",
|
||||
"import java.util.Formattable;",
|
||||
"",
|
||||
"class A {",
|
||||
" private final Formattable f = (formatter, flags, width, precision) -> {};",
|
||||
" private final Object o = new Object();",
|
||||
" private final String s = o.toString();",
|
||||
"",
|
||||
" void m() {",
|
||||
" checkState(true, s, f);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkState(true, s, f.toString());",
|
||||
" checkState(true, f.toString(), f);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkState(true, s.toString(), f);",
|
||||
"",
|
||||
" checkArgument(true, s, f);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkArgument(true, s, f.toString());",
|
||||
" checkArgument(true, f.toString(), f);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkArgument(true, s.toString(), f);",
|
||||
"",
|
||||
" checkNotNull(o, s, f);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkNotNull(o, s, f.toString());",
|
||||
" checkNotNull(o, f.toString(), f);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" checkNotNull(o, s.toString(), f);",
|
||||
" checkNotNull(o.toString(), s, f);",
|
||||
"",
|
||||
" verify(true, s, f);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" verify(true, s, f.toString());",
|
||||
" verify(true, f.toString(), f);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" verify(true, s.toString(), f);",
|
||||
"",
|
||||
" verifyNotNull(o, s, f);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" verifyNotNull(o, s, f.toString());",
|
||||
" verifyNotNull(o, f.toString(), f);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" verifyNotNull(o, s.toString(), f);",
|
||||
" verifyNotNull(o.toString(), s, f);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.base.Verify.verify;
|
||||
import static com.google.common.base.Verify.verifyNotNull;
|
||||
|
||||
import java.util.Formattable;
|
||||
|
||||
class A {
|
||||
private final Formattable f = (formatter, flags, width, precision) -> {};
|
||||
private final Object o = new Object();
|
||||
private final String s = o.toString();
|
||||
|
||||
void m() {
|
||||
checkState(true, s, f);
|
||||
// BUG: Diagnostic contains:
|
||||
checkState(true, s, f.toString());
|
||||
checkState(true, f.toString(), f);
|
||||
// BUG: Diagnostic contains:
|
||||
checkState(true, s.toString(), f);
|
||||
|
||||
checkArgument(true, s, f);
|
||||
// BUG: Diagnostic contains:
|
||||
checkArgument(true, s, f.toString());
|
||||
checkArgument(true, f.toString(), f);
|
||||
// BUG: Diagnostic contains:
|
||||
checkArgument(true, s.toString(), f);
|
||||
|
||||
checkNotNull(o, s, f);
|
||||
// BUG: Diagnostic contains:
|
||||
checkNotNull(o, s, f.toString());
|
||||
checkNotNull(o, f.toString(), f);
|
||||
// BUG: Diagnostic contains:
|
||||
checkNotNull(o, s.toString(), f);
|
||||
checkNotNull(o.toString(), s, f);
|
||||
|
||||
verify(true, s, f);
|
||||
// BUG: Diagnostic contains:
|
||||
verify(true, s, f.toString());
|
||||
verify(true, f.toString(), f);
|
||||
// BUG: Diagnostic contains:
|
||||
verify(true, s.toString(), f);
|
||||
|
||||
verifyNotNull(o, s, f);
|
||||
// BUG: Diagnostic contains:
|
||||
verifyNotNull(o, s, f.toString());
|
||||
verifyNotNull(o, f.toString(), f);
|
||||
// BUG: Diagnostic contains:
|
||||
verifyNotNull(o, s.toString(), f);
|
||||
verifyNotNull(o.toString(), s, f);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -354,53 +365,55 @@ final class RedundantStringConversionTest {
|
||||
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.util.Formattable;",
|
||||
"import org.slf4j.Logger;",
|
||||
"import org.slf4j.LoggerFactory;",
|
||||
"import org.slf4j.Marker;",
|
||||
"import org.slf4j.MarkerFactory;",
|
||||
"",
|
||||
"class A {",
|
||||
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
|
||||
"",
|
||||
" private final Marker marker = MarkerFactory.getMarker(A.class.getName());",
|
||||
" private final Formattable f = (formatter, flags, width, precision) -> {};",
|
||||
" private final Object o = new Object();",
|
||||
" private final String s = f.toString();",
|
||||
" private final Throwable t = new Throwable();",
|
||||
"",
|
||||
" void m() {",
|
||||
" LOG.trace(s, f);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug(s, f.toString());",
|
||||
" LOG.info(s, t.toString());",
|
||||
" LOG.warn(s, o, t.toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.error(s, o.toString(), t.toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.trace(s, t.toString(), o);",
|
||||
"",
|
||||
" LOG.trace(marker, s, f);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug(marker, s, f.toString());",
|
||||
" LOG.info(marker, s, t.toString());",
|
||||
" LOG.warn(marker, s, o, t.toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.error(marker, s, o.toString(), t.toString());",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.trace(marker, s, t.toString(), o);",
|
||||
"",
|
||||
" LOG.trace(f.toString(), f);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.debug(s.toString(), f);",
|
||||
" LOG.info(t.toString(), f);",
|
||||
" LOG.warn(marker.toString(), s, f);",
|
||||
" LOG.error(marker, o.toString(), f);",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" LOG.trace(marker, s.toString(), f);",
|
||||
" LOG.debug(marker, t.toString(), f);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import java.util.Formattable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.Marker;
|
||||
import org.slf4j.MarkerFactory;
|
||||
|
||||
class A {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(A.class);
|
||||
|
||||
private final Marker marker = MarkerFactory.getMarker(A.class.getName());
|
||||
private final Formattable f = (formatter, flags, width, precision) -> {};
|
||||
private final Object o = new Object();
|
||||
private final String s = f.toString();
|
||||
private final Throwable t = new Throwable();
|
||||
|
||||
void m() {
|
||||
LOG.trace(s, f);
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.debug(s, f.toString());
|
||||
LOG.info(s, t.toString());
|
||||
LOG.warn(s, o, t.toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.error(s, o.toString(), t.toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.trace(s, t.toString(), o);
|
||||
|
||||
LOG.trace(marker, s, f);
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.debug(marker, s, f.toString());
|
||||
LOG.info(marker, s, t.toString());
|
||||
LOG.warn(marker, s, o, t.toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.error(marker, s, o.toString(), t.toString());
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.trace(marker, s, t.toString(), o);
|
||||
|
||||
LOG.trace(f.toString(), f);
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.debug(s.toString(), f);
|
||||
LOG.info(t.toString(), f);
|
||||
LOG.warn(marker.toString(), s, f);
|
||||
LOG.error(marker, o.toString(), f);
|
||||
// BUG: Diagnostic contains:
|
||||
LOG.trace(marker, s.toString(), f);
|
||||
LOG.debug(marker, t.toString(), f);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -408,95 +421,96 @@ final class RedundantStringConversionTest {
|
||||
void identificationOfCustomConversionMethod() {
|
||||
CompilationTestHelper.newInstance(RedundantStringConversion.class, getClass())
|
||||
.setArgs(
|
||||
ImmutableList.of(
|
||||
"-XepOpt:RedundantStringConversion:ExtraConversionMethods=java.lang.Enum#name(),A#name(),A.B#toString(int)"))
|
||||
"-XepOpt:RedundantStringConversion:ExtraConversionMethods=java.lang.Enum#name(),A#name(),A.B#toString(int)")
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import java.math.RoundingMode;",
|
||||
"import java.util.Objects;",
|
||||
"",
|
||||
"class A {",
|
||||
" static class B {",
|
||||
" String name() {",
|
||||
" return toString();",
|
||||
" }",
|
||||
"",
|
||||
" static String toString(int i) {",
|
||||
" return Integer.toString(i);",
|
||||
" }",
|
||||
"",
|
||||
" static String toString(int i, int j) {",
|
||||
" return Integer.toString(i * j);",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" enum E {",
|
||||
" ELEM;",
|
||||
"",
|
||||
" public String toString() {",
|
||||
" return \"__\" + name() + \"__\";",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" private final B b = new B();",
|
||||
" private final String s = b.toString();",
|
||||
"",
|
||||
" String[] builtin() {",
|
||||
" return new String[] {",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + b.toString(),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + Objects.toString(b),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + String.valueOf(b),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + Boolean.toString(false),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + Byte.toString((byte) 0),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + Character.toString((char) 0),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + Short.toString((short) 0),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + Integer.toString(0),",
|
||||
" s + Integer.toString(0, 16),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + Long.toString(0),",
|
||||
" s + Long.toString(0, 16),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + Float.toString((float) 0.0),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + Double.toString(0.0),",
|
||||
" };",
|
||||
" }",
|
||||
"",
|
||||
" String[] custom() {",
|
||||
" return new String[] {",
|
||||
" s + b.name(),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + RoundingMode.UP.name(),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + mode().name(),",
|
||||
" s + A.name(),",
|
||||
" s + A.toString(42),",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" s + B.toString(42),",
|
||||
" s + B.toString(42, 42),",
|
||||
" };",
|
||||
" }",
|
||||
"",
|
||||
" static String name() {",
|
||||
" return A.class.toString();",
|
||||
" }",
|
||||
"",
|
||||
" RoundingMode mode() {",
|
||||
" return RoundingMode.UP;",
|
||||
" }",
|
||||
"",
|
||||
" static String toString(int i) {",
|
||||
" return Integer.toString(i);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Objects;
|
||||
|
||||
class A {
|
||||
static class B {
|
||||
String name() {
|
||||
return toString();
|
||||
}
|
||||
|
||||
static String toString(int i) {
|
||||
return Integer.toString(i);
|
||||
}
|
||||
|
||||
static String toString(int i, int j) {
|
||||
return Integer.toString(i * j);
|
||||
}
|
||||
}
|
||||
|
||||
enum E {
|
||||
ELEM;
|
||||
|
||||
public String toString() {
|
||||
return "__" + name() + "__";
|
||||
}
|
||||
}
|
||||
|
||||
private final B b = new B();
|
||||
private final String s = b.toString();
|
||||
|
||||
String[] builtin() {
|
||||
return new String[] {
|
||||
// BUG: Diagnostic contains:
|
||||
s + b.toString(),
|
||||
// BUG: Diagnostic contains:
|
||||
s + Objects.toString(b),
|
||||
// BUG: Diagnostic contains:
|
||||
s + String.valueOf(b),
|
||||
// BUG: Diagnostic contains:
|
||||
s + Boolean.toString(false),
|
||||
// BUG: Diagnostic contains:
|
||||
s + Byte.toString((byte) 0),
|
||||
// BUG: Diagnostic contains:
|
||||
s + Character.toString((char) 0),
|
||||
// BUG: Diagnostic contains:
|
||||
s + Short.toString((short) 0),
|
||||
// BUG: Diagnostic contains:
|
||||
s + Integer.toString(0),
|
||||
s + Integer.toString(0, 16),
|
||||
// BUG: Diagnostic contains:
|
||||
s + Long.toString(0),
|
||||
s + Long.toString(0, 16),
|
||||
// BUG: Diagnostic contains:
|
||||
s + Float.toString((float) 0.0),
|
||||
// BUG: Diagnostic contains:
|
||||
s + Double.toString(0.0),
|
||||
};
|
||||
}
|
||||
|
||||
String[] custom() {
|
||||
return new String[] {
|
||||
s + b.name(),
|
||||
// BUG: Diagnostic contains:
|
||||
s + RoundingMode.UP.name(),
|
||||
// BUG: Diagnostic contains:
|
||||
s + mode().name(),
|
||||
s + A.name(),
|
||||
s + A.toString(42),
|
||||
// BUG: Diagnostic contains:
|
||||
s + B.toString(42),
|
||||
s + B.toString(42, 42),
|
||||
};
|
||||
}
|
||||
|
||||
static String name() {
|
||||
return A.class.toString();
|
||||
}
|
||||
|
||||
RoundingMode mode() {
|
||||
return RoundingMode.UP;
|
||||
}
|
||||
|
||||
static String toString(int i) {
|
||||
return Integer.toString(i);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@@ -505,32 +519,36 @@ final class RedundantStringConversionTest {
|
||||
BugCheckerRefactoringTestHelper.newInstance(RedundantStringConversion.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" private final Object o = new Object();",
|
||||
" private final String s = o.toString();",
|
||||
"",
|
||||
" void m() {",
|
||||
" String v1 = s.toString();",
|
||||
" String v2 = \"foo\".toString();",
|
||||
" String v3 = v2 + super.toString();",
|
||||
" String v4 = 42 + String.valueOf((String) null);",
|
||||
" String.format(\"%s\", o.toString());",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
class A {
|
||||
private final Object o = new Object();
|
||||
private final String s = o.toString();
|
||||
|
||||
void m() {
|
||||
String v1 = s.toString();
|
||||
String v2 = "foo".toString();
|
||||
String v3 = v2 + super.toString();
|
||||
String v4 = 42 + String.valueOf((String) null);
|
||||
String.format("%s", o.toString());
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"class A {",
|
||||
" private final Object o = new Object();",
|
||||
" private final String s = o.toString();",
|
||||
"",
|
||||
" void m() {",
|
||||
" String v1 = s;",
|
||||
" String v2 = \"foo\";",
|
||||
" String v3 = v2 + super.toString();",
|
||||
" String v4 = 42 + (String) null;",
|
||||
" String.format(\"%s\", o);",
|
||||
" }",
|
||||
"}")
|
||||
"""
|
||||
class A {
|
||||
private final Object o = new Object();
|
||||
private final String s = o.toString();
|
||||
|
||||
void m() {
|
||||
String v1 = s;
|
||||
String v2 = "foo";
|
||||
String v3 = v2 + super.toString();
|
||||
String v4 = 42 + (String) null;
|
||||
String.format("%s", o);
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package tech.picnic.errorprone.bugpatterns;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class RedundantStringEscapeTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(RedundantStringEscape.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"""
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
class A {
|
||||
List<String> m() {
|
||||
return Arrays.asList(
|
||||
"foo",
|
||||
"ß",
|
||||
"'",
|
||||
"\\"",
|
||||
"\\\\",
|
||||
"\\\\'",
|
||||
"'\\\\",
|
||||
// BUG: Diagnostic contains:
|
||||
"\\\\\\'",
|
||||
// BUG: Diagnostic contains:
|
||||
"\\'\\\\",
|
||||
// BUG: Diagnostic contains:
|
||||
"\\'",
|
||||
// BUG: Diagnostic contains:
|
||||
"'\\'",
|
||||
// BUG: Diagnostic contains:
|
||||
"\\''",
|
||||
// BUG: Diagnostic contains:
|
||||
"\\'\\'",
|
||||
(
|
||||
// BUG: Diagnostic contains:
|
||||
/* Leading comment. */ "\\'" /* Trailing comment. */),
|
||||
// BUG: Diagnostic contains:
|
||||
"\\'foo\\"bar\\'baz\\"qux\\'");
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(RedundantStringEscape.class, getClass())
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"""
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
class A {
|
||||
List<String> m() {
|
||||
return Arrays.asList(
|
||||
"\\'",
|
||||
"'\\'",
|
||||
"\\''",
|
||||
"\\'\\'",
|
||||
"\\'ß\\'",
|
||||
(
|
||||
/* Leading comment. */ "\\'" /* Trailing comment. */),
|
||||
"\\'foo\\"bar\\'baz\\"qux\\'");
|
||||
}
|
||||
}
|
||||
""")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"""
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
class A {
|
||||
List<String> m() {
|
||||
return Arrays.asList(
|
||||
"'",
|
||||
"''",
|
||||
"''",
|
||||
"''",
|
||||
"'ß'",
|
||||
(
|
||||
/* Leading comment. */ "'" /* Trailing comment. */),
|
||||
"'foo\\"bar'baz\\"qux'");
|
||||
}
|
||||
}
|
||||
""")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -9,138 +9,140 @@ final class RequestMappingAnnotationTest {
|
||||
CompilationTestHelper.newInstance(RequestMappingAnnotation.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import jakarta.servlet.http.HttpServletRequest;",
|
||||
"import jakarta.servlet.http.HttpServletResponse;",
|
||||
"import java.io.InputStream;",
|
||||
"import java.time.ZoneId;",
|
||||
"import java.util.Locale;",
|
||||
"import java.util.TimeZone;",
|
||||
"import org.springframework.http.HttpMethod;",
|
||||
"import org.springframework.security.core.annotation.CurrentSecurityContext;",
|
||||
"import org.springframework.ui.Model;",
|
||||
"import org.springframework.validation.BindingResult;",
|
||||
"import org.springframework.web.bind.annotation.DeleteMapping;",
|
||||
"import org.springframework.web.bind.annotation.GetMapping;",
|
||||
"import org.springframework.web.bind.annotation.PatchMapping;",
|
||||
"import org.springframework.web.bind.annotation.PathVariable;",
|
||||
"import org.springframework.web.bind.annotation.PostMapping;",
|
||||
"import org.springframework.web.bind.annotation.PutMapping;",
|
||||
"import org.springframework.web.bind.annotation.RequestAttribute;",
|
||||
"import org.springframework.web.bind.annotation.RequestBody;",
|
||||
"import org.springframework.web.bind.annotation.RequestHeader;",
|
||||
"import org.springframework.web.bind.annotation.RequestMapping;",
|
||||
"import org.springframework.web.bind.annotation.RequestParam;",
|
||||
"import org.springframework.web.bind.annotation.RequestPart;",
|
||||
"import org.springframework.web.context.request.NativeWebRequest;",
|
||||
"import org.springframework.web.context.request.WebRequest;",
|
||||
"import org.springframework.web.server.ServerWebExchange;",
|
||||
"import org.springframework.web.util.UriBuilder;",
|
||||
"import org.springframework.web.util.UriComponentsBuilder;",
|
||||
"",
|
||||
"interface A {",
|
||||
" A noMapping();",
|
||||
"",
|
||||
" A noMapping(String param);",
|
||||
"",
|
||||
" @DeleteMapping",
|
||||
" A properNoParameters();",
|
||||
"",
|
||||
" @GetMapping",
|
||||
" A properPathVariable(@PathVariable String param);",
|
||||
"",
|
||||
" @PatchMapping",
|
||||
" A properRequestAttribute(@RequestAttribute String attribute);",
|
||||
"",
|
||||
" @PostMapping",
|
||||
" A properRequestBody(@RequestBody String body);",
|
||||
"",
|
||||
" @PutMapping",
|
||||
" A properRequestHeader(@RequestHeader String header);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properRequestParam(@RequestParam String param);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properRequestPart(@RequestPart String part);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properCurrentSecurityContext(",
|
||||
" @CurrentSecurityContext(expression = \"authentication.name\") String user);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properInputStream(InputStream input);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properZoneId(ZoneId zoneId);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properLocale(Locale locale);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properTimeZone(TimeZone timeZone);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properHttpServletRequest(HttpServletRequest request);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properHttpServletResponse(HttpServletResponse response);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properHttpMethod(HttpMethod method);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properModel(Model model);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properBindingResult(BindingResult result);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properNativeWebRequest(NativeWebRequest request);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properWebRequest(WebRequest request);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properServerWebExchange(ServerWebExchange exchange);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properServerUriBuilder(UriBuilder builder);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" A properServerUriComponentsBuilder(UriComponentsBuilder builder);",
|
||||
"",
|
||||
" @DeleteMapping",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" A delete(String param);",
|
||||
"",
|
||||
" @GetMapping",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" A get(String param);",
|
||||
"",
|
||||
" @PatchMapping",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" A patch(String param);",
|
||||
"",
|
||||
" @PostMapping",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" A post(String param);",
|
||||
"",
|
||||
" @PutMapping",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" A put(String param);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" A requestMultiple(String param, String param2);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" A requestFirstParamViolation(String param, @PathVariable String param2);",
|
||||
"",
|
||||
" @RequestMapping",
|
||||
" // BUG: Diagnostic contains:",
|
||||
" A requestSecondParamViolation(@RequestBody String param, String param2);",
|
||||
"}")
|
||||
"""
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.InputStream;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.core.annotation.CurrentSecurityContext;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.util.UriBuilder;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
interface A {
|
||||
A noMapping();
|
||||
|
||||
A noMapping(String param);
|
||||
|
||||
@DeleteMapping
|
||||
A properNoParameters();
|
||||
|
||||
@GetMapping
|
||||
A properPathVariable(@PathVariable String param);
|
||||
|
||||
@PatchMapping
|
||||
A properRequestAttribute(@RequestAttribute String attribute);
|
||||
|
||||
@PostMapping
|
||||
A properRequestBody(@RequestBody String body);
|
||||
|
||||
@PutMapping
|
||||
A properRequestHeader(@RequestHeader String header);
|
||||
|
||||
@RequestMapping
|
||||
A properRequestParam(@RequestParam String param);
|
||||
|
||||
@RequestMapping
|
||||
A properRequestPart(@RequestPart String part);
|
||||
|
||||
@RequestMapping
|
||||
A properCurrentSecurityContext(
|
||||
@CurrentSecurityContext(expression = "authentication.name") String user);
|
||||
|
||||
@RequestMapping
|
||||
A properInputStream(InputStream input);
|
||||
|
||||
@RequestMapping
|
||||
A properZoneId(ZoneId zoneId);
|
||||
|
||||
@RequestMapping
|
||||
A properLocale(Locale locale);
|
||||
|
||||
@RequestMapping
|
||||
A properTimeZone(TimeZone timeZone);
|
||||
|
||||
@RequestMapping
|
||||
A properHttpServletRequest(HttpServletRequest request);
|
||||
|
||||
@RequestMapping
|
||||
A properHttpServletResponse(HttpServletResponse response);
|
||||
|
||||
@RequestMapping
|
||||
A properHttpMethod(HttpMethod method);
|
||||
|
||||
@RequestMapping
|
||||
A properModel(Model model);
|
||||
|
||||
@RequestMapping
|
||||
A properBindingResult(BindingResult result);
|
||||
|
||||
@RequestMapping
|
||||
A properNativeWebRequest(NativeWebRequest request);
|
||||
|
||||
@RequestMapping
|
||||
A properWebRequest(WebRequest request);
|
||||
|
||||
@RequestMapping
|
||||
A properServerWebExchange(ServerWebExchange exchange);
|
||||
|
||||
@RequestMapping
|
||||
A properServerUriBuilder(UriBuilder builder);
|
||||
|
||||
@RequestMapping
|
||||
A properServerUriComponentsBuilder(UriComponentsBuilder builder);
|
||||
|
||||
@DeleteMapping
|
||||
// BUG: Diagnostic contains:
|
||||
A delete(String param);
|
||||
|
||||
@GetMapping
|
||||
// BUG: Diagnostic contains:
|
||||
A get(String param);
|
||||
|
||||
@PatchMapping
|
||||
// BUG: Diagnostic contains:
|
||||
A patch(String param);
|
||||
|
||||
@PostMapping
|
||||
// BUG: Diagnostic contains:
|
||||
A post(String param);
|
||||
|
||||
@PutMapping
|
||||
// BUG: Diagnostic contains:
|
||||
A put(String param);
|
||||
|
||||
@RequestMapping
|
||||
// BUG: Diagnostic contains:
|
||||
A requestMultiple(String param, String param2);
|
||||
|
||||
@RequestMapping
|
||||
// BUG: Diagnostic contains:
|
||||
A requestFirstParamViolation(String param, @PathVariable String param2);
|
||||
|
||||
@RequestMapping
|
||||
// BUG: Diagnostic contains:
|
||||
A requestSecondParamViolation(@RequestBody String param, String param2);
|
||||
}
|
||||
""")
|
||||
.doTest();
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user