Add GuardLogStatement
Based on Heiko Rupp implemetation: http://pilhuhn.blogspot.com/2008/09/pmd-rule-to-check-for-unguarded.html
This commit is contained in:
1 parent
a90e9fed0b
commit
4bce034c33
5 files changed
+143
-36
No files matched your search
@@ -321,9 +321,9 @@ public class RuleSetFactory {
|
||||
}
|
||||
|
||||
String attribute = ruleElement.getAttribute("class");
|
||||
Class<?> c = classLoader.loadClass(attribute);
|
||||
Rule rule = (Rule) c.newInstance();
|
||||
|
||||
if ( attribute == null || "".equals(attribute))
|
||||
throw new IllegalArgumentException("The 'class' field of rule can't be null, nor empty.");
|
||||
Rule rule = (Rule) classLoader.loadClass(attribute).newInstance();
|
||||
rule.setName(ruleElement.getAttribute("name"));
|
||||
|
||||
if (ruleElement.hasAttribute("language")) {
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package net.sourceforge.pmd.lang.java.rule.logging;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
|
||||
import net.sourceforge.pmd.lang.java.rule.optimizations.AbstractOptimizationRule;
|
||||
|
||||
|
||||
/**
|
||||
* Check that log.debug and log.trace statements are guarded by some
|
||||
* log.isDebugEnabled() or log.isTraceEnabled() checks.
|
||||
*
|
||||
* @author Heiko hwr@pilhuhn.de
|
||||
* @author Romain Pelisse - <belaran@gmail.com>
|
||||
*
|
||||
*/
|
||||
public class GuardLogStatementRule extends AbstractOptimizationRule implements Rule {
|
||||
|
||||
private static final Map<String,String> guardStmtByLogLevel = new HashMap<String,String>(5);
|
||||
|
||||
public GuardLogStatementRule() {
|
||||
guardStmtByLogLevel.put(".trace","isTraceEnabled");
|
||||
guardStmtByLogLevel.put(".debug","isDebugEnabled");
|
||||
guardStmtByLogLevel.put(".warn", "isWarnEnabled");
|
||||
guardStmtByLogLevel.put(".error", "isErrorEnabled");
|
||||
guardStmtByLogLevel.put(".info","isInfoEnabled");
|
||||
}
|
||||
|
||||
private String lastPrefix(String string) {
|
||||
return (string != null && ! "".equals(string)) ? string.substring(string.lastIndexOf('.'), string.length()) : string;
|
||||
}
|
||||
|
||||
public Object visit(ASTName name, Object data) {
|
||||
Node node = name.jjtGetParent();
|
||||
if ( node instanceof ASTPrimaryPrefix ) {
|
||||
|
||||
} else
|
||||
return super.visit(name,data);
|
||||
if (name != null) {
|
||||
String lastPrefix = lastPrefix(name.getImage());
|
||||
if ( guardStmtByLogLevel.keySet().contains(lastPrefix)) {
|
||||
// TODO check for type
|
||||
Node parent1 = name.getNthParent(5);
|
||||
boolean guardFound = false;
|
||||
if (parent1 instanceof ASTIfStatement) {
|
||||
guardFound = checkForGuard((ASTIfStatement) parent1, lastPrefix);
|
||||
}
|
||||
else if (parent1 instanceof ASTBlockStatement) {
|
||||
Node parent2 = name.getNthParent(7);
|
||||
if (parent2 instanceof ASTIfStatement) {
|
||||
guardFound = checkForGuard((ASTIfStatement) parent2, lastPrefix);
|
||||
}
|
||||
}
|
||||
if (!guardFound)
|
||||
addViolation(data, name);
|
||||
}
|
||||
}
|
||||
return super.visit(name, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* We stand on an if() check if it contains log.isDebugEnabled()
|
||||
* @param stm
|
||||
* @param isTrace true if log.trace() is used
|
||||
* @return true if guard was found
|
||||
*/
|
||||
|
||||
private boolean checkForGuard(ASTIfStatement stm, String logLevel) {
|
||||
|
||||
List<ASTName> names = stm.findDescendantsOfType(ASTName.class);
|
||||
if (names == null || names.isEmpty() )
|
||||
return false;
|
||||
|
||||
for ( ASTName name : names) {
|
||||
String image = name.getImage();
|
||||
if ( guardStmtByLogLevel.get(logLevel).equals(name.getImage()) );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -63,43 +63,27 @@ public class Foo{
|
||||
}
|
||||
]]>
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
<!-- This rule will probably be implemented in a java class, since we need to search the logger name
|
||||
first -->
|
||||
<!--
|
||||
<rule name="LogBlockWithoutIf"
|
||||
message="There is log block not surrounded by if"
|
||||
class="net.sourceforge.pmd.lang.rule.XPathRule">
|
||||
<description>
|
||||
When many log statements are used, it is convenient to surround them with an if statement.
|
||||
</description>
|
||||
<properties>
|
||||
<property name="xpath">
|
||||
<value>
|
||||
<![CDATA[
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
</properties>
|
||||
<priority>2</priority>
|
||||
</rule>
|
||||
|
||||
<rule name="GuardLogStatement"
|
||||
language="java"
|
||||
since="5.0"
|
||||
message="There is log block not surrounded by if"
|
||||
class="net.sourceforge.pmd.lang.java.rule.logging.GuardLogStatementRule"
|
||||
externalInfoUrl="${pmd.website.baseurl}/rules/java/logging-java.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.isLoggable(Level.FINE)) { ...
|
||||
log.fine("This happens");
|
||||
log.fine("Value of x:"+x);
|
||||
log.fine("Value of y:"+y);
|
||||
log.fine("Value of z:"+z);
|
||||
log.fine("Value of w:"+w);
|
||||
|
||||
if (log.isLoggable(Level.FINE)) { ...
|
||||
log.fine("This happens");
|
||||
]]>
|
||||
</example>
|
||||
</rule>
|
||||
-->
|
||||
|
||||
</rule>
|
||||
|
||||
<rule name="SystemPrintln"
|
||||
language="java"
|
||||
@@ -175,5 +159,5 @@ class Foo {
|
||||
]]>
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
|
||||
</ruleset>
|
||||
+1
@@ -15,6 +15,7 @@ public class LoggingJavaRulesTest extends SimpleAggregatorTst {
|
||||
addRule(RULESET, "LoggerIsNotStaticFinal");
|
||||
addRule(RULESET, "MoreThanOneLogger");
|
||||
addRule(RULESET, "SystemPrintln");
|
||||
addRule(RULESET, "GuardLogStatement");
|
||||
}
|
||||
|
||||
public static junit.framework.Test suite() {
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<test-data>
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
OK, guard is here
|
||||
]]></description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
private static final Logger logger = Logger.getLogger(Foo.class);
|
||||
|
||||
private void foo() {
|
||||
if ( logger.isDebugEnabled() )
|
||||
logger.debug("Debug statement");
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
KO, missing guard
|
||||
]]></description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
private static final Logger logger = Logger.getLogger(Foo.class);
|
||||
|
||||
private void foo() {
|
||||
logger.debug("Debug statement");
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
</test-data>
|
||||
Reference in new issue
Block a user