Merge branch 'Monits-addCommentDefaultModifierRule'

This commit is contained in:
Andreas Dangel
2015-07-26 19:25:04 +02:00
6 changed files with 284 additions and 0 deletions

View File

@ -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"/>

View File

@ -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());
}
}

View File

@ -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>

View File

@ -14,5 +14,6 @@ public class CommentRulesTest extends SimpleAggregatorTst {
addRule(RULESET, "CommentRequired");
addRule(RULESET, "CommentSize");
addRule(RULESET, "CommentContent");
addRule(RULESET, "CommentDefaultAccessModifier");
}
}

View File

@ -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>

View File

@ -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:**