LocalVariableCouldBeFinal and MethodArgumentCouldBeFinal use the same detection methods, refactoring

git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/trunk@4838 51baf565-9d33-0410-a72c-fc3788e3496d
This commit is contained in:
Xavier Le Vourch
2006-11-30 02:29:13 +00:00
parent f10997e29f
commit af4afaa78b
5 changed files with 38 additions and 162 deletions

View File

@ -10,7 +10,7 @@ These rules deal with different optimizations that generally apply to performanc
</description>
<rule name="LocalVariableCouldBeFinal"
message="Local variable could be declared final"
message="Local variable ''{0}'' could be declared final"
class="net.sourceforge.pmd.rules.optimization.LocalVariableCouldBeFinal"
externalInfoUrl="http://pmd.sourceforge.net/rules/optimizations.html#LocalVariableCouldBeFinal">
<description>

View File

@ -10,19 +10,8 @@ import java.util.List;
import net.sourceforge.pmd.AbstractRule;
import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.ast.ASTAssignmentOperator;
import net.sourceforge.pmd.ast.ASTExpression;
import net.sourceforge.pmd.ast.ASTLocalVariableDeclaration;
import net.sourceforge.pmd.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.ast.ASTName;
import net.sourceforge.pmd.ast.ASTPostfixExpression;
import net.sourceforge.pmd.ast.ASTPreDecrementExpression;
import net.sourceforge.pmd.ast.ASTPreIncrementExpression;
import net.sourceforge.pmd.ast.ASTPrimaryExpression;
import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
import net.sourceforge.pmd.ast.Node;
import net.sourceforge.pmd.ast.SimpleNode;
import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.symboltable.NameOccurrence;
/**
* Base class with utility methods for optimization rules
@ -31,109 +20,21 @@ import net.sourceforge.pmd.ast.SimpleNode;
*/
public class AbstractOptimizationRule extends AbstractRule implements Rule {
protected final boolean isVarWritterInMethod(String varName, ASTMethodDeclaration md) {
List assignments = md.findChildrenOfType(ASTAssignmentOperator.class);
return (variableAssigned(varName, assignments) || numericWithPrePost(md, varName));
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
if (node.isInterface()) {
return data;
}
return super.visit(node, data);
}
// TODO - symbol table?
protected final String getVarName(ASTLocalVariableDeclaration node) {
List l = node.findChildrenOfType(ASTVariableDeclaratorId.class);
if (!l.isEmpty()) {
ASTVariableDeclaratorId vd = (ASTVariableDeclaratorId) l.get(0);
return vd.getImage();
}
return null;
}
/**
* Check constructions like
* int i;
* ++i;
* --i;
* i++;
* i*=1;
* i+=1;
*/
private final boolean numericWithPrePost(ASTMethodDeclaration md, String varName) {
// ++i
List preinc = md.findChildrenOfType(ASTPreIncrementExpression.class);
if (preinc != null && !preinc.isEmpty()) {
for (Iterator it = preinc.iterator(); it.hasNext();) {
if (isName((Node)it.next(), varName)) {
return true;
}
}
}
// --i
List predec = md.findChildrenOfType(ASTPreDecrementExpression.class);
if (predec != null && !predec.isEmpty()) {
for (Iterator it = predec.iterator(); it.hasNext();) {
if (isName((Node)it.next(), varName)) {
return true;
}
}
}
List pf = md.findChildrenOfType(ASTPostfixExpression.class);
if (pf != null && !pf.isEmpty()) {
for (Iterator it = pf.iterator(); it.hasNext();) {
ASTPostfixExpression pe = (ASTPostfixExpression) it.next();
if ((pe.hasImageEqualTo("++") || pe.hasImageEqualTo("--"))) {
if (isName(pe, varName)) {
return true;
}
}
}
}
return false;
}
private final boolean isName(Node node, String varName) {
Node first = node.jjtGetChild(0);
Node second = first.jjtGetChild(0);
if (second.jjtGetNumChildren() == 0) {
return false;
}
Node third = second.jjtGetChild(0);
if (!(third instanceof ASTName)) {
if (first instanceof ASTPrimaryExpression) {
// deals with extra parenthesis:
// "(varName)++" instead of "varName++" for instance
if (first.jjtGetNumChildren() != 1) {
return false;
}
if (second instanceof ASTPrimaryPrefix && second.jjtGetNumChildren() == 1 &&
third instanceof ASTExpression && third.jjtGetNumChildren() == 1) {
return isName(third, varName);
}
}
return false;
}
ASTName name = (ASTName) third;
return name.hasImageEqualTo(varName);
}
private final boolean variableAssigned(final String varName, final List assignments) {
if (assignments == null || assignments.isEmpty()) {
return false;
}
for (Iterator it = assignments.iterator(); it.hasNext();) {
final ASTAssignmentOperator a = (ASTAssignmentOperator) it.next();
// if node is assigned return true
SimpleNode firstChild = (SimpleNode) a.jjtGetParent().jjtGetChild(0);
SimpleNode otherChild = (SimpleNode) firstChild.jjtGetChild(0);
if (otherChild.jjtGetNumChildren() == 0 || !(otherChild.jjtGetChild(0) instanceof ASTName)) {
continue;
}
ASTName n = (ASTName) otherChild.jjtGetChild(0);
if (n.hasImageEqualTo(varName)) {
protected boolean assigned(List usages) {
for (Iterator j = usages.iterator(); j.hasNext();) {
NameOccurrence occ = (NameOccurrence) j.next();
if (occ.isOnLeftHandSide() || occ.isSelfAssignment()) {
return true;
}
continue;
}
return false;
}

View File

@ -4,7 +4,6 @@
package net.sourceforge.pmd.rules.optimization;
import net.sourceforge.pmd.ast.ASTAllocationExpression;
import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.ast.ASTDoStatement;
import net.sourceforge.pmd.ast.ASTForStatement;
import net.sourceforge.pmd.ast.ASTReturnStatement;
@ -13,14 +12,6 @@ import net.sourceforge.pmd.ast.ASTWhileStatement;
public class AvoidInstantiatingObjectsInLoops extends AbstractOptimizationRule {
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
if (node.isInterface()) {
return data;
}
return super.visit(node, data);
}
public Object visit(ASTAllocationExpression node, Object data) {
if (insideLoop(node) && fourthParentNotThrow(node) && fourthParentNotReturn(node)) {
addViolation(data, node);

View File

@ -3,29 +3,30 @@
*/
package net.sourceforge.pmd.rules.optimization;
import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.sourceforge.pmd.ast.ASTLocalVariableDeclaration;
import net.sourceforge.pmd.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.symboltable.Scope;
import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
public class LocalVariableCouldBeFinal extends AbstractOptimizationRule {
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
if (node.isInterface()) {
return data;
}
return super.visit(node, data);
}
public Object visit(ASTLocalVariableDeclaration node, Object data) {
if (node.isFinal()) {
return data;
}
final String varName = getVarName(node);
ASTMethodDeclaration md = (ASTMethodDeclaration) node.getFirstParentOfType(ASTMethodDeclaration.class);
if (md != null) {
if (!isVarWritterInMethod(varName, md)) {
addViolation(data, node);
Scope s = node.getScope();
Map decls = s.getVariableDeclarations();
for (Iterator i = decls.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
VariableNameDeclaration var = (VariableNameDeclaration) entry.getKey();
if (var.getAccessNodeParent() != node) {
continue;
}
if (!assigned((List) entry.getValue())) {
addViolation(data, var.getAccessNodeParent(), var.getImage());
}
}
return data;

View File

@ -3,25 +3,17 @@
*/
package net.sourceforge.pmd.rules.optimization;
import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.ast.ASTFormalParameter;
import net.sourceforge.pmd.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.symboltable.NameOccurrence;
import net.sourceforge.pmd.symboltable.Scope;
import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class MethodArgumentCouldBeFinal extends AbstractOptimizationRule {
import net.sourceforge.pmd.ast.ASTFormalParameter;
import net.sourceforge.pmd.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.ast.AccessNode;
import net.sourceforge.pmd.symboltable.Scope;
import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
if (node.isInterface()) {
return data;
}
return super.visit(node, data);
}
public class MethodArgumentCouldBeFinal extends AbstractOptimizationRule {
public Object visit(ASTMethodDeclaration meth, Object data) {
if (meth.isNative() || meth.isAbstract()) {
@ -32,21 +24,12 @@ public class MethodArgumentCouldBeFinal extends AbstractOptimizationRule {
for (Iterator i = decls.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
VariableNameDeclaration var = (VariableNameDeclaration) entry.getKey();
if (!var.getAccessNodeParent().isFinal() && (var.getAccessNodeParent() instanceof ASTFormalParameter) && !assigned((List) entry.getValue())) {
addViolation(data, var.getAccessNodeParent(), var.getImage());
AccessNode node = var.getAccessNodeParent();
if (!node.isFinal() && (node instanceof ASTFormalParameter) && !assigned((List) entry.getValue())) {
addViolation(data, node, var.getImage());
}
}
return data;
}
private boolean assigned(List usages) {
for (Iterator j = usages.iterator(); j.hasNext();) {
NameOccurrence occ = (NameOccurrence) j.next();
if (occ.isOnLeftHandSide() || occ.isSelfAssignment()) {
return true;
}
continue;
}
return false;
}
}