diff --git a/docs/pages/pmd/rules/java.md b/docs/pages/pmd/rules/java.md index 80ca10856f..18c784a222 100644 --- a/docs/pages/pmd/rules/java.md +++ b/docs/pages/pmd/rules/java.md @@ -75,7 +75,7 @@ folder: pmd/rules * [BooleanGetMethodName](pmd_rules_java_codestyle.html#booleangetmethodname): Methods that return boolean results should be named as predicate statements to denote this.I.e, '... * [CallSuperInConstructor](pmd_rules_java_codestyle.html#callsuperinconstructor): It is a good practice to call super() in a constructor. If super() is not called butanother const... * [ClassNamingConventions](pmd_rules_java_codestyle.html#classnamingconventions): Configurable naming conventions for type declarations. This rule reports type declarat... -* [CommentDefaultAccessModifier](pmd_rules_java_codestyle.html#commentdefaultaccessmodifier): To avoid mistakes if we want that a Method, Constructor, Field or Nested class have a default acc... +* [CommentDefaultAccessModifier](pmd_rules_java_codestyle.html#commentdefaultaccessmodifier): To avoid mistakes if we want that an Annotation, Class, Enum, Method, Constructor or Field have a default acc... * [ConfusingTernary](pmd_rules_java_codestyle.html#confusingternary): Avoid negation within an "if" expression with an "else" clause. For example, rephrase:'if (x != ... * [ControlStatementBraces](pmd_rules_java_codestyle.html#controlstatementbraces): Enforce a policy for braces on control statements. It is recommended to use braces on 'if ... els... * [DefaultPackage](pmd_rules_java_codestyle.html#defaultpackage): Use explicit scoping instead of accidental usage of default package private level.The rule allows... diff --git a/docs/pages/pmd/rules/java/codestyle.md b/docs/pages/pmd/rules/java/codestyle.md index d2ff5b66c1..814e6a4f2a 100644 --- a/docs/pages/pmd/rules/java/codestyle.md +++ b/docs/pages/pmd/rules/java/codestyle.md @@ -473,7 +473,7 @@ public class Éléphant {} **Priority:** Medium (3) -To avoid mistakes if we want that a Method, Constructor, Field or Nested class have a default access modifier +To avoid mistakes if we want that an Annotation, Class, Enum, Method, Constructor or Field have a default access modifier we must add a comment at the beginning of it's declaration. By default the comment must be `/* default */` or `/* package */`, if you want another, you have to provide a regular expression. This rule ignores by default all cases that have a @VisibleForTesting annotation. Use the diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java index 37c5eac750..af2ebd7d56 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java @@ -11,10 +11,12 @@ import java.util.List; import java.util.Set; import java.util.regex.Pattern; +import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; @@ -84,11 +86,28 @@ public class CommentDefaultAccessModifierRule extends AbstractIgnoredAnnotationR return super.visit(decl, data); } + @Override + public Object visit(final ASTAnnotationTypeDeclaration decl, final Object data) { + if (!decl.isNested() && shouldReportTypeDeclaration(decl)) { // check for top-level annotation declarations + addViolationWithMessage(data, decl, String.format(MESSAGE, decl.getImage(), "top-level annotation")); + } + return super.visit(decl, data); + } + + @Override + public Object visit(final ASTEnumDeclaration decl, final Object data) { + if (!decl.isNested() && shouldReportTypeDeclaration(decl)) { // check for top-level enums + addViolationWithMessage(data, decl, String.format(MESSAGE, decl.getImage(), "top-level enum")); + } + return super.visit(decl, data); + } + @Override public Object visit(final ASTClassOrInterfaceDeclaration decl, final Object data) { - // check for nested classes - if (decl.isNested() && shouldReport(decl)) { + if (decl.isNested() && shouldReport(decl)) { // check for nested classes addViolationWithMessage(data, decl, String.format(MESSAGE, decl.getImage(), "nested class")); + } else if (!decl.isNested() && shouldReportTypeDeclaration(decl)) { // and for top-level ones + addViolationWithMessage(data, decl, String.format(MESSAGE, decl.getImage(), "top-level class")); } return super.visit(decl, data); } @@ -106,14 +125,15 @@ public class CommentDefaultAccessModifierRule extends AbstractIgnoredAnnotationR .getFirstParentOfType(AbstractAnyTypeDeclaration.class); boolean isConcreteClass = parentClassOrInterface.getTypeKind() == ASTAnyTypeDeclaration.TypeKind.CLASS; - boolean isEnumConstructor = parentClassOrInterface.getTypeKind() == ASTAnyTypeDeclaration.TypeKind.ENUM - && decl instanceof ASTConstructorDeclaration; - // ignore if it's an Interface / Annotation / Enum constructor - return isConcreteClass && !isEnumConstructor - // check if the field/method/nested class has a default access - // modifier - && decl.isPackagePrivate() + // ignore if it's an Interface / Annotation + return isConcreteClass && shouldReportTypeDeclaration(decl); + } + + private boolean shouldReportTypeDeclaration(final AbstractJavaAccessNode decl) { + // check if the class/method/field has a default access + // modifier + return decl.isPackagePrivate() // if is a default access modifier check if there is a comment // in this line && !interestingLineNumberComments.contains(decl.getBeginLine()) diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index 05bd9f803b..19c3e4dea5 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -402,7 +402,7 @@ public class Éléphant {} message="Missing commented default access modifier" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_codestyle.html#commentdefaultaccessmodifier"> -To avoid mistakes if we want that a Method, Constructor, Field or Nested class have a default access modifier +To avoid mistakes if we want that an Annotation, Class, Enum, Method, Constructor or Field have a default access modifier we must add a comment at the beginning of it's declaration. By default the comment must be `/* default */` or `/* package */`, if you want another, you have to provide a regular expression. This rule ignores by default all cases that have a @VisibleForTesting annotation. Use the diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml index a01d2c9997..ae52606693 100755 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml @@ -115,6 +115,66 @@ public class Foo { + + + Top-level annotations with default access modifier + 2 + 1,6 + + + + + + Top-level enums with default access modifier + 2 + 1,6 + + + + + + Top-level classes with default access modifier + 2 + 1,6 + + +