Clover coverage report - PMD - 3.9
Coverage timestamp: Tue Dec 19 2006 09:38:44 EST
file stats: LOC: 592   Methods: 25
NCLOC: 393   Classes: 4
 
 Source file Conditionals Statements Methods TOTAL
PMD.java 7.6% 14.6% 28% 14.1%
coverage coverage
 1    /**
 2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
 3    */
 4    package net.sourceforge.pmd;
 5   
 6    import net.sourceforge.pmd.ast.ParseException;
 7    import net.sourceforge.pmd.cpd.FileFinder;
 8    import net.sourceforge.pmd.cpd.SourceFileOrDirectoryFilter;
 9    import net.sourceforge.pmd.parsers.Parser;
 10    import net.sourceforge.pmd.renderers.Renderer;
 11    import net.sourceforge.pmd.sourcetypehandlers.SourceTypeHandler;
 12    import net.sourceforge.pmd.sourcetypehandlers.SourceTypeHandlerBroker;
 13   
 14    import java.io.BufferedInputStream;
 15    import java.io.BufferedWriter;
 16    import java.io.File;
 17    import java.io.FileWriter;
 18    import java.io.IOException;
 19    import java.io.InputStream;
 20    import java.io.InputStreamReader;
 21    import java.io.OutputStreamWriter;
 22    import java.io.Reader;
 23    import java.io.UnsupportedEncodingException;
 24    import java.io.Writer;
 25    import java.util.ArrayList;
 26    import java.util.Enumeration;
 27    import java.util.Iterator;
 28    import java.util.LinkedList;
 29    import java.util.List;
 30    import java.util.StringTokenizer;
 31    import edu.emory.mathcs.backport.java.util.concurrent.ExecutorService;
 32    import edu.emory.mathcs.backport.java.util.concurrent.Executors;
 33    import edu.emory.mathcs.backport.java.util.concurrent.ThreadFactory;
 34    import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
 35    import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicInteger;
 36    import edu.emory.mathcs.backport.java.util.Collections;
 37    import java.util.zip.ZipEntry;
 38    import java.util.zip.ZipFile;
 39   
 40    public class PMD {
 41    public static final String EOL = System.getProperty("line.separator", "\n");
 42    public static final String VERSION = "3.9";
 43    public static final String EXCLUDE_MARKER = "NOPMD";
 44   
 45   
 46    private String excludeMarker = EXCLUDE_MARKER;
 47    private SourceTypeDiscoverer sourceTypeDiscoverer = new SourceTypeDiscoverer();
 48   
 49  1260 public PMD() {}
 50   
 51    /**
 52    * Processes the file read by the reader agains the rule set.
 53    *
 54    * @param reader input stream reader
 55    * @param ruleSets set of rules to process against the file
 56    * @param ctx context in which PMD is operating. This contains the Renderer and
 57    * whatnot
 58    * @throws PMDException if the input could not be parsed or processed
 59    */
 60  3 public void processFile(Reader reader, RuleSets ruleSets, RuleContext ctx)
 61    throws PMDException {
 62  3 SourceType sourceType = getSourceTypeOfFile(ctx.getSourceCodeFilename());
 63   
 64  3 processFile(reader, ruleSets, ctx, sourceType);
 65    }
 66   
 67    /**
 68    * Processes the file read by the reader against the rule set.
 69    *
 70    * @param reader input stream reader
 71    * @param ruleSets set of rules to process against the file
 72    * @param ctx context in which PMD is operating. This contains the Renderer and
 73    * whatnot
 74    * @param sourceType the SourceType of the source
 75    * @throws PMDException if the input could not be parsed or processed
 76    */
 77  1260 public void processFile(Reader reader, RuleSets ruleSets, RuleContext ctx,
 78    SourceType sourceType) throws PMDException {
 79  1260 try {
 80  1260 SourceTypeHandler sourceTypeHandler = SourceTypeHandlerBroker.getVisitorsFactoryForSourceType(sourceType);
 81  1260 ctx.setSourceType(sourceType);
 82  1260 Parser parser = sourceTypeHandler.getParser();
 83  1260 parser.setExcludeMarker(excludeMarker);
 84  1260 Object rootNode = parser.parse(reader);
 85  1260 ctx.excludeLines(parser.getExcludeMap());
 86  1260 Thread.yield();
 87  1260 sourceTypeHandler.getSymbolFacade().start(rootNode);
 88   
 89  1260 Language language = SourceTypeToRuleLanguageMapper.getMappedLanguage(sourceType);
 90   
 91  1260 if (ruleSets.usesDFA(language)) {
 92  5 sourceTypeHandler.getDataFlowFacade().start(rootNode);
 93    }
 94   
 95  1260 if (ruleSets.usesTypeResolution(language)) {
 96  18 sourceTypeHandler.getTypeResolutionFacade().start(rootNode);
 97    }
 98   
 99  1260 List acus = new ArrayList();
 100  1260 acus.add(rootNode);
 101   
 102  1260 ruleSets.apply(acus, ctx, language);
 103    } catch (ParseException pe) {
 104  0 throw new PMDException("Error while parsing "
 105    + ctx.getSourceCodeFilename(), pe);
 106    } catch (Exception e) {
 107  0 throw new PMDException("Error while processing "
 108    + ctx.getSourceCodeFilename(), e);
 109    } finally {
 110  1260 try {
 111  1260 reader.close();
 112    } catch (IOException e) {
 113  0 throw new PMDException("Error while closing "
 114    + ctx.getSourceCodeFilename(), e);
 115    }
 116    }
 117    }
 118   
 119    /**
 120    * Get the SourceType of the source file with given name. This depends on the fileName
 121    * extension, and the java version.
 122    * <p/>
 123    * For compatibility with older code that does not always pass in a correct filename,
 124    * unrecognized files are assumed to be java files.
 125    *
 126    * @param fileName Name of the file, can be absolute, or simple.
 127    * @return the SourceType
 128    */
 129  3 private SourceType getSourceTypeOfFile(String fileName) {
 130  3 SourceType sourceType = sourceTypeDiscoverer.getSourceTypeOfFile(fileName);
 131  3 if (sourceType == null) {
 132    // For compatibility with older code that does not always pass in
 133    // a correct filename.
 134  3 sourceType = sourceTypeDiscoverer.getSourceTypeOfJavaFiles();
 135    }
 136  3 return sourceType;
 137    }
 138   
 139    /**
 140    * Processes the file read by the reader agains the rule set.
 141    *
 142    * @param reader input stream reader
 143    * @param ruleSet set of rules to process against the file
 144    * @param ctx context in which PMD is operating. This contains the Renderer and
 145    * whatnot
 146    * @throws PMDException if the input could not be parsed or processed
 147    */
 148  3 public void processFile(Reader reader, RuleSet ruleSet, RuleContext ctx)
 149    throws PMDException {
 150  3 processFile(reader, new RuleSets(ruleSet), ctx);
 151    }
 152   
 153    /**
 154    * Processes the input stream agains a rule set using the given input encoding.
 155    *
 156    * @param fileContents an input stream to analyze
 157    * @param encoding input stream's encoding
 158    * @param ruleSet set of rules to process against the file
 159    * @param ctx context in which PMD is operating. This contains the Report and whatnot
 160    * @throws PMDException if the input encoding is unsupported or the input stream could
 161    * not be parsed
 162    * @see #processFile(Reader, RuleSet, RuleContext)
 163    */
 164  0 public void processFile(InputStream fileContents, String encoding,
 165    RuleSet ruleSet, RuleContext ctx) throws PMDException {
 166  0 try {
 167  0 processFile(new InputStreamReader(fileContents, encoding), ruleSet, ctx);
 168    } catch (UnsupportedEncodingException uee) {
 169  0 throw new PMDException("Unsupported encoding exception: "
 170    + uee.getMessage());
 171    }
 172    }
 173   
 174    /**
 175    * Processes the input stream agains a rule set using the given input encoding.
 176    *
 177    * @param fileContents an input stream to analyze
 178    * @param encoding input stream's encoding
 179    * @param ruleSets set of rules to process against the file
 180    * @param ctx context in which PMD is operating. This contains the Report and whatnot
 181    * @throws PMDException if the input encoding is unsupported or the input stream could
 182    * not be parsed
 183    * @see #processFile(Reader, RuleSet, RuleContext)
 184    */
 185  0 public void processFile(InputStream fileContents, String encoding,
 186    RuleSets ruleSets, RuleContext ctx) throws PMDException {
 187  0 try {
 188  0 processFile(new InputStreamReader(fileContents, encoding), ruleSets, ctx);
 189    } catch (UnsupportedEncodingException uee) {
 190  0 throw new PMDException("Unsupported encoding exception: "
 191    + uee.getMessage());
 192    }
 193    }
 194   
 195    /**
 196    * Processes the input stream against a rule set assuming the platform character set.
 197    *
 198    * @param fileContents input stream to check
 199    * @param ruleSet the set of rules to process against the source code
 200    * @param ctx the context in which PMD is operating. This contains the Report and
 201    * whatnot
 202    * @throws PMDException if the input encoding is unsupported or the input input stream
 203    * could not be parsed
 204    * @see #processFile(InputStream, String, RuleSet, RuleContext)
 205    */
 206  0 public void processFile(InputStream fileContents, RuleSet ruleSet,
 207    RuleContext ctx) throws PMDException {
 208  0 processFile(fileContents, System.getProperty("file.encoding"), ruleSet, ctx);
 209    }
 210   
 211  1 public void setExcludeMarker(String marker) {
 212  1 this.excludeMarker = marker;
 213    }
 214   
 215    /**
 216    * Set the SourceType to be used for ".java" files.
 217    *
 218    * @param javaVersion the SourceType that indicates the java version
 219    */
 220  1256 public void setJavaVersion(SourceType javaVersion) {
 221  1256 sourceTypeDiscoverer.setSourceTypeOfJavaFiles(javaVersion);
 222    }
 223   
 224  0 public static void main(String[] args) {
 225  0 CommandLineOptions opts = new CommandLineOptions(args);
 226   
 227  0 SourceFileSelector fileSelector = new SourceFileSelector();
 228   
 229  0 fileSelector.setSelectJavaFiles(opts.isCheckJavaFiles());
 230  0 fileSelector.setSelectJspFiles(opts.isCheckJspFiles());
 231   
 232  0 List files;
 233  0 if (opts.containsCommaSeparatedFileList()) {
 234  0 files = collectFromCommaDelimitedString(opts.getInputPath(),
 235    fileSelector);
 236    } else {
 237  0 files = collectFilesFromOneName(opts.getInputPath(), fileSelector);
 238    }
 239   
 240  0 SourceType sourceType;
 241  0 if (opts.getTargetJDK().equals("1.3")) {
 242  0 if (opts.debugEnabled())
 243  0 System.out.println("In JDK 1.3 mode");
 244  0 sourceType = SourceType.JAVA_13;
 245  0 } else if (opts.getTargetJDK().equals("1.5")) {
 246  0 if (opts.debugEnabled())
 247  0 System.out.println("In JDK 1.5 mode");
 248  0 sourceType = SourceType.JAVA_15;
 249  0 } else if (opts.getTargetJDK().equals("1.6")) {
 250  0 if (opts.debugEnabled())
 251  0 System.out.println("In JDK 1.6 mode");
 252  0 sourceType = SourceType.JAVA_16;
 253    } else {
 254  0 if (opts.debugEnabled())
 255  0 System.out.println("In JDK 1.4 mode");
 256  0 sourceType = SourceType.JAVA_14;
 257    }
 258   
 259  0 RuleContext ctx = new RuleContext();
 260  0 Report report = new Report();
 261  0 ctx.setReport(report);
 262  0 report.start();
 263   
 264  0 try {
 265  0 RuleSetFactory ruleSetFactory = new RuleSetFactory();
 266  0 ruleSetFactory.setMinimumPriority(opts.getMinPriority());
 267   
 268  0 RuleSets rulesets = ruleSetFactory.createRuleSets(opts.getRulesets());
 269  0 printRuleNamesInDebug(opts.debugEnabled(), rulesets);
 270   
 271  0 processFiles(opts.getCpus(), ruleSetFactory, sourceType, files, ctx,
 272    opts.getRulesets(), opts.debugEnabled(), opts.shortNamesEnabled(),
 273    opts.getInputPath(), opts.getEncoding(), opts.getExcludeMarker());
 274    } catch (RuleSetNotFoundException rsnfe) {
 275  0 System.out.println(opts.usage());
 276  0 rsnfe.printStackTrace();
 277    }
 278  0 report.end();
 279   
 280  0 Writer w = null;
 281  0 try {
 282  0 Renderer r = opts.createRenderer();
 283  0 if (opts.getReportFile() != null) {
 284  0 w = new BufferedWriter(new FileWriter(opts.getReportFile()));
 285    } else {
 286  0 w = new OutputStreamWriter(System.out);
 287    }
 288  0 r.render(w, ctx.getReport());
 289  0 w.write(EOL);
 290  0 w.flush();
 291  0 if (opts.getReportFile() != null) {
 292  0 w.close();
 293    }
 294    } catch (Exception e) {
 295  0 System.out.println(e.getMessage());
 296  0 System.out.println(opts.usage());
 297  0 if (opts.debugEnabled()) {
 298  0 e.printStackTrace();
 299    }
 300    } finally {
 301  0 if (opts.getReportFile() != null && w != null) {
 302  0 try {
 303  0 w.close();
 304    } catch (Exception e) {
 305  0 System.out.println(e.getMessage());
 306    }
 307    }
 308    }
 309    }
 310   
 311    private static class PmdRunnable extends PMD implements Runnable {
 312    private final ExecutorService executor;
 313    private final DataSource dataSource;
 314    private final String fileName;
 315    private final boolean debugEnabled;
 316    private final String encoding;
 317    private final String rulesets;
 318   
 319  0 public PmdRunnable(ExecutorService executor, DataSource dataSource, String fileName, SourceType sourceType,
 320    boolean debugEnabled, String encoding, String rulesets, String excludeMarker) {
 321  0 this.executor = executor;
 322  0 this.dataSource = dataSource;
 323  0 this.fileName = fileName;
 324  0 this.debugEnabled = debugEnabled;
 325  0 this.encoding = encoding;
 326  0 this.rulesets = rulesets;
 327   
 328  0 setJavaVersion(sourceType);
 329  0 setExcludeMarker(excludeMarker);
 330    }
 331   
 332  0 public void run() {
 333  0 PmdThread thread = (PmdThread) Thread.currentThread();
 334   
 335  0 RuleContext ctx = thread.getRuleContext();
 336  0 RuleSets rs = thread.getRuleSets(rulesets);
 337   
 338  0 ctx.setSourceCodeFilename(fileName);
 339  0 if (debugEnabled) {
 340  0 System.out.println("Processing " + ctx.getSourceCodeFilename());
 341    }
 342   
 343  0 try {
 344  0 InputStream stream = new BufferedInputStream(dataSource.getInputStream());
 345  0 processFile(stream, encoding, rs, ctx);
 346    } catch (PMDException pmde) {
 347  0 if (debugEnabled) {
 348  0 pmde.getReason().printStackTrace();
 349    }
 350  0 ctx.getReport().addError(
 351    new Report.ProcessingError(pmde.getMessage(),
 352    fileName));
 353    } catch (Throwable t) {
 354    // unexepected exception: log and stop executor service
 355  0 if (debugEnabled) {
 356  0 t.printStackTrace();
 357    }
 358  0 ctx.getReport().addError(
 359    new Report.ProcessingError(t.getMessage(),
 360    fileName));
 361   
 362  0 executor.shutdownNow();
 363    }
 364    }
 365   
 366    }
 367   
 368    private static class PmdThreadFactory implements ThreadFactory {
 369   
 370  0 public PmdThreadFactory(RuleSetFactory ruleSetFactory) {
 371  0 this.ruleSetFactory = ruleSetFactory;
 372    }
 373   
 374    private final RuleSetFactory ruleSetFactory;
 375    private final AtomicInteger counter = new AtomicInteger();
 376   
 377  0 public Thread newThread(Runnable r) {
 378  0 PmdThread t = new PmdThread(counter.incrementAndGet(), r, ruleSetFactory);
 379  0 threadList.add(t);
 380  0 return t;
 381    }
 382   
 383    public List threadList = Collections.synchronizedList(new LinkedList());
 384   
 385    }
 386   
 387    private static class PmdThread extends Thread {
 388   
 389  0 public PmdThread(int id, Runnable r, RuleSetFactory ruleSetFactory) {
 390  0 super(r, "PmdThread " + id);
 391  0 this.id = id;
 392  0 context = new RuleContext();
 393  0 context.setReport(new Report());
 394  0 this.ruleSetFactory = ruleSetFactory;
 395    }
 396   
 397    private int id;
 398    private RuleContext context;
 399    private RuleSets rulesets;
 400    private RuleSetFactory ruleSetFactory;
 401   
 402  0 public RuleContext getRuleContext() {
 403  0 return context;
 404    }
 405   
 406  0 public RuleSets getRuleSets(String rsList) {
 407  0 if (rulesets == null) {
 408  0 try {
 409  0 rulesets = ruleSetFactory.createRuleSets(rsList);
 410    } catch (Exception e) {
 411  0 e.printStackTrace();
 412    }
 413    }
 414  0 return rulesets;
 415    }
 416   
 417  0 public String toString() {
 418  0 return "PmdThread " + id;
 419    }
 420   
 421    }
 422   
 423    /**
 424    * Run PMD on a list of files using multiple threads.
 425    *
 426    * @throws IOException If one of the files could not be read
 427    */
 428  0 public static void processFiles(int threadCount, RuleSetFactory ruleSetFactory, SourceType sourceType, List files, RuleContext ctx, String rulesets,
 429    boolean debugEnabled, boolean shortNamesEnabled, String inputPath,
 430    String encoding, String excludeMarker) {
 431   
 432  0 PmdThreadFactory factory = new PmdThreadFactory(ruleSetFactory);
 433  0 ExecutorService executor = Executors.newFixedThreadPool(threadCount, factory);
 434   
 435  0 for (Iterator i = files.iterator(); i.hasNext();) {
 436  0 DataSource dataSource = (DataSource) i.next();
 437  0 String niceFileName = dataSource.getNiceFileName(shortNamesEnabled,
 438    inputPath);
 439   
 440  0 Runnable r = new PmdRunnable(executor, dataSource, niceFileName, sourceType, debugEnabled,
 441    encoding, rulesets, excludeMarker);
 442   
 443  0 executor.execute(r);
 444    }
 445  0 executor.shutdown();
 446   
 447  0 try {
 448  0 executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
 449    } catch (InterruptedException e) {
 450    }
 451   
 452  0 Report mainReport = ctx.getReport();
 453  0 Iterator i = factory.threadList.iterator();
 454  0 while (i.hasNext()) {
 455  0 PmdThread thread = (PmdThread) i.next();
 456  0 Report r = thread.context.getReport();
 457  0 mainReport.merge(r);
 458    }
 459    }
 460   
 461    /**
 462    * Run PMD on a list of files.
 463    *
 464    * @param files the List of DataSource instances.
 465    * @param ctx the context in which PMD is operating. This contains the Report and
 466    * whatnot
 467    * @param rulesets the RuleSets
 468    * @param debugEnabled
 469    * @param shortNamesEnabled
 470    * @param inputPath
 471    * @param encoding
 472    * @throws IOException If one of the files could not be read
 473    */
 474  0 public void processFiles(List files, RuleContext ctx, RuleSets rulesets,
 475    boolean debugEnabled, boolean shortNamesEnabled, String inputPath,
 476    String encoding) throws IOException {
 477  0 for (Iterator i = files.iterator(); i.hasNext();) {
 478  0 DataSource dataSource = (DataSource) i.next();
 479   
 480  0 String niceFileName = dataSource.getNiceFileName(shortNamesEnabled,
 481    inputPath);
 482  0 ctx.setSourceCodeFilename(niceFileName);
 483  0 if (debugEnabled) {
 484  0 System.out.println("Processing " + ctx.getSourceCodeFilename());
 485    }
 486   
 487  0 try {
 488  0 InputStream stream = new BufferedInputStream(dataSource
 489    .getInputStream());
 490  0 processFile(stream, encoding, rulesets, ctx);
 491    } catch (PMDException pmde) {
 492  0 if (debugEnabled) {
 493  0 pmde.getReason().printStackTrace();
 494    }
 495  0 ctx.getReport().addError(new Report.ProcessingError(pmde.getMessage(), niceFileName));
 496    }
 497    }
 498    }
 499   
 500    /**
 501    * If in debug modus, print the names of the rules.
 502    *
 503    * @param debugEnabled the boolean indicating if debug is enabled
 504    * @param rulesets the RuleSets to print
 505    */
 506  0 private static void printRuleNamesInDebug(boolean debugEnabled, RuleSets rulesets) {
 507  0 if (debugEnabled) {
 508  0 for (Iterator i = rulesets.getAllRules().iterator(); i.hasNext();) {
 509  0 Rule r = (Rule) i.next();
 510  0 System.out.println("Loaded rule " + r.getName());
 511    }
 512    }
 513    }
 514   
 515    /**
 516    * Collects the given file into a list.
 517    *
 518    * @param inputFileName a file name
 519    * @param fileSelector Filtering of wanted source files
 520    * @return the list of files collected from the <code>inputFileName</code>
 521    * @see #collect(String, SourceFileSelector)
 522    */
 523  0 private static List collectFilesFromOneName(String inputFileName,
 524    SourceFileSelector fileSelector) {
 525  0 return collect(inputFileName, fileSelector);
 526    }
 527   
 528    /**
 529    * Collects the files from the given comma-separated list.
 530    *
 531    * @param fileList comma-separated list of filenames
 532    * @param fileSelector Filtering of wanted source files
 533    * @return list of files collected from the <code>fileList</code>
 534    */
 535  0 private static List collectFromCommaDelimitedString(String fileList,
 536    SourceFileSelector fileSelector) {
 537  0 List files = new ArrayList();
 538  0 for (StringTokenizer st = new StringTokenizer(fileList, ","); st
 539    .hasMoreTokens();) {
 540  0 files.addAll(collect(st.nextToken(), fileSelector));
 541    }
 542  0 return files;
 543    }
 544   
 545    /**
 546    * Collects the files from the given <code>filename</code>.
 547    *
 548    * @param filename the source from which to collect files
 549    * @param fileSelector Filtering of wanted source files
 550    * @return a list of files found at the given <code>filename</code>
 551    * @throws RuntimeException if <code>filename</code> is not found
 552    */
 553  0 private static List collect(String filename, SourceFileSelector fileSelector) {
 554  0 File inputFile = new File(filename);
 555  0 if (!inputFile.exists()) {
 556  0 throw new RuntimeException("File " + inputFile.getName()
 557    + " doesn't exist");
 558    }
 559  0 List dataSources = new ArrayList();
 560  0 if (!inputFile.isDirectory()) {
 561  0 if (filename.endsWith(".zip") || filename.endsWith(".jar")) {
 562  0 ZipFile zipFile;
 563  0 try {
 564  0 zipFile = new ZipFile(inputFile);
 565  0 Enumeration e = zipFile.entries();
 566  0 while (e.hasMoreElements()) {
 567  0 ZipEntry zipEntry = (ZipEntry) e.nextElement();
 568  0 if (fileSelector.isWantedFile(zipEntry.getName())) {
 569  0 dataSources.add(new ZipDataSource(zipFile, zipEntry));
 570    }
 571    }
 572    } catch (IOException ze) {
 573  0 throw new RuntimeException("Zip file " + inputFile.getName()
 574    + " can't be opened");
 575    }
 576    } else {
 577  0 dataSources.add(new FileDataSource(inputFile));
 578    }
 579    } else {
 580  0 FileFinder finder = new FileFinder();
 581  0 List files = finder.findFilesFrom(inputFile.getAbsolutePath(),
 582    new SourceFileOrDirectoryFilter(fileSelector), true);
 583  0 for (Iterator i = files.iterator(); i.hasNext();) {
 584  0 dataSources.add(new FileDataSource((File) i.next()));
 585    }
 586    }
 587  0 return dataSources;
 588    }
 589   
 590    }
 591   
 592