Merge branch '7.0.x' into java-pattern-binding-scopes

This commit is contained in:
Clément Fournier committed 2022-02-06 14:14:37 +01:00
commit c93eb11703
17 files changed
+314 -212

No files matched your search

+1 -1
View File
@@ -129,7 +129,7 @@
<rule ref="category/java/design.xml/ClassWithOnlyPrivateConstructorsShouldBeFinal"/>
<rule ref="category/java/design.xml/CognitiveComplexity" />
<rule ref="category/java/design.xml/CollapsibleIfStatements"/>
<!-- <rule ref="category/java/design.xml/CouplingBetweenObjects"/> -->
<rule ref="category/java/design.xml/CouplingBetweenObjects"/>
<rule ref="category/java/design.xml/CyclomaticComplexity"/>
<rule ref="category/java/design.xml/DataClass"/>
<rule ref="category/java/design.xml/DoNotExtendJavaLangError"/>
+1 -1
View File
@@ -2,7 +2,7 @@ repository: pmd/pmd
pmd:
version: 7.0.0-SNAPSHOT
previous_version: 6.41.0
previous_version: 6.42.0
date: ??-?????-2022
release_type: major
+4
View File
@@ -246,6 +246,10 @@ the breaking API changes will be performed in 7.0.0.
an API is tagged as `@Deprecated` or not in the latest minor release. During the development of 7.0.0,
we may decide to remove some APIs that were not tagged as deprecated, though we'll try to avoid it." %}
#### 6.42.0
No changes.
#### 6.41.0
##### Command Line Interface
-59
View File
@@ -19,70 +19,11 @@ This is a {{ site.pmd.release_type }} release.
### New and noteworthy
#### Javascript: Rhino updated to latest version 1.7.14
[Rhino](https://github.com/mozilla/rhino), the implementation of JavaScript we use
for parsing JavaScript code, has been updated to the latest version 1.7.14.
Now language features like template strings can be parsed. However Rhino does
not support all features of the latest EcmaScript standard.
#### New rules
* The new Java rule {% rule "java/codestyle/FinalParameterInAbstractMethod" %} detects parameters that are
declared as final in interfaces or abstract methods. Declaring the parameters as final is useless
because the implementation may choose to not respect it.
```xml
<rule ref="category/java/codestyle.xml/FinalParameterInAbstractMethod" />
```
The rule is part of the quickstart.xml ruleset.
#### Modified rules
* The Apex rule {% rule "apex/documentation/ApexDoc" %} has a new property `reportProperty`.
If set to `false` (default is `true` if unspecified) doesn't report missing ApexDoc comments on properties.
It allows you to enforce ApexDoc comments for classes and methods without requiring them for properties.
### Fixed Issues
* java
* [#3698](https://github.com/pmd/pmd/issues/3698): \[java] Error resolving Symbol Table
* java-bestpractices
* [#3209](https://github.com/pmd/pmd/issues/3209): \[java] UnusedPrivateMethod false positive with static method and cast expression
* [#3468](https://github.com/pmd/pmd/issues/3468): \[java] UnusedPrivateMethod false positive when outer class calls private static method on inner class
* java-design
* [#3679](https://github.com/pmd/pmd/issues/3679): \[java] Make FinalFieldCouldBeStatic detect constant variable
* java-errorprone
* [#3644](https://github.com/pmd/pmd/issues/3644): \[java] InvalidLogMessageFormat: false positives with logstash structured logging
* [#3686](https://github.com/pmd/pmd/issues/3686): \[java] ReturnEmptyCollectionRatherThanNull - false negative with conditioned returns
* [#3701](https://github.com/pmd/pmd/issues/3701): \[java] MissingStaticMethodInNonInstantiatableClass false positive with method inner classes
* [#3721](https://github.com/pmd/pmd/issues/3721): \[java] ReturnEmptyCollectionRatherThanNull - false positive with stream and lambda
* java-performance
* [#3492](https://github.com/pmd/pmd/issues/3492): \[java] UselessStringValueOf: False positive when there is no initial String to append to
* [#3639](https://github.com/pmd/pmd/issues/3639): \[java] UseStringBufferLength: false negative with empty string variable
* [#3712](https://github.com/pmd/pmd/issues/3712): \[java] InsufficientStringBufferDeclaration false positive with StringBuilder.setLength(0)
* javascript
* [#3703](https://github.com/pmd/pmd/issues/3703): \[javascript] Error - no Node adapter class registered for XmlPropRef
### API Changes
### External Contributions
* [#3631](https://github.com/pmd/pmd/pull/3631): \[java] Fixed False positive for UselessStringValueOf when there is no initial String to append to - [John Armgardt](https://github.com/johnra2)
* [#3683](https://github.com/pmd/pmd/pull/3683): \[java] Fixed 3468 UnusedPrivateMethod false positive when outer class calls private static method on inner class - [John Armgardt](https://github.com/johnra2)
* [#3688](https://github.com/pmd/pmd/pull/3688): \[java] Bump log4j to 2.16.0 - [Sergey Nuyanzin](https://github.com/snuyanzin)
* [#3693](https://github.com/pmd/pmd/pull/3693): \[apex] ApexDoc: Add reportProperty property - [Steve Babula](https://github.com/babula)
* [#3704](https://github.com/pmd/pmd/pull/3704): \[java] Fix for #3686 - Fix ReturnEmptyCollectionRatherThanNull - [Oleksii Dykov](https://github.com/dykov)
* [#3713](https://github.com/pmd/pmd/pull/3713): \[java] Enhance UnnecessaryModifier to support records - [Vincent Galloy](https://github.com/vgalloy)
* [#3719](https://github.com/pmd/pmd/pull/3719): \[java] Upgrade log4j to 2.17.1 - [Daniel Paul Searles](https://github.com/squaresurf)
* [#3720](https://github.com/pmd/pmd/pull/3720): \[java] New rule: FinalParameterInAbstractMethod - [Vincent Galloy](https://github.com/vgalloy)
* [#3724](https://github.com/pmd/pmd/pull/3724): \[java] Fix for #3679 - fix FinalFieldCouldBeStatic - [Oleksii Dykov](https://github.com/dykov)
* [#3727](https://github.com/pmd/pmd/pull/3727): \[java] #3724 - fix FinalFieldCouldBeStatic: triggers only if the referenced name is static - [Oleksii Dykov](https://github.com/dykov)
* [#3742](https://github.com/pmd/pmd/pull/3742): \[java] Fix #3701 - fix MissingStaticMethodInNonInstantiatableClass for method local classes - [Oleksii Dykov](https://github.com/dykov)
* [#3744](https://github.com/pmd/pmd/pull/3744): \[core] Updated SaxonXPathRuleQueryTest.java - [Vyom Yadav](https://github.com/Vyom-Yadav)
* [#3745](https://github.com/pmd/pmd/pull/3745): \[java] Fix #3712: InsufficientStringBufferDeclaration setLength false positive - [Daniel Gredler](https://github.com/gredler)
* [#3747](https://github.com/pmd/pmd/pull/3747): \[visualforce] Updated DataType.java - [Vyom Yadav](https://github.com/Vyom-Yadav)
{% endtocmaker %}
+93
View File
@@ -5,6 +5,99 @@ permalink: pmd_release_notes_old.html
Previous versions of PMD can be downloaded here: https://github.com/pmd/pmd/releases
## 29-January-2022 - 6.42.0
The PMD team is pleased to announce PMD 6.42.0.
This is a minor release.
### Table Of Contents
* [New and noteworthy](#new-and-noteworthy)
* [Javascript: Rhino updated to latest version 1.7.14](#javascript:-rhino-updated-to-latest-version-1.7.14)
* [New rules](#new-rules)
* [Modified rules](#modified-rules)
* [Fixed Issues](#fixed-issues)
* [API Changes](#api-changes)
* [External Contributions](#external-contributions)
* [Stats](#stats)
### New and noteworthy
#### Javascript: Rhino updated to latest version 1.7.14
[Rhino](https://github.com/mozilla/rhino), the implementation of JavaScript we use
for parsing JavaScript code, has been updated to the latest version 1.7.14.
Now language features like template strings can be parsed. However Rhino does
not support all features of the latest EcmaScript standard.
#### New rules
* The new Java rule [`FinalParameterInAbstractMethod`](https://pmd.github.io/pmd-6.42.0/pmd_rules_java_codestyle.html#finalparameterinabstractmethod) detects parameters that are
declared as final in interfaces or abstract methods. Declaring the parameters as final is useless
because the implementation may choose to not respect it.
```xml
<rule ref="category/java/codestyle.xml/FinalParameterInAbstractMethod" />
```
The rule is part of the quickstart.xml ruleset.
#### Modified rules
* The Apex rule [`ApexDoc`](https://pmd.github.io/pmd-6.42.0/pmd_rules_apex_documentation.html#apexdoc) has a new property `reportProperty`.
If set to `false` (default is `true` if unspecified) doesn't report missing ApexDoc comments on properties.
It allows you to enforce ApexDoc comments for classes and methods without requiring them for properties.
### Fixed Issues
* core
* [#3328](https://github.com/pmd/pmd/issues/3328): \[core] designer.bat errors when JAVAFX_HOME contains spaces
* java
* [#3698](https://github.com/pmd/pmd/issues/3698): \[java] Error resolving Symbol Table
* java-bestpractices
* [#3209](https://github.com/pmd/pmd/issues/3209): \[java] UnusedPrivateMethod false positive with static method and cast expression
* [#3468](https://github.com/pmd/pmd/issues/3468): \[java] UnusedPrivateMethod false positive when outer class calls private static method on inner class
* java-design
* [#3679](https://github.com/pmd/pmd/issues/3679): \[java] Make FinalFieldCouldBeStatic detect constant variable
* java-errorprone
* [#3644](https://github.com/pmd/pmd/issues/3644): \[java] InvalidLogMessageFormat: false positives with logstash structured logging
* [#3686](https://github.com/pmd/pmd/issues/3686): \[java] ReturnEmptyCollectionRatherThanNull - false negative with conditioned returns
* [#3701](https://github.com/pmd/pmd/issues/3701): \[java] MissingStaticMethodInNonInstantiatableClass false positive with method inner classes
* [#3721](https://github.com/pmd/pmd/issues/3721): \[java] ReturnEmptyCollectionRatherThanNull - false positive with stream and lambda
* java-performance
* [#3492](https://github.com/pmd/pmd/issues/3492): \[java] UselessStringValueOf: False positive when there is no initial String to append to
* [#3639](https://github.com/pmd/pmd/issues/3639): \[java] UseStringBufferLength: false negative with empty string variable
* [#3712](https://github.com/pmd/pmd/issues/3712): \[java] InsufficientStringBufferDeclaration false positive with StringBuilder.setLength(0)
* javascript
* [#3703](https://github.com/pmd/pmd/issues/3703): \[javascript] Error - no Node adapter class registered for XmlPropRef
### API Changes
No changes.
### External Contributions
* [#3631](https://github.com/pmd/pmd/pull/3631): \[java] Fixed False positive for UselessStringValueOf when there is no initial String to append to - [John Armgardt](https://github.com/johnra2)
* [#3683](https://github.com/pmd/pmd/pull/3683): \[java] Fixed 3468 UnusedPrivateMethod false positive when outer class calls private static method on inner class - [John Armgardt](https://github.com/johnra2)
* [#3688](https://github.com/pmd/pmd/pull/3688): \[java] Bump log4j to 2.16.0 - [Sergey Nuyanzin](https://github.com/snuyanzin)
* [#3693](https://github.com/pmd/pmd/pull/3693): \[apex] ApexDoc: Add reportProperty property - [Steve Babula](https://github.com/babula)
* [#3704](https://github.com/pmd/pmd/pull/3704): \[java] Fix for #3686 - Fix ReturnEmptyCollectionRatherThanNull - [Oleksii Dykov](https://github.com/dykov)
* [#3713](https://github.com/pmd/pmd/pull/3713): \[java] Enhance UnnecessaryModifier to support records - [Vincent Galloy](https://github.com/vgalloy)
* [#3719](https://github.com/pmd/pmd/pull/3719): \[java] Upgrade log4j to 2.17.1 - [Daniel Paul Searles](https://github.com/squaresurf)
* [#3720](https://github.com/pmd/pmd/pull/3720): \[java] New rule: FinalParameterInAbstractMethod - [Vincent Galloy](https://github.com/vgalloy)
* [#3724](https://github.com/pmd/pmd/pull/3724): \[java] Fix for #3679 - fix FinalFieldCouldBeStatic - [Oleksii Dykov](https://github.com/dykov)
* [#3727](https://github.com/pmd/pmd/pull/3727): \[java] #3724 - fix FinalFieldCouldBeStatic: triggers only if the referenced name is static - [Oleksii Dykov](https://github.com/dykov)
* [#3742](https://github.com/pmd/pmd/pull/3742): \[java] Fix #3701 - fix MissingStaticMethodInNonInstantiatableClass for method local classes - [Oleksii Dykov](https://github.com/dykov)
* [#3744](https://github.com/pmd/pmd/pull/3744): \[core] Updated SaxonXPathRuleQueryTest.java - [Vyom Yadav](https://github.com/Vyom-Yadav)
* [#3745](https://github.com/pmd/pmd/pull/3745): \[java] Fix #3712: InsufficientStringBufferDeclaration setLength false positive - [Daniel Gredler](https://github.com/gredler)
* [#3747](https://github.com/pmd/pmd/pull/3747): \[visualforce] Updated DataType.java - [Vyom Yadav](https://github.com/Vyom-Yadav)
### Stats
* 88 commits
* 35 closed tickets & PRs
* Days since last release: 62
## 27-November-2021 - 6.41.0
The PMD team is pleased to announce PMD 6.41.0.
+34 -26
View File
@@ -9,9 +9,9 @@
}
},
"node_modules/@babel/runtime": {
"version": "7.16.3",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz",
"integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
"dev": true,
"dependencies": {
"regenerator-runtime": "^0.13.4"
@@ -84,9 +84,9 @@
}
},
"node_modules/async": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz",
"integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==",
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz",
"integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==",
"dev": true
},
"node_modules/camelcase": {
@@ -306,13 +306,13 @@
}
},
"node_modules/json-fixer": {
"version": "1.6.12",
"resolved": "https://registry.npmjs.org/json-fixer/-/json-fixer-1.6.12.tgz",
"integrity": "sha512-BGO9HExf0ZUVYvuWsps71Re513Ss0il1Wp7wYWkir2NthzincvNJEUu82KagEfAkGdjOMsypj3t2JB7drBKWnA==",
"version": "1.6.13",
"resolved": "https://registry.npmjs.org/json-fixer/-/json-fixer-1.6.13.tgz",
"integrity": "sha512-DKQ71M+0uwAG3QsUkeVgh6XREw/OkpnTfHfM+sdmxRjHvYZ8PlcMVF4ibsHQ1ckR63NROs68qUr1I0u6yPVePQ==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.14.6",
"chalk": "^4.1.1",
"chalk": "^4.1.2",
"pegjs": "^0.10.0"
},
"engines": {
@@ -353,15 +353,23 @@
"dev": true
},
"node_modules/node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dev": true,
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/onetime": {
@@ -690,9 +698,9 @@
},
"dependencies": {
"@babel/runtime": {
"version": "7.16.3",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz",
"integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==",
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
"integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
"dev": true,
"requires": {
"regenerator-runtime": "^0.13.4"
@@ -741,9 +749,9 @@
}
},
"async": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz",
"integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==",
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz",
"integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==",
"dev": true
},
"camelcase": {
@@ -912,13 +920,13 @@
"dev": true
},
"json-fixer": {
"version": "1.6.12",
"resolved": "https://registry.npmjs.org/json-fixer/-/json-fixer-1.6.12.tgz",
"integrity": "sha512-BGO9HExf0ZUVYvuWsps71Re513Ss0il1Wp7wYWkir2NthzincvNJEUu82KagEfAkGdjOMsypj3t2JB7drBKWnA==",
"version": "1.6.13",
"resolved": "https://registry.npmjs.org/json-fixer/-/json-fixer-1.6.13.tgz",
"integrity": "sha512-DKQ71M+0uwAG3QsUkeVgh6XREw/OkpnTfHfM+sdmxRjHvYZ8PlcMVF4ibsHQ1ckR63NROs68qUr1I0u6yPVePQ==",
"dev": true,
"requires": {
"@babel/runtime": "^7.14.6",
"chalk": "^4.1.1",
"chalk": "^4.1.2",
"pegjs": "^0.10.0"
}
},
@@ -950,9 +958,9 @@
"dev": true
},
"node-fetch": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dev": true,
"requires": {
"whatwg-url": "^5.0.0"
@@ -1,6 +1,6 @@
@echo off
set TOPDIR=%~dp0..
set TOPDIR="%~dp0.."
set OPTS=
set MAIN_CLASS=net.sourceforge.pmd.util.treeexport.TreeExportCli
java %PMD_JAVA_OPTS% -classpath "%TOPDIR%\lib\*" %OPTS% %MAIN_CLASS% %*
java %PMD_JAVA_OPTS% -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %*
+2 -2
View File
@@ -1,6 +1,6 @@
@echo off
set TOPDIR=%~dp0..
set TOPDIR="%~dp0.."
set OPTS=
set MAIN_CLASS=net.sourceforge.pmd.cpd.CPD
java %PMD_JAVA_OPTS% -classpath "%TOPDIR%\lib\*" %OPTS% %MAIN_CLASS% %*
java %PMD_JAVA_OPTS% -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %*
@@ -1,6 +1,6 @@
@echo off
set TOPDIR=%~dp0..
set TOPDIR="%~dp0.."
set OPTS=
set MAIN_CLASS=net.sourceforge.pmd.cpd.GUI
java %PMD_JAVA_OPTS% -classpath "%TOPDIR%\lib\*" %OPTS% %MAIN_CLASS% %*
java %PMD_JAVA_OPTS% -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %*
@@ -1,5 +1,5 @@
@echo off
set TOPDIR=%~dp0..
set TOPDIR="%~dp0.."
set OPTS=
set MAIN_CLASS=net.sourceforge.pmd.util.fxdesigner.DesignerStarter
@@ -42,10 +42,10 @@ if %_needjfxlib% EQU 1 (
pause
exit
)
set "classpath=%TOPDIR%\lib\*;%JAVAFX_HOME%\lib\*"
set classpath=%TOPDIR%\lib\*;%JAVAFX_HOME%\lib\*
) else (
set "classpath=%TOPDIR%\lib\*"
set classpath=%TOPDIR%\lib\*
)
java %PMD_JAVA_OPTS% %jreopts% -classpath "%classpath%" %OPTS% %MAIN_CLASS% %*
java %PMD_JAVA_OPTS% %jreopts% -classpath %classpath% %OPTS% %MAIN_CLASS% %*
+2 -2
View File
@@ -1,6 +1,6 @@
@echo off
set TOPDIR=%~dp0..
set TOPDIR="%~dp0.."
set OPTS=
set MAIN_CLASS=net.sourceforge.pmd.PMD
java %PMD_JAVA_OPTS% -classpath "%TOPDIR%\lib\*" %OPTS% %MAIN_CLASS% %*
java %PMD_JAVA_OPTS% -classpath %TOPDIR%\lib\* %OPTS% %MAIN_CLASS% %*
@@ -9,6 +9,7 @@ import static net.sourceforge.pmd.lang.java.ast.AccessNode.Visibility.V_PRIVATE;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.JModifier;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
@@ -21,7 +22,7 @@ public class ClassWithOnlyPrivateConstructorsShouldBeFinalRule extends AbstractJ
@Override
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
if (node.isRegularClass()
&& !node.isFinal()
&& !node.hasModifiers(JModifier.FINAL)
&& hasOnlyPrivateCtors(node)
&& hasNoSubclasses(node)) {
addViolation(data, node);
@@ -37,7 +38,7 @@ public class ClassWithOnlyPrivateConstructorsShouldBeFinalRule extends AbstractJ
}
private boolean doesExtend(ASTAnyTypeDeclaration sub, ASTClassOrInterfaceDeclaration superClass) {
return sub != superClass && TypeTestUtil.isA(superClass.getTypeMirror(), sub);
return sub != superClass && TypeTestUtil.isA(superClass.getTypeMirror().getErasure(), sub);
}
private boolean hasOnlyPrivateCtors(ASTClassOrInterfaceDeclaration node) {
@@ -7,22 +7,19 @@ package net.sourceforge.pmd.lang.java.rule.design;
import static net.sourceforge.pmd.properties.constraints.NumericConstraints.positive;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTReferenceType;
import net.sourceforge.pmd.lang.java.ast.ASTResultType;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTType;
import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.symboltable.ClassScope;
import net.sourceforge.pmd.lang.java.symbols.JAccessibleElementSymbol;
import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
import net.sourceforge.pmd.properties.PropertyDescriptor;
import net.sourceforge.pmd.properties.PropertyFactory;
@@ -38,13 +35,14 @@ import net.sourceforge.pmd.properties.PropertyFactory;
*/
public class CouplingBetweenObjectsRule extends AbstractJavaRule {
private int couplingCount;
private Set<String> typesFoundSoFar;
private static final PropertyDescriptor<Integer> THRESHOLD_DESCRIPTOR
= PropertyFactory.intProperty("threshold")
.desc("Unique type reporting threshold")
.require(positive()).defaultValue(20).build();
= PropertyFactory.intProperty("threshold")
.desc("Unique type reporting threshold")
.require(positive()).defaultValue(20).build();
private int couplingCount;
private boolean inInterface;
private final Set<JTypeMirror> typesFoundSoFar = new HashSet<>();
public CouplingBetweenObjectsRule() {
definePropertyDescriptor(THRESHOLD_DESCRIPTOR);
@@ -52,104 +50,70 @@ public class CouplingBetweenObjectsRule extends AbstractJavaRule {
@Override
public Object visit(ASTCompilationUnit cu, Object data) {
typesFoundSoFar = new HashSet<>();
couplingCount = 0;
Object returnObj = super.visit(cu, data);
super.visit(cu, data);
if (couplingCount > getProperty(THRESHOLD_DESCRIPTOR)) {
addViolation(data, cu,
"A value of " + couplingCount + " may denote a high amount of coupling within the class");
"A value of " + couplingCount + " may denote a high amount of coupling within the class");
}
return returnObj;
couplingCount = 0;
typesFoundSoFar.clear();
return null;
}
@Override
public Object visit(ASTResultType node, Object data) {
for (int x = 0; x < node.getNumChildren(); x++) {
Node tNode = node.getChild(x);
if (tNode instanceof ASTType) {
Node reftypeNode = tNode.getChild(0);
if (reftypeNode instanceof ASTReferenceType) {
Node classOrIntType = reftypeNode.getChild(0);
if (classOrIntType instanceof ASTClassOrInterfaceType) {
Node nameNode = classOrIntType;
this.checkVariableType(nameNode, nameNode.getImage());
}
}
}
}
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
boolean prev = inInterface;
inInterface = node.isInterface();
super.visit(node, data);
inInterface = prev;
return null;
}
@Override
public Object visit(ASTMethodDeclaration node, Object data) {
ASTType type = node.getResultTypeNode();
checkVariableType(type);
return super.visit(node, data);
}
@Override
public Object visit(ASTLocalVariableDeclaration node, Object data) {
handleASTTypeChildren(node);
ASTType type = node.getTypeNode();
checkVariableType(type);
return super.visit(node, data);
}
@Override
public Object visit(ASTFormalParameter node, Object data) {
handleASTTypeChildren(node);
ASTType type = node.getTypeNode();
checkVariableType(type);
return super.visit(node, data);
}
@Override
public Object visit(ASTFieldDeclaration node, Object data) {
for (int x = 0; x < node.getNumChildren(); ++x) {
Node firstStmt = node.getChild(x);
if (firstStmt instanceof ASTType) {
ASTType tp = (ASTType) firstStmt;
Node nd = tp.getChild(0);
checkVariableType(nd, nd.getImage());
}
}
ASTType type = node.getTypeNode();
checkVariableType(type);
return super.visit(node, data);
}
/**
* Convenience method to handle hierarchy. This is probably too much work and
* will go away once I figure out the framework
*/
private void handleASTTypeChildren(Node node) {
for (int x = 0; x < node.getNumChildren(); x++) {
Node sNode = node.getChild(x);
if (sNode instanceof ASTType) {
Node nameNode = sNode.getChild(0);
checkVariableType(nameNode, nameNode.getImage());
}
}
}
/**
* performs a check on the variable and updates the counter. Counter is
* instance for a class and is reset upon new class scan.
*
* @param variableType
* The variable type.
* @param typeNode The variable type.
*/
private void checkVariableType(Node nameNode, String variableType) {
List<ASTClassOrInterfaceDeclaration> parentTypes = nameNode.getParentsOfType(ASTClassOrInterfaceDeclaration.class);
// TODO - move this into the symbol table somehow?
if (parentTypes.isEmpty()) {
private void checkVariableType(ASTType typeNode) {
if (inInterface || typeNode == null) {
return;
}
// skip interfaces
if (parentTypes.get(0).isInterface()) {
return;
}
// if the field is of any type other than the class type
// increment the count
ClassScope clzScope = ((JavaNode) nameNode).getScope().getEnclosingScope(ClassScope.class);
if (!clzScope.getClassName().equals(variableType) && !this.filterTypes(variableType)
&& !this.typesFoundSoFar.contains(variableType)) {
JTypeMirror t = typeNode.getTypeMirror();
if (!this.ignoreType(typeNode, t) && this.typesFoundSoFar.add(t)) {
couplingCount++;
typesFoundSoFar.add(variableType);
}
}
@@ -158,24 +122,19 @@ public class CouplingBetweenObjectsRule extends AbstractJavaRule {
* This needs more work. I'd like to filter out super types and perhaps
* interfaces
*
* @param variableType
* The variable type.
* @param t The variable type.
*
* @return boolean true if variableType is not what we care about
*/
private boolean filterTypes(String variableType) {
return variableType != null && (variableType.startsWith("java.lang.") || "String".equals(variableType)
|| filterPrimitivesAndWrappers(variableType));
private boolean ignoreType(ASTType typeNode, JTypeMirror t) {
if (typeNode.getEnclosingType().getSymbol().equals(t.getSymbol())) {
return true;
}
JTypeDeclSymbol symbol = t.getSymbol();
return symbol == null
|| symbol.getPackageName().equals(JAccessibleElementSymbol.PRIMITIVE_PACKAGE)
|| t.isPrimitive()
|| t.isBoxedPrimitive();
}
/**
* @param variableType
* The variable type.
* @return boolean true if variableType is a primitive or wrapper
*/
private boolean filterPrimitivesAndWrappers(String variableType) {
return "int".equals(variableType) || "Integer".equals(variableType) || "char".equals(variableType)
|| "Character".equals(variableType) || "double".equals(variableType) || "long".equals(variableType)
|| "short".equals(variableType) || "float".equals(variableType) || "byte".equals(variableType)
|| "boolean".equals(variableType);
}
}
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.design;
import net.sourceforge.pmd.testframework.PmdRuleTst;
@org.junit.Ignore("Rule has not been updated yet")
public class CouplingBetweenObjectsTest extends PmdRuleTst {
// no additional unit tests
}
@@ -7,6 +7,18 @@
<test-code>
<description>Simple violation</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>1</expected-linenumbers>
<code><![CDATA[
public class Foo {
private Foo() { }
}
]]></code>
</test-code>
<test-code>
<description>violation for abstract class</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>1</expected-linenumbers>
<code><![CDATA[
public class Foo {
private Foo() { }
@@ -35,6 +47,17 @@ public class Foo {
]]></code>
</test-code>
<test-code>
<description>abstract class, one public constructor, not required to be final</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public abstract class Foo {
private Foo() { }
public Foo(String param) { }
}
]]></code>
</test-code>
<test-code>
<description>Ok, subclass using the private constructor</description>
<expected-problems>0</expected-problems>
@@ -74,7 +97,7 @@ public class Foo {
public class Foo {
private Foo() { }
}
public class Bar extends Foo {
class Bar extends Foo {
public Bar() { }
}
]]></code>
@@ -140,27 +163,55 @@ class ClassWithOnlyPrivateConstructorsShouldBeFinal {
<expected-problems>1</expected-problems>
<expected-linenumbers>2</expected-linenumbers>
<code><![CDATA[
public class Main209 {
private static class InputBits {
private InputBits(int number) { }
}
}
]]></code>
public class Main209 {
private static class InputBits {
private InputBits(int number) { }
}
}
]]></code>
</test-code>
<test-code>
<description>Private inner class with no ctor</description>
<description>Inner class with only private constructor extended within compilation unit (#2536)</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Main209 {
private static class InputBits {
private InputBits(int number) { }
}
public static final class Sub extends InputBits {
private Sub() {
super(1);
}
}
}
]]></code>
</test-code>
<test-code>
<description>Private inner class with no ctor and no usage</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>2</expected-linenumbers>
<code><![CDATA[
public class Main209 {
private static class InputBits {
// default ctor is implicitly private
}
}
]]></code>
public class Main209 {
private static class InputBits {
// default ctor is implicitly private
}
}
]]></code>
</test-code>
<test-code>
<description>Private inner class with no ctor and usage</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Main209 {
private static class InputBits {
// default ctor is implicitly private
}
public static final class Sub extends InputBits {}
}
]]></code>
</test-code>
<test-code regressionTest="false">
<test-code>
<description>Private abstract classes with abstract methods should be ignored #3668</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
@@ -168,6 +219,32 @@ public class Outer {
private abstract class Base {
abstract void run();
}
public void someMethod() {
Base b = new Base() {
void run() {}
};
b.run();
}
}
]]></code>
</test-code>
<test-code>
<description>Private abstract generic classes with abstract methods should be ignored #3668</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import java.util.Comparator;
public class Outer {
private abstract class Base<E> {
abstract void run();
abstract void sort(Comparator<E> comparator);
}
public void someMethod() {
Base b = new Base<Object>() {
void run() {}
void sort(Comparator<Object> comparator) {}
};
}
}
]]></code>
</test-code>
@@ -185,7 +262,7 @@ public class Outer {
]]></code>
</test-code>
<test-code regressionTest="false">
<test-code>
<description>Private abstract classes without abstract methods and subclasses #3668</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>2</expected-linenumbers>
@@ -194,6 +271,22 @@ public class Outer {
private abstract class Base {
private void run() {}
}
}
]]></code>
</test-code>
<test-code>
<description>Abstract outer classes should be flagged #3668</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>1</expected-linenumbers>
<code><![CDATA[
public abstract class FooUtils {
private FooUtils() {
// private constructor can't be called from sub classes,
// so this class can't be extended
}
// note: this "abstract" class does not contain abstract methods
// it was only declared as abstract to prevent instantiation
}
]]></code>
</test-code>
@@ -34,6 +34,10 @@ public class Foo {
<rule-property name="threshold">2</rule-property>
<expected-problems>0</expected-problems>
<code><![CDATA[
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
public interface Foo {
List foo();
ArrayList foo();
+3 -3
View File
@@ -76,7 +76,7 @@
</issueManagement>
<properties>
<project.build.outputTimestamp>2021-11-27T10:21:16Z</project.build.outputTimestamp>
<project.build.outputTimestamp>2022-01-29T08:53:37Z</project.build.outputTimestamp>
<java.version>8</java.version>
@@ -416,12 +416,12 @@
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-core</artifactId>
<version>6.41.0</version> <!-- pmd.dogfood.version -->
<version>6.42.0</version> <!-- pmd.dogfood.version -->
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-java</artifactId>
<version>6.41.0</version> <!-- pmd.dogfood.version -->
<version>6.42.0</version> <!-- pmd.dogfood.version -->
</dependency>
<!-- This contains the dogfood ruleset -->
<dependency>