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.ASTCompilationUnit;
7 import net.sourceforge.pmd.ast.JavaParser;
8 import net.sourceforge.pmd.ast.ParseException;
9 import net.sourceforge.pmd.cpd.FileFinder;
10 import net.sourceforge.pmd.cpd.JavaLanguage;
11 import net.sourceforge.pmd.renderers.Renderer;
12 import net.sourceforge.pmd.symboltable.SymbolFacade;
13
14 import java.io.File;
15 import java.io.FileInputStream;
16 import java.io.FileNotFoundException;
17 import java.io.InputStream;
18 import java.io.InputStreamReader;
19 import java.io.Reader;
20 import java.io.UnsupportedEncodingException;
21 import java.util.ArrayList;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.StringTokenizer;
25
26 public class PMD {
27
28 public static final String EOL = System.getProperty("line.separator", "\n");
29
30 private TargetJDKVersion targetJDKVersion;
31
32 public PMD() {
33 targetJDKVersion = new TargetJDK1_4();
34 }
35
36 public PMD(TargetJDKVersion targetJDKVersion) {
37 this.targetJDKVersion = targetJDKVersion;
38 }
39
40 /***
41 * @param reader - a Reader to the Java code to analyse
42 * @param ruleSet - the set of rules to process against the file
43 * @param ctx - the context in which PMD is operating. This contains the Renderer and whatnot
44 */
45 public void processFile(Reader reader, RuleSet ruleSet, RuleContext ctx) throws PMDException {
46 try {
47 JavaParser parser = targetJDKVersion.createParser(reader);
48 ASTCompilationUnit c = parser.CompilationUnit();
49 Thread.yield();
50 SymbolFacade stb = new SymbolFacade();
51 stb.initializeWith(c);
52 List acus = new ArrayList();
53 acus.add(c);
54 ruleSet.apply(acus, ctx);
55 reader.close();
56 } catch (ParseException pe) {
57 throw new PMDException("Error while parsing " + ctx.getSourceCodeFilename(), pe);
58 } catch (Exception e) {
59 throw new PMDException("Error while processing " + ctx.getSourceCodeFilename(), e);
60 }
61 }
62
63 /***
64 * @param fileContents - an InputStream to the Java code to analyse
65 * @param encoding - the source code's character set encoding
66 * @param ruleSet - the set of rules to process against the file
67 * @param ctx - the context in which PMD is operating. This contains the Report and whatnot
68 */
69 public void processFile(InputStream fileContents, String encoding, RuleSet ruleSet, RuleContext ctx) throws PMDException {
70 try {
71 processFile(new InputStreamReader(fileContents, encoding), ruleSet, ctx);
72 } catch (UnsupportedEncodingException uee) {
73 throw new PMDException("Unsupported encoding exception: " + uee.getMessage());
74 }
75 }
76
77 /***
78 * @param fileContents - an InputStream to the Java code to analyse
79 * @param ruleSet - the set of rules to process against the source code
80 * @param ctx - the context in which PMD is operating. This contains the Report and whatnot
81 */
82 public void processFile(InputStream fileContents, RuleSet ruleSet, RuleContext ctx) throws PMDException {
83 processFile(fileContents, System.getProperty("file.encoding"), ruleSet, ctx);
84 }
85
86 public static void main(String[] args) {
87 CommandLineOptions opts = new CommandLineOptions(args);
88
89 List files;
90 if (opts.containsCommaSeparatedFileList()) {
91 files = collectFromCommaDelimitedString(opts.getInputFileName());
92 } else {
93 files = collectFilesFromOneName(opts.getInputFileName());
94 }
95
96 PMD pmd;
97 if (opts.jdk13()) {
98 pmd = new PMD(new TargetJDK1_3());
99 } else {
100 pmd = new PMD();
101 }
102
103 RuleContext ctx = new RuleContext();
104 ctx.setReport(new Report());
105
106 try {
107 RuleSetFactory ruleSetFactory = new RuleSetFactory();
108 RuleSet rules = ruleSetFactory.createRuleSet(opts.getRulesets());
109 for (Iterator i = files.iterator(); i.hasNext();) {
110 File file = (File) i.next();
111 ctx.setSourceCodeFilename(glomName(opts.shortNamesEnabled(), opts.getInputFileName(), file));
112 try {
113 pmd.processFile(new FileInputStream(file), opts.getEncoding(), rules, ctx);
114 } catch (PMDException pmde) {
115 if (opts.debugEnabled()) {
116 pmde.getReason().printStackTrace();
117 }
118 ctx.getReport().addError(new Report.ProcessingError(pmde.getMessage(), glomName(opts.shortNamesEnabled(), opts.getInputFileName(), file)));
119 }
120 }
121 } catch (FileNotFoundException fnfe) {
122 System.out.println(opts.usage());
123 fnfe.printStackTrace();
124 } catch (RuleSetNotFoundException rsnfe) {
125 System.out.println(opts.usage());
126 rsnfe.printStackTrace();
127 }
128
129 try {
130 Renderer r = opts.createRenderer();
131 System.out.println(r.render(ctx.getReport()));
132 } catch (Exception e) {
133 System.out.println(e.getMessage());
134 System.out.println(opts.usage());
135 if (opts.debugEnabled()) {
136 e.printStackTrace();
137 }
138 }
139 }
140
141 private static String glomName(boolean shortNames, String inputFileName, File file) {
142 if (shortNames && inputFileName.indexOf(',') == -1) {
143 if ((new File(inputFileName)).isDirectory()) {
144 return trimAnyPathSep(file.getAbsolutePath().substring(inputFileName.length()));
145 } else {
146 if (inputFileName.indexOf(System.getProperty("file.separator").charAt(0)) == -1) {
147 return inputFileName;
148 }
149 return trimAnyPathSep(inputFileName.substring(inputFileName.lastIndexOf(System.getProperty("file.separator"))));
150 }
151 } else {
152 return file.getAbsolutePath();
153 }
154 }
155
156 private static String trimAnyPathSep(String name) {
157 if (name.startsWith(System.getProperty("file.separator"))) {
158 name = name.substring(1);
159 }
160 return name;
161 }
162
163 private static List collectFilesFromOneName(String inputFileName) {
164 return collect(inputFileName);
165 }
166
167 private static List collectFromCommaDelimitedString(String fileList) {
168 List files = new ArrayList();
169 for (StringTokenizer st = new StringTokenizer(fileList, ","); st.hasMoreTokens();) {
170 files.addAll(collect(st.nextToken()));
171 }
172 return files;
173 }
174
175 private static List collect(String filename) {
176 File inputFile = new File(filename);
177 if (!inputFile.exists()) {
178 throw new RuntimeException("File " + inputFile.getName() + " doesn't exist");
179 }
180 List files;
181 if (!inputFile.isDirectory()) {
182 files = new ArrayList();
183 files.add(inputFile);
184 } else {
185 FileFinder finder = new FileFinder();
186 files = finder.findFilesFrom(inputFile.getAbsolutePath(), new JavaLanguage.JavaFileOrDirectoryFilter(), true);
187 }
188 return files;
189 }
190
191 }