/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd;
import net.sourceforge.pmd.ast.ASTCompilationUnit;
import net.sourceforge.pmd.ast.JavaParser;
import net.sourceforge.pmd.ast.ParseException;
import net.sourceforge.pmd.cpd.FileFinder;
import net.sourceforge.pmd.cpd.JavaLanguage;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.symboltable.SymbolFacade;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
public class PMD {
public static final String EOL = System.getProperty("line.separator", "\n");
private TargetJDKVersion targetJDKVersion;
public PMD() {
targetJDKVersion = new TargetJDK1_4();
}
public PMD(TargetJDKVersion targetJDKVersion) {
this.targetJDKVersion = targetJDKVersion;
}
/**
* @param reader - a Reader to the Java code to analyse
* @param ruleSet - the set of rules to process against the file
* @param ctx - the context in which PMD is operating. This contains the Renderer and whatnot
*/
public void processFile(Reader reader, RuleSet ruleSet, RuleContext ctx) throws PMDException {
try {
JavaParser parser = targetJDKVersion.createParser(reader);
ASTCompilationUnit c = parser.CompilationUnit();
Thread.yield();
SymbolFacade stb = new SymbolFacade();
stb.initializeWith(c);
List acus = new ArrayList();
acus.add(c);
ruleSet.apply(acus, ctx);
reader.close();
} catch (ParseException pe) {
throw new PMDException("Error while parsing " + ctx.getSourceCodeFilename(), pe);
} catch (Exception e) {
throw new PMDException("Error while processing " + ctx.getSourceCodeFilename(), e);
}
}
/**
* @param fileContents - an InputStream to the Java code to analyse
* @param encoding - the source code's character set encoding
* @param ruleSet - the set of rules to process against the file
* @param ctx - the context in which PMD is operating. This contains the Report and whatnot
*/
public void processFile(InputStream fileContents, String encoding, RuleSet ruleSet, RuleContext ctx) throws PMDException {
try {
processFile(new InputStreamReader(fileContents, encoding), ruleSet, ctx);
} catch (UnsupportedEncodingException uee) {
throw new PMDException("Unsupported encoding exception: " + uee.getMessage());
}
}
/**
* @param fileContents - an InputStream to the Java code to analyse
* @param ruleSet - the set of rules to process against the source code
* @param ctx - the context in which PMD is operating. This contains the Report and whatnot
*/
public void processFile(InputStream fileContents, RuleSet ruleSet, RuleContext ctx) throws PMDException {
processFile(fileContents, System.getProperty("file.encoding"), ruleSet, ctx);
}
public static void main(String[] args) {
CommandLineOptions opts = new CommandLineOptions(args);
List files;
if (opts.containsCommaSeparatedFileList()) {
files = collectFromCommaDelimitedString(opts.getInputFileName());
} else {
files = collectFilesFromOneName(opts.getInputFileName());
}
PMD pmd;
if (opts.jdk13()) {
pmd = new PMD(new TargetJDK1_3());
} else {
pmd = new PMD();
}
RuleContext ctx = new RuleContext();
ctx.setReport(new Report());
try {
RuleSetFactory ruleSetFactory = new RuleSetFactory();
RuleSet rules = ruleSetFactory.createRuleSet(opts.getRulesets());
for (Iterator i = files.iterator(); i.hasNext();) {
File file = (File) i.next();
ctx.setSourceCodeFilename(glomName(opts.shortNamesEnabled(), opts.getInputFileName(), file));
try {
pmd.processFile(new FileInputStream(file), opts.getEncoding(), rules, ctx);
} catch (PMDException pmde) {
if (opts.debugEnabled()) {
pmde.getReason().printStackTrace();
}
ctx.getReport().addError(new Report.ProcessingError(pmde.getMessage(), glomName(opts.shortNamesEnabled(), opts.getInputFileName(), file)));
}
}
} catch (FileNotFoundException fnfe) {
System.out.println(opts.usage());
fnfe.printStackTrace();
} catch (RuleSetNotFoundException rsnfe) {
System.out.println(opts.usage());
rsnfe.printStackTrace();
}
try {
Renderer r = opts.createRenderer();
System.out.println(r.render(ctx.getReport()));
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println(opts.usage());
if (opts.debugEnabled()) {
e.printStackTrace();
}
}
}
private static String glomName(boolean shortNames, String inputFileName, File file) {
if (shortNames && inputFileName.indexOf(',') == -1) {
if ((new File(inputFileName)).isDirectory()) {
return trimAnyPathSep(file.getAbsolutePath().substring(inputFileName.length()));
} else {
if (inputFileName.indexOf(System.getProperty("file.separator").charAt(0)) == -1) {
return inputFileName;
}
return trimAnyPathSep(inputFileName.substring(inputFileName.lastIndexOf(System.getProperty("file.separator"))));
}
} else {
return file.getAbsolutePath();
}
}
private static String trimAnyPathSep(String name) {
if (name.startsWith(System.getProperty("file.separator"))) {
name = name.substring(1);
}
return name;
}
private static List collectFilesFromOneName(String inputFileName) {
return collect(inputFileName);
}
private static List collectFromCommaDelimitedString(String fileList) {
List files = new ArrayList();
for (StringTokenizer st = new StringTokenizer(fileList, ","); st.hasMoreTokens();) {
files.addAll(collect(st.nextToken()));
}
return files;
}
private static List collect(String filename) {
File inputFile = new File(filename);
if (!inputFile.exists()) {
throw new RuntimeException("File " + inputFile.getName() + " doesn't exist");
}
List files;
if (!inputFile.isDirectory()) {
files = new ArrayList();
files.add(inputFile);
} else {
FileFinder finder = new FileFinder();
files = finder.findFilesFrom(inputFile.getAbsolutePath(), new JavaLanguage.JavaFileOrDirectoryFilter(), true);
}
return files;
}
}