forked from phoedos/pmd
Merge branch 'Monits-addCommentDefaultModifierRule'
This commit is contained in:
@ -8,6 +8,7 @@
|
||||
This ruleset contains links to rules that are new in PMD v5.4.0
|
||||
</description>
|
||||
|
||||
<rule ref="rulesets/java/comments.xml/CommentDefaultAccessModifier"/>
|
||||
<rule ref="rulesets/java/design.xml/SingleMethodSingleton"/>
|
||||
<rule ref="rulesets/java/design.xml/SingletonClassReturningNewInstance"/>
|
||||
|
||||
|
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
package net.sourceforge.pmd.lang.java.rule.comments;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
|
||||
import net.sourceforge.pmd.lang.java.ast.AbstractJavaAccessNode;
|
||||
import net.sourceforge.pmd.lang.java.ast.Comment;
|
||||
import net.sourceforge.pmd.lang.rule.properties.StringProperty;
|
||||
|
||||
/**
|
||||
* Check for Methods, Fields and Nested Classes that have a default access modifier
|
||||
*
|
||||
* @author Damián Techeira
|
||||
*/
|
||||
public class CommentDefaultAccessModifierRule extends AbstractCommentRule {
|
||||
|
||||
private static final StringProperty REGEX_DESCRIPTOR = new StringProperty("regex", "Regular expression", "", 1.0f);
|
||||
private static final String MESSAGE = "To avoid mistakes add a comment " +
|
||||
"at the beginning of the %s %s if you want a default access modifier";
|
||||
private final Set<Integer> interestingLineNumberComments = new HashSet<Integer>();
|
||||
|
||||
public CommentDefaultAccessModifierRule() {
|
||||
definePropertyDescriptor(REGEX_DESCRIPTOR);
|
||||
}
|
||||
|
||||
public CommentDefaultAccessModifierRule(final String regex) {
|
||||
this();
|
||||
setRegex(regex);
|
||||
}
|
||||
|
||||
public void setRegex(final String regex) {
|
||||
setProperty(CommentDefaultAccessModifierRule.REGEX_DESCRIPTOR, regex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(final ASTCompilationUnit node, final Object data) {
|
||||
interestingLineNumberComments.clear();
|
||||
final List<Comment> comments = node.getComments();
|
||||
for (final Comment comment : comments) {
|
||||
if (comment.getImage().matches(getProperty(REGEX_DESCRIPTOR).trim())) {
|
||||
interestingLineNumberComments.add(comment.getBeginLine());
|
||||
}
|
||||
}
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(final ASTMethodDeclaration decl, final Object data) {
|
||||
if (shouldReport(decl)) {
|
||||
addViolationWithMessage(data, decl, String.format(MESSAGE,
|
||||
decl.getFirstChildOfType(ASTMethodDeclarator.class).getImage(), "method"));
|
||||
}
|
||||
return super.visit(decl, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(final ASTFieldDeclaration decl, final Object data) {
|
||||
if (shouldReport(decl)) {
|
||||
addViolationWithMessage(data, decl, String.format(MESSAGE,
|
||||
decl.getFirstDescendantOfType(ASTVariableDeclaratorId.class).getImage(), "field"));
|
||||
}
|
||||
return super.visit(decl, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(final ASTClassOrInterfaceDeclaration decl, final Object data) {
|
||||
// check for nested classes
|
||||
if (decl.isNested() && shouldReport(decl)) {
|
||||
addViolationWithMessage(data, decl, String.format(MESSAGE, decl.getImage(), "nested class"));
|
||||
}
|
||||
return super.visit(decl, data);
|
||||
}
|
||||
|
||||
private boolean shouldReport(final AbstractJavaAccessNode decl) {
|
||||
// ignore if is a Interface
|
||||
return !decl.getParentsOfType(ASTClassOrInterfaceDeclaration.class).get(0).isInterface()
|
||||
// check if the field/method/nested class has a default access modifier
|
||||
&& decl.isPackagePrivate()
|
||||
// if is a default access modifier check if there is a comment in this line
|
||||
&& !interestingLineNumberComments.contains(decl.getBeginLine());
|
||||
}
|
||||
}
|
@ -76,5 +76,52 @@ A rule for the politically correct... we don't want to offend anyone.
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
<rule name="CommentDefaultAccessModifier"
|
||||
since="5.4.0"
|
||||
class="net.sourceforge.pmd.lang.java.rule.comments.CommentDefaultAccessModifierRule"
|
||||
message="Missing commented default access modifier"
|
||||
externalInfoUrl="${pmd.website.baseurl}/rules/java/comments.html#CommentDefaultAccessModifier">
|
||||
<description>
|
||||
<![CDATA[
|
||||
To avoid mistakes if we want that a Method, Field or Nested class have a default access modifier
|
||||
we must add a comment at the beginning of the Method, Field or Nested class.
|
||||
By default the comment must be /* default */, if you want another, you have to provide a regex.
|
||||
]]>
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<properties>
|
||||
<property name="regex">
|
||||
<value>
|
||||
<![CDATA[
|
||||
\/\*\s+default\s+\*\/
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
</properties>
|
||||
<example>
|
||||
<![CDATA[
|
||||
public class Foo {
|
||||
final String stringValue = "some string";
|
||||
String getString() {
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
class NestedFoo {
|
||||
}
|
||||
}
|
||||
|
||||
// should be
|
||||
public class Foo {
|
||||
/* default */ final String stringValue = "some string";
|
||||
/* default */ String getString() {
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
/* default */ class NestedFoo {
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
@ -14,5 +14,6 @@ public class CommentRulesTest extends SimpleAggregatorTst {
|
||||
addRule(RULESET, "CommentRequired");
|
||||
addRule(RULESET, "CommentSize");
|
||||
addRule(RULESET, "CommentContent");
|
||||
addRule(RULESET, "CommentDefaultAccessModifier");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<test-data>
|
||||
<code-fragment id="some-methods-fields-with-default-access-modifier"><![CDATA[
|
||||
public class Foo {
|
||||
public final String stringValue = "stringValue"; // should not be reported
|
||||
final String otherStringValue = "otherStringValue"; // should be reported
|
||||
/* default */ final String otherValue = "otherValue"; // should not be reported
|
||||
/* default */ final String anotherValue = "anotherValue"; // should not be reported
|
||||
|
||||
public void test() { // should not be reported
|
||||
}
|
||||
|
||||
void test2() { // should be reported
|
||||
}
|
||||
|
||||
/* default */ void test3() { // should not be reported
|
||||
}
|
||||
|
||||
/* default */ void test4() { // should not be reported
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</code-fragment>
|
||||
<test-code>
|
||||
<description>Some methods and Fields with default access modifier in a class</description>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>3,10</expected-linenumbers>
|
||||
<code-ref id="some-methods-fields-with-default-access-modifier"/>
|
||||
</test-code>
|
||||
|
||||
<code-fragment id="all-methods-fields-with-default-access-modifier"><![CDATA[
|
||||
public class Foo {
|
||||
final String stringValue = "stringValue";
|
||||
final String otherStringValue = "otherStringValue";
|
||||
final String otherValue = "otherValue";
|
||||
|
||||
void test() {
|
||||
}
|
||||
|
||||
void test2() {
|
||||
}
|
||||
|
||||
void test3() {
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</code-fragment>
|
||||
<test-code>
|
||||
<description>All methods and Field with default access modifier in a class</description>
|
||||
<expected-problems>6</expected-problems>
|
||||
<expected-linenumbers>2,3,4,6,9,12</expected-linenumbers>
|
||||
<code-ref id="all-methods-fields-with-default-access-modifier"/>
|
||||
</test-code>
|
||||
|
||||
<code-fragment id="all-methods-fields-without-default-access-modifier"><![CDATA[
|
||||
public class Foo {
|
||||
private final String stringValue = "stringValue";
|
||||
private final String otherStringValue = "otherStringValue";
|
||||
private final String otherValue = "otherValue";
|
||||
|
||||
public void test() {
|
||||
}
|
||||
|
||||
public void test2() {
|
||||
}
|
||||
|
||||
public void test3() {
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</code-fragment>
|
||||
<test-code>
|
||||
<description>All methods and Field without default access modifier in a class</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code-ref id="all-methods-fields-without-default-access-modifier"/>
|
||||
</test-code>
|
||||
|
||||
<code-fragment id="interface-with-methods-with-default-access-modifier"><![CDATA[
|
||||
public interface Foo {
|
||||
void test();
|
||||
public void test2();
|
||||
void test3();
|
||||
}
|
||||
]]></code-fragment>
|
||||
<test-code>
|
||||
<description>Methods with default access modifier in an Interface</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code-ref id="interface-with-methods-with-default-access-modifier"/>
|
||||
</test-code>
|
||||
|
||||
<code-fragment id="nested-class-with-default-access-modifier"><![CDATA[
|
||||
public class Foo {
|
||||
private final String stringValue = "stringValue";
|
||||
|
||||
public void test() {
|
||||
}
|
||||
|
||||
class NestedClass {
|
||||
}
|
||||
|
||||
static class OtherNestedClass {
|
||||
}
|
||||
|
||||
public class AnotherNestedClass {
|
||||
}
|
||||
}
|
||||
]]></code-fragment>
|
||||
<test-code>
|
||||
<description>Nested classes with default access modifier</description>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>7,10</expected-linenumbers>
|
||||
<code-ref id="nested-class-with-default-access-modifier"/>
|
||||
</test-code>
|
||||
|
||||
<code-fragment id="own-regex-to-default-access-modifier-rule"><![CDATA[
|
||||
public class Foo {
|
||||
/* default */ final String stringValue = "stringValue";
|
||||
|
||||
void test() {
|
||||
}
|
||||
|
||||
/* package-private */ class NestedClass {
|
||||
}
|
||||
|
||||
/* package-private */ class OtherNestedClass {
|
||||
}
|
||||
|
||||
static class AnotherNestedClass {
|
||||
}
|
||||
}
|
||||
]]></code-fragment>
|
||||
<test-code>
|
||||
<description>Test own regex to default access modifier rule</description>
|
||||
<rule-property name="regex">\/\*\s+package-private\s+\*\/</rule-property>
|
||||
<expected-problems>3</expected-problems>
|
||||
<expected-linenumbers>2,4,13</expected-linenumbers>
|
||||
<code-ref id="own-regex-to-default-access-modifier-rule"/>
|
||||
</test-code>
|
||||
</test-data>
|
@ -29,6 +29,9 @@
|
||||
the minimum required length of a variable name.
|
||||
* Modified Rule: rulesets/java/naming.xml/ShortMethodName: Additional property `minimum` to configure
|
||||
the minimum required length of a method name.
|
||||
* New Rule: rulesets/java/comments.xml/CommentDefaultAccessModifier: In order to avoid mistakes with
|
||||
forgotten access modifiers for methods, this rule ensures, that you explicitly mark the usage of the
|
||||
default access modifier by placing a comment.
|
||||
|
||||
|
||||
**Pull Requests:**
|
||||
@ -37,6 +40,7 @@
|
||||
* [#54](https://github.com/pmd/pmd/pull/54): Add a new rulesets for Maven's POM rules
|
||||
* [#55](https://github.com/pmd/pmd/pull/55): Fix run.sh for paths with spaces
|
||||
* [#56](https://github.com/pmd/pmd/pull/56): Adding support for WSDL rules
|
||||
* [#57](https://github.com/pmd/pmd/pull/57): Add default access modifier as comment rule
|
||||
|
||||
**Bugfixes:**
|
||||
|
||||
|
Reference in New Issue
Block a user