View Javadoc

    1   package net.sourceforge.pmd;
    2
    3   import java.io.InputStream;
    4   import java.io.InputStreamReader;
    5   import java.io.Reader;
    6   import java.io.UnsupportedEncodingException;
    7   import java.util.ArrayList;
    8   import java.util.List;
    9
    10  import net.sourceforge.pmd.benchmark.Benchmark;
    11  import net.sourceforge.pmd.benchmark.Benchmarker;
    12  import net.sourceforge.pmd.lang.Language;
    13  import net.sourceforge.pmd.lang.LanguageVersion;
    14  import net.sourceforge.pmd.lang.LanguageVersionHandler;
    15  import net.sourceforge.pmd.lang.Parser;
    16  import net.sourceforge.pmd.lang.ast.Node;
    17  import net.sourceforge.pmd.lang.java.ast.ParseException;
    18  import net.sourceforge.pmd.lang.xpath.Initializer;
    19  import net.sourceforge.pmd.util.IOUtil;
    20
    21  public class SourceCodeProcessor {
    22
    23      private final PMDConfiguration configuration;
    24
    25      public SourceCodeProcessor(PMDConfiguration configuration) {
    26      	this.configuration = configuration;
    27      }
    28
    29
    30      /**
    31       * Processes the input stream against a rule set using the given input encoding.
    32       *
    33       * @param sourceCode The InputStream to analyze.
    34       * @param ruleSets The collection of rules to process against the file.
    35       * @param ctx The context in which PMD is operating.
    36       * @throws PMDException if the input encoding is unsupported, the input stream could
    37       *                      not be parsed, or other error is encountered.
    38       * @see #processSourceCode(Reader, RuleSets, RuleContext)
    39       */
    40      public void processSourceCode(InputStream sourceCode, RuleSets ruleSets, RuleContext ctx) throws PMDException {
    41  		try {
    42  		    processSourceCode(new InputStreamReader(sourceCode, configuration.getSourceEncoding()), ruleSets, ctx);
    43  		} catch (UnsupportedEncodingException uee) {
    44  		    throw new PMDException("Unsupported encoding exception: " + uee.getMessage());
    45  		}
    46      }
    47
    48
    49      /**
    50       * Processes the input stream against a rule set using the given input encoding.
    51       * If the LanguageVersion is <code>null</code>  on the RuleContext, it will
    52       * be automatically determined.  Any code which wishes to process files for
    53       * different Languages, will need to be sure to either properly set the
    54       * Language on the RuleContext, or set it to <code>null</code> first.
    55       *
    56       * @see RuleContext#setLanguageVersion(LanguageVersion)
    57       * @see PMDConfiguration#getLanguageVersionOfFile(String)
    58       *
    59       * @param sourceCode The Reader to analyze.
    60       * @param ruleSets The collection of rules to process against the file.
    61       * @param ctx The context in which PMD is operating.
    62       * @throws PMDException if the input encoding is unsupported, the input stream could
    63       *                      not be parsed, or other error is encountered.
    64       */
    65      public void processSourceCode(Reader sourceCode, RuleSets ruleSets, RuleContext ctx) throws PMDException {
    66      	determineLanguage(ctx);
    67
    68  		// make sure custom XPath functions are initialized
    69  		Initializer.initialize();
    70
    71  	    // Coarse check to see if any RuleSet applies to file, will need to do a finer RuleSet specific check later
    72  		 if (ruleSets.applies(ctx.getSourceCodeFile())) {
    73
    74  		try {
    75  			processSource(sourceCode, ruleSets,ctx);
    76
    77  		} catch (ParseException pe) {
    78  		    throw new PMDException("Error while parsing " + ctx.getSourceCodeFilename(), pe);
    79  		} catch (Exception e) {
    80  		    throw new PMDException("Error while processing " + ctx.getSourceCodeFilename(), e);
    81  		} finally {
    82  		    IOUtil.closeQuietly(sourceCode);
    83  		}
    84  		}
    85      }
    86
    87
    88      private Node parse(RuleContext ctx, Reader sourceCode, Parser parser) {
    89  		long start = System.nanoTime();
    90  		Node rootNode = parser.parse(ctx.getSourceCodeFilename(), sourceCode);
    91  		ctx.getReport().suppress(parser.getSuppressMap());
    92  		long end = System.nanoTime();
    93  		Benchmarker.mark(Benchmark.Parser, end - start, 0);
    94  		return rootNode;
    95      }
    96
    97      private void symbolFacade(Node rootNode, LanguageVersionHandler languageVersionHandler) {
    98      	long start = System.nanoTime();
    99  		languageVersionHandler.getSymbolFacade().start(rootNode);
    100 		long end = System.nanoTime();
    101 		Benchmarker.mark(Benchmark.SymbolTable, end - start, 0);
    102     }
    103
    104 //    private ParserOptions getParserOptions(final LanguageVersionHandler languageVersionHandler) {
    105 //		// TODO Handle Rules having different parser options.
    106 //		ParserOptions parserOptions = languageVersionHandler.getDefaultParserOptions();
    107 //		parserOptions.setSuppressMarker(configuration.getSuppressMarker());
    108 //		return parserOptions;
    109 //    }
    110
    111     private void usesDFA(LanguageVersion languageVersion, Node rootNode, RuleSets ruleSets, Language language ) {
    112
    113 		if (ruleSets.usesDFA(language)) {
    114 		    long start = System.nanoTime();
    115 		    languageVersion.getLanguageVersionHandler().getDataFlowFacade().start(rootNode);
    116 		    long end = System.nanoTime();
    117 		    Benchmarker.mark(Benchmark.DFA, end - start, 0);
    118 		}
    119     }
    120
    121     private void usesTypeResolution(LanguageVersion languageVersion, Node rootNode, RuleSets ruleSets, Language language) {
    122
    123 		if (ruleSets.usesTypeResolution(language)) {
    124 		    long start = System.nanoTime();
    125 		    languageVersion.getLanguageVersionHandler().getTypeResolutionFacade(configuration.getClassLoader()).start(rootNode);
    126 		    long end = System.nanoTime();
    127 		    Benchmarker.mark(Benchmark.TypeResolution, end - start, 0);
    128 		}
    129     }
    130
    131     private void processSource(Reader sourceCode, RuleSets ruleSets, RuleContext ctx) {
    132 		LanguageVersion languageVersion = ctx.getLanguageVersion();
    133 		LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler();
    134 		Parser parser = PMD.parserFor(languageVersion, configuration);
    135
    136 		Node rootNode = parse(ctx, sourceCode, parser);
    137 		symbolFacade(rootNode, languageVersionHandler);
    138 		Language language = languageVersion.getLanguage();
    139 		usesDFA(languageVersion, rootNode, ruleSets, language);
    140 		usesTypeResolution(languageVersion, rootNode, ruleSets,language);
    141
    142 		List<Node> acus = new ArrayList<Node>();
    143 		acus.add(rootNode);
    144 		ruleSets.apply(acus, ctx, language);
    145 	}
    146
    147
    148
    149 	private void determineLanguage(RuleContext ctx) {
    150 		// If LanguageVersion of the source file is not known, make a determination
    151 		if (ctx.getLanguageVersion() == null) {
    152 		    LanguageVersion languageVersion = configuration.getLanguageVersionOfFile(ctx.getSourceCodeFilename());
    153 		    ctx.setLanguageVersion(languageVersion);
    154 		}
    155     }
    156 }