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 }