소스 검색

Mamy własną regułę PMD :)

Ranides Atterwim 10 년 전
부모
커밋
e482951530

+ 40 - 40
assira.rules/src/main/java/net/ranides/assira/rules/TestECB.java

@@ -1,40 +1,40 @@
-/*
- *  @author Ranides Atterwim <ranides@gmail.com>
- *  @copyright Ranides Atterwim
- *  @license WTFPL
- *  @url http://ranides.net/projects/assira.rules
- */
-package net.ranides.assira.rules;
-
-import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
-import net.sourceforge.pmd.lang.java.ast.JavaNode;
-import net.sourceforge.pmd.lang.java.rule.AbstractStatisticalJavaRule;
-import net.sourceforge.pmd.lang.rule.properties.DoubleProperty;
-import net.sourceforge.pmd.stat.DataPoint;
-
-public class TestECB extends AbstractStatisticalJavaRule {
-    
-     DoubleProperty MINIMUM_DESCRIPTOR = new DoubleProperty("minimum", "Minimum reporting threshold", 0d, 100d, null, 2.0f);
-
-    private final Class<?> nodeClass;
-
-    public TestECB() {
-        super();
-        this.nodeClass = ASTClassOrInterfaceDeclaration.class;
-        setProperty(MINIMUM_DESCRIPTOR, 20d);
-    }
-
-    @Override
-    public Object visit(final JavaNode node, final Object data) {
-        if (nodeClass.isInstance(node)) {
-            final DataPoint point = new DataPoint();
-            point.setNode(node);
-            point.setScore(1.0 * (node.getEndLine() - node.getBeginLine()));
-            point.setMessage(getMessage()+ " (V4)");
-            addDataPoint(point);
-        }
-
-        return node.childrenAccept(this, data);
-    }
-
-}
+/*
+ *  @author Ranides Atterwim <ranides@gmail.com>
+ *  @copyright Ranides Atterwim
+ *  @license WTFPL
+ *  @url http://ranides.net/projects/assira.rules
+ */
+package net.ranides.assira.rules;
+
+import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
+import net.sourceforge.pmd.lang.java.ast.JavaNode;
+import net.sourceforge.pmd.lang.java.rule.AbstractStatisticalJavaRule;
+import net.sourceforge.pmd.lang.rule.properties.DoubleProperty;
+import net.sourceforge.pmd.stat.DataPoint;
+
+public class TestECB extends AbstractStatisticalJavaRule {
+    
+     DoubleProperty MINIMUM_DESCRIPTOR = new DoubleProperty("minimum", "Minimum reporting threshold", 0d, 100d, null, 2.0f);
+
+    private final Class<?> nodeClass;
+
+    public TestECB() {
+        super();
+        this.nodeClass = ASTClassOrInterfaceDeclaration.class;
+        setProperty(MINIMUM_DESCRIPTOR, 20d);
+    }
+
+    @Override
+    public Object visit(final JavaNode node, final Object data) {
+        if (nodeClass.isInstance(node)) {
+            final DataPoint point = new DataPoint();
+            point.setNode(node);
+            point.setScore(1.0 * (node.getEndLine() - node.getBeginLine()));
+            point.setMessage(getMessage()+ " (V5)");
+            addDataPoint(point);
+        }
+
+        return node.childrenAccept(this, data);
+    }
+
+}

+ 116 - 0
assira.rules/src/main/java/net/ranides/assira/rules/UnusedParameterRule.java

@@ -0,0 +1,116 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+package net.ranides.assira.rules;
+
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.util.List;
+import java.util.Map;
+
+import net.sourceforge.pmd.lang.ast.Node;
+import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
+import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;
+import net.sourceforge.pmd.lang.java.ast.ASTName;
+import net.sourceforge.pmd.lang.java.ast.ASTNameList;
+import net.sourceforge.pmd.lang.java.ast.ASTType;
+import net.sourceforge.pmd.lang.java.ast.JavaNode;
+import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
+import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence;
+import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
+import net.sourceforge.pmd.lang.rule.properties.BooleanProperty;
+import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
+
+public class UnusedParameterRule extends AbstractJavaRule {
+
+    private static final BooleanProperty CHECKALL_DESCRIPTOR = new BooleanProperty("checkAll",
+            "Check all methods, including non-private ones", false, 1.0f);
+
+    public UnusedParameterRule() {
+        definePropertyDescriptor(CHECKALL_DESCRIPTOR);
+    }
+
+    public Object visit(ASTConstructorDeclaration node, Object data) {
+        check(node, data);
+        return data;
+    }
+
+    public Object visit(ASTMethodDeclaration node, Object data) {
+        if (!node.isPrivate() && !getProperty(CHECKALL_DESCRIPTOR)) {
+            return data;
+        }
+        if (!node.isNative() && !node.isAbstract() && !isSerializationMethod(node)) {
+            check(node, data);
+        }
+        return data;
+    }
+
+    private boolean isSerializationMethod(ASTMethodDeclaration node) {
+        ASTMethodDeclarator declarator = node.getFirstDescendantOfType(ASTMethodDeclarator.class);
+        List<ASTFormalParameter> parameters = declarator.findDescendantsOfType(ASTFormalParameter.class);
+        if (node.isPrivate()
+            && "readObject".equals(node.getMethodName())
+            && parameters.size() == 1
+            && throwsOneException(node, InvalidObjectException.class)) {
+            ASTType type = parameters.get(0).getTypeNode();
+            if (type.getType() == ObjectInputStream.class
+                    || ObjectInputStream.class.getSimpleName().equals(type.getTypeImage())
+                    || ObjectInputStream.class.getName().equals(type.getTypeImage())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean throwsOneException(ASTMethodDeclaration node, Class<? extends Throwable> exception) {
+        ASTNameList throwsList = node.getThrows();
+        if (throwsList != null && throwsList.jjtGetNumChildren() == 1) {
+            ASTName n = (ASTName)throwsList.jjtGetChild(0);
+            if (n.getType() == exception
+                || exception.getSimpleName().equals(n.getImage())
+                || exception.getName().equals(n.getImage())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void check(Node node, Object data) {
+        Node parent = node.jjtGetParent().jjtGetParent().jjtGetParent();
+        if (parent instanceof ASTClassOrInterfaceDeclaration
+                && !((ASTClassOrInterfaceDeclaration) parent).isInterface()) {
+            Map<VariableNameDeclaration, List<NameOccurrence>> vars = ((JavaNode) node).getScope().getDeclarations(
+                    VariableNameDeclaration.class);
+            for (Map.Entry<VariableNameDeclaration, List<NameOccurrence>> entry : vars.entrySet()) {
+                VariableNameDeclaration nameDecl = entry.getKey();
+                if (actuallyUsed(nameDecl, entry.getValue())) {
+                    continue;
+                }
+                if( nameDecl.getImage().startsWith("$")) {
+                    continue;
+                }
+                addViolation(data, nameDecl.getNode(), new Object[] {
+                        node instanceof ASTMethodDeclaration ? "method" : "constructor", nameDecl.getImage() });
+            }
+        }
+    }
+
+    private boolean actuallyUsed(VariableNameDeclaration nameDecl, List<NameOccurrence> usages) {
+        for (NameOccurrence occ : usages) {
+            JavaNameOccurrence jocc = (JavaNameOccurrence) occ;
+            if (jocc.isOnLeftHandSide()) {
+                if (nameDecl.isArray() && jocc.getLocation().jjtGetParent().jjtGetParent().jjtGetNumChildren() > 1) {
+                    // array element access
+                    return true;
+                }
+                continue;
+            } else {
+                return true;
+            }
+        }
+        return false;
+    }
+}

+ 376 - 354
assira.rules/src/main/resources/rulesets/java/assira.custom.xml

@@ -1,355 +1,377 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<ruleset name="net.ranides.assira.custom"
-    xmlns="http://pmd.sf.net/ruleset/1.0.0"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
-    xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
-
-    <description>
-    Assira Quality Policy - custom rules
-    </description>
-
-    <rule
-        name="TooManyDifferentMethods"
-        since="4.3"
-        class="net.sourceforge.pmd.lang.rule.XPathRule"
-        message="This class has too many different methods, consider refactoring it."
-        externalInfoUrl="http://pmd.sourceforge.net/rules/codesize.html#TooManyMethods"
-        language="java"
-        >
-        <description><![CDATA[Counts unique methods (all overloaded versions are considered as the same). Ignores UtilityClassess.]]></description>
-        <priority>3</priority>
-        <properties>
-            <property name="maxmethods" type="Integer" description="The method count reporting threshold " min="1" max="1000" value="15"/>
-            <property name="xpath"><value>
-            <![CDATA[
-            //ClassOrInterfaceDeclaration[
-            
-                count(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration[
-                    MethodDeclaration
-                    and not(Annotation/MarkerAnnotation/Name[@Image='Override'])
-                    and not(starts-with(MethodDeclaration/@MethodName,'get'))
-                    and not(starts-with(MethodDeclaration/@MethodName,'set'))
-                    and not(
-                        MethodDeclaration/@MethodName
-                        =
-                        preceding-sibling::ClassOrInterfaceBodyDeclaration/MethodDeclaration/@MethodName
-                        )
-                ]) > $maxmethods
-            
-                and not (
-                    @Final='true'
-                    and
-                    ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[@Private='true'][@ParameterCount='0']
-                    and
-                    count(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration)=1
-                )
-            ]
-            ]]>
-            </value></property>
-        </properties>
-    </rule>
-    
-    
-    <rule
-        name="TooManyPublicMethods"
-        since="4.3"
-        class="net.sourceforge.pmd.lang.rule.XPathRule"
-        message="This class has too many public methods, consider refactoring it."
-        externalInfoUrl="http://pmd.sourceforge.net/rules/codesize.html#TooManyMethods"
-        language="java"
-        >
-        <description><![CDATA[Counts public methods]]></description>
-        <priority>3</priority>
-        <properties>
-            <property name="maxmethods" type="Integer" description="The method count reporting threshold " min="1" max="1000" value="40"/>
-            <property name="xpath"><value>
-            <![CDATA[
-            //ClassOrInterfaceDeclaration[
-                count(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration[
-                    @Public='true'
-                    and not(starts-with(@MethodName,'get'))
-                    and not(starts-with(@MethodName,'set'))
-                    and not(../Annotation/MarkerAnnotation/Name[@Image='Override'])
-                ]) > $maxmethods
-            ]
-            ]]>
-            </value></property>
-        </properties>
-    </rule>
-    
-<!--
-    <rule
-        name="ShortVar" 
-        since="2.0" 
-        class="net.sourceforge.pmd.lang.rule.XPathRule"
-        message="Avoid variables with short names like {0}"
-        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#ShortVariable"
-        language="java"
-        >
-        <description>
-            <![CDATA[Detects when a field, local, or parameter has a very short name.Ignores primitive types, local Iterators and for-variables.]]>
-        </description>
-        <priority>3</priority>
-        <properties><property name="xpath" pluginname="true"><value>
-            <![CDATA[
-            //VariableDeclaratorId [
-               string-length(@Image) < 3
-               and not(@Image='_')
-               and not(@Image='id')
-               and not(ancestor::ForInit)
-               and not(../Type/PrimitiveType)
-               and not(../../Type/PrimitiveType)
-               and not(
-                  (../../Type/ReferenceType/ClassOrInterfaceType[@Image='Iterator'])
-                  or
-                  (../../../FormalParameter)
-               )
-               and not(/TypeDeclaration/ClassOrInterfaceDeclaration[ends-with(@Image,'Test')])
-               and not((ancestor::FormalParameter) and (ancestor::TryStatement))
-               and not((@Image='em') and (../../Type/@TypeImage='EntityManager'))
-               and not((@Image='em') and (../Type/@TypeImage='EntityManager'))
-            ]
-            ]]>
-        </value></property></properties>
-    </rule>
--->    
-    <rule
-        name="LongVar"
-      	since="0.3"
-        message="Avoid excessively long variable names like {0}"
-        class="net.sourceforge.pmd.lang.rule.XPathRule"
-        externalInfoUrl="http://pmd.sourceforge.net/rules/naming.html#LongVariable"
-        language="java"
-        >
-        <description>Detects when a field, formal or local variable is declared with a long name.</description>
-        <priority>3</priority>
-        <properties>
-            <property name="minimum" type="Integer" description="The variable length reporting threshold" min="1" max="1000" value="16"/>
-            <property name="xpath" pluginname="true"><value>
-            <![CDATA[
-                //VariableDeclaratorId[
-                    string-length(@Image) > $minimum
-                    and (@Static='false' or @Final='false')
-                ]
-            ]]>
-            </value></property>
-        </properties>
-    </rule>
-
-
-    <rule name="VarNameRules" since="2.0" class="net.sourceforge.pmd.lang.rule.XPathRule"
-        message="Field name doesn't respect required pattern"
-        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#VariableNamingRegexp"
-        language="java"
-    >
-        <description>Checks all field names against regular expression</description>
-        <priority>3</priority>
-        <properties><property name="xpath" pluginname="true"><value>
-            <![CDATA[
-            //FieldDeclaration[
-                not(matches(@VariableName,'^(m_|\$)?([a-z][a-zA-Z0-9]*)$'))
-                and( (@Static='false') or (@Final='false') )
-            ]
-            ]]>
-        </value></property></properties>
-    </rule>
-
-    <rule name="MethodNameRules" since="2.0" class="net.sourceforge.pmd.lang.rule.XPathRule"
-        message="Method name doesn't respect required pattern"
-        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#VariableNamingRegexp"
-        language="java"
-    >
-        <description>Checks all methods names against regular expression</description>
-        <priority>3</priority>
-        <properties><property name="xpath" pluginname="true"><value>
-            <![CDATA[
-            //ClassOrInterfaceBodyDeclaration
-                [not(Annotation/MarkerAnnotation/Name[@Image='Test'])]
-                [not(Annotation/MarkerAnnotation/Name[@Image='InterfaceTest'])]
-            /MethodDeclaration/MethodDeclarator
-                [not(matches(@Image,'^(m_|\$)?([a-z][a-zA-Z0-9]*)$'))]
-            ]]>
-        </value></property></properties>
-    </rule>
-
-    <rule
-        name="InvalidUtilityClass"
-    	since="3.0"
-        message="Utility class does not provide any static methods, fields or interfaces"
-        class="net.sourceforge.pmd.lang.rule.XPathRule"
-        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#InvalidUtilityClass"
-        language="java"
-        >
-        <description>A class that has private constructors and does not have any static methods, fields or type declarations cannot be used.</description>
-        <priority>3</priority>
-        <properties><property name="xpath"><value>
-            <![CDATA[
-            //ClassOrInterfaceDeclaration[@Nested='false'][
-                (
-                    count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration)>0
-                    and 
-                    count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration) = count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[@Private='true']) 
-                )
-                and count(.//MethodDeclaration[@Static='true'])=0
-                and count(.//FieldDeclaration[@Private='false'][@Static='true'])=0
-                and count(.//ClassOrInterfaceDeclaration[@Interface='true'])=0
-                and count(.//AnnotationTypeDeclaration)=0
-                and count(.//ClassOrInterfaceDeclaration[@Static='true' and @Private='false'])=0
-            ]
-            ]]>
-        </value></property></properties>
-    </rule>
-    
-    <rule
-        name="TooManyParams"
-    	since="3.0"
-        message="Avoid really long parameter lists."
-        class="net.sourceforge.pmd.lang.rule.XPathRule"
-        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#TooManyParams"
-        language="java"
-        >
-        <description>Long parameter lists can indicate that a new object should be created to wrap the numerous parameters.  Basically, try to group the parameters together.</description>
-        <priority>3</priority>
-        <properties>
-            <property name="maximum" type="Integer" description="The parameter count reporting threshold" min="1" max="1000" value="6"/>
-            <property name="xpath"><value>
-            <![CDATA[
-            //ClassOrInterfaceBodyDeclaration
-                [ MethodDeclaration/MethodDeclarator/FormalParameters[@ParameterCount>$maximum] ]
-                [ not(Annotation/MarkerAnnotation/Name[@Image='Override']) ]
-            ]]>
-            </value></property>
-        </properties>
-    </rule>
-    
-    <rule
-        name="AvoidThreadGroup"
-        since="3.6"
-        message="Avoid using java.lang.ThreadGroup; it is not thread safe"
-        class="net.sourceforge.pmd.lang.rule.XPathRule"
-        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#AvoidThreadGroup"
-        language="java"
-        typeResolution="true"
-        >
-        <description>Avoid using java.lang.ThreadGroup; although it is intended to be used in a threaded environment it contains methods that are not thread safe.</description>
-        <priority>3</priority>
-        <properties>
-            <property name="xpath"><value>
-            <![CDATA[
-            //AllocationExpression/ClassOrInterfaceType
-                [ typeof(@Image, 'java.lang.ThreadGroup') and contains(@Image, 'ThreadGroup') ]
-            |
-            //PrimarySuffix[contains(@Image, 'getThreadGroup')]
-            ]]>
-            </value></property>
-        </properties>
-    </rule>
-    
-    <rule
-        name="UseSingleton"
-    	since="3.0"
-        message="All methods are static.  Consider using Singleton instead.  Alternatively, you could add a private constructor or make the class abstract to silence this warning."
-        class="net.sourceforge.pmd.lang.rule.XPathRule"
-        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#UseSingleton"
-        language="java"
-        >
-        <description><![CDATA[If you have a class that has nothing but static methods, consider making it a Singleton. If you want this class to be a Singleton, remember to add a private constructor to prevent instantiation.]]></description>
-        <priority>3</priority>
-        <properties>
-            <property name="xpath"><value>
-            <![CDATA[
-            //ClassOrInterfaceDeclaration[
-                @Interface='false' and @Abstract='false'
-                and not(ExtendsList)
-                and not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration[
-                    @Private!='true' and @Static='false'
-                ]) 
-                and not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration[
-                    @Private!='true' and @Static='false'
-                ])
-                and not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration[
-                    @MethodName='main' and
-                    @Static='true' and
-                    @Public='true' and
-                    @Void='true' and
-                    MethodDeclarator/FormalParameters[@ParameterCount=1] and
-                    MethodDeclarator/FormalParameters/FormalParameter/Type[@Array='true' and @TypeImage='String']
-                ])
-                and (
-                    @Final='false' or
-                    count(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration)!=1
-                    or not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[
-                        @Private='true'
-                        and FormalParameters[@ParameterCount=0]
-                    ])
-                )
-            ]
-            ]]>
-            </value></property>
-        </properties>
-    </rule>
-    
-    
-    <rule
-        name="TooManyFields"
-        since="4.3"
-        message="Too many fields"
-        class="net.sourceforge.pmd.lang.rule.XPathRule"
-        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#TooManyFields"
-        typeResolution="true"
-        language="java"
-        >
-        <description><![CDATA[Classes that have too many fields could be redesigned to have fewer fields, possibly through some nested object grouping of some of the information.  For example, a class with city/state/zip fields could instead have one Address field.]]></description>
-        <priority>3</priority>
-        <properties>
-            <property name="maxfields" type="Integer" description="The field count reporting threshold " min="1" max="1000" value="15"/>
-            <property name="xpath"><value>
-            <![CDATA[
-            //ClassOrInterfaceDeclaration[
-                count(
-                    ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration
-                    [@Final='false']
-                    [@Static='false']
-                ) > $maxfields
-            ]
-            ]]>
-            </value></property>
-        </properties>
-    </rule>
-    
-    <!--
-    <rule
-        name="LexicableConstructor"
-        since="4.3"
-        message="Lexicable class must be constructable from LexicalContext"
-        class="net.sourceforge.pmd.lang.rule.XPathRule"
-        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#TooManyFields"
-        typeResolution="true"
-        >
-        <description><![CDATA[Classes that implement Lexicable interface must declare apriotiate ocnstructor with signature: Construct(LexicalContext context). It can be public but this is not obligatory.]]></description>
-        <priority>3</priority>
-        <properties>
-            <property name="xpath"><value>
-            <![CDATA[
-            //ClassOrInterfaceDeclaration[
-                ImplementsList/ClassOrInterfaceType[
-                    @Image='Lexicable' or @Image='net.ranides.assira.text.Lexicable'
-                ]
-                and
-                not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[
-                    FormalParameters[
-                        @ParameterCount='1' 
-                        and 
-                        FormalParameter/Type[@Array='false'][@TypeImage='LexicalContext' or @TypeImage='net.ranides.assira.text.LexicalContext']
-                    ]
-                ])
-            ]
-            ]]>
-            </value></property>
-        </properties>
-    </rule>
-    -->
-
+<?xml version="1.0" encoding="utf-8"?>
+
+<ruleset name="net.ranides.assira.custom"
+    xmlns="http://pmd.sf.net/ruleset/1.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
+    xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
+
+    <description>
+    Assira Quality Policy - custom rules
+    </description>
+
+    <rule
+        name="TooManyDifferentMethods"
+        since="4.3"
+        class="net.sourceforge.pmd.lang.rule.XPathRule"
+        message="This class has too many different methods, consider refactoring it."
+        externalInfoUrl="http://pmd.sourceforge.net/rules/codesize.html#TooManyMethods"
+        language="java"
+        >
+        <description><![CDATA[Counts unique methods (all overloaded versions are considered as the same). Ignores UtilityClassess.]]></description>
+        <priority>3</priority>
+        <properties>
+            <property name="maxmethods" type="Integer" description="The method count reporting threshold " min="1" max="1000" value="15"/>
+            <property name="xpath"><value>
+            <![CDATA[
+            //ClassOrInterfaceDeclaration[
+            
+                count(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration[
+                    MethodDeclaration
+                    and not(Annotation/MarkerAnnotation/Name[@Image='Override'])
+                    and not(starts-with(MethodDeclaration/@MethodName,'get'))
+                    and not(starts-with(MethodDeclaration/@MethodName,'set'))
+                    and not(
+                        MethodDeclaration/@MethodName
+                        =
+                        preceding-sibling::ClassOrInterfaceBodyDeclaration/MethodDeclaration/@MethodName
+                        )
+                ]) > $maxmethods
+            
+                and not (
+                    @Final='true'
+                    and
+                    ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[@Private='true'][@ParameterCount='0']
+                    and
+                    count(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration)=1
+                )
+            ]
+            ]]>
+            </value></property>
+        </properties>
+    </rule>
+    
+    
+    <rule
+        name="TooManyPublicMethods"
+        since="4.3"
+        class="net.sourceforge.pmd.lang.rule.XPathRule"
+        message="This class has too many public methods, consider refactoring it."
+        externalInfoUrl="http://pmd.sourceforge.net/rules/codesize.html#TooManyMethods"
+        language="java"
+        >
+        <description><![CDATA[Counts public methods]]></description>
+        <priority>3</priority>
+        <properties>
+            <property name="maxmethods" type="Integer" description="The method count reporting threshold " min="1" max="1000" value="40"/>
+            <property name="xpath"><value>
+            <![CDATA[
+            //ClassOrInterfaceDeclaration[
+                count(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration[
+                    @Public='true'
+                    and not(starts-with(@MethodName,'get'))
+                    and not(starts-with(@MethodName,'set'))
+                    and not(../Annotation/MarkerAnnotation/Name[@Image='Override'])
+                ]) > $maxmethods
+            ]
+            ]]>
+            </value></property>
+        </properties>
+    </rule>
+    
+<!--
+    <rule
+        name="ShortVar" 
+        since="2.0" 
+        class="net.sourceforge.pmd.lang.rule.XPathRule"
+        message="Avoid variables with short names like {0}"
+        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#ShortVariable"
+        language="java"
+        >
+        <description>
+            <![CDATA[Detects when a field, local, or parameter has a very short name.Ignores primitive types, local Iterators and for-variables.]]>
+        </description>
+        <priority>3</priority>
+        <properties><property name="xpath" pluginname="true"><value>
+            <![CDATA[
+            //VariableDeclaratorId [
+               string-length(@Image) < 3
+               and not(@Image='_')
+               and not(@Image='id')
+               and not(ancestor::ForInit)
+               and not(../Type/PrimitiveType)
+               and not(../../Type/PrimitiveType)
+               and not(
+                  (../../Type/ReferenceType/ClassOrInterfaceType[@Image='Iterator'])
+                  or
+                  (../../../FormalParameter)
+               )
+               and not(/TypeDeclaration/ClassOrInterfaceDeclaration[ends-with(@Image,'Test')])
+               and not((ancestor::FormalParameter) and (ancestor::TryStatement))
+               and not((@Image='em') and (../../Type/@TypeImage='EntityManager'))
+               and not((@Image='em') and (../Type/@TypeImage='EntityManager'))
+            ]
+            ]]>
+        </value></property></properties>
+    </rule>
+-->    
+    <rule
+        name="LongVar"
+      	since="0.3"
+        message="Avoid excessively long variable names like {0}"
+        class="net.sourceforge.pmd.lang.rule.XPathRule"
+        externalInfoUrl="http://pmd.sourceforge.net/rules/naming.html#LongVariable"
+        language="java"
+        >
+        <description>Detects when a field, formal or local variable is declared with a long name.</description>
+        <priority>3</priority>
+        <properties>
+            <property name="minimum" type="Integer" description="The variable length reporting threshold" min="1" max="1000" value="16"/>
+            <property name="xpath" pluginname="true"><value>
+            <![CDATA[
+                //VariableDeclaratorId[
+                    string-length(@Image) > $minimum
+                    and (@Static='false' or @Final='false')
+                ]
+            ]]>
+            </value></property>
+        </properties>
+    </rule>
+
+
+    <rule name="VarNameRules" since="2.0" class="net.sourceforge.pmd.lang.rule.XPathRule"
+        message="Field name doesn't respect required pattern"
+        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#VariableNamingRegexp"
+        language="java"
+    >
+        <description>Checks all field names against regular expression</description>
+        <priority>3</priority>
+        <properties><property name="xpath" pluginname="true"><value>
+            <![CDATA[
+            //FieldDeclaration[
+                not(matches(@VariableName,'^(m_|\$)?([a-z][a-zA-Z0-9]*)$'))
+                and( (@Static='false') or (@Final='false') )
+            ]
+            ]]>
+        </value></property></properties>
+    </rule>
+
+    <rule name="MethodNameRules" since="2.0" class="net.sourceforge.pmd.lang.rule.XPathRule"
+        message="Method name doesn't respect required pattern"
+        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#VariableNamingRegexp"
+        language="java"
+    >
+        <description>Checks all methods names against regular expression</description>
+        <priority>3</priority>
+        <properties><property name="xpath" pluginname="true"><value>
+            <![CDATA[
+            //ClassOrInterfaceBodyDeclaration
+                [not(Annotation/MarkerAnnotation/Name[@Image='Test'])]
+                [not(Annotation/MarkerAnnotation/Name[@Image='InterfaceTest'])]
+            /MethodDeclaration/MethodDeclarator
+                [not(matches(@Image,'^(m_|\$)?([a-z][a-zA-Z0-9]*)$'))]
+            ]]>
+        </value></property></properties>
+    </rule>
+
+    <rule
+        name="InvalidUtilityClass"
+    	since="3.0"
+        message="Utility class does not provide any static methods, fields or interfaces"
+        class="net.sourceforge.pmd.lang.rule.XPathRule"
+        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#InvalidUtilityClass"
+        language="java"
+        >
+        <description>A class that has private constructors and does not have any static methods, fields or type declarations cannot be used.</description>
+        <priority>3</priority>
+        <properties><property name="xpath"><value>
+            <![CDATA[
+            //ClassOrInterfaceDeclaration[@Nested='false'][
+                (
+                    count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration)>0
+                    and 
+                    count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration) = count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[@Private='true']) 
+                )
+                and count(.//MethodDeclaration[@Static='true'])=0
+                and count(.//FieldDeclaration[@Private='false'][@Static='true'])=0
+                and count(.//ClassOrInterfaceDeclaration[@Interface='true'])=0
+                and count(.//AnnotationTypeDeclaration)=0
+                and count(.//ClassOrInterfaceDeclaration[@Static='true' and @Private='false'])=0
+            ]
+            ]]>
+        </value></property></properties>
+    </rule>
+    
+    <rule
+        name="TooManyParams"
+    	since="3.0"
+        message="Avoid really long parameter lists."
+        class="net.sourceforge.pmd.lang.rule.XPathRule"
+        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#TooManyParams"
+        language="java"
+        >
+        <description>Long parameter lists can indicate that a new object should be created to wrap the numerous parameters.  Basically, try to group the parameters together.</description>
+        <priority>3</priority>
+        <properties>
+            <property name="maximum" type="Integer" description="The parameter count reporting threshold" min="1" max="1000" value="6"/>
+            <property name="xpath"><value>
+            <![CDATA[
+            //ClassOrInterfaceBodyDeclaration
+                [ MethodDeclaration/MethodDeclarator/FormalParameters[@ParameterCount>$maximum] ]
+                [ not(Annotation/MarkerAnnotation/Name[@Image='Override']) ]
+            ]]>
+            </value></property>
+        </properties>
+    </rule>
+    
+    <rule
+        name="AvoidThreadGroup"
+        since="3.6"
+        message="Avoid using java.lang.ThreadGroup; it is not thread safe"
+        class="net.sourceforge.pmd.lang.rule.XPathRule"
+        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#AvoidThreadGroup"
+        language="java"
+        typeResolution="true"
+        >
+        <description>Avoid using java.lang.ThreadGroup; although it is intended to be used in a threaded environment it contains methods that are not thread safe.</description>
+        <priority>3</priority>
+        <properties>
+            <property name="xpath"><value>
+            <![CDATA[
+            //AllocationExpression/ClassOrInterfaceType
+                [ typeof(@Image, 'java.lang.ThreadGroup') and contains(@Image, 'ThreadGroup') ]
+            |
+            //PrimarySuffix[contains(@Image, 'getThreadGroup')]
+            ]]>
+            </value></property>
+        </properties>
+    </rule>
+    
+    <rule
+        name="UseSingleton"
+    	since="3.0"
+        message="All methods are static.  Consider using Singleton instead.  Alternatively, you could add a private constructor or make the class abstract to silence this warning."
+        class="net.sourceforge.pmd.lang.rule.XPathRule"
+        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#UseSingleton"
+        language="java"
+        >
+        <description><![CDATA[If you have a class that has nothing but static methods, consider making it a Singleton. If you want this class to be a Singleton, remember to add a private constructor to prevent instantiation.]]></description>
+        <priority>3</priority>
+        <properties>
+            <property name="xpath"><value>
+            <![CDATA[
+            //ClassOrInterfaceDeclaration[
+                @Interface='false' and @Abstract='false'
+                and not(ExtendsList)
+                and not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration[
+                    @Private!='true' and @Static='false'
+                ]) 
+                and not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration[
+                    @Private!='true' and @Static='false'
+                ])
+                and not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration[
+                    @MethodName='main' and
+                    @Static='true' and
+                    @Public='true' and
+                    @Void='true' and
+                    MethodDeclarator/FormalParameters[@ParameterCount=1] and
+                    MethodDeclarator/FormalParameters/FormalParameter/Type[@Array='true' and @TypeImage='String']
+                ])
+                and (
+                    @Final='false' or
+                    count(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration)!=1
+                    or not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[
+                        @Private='true'
+                        and FormalParameters[@ParameterCount=0]
+                    ])
+                )
+            ]
+            ]]>
+            </value></property>
+        </properties>
+    </rule>
+    
+    
+    <rule
+        name="TooManyFields"
+        since="4.3"
+        message="Too many fields"
+        class="net.sourceforge.pmd.lang.rule.XPathRule"
+        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#TooManyFields"
+        typeResolution="true"
+        language="java"
+        >
+        <description><![CDATA[Classes that have too many fields could be redesigned to have fewer fields, possibly through some nested object grouping of some of the information.  For example, a class with city/state/zip fields could instead have one Address field.]]></description>
+        <priority>3</priority>
+        <properties>
+            <property name="maxfields" type="Integer" description="The field count reporting threshold " min="1" max="1000" value="15"/>
+            <property name="xpath"><value>
+            <![CDATA[
+            //ClassOrInterfaceDeclaration[
+                count(
+                    ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration
+                    [@Final='false']
+                    [@Static='false']
+                ) > $maxfields
+            ]
+            ]]>
+            </value></property>
+        </properties>
+    </rule>
+
+    <!--  Ignores parameters prefixed with $ :) -->    
+    <rule name="UnusedParameter"
+              language="java"
+              since="5.3"
+              message="Avoid unused {0} parameters such as ''{1}''."
+              class="net.ranides.assira.rules.UnusedParameterRule"
+              externalInfoUrl="${pmd.website.baseurl}/rules/java/unusedcode.html#UnusedFormalParameter">
+        <description>
+            Avoid passing parameters to methods or constructors without actually referencing them in the method body.
+        </description>
+        <priority>3</priority>
+        <example>
+<![CDATA[
+public class Foo {
+	private void bar(String howdy) {
+	// howdy is not used
+	}
+}
+]]>
+        </example>
+    </rule>
+    
+    <!--
+    <rule
+        name="LexicableConstructor"
+        since="4.3"
+        message="Lexicable class must be constructable from LexicalContext"
+        class="net.sourceforge.pmd.lang.rule.XPathRule"
+        externalInfoUrl="http://java.ranides.net/docs/pmd.htm#TooManyFields"
+        typeResolution="true"
+        >
+        <description><![CDATA[Classes that implement Lexicable interface must declare apriotiate ocnstructor with signature: Construct(LexicalContext context). It can be public but this is not obligatory.]]></description>
+        <priority>3</priority>
+        <properties>
+            <property name="xpath"><value>
+            <![CDATA[
+            //ClassOrInterfaceDeclaration[
+                ImplementsList/ClassOrInterfaceType[
+                    @Image='Lexicable' or @Image='net.ranides.assira.text.Lexicable'
+                ]
+                and
+                not(ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[
+                    FormalParameters[
+                        @ParameterCount='1' 
+                        and 
+                        FormalParameter/Type[@Array='false'][@TypeImage='LexicalContext' or @TypeImage='net.ranides.assira.text.LexicalContext']
+                    ]
+                ])
+            ]
+            ]]>
+            </value></property>
+        </properties>
+    </rule>
+    -->
+
 </ruleset>

+ 4 - 1
assira.rules/src/main/resources/rulesets/java/assira.standard.xml

@@ -255,7 +255,10 @@
 
     <rule ref="rulesets/java/sunsecure.xml" />
     
-    <rule ref="rulesets/java/unusedcode.xml" />
+    <rule ref="rulesets/java/unusedcode.xml/UnusedPrivateField" />
+    <rule ref="rulesets/java/unusedcode.xml/UnusedLocalVariable" />
+    <rule ref="rulesets/java/unusedcode.xml/UnusedPrivateMethod" />
+    <rule ref="rulesets/java/unusedcode.xml/UnusedModifier" />
     
     <rule ref="rulesets/java/unnecessary.xml/UnnecessaryConversionTemporary"/>
     <rule ref="rulesets/java/unnecessary.xml/UnnecessaryFinalModifier"/>

+ 55 - 33
assira.rules/src/main/resources/rulesets/java/ranides.test.xml

@@ -1,33 +1,55 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<ruleset name="net.ranides.assira.standard"
-    xmlns="http://pmd.sf.net/ruleset/1.0.0"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
-    xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
-
-    <description>TEST</description>
-
-	<rule
-		name="TST-ECB"
-		ref="rulesets/java/empty.xml/EmptyCatchBlock"
-		message="TEST: Must handle exceptions">
-		<priority>2</priority>
-	</rule>
-        
-        <rule name="TST-RES"
-              language="java"
-              since="0.1"
-              message="TEST: Big"
-              class="net.ranides.assira.rules.TestECB"
-              externalInfoUrl="${pmd.website.baseurl}/rules/java/empty.html#EmptyCatchBlock">
-            <description>
-                ecb22
-            </description>
-            <priority>3</priority>
-            <properties>
-                <property name="allowCommentedBlocks" type="Boolean" value="false" description="text" />
-            </properties>
-        </rule>
-
-</ruleset>
+<?xml version="1.0" encoding="utf-8"?>
+
+<ruleset name="net.ranides.assira.standard"
+         xmlns="http://pmd.sf.net/ruleset/1.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
+         xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
+
+    <description>TEST</description>
+
+    <rule
+        name="TST-ECB"
+        ref="rulesets/java/empty.xml/EmptyCatchBlock"
+        message="TEST: Must handle exceptions">
+        <priority>2</priority>
+    </rule>
+        
+    <rule name="TST-RES"
+              language="java"
+              since="0.1"
+              message="TEST: Big"
+              class="net.ranides.assira.rules.TestECB"
+              externalInfoUrl="${pmd.website.baseurl}/rules/java/empty.html#EmptyCatchBlock">
+        <description>
+            ecb22
+        </description>
+        <priority>3</priority>
+        <properties>
+            <property name="allowCommentedBlocks" type="Boolean" value="false" description="text" />
+        </properties>
+    </rule>
+        
+    <rule name="UnusedParameter"
+              language="java"
+              since="0.8"
+              message="Avoid unused {0} parameters such as ''{1}''."
+              class="net.ranides.assira.rules.UnusedParameterRule"
+              externalInfoUrl="${pmd.website.baseurl}/rules/java/unusedcode.html#UnusedFormalParameter">
+        <description>
+            Avoid passing parameters to methods or constructors without actually referencing them in the method body.
+        </description>
+        <priority>3</priority>
+
+        <example>
+<![CDATA[
+public class Foo {
+	private void bar(String howdy) {
+	// howdy is not used
+	}
+}
+]]>
+        </example>
+    </rule>
+
+</ruleset>