Search code examples
javapluginsjavadocpmd

creatRuleViolation how to define it? Save me from this


Help. I would like to sacrifice the reputation for a proper answer..

public class ParameterNameConvention extends AbstractJavaRule {

private final static String PATTERN = "[p][a-zA-Z]+";

    public Object visit(ASTMethodDeclaration node, Object data) {
        RuleContext result = (RuleContext) data;
        String rulePattern = (!getStringProperty("rulePattern")
                .equalsIgnoreCase("")) ? getStringProperty("rulePattern")
                : PATTERN;
        if (node.containsChildOfType(ASTFormalParameter.class)) {
            Iterator iterator = node.findChildrenOfType(
                    ASTFormalParameter.class).iterator();
            while (iterator.hasNext()) {
                ASTFormalParameter element = (ASTFormalParameter) iterator
                        .next();
                Iterator decIdIterator = element.findChildrenOfType(
                        ASTVariableDeclaratorId.class).iterator();
                while (decIdIterator.hasNext()) {
                    ASTVariableDeclaratorId decElement = (ASTVariableDeclaratorId) decIdIterator
                            .next();
                    if (!decElement.getImage().matches(rulePattern)) {

                        result.getReport()
                                .addRuleViolation(
                                        createRuleViolation(
                                                this,
                                                node.getBeginLine(),
                                                "Parameter '"
                                                        + decElement.getImage()
                                                        + "' should match regular expression pattern '"
                                                        + rulePattern + "'",
                                                result));
                    }
                }
            }
        }
        return result;
    }
}

However, 'creatRuleViolation' doesn't work. How to define it?


Solution

  • Here we go, I did a bit of research last night to help you out. createRuleViolation() is defined in AbstractRuleViolationFactory as abstract and implemented in language specific factory sub-classes (eg: JavaRuleViolationFactory), not directly available in Rule classes hierarchy.

    Instead use addViolationWithMessage() method that is inherited from AbstractRule via AbstractJavaRule. This method eventually calls the create method on appropriate factory at runtime.

    I tried your code with latest PMD version 5.0.3, and required few more tweaks other than the issue withcreateRuleViolation() method to get it working. Mainly to navigate from MethodDeclaration node to Parameter nodes, there could be a better way though, but it works now. I have modified the code based on the AST (abstract source tree).

    package madhav.pmd.rule;
    
    import net.sourceforge.pmd.RuleContext;
    import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
    import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;
    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.rule.AbstractJavaRule;
    
    public class ParameterNameConvention extends AbstractJavaRule
    {
        private final static String PATTERN = "[p][a-zA-Z]+";
    
        @Override
        public Object visit(final ASTMethodDeclaration node, final Object pData)
        {
            final RuleContext result = (RuleContext) pData;
            // TODO : get property
            final String rulePattern = PATTERN;
            final ASTMethodDeclarator methodDecNode = node.getFirstChildOfType(ASTMethodDeclarator.class);
            final ASTFormalParameters paramsNode = methodDecNode.getFirstChildOfType(ASTFormalParameters.class);
            if (paramsNode.getParameterCount() > 0)
            {
                for (final ASTFormalParameter element : paramsNode.findChildrenOfType(ASTFormalParameter.class))
                {
                    for (final ASTVariableDeclaratorId decElement : element.findChildrenOfType(ASTVariableDeclaratorId.class))
                    {
                        if (!decElement.getImage().matches(rulePattern))
                        {
                            addViolationWithMessage(result, node,
                                    "Parameter '"
                                            + decElement.getImage()
                                            + "' should match regular expression pattern '"
                                            + rulePattern + "'",
                                    node.getBeginLine(),
                                    node.getEndLine());
                        }
                    }
                }
            }
            return result;
        }
    }
    

    To test the rule on the same class, I named one parameter to satisfy the rule and one not to satisfy (final ASTMethodDeclaration node, final Object pData).

    The ruleset xml is

    <?xml version="1.0"?>
    <ruleset name="My rules">
      <description>My test rules</description>
      <rule name="ParameterNameConvention"
            message="Parameter must start with p"
            class="madhav.pmd.rule.ParameterNameConvention">
        <description>Don't use non-complaint parameters </description>
    
        <example>
            <![CDATA[
             void methodX(int value)
            ]]>
        </example>
      </rule>
    </ruleset>
    

    The result xml PMD generated is :

    <?xml version="1.0" encoding="UTF-8"?>
    <pmd version="5.0.3" timestamp="2013-06-13T16:03:52.404">
        <file name="D:\Projects\ZRules\src\madhav\pmd\rule\ParameterNameConvention.java">
            <violation beginline="16" endline="43" begincolumn="16" endcolumn="9" 
                rule="ParameterNameConvention" ruleset="My rules" package="madhav.pmd.rule" 
                class="ParameterNameConvention" priority="5">
                    Parameter node should match regular expression pattern [p][a-zA-Z]+
            </violation>
        </file>
    </pmd>
    

    For more details on running PMD standalone from command line see the documentation on PMD website or there is loads available if you google around.

    Hope this is helpful.