Skip to content

Commit

Permalink
Merge branch 'addCommentDefaultModifierRule' of https://github.com/Mo…
Browse files Browse the repository at this point in the history
…nits/pmd into Monits-addCommentDefaultModifierRule
  • Loading branch information
adangel committed Jul 26, 2015
2 parents 6b9d0fb + 89e7d04 commit 3b60cac
Show file tree
Hide file tree
Showing 4 changed files with 275 additions and 0 deletions.
@@ -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());
}
}
47 changes: 47 additions & 0 deletions pmd-java/src/main/resources/rulesets/java/comments.xml
Expand Up @@ -76,5 +76,52 @@ A rule for the politically correct... we don't want to offend anyone.
</example>
</rule>

<rule name="CommentDefaultAccessModifier"
since="5.3.2"
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>
Expand Up @@ -14,5 +14,6 @@ public void setUp() {
addRule(RULESET, "CommentRequired");
addRule(RULESET, "CommentSize");
addRule(RULESET, "CommentContent");
addRule(RULESET, "CommentDefaultAccessModifier");
}
}
@@ -0,0 +1,135 @@
<?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>
<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>
<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>
<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>
<code-ref id="own-regex-to-default-access-modifier-rule"/>
</test-code>
</test-data>

0 comments on commit 3b60cac

Please sign in to comment.