diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index b8afc5698b..3905c313af 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -27,7 +27,6 @@ This is a minor release. letting you know exactly which modifiers are redundant at each declaration. ### Fixed Issues - * all * [#1168](https://github.com/pmd/pmd/issues/1168): \[core] xml renderer schema definitions (#538) break included xslt files * ecmascript @@ -36,6 +35,7 @@ This is a minor release. * [#651](https://github.com/pmd/pmd/issues/651): \[java] SwitchStmtsShouldHaveDefault should be aware of enum types * [#869](https://github.com/pmd/pmd/issues/869): \[java] GuardLogStatement false positive on return statements and Math.log * java-codestyle + * [#667](https://github.com/pmd/pmd/issues/667): [java] Make AtLeastOneConstructor Lombok-aware * [#1154](https://github.com/pmd/pmd/pull/1154): [java] CommentDefaultAccessModifierRule FP with nested enums * [#1158](https://github.com/pmd/pmd/issues/1158): \[java] Fix IdenticalCatchBranches false positive * xml diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateMethodRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateMethodRule.java index 6cd2a517e2..8cc74f19aa 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateMethodRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateMethodRule.java @@ -4,8 +4,8 @@ package net.sourceforge.pmd.lang.java.rule.bestpractices; -import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -33,9 +33,7 @@ public class UnusedPrivateMethodRule extends AbstractIgnoredAnnotationRule { @Override protected Collection defaultSuppressionAnnotations() { - Collection defaultValues = new ArrayList<>(); - defaultValues.add("java.lang.Deprecated"); - return defaultValues; + return Collections.singletonList("java.lang.Deprecated"); } /** diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/AtLeastOneConstructorRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/AtLeastOneConstructorRule.java new file mode 100644 index 0000000000..2983c4eaad --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/AtLeastOneConstructorRule.java @@ -0,0 +1,74 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codestyle; + +import java.util.Arrays; +import java.util.Collection; + +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.rule.AbstractIgnoredAnnotationRule; +import net.sourceforge.pmd.lang.java.rule.design.UseUtilityClassRule; + +/** + * This rule detects non-static classes with no constructors; + * requiring even the default constructor to be explicit. + * It ignores classes with solely static methods, + * use {@link UseUtilityClassRule} to flag those. + */ +public class AtLeastOneConstructorRule extends AbstractIgnoredAnnotationRule { + + public AtLeastOneConstructorRule() { + addRuleChainVisit(ASTClassOrInterfaceDeclaration.class); + } + + @Override + protected Collection defaultSuppressionAnnotations() { + return Arrays.asList("lombok.Data", + "lombok.Value", + "lombok.Builder", + "lombok.NoArgsConstructor", + "lombok.RequiredArgsConstructor", + "lombok.AllArgsConstructorAtLeastOneConstructor"); + } + + @Override + public Object visit(final ASTClassOrInterfaceDeclaration node, final Object data) { + // Ignore interfaces / static classes / classes that have a constructor / classes ignored through annotations + if (node.isInterface() || node.isStatic() || node.hasDescendantOfType(ASTConstructorDeclaration.class) + || hasIgnoredAnnotation(node)) { + return data; + } + + boolean atLeastOneMember = false; + + // Do we have any non-static methods? + for (final ASTMethodDeclaration m : node.findDescendantsOfType(ASTMethodDeclaration.class)) { + if (!m.isStatic()) { + addViolation(data, node); + return data; + } + atLeastOneMember = true; + } + + // .. or fields? + for (final ASTFieldDeclaration f : node.findDescendantsOfType(ASTFieldDeclaration.class)) { + if (!f.isStatic()) { + addViolation(data, node); + return data; + } + atLeastOneMember = true; + } + + // Class has no declared members + if (!atLeastOneMember) { + addViolation(data, node); + } + + return data; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryConstructorRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryConstructorRule.java index 3415351032..c9c8ad1e40 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryConstructorRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryConstructorRule.java @@ -4,8 +4,8 @@ package net.sourceforge.pmd.lang.java.rule.codestyle; -import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.List; import net.sourceforge.pmd.lang.ast.Node; @@ -26,7 +26,7 @@ public class UnnecessaryConstructorRule extends AbstractIgnoredAnnotationRule { @Override protected Collection defaultSuppressionAnnotations() { - return Arrays.asList("javax.inject.Inject"); + return Collections.singletonList("javax.inject.Inject"); } @Override diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index 0da8efdb00..64b12745c6 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -49,28 +49,15 @@ public abstract class Foo { // should be AbstractFoo language="java" since="1.04" message="Each class should declare at least one constructor" - class="net.sourceforge.pmd.lang.rule.XPathRule" + class="net.sourceforge.pmd.lang.java.rule.codestyle.AtLeastOneConstructorRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_codestyle.html#atleastoneconstructor"> -Each class should declare at least one constructor. + 3 - - - - - - - 0 @@ -113,6 +113,37 @@ public class TestAtLeastOneConstructor { public void NotStatic() { System.out.println("This class should have a constructor"); } +} + ]]> + + + Ignore classes with lombok-generated constructors + 0 + + + + Report classes with at least one non-static method + 1 + + + + Report classes with at least one non-static field + 1 +