forked from phoedos/pmd
Merge branch 'pmd/7.0.x' into cannot-resolve-ambiguous-dollar
This commit is contained in:
@ -6539,6 +6539,15 @@
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "filiprafalowicz",
|
||||
"name": "filiprafalowicz",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/24355557?v=4",
|
||||
"profile": "https://github.com/filiprafalowicz",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "JerritEic",
|
||||
"name": "JerritEic",
|
||||
|
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -23,7 +23,7 @@ jobs:
|
||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- uses: actions/cache@v2
|
||||
|
2
.github/workflows/git-repo-sync.yml
vendored
2
.github/workflows/git-repo-sync.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: false
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 100
|
||||
- name: Setup Environment
|
||||
|
2
.github/workflows/troubleshooting.yml
vendored
2
.github/workflows/troubleshooting.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
os: [ ubuntu-latest ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
|
@ -775,163 +775,164 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center"><a href="https://github.com/ekkirala"><img src="https://avatars.githubusercontent.com/u/44954455?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ekkirala</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aekkirala" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/emersonmoura"><img src="https://avatars.githubusercontent.com/u/5419868?v=4?s=100" width="100px;" alt=""/><br /><sub><b>emersonmoura</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aemersonmoura" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://juejin.cn/user/1063982985642525"><img src="https://avatars.githubusercontent.com/u/24585054?v=4?s=100" width="100px;" alt=""/><br /><sub><b>fairy</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aguxiaonian" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/filiprafalowicz"><img src="https://avatars.githubusercontent.com/u/24355557?v=4?s=100" width="100px;" alt=""/><br /><sub><b>filiprafalowicz</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=filiprafalowicz" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/foxmason"><img src="https://avatars.githubusercontent.com/u/33361071?v=4?s=100" width="100px;" alt=""/><br /><sub><b>foxmason</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Afoxmason" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/frankegabor"><img src="https://avatars.githubusercontent.com/u/13273444?v=4?s=100" width="100px;" alt=""/><br /><sub><b>frankegabor</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Afrankegabor" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/frankegabor"><img src="https://avatars.githubusercontent.com/u/13273444?v=4?s=100" width="100px;" alt=""/><br /><sub><b>frankegabor</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Afrankegabor" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/fanlw0816"><img src="https://avatars.githubusercontent.com/u/22781995?v=4?s=100" width="100px;" alt=""/><br /><sub><b>frankl</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Afanlw0816" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/freafrea"><img src="https://avatars.githubusercontent.com/u/39403091?v=4?s=100" width="100px;" alt=""/><br /><sub><b>freafrea</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Afreafrea" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/fsapatin"><img src="https://avatars.githubusercontent.com/u/10675254?v=4?s=100" width="100px;" alt=""/><br /><sub><b>fsapatin</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Afsapatin" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/gracia19"><img src="https://avatars.githubusercontent.com/u/32557952?v=4?s=100" width="100px;" alt=""/><br /><sub><b>gracia19</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Agracia19" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/ief2009"><img src="https://avatars.githubusercontent.com/u/1955449?v=4?s=100" width="100px;" alt=""/><br /><sub><b>guo fei</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aief2009" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/gurmsc5"><img src="https://avatars.githubusercontent.com/u/26914263?v=4?s=100" width="100px;" alt=""/><br /><sub><b>gurmsc5</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Agurmsc5" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/gwilymatgearset"><img src="https://avatars.githubusercontent.com/u/43957113?v=4?s=100" width="100px;" alt=""/><br /><sub><b>gwilymatgearset</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=gwilymatgearset" title="Code">💻</a> <a href="https://github.com/pmd/pmd/issues?q=author%3Agwilymatgearset" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/gwilymatgearset"><img src="https://avatars.githubusercontent.com/u/43957113?v=4?s=100" width="100px;" alt=""/><br /><sub><b>gwilymatgearset</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=gwilymatgearset" title="Code">💻</a> <a href="https://github.com/pmd/pmd/issues?q=author%3Agwilymatgearset" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/haigsn"><img src="https://avatars.githubusercontent.com/u/52993319?v=4?s=100" width="100px;" alt=""/><br /><sub><b>haigsn</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ahaigsn" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/hemanshu070"><img src="https://avatars.githubusercontent.com/u/32012651?v=4?s=100" width="100px;" alt=""/><br /><sub><b>hemanshu070</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ahemanshu070" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/henrik242"><img src="https://avatars.githubusercontent.com/u/129931?v=4?s=100" width="100px;" alt=""/><br /><sub><b>henrik242</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ahenrik242" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/hongpuwu"><img src="https://avatars.githubusercontent.com/u/19198552?v=4?s=100" width="100px;" alt=""/><br /><sub><b>hongpuwu</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ahongpuwu" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/hvbtup"><img src="https://avatars.githubusercontent.com/u/7644776?v=4?s=100" width="100px;" alt=""/><br /><sub><b>hvbtup</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=hvbtup" title="Code">💻</a> <a href="https://github.com/pmd/pmd/issues?q=author%3Ahvbtup" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="http://www.igniti.de/"><img src="https://avatars.githubusercontent.com/u/7207145?v=4?s=100" width="100px;" alt=""/><br /><sub><b>igniti GmbH</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aigniti-gmbh" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/ilovezfs"><img src="https://avatars.githubusercontent.com/u/5268928?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ilovezfs</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ailovezfs" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/ilovezfs"><img src="https://avatars.githubusercontent.com/u/5268928?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ilovezfs</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ailovezfs" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/itaigilo"><img src="https://avatars.githubusercontent.com/u/13402361?v=4?s=100" width="100px;" alt=""/><br /><sub><b>itaigilo</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aitaigilo" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/jakivey32"><img src="https://avatars.githubusercontent.com/u/36869603?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jakivey32</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ajakivey32" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/jbennett2091"><img src="https://avatars.githubusercontent.com/u/16721671?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jbennett2091</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ajbennett2091" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/jcamerin"><img src="https://avatars.githubusercontent.com/u/7663252?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jcamerin</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ajcamerin" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/jkeener1"><img src="https://avatars.githubusercontent.com/u/11696155?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jkeener1</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ajkeener1" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/jmetertea"><img src="https://avatars.githubusercontent.com/u/33323555?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jmetertea</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ajmetertea" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/johnra2"><img src="https://avatars.githubusercontent.com/u/90150885?v=4?s=100" width="100px;" alt=""/><br /><sub><b>johnra2</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=johnra2" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/johnra2"><img src="https://avatars.githubusercontent.com/u/90150885?v=4?s=100" width="100px;" alt=""/><br /><sub><b>johnra2</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=johnra2" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/josemanuelrolon"><img src="https://avatars.githubusercontent.com/u/1685807?v=4?s=100" width="100px;" alt=""/><br /><sub><b>josemanuelrolon</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=josemanuelrolon" title="Code">💻</a> <a href="https://github.com/pmd/pmd/issues?q=author%3Ajosemanuelrolon" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/kabroxiko"><img src="https://avatars.githubusercontent.com/u/20568120?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kabroxiko</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=kabroxiko" title="Code">💻</a> <a href="https://github.com/pmd/pmd/issues?q=author%3Akabroxiko" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/karwer"><img src="https://avatars.githubusercontent.com/u/862540?v=4?s=100" width="100px;" alt=""/><br /><sub><b>karwer</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Akarwer" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/kaulonline"><img src="https://avatars.githubusercontent.com/u/1171723?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kaulonline</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Akaulonline" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/kdaemonv"><img src="https://avatars.githubusercontent.com/u/5984651?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kdaemonv</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Akdaemonv" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/kenji21"><img src="https://avatars.githubusercontent.com/u/1105089?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kenji21</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=kenji21" title="Code">💻</a> <a href="https://github.com/pmd/pmd/issues?q=author%3Akenji21" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/kfranic"><img src="https://avatars.githubusercontent.com/u/26544594?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kfranic</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Akfranic" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/kfranic"><img src="https://avatars.githubusercontent.com/u/26544594?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kfranic</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Akfranic" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/khalidkh"><img src="https://avatars.githubusercontent.com/u/6832066?v=4?s=100" width="100px;" alt=""/><br /><sub><b>khalidkh</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Akhalidkh" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/krzyk"><img src="https://avatars.githubusercontent.com/u/105730?v=4?s=100" width="100px;" alt=""/><br /><sub><b>krzyk</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Akrzyk" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/lasselindqvist"><img src="https://avatars.githubusercontent.com/u/13466645?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lasselindqvist</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Alasselindqvist" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/lihuaib"><img src="https://avatars.githubusercontent.com/u/3365643?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lihuaib</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Alihuaib" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/lonelyma1021"><img src="https://avatars.githubusercontent.com/u/22359014?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lonelyma1021</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Alonelyma1021" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/lpeddy"><img src="https://avatars.githubusercontent.com/u/48803108?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lpeddy</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Alpeddy" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="http://lujie.ac.cn/"><img src="https://avatars.githubusercontent.com/u/2918158?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lujiefsi</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=lujiefsi" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://lujie.ac.cn/"><img src="https://avatars.githubusercontent.com/u/2918158?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lujiefsi</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=lujiefsi" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/lyriccoder"><img src="https://avatars.githubusercontent.com/u/20803206?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lyriccoder</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Alyriccoder" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/marcelmore"><img src="https://avatars.githubusercontent.com/u/2975481?v=4?s=100" width="100px;" alt=""/><br /><sub><b>marcelmore</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Amarcelmore" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/matchboxy"><img src="https://avatars.githubusercontent.com/u/6457674?v=4?s=100" width="100px;" alt=""/><br /><sub><b>matchbox</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Amatchboxy" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/matthiaskraaz"><img src="https://avatars.githubusercontent.com/u/5954500?v=4?s=100" width="100px;" alt=""/><br /><sub><b>matthiaskraaz</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Amatthiaskraaz" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/mkeller-ergon"><img src="https://avatars.githubusercontent.com/u/23031669?v=4?s=100" width="100px;" alt=""/><br /><sub><b>meandonlyme</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Amkeller-ergon" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/mikesive"><img src="https://avatars.githubusercontent.com/u/4043189?v=4?s=100" width="100px;" alt=""/><br /><sub><b>mikesive</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Amikesive" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/milossesic"><img src="https://avatars.githubusercontent.com/u/20756244?v=4?s=100" width="100px;" alt=""/><br /><sub><b>milossesic</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Amilossesic" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/milossesic"><img src="https://avatars.githubusercontent.com/u/20756244?v=4?s=100" width="100px;" alt=""/><br /><sub><b>milossesic</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Amilossesic" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/mriddell95"><img src="https://avatars.githubusercontent.com/u/25618660?v=4?s=100" width="100px;" alt=""/><br /><sub><b>mriddell95</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Amriddell95" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/mrlzh"><img src="https://avatars.githubusercontent.com/u/13222791?v=4?s=100" width="100px;" alt=""/><br /><sub><b>mrlzh</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Amrlzh" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/msloan"><img src="https://avatars.githubusercontent.com/u/1783723?v=4?s=100" width="100px;" alt=""/><br /><sub><b>msloan</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Amsloan" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/mucharlaravalika"><img src="https://avatars.githubusercontent.com/u/32505587?v=4?s=100" width="100px;" alt=""/><br /><sub><b>mucharlaravalika</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Amucharlaravalika" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/mvenneman"><img src="https://avatars.githubusercontent.com/u/1266912?v=4?s=100" width="100px;" alt=""/><br /><sub><b>mvenneman</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Amvenneman" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/nareshl119"><img src="https://avatars.githubusercontent.com/u/39321364?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nareshl119</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Anareshl119" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/nicolas-harraudeau-sonarsource"><img src="https://avatars.githubusercontent.com/u/40498978?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nicolas-harraudeau-sonarsource</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Anicolas-harraudeau-sonarsource" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/nicolas-harraudeau-sonarsource"><img src="https://avatars.githubusercontent.com/u/40498978?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nicolas-harraudeau-sonarsource</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Anicolas-harraudeau-sonarsource" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/noerremark"><img src="https://avatars.githubusercontent.com/u/4252411?v=4?s=100" width="100px;" alt=""/><br /><sub><b>noerremark</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Anoerremark" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/novsirion"><img src="https://avatars.githubusercontent.com/u/7797113?v=4?s=100" width="100px;" alt=""/><br /><sub><b>novsirion</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Anovsirion" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/oggboy"><img src="https://avatars.githubusercontent.com/u/4798818?v=4?s=100" width="100px;" alt=""/><br /><sub><b>oggboy</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aoggboy" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://journal.lampetty.net/archive/category/in%20English"><img src="https://avatars.githubusercontent.com/u/78990?v=4?s=100" width="100px;" alt=""/><br /><sub><b>oinume</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aoinume" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/orimarko"><img src="https://avatars.githubusercontent.com/u/17137249?v=4?s=100" width="100px;" alt=""/><br /><sub><b>orimarko</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=orimarko" title="Code">💻</a> <a href="https://github.com/pmd/pmd/issues?q=author%3Aorimarko" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/pagarwal-ignitetech"><img src="https://avatars.githubusercontent.com/u/30888430?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pallavi agarwal</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Apagarwal-ignitetech" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/parksungrin"><img src="https://avatars.githubusercontent.com/u/29750262?v=4?s=100" width="100px;" alt=""/><br /><sub><b>parksungrin</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aparksungrin" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/parksungrin"><img src="https://avatars.githubusercontent.com/u/29750262?v=4?s=100" width="100px;" alt=""/><br /><sub><b>parksungrin</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aparksungrin" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/patpatpat123"><img src="https://avatars.githubusercontent.com/u/43899031?v=4?s=100" width="100px;" alt=""/><br /><sub><b>patpatpat123</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Apatpatpat123" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/patriksevallius"><img src="https://avatars.githubusercontent.com/u/7291479?v=4?s=100" width="100px;" alt=""/><br /><sub><b>patriksevallius</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Apatriksevallius" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/pbrajesh1"><img src="https://avatars.githubusercontent.com/u/32388299?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pbrajesh1</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Apbrajesh1" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/phoenix384"><img src="https://avatars.githubusercontent.com/u/3883662?v=4?s=100" width="100px;" alt=""/><br /><sub><b>phoenix384</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aphoenix384" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/piotrszymanski-sc"><img src="https://avatars.githubusercontent.com/u/71124942?v=4?s=100" width="100px;" alt=""/><br /><sub><b>piotrszymanski-sc</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=piotrszymanski-sc" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/plan3d"><img src="https://avatars.githubusercontent.com/u/76825073?v=4?s=100" width="100px;" alt=""/><br /><sub><b>plan3d</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aplan3d" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/poojasix"><img src="https://avatars.githubusercontent.com/u/85337280?v=4?s=100" width="100px;" alt=""/><br /><sub><b>poojasix</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Apoojasix" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/poojasix"><img src="https://avatars.githubusercontent.com/u/85337280?v=4?s=100" width="100px;" alt=""/><br /><sub><b>poojasix</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Apoojasix" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/prabhushrikant"><img src="https://avatars.githubusercontent.com/u/6848200?v=4?s=100" width="100px;" alt=""/><br /><sub><b>prabhushrikant</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aprabhushrikant" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/pujitha8783"><img src="https://avatars.githubusercontent.com/u/20646357?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pujitha8783</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Apujitha8783" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/r-r-a-j"><img src="https://avatars.githubusercontent.com/u/33902071?v=4?s=100" width="100px;" alt=""/><br /><sub><b>r-r-a-j</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ar-r-a-j" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/raghujayjunk"><img src="https://avatars.githubusercontent.com/u/48074475?v=4?s=100" width="100px;" alt=""/><br /><sub><b>raghujayjunk</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Araghujayjunk" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/rajeshveera"><img src="https://avatars.githubusercontent.com/u/1306514?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rajeshveera</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Arajeshveera" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/rajeswarreddy88"><img src="https://avatars.githubusercontent.com/u/48543250?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rajeswarreddy88</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Arajeswarreddy88" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/recdevs"><img src="https://avatars.githubusercontent.com/u/63118273?v=4?s=100" width="100px;" alt=""/><br /><sub><b>recdevs</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Arecdevs" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/recdevs"><img src="https://avatars.githubusercontent.com/u/63118273?v=4?s=100" width="100px;" alt=""/><br /><sub><b>recdevs</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Arecdevs" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/reudismam"><img src="https://avatars.githubusercontent.com/u/1970407?v=4?s=100" width="100px;" alt=""/><br /><sub><b>reudismam</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=reudismam" title="Code">💻</a> <a href="https://github.com/pmd/pmd/issues?q=author%3Areudismam" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/rijkt"><img src="https://avatars.githubusercontent.com/u/56129985?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rijkt</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Arijkt" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/rillig-tk"><img src="https://avatars.githubusercontent.com/u/46376960?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rillig-tk</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Arillig-tk" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/rmohan20"><img src="https://avatars.githubusercontent.com/u/58573547?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rmohan20</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=rmohan20" title="Code">💻</a> <a href="https://github.com/pmd/pmd/issues?q=author%3Armohan20" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://rxmicro.io/"><img src="https://avatars.githubusercontent.com/u/54791695?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rxmicro</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Arxmicro" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/ryan-gustafson"><img src="https://avatars.githubusercontent.com/u/1227016?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ryan-gustafson</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=ryan-gustafson" title="Code">💻</a> <a href="https://github.com/pmd/pmd/issues?q=author%3Aryan-gustafson" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/sabi0"><img src="https://avatars.githubusercontent.com/u/11509875?v=4?s=100" width="100px;" alt=""/><br /><sub><b>sabi0</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Asabi0" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/sabi0"><img src="https://avatars.githubusercontent.com/u/11509875?v=4?s=100" width="100px;" alt=""/><br /><sub><b>sabi0</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Asabi0" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/scais"><img src="https://avatars.githubusercontent.com/u/4539192?v=4?s=100" width="100px;" alt=""/><br /><sub><b>scais</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ascais" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/sebbASF"><img src="https://avatars.githubusercontent.com/u/16689231?v=4?s=100" width="100px;" alt=""/><br /><sub><b>sebbASF</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3AsebbASF" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/sergeygorbaty"><img src="https://avatars.githubusercontent.com/u/14813710?v=4?s=100" width="100px;" alt=""/><br /><sub><b>sergeygorbaty</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=sergeygorbaty" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/shilko2013"><img src="https://avatars.githubusercontent.com/u/33313482?v=4?s=100" width="100px;" alt=""/><br /><sub><b>shilko2013</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ashilko2013" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/simeonKondr"><img src="https://avatars.githubusercontent.com/u/42644177?v=4?s=100" width="100px;" alt=""/><br /><sub><b>simeonKondr</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3AsimeonKondr" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/snajberk"><img src="https://avatars.githubusercontent.com/u/3585281?v=4?s=100" width="100px;" alt=""/><br /><sub><b>snajberk</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Asnajberk" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/sniperrifle2004"><img src="https://avatars.githubusercontent.com/u/18223222?v=4?s=100" width="100px;" alt=""/><br /><sub><b>sniperrifle2004</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Asniperrifle2004" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/sniperrifle2004"><img src="https://avatars.githubusercontent.com/u/18223222?v=4?s=100" width="100px;" alt=""/><br /><sub><b>sniperrifle2004</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Asniperrifle2004" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/snuyanzin"><img src="https://avatars.githubusercontent.com/u/403174?v=4?s=100" width="100px;" alt=""/><br /><sub><b>snuyanzin</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Asnuyanzin" title="Bug reports">🐛</a> <a href="https://github.com/pmd/pmd/commits?author=snuyanzin" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/sratz"><img src="https://avatars.githubusercontent.com/u/14908423?v=4?s=100" width="100px;" alt=""/><br /><sub><b>sratz</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Asratz" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/stonio"><img src="https://avatars.githubusercontent.com/u/19952825?v=4?s=100" width="100px;" alt=""/><br /><sub><b>stonio</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Astonio" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/sturton"><img src="https://avatars.githubusercontent.com/u/1734891?v=4?s=100" width="100px;" alt=""/><br /><sub><b>sturton</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=sturton" title="Code">💻</a> <a href="https://github.com/pmd/pmd/issues?q=author%3Asturton" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/sudharmohan"><img src="https://avatars.githubusercontent.com/u/16752281?v=4?s=100" width="100px;" alt=""/><br /><sub><b>sudharmohan</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Asudharmohan" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/suruchidawar"><img src="https://avatars.githubusercontent.com/u/30810931?v=4?s=100" width="100px;" alt=""/><br /><sub><b>suruchidawar</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Asuruchidawar" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/svenfinitiv"><img src="https://avatars.githubusercontent.com/u/5653724?v=4?s=100" width="100px;" alt=""/><br /><sub><b>svenfinitiv</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Asvenfinitiv" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/svenfinitiv"><img src="https://avatars.githubusercontent.com/u/5653724?v=4?s=100" width="100px;" alt=""/><br /><sub><b>svenfinitiv</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Asvenfinitiv" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/tashiscool"><img src="https://avatars.githubusercontent.com/u/1057457?v=4?s=100" width="100px;" alt=""/><br /><sub><b>tashiscool</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Atashiscool" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/test-git-hook"><img src="https://avatars.githubusercontent.com/u/49142715?v=4?s=100" width="100px;" alt=""/><br /><sub><b>test-git-hook</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Atest-git-hook" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/testation21"><img src="https://avatars.githubusercontent.com/u/47239708?v=4?s=100" width="100px;" alt=""/><br /><sub><b>testation21</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=testation21" title="Code">💻</a> <a href="https://github.com/pmd/pmd/issues?q=author%3Atestation21" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/thanosa"><img src="https://avatars.githubusercontent.com/u/24596498?v=4?s=100" width="100px;" alt=""/><br /><sub><b>thanosa</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Athanosa" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/tiandiyixian"><img src="https://avatars.githubusercontent.com/u/27055337?v=4?s=100" width="100px;" alt=""/><br /><sub><b>tiandiyixian</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Atiandiyixian" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/tobwoerk"><img src="https://avatars.githubusercontent.com/u/11739442?v=4?s=100" width="100px;" alt=""/><br /><sub><b>tobwoerk</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Atobwoerk" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/tprouvot"><img src="https://avatars.githubusercontent.com/u/35368290?v=4?s=100" width="100px;" alt=""/><br /><sub><b>tprouvot</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Atprouvot" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/tprouvot"><img src="https://avatars.githubusercontent.com/u/35368290?v=4?s=100" width="100px;" alt=""/><br /><sub><b>tprouvot</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Atprouvot" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/trentchilders"><img src="https://avatars.githubusercontent.com/u/6664350?v=4?s=100" width="100px;" alt=""/><br /><sub><b>trentchilders</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Atrentchilders" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/triandicAnt"><img src="https://avatars.githubusercontent.com/u/2345902?v=4?s=100" width="100px;" alt=""/><br /><sub><b>triandicAnt</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3AtriandicAnt" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/trishul14"><img src="https://avatars.githubusercontent.com/u/24551131?v=4?s=100" width="100px;" alt=""/><br /><sub><b>trishul14</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Atrishul14" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/xmtsui"><img src="https://avatars.githubusercontent.com/u/1542690?v=4?s=100" width="100px;" alt=""/><br /><sub><b>tsui</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Axmtsui" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/winhkey"><img src="https://avatars.githubusercontent.com/u/4877808?v=4?s=100" width="100px;" alt=""/><br /><sub><b>winhkey</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Awinhkey" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/witherspore"><img src="https://avatars.githubusercontent.com/u/813263?v=4?s=100" width="100px;" alt=""/><br /><sub><b>witherspore</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Awitherspore" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/wjljack"><img src="https://avatars.githubusercontent.com/u/1182478?v=4?s=100" width="100px;" alt=""/><br /><sub><b>wjljack</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Awjljack" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/wjljack"><img src="https://avatars.githubusercontent.com/u/1182478?v=4?s=100" width="100px;" alt=""/><br /><sub><b>wjljack</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Awjljack" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/wuchiuwong"><img src="https://avatars.githubusercontent.com/u/15967553?v=4?s=100" width="100px;" alt=""/><br /><sub><b>wuchiuwong</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Awuchiuwong" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/songxing10000"><img src="https://avatars.githubusercontent.com/u/10040131?v=4?s=100" width="100px;" alt=""/><br /><sub><b>xingsong</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Asongxing10000" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/xioayuge"><img src="https://avatars.githubusercontent.com/u/45328272?v=4?s=100" width="100px;" alt=""/><br /><sub><b>xioayuge</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Axioayuge" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/xnYi9wRezm"><img src="https://avatars.githubusercontent.com/u/61201892?v=4?s=100" width="100px;" alt=""/><br /><sub><b>xnYi9wRezm</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=xnYi9wRezm" title="Code">💻</a> <a href="https://github.com/pmd/pmd/issues?q=author%3AxnYi9wRezm" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/xuanuy"><img src="https://avatars.githubusercontent.com/u/3894777?v=4?s=100" width="100px;" alt=""/><br /><sub><b>xuanuy</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Axuanuy" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/xyf0921"><img src="https://avatars.githubusercontent.com/u/17350974?v=4?s=100" width="100px;" alt=""/><br /><sub><b>xyf0921</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Axyf0921" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/yalechen-cyw3"><img src="https://avatars.githubusercontent.com/u/34886223?v=4?s=100" width="100px;" alt=""/><br /><sub><b>yalechen-cyw3</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ayalechen-cyw3" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/yalechen-cyw3"><img src="https://avatars.githubusercontent.com/u/34886223?v=4?s=100" width="100px;" alt=""/><br /><sub><b>yalechen-cyw3</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ayalechen-cyw3" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/yasuharu-sato"><img src="https://avatars.githubusercontent.com/u/45546628?v=4?s=100" width="100px;" alt=""/><br /><sub><b>yasuharu-sato</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ayasuharu-sato" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/zenglian"><img src="https://avatars.githubusercontent.com/u/5268434?v=4?s=100" width="100px;" alt=""/><br /><sub><b>zenglian</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Azenglian" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/zgrzyt93"><img src="https://avatars.githubusercontent.com/u/54275965?v=4?s=100" width="100px;" alt=""/><br /><sub><b>zgrzyt93</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=zgrzyt93" title="Code">💻</a> <a href="https://github.com/pmd/pmd/issues?q=author%3Azgrzyt93" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/zhangxinngang"><img src="https://avatars.githubusercontent.com/u/6891146?v=4?s=100" width="100px;" alt=""/><br /><sub><b>zh3ng</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Azhangxinngang" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/yuchen1013"><img src="https://avatars.githubusercontent.com/u/17316917?v=4?s=100" width="100px;" alt=""/><br /><sub><b>zt_soft</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Ayuchen1013" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/ztt79"><img src="https://avatars.githubusercontent.com/u/48408552?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ztt79</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aztt79" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/zzzzfeng"><img src="https://avatars.githubusercontent.com/u/8851007?v=4?s=100" width="100px;" alt=""/><br /><sub><b>zzzzfeng</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Azzzzfeng" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/zzzzfeng"><img src="https://avatars.githubusercontent.com/u/8851007?v=4?s=100" width="100px;" alt=""/><br /><sub><b>zzzzfeng</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Azzzzfeng" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/magwas"><img src="https://avatars.githubusercontent.com/u/756838?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Árpád Magosányi</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Amagwas" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/clsaa"><img src="https://avatars.githubusercontent.com/u/32028545?v=4?s=100" width="100px;" alt=""/><br /><sub><b>任贵杰</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aclsaa" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
|
@ -66,11 +66,11 @@ public class PmdExample {
|
||||
public static void main(String[] args) {
|
||||
PMDConfiguration configuration = new PMDConfiguration();
|
||||
configuration.setInputPaths("/home/workspace/src/main/java/code");
|
||||
configuration.setRuleSets("rulesets/java/quickstart.xml");
|
||||
configuration.addRuleSet("rulesets/java/quickstart.xml");
|
||||
configuration.setReportFormat("xml");
|
||||
configuration.setReportFile("/home/workspace/pmd-report.xml");
|
||||
|
||||
PMD.runPMD(configuration);
|
||||
PMD.runPmd(configuration);
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -80,66 +80,75 @@ public class PmdExample {
|
||||
This gives you more control over which files are processed, but is also more complicated.
|
||||
You can also provide your own custom renderers.
|
||||
|
||||
1. First we create a `PMDConfiguration`. This is currently the only way to specify a ruleset:
|
||||
1. First we create a `PMDConfiguration` and configure it, first the rules:
|
||||
|
||||
```java
|
||||
PMDConfiguration configuration = new PMDConfiguration();
|
||||
configuration.setMinimumPriority(RulePriority.MEDIUM);
|
||||
configuration.setRuleSets("rulesets/java/quickstart.xml");
|
||||
configuration.addRuleSet("rulesets/java/quickstart.xml");
|
||||
```
|
||||
|
||||
2. In order to support type resolution, PMD needs to have access to the compiled classes and dependencies
|
||||
as well. This is called "auxclasspath" and is also configured here.
|
||||
2. Then we configure, which paths to analyze:
|
||||
|
||||
```java
|
||||
configuration.setInputPaths("/home/workspace/src/main/java/code");
|
||||
```
|
||||
|
||||
3. The we configure the default language version for Java. And in order to support type resolution,
|
||||
PMD needs to have access to the compiled classes and dependencies as well. This is called
|
||||
"auxclasspath" and is also configured here.
|
||||
|
||||
Note: you can specify multiple class paths separated by `:` on Unix-systems or `;` under Windows.
|
||||
|
||||
```java
|
||||
configuration.prependClasspath("/home/workspace/target/classes:/home/.m2/repository/my/dependency.jar");
|
||||
configuration.setDefaultLanguageVersion(LanguageRegistry.findLanguageByTerseName("java").getVersion("11"));
|
||||
configuration.prependAuxClasspath("/home/workspace/target/classes:/home/.m2/repository/my/dependency.jar");
|
||||
```
|
||||
|
||||
3. Then we need to load the rulesets. This is done by using the configuration, taking the minimum priority into
|
||||
account:
|
||||
4. Then we configure the reporting. Configuring the report file is optional. If not specified, the report
|
||||
will be written to `stdout`.
|
||||
|
||||
```java
|
||||
RuleSetLoader ruleSetLoader = RuleSetLoader.fromPmdConfig(configuration);
|
||||
List<RuleSet> ruleSets = ruleSetLoader.loadFromResources(Arrays.asList(configuration.getRuleSets().split(",")));
|
||||
configuration.setReportFormat("xml");
|
||||
configuration.setReportFile("/home/workspace/pmd-report.xml");
|
||||
```
|
||||
|
||||
4. PMD operates on a list of `DataSource`. You can assemble a own list of `FileDataSource`, e.g.
|
||||
5. Now an optional step: If you want to use additional renderers as in the example, set them up before
|
||||
calling PMD. You can use a built-in renderer, e.g. `XMLRenderer` or a custom renderer implementing
|
||||
`Renderer`. Note, that you must manually initialize the renderer by setting a suitable `Writer`:
|
||||
|
||||
```java
|
||||
List<DataSource> files = Arrays.asList(new FileDataSource(new File("/path/to/src/MyClass.java")));
|
||||
```
|
||||
|
||||
5. For reporting, you can use `GlobalAnalysisListener`, which receives events like violations and errors.
|
||||
Useful implementations are provided by `Renderer` instances. To use a renderer, eg the built-in `XMLRenderer`,
|
||||
create it and configure it with a suitable `Writer`.
|
||||
Writer rendererOutput = new StringWriter();
|
||||
Renderer renderer = createRenderer(rendererOutput);
|
||||
|
||||
```java
|
||||
StringWriter rendererOutput = new StringWriter();
|
||||
Renderer xmlRenderer = new XMLRenderer("UTF-8");
|
||||
xmlRenderer.setWriter(rendererOutput);
|
||||
// The listener is created from the renderer in the next listing
|
||||
// ...
|
||||
private static Renderer createRenderer(Writer writer) {
|
||||
XMLRenderer xml = new XMLRenderer("UTF-8");
|
||||
xml.setWriter(writer);
|
||||
return xml;
|
||||
}
|
||||
```
|
||||
|
||||
6. Now, all the preparations are done, and PMD can be executed. This is done by calling
|
||||
`PMD.processFiles(...)`. This method call takes the configuration, the rulesets, the files
|
||||
to process, and the list of renderers. Provide an empty list, if you don't want to use
|
||||
any renderer. Note: The auxclasspath needs to be closed explicitly. Otherwise the class or jar files may
|
||||
remain open and file resources are leaked.
|
||||
6. Finally we can start the PMD analysis. There is the possibility to fine-tune the configuration
|
||||
by adding additional files to analyze or adding additional rulesets or renderers:
|
||||
|
||||
```java
|
||||
try (GlobalAnalysisListener listener = xmlRenderer.newListener()) {
|
||||
PMD.processFiles(configuration, ruleSets, files, listener);
|
||||
} finally {
|
||||
ClassLoader auxiliaryClassLoader = configuration.getClassLoader();
|
||||
if (auxiliaryClassLoader instanceof ClasspathClassLoader) {
|
||||
((ClasspathClassLoader) auxiliaryClassLoader).close();
|
||||
}
|
||||
try (PmdAnalysis pmd = PmdAnalysis.create(configuration)) {
|
||||
// optional: add more rulesets
|
||||
pmd.addRuleSet(pmd.newRuleSetLoader().loadFromResource("custom-ruleset.xml"));
|
||||
// optional: add more files
|
||||
pmd.files().addFile(Paths.get("src", "main", "more-java", "ExtraSource.java"));
|
||||
// optional: add more renderers
|
||||
pmd.addRenderer(renderer);
|
||||
|
||||
// or just call PMD
|
||||
pmd.performAnalysis();
|
||||
}
|
||||
```
|
||||
|
||||
7. After the call, the renderer will have been flushed by PMD (through its `GlobalAnalysisListener`).
|
||||
Then you can check the rendered output.
|
||||
The renderer will be automatically flushed and closed at the end of the analysis.
|
||||
|
||||
7. Then you can check the rendered output.
|
||||
|
||||
``` java
|
||||
System.out.println("Rendered Report:");
|
||||
@ -152,51 +161,43 @@ Here is a complete example:
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import net.sourceforge.pmd.PMD;
|
||||
import net.sourceforge.pmd.PMDConfiguration;
|
||||
import net.sourceforge.pmd.PmdAnalysis;
|
||||
import net.sourceforge.pmd.RulePriority;
|
||||
import net.sourceforge.pmd.RuleSet;
|
||||
import net.sourceforge.pmd.RuleSetLoader;
|
||||
import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.renderers.Renderer;
|
||||
import net.sourceforge.pmd.renderers.XMLRenderer;
|
||||
import net.sourceforge.pmd.util.ClasspathClassLoader;
|
||||
import net.sourceforge.pmd.util.datasource.DataSource;
|
||||
import net.sourceforge.pmd.util.datasource.FileDataSource;
|
||||
|
||||
public class PmdExample2 {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
PMDConfiguration configuration = new PMDConfiguration();
|
||||
configuration.setMinimumPriority(RulePriority.MEDIUM);
|
||||
configuration.setRuleSets("rulesets/java/quickstart.xml");
|
||||
configuration.prependClasspath("/home/workspace/target/classes");
|
||||
RuleSetLoader ruleSetLoader = RuleSetLoader.fromPmdConfig(configuration);
|
||||
List<RuleSet> ruleSets = ruleSetLoader.loadFromResources(Arrays.asList(configuration.getRuleSets().split(",")));
|
||||
configuration.addRuleSet("rulesets/java/quickstart.xml");
|
||||
|
||||
List<DataSource> files = determineFiles("/home/workspace/src/main/java/code");
|
||||
configuration.setInputPaths("/home/workspace/src/main/java/code");
|
||||
|
||||
configuration.setDefaultLanguageVersion(LanguageRegistry.findLanguageByTerseName("java").getVersion("11"));
|
||||
configuration.prependAuxClasspath("/home/workspace/target/classes");
|
||||
|
||||
configuration.setReportFormat("xml");
|
||||
configuration.setReportFile("/home/workspace/pmd-report.xml");
|
||||
|
||||
Writer rendererOutput = new StringWriter();
|
||||
Renderer renderer = createRenderer(rendererOutput);
|
||||
|
||||
try (GlobalAnalysisListener listener = renderer.newListener()) {
|
||||
PMD.processFiles(configuration, ruleSets, files, listener);
|
||||
} finally {
|
||||
ClassLoader auxiliaryClassLoader = configuration.getClassLoader();
|
||||
if (auxiliaryClassLoader instanceof ClasspathClassLoader) {
|
||||
((ClasspathClassLoader) auxiliaryClassLoader).close();
|
||||
}
|
||||
try (PmdAnalysis pmd = PmdAnalysis.create(configuration)) {
|
||||
// optional: add more rulesets
|
||||
pmd.addRuleSet(pmd.newRuleSetLoader().loadFromResource("custom-ruleset.xml"));
|
||||
// optional: add more files
|
||||
pmd.files().addFile(Paths.get("src", "main", "more-java", "ExtraSource.java"));
|
||||
// optional: add more renderers
|
||||
pmd.addRenderer(renderer);
|
||||
|
||||
// or just call PMD
|
||||
pmd.performAnalysis();
|
||||
}
|
||||
|
||||
System.out.println("Rendered Report:");
|
||||
@ -208,28 +209,6 @@ public class PmdExample2 {
|
||||
xml.setWriter(writer);
|
||||
return xml;
|
||||
}
|
||||
|
||||
private static List<DataSource> determineFiles(String basePath) throws IOException {
|
||||
Path dirPath = FileSystems.getDefault().getPath(basePath);
|
||||
final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:*.java");
|
||||
|
||||
final List<DataSource> files = new ArrayList<>();
|
||||
|
||||
Files.walkFileTree(dirPath, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
|
||||
if (matcher.matches(path.getFileName())) {
|
||||
System.out.printf("Using %s%n", path);
|
||||
files.add(new FileDataSource(path.toFile()));
|
||||
} else {
|
||||
System.out.printf("Ignoring %s%n", path);
|
||||
}
|
||||
return super.visitFile(path, attrs);
|
||||
}
|
||||
});
|
||||
System.out.printf("Analyzing %d files in %s%n", files.size(), basePath);
|
||||
return files;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -19,11 +19,83 @@ This is a {{ site.pmd.release_type }} release.
|
||||
|
||||
### New and noteworthy
|
||||
|
||||
|
||||
#### New programmatic API
|
||||
|
||||
This release introduces a new programmatic API to replace the inflexible {% jdoc core::PMD %} class.
|
||||
Programmatic execution of PMD should now be done with a {% jdoc core::PMDConfiguration %}
|
||||
and a {% jdoc core::PmdAnalysis %}, for instance:
|
||||
|
||||
```java
|
||||
PMDConfiguration config = new PMDConfiguration();
|
||||
config.setDefaultLanguageVersion(LanguageRegistry.findLanguageByTerseName("java").getVersion("11"));
|
||||
config.setInputPaths("src/main/java");
|
||||
config.prependAuxClasspath("target/classes");
|
||||
config.setMinimumPriority(RulePriority.HIGH);
|
||||
config.addRuleSet("rulesets/java/quickstart.xml");
|
||||
config.setReportFormat("xml");
|
||||
config.setReportFile("target/pmd-report.xml");
|
||||
|
||||
try (PmdAnalysis pmd = PmdAnalysis.create(config)) {
|
||||
// note: don't use `config` once a PmdAnalysis has been created.
|
||||
// optional: add more rulesets
|
||||
pmd.addRuleSet(pmd.newRuleSetLoader().loadFromResource("custom-ruleset.xml"));
|
||||
// optional: add more files
|
||||
pmd.files().addFile(Paths.get("src", "main", "more-java", "ExtraSource.java"));
|
||||
// optional: add more renderers
|
||||
pmd.addRenderer(renderer);
|
||||
|
||||
// or just call PMD
|
||||
pmd.performAnalysis();
|
||||
}
|
||||
```
|
||||
|
||||
The `PMD` class still supports methods related to CLI execution: `runPmd` and `main`.
|
||||
All other members are now deprecated for removal.
|
||||
The CLI itself remains compatible, if you run PMD via command-line, no action is required on your part.
|
||||
|
||||
### Fixed Issues
|
||||
|
||||
* apex-performance
|
||||
* [#3773](https://github.com/pmd/pmd/pull/3773): \[apex] EagerlyLoadedDescribeSObjectResult false positives with SObjectField.getDescribe()
|
||||
* core
|
||||
* [#3299](https://github.com/pmd/pmd/issues/3299): \[core] Deprecate system properties of PMDCommandLineInterface
|
||||
|
||||
### API Changes
|
||||
|
||||
#### Deprecated API
|
||||
|
||||
* Several members of {% jdoc core::PMD %} have been newly deprecated, including:
|
||||
- `PMD#EOL`: use `System#lineSeparator()`
|
||||
- `PMD#SUPPRESS_MARKER`: use {% jdoc core::PMDConfiguration#DEFAULT_SUPPRESS_MARKER %}
|
||||
- `PMD#processFiles`: use the [new programmatic API](#new-programmatic-api)
|
||||
- `PMD#getApplicableFiles`: is internal
|
||||
* {% jdoc !!core::PMDConfiguration#prependClasspath(java.lang.String) %} is deprecated
|
||||
in favour of {% jdoc core::PMDConfiguration#prependAuxClasspath(java.lang.String) %}.
|
||||
* {% jdoc !!core::PMDConfiguration#setRuleSets(java.lang.String) %} and
|
||||
{% jdoc core::PMDConfiguration#getRuleSets() %} are deprecated. Use instead
|
||||
{% jdoc core::PMDConfiguration#setRuleSets(java.util.List) %},
|
||||
{% jdoc core::PMDConfiguration#addRuleSet(java.lang.String) %},
|
||||
and {% jdoc core::PMDConfiguration#getRuleSetPaths() %}.
|
||||
* Several members of {% jdoc test::cli.BaseCLITest %} have been deprecated with replacements.
|
||||
* Several members of {% jdoc core::cli.PMDCommandLineInterface %} have been explicitly deprecated.
|
||||
The whole class however was deprecated long ago already with 6.30.0. It is internal API and should
|
||||
not be used.
|
||||
|
||||
#### Experimental APIs
|
||||
|
||||
* Together with the [new programmatic API](#new-programmatic-api) the interface
|
||||
{% jdoc core::lang.document.TextFile %} has been added as *experimental*. It intends
|
||||
to replace {% jdoc core::util.datasource.DataSource %} and {% jdoc core::cpd.SourceCode %} in the long term.
|
||||
|
||||
This interface will change in PMD 7 to support read/write operations
|
||||
and other things. You don't need to use it in PMD 6, as {% jdoc core::lang.document.FileCollector %}
|
||||
decouples you from this. A file collector is available through {% jdoc !!core::PmdAnalysis#files() %}.
|
||||
|
||||
|
||||
### External Contributions
|
||||
|
||||
* [#3773](https://github.com/pmd/pmd/pull/3773): \[apex] EagerlyLoadedDescribeSObjectResult false positives with SObjectField.getDescribe() - [@filiprafalowicz](https://github.com/filiprafalowicz)
|
||||
|
||||
{% endtocmaker %}
|
||||
|
||||
|
@ -56,4 +56,10 @@ public final class ASTReferenceExpression extends AbstractApexNode<ReferenceExpr
|
||||
public boolean isSafeNav() {
|
||||
return node.isSafeNav();
|
||||
}
|
||||
|
||||
public boolean isSObjectType() {
|
||||
List<Identifier> identifiers = node.getNames();
|
||||
return identifiers != null
|
||||
&& identifiers.stream().anyMatch(id -> "sobjecttype".equalsIgnoreCase(id.getValue()));
|
||||
}
|
||||
}
|
||||
|
@ -146,23 +146,26 @@ public class Something {
|
||||
<description>
|
||||
This rule finds `DescribeSObjectResult`s which could have been loaded eagerly via `SObjectType.getDescribe()`.
|
||||
|
||||
When using `SObjectType.getDescribe()` or `Schema.describeSObjects()` without supplying a `SObjectDescribeOptions`, implicitely it will be using `SObjectDescribeOptions.DEFAULT` then all
|
||||
When using `SObjectType.getDescribe()` or `Schema.describeSObjects()` without supplying a `SObjectDescribeOptions`,
|
||||
implicitly it will be using `SObjectDescribeOptions.DEFAULT` and then all
|
||||
child relationships will be loaded eagerly regardless whether this information is needed or not.
|
||||
This has a potential negative performance impact. Instead [`SObjectType.getDescribe(options)`](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_class_Schema_SObjectType.htm#unique_346834793)
|
||||
or [`Schema.describeSObjects(SObjectTypes, options)`](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_schema.htm#apex_System_Schema_describeSObjects) should be used and a `SObjectDescribeOptions` should be supplied. By using
|
||||
or [`Schema.describeSObjects(SObjectTypes, options)`](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_schema.htm#apex_System_Schema_describeSObjects)
|
||||
should be used and a `SObjectDescribeOptions` should be supplied. By using
|
||||
`SObjectDescribeOptions.DEFERRED` the describe attributes will be lazily initialized at first use.
|
||||
|
||||
Lazy loading `DescribeSObjectResult` on picklist fields is not recommended. The lazy loaded
|
||||
Lazy loading `DescribeSObjectResult` on picklist fields is not always recommended. The lazy loaded
|
||||
describe objects might not be 100% accurate. It might be safer to explicitly use
|
||||
`SObjectDescribeOptions.FULL` in such a case. The same applies when you need the same `DescribeSObjectResult` to be consistent
|
||||
accross different contexts and API versions.
|
||||
`SObjectDescribeOptions.FULL` in such a case. The same applies when you need the same `DescribeSObjectResult`
|
||||
to be consistent across different contexts and API versions.
|
||||
|
||||
Properties:
|
||||
|
||||
* `noDefault`: The behavior of `SObjectDescribeOptions.DEFAULT` changes from API Version 43 to 44:
|
||||
With API Version 43, the attributes are loaded eagerly. With API Version 44, they are loaded lazily.
|
||||
Simply using `SObjectDescribeOptions.DEFAULT` doesn't automatically make use of lazy loading.
|
||||
(unless "Use Improved Schema Caching" critical update is applied, `SObjectDescribeOptions.DEFAULT` do fallback to lazy loading)
|
||||
(unless "Use Improved Schema Caching" critical update is applied, `SObjectDescribeOptions.DEFAULT` does fallback
|
||||
to lazy loading)
|
||||
With this property enabled, such usages are found.
|
||||
You might ignore this, if you can make sure, that you don't run a mix of API Versions.
|
||||
</description>
|
||||
@ -173,8 +176,20 @@ Properties:
|
||||
<property name="xpath">
|
||||
<value>
|
||||
<![CDATA[
|
||||
//MethodCallExpression[(lower-case(@MethodName) = "getdescribe" or lower-case(@MethodName) = "describesobjects") and not(VariableExpression/ReferenceExpression[lower-case(@Image) = "sobjectdescribeoptions" ])] |
|
||||
//ReferenceExpression[$noDefault = true() and lower-case(@Image) = "sobjectdescribeoptions" and parent::VariableExpression[lower-case(@Image) = "default"]]
|
||||
//MethodCallExpression
|
||||
[
|
||||
lower-case(@MethodName) = "getdescribe" and ReferenceExpression[@SObjectType = true()]
|
||||
or lower-case(@MethodName) = "describesobjects"
|
||||
]
|
||||
[not(VariableExpression/ReferenceExpression
|
||||
[lower-case(@Image) = ("sobjectdescribeoptions", "fielddescribeoptions")]
|
||||
)
|
||||
]
|
||||
|
|
||||
//ReferenceExpression
|
||||
[$noDefault = true()]
|
||||
[lower-case(@Image) = "sobjectdescribeoptions"]
|
||||
[parent::VariableExpression[lower-case(@Image) = "default"]]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
|
@ -9,7 +9,7 @@
|
||||
| +- ModifierNode[@Abstract = "false", @ApexVersion = "54.0", @DefiningType = "Foo", @DeprecatedTestMethod = "false", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "no location", @Modifiers = "0", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "false", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @Virtual = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
| +- FieldDeclaration[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "anIntegerField", @Location = "(5, 13, 198, 199)", @Name = "anIntegerField", @Namespace = "", @RealLoc = "true"]
|
||||
| +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "anIntegerField", @Location = "(5, 27, 212, 226)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SafeNav = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SObjectType = "false", @SafeNav = "true"]
|
||||
| | +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "anObject", @Location = "(5, 17, 202, 210)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- EmptyReferenceExpression[@ApexVersion = "54.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
| +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "x", @Location = "(5, 13, 198, 199)", @Namespace = "", @RealLoc = "true"]
|
||||
@ -18,9 +18,9 @@
|
||||
| +- ModifierNode[@Abstract = "false", @ApexVersion = "54.0", @DefiningType = "Foo", @DeprecatedTestMethod = "false", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "no location", @Modifiers = "0", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "false", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @Virtual = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
| +- FieldDeclaration[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "profileUrl", @Location = "(8, 12, 365, 375)", @Name = "profileUrl", @Namespace = "", @RealLoc = "true"]
|
||||
| +- MethodCallExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @FullMethodName = "toExternalForm", @InputParametersSize = "0", @Location = "(8, 47, 400, 414)", @MethodName = "toExternalForm", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "METHOD", @SafeNav = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "METHOD", @SObjectType = "false", @SafeNav = "true"]
|
||||
| | +- MethodCallExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @FullMethodName = "user.getProfileUrl", @InputParametersSize = "0", @Location = "(8, 30, 383, 396)", @MethodName = "getProfileUrl", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Image = "user", @Location = "(8, 25, 378, 382)", @Namespace = "", @RealLoc = "true", @ReferenceType = "METHOD", @SafeNav = "false"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Image = "user", @Location = "(8, 25, 378, 382)", @Namespace = "", @RealLoc = "true", @ReferenceType = "METHOD", @SObjectType = "false", @SafeNav = "false"]
|
||||
| +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "profileUrl", @Location = "(8, 12, 365, 375)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- EmptyReferenceExpression[@ApexVersion = "54.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
+- Method[@ApexVersion = "54.0", @Arity = "1", @CanonicalName = "bar1", @Constructor = "false", @DefiningType = "Foo", @Image = "bar1", @Location = "(10, 17, 435, 439)", @Namespace = "", @RealLoc = "true", @ReturnType = "void", @Synthetic = "false"]
|
||||
@ -30,15 +30,15 @@
|
||||
| +- BlockStatement[@ApexVersion = "54.0", @CurlyBrace = "true", @DefiningType = "Foo", @Location = "(10, 32, 450, 538)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- ExpressionStatement[@ApexVersion = "54.0", @DefiningType = "Foo", @Location = "(11, 12, 463, 465)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "b", @Location = "(11, 12, 463, 464)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SafeNav = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SObjectType = "false", @SafeNav = "true"]
|
||||
| | +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "a", @Location = "(11, 9, 460, 461)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- EmptyReferenceExpression[@ApexVersion = "54.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
| +- ExpressionStatement[@ApexVersion = "54.0", @DefiningType = "Foo", @Location = "(12, 22, 527, 532)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- MethodCallExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @FullMethodName = "c1", @InputParametersSize = "0", @Location = "(12, 22, 527, 529)", @MethodName = "c1", @Namespace = "", @RealLoc = "true"]
|
||||
| +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "METHOD", @SafeNav = "true"]
|
||||
| +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "METHOD", @SObjectType = "false", @SafeNav = "true"]
|
||||
| +- CastExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Location = "(12, 10, 515, 518)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "b1", @Location = "(12, 17, 522, 524)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SafeNav = "true"]
|
||||
| +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SObjectType = "false", @SafeNav = "true"]
|
||||
| +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "a1", @Location = "(12, 13, 518, 520)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- EmptyReferenceExpression[@ApexVersion = "54.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
+- Method[@ApexVersion = "54.0", @Arity = "2", @CanonicalName = "bar2", @Constructor = "false", @DefiningType = "Foo", @Image = "bar2", @Location = "(15, 17, 556, 560)", @Namespace = "", @RealLoc = "true", @ReturnType = "void", @Synthetic = "false"]
|
||||
@ -50,9 +50,9 @@
|
||||
| +- BlockStatement[@ApexVersion = "54.0", @CurlyBrace = "true", @DefiningType = "Foo", @Location = "(15, 41, 580, 688)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- ExpressionStatement[@ApexVersion = "54.0", @DefiningType = "Foo", @Location = "(16, 25, 606, 613)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "aField", @Location = "(16, 25, 606, 612)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SafeNav = "false"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SObjectType = "false", @SafeNav = "false"]
|
||||
| | +- MethodCallExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @FullMethodName = "aMethod", @InputParametersSize = "0", @Location = "(16, 15, 596, 603)", @MethodName = "aMethod", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "METHOD", @SafeNav = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "METHOD", @SObjectType = "false", @SafeNav = "true"]
|
||||
| | +- ArrayLoadExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Location = "(16, 9, 590, 591)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "a", @Location = "(16, 9, 590, 591)", @Namespace = "", @RealLoc = "true"]
|
||||
| | | +- EmptyReferenceExpression[@ApexVersion = "54.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
@ -60,9 +60,9 @@
|
||||
| | +- EmptyReferenceExpression[@ApexVersion = "54.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
| +- ExpressionStatement[@ApexVersion = "54.0", @DefiningType = "Foo", @Location = "(17, 25, 675, 682)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "aField", @Location = "(17, 25, 675, 681)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SafeNav = "true"]
|
||||
| +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SObjectType = "false", @SafeNav = "true"]
|
||||
| +- MethodCallExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @FullMethodName = "aMethod", @InputParametersSize = "0", @Location = "(17, 14, 664, 671)", @MethodName = "aMethod", @Namespace = "", @RealLoc = "true"]
|
||||
| +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "METHOD", @SafeNav = "false"]
|
||||
| +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "METHOD", @SObjectType = "false", @SafeNav = "false"]
|
||||
| +- ArrayLoadExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Location = "(17, 9, 659, 660)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "a", @Location = "(17, 9, 659, 660)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- EmptyReferenceExpression[@ApexVersion = "54.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
@ -77,14 +77,14 @@
|
||||
| | +- ModifierNode[@Abstract = "false", @ApexVersion = "54.0", @DefiningType = "Foo", @DeprecatedTestMethod = "false", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "no location", @Modifiers = "0", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "false", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @Virtual = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
| | +- VariableDeclaration[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "s", @Location = "(21, 16, 744, 745)", @Namespace = "", @RealLoc = "true", @Type = "String"]
|
||||
| | +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "BillingCity", @Location = "(21, 37, 765, 776)", @Namespace = "", @RealLoc = "true"]
|
||||
| | | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SafeNav = "true"]
|
||||
| | | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SObjectType = "false", @SafeNav = "true"]
|
||||
| | | +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "Account", @Location = "(21, 28, 756, 763)", @Namespace = "", @RealLoc = "true"]
|
||||
| | | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Image = "contact", @Location = "(21, 20, 748, 755)", @Namespace = "", @RealLoc = "true", @ReferenceType = "LOAD", @SafeNav = "false"]
|
||||
| | | +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Image = "contact", @Location = "(21, 20, 748, 755)", @Namespace = "", @RealLoc = "true", @ReferenceType = "LOAD", @SObjectType = "false", @SafeNav = "false"]
|
||||
| | +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "s", @Location = "(21, 16, 744, 745)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- EmptyReferenceExpression[@ApexVersion = "54.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
| +- ReturnStatement[@ApexVersion = "54.0", @DefiningType = "Foo", @Location = "(23, 9, 841, 899)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "Name", @Location = "(23, 62, 894, 898)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SafeNav = "true"]
|
||||
| +- ReferenceExpression[@ApexVersion = "54.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SObjectType = "false", @SafeNav = "true"]
|
||||
| +- SoqlExpression[@ApexVersion = "54.0", @CanonicalQuery = "SELECT Name FROM Account WHERE Id = :tmpVar1", @DefiningType = "Foo", @Location = "(23, 16, 848, 892)", @Namespace = "", @Query = "SELECT Name FROM Account WHERE Id = :accId", @RealLoc = "true"]
|
||||
| +- BindExpressions[@ApexVersion = "54.0", @DefiningType = "Foo", @Location = "(23, 16, 848, 892)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- VariableExpression[@ApexVersion = "54.0", @DefiningType = "Foo", @Image = "accId", @Location = "(23, 54, 886, 891)", @Namespace = "", @RealLoc = "true"]
|
||||
|
@ -7,6 +7,7 @@
|
||||
<test-code>
|
||||
<description>No describer options</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>3</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public void bar(List<Account> accounts) {
|
||||
@ -21,6 +22,7 @@ public class Foo {
|
||||
<test-code>
|
||||
<description>No describer options using Schema class</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>3</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public void bar(List<Account> accounts) {
|
||||
@ -89,4 +91,54 @@ public class Foo {
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>False positive with no describer options on SObjectField</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<!-- note, this is not a violation. The default behaviour for SObjectField.getDescribe()
|
||||
doesn't seem to be a performance problem. #3773 -->
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public void bar(Case case) {
|
||||
String fieldName = Case.Subject.getDescribe().getName();
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>False positive on SObjectField with FieldDescribeOptions.FULL_DESCRIBE</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public void bar(Case case) {
|
||||
String fieldName = Case.Subject.getDescribe(FieldDescribeOptions.FULL_DESCRIBE).getName();
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>False positive on SObjectField with FieldDescribeOptions.DEFAULT</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public void bar(Case case) {
|
||||
String fieldName = Case.Subject.getDescribe(FieldDescribeOptions.DEFAULT).getName();
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>False positive on SObjectField with FieldDescribeOptions.DEFAULT with noDefault=true</description>
|
||||
<rule-property name="noDefault">true</rule-property>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public void bar(Case case) {
|
||||
String fieldName = Case.Subject.getDescribe(FieldDescribeOptions.DEFAULT).getName();
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
</test-data>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,12 +13,14 @@ import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import net.sourceforge.pmd.annotation.DeprecatedUntil700;
|
||||
import net.sourceforge.pmd.cache.AnalysisCache;
|
||||
import net.sourceforge.pmd.cache.FileAnalysisCache;
|
||||
import net.sourceforge.pmd.cache.NoopAnalysisCache;
|
||||
import net.sourceforge.pmd.cli.PmdParametersParseResult;
|
||||
import net.sourceforge.pmd.internal.util.AssertionUtil;
|
||||
import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.lang.LanguageVersion;
|
||||
import net.sourceforge.pmd.lang.LanguageVersionDiscoverer;
|
||||
@ -44,7 +46,7 @@ import net.sourceforge.pmd.util.ClasspathClassLoader;
|
||||
* {@link #getClassLoader()}</li>
|
||||
* <li>A means to configure a ClassLoader using a prepended classpath String,
|
||||
* instead of directly setting it programmatically.
|
||||
* {@link #prependClasspath(String)}</li>
|
||||
* {@link #prependAuxClasspath(String)}</li>
|
||||
* <li>A LanguageVersionDiscoverer instance, which defaults to using the default
|
||||
* LanguageVersion of each Language. Means are provided to change the
|
||||
* LanguageVersion for each Language.
|
||||
@ -88,15 +90,19 @@ import net.sourceforge.pmd.util.ClasspathClassLoader;
|
||||
* </ul>
|
||||
*/
|
||||
public class PMDConfiguration extends AbstractConfiguration {
|
||||
|
||||
/** The default suppress marker string. */
|
||||
public static final String DEFAULT_SUPPRESS_MARKER = "NOPMD";
|
||||
|
||||
// General behavior options
|
||||
private String suppressMarker = PMD.SUPPRESS_MARKER;
|
||||
private String suppressMarker = DEFAULT_SUPPRESS_MARKER;
|
||||
private int threads = Runtime.getRuntime().availableProcessors();
|
||||
private ClassLoader classLoader = getClass().getClassLoader();
|
||||
private LanguageVersionDiscoverer languageVersionDiscoverer = new LanguageVersionDiscoverer();
|
||||
private LanguageVersion forceLanguageVersion;
|
||||
|
||||
// Rule and source file options
|
||||
private List<String> ruleSets;
|
||||
private List<String> ruleSets = new ArrayList<>();
|
||||
private RulePriority minimumPriority = RulePriority.LOW;
|
||||
private String inputPaths;
|
||||
private String inputUri;
|
||||
@ -197,13 +203,46 @@ public class PMDConfiguration extends AbstractConfiguration {
|
||||
* if the given classpath is invalid (e.g. does not exist)
|
||||
* @see PMDConfiguration#setClassLoader(ClassLoader)
|
||||
* @see ClasspathClassLoader
|
||||
*
|
||||
* @deprecated Use {@link #prependAuxClasspath(String)}, which doesn't
|
||||
* throw a checked {@link IOException}
|
||||
*/
|
||||
@Deprecated
|
||||
public void prependClasspath(String classpath) throws IOException {
|
||||
if (classLoader == null) {
|
||||
classLoader = PMDConfiguration.class.getClassLoader();
|
||||
try {
|
||||
prependAuxClasspath(classpath);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
if (classpath != null) {
|
||||
classLoader = new ClasspathClassLoader(classpath, classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepend the specified classpath like string to the current ClassLoader of
|
||||
* the configuration. If no ClassLoader is currently configured, the
|
||||
* ClassLoader used to load the {@link PMDConfiguration} class will be used
|
||||
* as the parent ClassLoader of the created ClassLoader.
|
||||
*
|
||||
* <p>If the classpath String looks like a URL to a file (i.e. starts with
|
||||
* <code>file://</code>) the file will be read with each line representing
|
||||
* an entry on the classpath.</p>
|
||||
*
|
||||
* @param classpath The prepended classpath.
|
||||
*
|
||||
* @throws IllegalArgumentException if the given classpath is invalid (e.g. does not exist)
|
||||
* @see PMDConfiguration#setClassLoader(ClassLoader)
|
||||
*/
|
||||
public void prependAuxClasspath(String classpath) {
|
||||
try {
|
||||
if (classLoader == null) {
|
||||
classLoader = PMDConfiguration.class.getClassLoader();
|
||||
}
|
||||
if (classpath != null) {
|
||||
classLoader = new ClasspathClassLoader(classpath, classLoader);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Note: IOExceptions shouldn't appear anymore, they should already be converted
|
||||
// to IllegalArgumentException in ClasspathClassLoader.
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,6 +283,7 @@ public class PMDConfiguration extends AbstractConfiguration {
|
||||
*/
|
||||
public void setForceLanguageVersion(LanguageVersion forceLanguageVersion) {
|
||||
this.forceLanguageVersion = forceLanguageVersion;
|
||||
languageVersionDiscoverer.setForcedVersion(forceLanguageVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -253,6 +293,7 @@ public class PMDConfiguration extends AbstractConfiguration {
|
||||
* the LanguageVersion
|
||||
*/
|
||||
public void setDefaultLanguageVersion(LanguageVersion languageVersion) {
|
||||
Objects.requireNonNull(languageVersion);
|
||||
setDefaultLanguageVersions(Arrays.asList(languageVersion));
|
||||
}
|
||||
|
||||
@ -265,6 +306,7 @@ public class PMDConfiguration extends AbstractConfiguration {
|
||||
*/
|
||||
public void setDefaultLanguageVersions(List<LanguageVersion> languageVersions) {
|
||||
for (LanguageVersion languageVersion : languageVersions) {
|
||||
Objects.requireNonNull(languageVersion);
|
||||
languageVersionDiscoverer.setDefaultLanguageVersion(languageVersion);
|
||||
}
|
||||
}
|
||||
@ -310,7 +352,10 @@ public class PMDConfiguration extends AbstractConfiguration {
|
||||
*/
|
||||
@Deprecated
|
||||
@DeprecatedUntil700
|
||||
public String getRuleSets() {
|
||||
public @Nullable String getRuleSets() {
|
||||
if (ruleSets.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return String.join(",", ruleSets);
|
||||
}
|
||||
|
||||
@ -319,17 +364,34 @@ public class PMDConfiguration extends AbstractConfiguration {
|
||||
*
|
||||
* @see RuleSetLoader#loadFromResource(String)
|
||||
*/
|
||||
public List<String> getRuleSetPaths() {
|
||||
public @NonNull List<@NonNull String> getRuleSetPaths() {
|
||||
return ruleSets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rulesets.
|
||||
* Sets the list of ruleset paths to load when starting the analysis.
|
||||
*
|
||||
* @param ruleSetPaths A list of ruleset paths, understandable by {@link RuleSetLoader#loadFromResource(String)}.
|
||||
*
|
||||
* @throws NullPointerException If the parameter is null
|
||||
*/
|
||||
public void setRuleSets(@NonNull List<String> ruleSets) {
|
||||
this.ruleSets = new ArrayList<>(ruleSets);
|
||||
public void setRuleSets(@NonNull List<@NonNull String> ruleSetPaths) {
|
||||
AssertionUtil.requireParamNotNull("ruleSetPaths", ruleSetPaths);
|
||||
AssertionUtil.requireContainsNoNullValue("ruleSetPaths", ruleSetPaths);
|
||||
this.ruleSets = new ArrayList<>(ruleSetPaths);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new ruleset paths to load when starting the analysis.
|
||||
* This list is initially empty.
|
||||
*
|
||||
* @param rulesetPath A ruleset path, understandable by {@link RuleSetLoader#loadFromResource(String)}.
|
||||
*
|
||||
* @throws NullPointerException If the parameter is null
|
||||
*/
|
||||
public void addRuleSet(@NonNull String rulesetPath) {
|
||||
AssertionUtil.requireParamNotNull("rulesetPath", rulesetPath);
|
||||
this.ruleSets.add(rulesetPath);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -337,12 +399,16 @@ public class PMDConfiguration extends AbstractConfiguration {
|
||||
*
|
||||
* @param ruleSets the rulesets to set
|
||||
*
|
||||
* @deprecated Use {@link #setRuleSets(List)}
|
||||
* @deprecated Use {@link #setRuleSets(List)} or {@link #addRuleSet(String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
@DeprecatedUntil700
|
||||
public void setRuleSets(String ruleSets) {
|
||||
this.ruleSets = Arrays.asList(ruleSets.split(","));
|
||||
public void setRuleSets(@Nullable String ruleSets) {
|
||||
if (ruleSets == null) {
|
||||
this.ruleSets = new ArrayList<>();
|
||||
} else {
|
||||
this.ruleSets = new ArrayList<>(Arrays.asList(ruleSets.split(",")));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
403
pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java
Normal file
403
pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -28,7 +28,7 @@ import net.sourceforge.pmd.util.datasource.DataSource;
|
||||
* and configuration errors.
|
||||
*
|
||||
* <p>A report may be created by a {@link GlobalReportBuilderListener} that you
|
||||
* use as the {@link GlobalAnalysisListener} in {@linkplain PMD#processFiles(PMDConfiguration, List, List, GlobalAnalysisListener) PMD's entry point}.
|
||||
* use as the {@linkplain GlobalAnalysisListener} in {@link PmdAnalysis#performAnalysisAndCollectReport() PMD's entry point}.
|
||||
* You can also create one manually with {@link #buildReport(Consumer)}.
|
||||
*/
|
||||
public final class Report {
|
||||
|
@ -16,11 +16,16 @@ import java.util.Properties;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.Language;
|
||||
import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.util.CollectionUtil;
|
||||
import net.sourceforge.pmd.util.ResourceLoader;
|
||||
import net.sourceforge.pmd.util.log.MessageReporter;
|
||||
import net.sourceforge.pmd.util.log.internal.NoopReporter;
|
||||
|
||||
/**
|
||||
* Configurable object to load rulesets from XML resources.
|
||||
@ -29,12 +34,26 @@ import net.sourceforge.pmd.util.ResourceLoader;
|
||||
* or some such overload.
|
||||
*/
|
||||
public final class RuleSetLoader {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RuleSetLoader.class);
|
||||
|
||||
private ResourceLoader resourceLoader = new ResourceLoader(RuleSetLoader.class.getClassLoader());
|
||||
private RulePriority minimumPriority = RulePriority.LOW;
|
||||
private boolean warnDeprecated = true;
|
||||
private @NonNull RuleSetFactoryCompatibility compatFilter = RuleSetFactoryCompatibility.DEFAULT;
|
||||
private boolean includeDeprecatedRuleReferences = false;
|
||||
private MessageReporter reporter = new NoopReporter(); // non-null
|
||||
|
||||
/**
|
||||
* Create a new RuleSetLoader with a default configuration.
|
||||
* The defaults are described on each configuration method of this class.
|
||||
*/
|
||||
public RuleSetLoader() { // NOPMD UnnecessaryConstructor
|
||||
// default
|
||||
}
|
||||
|
||||
void setReporter(MessageReporter reporter) {
|
||||
this.reporter = reporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that the given classloader should be used to resolve
|
||||
@ -145,7 +164,7 @@ public final class RuleSetLoader {
|
||||
*
|
||||
* @throws RuleSetLoadException If any error occurs (eg, invalid syntax)
|
||||
*/
|
||||
public RuleSet loadFromString(String filename, String rulesetXmlContent) {
|
||||
public RuleSet loadFromString(String filename, final String rulesetXmlContent) {
|
||||
return loadFromResource(new RuleSetReferenceId(filename) {
|
||||
@Override
|
||||
public InputStream getInputStream(ResourceLoader rl) {
|
||||
@ -171,6 +190,52 @@ public final class RuleSetLoader {
|
||||
return ruleSets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a list of rulesets, if any has an error, report it on the contextual
|
||||
* error reporter instead of aborting, and continue loading the rest.
|
||||
*
|
||||
* <p>Internal API: might be published later, or maybe in PMD 7 this
|
||||
* will be the default behaviour of every method of this class.
|
||||
*/
|
||||
@InternalApi
|
||||
public List<RuleSet> loadRuleSetsWithoutException(List<String> rulesetPaths) {
|
||||
List<RuleSet> ruleSets = new ArrayList<>(rulesetPaths.size());
|
||||
boolean anyRules = false;
|
||||
for (String path : rulesetPaths) {
|
||||
try {
|
||||
RuleSet ruleset = this.loadFromResource(path);
|
||||
anyRules |= !ruleset.getRules().isEmpty();
|
||||
printRulesInDebug(path, ruleset);
|
||||
ruleSets.add(ruleset);
|
||||
} catch (RuleSetLoadException e) {
|
||||
if (e.getCause() != null) {
|
||||
// eg RuleSetNotFoundException
|
||||
reporter.errorEx("Cannot load ruleset {0}", new Object[] { path }, e.getCause());
|
||||
} else {
|
||||
reporter.errorEx("Cannot load ruleset {0}", new Object[] { path }, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!anyRules) {
|
||||
reporter.warn("No rules found. Maybe you misspelled a rule name? ({})",
|
||||
StringUtils.join(rulesetPaths, ','));
|
||||
}
|
||||
return ruleSets;
|
||||
}
|
||||
|
||||
void printRulesInDebug(String path, RuleSet ruleset) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Rules loaded from {}:", path);
|
||||
for (Rule rule : ruleset.getRules()) {
|
||||
LOG.debug("- {} ({})", rule.getName(), rule.getLanguage().getName());
|
||||
}
|
||||
}
|
||||
if (ruleset.getRules().isEmpty()) {
|
||||
reporter.warn("No rules found in ruleset {}", path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses several resources into a list of rulesets.
|
||||
*
|
||||
|
@ -4,10 +4,9 @@
|
||||
|
||||
package net.sourceforge.pmd.ant.internal;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
@ -22,12 +21,9 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.event.Level;
|
||||
|
||||
import net.sourceforge.pmd.PMD;
|
||||
import net.sourceforge.pmd.PMDConfiguration;
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.PmdAnalysis;
|
||||
import net.sourceforge.pmd.RulePriority;
|
||||
import net.sourceforge.pmd.RuleSet;
|
||||
import net.sourceforge.pmd.RuleSetLoadException;
|
||||
import net.sourceforge.pmd.RuleSetLoader;
|
||||
import net.sourceforge.pmd.ant.Formatter;
|
||||
import net.sourceforge.pmd.ant.PMDTask;
|
||||
@ -38,11 +34,11 @@ import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.lang.LanguageVersion;
|
||||
import net.sourceforge.pmd.reporting.FileAnalysisListener;
|
||||
import net.sourceforge.pmd.reporting.GlobalAnalysisListener;
|
||||
import net.sourceforge.pmd.reporting.GlobalAnalysisListener.ViolationCounterListener;
|
||||
import net.sourceforge.pmd.reporting.ReportStats;
|
||||
import net.sourceforge.pmd.reporting.ReportStatsListener;
|
||||
import net.sourceforge.pmd.util.ClasspathClassLoader;
|
||||
import net.sourceforge.pmd.util.IOUtil;
|
||||
import net.sourceforge.pmd.util.datasource.DataSource;
|
||||
import net.sourceforge.pmd.util.datasource.FileDataSource;
|
||||
|
||||
public class PMDTaskImpl {
|
||||
|
||||
@ -51,7 +47,7 @@ public class PMDTaskImpl {
|
||||
private final List<Formatter> formatters = new ArrayList<>();
|
||||
private final List<FileSet> filesets = new ArrayList<>();
|
||||
private final PMDConfiguration configuration = new PMDConfiguration();
|
||||
private final String rulesetPaths;
|
||||
private boolean failOnError;
|
||||
private boolean failOnRuleViolation;
|
||||
private int maxRuleViolations = 0;
|
||||
private String failuresPropertyName;
|
||||
@ -62,12 +58,16 @@ public class PMDTaskImpl {
|
||||
if (task.getSuppressMarker() != null) {
|
||||
configuration.setSuppressMarker(task.getSuppressMarker());
|
||||
}
|
||||
this.failOnError = task.isFailOnError();
|
||||
this.failOnRuleViolation = task.isFailOnRuleViolation();
|
||||
this.maxRuleViolations = task.getMaxRuleViolations();
|
||||
if (this.maxRuleViolations > 0) {
|
||||
this.failOnRuleViolation = true;
|
||||
}
|
||||
this.rulesetPaths = task.getRulesetFiles() == null ? "" : task.getRulesetFiles();
|
||||
if (task.getRulesetFiles() != null) {
|
||||
configuration.setRuleSets(Arrays.asList(task.getRulesetFiles().split(",")));
|
||||
}
|
||||
|
||||
configuration.setRuleSetFactoryCompatibilityEnabled(!task.isNoRuleSetCompatibility());
|
||||
if (task.getEncoding() != null) {
|
||||
configuration.setSourceEncoding(task.getEncoding());
|
||||
@ -100,46 +100,49 @@ public class PMDTaskImpl {
|
||||
private void doTask() {
|
||||
setupClassLoader();
|
||||
|
||||
// Setup RuleSetFactory and validate RuleSets
|
||||
RuleSetLoader rulesetLoader = RuleSetLoader.fromPmdConfig(configuration)
|
||||
.loadResourcesWith(setupResourceLoader());
|
||||
|
||||
List<RuleSet> rules = loadRulesets(rulesetLoader);
|
||||
|
||||
if (configuration.getSuppressMarker() != null) {
|
||||
project.log("Setting suppress marker to be " + configuration.getSuppressMarker(), Project.MSG_VERBOSE);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("PMD.CloseResource")
|
||||
ViolationCounterListener reportSizeListener = new ViolationCounterListener();
|
||||
|
||||
final List<DataSource> files = new ArrayList<>();
|
||||
final List<String> reportShortNamesPaths = new ArrayList<>();
|
||||
@SuppressWarnings("PMD.CloseResource") final List<String> reportShortNamesPaths = new ArrayList<>();
|
||||
StringJoiner fullInputPath = new StringJoiner(",");
|
||||
|
||||
for (FileSet fs : filesets) {
|
||||
DirectoryScanner ds = fs.getDirectoryScanner(project);
|
||||
for (String srcFile : ds.getIncludedFiles()) {
|
||||
File file = new File(ds.getBasedir() + File.separator + srcFile);
|
||||
files.add(new FileDataSource(file));
|
||||
List<String> ruleSetPaths = expandRuleSetPaths(configuration.getRuleSetPaths());
|
||||
// don't let PmdAnalysis.create create rulesets itself.
|
||||
configuration.setRuleSets(Collections.emptyList());
|
||||
|
||||
ReportStats stats;
|
||||
try (PmdAnalysis pmd = PmdAnalysis.create(configuration)) {
|
||||
RuleSetLoader rulesetLoader =
|
||||
pmd.newRuleSetLoader().loadResourcesWith(setupResourceLoader());
|
||||
pmd.addRuleSets(rulesetLoader.loadRuleSetsWithoutException(ruleSetPaths));
|
||||
|
||||
for (FileSet fileset : filesets) {
|
||||
DirectoryScanner ds = fileset.getDirectoryScanner(project);
|
||||
for (String srcFile : ds.getIncludedFiles()) {
|
||||
pmd.files().addFile(ds.getBasedir().toPath().resolve(srcFile));
|
||||
}
|
||||
|
||||
final String commonInputPath = ds.getBasedir().getPath();
|
||||
fullInputPath.add(commonInputPath);
|
||||
if (configuration.isReportShortNames()) {
|
||||
reportShortNamesPaths.add(commonInputPath);
|
||||
}
|
||||
}
|
||||
|
||||
final String commonInputPath = ds.getBasedir().getPath();
|
||||
fullInputPath.add(commonInputPath);
|
||||
if (configuration.isReportShortNames()) {
|
||||
reportShortNamesPaths.add(commonInputPath);
|
||||
@SuppressWarnings("PMD.CloseResource")
|
||||
ReportStatsListener reportStatsListener = new ReportStatsListener();
|
||||
pmd.addListener(getListener(reportStatsListener, reportShortNamesPaths, fullInputPath.toString()));
|
||||
|
||||
pmd.performAnalysis();
|
||||
stats = reportStatsListener.getResult();
|
||||
if (failOnError && pmd.getReporter().numErrors() > 0) {
|
||||
throw new BuildException("Some errors occurred while running PMD");
|
||||
}
|
||||
}
|
||||
configuration.setInputPaths(fullInputPath.toString());
|
||||
|
||||
try (GlobalAnalysisListener listener = getListener(reportSizeListener, reportShortNamesPaths)) {
|
||||
PMD.processFiles(configuration, rules, files, listener);
|
||||
} catch (Exception e) {
|
||||
throw new BuildException("Exception while closing data sources", e);
|
||||
}
|
||||
|
||||
int problemCount = reportSizeListener.getResult();
|
||||
int problemCount = stats.getNumViolations();
|
||||
project.log(problemCount + " problems found", Project.MSG_VERBOSE);
|
||||
|
||||
if (failuresPropertyName != null && problemCount > 0) {
|
||||
@ -152,34 +155,27 @@ public class PMDTaskImpl {
|
||||
}
|
||||
}
|
||||
|
||||
private List<RuleSet> loadRulesets(RuleSetLoader rulesetLoader) {
|
||||
try {
|
||||
// This is just used to validate and display rules. Each thread will create its own ruleset
|
||||
// Substitute env variables/properties
|
||||
String ruleSetString = project.replaceProperties(rulesetPaths);
|
||||
|
||||
List<String> rulesets = Arrays.asList(ruleSetString.split(","));
|
||||
List<RuleSet> rulesetList = rulesetLoader.loadFromResources(rulesets);
|
||||
if (rulesetList.isEmpty()) {
|
||||
throw new BuildException("No rulesets");
|
||||
}
|
||||
logRulesUsed(rulesetList);
|
||||
return rulesetList;
|
||||
} catch (RuleSetLoadException e) {
|
||||
throw new BuildException(e.getMessage(), e);
|
||||
private List<String> expandRuleSetPaths(List<String> ruleSetPaths) {
|
||||
List<String> paths = new ArrayList<>(ruleSetPaths);
|
||||
for (int i = 0; i < paths.size(); i++) {
|
||||
paths.set(i, project.replaceProperties(paths.get(i)));
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
private @NonNull GlobalAnalysisListener getListener(ViolationCounterListener reportSizeListener, List<String> reportShortNamesPaths) {
|
||||
private @NonNull GlobalAnalysisListener getListener(ReportStatsListener reportSizeListener,
|
||||
List<String> reportShortNamesPaths,
|
||||
String inputPaths) {
|
||||
List<GlobalAnalysisListener> renderers = new ArrayList<>(formatters.size() + 1);
|
||||
try {
|
||||
renderers.add(makeLogListener(configuration.getInputPaths()));
|
||||
renderers.add(makeLogListener(inputPaths));
|
||||
renderers.add(reportSizeListener);
|
||||
for (Formatter formatter : formatters) {
|
||||
project.log("Sending a report to " + formatter, Project.MSG_VERBOSE);
|
||||
renderers.add(formatter.newListener(project, reportShortNamesPaths));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return GlobalAnalysisListener.tee(renderers);
|
||||
} catch (Exception e) {
|
||||
// close those opened so far
|
||||
Exception e2 = IOUtil.closeAll(renderers);
|
||||
if (e2 != null) {
|
||||
@ -187,8 +183,6 @@ public class PMDTaskImpl {
|
||||
}
|
||||
throw new BuildException("Exception while initializing renderers", e);
|
||||
}
|
||||
|
||||
return GlobalAnalysisListener.tee(renderers);
|
||||
}
|
||||
|
||||
private GlobalAnalysisListener makeLogListener(String commonInputPath) {
|
||||
@ -233,9 +227,9 @@ public class PMDTaskImpl {
|
||||
try {
|
||||
if (auxClasspath != null) {
|
||||
project.log("Using auxclasspath: " + auxClasspath, Project.MSG_VERBOSE);
|
||||
configuration.prependClasspath(auxClasspath.toString());
|
||||
configuration.prependAuxClasspath(auxClasspath.toString());
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
} catch (IllegalArgumentException ioe) {
|
||||
throw new BuildException(ioe.getMessage(), ioe);
|
||||
}
|
||||
}
|
||||
@ -257,13 +251,4 @@ public class PMDTaskImpl {
|
||||
}
|
||||
}
|
||||
|
||||
private void logRulesUsed(List<RuleSet> rulesets) {
|
||||
project.log("Using these rulesets: " + rulesetPaths, Project.MSG_VERBOSE);
|
||||
|
||||
for (RuleSet ruleSet : rulesets) {
|
||||
for (Rule rule : ruleSet.getRules()) {
|
||||
project.log("Using rule " + rule.getName(), Project.MSG_VERBOSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sourceforge.pmd.PMDVersion;
|
||||
import net.sourceforge.pmd.Report.ProcessingError;
|
||||
import net.sourceforge.pmd.RuleSets;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
@ -210,13 +211,26 @@ public abstract class AbstractAnalysisCache implements AnalysisCache {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileAnalysisListener startFileAnalysis(DataSource filename) {
|
||||
return violation -> {
|
||||
final AnalysisResult analysisResult =
|
||||
updatedResultsCache.get(violation.getFilename());
|
||||
public FileAnalysisListener startFileAnalysis(DataSource dataSource) {
|
||||
String fileName = dataSource.getNiceFileName(false, "");
|
||||
File sourceFile = new File(fileName);
|
||||
AnalysisResult analysisResult = updatedResultsCache.get(fileName);
|
||||
if (analysisResult == null) {
|
||||
analysisResult = new AnalysisResult(sourceFile);
|
||||
}
|
||||
final AnalysisResult nonNullAnalysisResult = analysisResult;
|
||||
|
||||
synchronized (analysisResult) {
|
||||
analysisResult.addViolation(violation);
|
||||
return new FileAnalysisListener() {
|
||||
@Override
|
||||
public void onRuleViolation(RuleViolation violation) {
|
||||
synchronized (nonNullAnalysisResult) {
|
||||
nonNullAnalysisResult.addViolation(violation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ProcessingError error) {
|
||||
analysisFailed(sourceFile);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
package net.sourceforge.pmd.cache;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.RuleSets;
|
||||
@ -12,6 +13,7 @@ import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.reporting.FileAnalysisListener;
|
||||
import net.sourceforge.pmd.reporting.GlobalAnalysisListener;
|
||||
import net.sourceforge.pmd.util.datasource.DataSource;
|
||||
|
||||
/**
|
||||
* An analysis cache for incremental analysis.
|
||||
@ -22,12 +24,12 @@ import net.sourceforge.pmd.reporting.GlobalAnalysisListener;
|
||||
*/
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
public interface AnalysisCache extends GlobalAnalysisListener {
|
||||
public interface AnalysisCache {
|
||||
|
||||
/**
|
||||
* Persists the updated analysis results on whatever medium is used by the cache.
|
||||
*/
|
||||
void persist();
|
||||
void persist() throws IOException;
|
||||
|
||||
/**
|
||||
* Checks if a given file is up to date in the cache and can be skipped from analysis.
|
||||
@ -59,8 +61,16 @@ public interface AnalysisCache extends GlobalAnalysisListener {
|
||||
* cache is invalidated. This needs to be called before analysis, as it
|
||||
* conditions the good behaviour of {@link #isUpToDate(File)}.
|
||||
*
|
||||
* @param ruleSets The rulesets configured for this analysis.
|
||||
* @param ruleSets The rulesets configured for this analysis.
|
||||
* @param auxclassPathClassLoader The class loader for auxclasspath configured for this analysis.
|
||||
*/
|
||||
void checkValidity(RuleSets ruleSets, ClassLoader auxclassPathClassLoader);
|
||||
|
||||
/**
|
||||
* Returns a listener that will be used like in {@link GlobalAnalysisListener#startFileAnalysis(DataSource)}.
|
||||
* This should record violations, and call {@link #analysisFailed(File)}
|
||||
* upon error.
|
||||
*/
|
||||
FileAnalysisListener startFileAnalysis(DataSource file);
|
||||
|
||||
}
|
||||
|
40
pmd-core/src/main/java/net/sourceforge/pmd/cache/AnalysisCacheListener.java
vendored
Normal file
40
pmd-core/src/main/java/net/sourceforge/pmd/cache/AnalysisCacheListener.java
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.sourceforge.pmd.RuleSets;
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.reporting.FileAnalysisListener;
|
||||
import net.sourceforge.pmd.reporting.GlobalAnalysisListener;
|
||||
import net.sourceforge.pmd.util.datasource.DataSource;
|
||||
|
||||
/**
|
||||
* Adapter to wrap {@link AnalysisCache} behaviour in a {@link GlobalAnalysisListener}.
|
||||
*/
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
public class AnalysisCacheListener implements GlobalAnalysisListener {
|
||||
|
||||
private final AnalysisCache cache;
|
||||
|
||||
public AnalysisCacheListener(AnalysisCache cache, RuleSets ruleSets, ClassLoader classLoader) {
|
||||
this.cache = cache;
|
||||
cache.checkValidity(ruleSets, classLoader);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FileAnalysisListener startFileAnalysis(DataSource file) {
|
||||
return cache.startFileAnalysis(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
cache.persist();
|
||||
}
|
||||
|
||||
}
|
@ -151,11 +151,6 @@ public class FileAnalysisCache extends AbstractAnalysisCache {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
// nothing to do, PMD calls persist explicitly
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean cacheExists() {
|
||||
return cacheFile.exists() && cacheFile.isFile() && cacheFile.length() > 0;
|
||||
|
@ -53,8 +53,4 @@ public class NoopAnalysisCache implements AnalysisCache {
|
||||
return FileAnalysisListener.noop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.sourceforge.pmd.PMD;
|
||||
import net.sourceforge.pmd.PMD.StatusCode;
|
||||
import net.sourceforge.pmd.PMDVersion;
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.Language;
|
||||
@ -28,13 +29,39 @@ import com.beust.jcommander.ParameterException;
|
||||
@InternalApi
|
||||
public final class PMDCommandLineInterface {
|
||||
|
||||
@Deprecated
|
||||
public static final String PROG_NAME = "pmd";
|
||||
|
||||
/**
|
||||
* @deprecated This is used for testing, but support for it will be removed in PMD 7.
|
||||
* Use {@link PMD#runPmd(String...)} or an overload to avoid exiting the VM. In PMD 7,
|
||||
* {@link PMD#main(String[])} will call {@link System#exit(int)} always.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String NO_EXIT_AFTER_RUN = "net.sourceforge.pmd.cli.noExit";
|
||||
|
||||
/**
|
||||
* @deprecated This is used for testing, but support for it will be removed in PMD 7.
|
||||
* Use {@link PMD#runPmd(String...)} or an overload to avoid exiting the VM. In PMD 7,
|
||||
* {@link PMD#main(String[])} will call {@link System#exit(int)} always.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String STATUS_CODE_PROPERTY = "net.sourceforge.pmd.cli.status";
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link StatusCode#OK}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int NO_ERRORS_STATUS = 0;
|
||||
/**
|
||||
* @deprecated Use {@link StatusCode#ERROR}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int ERROR_STATUS = 1;
|
||||
/**
|
||||
* @deprecated Use {@link StatusCode#VIOLATIONS_FOUND}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int VIOLATIONS_FOUND = 4;
|
||||
|
||||
private PMDCommandLineInterface() { }
|
||||
@ -126,7 +153,10 @@ public final class PMDCommandLineInterface {
|
||||
* For testing purpose only...
|
||||
*
|
||||
* @param args
|
||||
*
|
||||
* @deprecated Use {@link PMD#runPmd(String...)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static void main(String[] args) {
|
||||
System.out.println(PMDCommandLineInterface.buildUsageText());
|
||||
}
|
||||
@ -160,14 +190,6 @@ public final class PMDCommandLineInterface {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link PMD#main(String[])}
|
||||
*/
|
||||
@Deprecated
|
||||
public static void run(String[] args) {
|
||||
setStatusCodeOrExit(PMD.run(args));
|
||||
}
|
||||
|
||||
public static void setStatusCodeOrExit(int status) {
|
||||
if (isExitAfterRunSet()) {
|
||||
System.exit(status);
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
package net.sourceforge.pmd.cli;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -235,8 +234,8 @@ public class PMDParameters {
|
||||
}
|
||||
|
||||
try {
|
||||
configuration.prependClasspath(this.getAuxclasspath());
|
||||
} catch (IOException e) {
|
||||
configuration.prependAuxClasspath(this.getAuxclasspath());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException("Invalid auxiliary classpath: " + e.getMessage(), e);
|
||||
}
|
||||
return configuration;
|
||||
|
@ -25,10 +25,12 @@ public final class AssertionUtil {
|
||||
|
||||
/** @throws NullPointerException if $name */
|
||||
public static void requireContainsNoNullValue(String name, Collection<?> c) {
|
||||
int i = 0;
|
||||
for (Object o : c) {
|
||||
if (o == null) {
|
||||
throw new NullPointerException(name + " contains null elements");
|
||||
throw new NullPointerException(name + " contains a null element at index " + i);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.internal.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sourceforge.pmd.PMDConfiguration;
|
||||
import net.sourceforge.pmd.lang.Language;
|
||||
import net.sourceforge.pmd.lang.document.FileCollector;
|
||||
import net.sourceforge.pmd.lang.document.TextFile;
|
||||
import net.sourceforge.pmd.util.FileUtil;
|
||||
import net.sourceforge.pmd.util.database.DBMSMetadata;
|
||||
import net.sourceforge.pmd.util.database.DBURI;
|
||||
import net.sourceforge.pmd.util.database.SourceObject;
|
||||
import net.sourceforge.pmd.util.datasource.DataSource;
|
||||
import net.sourceforge.pmd.util.log.MessageReporter;
|
||||
import net.sourceforge.pmd.util.log.internal.ErrorsAsWarningsReporter;
|
||||
|
||||
/**
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public final class FileCollectionUtil {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FileCollectionUtil.class);
|
||||
|
||||
private FileCollectionUtil() {
|
||||
|
||||
}
|
||||
|
||||
public static List<DataSource> collectorToDataSource(FileCollector collector) {
|
||||
List<DataSource> result = new ArrayList<>();
|
||||
for (TextFile file : collector.getCollectedFiles()) {
|
||||
result.add(file.toDataSourceCompat());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static FileCollector collectFiles(PMDConfiguration configuration, Set<Language> languages, MessageReporter reporter) {
|
||||
FileCollector collector = collectFiles(configuration, reporter);
|
||||
collector.filterLanguages(languages);
|
||||
return collector;
|
||||
}
|
||||
|
||||
private static FileCollector collectFiles(PMDConfiguration configuration, MessageReporter reporter) {
|
||||
FileCollector collector = FileCollector.newCollector(
|
||||
configuration.getLanguageVersionDiscoverer(),
|
||||
reporter
|
||||
);
|
||||
collectFiles(configuration, collector);
|
||||
return collector;
|
||||
}
|
||||
|
||||
public static void collectFiles(PMDConfiguration configuration, FileCollector collector) {
|
||||
if (configuration.getSourceEncoding() != null) {
|
||||
collector.setCharset(configuration.getSourceEncoding());
|
||||
}
|
||||
|
||||
if (configuration.getInputPaths() != null) {
|
||||
collectFiles(collector, configuration.getInputPaths());
|
||||
}
|
||||
|
||||
if (configuration.getInputUri() != null) {
|
||||
collectDB(collector, configuration.getInputUri());
|
||||
}
|
||||
|
||||
if (configuration.getInputFilePath() != null) {
|
||||
collectFileList(collector, configuration.getInputFilePath());
|
||||
}
|
||||
|
||||
if (configuration.getIgnoreFilePath() != null) {
|
||||
// This is to be able to interpret the log (will report 'adding' xxx)
|
||||
LOG.debug("Now collecting files to exclude.");
|
||||
// errors like "excluded file does not exist" are reported as warnings.
|
||||
// todo better reporting of *where* exactly the path is
|
||||
MessageReporter mutedLog = new ErrorsAsWarningsReporter(collector.getReporter());
|
||||
try (FileCollector excludeCollector = collector.newCollector(mutedLog)) {
|
||||
collectFileList(excludeCollector, configuration.getIgnoreFilePath());
|
||||
collector.exclude(excludeCollector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void collectFiles(FileCollector collector, String fileLocations) {
|
||||
for (String rootLocation : fileLocations.split(",")) {
|
||||
try {
|
||||
collector.relativizeWith(rootLocation);
|
||||
addRoot(collector, rootLocation);
|
||||
} catch (IOException e) {
|
||||
collector.getReporter().errorEx("Error collecting " + rootLocation, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void collectFileList(FileCollector collector, String fileListLocation) {
|
||||
LOG.debug("Reading file list {}.", fileListLocation);
|
||||
Path path = Paths.get(fileListLocation);
|
||||
if (!Files.exists(path)) {
|
||||
collector.getReporter().error("No such file {}", fileListLocation);
|
||||
return;
|
||||
}
|
||||
|
||||
String filePaths;
|
||||
try {
|
||||
filePaths = FileUtil.readFilelist(path.toFile());
|
||||
} catch (IOException e) {
|
||||
collector.getReporter().errorEx("Error reading {}", new Object[] { fileListLocation }, e);
|
||||
return;
|
||||
}
|
||||
collectFiles(collector, filePaths);
|
||||
}
|
||||
|
||||
private static void addRoot(FileCollector collector, String rootLocation) throws IOException {
|
||||
Path path = Paths.get(rootLocation);
|
||||
if (!Files.exists(path)) {
|
||||
collector.getReporter().error("No such file {}", path);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Files.isDirectory(path)) {
|
||||
LOG.debug("Adding directory {}.", path);
|
||||
collector.addDirectory(path);
|
||||
} else if (rootLocation.endsWith(".zip") || rootLocation.endsWith(".jar")) {
|
||||
LOG.debug("Adding zip file {}.", path);
|
||||
@SuppressWarnings("PMD.CloseResource")
|
||||
FileSystem fs = collector.addZipFile(path);
|
||||
if (fs == null) {
|
||||
return;
|
||||
}
|
||||
for (Path zipRoot : fs.getRootDirectories()) {
|
||||
collector.addFileOrDirectory(zipRoot);
|
||||
}
|
||||
} else if (Files.isRegularFile(path)) {
|
||||
LOG.debug("Adding regular file {}.", path);
|
||||
collector.addFile(path);
|
||||
} else {
|
||||
LOG.debug("Ignoring {}: not a regular file or directory", path);
|
||||
}
|
||||
}
|
||||
|
||||
public static void collectDB(FileCollector collector, String uriString) {
|
||||
try {
|
||||
LOG.debug("Connecting to {}", uriString);
|
||||
DBURI dbUri = new DBURI(uriString);
|
||||
DBMSMetadata dbmsMetadata = new DBMSMetadata(dbUri);
|
||||
LOG.trace("DBMSMetadata retrieved");
|
||||
List<SourceObject> sourceObjectList = dbmsMetadata.getSourceObjectList();
|
||||
LOG.trace("Located {} database source objects", sourceObjectList.size());
|
||||
for (SourceObject sourceObject : sourceObjectList) {
|
||||
String falseFilePath = sourceObject.getPseudoFileName();
|
||||
LOG.trace("Adding database source object {}", falseFilePath);
|
||||
|
||||
try (Reader sourceCode = dbmsMetadata.getSourceCode(sourceObject)) {
|
||||
String source = IOUtils.toString(sourceCode);
|
||||
collector.addSourceFile(source, falseFilePath);
|
||||
} catch (SQLException ex) {
|
||||
collector.getReporter().warnEx("Cannot get SourceCode for {} - skipping ...",
|
||||
new Object[] { falseFilePath },
|
||||
ex);
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
collector.getReporter().errorEx("Cannot get files from DB - probably missing database JDBC driver", e);
|
||||
} catch (Exception e) {
|
||||
collector.getReporter().errorEx("Cannot get files from DB - ''{}''", new Object[] { uriString }, e);
|
||||
}
|
||||
}
|
||||
}
|
@ -154,7 +154,7 @@ public abstract class BaseLanguageModule implements Language {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LanguageModule:" + name + '(' + this.getClass().getSimpleName() + ')';
|
||||
return getTerseName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -35,7 +35,7 @@ public class LanguageVersion implements Comparable<LanguageVersion> {
|
||||
|
||||
private final Language language;
|
||||
private final String version;
|
||||
private final LanguageVersionHandler languageVersionHandler;
|
||||
private final LanguageVersionHandler languageVersionHandler; // note: this is null if this is a cpd-only language...
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link Language#getVersion(String)}. This is only
|
||||
|
@ -8,6 +8,11 @@ import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import net.sourceforge.pmd.internal.util.AssertionUtil;
|
||||
|
||||
/**
|
||||
* This class can discover the LanguageVersion of a source file. Further, every
|
||||
@ -17,6 +22,23 @@ import java.util.Map;
|
||||
public class LanguageVersionDiscoverer {
|
||||
private Map<Language, LanguageVersion> languageToLanguageVersion = new HashMap<>();
|
||||
|
||||
private LanguageVersion forcedVersion;
|
||||
|
||||
public LanguageVersionDiscoverer() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a new instance.
|
||||
*
|
||||
* @param forcedVersion If non-null, all files should be assigned this version.
|
||||
* The methods of this class still work as usual and do not
|
||||
* care about the forced language version.
|
||||
*/
|
||||
public LanguageVersionDiscoverer(LanguageVersion forcedVersion) {
|
||||
this.forcedVersion = forcedVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given LanguageVersion as the current default for it's Language.
|
||||
*
|
||||
@ -25,6 +47,7 @@ public class LanguageVersionDiscoverer {
|
||||
* @return The previous default version for the language.
|
||||
*/
|
||||
public LanguageVersion setDefaultLanguageVersion(LanguageVersion languageVersion) {
|
||||
AssertionUtil.requireParamNotNull("languageVersion", languageVersion);
|
||||
LanguageVersion currentLanguageVersion = languageToLanguageVersion.put(languageVersion.getLanguage(),
|
||||
languageVersion);
|
||||
if (currentLanguageVersion == null) {
|
||||
@ -41,6 +64,7 @@ public class LanguageVersionDiscoverer {
|
||||
* @return The current default version for the language.
|
||||
*/
|
||||
public LanguageVersion getDefaultLanguageVersion(Language language) {
|
||||
Objects.requireNonNull(language);
|
||||
LanguageVersion languageVersion = languageToLanguageVersion.get(language);
|
||||
if (languageVersion == null) {
|
||||
languageVersion = language.getDefaultVersion();
|
||||
@ -81,6 +105,14 @@ public class LanguageVersionDiscoverer {
|
||||
return languageVersion;
|
||||
}
|
||||
|
||||
public LanguageVersion getForcedVersion() {
|
||||
return forcedVersion;
|
||||
}
|
||||
|
||||
public void setForcedVersion(LanguageVersion forceLanguageVersion) {
|
||||
this.forcedVersion = forceLanguageVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Languages of a given source file.
|
||||
*
|
||||
@ -106,11 +138,8 @@ public class LanguageVersionDiscoverer {
|
||||
|
||||
// Get the extensions from a file
|
||||
private String getExtension(String fileName) {
|
||||
String extension = null;
|
||||
int extensionIndex = 1 + fileName.lastIndexOf('.');
|
||||
if (extensionIndex > 0) {
|
||||
extension = fileName.substring(extensionIndex);
|
||||
}
|
||||
return extension;
|
||||
return StringUtils.substringAfterLast(fileName, ".");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import java.util.Objects;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import net.sourceforge.pmd.PMD;
|
||||
import net.sourceforge.pmd.PMDConfiguration;
|
||||
import net.sourceforge.pmd.lang.LanguageVersion;
|
||||
import net.sourceforge.pmd.properties.AbstractPropertySource;
|
||||
import net.sourceforge.pmd.properties.PropertyDescriptor;
|
||||
@ -72,7 +72,7 @@ public interface Parser {
|
||||
public static final PropertyDescriptor<String> COMMENT_MARKER =
|
||||
PropertyFactory.stringProperty("suppressionCommentMarker")
|
||||
.desc("deprecated! NOPMD")
|
||||
.defaultValue(PMD.SUPPRESS_MARKER)
|
||||
.defaultValue(PMDConfiguration.DEFAULT_SUPPRESS_MARKER)
|
||||
.build();
|
||||
|
||||
@Deprecated // transitional until language properties are implemented
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user