mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 08:11:25 +00:00
Compare commits
90 Commits
v0.16.1
...
sschroever
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5f825b9ff | ||
|
|
d85f2dd6a8 | ||
|
|
2b7a555c05 | ||
|
|
ca85533b0d | ||
|
|
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 |
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"
|
||||
|
||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
continue-on-error: ${{ matrix.experimental }}
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
|
||||
6
.github/workflows/codeql.yml
vendored
6
.github/workflows/codeql.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -39,13 +39,13 @@ jobs:
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
|
||||
uses: github/codeql-action/init@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1
|
||||
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@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1
|
||||
with:
|
||||
category: /language:${{ matrix.language }}
|
||||
|
||||
12
.github/workflows/deploy-website.yml
vendored
12
.github/workflows/deploy-website.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
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@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 # v1.172.0
|
||||
- uses: ruby/setup-ruby@6bd3d993c602f6b675728ebaecb2b569ff86e99b # v1.174.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
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
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@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
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
|
||||
|
||||
6
.github/workflows/openssf-scorecard.yml
vendored
6
.github/workflows/openssf-scorecard.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
tuf-repo-cdn.sigstore.dev:443
|
||||
www.bestpractices.dev:443
|
||||
- name: Check out code
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run OpenSSF Scorecard analysis
|
||||
@@ -46,6 +46,6 @@ jobs:
|
||||
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@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
4
.github/workflows/pitest-analyze-pr.yml
vendored
4
.github/workflows/pitest-analyze-pr.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -36,7 +36,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@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: pitest-reports
|
||||
path: ./target/pit-reports-ci
|
||||
|
||||
4
.github/workflows/pitest-update-pr.yml
vendored
4
.github/workflows/pitest-update-pr.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
java-distribution: temurin
|
||||
maven-version: 3.9.6
|
||||
- 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
|
||||
|
||||
4
.github/workflows/run-integration-tests.yml
vendored
4
.github/workflows/run-integration-tests.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
run: xvfb-run ./integration-tests/checkstyle.sh "${{ runner.temp }}/artifacts"
|
||||
- name: Upload artifacts on failure
|
||||
if: ${{ failure() }}
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: integration-test-checkstyle
|
||||
path: "${{ runner.temp }}/artifacts"
|
||||
|
||||
2
.github/workflows/sonarcloud.yml
vendored
2
.github/workflows/sonarcloud.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Harden-Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
|
||||
with:
|
||||
disable-sudo: true
|
||||
egress-policy: block
|
||||
|
||||
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 |
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>documentation-support</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-contrib</artifactId>
|
||||
@@ -179,6 +179,11 @@
|
||||
<artifactId>mongodb-driver-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openrewrite</groupId>
|
||||
<artifactId>rewrite-core</artifactId>
|
||||
@@ -272,6 +277,11 @@
|
||||
<artifactId>refaster-compiler</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>refaster-rule-benchmark-generator</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>refaster-support</artifactId>
|
||||
@@ -280,6 +290,7 @@
|
||||
</annotationProcessorPaths>
|
||||
<compilerArgs combine.children="append">
|
||||
<arg>-Xplugin:DocumentationGenerator -XoutputDirectory=${project.build.directory}/docs</arg>
|
||||
<arg>-Xplugin:RefasterRuleBenchmarkGenerator -XoutputDirectory=${project.build.directory}/generated-test-sources/test-annotations</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -192,7 +192,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 +203,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);
|
||||
|
||||
|
||||
@@ -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,135 @@
|
||||
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.google.errorprone.util.ASTHelpers;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.IdentifierTree;
|
||||
import com.sun.source.tree.LiteralTree;
|
||||
import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import tech.picnic.errorprone.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: Consider also implementing the inverse, in which `.orElseGet(() -> someConstant)` is
|
||||
// flagged.
|
||||
// XXX: Once the `MethodReferenceUsageCheck` becomes generally usable, consider leaving the method
|
||||
// reference cleanup to that check, and express the remainder of the logic in this class using a
|
||||
// Refaster template, i.c.w. a `@Matches` constraint that implements the `requiresComputation`
|
||||
// logic.
|
||||
@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 OptionalOrElse extends BugChecker implements MethodInvocationTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Matcher<ExpressionTree> OPTIONAL_OR_ELSE_METHOD =
|
||||
instanceMethod().onExactClass(Optional.class.getCanonicalName()).namedAnyOf("orElse");
|
||||
// XXX: Also exclude invocations of `@Placeholder`-annotated methods.
|
||||
private static final Matcher<ExpressionTree> REFASTER_METHOD =
|
||||
staticMethod().onClass(Refaster.class.getCanonicalName());
|
||||
|
||||
/** Instantiates a new {@link OptionalOrElse} instance. */
|
||||
public OptionalOrElse() {}
|
||||
|
||||
@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 (!requiresComputation(argument) || 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given expression contains anything other than a literal or a (possibly
|
||||
* dereferenced) variable or constant.
|
||||
*/
|
||||
private static boolean requiresComputation(ExpressionTree tree) {
|
||||
return !(tree instanceof IdentifierTree
|
||||
|| tree instanceof LiteralTree
|
||||
|| (tree instanceof MemberSelectTree memberSelect
|
||||
&& !requiresComputation(memberSelect.getExpression()))
|
||||
|| ASTHelpers.constValue(tree) != null);
|
||||
}
|
||||
|
||||
/** Returns the nullary method reference matching the given expression, if any. */
|
||||
private static Optional<String> tryMethodReferenceConversion(
|
||||
ExpressionTree tree, VisitorState state) {
|
||||
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 (requiresComputation(memberSelect.getExpression())) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -22,9 +22,12 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import reactor.core.publisher.Mono;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
|
||||
/**
|
||||
@@ -211,6 +214,27 @@ final class AssortedRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't defer to subscription-time non-reactive operations that can efficiently be performed
|
||||
* during assembly.
|
||||
*/
|
||||
// XXX: There are all kinds of variations on this theme. Generalize.
|
||||
// XXX: Drop or move to `ReactorRules`.
|
||||
static final class MonoFromSupplierOptionalMapOrElse<T, S> {
|
||||
@BeforeTemplate
|
||||
Mono<S> before(Optional<T> optional, Function<? super T, S> transformer, S value) {
|
||||
return Refaster.anyOf(
|
||||
Mono.justOrEmpty(optional).map(transformer),
|
||||
Mono.justOrEmpty(optional).mapNotNull(transformer))
|
||||
.defaultIfEmpty(value);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<? extends S> after(Optional<T> optional, Function<? super T, S> transformer, S value) {
|
||||
return Mono.fromSupplier(() -> optional.map(transformer).orElse(value));
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Don't unnecessarily pass a method reference to {@link Supplier#get()} or wrap this method
|
||||
// * in a lambda expression.
|
||||
|
||||
@@ -39,7 +39,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) {
|
||||
|
||||
@@ -16,8 +16,11 @@ 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;
|
||||
@@ -92,6 +95,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
|
||||
@@ -269,7 +290,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,7 +305,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.min(value1, value2, cmp);
|
||||
}
|
||||
}
|
||||
@@ -336,7 +357,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 +372,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 +440,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,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
|
||||
|
||||
@@ -27,6 +27,19 @@ import tech.picnic.errorprone.refaster.matchers.IsLikelyTrivialComputation;
|
||||
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.
|
||||
@@ -114,6 +127,20 @@ final class OptionalRules {
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link Optional#equals(Object)} over more contrived alternatives. */
|
||||
static final class NotOptionalEqualsOptional<T, S> {
|
||||
@BeforeTemplate
|
||||
boolean before(Optional<T> optional, S value) {
|
||||
return Refaster.anyOf(
|
||||
optional.filter(value::equals).isEmpty(), optional.stream().noneMatch(value::equals));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
boolean after(Optional<T> optional, S value) {
|
||||
return !optional.equals(Optional.of(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't use the ternary operator to extract the first element of a possibly-empty {@link
|
||||
* Iterator} as an {@link Optional}.
|
||||
@@ -360,7 +387,7 @@ 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("NestedOptionals")
|
||||
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.
|
||||
@@ -386,9 +413,13 @@ final class OptionalRules {
|
||||
*/
|
||||
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 +473,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
|
||||
|
||||
@@ -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;
|
||||
@@ -52,9 +51,9 @@ 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.IsLikelyTrivialComputation;
|
||||
import tech.picnic.errorprone.refaster.matchers.ThrowsCheckedException;
|
||||
|
||||
/** Refaster rules related to Reactor expressions and statements. */
|
||||
@@ -174,6 +173,7 @@ final class ReactorRules {
|
||||
*
|
||||
* <p>In particular, avoid mixing of the {@link Optional} and {@link Mono} APIs.
|
||||
*/
|
||||
// XXX: Below we now have the opposite advice. Test.
|
||||
static final class MonoFromOptionalSwitchIfEmpty<T> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(Optional<T> optional, Mono<T> mono) {
|
||||
@@ -303,6 +303,38 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't eagerly instantiate {@link Throwable}s for {@link Mono#error(Throwable)}; let the
|
||||
* framework do it on subscription.
|
||||
*/
|
||||
static final class MonoError<T> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(@NotMatches(IsLikelyTrivialComputation.class) Throwable throwable) {
|
||||
return Mono.error(throwable);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(Throwable throwable) {
|
||||
return Mono.error(() -> throwable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't eagerly instantiate {@link Throwable}s for {@link Flux#error(Throwable)}; let the
|
||||
* framework do it on subscription.
|
||||
*/
|
||||
static final class FluxError<T> {
|
||||
@BeforeTemplate
|
||||
Flux<T> before(@NotMatches(IsLikelyTrivialComputation.class) Throwable throwable) {
|
||||
return Flux.error(throwable);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<T> after(Throwable throwable) {
|
||||
return Flux.error(() -> throwable);
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't unnecessarily defer {@link Mono#error(Throwable)}. */
|
||||
static final class MonoDeferredError<T> {
|
||||
@BeforeTemplate
|
||||
@@ -380,30 +412,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1707,6 +1732,22 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't defer to subscription-time non-reactive operations that can efficiently be performed
|
||||
* during assembly.
|
||||
*/
|
||||
static final class OptionalMapOrElse<T, S, M extends Mono<? extends S>> {
|
||||
@BeforeTemplate
|
||||
Mono<S> before(Optional<T> optional, Function<? super T, M> transformer, M mono) {
|
||||
return Mono.justOrEmpty(optional).flatMap(transformer).switchIfEmpty(mono);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<? extends S> after(Optional<T> optional, Function<? super T, M> transformer, M mono) {
|
||||
return optional.map(transformer).orElse(mono);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link reactor.util.context.Context#empty()}} over more verbose alternatives. */
|
||||
// XXX: Introduce Refaster rules or a `BugChecker` that maps `(Immutable)Map.of(k, v)` to
|
||||
// `Context.of(k, v)` and likewise for multi-pair overloads.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
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 OptionalOrElseTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(OptionalOrElse.class, getClass())
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.google.errorprone.refaster.Refaster;",
|
||||
"import java.util.Optional;",
|
||||
"",
|
||||
"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\"));",
|
||||
"",
|
||||
" // 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(OptionalOrElse.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);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ final class Slf4jLogStatementTest {
|
||||
"class A {",
|
||||
" private static final String FMT0 = \"format-string-without-placeholders\";",
|
||||
" private static final String FMT1 = \"format-string-with-{}-placeholder\";",
|
||||
" private static final String FMT2 = \"format-string-with-{}-{}-placeholders\";",
|
||||
" private static final String FMT_ERR = \"format-string-with-%s-placeholder\";",
|
||||
" private static final Logger LOG = LoggerFactory.getLogger(A.class);",
|
||||
"",
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static org.openjdk.jmh.results.format.ResultFormatType.JSON;
|
||||
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.MayOptionallyUse;
|
||||
import com.google.errorprone.refaster.annotation.Placeholder;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
import org.openjdk.jmh.profile.GCProfiler;
|
||||
import org.openjdk.jmh.runner.Runner;
|
||||
import org.openjdk.jmh.runner.RunnerException;
|
||||
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import tech.picnic.errorprone.refaster.annotation.Benchmarked;
|
||||
|
||||
// XXX: Fix warmup and measurements etc.
|
||||
// XXX: Flag cases where the `before` code is faster, taking into account variation.
|
||||
@SuppressWarnings("FieldCanBeFinal") // XXX: Triggers CompilesWithFix!!!
|
||||
@State(Scope.Benchmark)
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@Fork(
|
||||
jvmArgs = {"-Xms256M", "-Xmx256M"},
|
||||
value = 1)
|
||||
@Warmup(iterations = 1)
|
||||
@Measurement(iterations = 10, time = 1)
|
||||
public class ReactorRulesBenchmarks {
|
||||
public static void main(String[] args) throws RunnerException {
|
||||
String testRegex = Pattern.quote(ReactorRulesBenchmarks.class.getCanonicalName());
|
||||
new Runner(
|
||||
new OptionsBuilder()
|
||||
.include(testRegex)
|
||||
.addProfiler(GCProfiler.class)
|
||||
.resultFormat(JSON) // XXX: Review.
|
||||
.build())
|
||||
.run();
|
||||
}
|
||||
|
||||
// XXX: What a benchmarked rule could look like.
|
||||
@Benchmarked
|
||||
static final class MonoFromOptionalSwitchIfEmpty<T> {
|
||||
// XXX: These parameters could perhaps be inferred in the common case.
|
||||
@Benchmarked.Param private final Optional<String> emptyOptional = Optional.empty();
|
||||
@Benchmarked.Param private final Optional<String> nonEmptyOptional = Optional.of("foo");
|
||||
@Benchmarked.Param private final Mono<String> emptyMono = Mono.<String>empty().hide();
|
||||
@Benchmarked.Param private final Mono<String> nonEmptyMono = Mono.just("bar").hide();
|
||||
|
||||
// XXX: Dropped to hide this class from `RefasterRuleCompilerTaskListener`: @BeforeTemplate
|
||||
Mono<T> before(Optional<T> optional, Mono<T> mono) {
|
||||
return optional.map(Mono::just).orElse(mono);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(Optional<T> optional, Mono<T> mono) {
|
||||
return Mono.justOrEmpty(optional).switchIfEmpty(mono);
|
||||
}
|
||||
|
||||
// XXX: Methods such as this one could perhaps be inferred in the common case.
|
||||
@Benchmarked.OnResult
|
||||
T subscribe(Mono<T> mono) {
|
||||
return mono.block();
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Variations like this would be generated.
|
||||
public static class MonoFromOptionalSwitchIfEmptyBenchmark extends ReactorRulesBenchmarks {
|
||||
private final MonoFromOptionalSwitchIfEmpty<String> rule = new MonoFromOptionalSwitchIfEmpty();
|
||||
// private final Optional<String> optional = Optional.of("foo");
|
||||
// private final Mono<String> mono = Mono.just("bar").hide();
|
||||
private final Optional<String> optional = Optional.empty();
|
||||
private final Mono<String> mono = Mono.<String>empty().hide();
|
||||
private final Mono<String> before = rule.before(optional, mono);
|
||||
private final Mono<String> after = rule.after(optional, mono);
|
||||
|
||||
@Benchmark
|
||||
public Mono<String> before() {
|
||||
return rule.before(optional, mono);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public String beforeSubscribe1() {
|
||||
return before.block();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Mono<String> after() {
|
||||
return rule.after(optional, mono);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public String afterSubscribe() {
|
||||
return after.block();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
abstract static class MonoFlatMapToFlux<T, S> {
|
||||
@Placeholder(allowsIdentity = true)
|
||||
abstract Mono<S> transformation(@MayOptionallyUse T value);
|
||||
|
||||
// XXX: Dropped to hide this class from `RefasterRuleCompilerTaskListener`: @BeforeTemplate
|
||||
Flux<S> before(Mono<T> mono) {
|
||||
return mono.flatMapMany(v -> transformation(v));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Flux<S> after(Mono<T> mono) {
|
||||
return mono.flatMap(v -> transformation(v)).flux();
|
||||
}
|
||||
|
||||
@Benchmarked.OnResult
|
||||
Long subscribe(Flux<T> flux) {
|
||||
return flux.count().block();
|
||||
}
|
||||
|
||||
@Benchmarked.MinimalPlaceholder
|
||||
<X> Mono<X> identity(X value) {
|
||||
return Mono.just(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MonoFlatMapToFluxBenchmarks extends ReactorRulesBenchmarks {
|
||||
abstract static class Rule<T, S> {
|
||||
abstract Mono<S> transformation(T value);
|
||||
|
||||
Flux<S> before(Mono<T> mono) {
|
||||
return mono.flatMapMany(v -> transformation(v));
|
||||
}
|
||||
|
||||
Flux<S> after(Mono<T> mono) {
|
||||
return mono.flatMap(v -> transformation(v)).flux();
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: For variantions, we could use `@Param(strings)` indirection, like in
|
||||
// https://github.com/openjdk/jmh/blob/master/jmh-samples/src/main/java/org/openjdk/jmh/samples/JMHSample_35_Profilers.java
|
||||
|
||||
// XXX: Or we can make the benchmark abstract and have subclasses for each variant:
|
||||
// https://github.com/openjdk/jmh/blob/master/jmh-samples/src/main/java/org/openjdk/jmh/samples/JMHSample_24_Inheritance.java
|
||||
|
||||
public static class MonoFlatMapToFluxStringStringBenchmark extends MonoFlatMapToFluxBenchmarks {
|
||||
private final Rule<String, String> rule =
|
||||
new Rule<>() {
|
||||
@Override
|
||||
Mono<String> transformation(String value) {
|
||||
return Mono.just(value);
|
||||
}
|
||||
};
|
||||
private final Mono<String> mono = Mono.just("foo");
|
||||
private final Flux<String> before = rule.before(mono);
|
||||
private final Flux<String> after = rule.after(mono);
|
||||
|
||||
@Benchmark
|
||||
public Flux<String> before() {
|
||||
return rule.before(mono);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Flux<String> after() {
|
||||
return rule.after(mono);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Long onResultOfBefore() {
|
||||
return before.count().block();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Long onResultOfAfter() {
|
||||
return after.count().block();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import static java.util.stream.Collectors.minBy;
|
||||
import com.google.common.collect.Comparators;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -54,6 +55,10 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Comparator.comparing(s -> "foo", Comparator.comparingInt(String::length)));
|
||||
}
|
||||
|
||||
Comparator<String> testComparingEnum() {
|
||||
return Comparator.comparingInt(s -> RoundingMode.valueOf(s).ordinal());
|
||||
}
|
||||
|
||||
Comparator<String> testThenComparing() {
|
||||
return Comparator.<String>naturalOrder().thenComparing(Comparator.comparing(String::isEmpty));
|
||||
}
|
||||
@@ -173,4 +178,16 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Collector<Integer, ?, Optional<Integer>> testMaxByNaturalOrder() {
|
||||
return minBy(reverseOrder());
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIsLessThan() {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP.ordinal() < RoundingMode.DOWN.ordinal(),
|
||||
RoundingMode.UP.ordinal() >= RoundingMode.DOWN.ordinal());
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIsLessThanOrEqualTo() {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP.ordinal() <= RoundingMode.DOWN.ordinal(),
|
||||
RoundingMode.UP.ordinal() > RoundingMode.DOWN.ordinal());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static java.util.Comparator.naturalOrder;
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
import static java.util.function.Function.identity;
|
||||
@@ -9,6 +10,7 @@ import static java.util.stream.Collectors.minBy;
|
||||
import com.google.common.collect.Comparators;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -52,6 +54,10 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Comparator.comparing(s -> "foo", Comparator.comparingInt(String::length)));
|
||||
}
|
||||
|
||||
Comparator<String> testComparingEnum() {
|
||||
return comparing(s -> RoundingMode.valueOf(s));
|
||||
}
|
||||
|
||||
Comparator<String> testThenComparing() {
|
||||
return Comparator.<String>naturalOrder().thenComparing(String::isEmpty);
|
||||
}
|
||||
@@ -163,4 +169,16 @@ final class ComparatorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Collector<Integer, ?, Optional<Integer>> testMaxByNaturalOrder() {
|
||||
return maxBy(naturalOrder());
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIsLessThan() {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP.compareTo(RoundingMode.DOWN) < 0,
|
||||
RoundingMode.UP.compareTo(RoundingMode.DOWN) >= 0);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testIsLessThanOrEqualTo() {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP.compareTo(RoundingMode.DOWN) <= 0,
|
||||
RoundingMode.UP.compareTo(RoundingMode.DOWN) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,10 @@ final class EqualityRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP.equals(RoundingMode.DOWN),
|
||||
Objects.equals(RoundingMode.UP, RoundingMode.DOWN),
|
||||
RoundingMode.UP.ordinal() == RoundingMode.DOWN.ordinal(),
|
||||
!RoundingMode.UP.equals(RoundingMode.DOWN),
|
||||
!Objects.equals(RoundingMode.UP, RoundingMode.DOWN));
|
||||
!Objects.equals(RoundingMode.UP, RoundingMode.DOWN),
|
||||
RoundingMode.UP.ordinal() != RoundingMode.DOWN.ordinal());
|
||||
}
|
||||
|
||||
boolean testEqualsPredicate() {
|
||||
|
||||
@@ -21,6 +21,8 @@ final class EqualityRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(
|
||||
RoundingMode.UP == RoundingMode.DOWN,
|
||||
RoundingMode.UP == RoundingMode.DOWN,
|
||||
RoundingMode.UP == RoundingMode.DOWN,
|
||||
RoundingMode.UP != RoundingMode.DOWN,
|
||||
RoundingMode.UP != RoundingMode.DOWN,
|
||||
RoundingMode.UP != RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(Streams.class);
|
||||
}
|
||||
|
||||
Optional<String> testOptionalEmpty() {
|
||||
return Optional.ofNullable(null);
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalOfNullable() {
|
||||
return ImmutableSet.of(
|
||||
toString() == null ? Optional.empty() : Optional.of(toString()),
|
||||
@@ -41,6 +45,12 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Optional.of("baz").stream().anyMatch("qux"::equals));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testNotOptionalEqualsOptional() {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").filter("bar"::equals).isEmpty(),
|
||||
Optional.of("baz").stream().noneMatch("qux"::equals));
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalFirstIteratorElement() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableSet.of("foo").iterator().hasNext()
|
||||
@@ -120,10 +130,12 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").or(() -> Optional.empty()),
|
||||
Optional.of("bar").or(Optional::empty),
|
||||
Optional.of("baz").stream().findFirst(),
|
||||
Optional.of("qux").stream().findAny(),
|
||||
Optional.of("quux").stream().min(String::compareTo),
|
||||
Optional.of("quuz").stream().max(String::compareTo));
|
||||
Optional.of("baz").map(Optional::of).orElseGet(() -> Optional.empty()),
|
||||
Optional.of("qux").map(Optional::of).orElseGet(Optional::empty),
|
||||
Optional.of("quux").stream().findFirst(),
|
||||
Optional.of("quuz").stream().findAny(),
|
||||
Optional.of("corge").stream().min(String::compareTo),
|
||||
Optional.of("grault").stream().max(String::compareTo));
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalFilter() {
|
||||
@@ -136,9 +148,7 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Optional.of(1).stream().map(String::valueOf).findAny();
|
||||
}
|
||||
|
||||
ImmutableSet<Stream<String>> testOptionalStream() {
|
||||
return ImmutableSet.of(
|
||||
Optional.of("foo").map(Stream::of).orElse(Stream.empty()),
|
||||
Optional.of("bar").map(Stream::of).orElseGet(Stream::empty));
|
||||
Stream<String> testOptionalStream() {
|
||||
return Optional.of("foo").map(Stream::of).orElseGet(Stream::empty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(Streams.class);
|
||||
}
|
||||
|
||||
Optional<String> testOptionalEmpty() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalOfNullable() {
|
||||
return ImmutableSet.of(Optional.ofNullable(toString()), Optional.ofNullable(toString()));
|
||||
}
|
||||
@@ -41,6 +45,12 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Optional.of("baz").equals(Optional.of("qux")));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testNotOptionalEqualsOptional() {
|
||||
return ImmutableSet.of(
|
||||
!Optional.of("foo").equals(Optional.of("bar")),
|
||||
!Optional.of("baz").equals(Optional.of("qux")));
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalFirstIteratorElement() {
|
||||
return ImmutableSet.of(
|
||||
stream(ImmutableSet.of("foo").iterator()).findFirst(),
|
||||
@@ -120,7 +130,9 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Optional.of("baz"),
|
||||
Optional.of("qux"),
|
||||
Optional.of("quux"),
|
||||
Optional.of("quuz"));
|
||||
Optional.of("quuz"),
|
||||
Optional.of("corge"),
|
||||
Optional.of("grault"));
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testOptionalFilter() {
|
||||
@@ -132,7 +144,7 @@ final class OptionalRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Optional.of(1).map(String::valueOf);
|
||||
}
|
||||
|
||||
ImmutableSet<Stream<String>> testOptionalStream() {
|
||||
return ImmutableSet.of(Optional.of("foo").stream(), Optional.of("bar").stream());
|
||||
Stream<String> testOptionalStream() {
|
||||
return Optional.of("foo").stream();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,6 +118,16 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Flux.just("foo", "bar").zipWithIterable(ImmutableSet.of(1, 2), String::repeat);
|
||||
}
|
||||
|
||||
ImmutableSet<?> testMonoError() {
|
||||
IllegalStateException exception = new IllegalStateException();
|
||||
return ImmutableSet.of(Mono.error(exception), Mono.error(new IllegalArgumentException()));
|
||||
}
|
||||
|
||||
ImmutableSet<?> testFluxError() {
|
||||
IllegalStateException exception = new IllegalStateException();
|
||||
return ImmutableSet.of(Flux.error(exception), Flux.error(new IllegalArgumentException()));
|
||||
}
|
||||
|
||||
Mono<Void> testMonoDeferredError() {
|
||||
return Mono.defer(() -> Mono.error(new IllegalStateException()));
|
||||
}
|
||||
@@ -142,7 +152,7 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxTake() {
|
||||
return Flux.just(1, 2, 3).take(1);
|
||||
return Flux.just(1, 2, 3).take(1, true);
|
||||
}
|
||||
|
||||
Mono<String> testMonoDefaultIfEmpty() {
|
||||
@@ -575,6 +585,10 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
MathFlux.min(Flux.just(1), reverseOrder()), MathFlux.max(Flux.just(2), naturalOrder()));
|
||||
}
|
||||
|
||||
Mono<String> testOptionalMapOrElse() {
|
||||
return Mono.justOrEmpty(Optional.of("foo")).flatMap(Mono::just).switchIfEmpty(Mono.just("bar"));
|
||||
}
|
||||
|
||||
ImmutableSet<Context> testContextEmpty() {
|
||||
return ImmutableSet.of(Context.of(ImmutableMap.of()), Context.of(ImmutableMap.of(1, 2)));
|
||||
}
|
||||
|
||||
@@ -123,6 +123,16 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
.map(function(String::repeat));
|
||||
}
|
||||
|
||||
ImmutableSet<?> testMonoError() {
|
||||
IllegalStateException exception = new IllegalStateException();
|
||||
return ImmutableSet.of(Mono.error(exception), Mono.error(() -> new IllegalArgumentException()));
|
||||
}
|
||||
|
||||
ImmutableSet<?> testFluxError() {
|
||||
IllegalStateException exception = new IllegalStateException();
|
||||
return ImmutableSet.of(Flux.error(exception), Flux.error(() -> new IllegalArgumentException()));
|
||||
}
|
||||
|
||||
Mono<Void> testMonoDeferredError() {
|
||||
return Mono.error(() -> new IllegalStateException());
|
||||
}
|
||||
@@ -147,7 +157,7 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
}
|
||||
|
||||
Flux<Integer> testFluxTake() {
|
||||
return Flux.just(1, 2, 3).take(1, true);
|
||||
return Flux.just(1, 2, 3).take(1);
|
||||
}
|
||||
|
||||
Mono<String> testMonoDefaultIfEmpty() {
|
||||
@@ -564,6 +574,10 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(MathFlux.max(Flux.just(1)), MathFlux.max(Flux.just(2)));
|
||||
}
|
||||
|
||||
Mono<String> testOptionalMapOrElse() {
|
||||
return Optional.of("foo").map(Mono::just).orElse(Mono.just("bar"));
|
||||
}
|
||||
|
||||
ImmutableSet<Context> testContextEmpty() {
|
||||
return ImmutableSet.of(Context.empty(), Context.of(ImmutableMap.of(1, 2)));
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Stream.of("bar").map(String::length).findFirst());
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testStreamIsEmpty() {
|
||||
ImmutableSet<Boolean> testStreamFindAnyIsEmpty() {
|
||||
return ImmutableSet.of(
|
||||
Stream.of(1).count() == 0,
|
||||
Stream.of(2).count() <= 0,
|
||||
@@ -131,15 +131,14 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Stream.of(7).collect(collectingAndThen(toImmutableList(), ImmutableList::isEmpty)),
|
||||
Stream.of(8).collect(collectingAndThen(toImmutableMap(k -> k, v -> v), Map::isEmpty)),
|
||||
Stream.of(9)
|
||||
.collect(collectingAndThen(toImmutableMap(k -> k, v -> v), ImmutableMap::isEmpty)));
|
||||
.collect(collectingAndThen(toImmutableMap(k -> k, v -> v), ImmutableMap::isEmpty)),
|
||||
Stream.of(10).count() != 0,
|
||||
Stream.of(11).count() > 0,
|
||||
Stream.of(12).count() >= 1);
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testStreamIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
Stream.of(1).count() != 0,
|
||||
Stream.of(2).count() > 0,
|
||||
Stream.of(3).count() >= 1,
|
||||
Stream.of(4).findFirst().isPresent());
|
||||
boolean testStreamFindAnyIsPresent() {
|
||||
return Stream.of(1).findFirst().isPresent();
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testStreamMin() {
|
||||
|
||||
@@ -121,7 +121,7 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Stream.of("bar").findFirst().map(String::length));
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testStreamIsEmpty() {
|
||||
ImmutableSet<Boolean> testStreamFindAnyIsEmpty() {
|
||||
return ImmutableSet.of(
|
||||
Stream.of(1).findAny().isEmpty(),
|
||||
Stream.of(2).findAny().isEmpty(),
|
||||
@@ -131,15 +131,14 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Stream.of(6).findAny().isEmpty(),
|
||||
Stream.of(7).findAny().isEmpty(),
|
||||
Stream.of(8).findAny().isEmpty(),
|
||||
Stream.of(9).findAny().isEmpty());
|
||||
Stream.of(9).findAny().isEmpty(),
|
||||
!Stream.of(10).findAny().isEmpty(),
|
||||
!Stream.of(11).findAny().isEmpty(),
|
||||
!Stream.of(12).findAny().isEmpty());
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testStreamIsNotEmpty() {
|
||||
return ImmutableSet.of(
|
||||
Stream.of(1).findAny().isPresent(),
|
||||
Stream.of(2).findAny().isPresent(),
|
||||
Stream.of(3).findAny().isPresent(),
|
||||
Stream.of(4).findAny().isPresent());
|
||||
boolean testStreamFindAnyIsPresent() {
|
||||
return Stream.of(1).findAny().isPresent();
|
||||
}
|
||||
|
||||
ImmutableSet<Optional<String>> testStreamMin() {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-experimental</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-guidelines</artifactId>
|
||||
@@ -120,6 +120,7 @@
|
||||
</annotationProcessorPaths>
|
||||
<compilerArgs combine.children="append">
|
||||
<arg>-Xplugin:DocumentationGenerator -XoutputDirectory=${project.build.directory}/docs</arg>
|
||||
<!-- XXX: Enable `refaster-rule-benchmark-generator` here. -->
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-utils</artifactId>
|
||||
|
||||
@@ -53686,6 +53686,15 @@
|
||||
final ModuleFactory moduleFactory = TestUtil.getPackageObjectFactory();
|
||||
|
||||
final Path path = Paths.get(XdocUtil.DIRECTORY_PATH + "/config.xml");
|
||||
@@ -1081,7 +1083,7 @@ public class XdocsPagesTest {
|
||||
Optional.ofNullable(field)
|
||||
.map(nonNullField -> nonNullField.getAnnotation(XdocsPropertyType.class))
|
||||
.map(propertyType -> propertyType.value().getDescription())
|
||||
- .orElse(fieldClass.getSimpleName());
|
||||
+ .orElseGet(fieldClass::getSimpleName);
|
||||
final String expectedValue =
|
||||
getModulePropertyExpectedValue(sectionName, propertyName, field, fieldClass, instance);
|
||||
|
||||
@@ -1364,7 +1366,7 @@ public class XdocsPagesTest {
|
||||
final Object[] array = (Object[]) value;
|
||||
valuesStream = Arrays.stream(array);
|
||||
|
||||
149
pom.xml
149
pom.xml
@@ -4,7 +4,7 @@
|
||||
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Picnic :: Error Prone Support</name>
|
||||
@@ -45,6 +45,7 @@
|
||||
<module>error-prone-guidelines</module>
|
||||
<module>error-prone-utils</module>
|
||||
<module>refaster-compiler</module>
|
||||
<module>refaster-rule-benchmark-generator</module>
|
||||
<module>refaster-runner</module>
|
||||
<module>refaster-support</module>
|
||||
<module>refaster-test-support</module>
|
||||
@@ -52,7 +53,7 @@
|
||||
|
||||
<scm child.scm.developerConnection.inherit.append.path="false" child.scm.url.inherit.append.path="false">
|
||||
<developerConnection>scm:git:git@github.com:PicnicSupermarket/error-prone-support.git</developerConnection>
|
||||
<tag>v0.16.1</tag>
|
||||
<tag>HEAD</tag>
|
||||
<url>https://github.com/PicnicSupermarket/error-prone-support</url>
|
||||
</scm>
|
||||
<issueManagement>
|
||||
@@ -148,7 +149,7 @@
|
||||
<groupId.error-prone>com.google.errorprone</groupId.error-prone>
|
||||
<!-- The build timestamp is derived from the most recent commit
|
||||
timestamp in support of reproducible builds. -->
|
||||
<project.build.outputTimestamp>2024-03-15T12:02:48Z</project.build.outputTimestamp>
|
||||
<project.build.outputTimestamp>2024-03-15T12:04:44Z</project.build.outputTimestamp>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<!-- Glob pattern identifying Refaster rule definition files. These
|
||||
Java classes don't contain "regular" code, and thus require special
|
||||
@@ -207,17 +208,18 @@
|
||||
<version.auto-service>1.1.1</version.auto-service>
|
||||
<version.auto-value>1.10.4</version.auto-value>
|
||||
<version.error-prone>${version.error-prone-orig}</version.error-prone>
|
||||
<version.error-prone-fork>v${version.error-prone-orig}-picnic-2</version.error-prone-fork>
|
||||
<version.error-prone-orig>2.25.0</version.error-prone-orig>
|
||||
<version.error-prone-slf4j>0.1.22</version.error-prone-slf4j>
|
||||
<version.error-prone-fork>v${version.error-prone-orig}-picnic-1</version.error-prone-fork>
|
||||
<version.error-prone-orig>2.27.1</version.error-prone-orig>
|
||||
<version.error-prone-slf4j>0.1.24</version.error-prone-slf4j>
|
||||
<version.guava-beta-checker>1.0</version.guava-beta-checker>
|
||||
<version.jdk>17</version.jdk>
|
||||
<version.jmh>1.37</version.jmh>
|
||||
<version.maven>3.9.5</version.maven>
|
||||
<version.mockito>5.11.0</version.mockito>
|
||||
<version.nopen-checker>1.0.1</version.nopen-checker>
|
||||
<version.nullaway>0.10.24</version.nullaway>
|
||||
<version.nullaway>0.10.26</version.nullaway>
|
||||
<version.pitest-git>1.1.4</version.pitest-git>
|
||||
<version.rewrite-templating>1.6.2</version.rewrite-templating>
|
||||
<version.rewrite-templating>1.8.1</version.rewrite-templating>
|
||||
<version.surefire>3.2.3</version.surefire>
|
||||
</properties>
|
||||
|
||||
@@ -296,7 +298,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson</groupId>
|
||||
<artifactId>jackson-bom</artifactId>
|
||||
<version>2.16.2</version>
|
||||
<version>2.17.1</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -328,7 +330,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.googlejavaformat</groupId>
|
||||
<artifactId>google-java-format</artifactId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.22.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
@@ -338,7 +340,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava-bom</artifactId>
|
||||
<version>33.0.0-jre</version>
|
||||
<version>33.2.0-jre</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -360,7 +362,7 @@
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-bom</artifactId>
|
||||
<version>2023.0.3</version>
|
||||
<version>2023.0.5</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@@ -372,12 +374,12 @@
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>1.6.13</version>
|
||||
<version>1.6.14</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>2.2.20</version>
|
||||
<version>2.2.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
@@ -407,7 +409,7 @@
|
||||
<dependency>
|
||||
<groupId>net.bytebuddy</groupId>
|
||||
<artifactId>byte-buddy</artifactId>
|
||||
<version>1.14.12</version>
|
||||
<version>1.14.14</version>
|
||||
</dependency>
|
||||
<!-- Specified so that Renovate will file Maven upgrade PRs, which
|
||||
subsequently will cause `maven-enforcer-plugin` to require that
|
||||
@@ -420,7 +422,7 @@
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<version>1.9.21.1</version>
|
||||
<version>1.9.22</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
@@ -432,7 +434,7 @@
|
||||
<dependency>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
<artifactId>checker-qual</artifactId>
|
||||
<version>3.42.0</version>
|
||||
<version>3.43.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
@@ -466,7 +468,12 @@
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongodb-driver-core</artifactId>
|
||||
<version>5.0.0</version>
|
||||
<version>5.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-core</artifactId>
|
||||
<version>${version.jmh}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openrewrite</groupId>
|
||||
@@ -476,40 +483,40 @@
|
||||
<dependency>
|
||||
<groupId>org.openrewrite.recipe</groupId>
|
||||
<artifactId>rewrite-recipe-bom</artifactId>
|
||||
<version>2.7.1</version>
|
||||
<version>2.11.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-bom</artifactId>
|
||||
<version>2.0.12</version>
|
||||
<version>2.0.13</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>6.1.4</version>
|
||||
<version>6.1.6</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test</artifactId>
|
||||
<version>3.2.3</version>
|
||||
<version>3.2.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-bom</artifactId>
|
||||
<version>6.2.2</version>
|
||||
<version>6.2.4</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<version>7.9.0</version>
|
||||
<version>7.10.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
@@ -520,7 +527,7 @@
|
||||
<plugin>
|
||||
<groupId>com.github.ekryd.sortpom</groupId>
|
||||
<artifactId>sortpom-maven-plugin</artifactId>
|
||||
<version>3.4.0</version>
|
||||
<version>3.4.1</version>
|
||||
<configuration>
|
||||
<createBackupFile>false</createBackupFile>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
@@ -577,7 +584,7 @@
|
||||
<plugin>
|
||||
<groupId>de.thetaphi</groupId>
|
||||
<artifactId>forbiddenapis</artifactId>
|
||||
<version>3.6</version>
|
||||
<version>3.7</version>
|
||||
<configuration>
|
||||
<bundledSignatures>
|
||||
<bundledSignature>jdk-internal</bundledSignature>
|
||||
@@ -624,7 +631,7 @@
|
||||
<plugin>
|
||||
<groupId>io.github.git-commit-id</groupId>
|
||||
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||
<version>8.0.1</version>
|
||||
<version>8.0.2</version>
|
||||
<configuration>
|
||||
<injectAllReactorProjects>true</injectAllReactorProjects>
|
||||
<runOnlyOnce>true</runOnlyOnce>
|
||||
@@ -891,7 +898,7 @@
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>10.14.0</version>
|
||||
<version>10.16.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.spring.nohttp</groupId>
|
||||
@@ -916,7 +923,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
<version>3.13.0</version>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<!-- XXX: Inline and drop the version
|
||||
@@ -932,6 +939,11 @@
|
||||
<artifactId>auto-service</artifactId>
|
||||
<version>${version.auto-service}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
<version>${version.jmh}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.openrewrite</groupId>
|
||||
<artifactId>rewrite-templating</artifactId>
|
||||
@@ -978,7 +990,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.1.2</version>
|
||||
<configuration>
|
||||
<retryFailedDeploymentCount>3</retryFailedDeploymentCount>
|
||||
</configuration>
|
||||
@@ -1068,7 +1080,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<version>3.2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
@@ -1081,12 +1093,12 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.1.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.4.1</version>
|
||||
<configuration>
|
||||
<skipIfEmpty>true</skipIfEmpty>
|
||||
<archive>
|
||||
@@ -1170,7 +1182,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.3.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate-source-jar</id>
|
||||
@@ -1382,7 +1394,7 @@
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.11</version>
|
||||
<version>0.8.12</version>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<!-- Refaster rules are tested using a custom method
|
||||
@@ -1394,7 +1406,7 @@
|
||||
<plugin>
|
||||
<groupId>org.kordamp.maven</groupId>
|
||||
<artifactId>pomchecker-maven-plugin</artifactId>
|
||||
<version>1.10.0</version>
|
||||
<version>1.11.0</version>
|
||||
<configuration>
|
||||
<failOnError>false</failOnError>
|
||||
<release>false</release>
|
||||
@@ -1412,7 +1424,7 @@
|
||||
<plugin>
|
||||
<groupId>org.pitest</groupId>
|
||||
<artifactId>pitest-maven</artifactId>
|
||||
<version>1.15.8</version>
|
||||
<version>1.16.1</version>
|
||||
<configuration>
|
||||
<excludedClasses>
|
||||
<!-- AutoValue generated classes. -->
|
||||
@@ -1466,7 +1478,7 @@
|
||||
<plugin>
|
||||
<groupId>org.sonarsource.scanner.maven</groupId>
|
||||
<artifactId>sonar-maven-plugin</artifactId>
|
||||
<version>3.10.0.2594</version>
|
||||
<version>3.11.0.3922</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
@@ -2054,6 +2066,67 @@
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<!-- Enables execution of a JMH benchmark. Given a benchmark class
|
||||
`tech.picnic.MyBenchmark`, the following command (executed against
|
||||
the (sub)module in which the benchmark resides) will compile and
|
||||
execute said benchmark:
|
||||
|
||||
mvn process-test-classes -Dverification.skip \
|
||||
-Djmh.run-benchmark=tech.picnic.MyBenchmark
|
||||
-->
|
||||
<id>run-jmh-benchmark</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>jmh.run-benchmark</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>build-jmh-runtime-classpath</id>
|
||||
<goals>
|
||||
<goal>build-classpath</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputProperty>testClasspath</outputProperty>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>run-jmh-benchmark</id>
|
||||
<goals>
|
||||
<goal>java</goal>
|
||||
</goals>
|
||||
<phase>process-test-classes</phase>
|
||||
<configuration>
|
||||
<classpathScope>test</classpathScope>
|
||||
<mainClass>${jmh.run-benchmark}</mainClass>
|
||||
<systemProperties>
|
||||
<!-- The runtime classpath is defined
|
||||
in this way so that any JVMs forked by
|
||||
JMH will have the desired classpath. -->
|
||||
<systemProperty>
|
||||
<key>java.class.path</key>
|
||||
<value>${project.build.testOutputDirectory}${path.separator}${project.build.outputDirectory}${path.separator}${testClasspath}</value>
|
||||
</systemProperty>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<!-- This profile is auto-activated when performing a release. -->
|
||||
<id>release</id>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-compiler</artifactId>
|
||||
|
||||
@@ -112,7 +112,7 @@ final class RefasterRuleCompilerTaskListener implements TaskListener {
|
||||
return (sym != null
|
||||
&& sym.getQualifiedName()
|
||||
.contentEquals(BeforeTemplate.class.getCanonicalName()))
|
||||
|| super.visitAnnotation(node, unused);
|
||||
|| super.visitAnnotation(node, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
117
refaster-rule-benchmark-generator/pom.xml
Normal file
117
refaster-rule-benchmark-generator/pom.xml
Normal file
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-rule-benchmark-generator</artifactId>
|
||||
|
||||
<name>Picnic :: Error Prone Support :: Refaster Rule Benchmark Generator</name>
|
||||
<!-- XXX: Review description: can this be an annotation processor? -->
|
||||
<description>Compiler plugin that derives JMH benchmarks from Refaster Rules.</description>
|
||||
<url>https://error-prone.picnic.tech</url>
|
||||
|
||||
<dependencies>
|
||||
<!-- XXX: Prune this list. -->
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_annotation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_check_api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_core</artifactId>
|
||||
<!-- XXX: Review scope. -->
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_test_helpers</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>refaster-support</artifactId>
|
||||
<!-- XXX: Review scope. -->
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.module</groupId>
|
||||
<artifactId>jackson-module-parameter-names</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto</groupId>
|
||||
<artifactId>auto-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.service</groupId>
|
||||
<artifactId>auto-service-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.value</groupId>
|
||||
<artifactId>auto-value-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jspecify</groupId>
|
||||
<artifactId>jspecify</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- XXX: Explicitly declared as a workaround for
|
||||
https://github.com/pitest/pitest-junit5-plugin/issues/105. -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,55 @@
|
||||
package tech.picnic.errorprone.refaster.benchmark;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.sun.source.util.JavacTask;
|
||||
import com.sun.source.util.Plugin;
|
||||
import com.sun.tools.javac.api.BasicJavacTask;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** A compiler {@link Plugin} that generates JMH benchmarks for Refaster rules. */
|
||||
// XXX: Review whether this can be an annotation processor instead.
|
||||
@AutoService(Plugin.class)
|
||||
public final class RefasterRuleBenchmarkGenerator implements Plugin {
|
||||
@VisibleForTesting static final String OUTPUT_DIRECTORY_FLAG = "-XoutputDirectory";
|
||||
private static final Pattern OUTPUT_DIRECTORY_FLAG_PATTERN =
|
||||
Pattern.compile(Pattern.quote(OUTPUT_DIRECTORY_FLAG) + "=(.*)");
|
||||
|
||||
/** Instantiates a new {@link RefasterRuleBenchmarkGenerator} instance. */
|
||||
public RefasterRuleBenchmarkGenerator() {}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(JavacTask javacTask, String... args) {
|
||||
checkArgument(args.length == 1, "Precisely one path must be provided");
|
||||
|
||||
// XXX: Drop all path logic: instead generate in the same package as the Refaster rule
|
||||
// collection. (But how do we then determine the base directory?)
|
||||
javacTask.addTaskListener(
|
||||
new RefasterRuleBenchmarkGeneratorTaskListener(
|
||||
((BasicJavacTask) javacTask).getContext(), getOutputPath(args[0])));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static Path getOutputPath(String pathArg) {
|
||||
Matcher matcher = OUTPUT_DIRECTORY_FLAG_PATTERN.matcher(pathArg);
|
||||
checkArgument(
|
||||
matcher.matches(), "'%s' must be of the form '%s=<value>'", pathArg, OUTPUT_DIRECTORY_FLAG);
|
||||
|
||||
String path = matcher.group(1);
|
||||
try {
|
||||
return Path.of(path);
|
||||
} catch (InvalidPathException e) {
|
||||
throw new IllegalArgumentException(String.format("Invalid path '%s'", path), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package tech.picnic.errorprone.refaster.benchmark;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.errorprone.matchers.Matchers.anyOf;
|
||||
import static com.google.errorprone.matchers.Matchers.hasAnnotation;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.matchers.Matcher;
|
||||
import com.google.errorprone.matchers.Matchers;
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.util.TaskEvent;
|
||||
import com.sun.source.util.TaskEvent.Kind;
|
||||
import com.sun.source.util.TaskListener;
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.source.util.TreePathScanner;
|
||||
import com.sun.tools.javac.api.JavacTrees;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import javax.tools.JavaFileObject;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
// XXX: Document.
|
||||
final class RefasterRuleBenchmarkGeneratorTaskListener implements TaskListener {
|
||||
private static final Matcher<Tree> IS_TEMPLATE =
|
||||
anyOf(hasAnnotation(BeforeTemplate.class), hasAnnotation(AfterTemplate.class));
|
||||
private static final Matcher<Tree> IS_BENCHMARKED =
|
||||
Matchers.hasAnnotation("tech.picnic.errorprone.refaster.annotation.Benchmarked");
|
||||
|
||||
private final Context context;
|
||||
private final Path outputPath;
|
||||
|
||||
RefasterRuleBenchmarkGeneratorTaskListener(Context context, Path outputPath) {
|
||||
this.context = context;
|
||||
this.outputPath = outputPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void started(TaskEvent taskEvent) {
|
||||
if (taskEvent.getKind() == Kind.ANALYZE) {
|
||||
createOutputDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finished(TaskEvent taskEvent) {
|
||||
if (taskEvent.getKind() != Kind.ANALYZE) {
|
||||
return;
|
||||
}
|
||||
|
||||
JavaFileObject sourceFile = taskEvent.getSourceFile();
|
||||
CompilationUnitTree compilationUnit = taskEvent.getCompilationUnit();
|
||||
ClassTree classTree = JavacTrees.instance(context).getTree(taskEvent.getTypeElement());
|
||||
if (sourceFile == null || compilationUnit == null || classTree == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
VisitorState state =
|
||||
VisitorState.createForUtilityPurposes(context)
|
||||
.withPath(new TreePath(new TreePath(compilationUnit), classTree));
|
||||
|
||||
new TreePathScanner<@Nullable Void, Boolean>() {
|
||||
@Override
|
||||
public @Nullable Void visitClass(ClassTree classTree, Boolean doBenchmark) {
|
||||
// XXX: Validate that `@Benchmarked` is only placed in contexts with at least one Refaster
|
||||
// rule.
|
||||
boolean inspectClass = doBenchmark || IS_BENCHMARKED.matches(classTree, state);
|
||||
|
||||
if (inspectClass) {
|
||||
System.out.println(handle(classTree, state));
|
||||
// XXX: If this class has a `@BeforeTemplate` method, generate a benchmark for it.
|
||||
}
|
||||
|
||||
return super.visitClass(classTree, inspectClass);
|
||||
}
|
||||
}.scan(compilationUnit, false);
|
||||
}
|
||||
|
||||
// XXX: Name? Scope?
|
||||
private static Rule handle(ClassTree classTree, VisitorState state) {
|
||||
ImmutableList<Rule.Method> methods =
|
||||
classTree.getMembers().stream()
|
||||
.filter(m -> IS_TEMPLATE.matches(m, state))
|
||||
.map(m -> process((MethodTree) m, state))
|
||||
.collect(toImmutableList());
|
||||
|
||||
Rule rule = new Rule(classTree, methods);
|
||||
return rule;
|
||||
}
|
||||
|
||||
private static Rule.Method process(MethodTree methodTree, VisitorState state) {
|
||||
// XXX: Initially, disallow `Refaster.x` usages.
|
||||
// XXX: Initially, disallow references to `@Placeholder` methods.
|
||||
// XXX: Disallow `void` methods. (Can't be black-holed.)
|
||||
return new Rule.Method(methodTree);
|
||||
}
|
||||
|
||||
// XXX: Move types down.
|
||||
record Rule(ClassTree tree, ImmutableList<Rule.Method> methods) {
|
||||
record Method(MethodTree tree) {}
|
||||
}
|
||||
|
||||
private void createOutputDirectory() {
|
||||
try {
|
||||
Files.createDirectories(outputPath);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(
|
||||
String.format("Error while creating directory with path '%s'", outputPath), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package tech.picnic.errorprone.refaster.benchmark;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.FileManagers;
|
||||
import com.google.errorprone.FileObjects;
|
||||
import com.sun.tools.javac.api.JavacTaskImpl;
|
||||
import com.sun.tools.javac.api.JavacTool;
|
||||
import com.sun.tools.javac.file.JavacFileManager;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
// XXX: This code is a near-duplicate of the identically named class in `documentation-support`.
|
||||
public final class Compilation {
|
||||
private Compilation() {}
|
||||
|
||||
public static void compileWithRefasterRuleBenchmarkGenerator(
|
||||
Path outputDirectory, String path, String... lines) {
|
||||
compileWithRefasterRuleBenchmarkGenerator(
|
||||
outputDirectory.toAbsolutePath().toString(), path, lines);
|
||||
}
|
||||
|
||||
public static void compileWithRefasterRuleBenchmarkGenerator(
|
||||
String outputDirectory, String path, String... lines) {
|
||||
/*
|
||||
* The compiler options specified here largely match those used by Error Prone's
|
||||
* `CompilationTestHelper`. A key difference is the stricter linting configuration. When
|
||||
* compiling using JDK 21+, these lint options also require that certain JDK modules are
|
||||
* explicitly exported.
|
||||
*/
|
||||
compile(
|
||||
ImmutableList.of(
|
||||
"--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
|
||||
"--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
|
||||
"--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
|
||||
"-encoding",
|
||||
"UTF-8",
|
||||
"-parameters",
|
||||
"-proc:none",
|
||||
"-Werror",
|
||||
"-Xlint:all,-serial",
|
||||
"-Xplugin:RefasterRuleBenchmarkGenerator -XoutputDirectory=" + outputDirectory,
|
||||
"-XDdev",
|
||||
"-XDcompilePolicy=simple"),
|
||||
FileObjects.forSourceLines(path, lines));
|
||||
}
|
||||
|
||||
private static void compile(ImmutableList<String> options, JavaFileObject javaFileObject) {
|
||||
JavacFileManager javacFileManager = FileManagers.testFileManager();
|
||||
JavaCompiler compiler = JavacTool.create();
|
||||
|
||||
List<Diagnostic<?>> diagnostics = new ArrayList<>();
|
||||
JavacTaskImpl task =
|
||||
(JavacTaskImpl)
|
||||
compiler.getTask(
|
||||
null,
|
||||
javacFileManager,
|
||||
diagnostics::add,
|
||||
options,
|
||||
ImmutableList.of(),
|
||||
ImmutableList.of(javaFileObject));
|
||||
|
||||
Boolean result = task.call();
|
||||
assertThat(diagnostics).isEmpty();
|
||||
assertThat(result).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package tech.picnic.errorprone.refaster.benchmark;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
// XXX: Add relevant tests also present in `DocumentationGeneratorTaskListenerTest`.
|
||||
// XXX: Test package placement.
|
||||
final class RefasterRuleBenchmarkGeneratorTaskListenerTest {
|
||||
// XXX: Rename!
|
||||
@Test
|
||||
void xxx(@TempDir Path outputDirectory) {
|
||||
Compilation.compileWithRefasterRuleBenchmarkGenerator(
|
||||
outputDirectory,
|
||||
"TestCheckerWithoutAnnotation.java",
|
||||
"""
|
||||
import com.google.errorprone.refaster.annotation.AfterTemplate;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import java.util.Optional;
|
||||
import reactor.core.publisher.Mono;
|
||||
import tech.picnic.errorprone.refaster.annotation.Benchmarked;
|
||||
|
||||
@Benchmarked
|
||||
final class MonoFromOptionalSwitchIfEmpty<T> {
|
||||
@BeforeTemplate
|
||||
Mono<T> before(Optional<T> optional, Mono<T> mono) {
|
||||
return optional.map(Mono::just).orElse(mono);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<T> after(Optional<T> optional, Mono<T> mono) {
|
||||
return Mono.justOrEmpty(optional).switchIfEmpty(mono);
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
assertThat(outputDirectory.toAbsolutePath()).isEmptyDirectory();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package tech.picnic.errorprone.refaster.benchmark;
|
||||
|
||||
final class RefasterRuleBenchmarkGeneratorTest {
|
||||
// XXX: TBD. See `DocumentationGeneratorTest`.
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-runner</artifactId>
|
||||
|
||||
@@ -166,7 +166,7 @@ public final class Refaster extends BugChecker implements CompilationUnitTreeMat
|
||||
"Refaster Rule",
|
||||
description.getLink(),
|
||||
String.join(": ", description.checkName, description.getRawMessage()))
|
||||
.overrideSeverity(severityOverride.orElse(description.severity()))
|
||||
.overrideSeverity(severityOverride.orElseGet(description::severity))
|
||||
.addAllFixes(description.fixes)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-support</artifactId>
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package tech.picnic.errorprone.refaster.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates that benchmark(s) should be generated for the annotated Refaster rule or group of
|
||||
* Refaster rules.
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Benchmarked {
|
||||
// XXX: Make configurable. E.g.
|
||||
// - While not supported, don't complain about `Refaster.anyOf` or other `Refaster` utility method
|
||||
// usages.
|
||||
// - Specify warmup and measurement iterations.
|
||||
// - Specify output time unit.
|
||||
// - Value generation hints.f
|
||||
// Once configuration is supported, annotations on nested classes should override the
|
||||
// configuration specified by outer classes.
|
||||
|
||||
// XXX: Explain use. Allow restriction by name?
|
||||
@Target(ElementType.FIELD)
|
||||
@interface Param {}
|
||||
|
||||
// XXX: Explain use
|
||||
@Target(ElementType.METHOD)
|
||||
@interface OnResult {}
|
||||
|
||||
// XXX: Explain use
|
||||
@Target(ElementType.METHOD)
|
||||
@interface MinimalPlaceholder {}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.16.1</version>
|
||||
<version>0.16.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-test-support</artifactId>
|
||||
|
||||
@@ -1,8 +1,44 @@
|
||||
# An overview of Error Prone Support releases, along with compatible Error
|
||||
# Prone releases. This data was generated by `generate-version-compatibility-overview.sh`.
|
||||
releases:
|
||||
- version: 0.16.1
|
||||
compatible:
|
||||
- "2.27.1"
|
||||
- "2.27.0"
|
||||
- "2.26.1"
|
||||
- "2.26.0"
|
||||
- "2.25.0"
|
||||
- "2.24.1"
|
||||
- "2.24.0"
|
||||
- "2.23.0"
|
||||
- version: 0.16.0
|
||||
compatible:
|
||||
- "2.27.1"
|
||||
- "2.27.0"
|
||||
- "2.26.1"
|
||||
- "2.26.0"
|
||||
- "2.25.0"
|
||||
- "2.24.1"
|
||||
- "2.24.0"
|
||||
- "2.23.0"
|
||||
- version: 0.15.0
|
||||
compatible:
|
||||
- "2.27.1"
|
||||
- "2.27.0"
|
||||
- "2.26.1"
|
||||
- "2.26.0"
|
||||
- "2.25.0"
|
||||
- "2.24.1"
|
||||
- "2.24.0"
|
||||
- "2.23.0"
|
||||
- version: 0.14.0
|
||||
compatible:
|
||||
- "2.27.1"
|
||||
- "2.27.0"
|
||||
- "2.26.1"
|
||||
- "2.26.0"
|
||||
- "2.25.0"
|
||||
- "2.24.1"
|
||||
- "2.24.0"
|
||||
- "2.23.0"
|
||||
- "2.22.0"
|
||||
|
||||
@@ -10,15 +10,21 @@ source "${HOME}/.sdkman/bin/sdkman-init.sh"
|
||||
|
||||
set -e -u -o pipefail
|
||||
|
||||
# Currently all released Error Prone Support versions are compatible with Java
|
||||
# 17.
|
||||
java_version=17.0.10-tem
|
||||
(set +u && echo n | sdk install java "${java_version}")
|
||||
sdk use java "${java_version}"
|
||||
|
||||
output_file="$(dirname "${0}")/_data/compatibility.yml"
|
||||
|
||||
ep_versions=$(
|
||||
ep_versions="$(
|
||||
git ls-remote \
|
||||
--exit-code --refs --sort='-v:refname' \
|
||||
https://github.com/google/error-prone.git \
|
||||
'v*.*' \
|
||||
| grep -oP '(?<=/v)[^/]+$'
|
||||
)
|
||||
)"
|
||||
|
||||
work_dir="$(mktemp -d)"
|
||||
trap 'rm -rf -- "${work_dir=}"' INT TERM HUP EXIT
|
||||
@@ -39,26 +45,43 @@ for eps_version in ${eps_versions}; do
|
||||
(set +u && echo n | sdk install maven "${mvn_version}")
|
||||
sdk use maven "${mvn_version}"
|
||||
|
||||
# Collect the list of checks supported by this version of Error Prone
|
||||
# Support.
|
||||
# XXX: Conditionally omit the `MethodReferenceUsage` exclusion once that
|
||||
# check is production-ready.
|
||||
mvn clean compile -Dverification.skip -DskipTests
|
||||
checks="$(
|
||||
find \
|
||||
-path "*/META-INF/services/com.google.errorprone.bugpatterns.BugChecker" \
|
||||
-not -path "*/error-prone-experimental/*" \
|
||||
-not -path "*/error-prone-guidelines/*" \
|
||||
-print0 \
|
||||
| xargs -0 grep -hoP '[^.]+$' \
|
||||
| grep -v '^MethodReferenceUsage$' \
|
||||
| paste -s -d ',' -
|
||||
)"
|
||||
|
||||
# Remove any Error Prone flags used by this build that may not be compatible
|
||||
# with the targeted version of Error Prone. Removal of these build flags does
|
||||
# not influence the compatibility assessment.
|
||||
sed -i -r 's,-XepAllSuggestionsAsWarnings|-Xep:\w+:\w+,,g' pom.xml
|
||||
|
||||
# Using each Error Prone release, attempt to build and test the source, while
|
||||
# also applying the Maven Central-hosted Refaster rules. This determines
|
||||
# source and behavioral (in)compatibility with Error Prone APIs, while also
|
||||
# assessing whether the Refaster rules are deserialization-compatible.
|
||||
# also applying the Maven Central-hosted Error Prone Support-defined checks
|
||||
# and Refaster rules. This determines source and behavioral (in)compatibility
|
||||
# with Error Prone APIs, while also assessing whether the Refaster rules are
|
||||
# deserialization-compatible.
|
||||
for ep_version in ${ep_versions}; do
|
||||
echo "Testing Error Prone Support ${eps_version} with Error Prone ${ep_version}..."
|
||||
mvn clean test \
|
||||
-Perror-prone \
|
||||
-Derror-prone.patch-checks=Refaster \
|
||||
-Derror-prone.patch-checks="${checks}" \
|
||||
-Ppatch \
|
||||
-Pself-check \
|
||||
-Dverification.skip \
|
||||
-Dversion.error-prone-orig="${ep_version}" \
|
||||
&& echo "SUCCESS: { \"eps_version\": \"${eps_version}\", \"ep_version\": \"${ep_version}\" }" || true
|
||||
# Undo any changes applied by Refaster.
|
||||
# Undo any changes applied by the checks.
|
||||
git checkout -- '*.java'
|
||||
done
|
||||
done | tee "${build_log}"
|
||||
|
||||
Reference in New Issue
Block a user