1650 lines
60 KiB
XML
Vendored
1650 lines
60 KiB
XML
Vendored
<?xml version="1.0"?>
|
|
|
|
<ruleset name="Best Practices"
|
|
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
|
|
|
<description>
|
|
Rules which enforce generally accepted best practices.
|
|
</description>
|
|
|
|
<rule name="AbstractClassWithoutAbstractMethod"
|
|
language="java"
|
|
since="3.0"
|
|
message="This abstract class does not have any abstract methods"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#abstractclasswithoutabstractmethod">
|
|
<description>
|
|
The abstract class does not contain any abstract methods. An abstract class suggests
|
|
an incomplete implementation, which is to be completed by subclasses implementing the
|
|
abstract methods. If the class is intended to be used as a base class only (not to be instantiated
|
|
directly) a protected constructor can be provided prevent direct instantiation.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//ClassOrInterfaceDeclaration
|
|
[@Abstract='true'
|
|
and count( .//MethodDeclaration[@Abstract='true'] )=0 ]
|
|
[count(ImplementsList)=0]
|
|
[count(.//ExtendsList)=0]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public abstract class Foo {
|
|
void int method1() { ... }
|
|
void int method2() { ... }
|
|
// consider using abstract methods or removing
|
|
// the abstract modifier and adding protected constructors
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AccessorClassGeneration"
|
|
language="java"
|
|
since="1.04"
|
|
maximumLanguageVersion="10"
|
|
message="Avoid instantiation through private constructors from outside of the constructor's class."
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.AccessorClassGenerationRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#accessorclassgeneration">
|
|
<description>
|
|
Instantiation by way of private constructors from outside of the constructor's class often causes the
|
|
generation of an accessor. A factory method, or non-privatization of the constructor can eliminate this
|
|
situation. The generated class file is actually an interface. It gives the accessing class the ability
|
|
to invoke a new hidden package scope constructor that takes the interface as a supplementary parameter.
|
|
This turns a private constructor effectively into one with package scope, and is challenging to discern.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Outer {
|
|
void method(){
|
|
Inner ic = new Inner();//Causes generation of accessor class
|
|
}
|
|
public class Inner {
|
|
private Inner(){}
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AccessorMethodGeneration"
|
|
language="java"
|
|
since="5.5.4"
|
|
maximumLanguageVersion="10"
|
|
message="Avoid autogenerated methods to access private fields and methods of inner / outer classes"
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.AccessorMethodGenerationRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#accessormethodgeneration">
|
|
<description>
|
|
When accessing a private field / method from another class, the Java compiler will generate a accessor methods
|
|
with package-private visibility. This adds overhead, and to the dex method count on Android. This situation can
|
|
be avoided by changing the visibility of the field / method from private to package-private.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class OuterClass {
|
|
private int counter;
|
|
/* package */ int id;
|
|
|
|
public class InnerClass {
|
|
InnerClass() {
|
|
OuterClass.this.counter++; // wrong accessor method will be generated
|
|
}
|
|
|
|
public int getOuterClassId() {
|
|
return OuterClass.this.id; // id is package-private, no accessor method needed
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="ArrayIsStoredDirectly"
|
|
language="java"
|
|
since="2.2"
|
|
message="The user-supplied array ''{0}'' is stored directly."
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.ArrayIsStoredDirectlyRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#arrayisstoreddirectly">
|
|
<description>
|
|
Constructors and methods receiving arrays should clone objects and store the copy.
|
|
This prevents future changes from the user from affecting the original array.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
private String [] x;
|
|
public void foo (String [] param) {
|
|
// Don't do this, make a copy of the array at least
|
|
this.x=param;
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidPrintStackTrace"
|
|
language="java"
|
|
since="3.2"
|
|
message="Avoid printStackTrace(); use a logger call instead."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#avoidprintstacktrace">
|
|
<description>
|
|
Avoid printStackTrace(); use a logger call instead.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//PrimaryExpression
|
|
[PrimaryPrefix/Name[contains(@Image,'printStackTrace')]]
|
|
[PrimarySuffix[not(boolean(Arguments/ArgumentList/Expression))]]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
class Foo {
|
|
void bar() {
|
|
try {
|
|
// do something
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidReassigningLoopVariables"
|
|
language="java"
|
|
since="6.11.0"
|
|
message="Avoid reassigning the loop control variable ''{0}''"
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.AvoidReassigningLoopVariablesRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#avoidreassigningloopvariables">
|
|
<description>
|
|
Reassigning loop variables can lead to hard-to-find bugs. Prevent or limit how these variables can be changed.
|
|
|
|
In foreach-loops, configured by the `foreachReassign` property:
|
|
- `deny`: Report any reassignment of the loop variable in the loop body. _This is the default._
|
|
- `allow`: Don't check the loop variable.
|
|
- `firstOnly`: Report any reassignments of the loop variable, except as the first statement in the loop body.
|
|
_This is useful if some kind of normalization or clean-up of the value before using is permitted, but any other change of the variable is not._
|
|
|
|
In for-loops, configured by the `forReassign` property:
|
|
- `deny`: Report any reassignment of the control variable in the loop body. _This is the default._
|
|
- `allow`: Don't check the control variable.
|
|
- `skip`: Report any reassignments of the control variable, except conditional increments/decrements (`++`, `--`, `+=`, `-=`).
|
|
_This prevents accidental reassignments or unconditional increments of the control variable._
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
private void foo() {
|
|
for (String s : listOfStrings()) {
|
|
s = s.trim(); // OK, when foreachReassign is "firstOnly" or "allow"
|
|
doSomethingWith(s);
|
|
|
|
s = s.toUpper(); // OK, when foreachReassign is "allow"
|
|
doSomethingElseWith(s);
|
|
}
|
|
|
|
for (int i=0; i < 10; i++) {
|
|
if (check(i)) {
|
|
i++; // OK, when forReassign is "skip" or "allow"
|
|
}
|
|
|
|
i = 5; // OK, when forReassign is "allow"
|
|
|
|
doSomethingWith(i);
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidReassigningParameters"
|
|
language="java"
|
|
since="1.0"
|
|
message="Avoid reassigning parameters such as ''{0}''"
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.AvoidReassigningParametersRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#avoidreassigningparameters">
|
|
<description>
|
|
Reassigning values to incoming parameters is not recommended. Use temporary local variables instead.
|
|
</description>
|
|
<priority>2</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
private void foo(String bar) {
|
|
bar = "something else";
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidStringBufferField"
|
|
language="java"
|
|
since="4.2"
|
|
message="StringBuffers can grow quite a lot, and so may become a source of memory leak (if the owning class has a long life time)."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#avoidstringbufferfield">
|
|
<description>
|
|
StringBuffers/StringBuilders can grow considerably, and so may become a source of memory leaks
|
|
if held within objects with long lifetimes.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//FieldDeclaration/Type/ReferenceType/ClassOrInterfaceType[@Image = 'StringBuffer' or @Image = 'StringBuilder']
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
private StringBuffer buffer; // potential memory leak as an instance variable;
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidUsingHardCodedIP"
|
|
language="java"
|
|
since="4.1"
|
|
message="Do not hard code the IP address ${variableName}"
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.AvoidUsingHardCodedIPRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#avoidusinghardcodedip">
|
|
<description>
|
|
Application with hard-coded IP addresses can become impossible to deploy in some cases.
|
|
Externalizing IP adresses is preferable.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
private String ip = "127.0.0.1"; // not recommended
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="CheckResultSet"
|
|
language="java"
|
|
since="4.1"
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.CheckResultSetRule"
|
|
message="Always check the return of one of the navigation method (next,previous,first,last) of a ResultSet."
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#checkresultset">
|
|
<description>
|
|
Always check the return values of navigation methods (next, previous, first, last) of a ResultSet.
|
|
If the value return is 'false', it should be handled properly.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
Statement stat = conn.createStatement();
|
|
ResultSet rst = stat.executeQuery("SELECT name FROM person");
|
|
rst.next(); // what if it returns false? bad form
|
|
String firstName = rst.getString(1);
|
|
|
|
Statement stat = conn.createStatement();
|
|
ResultSet rst = stat.executeQuery("SELECT name FROM person");
|
|
if (rst.next()) { // result is properly examined and used
|
|
String firstName = rst.getString(1);
|
|
} else {
|
|
// handle missing data
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="ConstantsInInterface"
|
|
language="java"
|
|
since="5.5"
|
|
message="Avoid constants in interfaces. Interfaces define types, constants are implementation details better placed in classes or enums. See Effective Java, item 19."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#constantsininterface">
|
|
<description>
|
|
Avoid constants in interfaces. Interfaces should define types, constants are implementation details
|
|
better placed in classes or enums. See Effective Java, item 19.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="ignoreIfHasMethods" type="Boolean" description="Whether to ignore constants in interfaces if the interface defines any methods" value="true"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//ClassOrInterfaceDeclaration[@Interface='true'][$ignoreIfHasMethods='false' or not(.//MethodDeclaration)]//FieldDeclaration
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public interface ConstantInterface {
|
|
public static final int CONST1 = 1; // violation, no fields allowed in interface!
|
|
static final int CONST2 = 1; // violation, no fields allowed in interface!
|
|
final int CONST3 = 1; // violation, no fields allowed in interface!
|
|
int CONST4 = 1; // violation, no fields allowed in interface!
|
|
}
|
|
|
|
// with ignoreIfHasMethods = false
|
|
public interface AnotherConstantInterface {
|
|
public static final int CONST1 = 1; // violation, no fields allowed in interface!
|
|
|
|
int anyMethod();
|
|
}
|
|
|
|
// with ignoreIfHasMethods = true
|
|
public interface YetAnotherConstantInterface {
|
|
public static final int CONST1 = 1; // no violation
|
|
|
|
int anyMethod();
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="DefaultLabelNotLastInSwitchStmt"
|
|
language="java"
|
|
since="1.5"
|
|
message="The default label should be the last label in a switch statement"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#defaultlabelnotlastinswitchstmt">
|
|
<description>
|
|
By convention, the default label should be the last label in a switch statement.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//SwitchStatement
|
|
[not(SwitchLabel[position() = last()][@Default='true'])]
|
|
[SwitchLabel[@Default='true']]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
void bar(int a) {
|
|
switch (a) {
|
|
case 1: // do something
|
|
break;
|
|
default: // the default case should be last, by convention
|
|
break;
|
|
case 2:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="ForLoopCanBeForeach"
|
|
language="java"
|
|
since="6.0.0"
|
|
message="This 'for' loop can be replaced by a 'foreach' loop"
|
|
typeResolution="true"
|
|
minimumLanguageVersion="1.5"
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.ForLoopCanBeForeachRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#forloopcanbeforeach">
|
|
<description>
|
|
Reports loops that can be safely replaced with the foreach syntax. The rule considers loops over
|
|
lists, arrays and iterators. A loop is safe to replace if it only uses the index variable to
|
|
access an element of the list or array, only has one update statement, and loops through *every*
|
|
element of the list or array left to right.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class MyClass {
|
|
void loop(List<String> l) {
|
|
for (int i = 0; i < l.size(); i++) { // pre Java 1.5
|
|
System.out.println(l.get(i));
|
|
}
|
|
|
|
for (String s : l) { // post Java 1.5
|
|
System.out.println(s);
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="ForLoopVariableCount"
|
|
language="java"
|
|
since="6.11.0"
|
|
message="Too many control variables in the 'for' statement"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#forloopvariablecount">
|
|
<description>
|
|
Having a lot of control variables in a 'for' loop makes it harder to see what range of values
|
|
the loop iterates over. By default this rule allows a regular 'for' loop with only one variable.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="maximumVariables" type="Integer"
|
|
description="A regular for statement will have 1 control variable" min="0" max="100" value="1"/>
|
|
<property name="xpath">
|
|
<value>//ForInit/LocalVariableDeclaration[count(VariableDeclarator) > $maximumVariables]</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
// this will be reported with the default setting of at most one control variable in a for loop
|
|
for (int i = 0, j = 0; i < 10; i++, j += 2) {
|
|
foo();
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="GuardLogStatement"
|
|
language="java"
|
|
since="5.1.0"
|
|
message="Logger calls should be surrounded by log level guards."
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.GuardLogStatementRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#guardlogstatement">
|
|
<description>
|
|
Whenever using a log level, one should check if the loglevel is actually enabled, or
|
|
otherwise skip the associate String creation and manipulation.
|
|
</description>
|
|
<priority>2</priority>
|
|
<example>
|
|
<![CDATA[
|
|
// Add this for performance
|
|
if (log.isDebugEnabled() { ...
|
|
log.debug("log something" + " and " + "concat strings");
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="JUnit4SuitesShouldUseSuiteAnnotation"
|
|
language="java"
|
|
since="4.0"
|
|
message="JUnit 4 indicates test suites via annotations, not the suite method."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#junit4suitesshouldusesuiteannotation">
|
|
<description>
|
|
In JUnit 3, test suites are indicated by the suite() method. In JUnit 4, suites are indicated
|
|
through the @RunWith(Suite.class) annotation.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//ClassOrInterfaceBodyDeclaration[MethodDeclaration/MethodDeclarator[@Name='suite']]
|
|
[MethodDeclaration/ResultType/Type/ReferenceType/ClassOrInterfaceType[pmd-java:typeIs('junit.framework.Test')]]
|
|
[not(MethodDeclaration/Block//ClassOrInterfaceType[pmd-java:typeIs('junit.framework.JUnit4TestAdapter')])]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class BadExample extends TestCase{
|
|
|
|
public static Test suite(){
|
|
return new Suite();
|
|
}
|
|
}
|
|
|
|
@RunWith(Suite.class)
|
|
@SuiteClasses( { TestOne.class, TestTwo.class })
|
|
public class GoodTest {
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="JUnit4TestShouldUseAfterAnnotation"
|
|
language="java"
|
|
since="4.0"
|
|
message="JUnit 4 tests that clean up tests should use the @After annotation, JUnit5 tests should use @AfterEach or @AfterAll"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#junit4testshoulduseafterannotation">
|
|
<description>
|
|
In JUnit 3, the tearDown method was used to clean up all data entities required in running tests.
|
|
JUnit 4 skips the tearDown method and executes all methods annotated with @After after running each test.
|
|
JUnit 5 introduced @AfterEach and @AfterAll annotations to execute methods after each test or after all tests in the class, respectively.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//ClassOrInterfaceBodyDeclaration
|
|
[MethodDeclaration/MethodDeclarator[@Name='tearDown']]
|
|
[count(Annotation//Name[
|
|
pmd-java:typeIs('org.junit.After')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.AfterEach')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.AfterAll')
|
|
or pmd-java:typeIs('org.testng.annotations.AfterMethod')])=0]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class MyTest {
|
|
public void tearDown() {
|
|
bad();
|
|
}
|
|
}
|
|
public class MyTest2 {
|
|
@After public void tearDown() {
|
|
good();
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="JUnit4TestShouldUseBeforeAnnotation"
|
|
language="java"
|
|
since="4.0"
|
|
message="JUnit 4 tests that set up tests should use the @Before annotation, JUnit5 tests should use @BeforeEach or @BeforeAll"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#junit4testshouldusebeforeannotation">
|
|
<description>
|
|
In JUnit 3, the setUp method was used to set up all data entities required in running tests.
|
|
JUnit 4 skips the setUp method and executes all methods annotated with @Before before all tests.
|
|
JUnit 5 introduced @BeforeEach and @BeforeAll annotations to execute methods before each test or before all tests in the class, respectively.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//ClassOrInterfaceBodyDeclaration
|
|
[MethodDeclaration/MethodDeclarator[@Name='setUp']]
|
|
[count(Annotation//Name[
|
|
pmd-java:typeIs('org.junit.Before')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.BeforeEach')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.BeforeAll')
|
|
or pmd-java:typeIs('org.testng.annotations.BeforeMethod')])=0]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class MyTest {
|
|
public void setUp() {
|
|
bad();
|
|
}
|
|
}
|
|
public class MyTest2 {
|
|
@Before public void setUp() {
|
|
good();
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="JUnit4TestShouldUseTestAnnotation"
|
|
language="java"
|
|
since="4.0"
|
|
message="JUnit 4 tests that execute tests should use the @Test annotation, JUnit 5 tests should use @Test, @RepeatedTest, @TestFactory, @TestTemplate or @ParameterizedTest"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#junit4testshouldusetestannotation">
|
|
<description>
|
|
In JUnit 3, the framework executed all methods which started with the word test as a unit test.
|
|
In JUnit 4, only methods annotated with the @Test annotation are executed.
|
|
In JUnit 5, one of the following annotations should be used for tests: @Test, @RepeatedTest, @TestFactory, @TestTemplate or @ParameterizedTest.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//ClassOrInterfaceDeclaration[
|
|
matches(@SimpleName, $testClassPattern)
|
|
or ExtendsList/ClassOrInterfaceType[pmd-java:typeIs('junit.framework.TestCase')]]
|
|
|
|
/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration[MethodDeclaration[@Public=true()]/MethodDeclarator[starts-with(@Name, 'test')]]
|
|
[not(Annotation//Name[
|
|
pmd-java:typeIs('org.junit.Test')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.Test') or pmd-java:typeIs('org.junit.jupiter.api.RepeatedTest')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.TestFactory') or pmd-java:typeIs('org.junit.jupiter.api.TestTemplate')
|
|
or pmd-java:typeIs('org.junit.jupiter.params.ParameterizedTest')
|
|
])]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
<property name="testClassPattern" type="Regex" description="The regex pattern used to identify test classes" value="Test" />
|
|
<property name="version" value="2.0"/>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class MyTest {
|
|
public void testBad() {
|
|
doSomething();
|
|
}
|
|
|
|
@Test
|
|
public void testGood() {
|
|
doSomething();
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="JUnitAssertionsShouldIncludeMessage"
|
|
language="java"
|
|
since="1.04"
|
|
message="JUnit assertions should include a message"
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.JUnitAssertionsShouldIncludeMessageRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#junitassertionsshouldincludemessage">
|
|
<description>
|
|
JUnit assertions should include an informative message - i.e., use the three-argument version of
|
|
assertEquals(), not the two-argument version.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo extends TestCase {
|
|
public void testSomething() {
|
|
assertEquals("foo", "bar");
|
|
// Use the form:
|
|
// assertEquals("Foo does not equals bar", "foo", "bar");
|
|
// instead
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="JUnitTestContainsTooManyAsserts"
|
|
language="java"
|
|
since="5.0"
|
|
message="Unit tests should not contain more than ${maximumAsserts} assert(s)."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#junittestcontainstoomanyasserts">
|
|
<description>
|
|
Unit tests should not contain too many asserts. Many asserts are indicative of a complex test, for which
|
|
it is harder to verify correctness. Consider breaking the test scenario into multiple, shorter test scenarios.
|
|
Customize the maximum number of assertions used by this Rule to suit your needs.
|
|
|
|
This rule checks for JUnit4, JUnit5 and TestNG Tests, as well as methods starting with "test".
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="maximumAsserts" type="Integer" min="1" max="1000" description="Maximum number of Asserts in a test method" value="1"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//MethodDeclarator[@Image[fn:matches(.,'^test')] or ../../Annotation/MarkerAnnotation/Name[
|
|
pmd-java:typeIs('org.junit.Test')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.Test')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.RepeatedTest')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.TestFactory')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.TestTemplate')
|
|
or pmd-java:typeIs('org.junit.jupiter.params.ParameterizedTest')
|
|
or pmd-java:typeIs('org.testng.annotations.Test')
|
|
]]
|
|
[count(..//PrimaryPrefix/Name[@Image[fn:matches(.,'^assert')]]) > $maximumAsserts]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class MyTestCase extends TestCase {
|
|
// Ok
|
|
public void testMyCaseWithOneAssert() {
|
|
boolean myVar = false;
|
|
assertFalse("should be false", myVar);
|
|
}
|
|
|
|
// Bad, too many asserts (assuming max=1)
|
|
public void testMyCaseWithMoreAsserts() {
|
|
boolean myVar = false;
|
|
assertFalse("myVar should be false", myVar);
|
|
assertEquals("should equals false", false, myVar);
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="JUnitTestsShouldIncludeAssert"
|
|
language="java"
|
|
since="2.0"
|
|
message="JUnit tests should include assert() or fail()"
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.JUnitTestsShouldIncludeAssertRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#junittestsshouldincludeassert">
|
|
<description>
|
|
JUnit tests should include at least one assertion. This makes the tests more robust, and using assert
|
|
with messages provide the developer a clearer idea of what the test does.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo extends TestCase {
|
|
public void testSomething() {
|
|
Bar b = findBar();
|
|
// This is better than having a NullPointerException
|
|
// assertNotNull("bar not found", b);
|
|
b.work();
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="JUnitUseExpected"
|
|
language="java"
|
|
since="4.0"
|
|
message="In JUnit4, use the @Test(expected) annotation to denote tests that should throw exceptions"
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.JUnitUseExpectedRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#junituseexpected">
|
|
<description>
|
|
In JUnit4, use the @Test(expected) annotation to denote tests that should throw exceptions.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class MyTest {
|
|
@Test
|
|
public void testBad() {
|
|
try {
|
|
doSomething();
|
|
fail("should have thrown an exception");
|
|
} catch (Exception e) {
|
|
}
|
|
}
|
|
|
|
@Test(expected=Exception.class)
|
|
public void testGood() {
|
|
doSomething();
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="LooseCoupling"
|
|
language="java"
|
|
since="0.7"
|
|
message="Avoid using implementation types like ''{0}''; use the interface instead"
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.LooseCouplingRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#loosecoupling">
|
|
<description>
|
|
The use of implementation types (i.e., HashSet) as object references limits your ability to use alternate
|
|
implementations in the future as requirements change. Whenever available, referencing objects
|
|
by their interface types (i.e, Set) provides much more flexibility.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
import java.util.ArrayList;
|
|
import java.util.HashSet;
|
|
|
|
public class Bar {
|
|
// sub-optimal approach
|
|
private ArrayList<SomeType> list = new ArrayList<>();
|
|
|
|
public HashSet<SomeType> getFoo() {
|
|
return new HashSet<SomeType>();
|
|
}
|
|
|
|
// preferred approach
|
|
private List<SomeType> list = new ArrayList<>();
|
|
|
|
public Set<SomeType> getFoo() {
|
|
return new HashSet<SomeType>();
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="MethodReturnsInternalArray"
|
|
language="java"
|
|
since="2.2"
|
|
message="Returning ''{0}'' may expose an internal array."
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.MethodReturnsInternalArrayRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#methodreturnsinternalarray">
|
|
<description>
|
|
Exposing internal arrays to the caller violates object encapsulation since elements can be
|
|
removed or replaced outside of the object that owns it. It is safer to return a copy of the array.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class SecureSystem {
|
|
UserData [] ud;
|
|
public UserData [] getUserData() {
|
|
// Don't return directly the internal array, return a copy
|
|
return ud;
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
|
|
<rule name="MissingOverride"
|
|
language="java"
|
|
since="6.2.0"
|
|
minimumLanguageVersion="1.5"
|
|
message="The method ''{0}'' is missing an @Override annotation."
|
|
typeResolution="true"
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.MissingOverrideRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#missingoverride">
|
|
<description>
|
|
Annotating overridden methods with @Override ensures at compile time that
|
|
the method really overrides one, which helps refactoring and clarifies intent.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo implements Runnable {
|
|
// This method is overridden, and should have an @Override annotation
|
|
public void run() {
|
|
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="OneDeclarationPerLine"
|
|
language="java"
|
|
since="5.0"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
message="Use one line for each declaration, it enhances code readability."
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#onedeclarationperline">
|
|
<description>
|
|
Java allows the use of several variables declaration of the same type on one line. However, it
|
|
can lead to quite messy code. This rule looks for several declarations on the same line.
|
|
</description>
|
|
<priority>4</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//LocalVariableDeclaration
|
|
[not(parent::ForInit)]
|
|
[count(VariableDeclarator) > 1]
|
|
[$strictMode or count(distinct-values(VariableDeclarator/@BeginLine)) != count(VariableDeclarator)]
|
|
|
|
|
//FieldDeclaration
|
|
[count(VariableDeclarator) > 1]
|
|
[$strictMode or count(distinct-values(VariableDeclarator/@BeginLine)) != count(VariableDeclarator)]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
<property name="version" value="2.0"/>
|
|
<property name="strictMode" type="Boolean" value="false"
|
|
description="If true, mark combined declaration even if the declarations are on separate lines."/>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
String name; // separate declarations
|
|
String lastname;
|
|
|
|
String name, lastname; // combined declaration, a violation
|
|
|
|
String name,
|
|
lastname; // combined declaration on multiple lines, no violation by default.
|
|
// Set property strictMode to true to mark this as violation.
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="PositionLiteralsFirstInCaseInsensitiveComparisons"
|
|
language="java"
|
|
since="5.1"
|
|
message="Position literals first in String comparisons for EqualsIgnoreCase"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#positionliteralsfirstincaseinsensitivecomparisons">
|
|
<description>
|
|
Position literals first in comparisons, if the second argument is null then NullPointerExceptions
|
|
can be avoided, they will just return false.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//PrimaryExpression[
|
|
PrimaryPrefix[Name
|
|
[
|
|
(ends-with(@Image, '.equalsIgnoreCase'))
|
|
]
|
|
]
|
|
[
|
|
(../PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Literal)
|
|
and
|
|
( count(../PrimarySuffix/Arguments/ArgumentList/Expression) = 1 )
|
|
]
|
|
]
|
|
[not(ancestor::Expression/ConditionalAndExpression//EqualityExpression[@Image='!=']//NullLiteral)]
|
|
[not(ancestor::Expression/ConditionalOrExpression//EqualityExpression[@Image='==']//NullLiteral)]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
class Foo {
|
|
boolean bar(String x) {
|
|
return x.equalsIgnoreCase("2"); // should be "2".equalsIgnoreCase(x)
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="PositionLiteralsFirstInComparisons"
|
|
language="java"
|
|
since="3.3"
|
|
message="Position literals first in String comparisons"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#positionliteralsfirstincomparisons">
|
|
<description>
|
|
Position literals first in comparisons, if the second argument is null then NullPointerExceptions
|
|
can be avoided, they will just return false.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//PrimaryExpression[
|
|
PrimaryPrefix[Name[(ends-with(@Image, '.equals'))]]
|
|
[
|
|
(../PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Literal[@StringLiteral='true'])
|
|
and
|
|
( count(../PrimarySuffix/Arguments/ArgumentList/Expression) = 1 )
|
|
]
|
|
]
|
|
[not(ancestor::Expression/ConditionalAndExpression//EqualityExpression[@Image='!=']//NullLiteral)]
|
|
[not(ancestor::Expression/ConditionalOrExpression//EqualityExpression[@Image='==']//NullLiteral)]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
class Foo {
|
|
boolean bar(String x) {
|
|
return x.equals("2"); // should be "2".equals(x)
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="PreserveStackTrace"
|
|
language="java"
|
|
since="3.7"
|
|
message="New exception is thrown in catch block, original stack trace may be lost"
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.PreserveStackTraceRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#preservestacktrace">
|
|
<description>
|
|
Throwing a new exception from a catch block without passing the original exception into the
|
|
new exception will cause the original stack trace to be lost making it difficult to debug
|
|
effectively.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
void good() {
|
|
try{
|
|
Integer.parseInt("a");
|
|
} catch (Exception e) {
|
|
throw new Exception(e); // first possibility to create exception chain
|
|
}
|
|
try {
|
|
Integer.parseInt("a");
|
|
} catch (Exception e) {
|
|
throw (IllegalStateException)new IllegalStateException().initCause(e); // second possibility to create exception chain.
|
|
}
|
|
}
|
|
void bad() {
|
|
try{
|
|
Integer.parseInt("a");
|
|
} catch (Exception e) {
|
|
throw new Exception(e.getMessage());
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="ReplaceEnumerationWithIterator"
|
|
language="java"
|
|
since="3.4"
|
|
message="Consider replacing this Enumeration with the newer java.util.Iterator"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#replaceenumerationwithiterator">
|
|
<description>
|
|
Consider replacing Enumeration usages with the newer java.util.Iterator
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//ImplementsList/ClassOrInterfaceType[@Image='Enumeration']
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo implements Enumeration {
|
|
private int x = 42;
|
|
public boolean hasMoreElements() {
|
|
return true;
|
|
}
|
|
public Object nextElement() {
|
|
return String.valueOf(i++);
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="ReplaceHashtableWithMap"
|
|
language="java"
|
|
since="3.4"
|
|
message="Consider replacing this Hashtable with the newer java.util.Map"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#replacehashtablewithmap">
|
|
<description>
|
|
Consider replacing Hashtable usage with the newer java.util.Map if thread safety is not required.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>//Type/ReferenceType/ClassOrInterfaceType[@Image='Hashtable']</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
void bar() {
|
|
Hashtable h = new Hashtable();
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="ReplaceVectorWithList"
|
|
language="java"
|
|
since="3.4"
|
|
message="Consider replacing this Vector with the newer java.util.List"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#replacevectorwithlist">
|
|
<description>
|
|
Consider replacing Vector usages with the newer java.util.ArrayList if expensive thread-safe operations are not required.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>//Type/ReferenceType/ClassOrInterfaceType[@Image='Vector']</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
void bar() {
|
|
Vector v = new Vector();
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="SwitchStmtsShouldHaveDefault"
|
|
language="java"
|
|
since="1.0"
|
|
message="Switch statements should have a default label"
|
|
typeResolution="true"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#switchstmtsshouldhavedefault">
|
|
<description>
|
|
All switch statements should include a default option to catch any unspecified values.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//SwitchStatement[@DefaultCase = false() and @ExhaustiveEnumSwitch = false()]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public void bar() {
|
|
int x = 2;
|
|
switch (x) {
|
|
case 1: int j = 6;
|
|
case 2: int j = 8;
|
|
// missing default: here
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="SystemPrintln"
|
|
language="java"
|
|
since="2.1"
|
|
message="{0} is used"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#systemprintln">
|
|
<description>
|
|
References to System.(out|err).print are usually intended for debugging purposes and can remain in
|
|
the codebase even in production code. By using a logger one can enable/disable this behaviour at
|
|
will (and by priority) and avoid clogging the Standard out log.
|
|
</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//Name[
|
|
starts-with(@Image, 'System.out.print')
|
|
or
|
|
starts-with(@Image, 'System.err.print')
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
class Foo{
|
|
Logger log = Logger.getLogger(Foo.class.getName());
|
|
public void testA () {
|
|
System.out.println("Entering test");
|
|
// Better use this
|
|
log.fine("Entering test");
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UnusedFormalParameter"
|
|
language="java"
|
|
since="0.8"
|
|
message="Avoid unused {0} parameters such as ''{1}''."
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.UnusedFormalParameterRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.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="UnusedImports"
|
|
language="java"
|
|
since="1.0"
|
|
message="Avoid unused imports such as ''{0}''"
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.UnusedImportsRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#unusedimports">
|
|
<description>
|
|
Avoid unused import statements to prevent unwanted dependencies.
|
|
This rule will also find unused on demand imports, i.e. import com.foo.*.
|
|
</description>
|
|
<priority>4</priority>
|
|
<example>
|
|
<![CDATA[
|
|
import java.io.File; // not referenced or required
|
|
import java.util.*; // not referenced or required
|
|
|
|
public class Foo {}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UnusedLocalVariable"
|
|
language="java"
|
|
since="0.1"
|
|
message="Avoid unused local variables such as ''{0}''."
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.UnusedLocalVariableRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#unusedlocalvariable">
|
|
<description>
|
|
Detects when a local variable is declared and/or assigned, but not used.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
public void doSomething() {
|
|
int i = 5; // Unused
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UnusedPrivateField"
|
|
since="0.1"
|
|
language="java"
|
|
message="Avoid unused private fields such as ''{0}''."
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.UnusedPrivateFieldRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#unusedprivatefield">
|
|
<description>
|
|
Detects when a private field is declared and/or assigned a value, but not used.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Something {
|
|
private static int FOO = 2; // Unused
|
|
private int i = 5; // Unused
|
|
private int j = 6;
|
|
public int addOne() {
|
|
return j++;
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UnusedPrivateMethod"
|
|
language="java"
|
|
since="0.7"
|
|
message="Avoid unused private methods such as ''{0}''."
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.UnusedPrivateMethodRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#unusedprivatemethod">
|
|
<description>
|
|
Unused Private Method detects when a private method is declared but is unused.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Something {
|
|
private void foo() {} // unused
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UseAssertEqualsInsteadOfAssertTrue"
|
|
language="java"
|
|
since="3.1"
|
|
message="Use assertEquals(x, y) instead of assertTrue(x.equals(y))"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#useassertequalsinsteadofasserttrue">
|
|
<description>
|
|
This rule detects JUnit assertions in object equality. These assertions should be made by more specific methods, like assertEquals.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//PrimaryExpression[
|
|
PrimaryPrefix/Name[@Image = 'assertTrue']
|
|
][
|
|
PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Name
|
|
[ends-with(@Image, '.equals')]
|
|
]
|
|
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeIs('junit.framework.TestCase')]
|
|
or //MarkerAnnotation/Name[
|
|
pmd-java:typeIs('org.junit.Test')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.Test') or pmd-java:typeIs('org.junit.jupiter.api.RepeatedTest')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.TestFactory') or pmd-java:typeIs('org.junit.jupiter.api.TestTemplate')
|
|
or pmd-java:typeIs('org.junit.jupiter.params.ParameterizedTest')
|
|
]
|
|
]]]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class FooTest extends TestCase {
|
|
void testCode() {
|
|
Object a, b;
|
|
assertTrue(a.equals(b)); // bad usage
|
|
assertEquals(?a should equals b?, a, b); // good usage
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UseAssertNullInsteadOfAssertTrue"
|
|
language="java"
|
|
since="3.5"
|
|
message="Use assertNull(x) instead of assertTrue(x==null), or assertNotNull(x) vs assertFalse(x==null)"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#useassertnullinsteadofasserttrue">
|
|
<description>
|
|
This rule detects JUnit assertions in object references equality. These assertions should be made by
|
|
more specific methods, like assertNull, assertNotNull.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//PrimaryExpression[
|
|
PrimaryPrefix/Name[@Image = 'assertTrue' or @Image = 'assertFalse']
|
|
][
|
|
PrimarySuffix/Arguments/ArgumentList[
|
|
Expression/EqualityExpression/PrimaryExpression/PrimaryPrefix/Literal/NullLiteral
|
|
]
|
|
]
|
|
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeIs('junit.framework.TestCase')]
|
|
or //MarkerAnnotation/Name[
|
|
pmd-java:typeIs('org.junit.Test')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.Test') or pmd-java:typeIs('org.junit.jupiter.api.RepeatedTest')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.TestFactory') or pmd-java:typeIs('org.junit.jupiter.api.TestTemplate')
|
|
or pmd-java:typeIs('org.junit.jupiter.params.ParameterizedTest')
|
|
]
|
|
]]]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class FooTest extends TestCase {
|
|
void testCode() {
|
|
Object a = doSomething();
|
|
assertTrue(a==null); // bad usage
|
|
assertNull(a); // good usage
|
|
assertTrue(a != null); // bad usage
|
|
assertNotNull(a); // good usage
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UseAssertSameInsteadOfAssertTrue"
|
|
language="java"
|
|
since="3.1"
|
|
message="Use assertSame(x, y) instead of assertTrue(x==y), or assertNotSame(x,y) vs assertFalse(x==y)"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#useassertsameinsteadofasserttrue">
|
|
<description>
|
|
This rule detects JUnit assertions in object references equality. These assertions should be made
|
|
by more specific methods, like assertSame, assertNotSame.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//PrimaryExpression[
|
|
PrimaryPrefix/Name
|
|
[@Image = 'assertTrue' or @Image = 'assertFalse']
|
|
]
|
|
[PrimarySuffix/Arguments
|
|
/ArgumentList/Expression
|
|
/EqualityExpression[count(.//NullLiteral) = 0]]
|
|
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeIs('junit.framework.TestCase')]
|
|
or //MarkerAnnotation/Name[
|
|
pmd-java:typeIs('org.junit.Test')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.Test') or pmd-java:typeIs('org.junit.jupiter.api.RepeatedTest')
|
|
or pmd-java:typeIs('org.junit.jupiter.api.TestFactory') or pmd-java:typeIs('org.junit.jupiter.api.TestTemplate')
|
|
or pmd-java:typeIs('org.junit.jupiter.params.ParameterizedTest')
|
|
]
|
|
]]]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class FooTest extends TestCase {
|
|
void testCode() {
|
|
Object a, b;
|
|
assertTrue(a == b); // bad usage
|
|
assertSame(a, b); // good usage
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UseAssertTrueInsteadOfAssertEquals"
|
|
language="java"
|
|
since="5.0"
|
|
message="Use assertTrue(x)/assertFalse(x) instead of assertEquals(true, x)/assertEquals(false, x) or assertEquals(Boolean.TRUE, x)/assertEquals(Boolean.FALSE, x)."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#useasserttrueinsteadofassertequals">
|
|
<description>
|
|
When asserting a value is the same as a literal or Boxed boolean, use assertTrue/assertFalse, instead of assertEquals.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//PrimaryExpression[PrimaryPrefix/Name[@Image = 'assertEquals']]
|
|
[
|
|
PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Literal/BooleanLiteral
|
|
or
|
|
PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix
|
|
/Name[(@Image = 'Boolean.TRUE' or @Image = 'Boolean.FALSE')]
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class MyTestCase extends TestCase {
|
|
public void testMyCase() {
|
|
boolean myVar = true;
|
|
// Ok
|
|
assertTrue("myVar is true", myVar);
|
|
// Bad
|
|
assertEquals("myVar is true", true, myVar);
|
|
// Bad
|
|
assertEquals("myVar is false", false, myVar);
|
|
// Bad
|
|
assertEquals("myVar is true", Boolean.TRUE, myVar);
|
|
// Bad
|
|
assertEquals("myVar is false", Boolean.FALSE, myVar);
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UseCollectionIsEmpty"
|
|
language="java"
|
|
since="3.9"
|
|
message="Substitute calls to size() == 0 (or size() != 0, size() > 0, size() < 1) with calls to isEmpty()"
|
|
class="net.sourceforge.pmd.lang.java.rule.bestpractices.UseCollectionIsEmptyRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#usecollectionisempty">
|
|
<description>
|
|
The isEmpty() method on java.util.Collection is provided to determine if a collection has any elements.
|
|
Comparing the value of size() to 0 does not convey intent as well as the isEmpty() method.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
void good() {
|
|
List foo = getList();
|
|
if (foo.isEmpty()) {
|
|
// blah
|
|
}
|
|
}
|
|
|
|
void bad() {
|
|
List foo = getList();
|
|
if (foo.size() == 0) {
|
|
// blah
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UseTryWithResources"
|
|
language="java"
|
|
minimumLanguageVersion="1.7"
|
|
since="6.12.0"
|
|
typeResolution="true"
|
|
message="Consider using a try-with-resources statement instead of explicitly closing the resource"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#usetrywithresources">
|
|
<description>
|
|
Java 7 introduced the try-with-resources statement. This statement ensures that each resource is closed at the end
|
|
of the statement. It avoids the need of explicitly closing the resources in a finally block. Additionally exceptions
|
|
are better handled: If an exception occurred both in the `try` block and `finally` block, then the exception from
|
|
the try block was suppressed. With the `try`-with-resources statement, the exception thrown from the try-block is
|
|
preserved.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="closeMethods" type="List[String]" delimiter="," description="Method names in finally block, which trigger this rule" value="close,closeQuietly"/>
|
|
<property name="version" value="2.0" />
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//TryStatement[FinallyStatement//Name[
|
|
tokenize(@Image, '\.')[last()] = $closeMethods
|
|
][
|
|
pmd-java:typeIs('java.lang.AutoCloseable')
|
|
or
|
|
../../PrimarySuffix/Arguments[@Size = 1]//PrimaryPrefix[pmd-java:typeIs('java.lang.AutoCloseable')]
|
|
]]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class TryWithResources {
|
|
public void run() {
|
|
InputStream in = null;
|
|
try {
|
|
in = openInputStream();
|
|
int i = in.read();
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
} finally {
|
|
try {
|
|
if (in != null) in.close();
|
|
} catch (IOException ignored) {
|
|
// ignored
|
|
}
|
|
}
|
|
|
|
// better use try-with-resources
|
|
try (InputStream in2 = openInputStream()) {
|
|
int i = in2.read();
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UseVarargs"
|
|
language="java"
|
|
minimumLanguageVersion="1.5"
|
|
since="5.0"
|
|
message="Consider using varargs for methods or constructors which take an array the last parameter."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#usevarargs">
|
|
<description>
|
|
Java 5 introduced the varargs parameter declaration for methods and constructors. This syntactic
|
|
sugar provides flexibility for users of these methods and constructors, allowing them to avoid
|
|
having to deal with the creation of an array.
|
|
</description>
|
|
<priority>4</priority>
|
|
<properties>
|
|
<property name="version" value="2.0" />
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//FormalParameters/FormalParameter
|
|
[position()=last()]
|
|
[VariableDeclaratorId/@ArrayType=true()]
|
|
[@Varargs=false()]
|
|
[not (./Type[@ArrayType=true()]/ReferenceType[PrimitiveType[@Image='byte']])]
|
|
[not (./Type/ReferenceType[ClassOrInterfaceType[@Image='Byte']])]
|
|
[not (./Type/PrimitiveType[@Image='byte'])]
|
|
[not (ancestor::MethodDeclaration/preceding-sibling::Annotation/*/Name[@Image='Override'])]
|
|
[not(
|
|
ancestor::MethodDeclaration
|
|
[@Public=true() and @Static=true()]
|
|
[child::ResultType[@Void=true()]] and
|
|
ancestor::MethodDeclarator[@Image='main'] and
|
|
..[@ParameterCount=1] and
|
|
./Type/ReferenceType[ClassOrInterfaceType[@Image='String']]
|
|
)]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
public void foo(String s, Object[] args) {
|
|
// Do something here...
|
|
}
|
|
|
|
public void bar(String s, Object... args) {
|
|
// Ahh, varargs tastes much better...
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
</ruleset>
|