*** empty log message ***
git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/trunk@16 51baf565-9d33-0410-a72c-fc3788e3496d
This commit is contained in:
parent
f8f1722140
commit
e65dfc8a04
@ -33,7 +33,7 @@ Runs a set of PMD rules on a set of files and generates a report.
|
||||
<h3>Examples</h3>
|
||||
<pre>
|
||||
<target name="pmd">
|
||||
<taskdef name="pmd" classname="com.infoether.pmd.PMDTask"/>
|
||||
<taskdef name="pmd" classname="net.sourceforge.pmd.PMDTask"/>
|
||||
<pmd reportFile="c:\foo.txt" verbose="false" rulesettype="general">
|
||||
<fileset dir="c:\j2sdk1.4.0\src\">
|
||||
<include name="**/*.java"/>
|
||||
|
@ -3,16 +3,16 @@
|
||||
* Date: Jun 17, 2002
|
||||
* Time: 3:19:33 PM
|
||||
*/
|
||||
package test.com.infoether.pmd;
|
||||
package test.net.sourceforge.pmd;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.infoether.pmd.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.sourceforge.pmd.*;
|
||||
|
||||
public class FunctionalTest extends TestCase{
|
||||
|
||||
public FunctionalTest(String name) {
|
@ -3,11 +3,11 @@
|
||||
* Date: Jun 21, 2002
|
||||
* Time: 2:21:44 PM
|
||||
*/
|
||||
package test.com.infoether.pmd;
|
||||
package test.net.sourceforge.pmd;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import com.infoether.pmd.Namespace;
|
||||
import com.infoether.pmd.SymbolTable;
|
||||
import net.sourceforge.pmd.Namespace;
|
||||
import net.sourceforge.pmd.SymbolTable;
|
||||
|
||||
public class NamespaceTest extends TestCase{
|
||||
public NamespaceTest(String name) {
|
@ -3,12 +3,12 @@
|
||||
* Date: Jun 14, 2002
|
||||
* Time: 1:18:30 PM
|
||||
*/
|
||||
package test.com.infoether.pmd;
|
||||
package test.net.sourceforge.pmd;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import com.infoether.pmd.Report;
|
||||
import com.infoether.pmd.RuleViolation;
|
||||
import com.infoether.pmd.Rule;
|
||||
import net.sourceforge.pmd.Report;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.Rule;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.InvocationHandler;
|
@ -3,16 +3,16 @@
|
||||
* Date: Jun 20, 2002
|
||||
* Time: 8:43:20 AM
|
||||
*/
|
||||
package test.com.infoether.pmd;
|
||||
package test.net.sourceforge.pmd;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.infoether.pmd.RuleFactory;
|
||||
import com.infoether.pmd.Rule;
|
||||
import com.infoether.pmd.DontCreateTimersRule;
|
||||
import com.infoether.pmd.EmptyIfStmtRule;
|
||||
import net.sourceforge.pmd.RuleFactory;
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.DontCreateTimersRule;
|
||||
import net.sourceforge.pmd.EmptyIfStmtRule;
|
||||
|
||||
public class RuleFactoryTest extends TestCase {
|
||||
public RuleFactoryTest(String name) {
|
@ -1,9 +1,11 @@
|
||||
package test.com.infoether.pmd;
|
||||
package test.net.sourceforge.pmd;
|
||||
|
||||
import junit.framework.*;
|
||||
import com.infoether.pmd.*;
|
||||
import java.util.*;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
|
||||
public class RuleViolationTest extends TestCase {
|
||||
public RuleViolationTest(String name) {
|
||||
super(name);
|
@ -3,11 +3,11 @@
|
||||
* Date: Jun 19, 2002
|
||||
* Time: 11:09:06 AM
|
||||
*/
|
||||
package test.com.infoether.pmd;
|
||||
package test.net.sourceforge.pmd;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import com.infoether.pmd.SymbolTable;
|
||||
import com.infoether.pmd.Symbol;
|
||||
import net.sourceforge.pmd.SymbolTable;
|
||||
import net.sourceforge.pmd.Symbol;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
@ -3,10 +3,10 @@
|
||||
* Date: Jun 19, 2002
|
||||
* Time: 11:59:24 AM
|
||||
*/
|
||||
package test.com.infoether.pmd;
|
||||
package test.net.sourceforge.pmd;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import com.infoether.pmd.Symbol;
|
||||
import net.sourceforge.pmd.Symbol;
|
||||
|
||||
public class SymbolTest extends TestCase {
|
||||
|
21
pmd/src/net/sourceforge/pmd/AbstractRule.java
Normal file
21
pmd/src/net/sourceforge/pmd/AbstractRule.java
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* User: tom
|
||||
* Date: Jun 17, 2002
|
||||
* Time: 5:44:22 PM
|
||||
*/
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import net.sourceforge.pmd.ast.JavaParserVisitorAdapter;
|
||||
|
||||
public abstract class AbstractRule extends JavaParserVisitorAdapter {
|
||||
public String getName() {return getClass().getName();}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
Rule r = (Rule)o;
|
||||
return r.getName().equals(getName());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return getName().hashCode();
|
||||
}
|
||||
}
|
20
pmd/src/net/sourceforge/pmd/DontCreateThreadsRule.java
Normal file
20
pmd/src/net/sourceforge/pmd/DontCreateThreadsRule.java
Normal file
@ -0,0 +1,20 @@
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import net.sourceforge.pmd.ast.JavaParserVisitorAdapter;
|
||||
import net.sourceforge.pmd.ast.ASTAllocationExpression;
|
||||
import net.sourceforge.pmd.ast.ASTName;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class DontCreateThreadsRule extends AbstractRule implements Rule {
|
||||
|
||||
public String getDescription() {return "Don't create threads, use the ThreadService instead";}
|
||||
|
||||
public Object visit(ASTAllocationExpression node, Object data){
|
||||
if ((node.jjtGetChild(0) instanceof ASTName) // this avoids "new <primitive-type>", i.e., "new int[]"
|
||||
&& ((ASTName)node.jjtGetChild(0)).getImage().equals("Thread")) {
|
||||
((Report)data).addRuleViolation(new RuleViolation(this, node.getBeginLine()));
|
||||
}
|
||||
return super.visit(node, data);
|
||||
}
|
||||
}
|
20
pmd/src/net/sourceforge/pmd/DontCreateTimersRule.java
Normal file
20
pmd/src/net/sourceforge/pmd/DontCreateTimersRule.java
Normal file
@ -0,0 +1,20 @@
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import net.sourceforge.pmd.ast.JavaParserVisitorAdapter;
|
||||
import net.sourceforge.pmd.ast.ASTAllocationExpression;
|
||||
import net.sourceforge.pmd.ast.ASTName;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class DontCreateTimersRule extends AbstractRule implements Rule {
|
||||
|
||||
public String getDescription() {return "Don't create java.util.Timers, use the Cougaar alarm service instead";}
|
||||
|
||||
public Object visit(ASTAllocationExpression node, Object data){
|
||||
if ((node.jjtGetChild(0) instanceof ASTName) // this avoids "new <primitive-type>", i.e., "new int[]"
|
||||
&& ((ASTName)node.jjtGetChild(0)).getImage().equals("Timer")) {
|
||||
((Report)data).addRuleViolation(new RuleViolation(this, node.getBeginLine()));
|
||||
}
|
||||
return super.visit(node, data);
|
||||
}
|
||||
}
|
22
pmd/src/net/sourceforge/pmd/EmptyCatchBlockRule.java
Normal file
22
pmd/src/net/sourceforge/pmd/EmptyCatchBlockRule.java
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* User: tom
|
||||
* Date: Jun 14, 2002
|
||||
* Time: 12:13:55 PM
|
||||
*/
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import net.sourceforge.pmd.ast.ASTBlock;
|
||||
import net.sourceforge.pmd.ast.ASTTryStatement;
|
||||
|
||||
public class EmptyCatchBlockRule extends AbstractRule implements Rule {
|
||||
|
||||
public String getDescription() {return "Avoid empty catch blocks";}
|
||||
|
||||
public Object visit(ASTBlock node, Object data){
|
||||
if ((node.jjtGetParent() instanceof ASTTryStatement) && node.jjtGetNumChildren()==0) {
|
||||
((Report)data).addRuleViolation(new RuleViolation(this, node.getBeginLine()));
|
||||
}
|
||||
|
||||
return super.visit(node, data);
|
||||
}
|
||||
}
|
23
pmd/src/net/sourceforge/pmd/EmptyIfStmtRule.java
Normal file
23
pmd/src/net/sourceforge/pmd/EmptyIfStmtRule.java
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* User: tom
|
||||
* Date: Jun 17, 2002
|
||||
* Time: 4:23:30 PM
|
||||
*/
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import net.sourceforge.pmd.ast.JavaParserVisitorAdapter;
|
||||
import net.sourceforge.pmd.ast.ASTBlock;
|
||||
import net.sourceforge.pmd.ast.ASTTryStatement;
|
||||
import net.sourceforge.pmd.ast.ASTIfStatement;
|
||||
|
||||
public class EmptyIfStmtRule extends AbstractRule implements Rule {
|
||||
public String getDescription() {return "Avoid empty IF statements";}
|
||||
|
||||
public Object visit(ASTBlock node, Object data){
|
||||
if ((node.jjtGetParent().jjtGetParent() instanceof ASTIfStatement) && node.jjtGetNumChildren()==0) {
|
||||
((Report)data).addRuleViolation(new RuleViolation(this, node.getBeginLine()));
|
||||
}
|
||||
|
||||
return super.visit(node, data);
|
||||
}
|
||||
}
|
63
pmd/src/net/sourceforge/pmd/Namespace.java
Normal file
63
pmd/src/net/sourceforge/pmd/Namespace.java
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* User: tom
|
||||
* Date: Jun 21, 2002
|
||||
* Time: 2:11:15 PM
|
||||
*/
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Here's the problem:
|
||||
*
|
||||
* public class Outer
|
||||
* {
|
||||
* private String foo;
|
||||
* public void foo() {
|
||||
* bar(new Runnable() {public void run() {String foo;}});
|
||||
* }
|
||||
* private void bar(Runnable r) {}
|
||||
* }
|
||||
*
|
||||
* In this example, Outer.foo and the Runnable.foo are two different variables - even though
|
||||
* Runnable.foo looks like its inside Outer, they don't conflict.
|
||||
*
|
||||
* So, a couple of SymbolTables are grouped into a Namespace. SymbolTables are grouped so that inner classes have their own
|
||||
* "group" of symbol tables. So a class with an inner class would look like this:
|
||||
*
|
||||
* ST
|
||||
* ST
|
||||
* NS2
|
||||
* ST ST ST
|
||||
* ST ST ST
|
||||
* NS1 NS1 NS1
|
||||
*
|
||||
* That way the scopes work out nicely and inner classes can be arbitrarily nested.
|
||||
*/
|
||||
public class Namespace {
|
||||
|
||||
private Stack tables = new Stack();
|
||||
|
||||
public void addTable() {
|
||||
if (tables.empty()) {
|
||||
tables.push(new SymbolTable());
|
||||
} else {
|
||||
tables.push(new SymbolTable((SymbolTable)tables.peek()));
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTable() {
|
||||
tables.pop();
|
||||
}
|
||||
|
||||
public SymbolTable peek() {
|
||||
return (SymbolTable)tables.peek();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return tables.size();
|
||||
}
|
||||
|
||||
}
|
65
pmd/src/net/sourceforge/pmd/PMD.java
Normal file
65
pmd/src/net/sourceforge/pmd/PMD.java
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* User: tom
|
||||
* Date: Jun 17, 2002
|
||||
* Time: 3:23:17 PM
|
||||
*/
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import net.sourceforge.pmd.ast.JavaParser;
|
||||
import net.sourceforge.pmd.ast.ASTCompilationUnit;
|
||||
import net.sourceforge.pmd.ast.JavaParserVisitor;
|
||||
import net.sourceforge.pmd.ast.ParseException;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class PMD {
|
||||
|
||||
public Report processFile(InputStream is) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Report processFile(FileReader fr) {
|
||||
return null; }
|
||||
|
||||
public Report processFile(File file, String ruleSetType) {
|
||||
Report report = new Report(file.getAbsolutePath());
|
||||
List rules = RuleFactory.createRules(ruleSetType);
|
||||
|
||||
try {
|
||||
Reader reader = new BufferedReader(new FileReader(file));
|
||||
JavaParser parser = new JavaParser(reader);
|
||||
ASTCompilationUnit c = parser.CompilationUnit();
|
||||
//c.dump("");
|
||||
for (Iterator iterator = rules.iterator(); iterator.hasNext();) {
|
||||
JavaParserVisitor rule = (JavaParserVisitor)iterator.next();
|
||||
c.childrenAccept(rule, report);
|
||||
}
|
||||
reader.close();
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
fnfe.printStackTrace();
|
||||
} catch (ParseException pe) {
|
||||
System.out.println("Error while parsing " + file.getAbsolutePath() + " at line " + pe.currentToken.beginLine + "; continuing...");
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
} catch (Throwable t) {
|
||||
System.out.println("Error while parsing " + file.getAbsolutePath() + "; "+ t.getMessage() + "; continuing...");
|
||||
//t.printStackTrace();
|
||||
}
|
||||
return report;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (args.length == 0) {
|
||||
throw new RuntimeException("Pass a filename in");
|
||||
}
|
||||
File input = new File(args[0]);
|
||||
if (!input.exists()) {
|
||||
throw new RuntimeException("File " + args[0] + " doesn't exist");
|
||||
}
|
||||
PMD pmd = new PMD();
|
||||
Report report = pmd.processFile(input, RuleFactory.ALL);
|
||||
System.out.println(report.renderToText());
|
||||
}
|
||||
}
|
68
pmd/src/net/sourceforge/pmd/PMDTask.java
Normal file
68
pmd/src/net/sourceforge/pmd/PMDTask.java
Normal file
@ -0,0 +1,68 @@
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import org.apache.tools.ant.*;
|
||||
import org.apache.tools.ant.types.*;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
import net.sourceforge.pmd.ast.JavaParser;
|
||||
import net.sourceforge.pmd.ast.JavaParserVisitor;
|
||||
import net.sourceforge.pmd.ast.ParseException;
|
||||
import net.sourceforge.pmd.ast.ASTCompilationUnit;
|
||||
|
||||
public class PMDTask extends Task {
|
||||
|
||||
private List filesets = new ArrayList();
|
||||
private String reportFile;
|
||||
private boolean verbose;
|
||||
private String ruleSetType;
|
||||
|
||||
public void setVerbose(boolean verbose) {
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
public void setRuleSetType(String ruleSetType) {
|
||||
this.ruleSetType = ruleSetType;
|
||||
}
|
||||
|
||||
public void addFileset(FileSet set) {
|
||||
filesets.add(set);
|
||||
}
|
||||
|
||||
public void setReportFile(String reportFile) {
|
||||
this.reportFile = reportFile;
|
||||
}
|
||||
|
||||
public void execute() throws BuildException {
|
||||
if (reportFile == null) {
|
||||
throw new BuildException("No report file specified");
|
||||
}
|
||||
if (ruleSetType == null) {
|
||||
throw new BuildException("No rule set type specified");
|
||||
}
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (Iterator i = filesets.iterator(); i.hasNext();) {
|
||||
FileSet fs = (FileSet) i.next();
|
||||
DirectoryScanner ds = fs.getDirectoryScanner(project);
|
||||
String[] srcFiles = ds.getIncludedFiles();
|
||||
for (int j=0; j<srcFiles.length; j++) {
|
||||
File file = new File(ds.getBasedir() + System.getProperty("file.separator") + srcFiles[j]);
|
||||
if (verbose) System.out.println(file.getAbsoluteFile());
|
||||
PMD pmd = new PMD();
|
||||
Report report = pmd.processFile(file, ruleSetType);
|
||||
if (!report.empty()) {
|
||||
buf.append(report.renderToText());
|
||||
buf.append(System.getProperty("line.separator"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(reportFile)));
|
||||
writer.write(buf.toString(), 0, buf.length());
|
||||
writer.close();
|
||||
} catch (IOException ioe) {
|
||||
throw new BuildException(ioe.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
40
pmd/src/net/sourceforge/pmd/Report.java
Normal file
40
pmd/src/net/sourceforge/pmd/Report.java
Normal file
@ -0,0 +1,40 @@
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Report {
|
||||
|
||||
private List violations = new ArrayList();
|
||||
private String filename;
|
||||
|
||||
public Report(String filename) {
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public void addRuleViolation(RuleViolation violation) {
|
||||
violations.add(violation);
|
||||
}
|
||||
|
||||
public String renderToText() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (Iterator i = violations.iterator(); i.hasNext();) {
|
||||
if (buf.length() != 0) {
|
||||
buf.append(System.getProperty("line.separator"));
|
||||
}
|
||||
buf.append(filename + ":" + ((RuleViolation)i.next()).getText());
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public boolean empty() {
|
||||
return violations.size() == 0;
|
||||
}
|
||||
|
||||
public Iterator iterator() {
|
||||
return violations.iterator();
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return violations.size();
|
||||
}
|
||||
}
|
8
pmd/src/net/sourceforge/pmd/Rule.java
Normal file
8
pmd/src/net/sourceforge/pmd/Rule.java
Normal file
@ -0,0 +1,8 @@
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public interface Rule {
|
||||
public String getName();
|
||||
public String getDescription();
|
||||
}
|
55
pmd/src/net/sourceforge/pmd/RuleFactory.java
Normal file
55
pmd/src/net/sourceforge/pmd/RuleFactory.java
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* User: tom
|
||||
* Date: Jun 10, 2002
|
||||
* Time: 11:27:51 AM
|
||||
*/
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class RuleFactory {
|
||||
|
||||
public static final String ALL = "all";
|
||||
public static final String GENERAL = "general";
|
||||
public static final String COUGAAR = "cougaar";
|
||||
|
||||
public static List createRules(String ruleSetType) {
|
||||
if (ruleSetType.equals(ALL)) {
|
||||
return createAllRules();
|
||||
} else if (ruleSetType.equals(GENERAL)) {
|
||||
return createGeneralRules();
|
||||
} else if (ruleSetType.equals(COUGAAR)) {
|
||||
return createCougaarRules();
|
||||
}
|
||||
throw new RuntimeException("Unknown rule set type " + ruleSetType);
|
||||
}
|
||||
|
||||
private static List createAllRules() {
|
||||
List list = new ArrayList();
|
||||
list.addAll(createCougaarRules());
|
||||
list.addAll(createGeneralRules());
|
||||
return list;
|
||||
}
|
||||
|
||||
private static List createCougaarRules() {
|
||||
List list = new ArrayList();
|
||||
list.add(new DontCreateThreadsRule());
|
||||
list.add(new DontCreateTimersRule());
|
||||
list.add(new SystemOutRule());
|
||||
list.add(new SystemPropsRule());
|
||||
return list;
|
||||
}
|
||||
|
||||
private static List createGeneralRules() {
|
||||
List list = new ArrayList();
|
||||
list.add(new EmptyCatchBlockRule());
|
||||
list.add(new EmptyIfStmtRule());
|
||||
list.add(new UnnecessaryConversionTemporaryRule());
|
||||
list.add(new UnusedLocalVariableRule());
|
||||
//list.add(new UnusedPrivateInstanceVariableRule());
|
||||
return list;
|
||||
}
|
||||
}
|
27
pmd/src/net/sourceforge/pmd/RuleViolation.java
Normal file
27
pmd/src/net/sourceforge/pmd/RuleViolation.java
Normal file
@ -0,0 +1,27 @@
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
|
||||
public class RuleViolation {
|
||||
|
||||
private int line;
|
||||
private Rule rule;
|
||||
private String specificDescription;
|
||||
|
||||
public RuleViolation(Rule rule, int line) {
|
||||
this(rule, line, rule.getDescription());
|
||||
}
|
||||
|
||||
public RuleViolation(Rule rule, int line, String specificDescription) {
|
||||
this.line = line;
|
||||
this.rule = rule;
|
||||
this.specificDescription = specificDescription;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return rule.getName() +":" + specificDescription + ":" + line;
|
||||
}
|
||||
|
||||
public Rule getRule() {
|
||||
return rule;
|
||||
}
|
||||
}
|
38
pmd/src/net/sourceforge/pmd/Symbol.java
Normal file
38
pmd/src/net/sourceforge/pmd/Symbol.java
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* User: tom
|
||||
* Date: Jun 19, 2002
|
||||
* Time: 11:48:50 AM
|
||||
*/
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
public class Symbol {
|
||||
|
||||
private String image;
|
||||
private int line;
|
||||
|
||||
public Symbol(String image, int line) {
|
||||
this.image = image;
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public String getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
Symbol s = (Symbol)o;
|
||||
return s.image.equals(this.image);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return image.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return image + ":" + line;
|
||||
}
|
||||
}
|
83
pmd/src/net/sourceforge/pmd/SymbolTable.java
Normal file
83
pmd/src/net/sourceforge/pmd/SymbolTable.java
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* User: tom
|
||||
* Date: Jun 19, 2002
|
||||
* Time: 9:31:16 AM
|
||||
*/
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class SymbolTable {
|
||||
|
||||
private SymbolTable parent;
|
||||
private HashMap usageCounts = new HashMap();
|
||||
|
||||
public SymbolTable() {}
|
||||
|
||||
public SymbolTable(SymbolTable parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public SymbolTable getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void add(Symbol symbol) {
|
||||
if (usageCounts.containsKey(symbol)) {
|
||||
throw new RuntimeException(symbol + " is already in the symbol table");
|
||||
}
|
||||
if (parent != null && parent.contains(symbol)) {
|
||||
throw new RuntimeException(symbol + " is already in the parent symbol table");
|
||||
}
|
||||
usageCounts.put(symbol, new Integer(0));
|
||||
}
|
||||
|
||||
public void recordPossibleUsageOf(Symbol symbol) {
|
||||
if (!usageCounts.containsKey(symbol) && parent != null) {
|
||||
parent.recordPossibleUsageOf(symbol);
|
||||
return;
|
||||
}
|
||||
if (!usageCounts.containsKey(symbol) ) {
|
||||
return;
|
||||
}
|
||||
Integer usageCount = (Integer)usageCounts.get(symbol);
|
||||
usageCount = new Integer(usageCount.intValue() + 1);
|
||||
usageCounts.put(symbol, usageCount);
|
||||
}
|
||||
|
||||
public Iterator getUnusedSymbols() {
|
||||
List list = new ArrayList();
|
||||
for (Iterator i = usageCounts.keySet().iterator(); i.hasNext();) {
|
||||
Symbol symbol = (Symbol)i.next();
|
||||
int usageCount = ((Integer)(usageCounts.get(symbol))).intValue();
|
||||
if (usageCount == 0) {
|
||||
list.add(symbol);
|
||||
}
|
||||
}
|
||||
return list.iterator();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (Iterator i = usageCounts.keySet().iterator(); i.hasNext();) {
|
||||
Symbol symbol = (Symbol)i.next();
|
||||
int usageCount = ((Integer)(usageCounts.get(symbol))).intValue();
|
||||
buf.append(symbol + "," + usageCount +":");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
protected boolean contains(Symbol symbol) {
|
||||
if (usageCounts.containsKey(symbol)) {
|
||||
return true;
|
||||
}
|
||||
if (parent == null) {
|
||||
return false;
|
||||
}
|
||||
return parent.contains(symbol);
|
||||
}
|
||||
|
||||
}
|
18
pmd/src/net/sourceforge/pmd/SystemOutRule.java
Normal file
18
pmd/src/net/sourceforge/pmd/SystemOutRule.java
Normal file
@ -0,0 +1,18 @@
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import net.sourceforge.pmd.ast.JavaParserVisitorAdapter;
|
||||
import net.sourceforge.pmd.ast.ASTName;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class SystemOutRule extends AbstractRule implements Rule {
|
||||
|
||||
public String getDescription() {return "Don't use System.out/in/err, use the Cougaar logging service instead";}
|
||||
|
||||
public Object visit(ASTName node, Object data){
|
||||
if (node.getImage() != null && (node.getImage().startsWith("System.out") || node.getImage().startsWith("System.err") || node.getImage().startsWith("System.in"))) {
|
||||
((Report)data).addRuleViolation(new RuleViolation(this, node.getBeginLine()));
|
||||
}
|
||||
return super.visit(node,data);
|
||||
}
|
||||
}
|
19
pmd/src/net/sourceforge/pmd/SystemPropsRule.java
Normal file
19
pmd/src/net/sourceforge/pmd/SystemPropsRule.java
Normal file
@ -0,0 +1,19 @@
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import net.sourceforge.pmd.ast.ASTName;
|
||||
import net.sourceforge.pmd.ast.JavaParserVisitorAdapter;
|
||||
import net.sourceforge.pmd.ast.SimpleNode;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class SystemPropsRule extends AbstractRule implements Rule {
|
||||
|
||||
public String getDescription() {return "Don't use System.getProperty()/getProperties()/setProperty";}
|
||||
|
||||
public Object visit(ASTName node, Object data){
|
||||
if (node.getImage() != null && (node.getImage().startsWith("System.getProperty") || node.getImage().startsWith("System.setProperty") || node.getImage().startsWith("System.getProperties"))) {
|
||||
((Report)data).addRuleViolation(new RuleViolation(this, node.getBeginLine()));
|
||||
}
|
||||
return super.visit(node,data);
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* User: tom
|
||||
* Date: Jun 20, 2002
|
||||
* Time: 1:35:27 PM
|
||||
*/
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import net.sourceforge.pmd.ast.*;
|
||||
|
||||
public class UnnecessaryConversionTemporaryRule extends AbstractRule implements Rule{
|
||||
|
||||
private boolean inPrimaryExpressionContext;
|
||||
private boolean usingPrimitiveWrapperAllocation;
|
||||
|
||||
public String getDescription() {
|
||||
return "Avoid unnecessay temporaries when converting primitives to Strings";
|
||||
}
|
||||
|
||||
public Object visit(ASTPrimaryExpression node, Object data) {
|
||||
if (node.jjtGetNumChildren() == 0 || ((SimpleNode)node.jjtGetChild(0)).jjtGetNumChildren() == 0 || !(node.jjtGetChild(0).jjtGetChild(0) instanceof ASTAllocationExpression)) {
|
||||
return super.visit(node, data);
|
||||
}
|
||||
inPrimaryExpressionContext = true;
|
||||
Object report = super.visit(node, data);
|
||||
inPrimaryExpressionContext = false;
|
||||
usingPrimitiveWrapperAllocation = false;
|
||||
return report;
|
||||
}
|
||||
|
||||
public Object visit(ASTAllocationExpression node, Object data) {
|
||||
if (!inPrimaryExpressionContext) {
|
||||
return super.visit(node, data);
|
||||
}
|
||||
if (!(node.jjtGetChild(0) instanceof ASTName)) {
|
||||
return super.visit(node, data);
|
||||
}
|
||||
SimpleNode child = (SimpleNode)node.jjtGetChild(0);
|
||||
if (!isPrimitiveWrapperType(child.getImage())) {
|
||||
return super.visit(node, data);
|
||||
}
|
||||
usingPrimitiveWrapperAllocation = true;
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
||||
public Object visit(ASTPrimarySuffix node, Object data) {
|
||||
if (!inPrimaryExpressionContext || !usingPrimitiveWrapperAllocation) {
|
||||
return super.visit(node, data);
|
||||
}
|
||||
if (node.getImage() != null && node.getImage().equals("toString")) {
|
||||
((Report)data).addRuleViolation(new RuleViolation(this, node.getBeginLine()));
|
||||
}
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
||||
private boolean isPrimitiveWrapperType(String name) {
|
||||
return name.equals("Integer") || name.equals("Boolean") || name.equals("Double") || name.equals("Long") || name.equals("Short") || name.equals("Byte") || name.equals("Float");
|
||||
}
|
||||
}
|
80
pmd/src/net/sourceforge/pmd/UnusedLocalVariableRule.java
Normal file
80
pmd/src/net/sourceforge/pmd/UnusedLocalVariableRule.java
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* User: tom
|
||||
* Date: Jun 18, 2002
|
||||
* Time: 11:02:09 AM
|
||||
*/
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Stack;
|
||||
|
||||
import net.sourceforge.pmd.ast.*;
|
||||
|
||||
public class UnusedLocalVariableRule extends AbstractRule implements Rule{
|
||||
|
||||
private Stack tableGroups = new Stack();
|
||||
|
||||
public String getDescription() {
|
||||
return "Avoid unused local variables";
|
||||
}
|
||||
|
||||
public Object createGroup(SimpleNode node, Object data) {
|
||||
tableGroups.push(new Namespace());
|
||||
Object report = super.visit(node, data);
|
||||
tableGroups.pop();
|
||||
return report;
|
||||
}
|
||||
|
||||
// these AST types trigger creation of a new symbol table group
|
||||
public Object visit(ASTClassBody node, Object data) {return createGroup(node, data);}
|
||||
public Object visit(ASTInterfaceDeclaration node, Object data) {return createGroup(node, data);}
|
||||
// these AST types trigger creation of a new symbol table group
|
||||
|
||||
// these AST types trigger creation of a new symbol table
|
||||
public Object visit(ASTBlock node, Object data){return addTable(node, data);}
|
||||
public Object visit(ASTConstructorDeclaration node, Object data){return addTable(node, data);}
|
||||
public Object visit(ASTMethodDeclaration node, Object data){return addTable(node, data);}
|
||||
public Object visit(ASTFieldDeclaration node, Object data){return addTable(node, data);}
|
||||
public Object visit(ASTTryStatement node, Object data){return addTable(node, data);}
|
||||
public Object visit(ASTForStatement node, Object data){return addTable(node, data);}
|
||||
// these AST types trigger creation of a new symbol table
|
||||
|
||||
// these AST types are variable/name usages
|
||||
public Object visit(ASTVariableDeclaratorId node, Object data) {
|
||||
//System.out.println("ASTVariableDeclaratorId.getImage() = " + node.getImage());
|
||||
if (!(node.jjtGetParent().jjtGetParent() instanceof ASTLocalVariableDeclaration)) {
|
||||
return super.visit(node, data);
|
||||
}
|
||||
Namespace group = (Namespace)tableGroups.peek();
|
||||
group.peek().add(new Symbol(node.getImage(), node.getBeginLine()));
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
||||
public Object visit(ASTName node, Object data) {
|
||||
//System.out.println("ASTName.getImage() = " + node.getImage() + "; " + node.getBeginLine());
|
||||
if (node.jjtGetParent() instanceof ASTPrimaryPrefix) {
|
||||
String img = (node.getImage().indexOf('.') == -1) ? node.getImage() : node.getImage().substring(0, node.getImage().indexOf('.'));
|
||||
Namespace group = (Namespace)tableGroups.peek();
|
||||
group.peek().recordPossibleUsageOf(new Symbol(img, node.getBeginLine()));
|
||||
}
|
||||
return super.visit(node, data);
|
||||
}
|
||||
// these AST types are variable/name usages
|
||||
|
||||
private void reportUnusedLocals(Report report, SymbolTable table) {
|
||||
for (Iterator i = table.getUnusedSymbols(); i.hasNext();) {
|
||||
Symbol symbol = (Symbol)i.next();
|
||||
report.addRuleViolation(new RuleViolation(this, symbol.getLine(), "Found unused local variable '" + symbol.getImage() + "'"));
|
||||
}
|
||||
}
|
||||
|
||||
private Object addTable(SimpleNode node, Object data) {
|
||||
Namespace group = (Namespace)tableGroups.peek();
|
||||
group.addTable();
|
||||
Object RC = super.visit(node, data);
|
||||
reportUnusedLocals((Report)data, group.peek());
|
||||
group.removeTable();
|
||||
return RC;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* User: tom
|
||||
* Date: Jun 21, 2002
|
||||
* Time: 11:26:34 AM
|
||||
*/
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Stack;
|
||||
|
||||
import net.sourceforge.pmd.ast.*;
|
||||
|
||||
public class UnusedPrivateInstanceVariableRule extends AbstractRule implements Rule {
|
||||
|
||||
private Stack nameSpaces = new Stack();
|
||||
// TODO
|
||||
// this being an instance variable totally hoses up the recursion
|
||||
// need to attach it to the report or the stack or something
|
||||
// TODO
|
||||
private boolean doingIDTraversal;
|
||||
|
||||
public String getDescription() {
|
||||
return "Avoid unused private instance variables";
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip interfaces because they don't have instance variables.
|
||||
*/
|
||||
public Object visit(ASTInterfaceDeclaration node, Object data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
public Object visit(ASTClassBody node, Object data) {
|
||||
doingIDTraversal = true;
|
||||
Namespace nameSpace = new Namespace();
|
||||
nameSpaces.push(nameSpace);
|
||||
nameSpace.addTable();
|
||||
Object report = super.visit(node, data);
|
||||
|
||||
doingIDTraversal = false;
|
||||
//System.out.println("data = " + data);
|
||||
report = super.visit(node, data);
|
||||
reportUnusedInstanceVars((Report)report, nameSpace.peek());
|
||||
|
||||
nameSpace.removeTable();
|
||||
nameSpaces.pop();
|
||||
return report;
|
||||
}
|
||||
|
||||
public Object visit(ASTVariableDeclaratorId node, Object data) {
|
||||
if (!doingIDTraversal) {
|
||||
return super.visit(node, data);
|
||||
}
|
||||
//System.out.println("ASTVariableDeclaratorId.getImage() = " + node.getImage() + "; " + node.getBeginLine());
|
||||
SimpleNode grandparent = (SimpleNode)node.jjtGetParent().jjtGetParent();
|
||||
if (!(grandparent instanceof ASTFieldDeclaration) || grandparent.getImage().indexOf("private") == -1 || grandparent.getImage().indexOf("static") != -1) {
|
||||
return super.visit(node, data);
|
||||
}
|
||||
Namespace group = (Namespace)nameSpaces.peek();
|
||||
group.peek().add(new Symbol(node.getImage(), node.getBeginLine()));
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
||||
public Object visit(ASTPrimarySuffix node, Object data) {
|
||||
if (!doingIDTraversal && (node.jjtGetParent() instanceof ASTPrimaryExpression) && (node.getImage() != null)) {
|
||||
recordPossibleUsage(node, data);
|
||||
}
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
||||
public Object visit(ASTName node, Object data) {
|
||||
if (!doingIDTraversal && (node.jjtGetParent() instanceof ASTPrimaryPrefix)) {
|
||||
recordPossibleUsage(node, data);
|
||||
}
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
||||
private void recordPossibleUsage(SimpleNode node, Object data) {
|
||||
String img = (node.getImage().indexOf('.') == -1) ? node.getImage() : node.getImage().substring(0, node.getImage().indexOf('.'));
|
||||
Namespace group = (Namespace)nameSpaces.peek();
|
||||
group.peek().recordPossibleUsageOf(new Symbol(img, node.getBeginLine()));
|
||||
}
|
||||
|
||||
private void reportUnusedInstanceVars(Report report, SymbolTable table) {
|
||||
for (Iterator i = table.getUnusedSymbols(); i.hasNext();) {
|
||||
Symbol symbol = (Symbol)i.next();
|
||||
report.addRuleViolation(new RuleViolation(this, symbol.getLine(), "Found unused private instance variable '" + symbol.getImage() + "'"));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
/* Generated By:JJTree: Do not edit this line. ASTAdditiveExpression.java */
|
||||
|
||||
package com.infoether.pmd.ast;
|
||||
package net.sourceforge.pmd.ast;
|
||||
|
||||
|
||||
public class ASTAdditiveExpression extends SimpleNode {
|
||||
public ASTAdditiveExpression(int id) {
|
@ -1,6 +1,7 @@
|
||||
/* Generated By:JJTree: Do not edit this line. ASTAllocationExpression.java */
|
||||
|
||||
package com.infoether.pmd.ast;
|
||||
package net.sourceforge.pmd.ast;
|
||||
|
||||
|
||||
public class ASTAllocationExpression extends SimpleNode {
|
||||
public ASTAllocationExpression(int id) {
|
@ -1,6 +1,7 @@
|
||||
/* Generated By:JJTree: Do not edit this line. ASTAndExpression.java */
|
||||
|
||||
package com.infoether.pmd.ast;
|
||||
package net.sourceforge.pmd.ast;
|
||||
|
||||
|
||||
public class ASTAndExpression extends SimpleNode {
|
||||
public ASTAndExpression(int id) {
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user