1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/doclint/DocLint.java Mon Dec 17 07:47:05 2012 -0800 1.3 @@ -0,0 +1,376 @@ 1.4 +/* 1.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.tools.doclint; 1.30 + 1.31 +import java.io.File; 1.32 +import java.io.IOException; 1.33 +import java.io.PrintWriter; 1.34 +import java.util.ArrayList; 1.35 +import java.util.List; 1.36 + 1.37 +import javax.lang.model.element.Name; 1.38 +import javax.tools.StandardLocation; 1.39 + 1.40 +import com.sun.source.doctree.DocCommentTree; 1.41 +import com.sun.source.tree.ClassTree; 1.42 +import com.sun.source.tree.CompilationUnitTree; 1.43 +import com.sun.source.tree.MethodTree; 1.44 +import com.sun.source.tree.Tree; 1.45 +import com.sun.source.tree.VariableTree; 1.46 +import com.sun.source.util.JavacTask; 1.47 +import com.sun.source.util.Plugin; 1.48 +import com.sun.source.util.TaskEvent; 1.49 +import com.sun.source.util.TaskListener; 1.50 +import com.sun.source.util.TreePath; 1.51 +import com.sun.source.util.TreePathScanner; 1.52 +import com.sun.tools.javac.api.JavacTaskImpl; 1.53 +import com.sun.tools.javac.api.JavacTool; 1.54 +import com.sun.tools.javac.file.JavacFileManager; 1.55 +import com.sun.tools.javac.main.JavaCompiler; 1.56 +import com.sun.tools.javac.util.Context; 1.57 + 1.58 +/** 1.59 + * Multi-function entry point for the doc check utility. 1.60 + * 1.61 + * This class can be invoked in the following ways: 1.62 + * <ul> 1.63 + * <li>From the command line 1.64 + * <li>From javac, as a plugin 1.65 + * <li>Directly, via a simple API 1.66 + * </ul> 1.67 + * 1.68 + * <p><b>This is NOT part of any supported API. 1.69 + * If you write code that depends on this, you do so at your own 1.70 + * risk. This code and its internal interfaces are subject to change 1.71 + * or deletion without notice.</b></p> 1.72 + */ 1.73 +public class DocLint implements Plugin { 1.74 + 1.75 + public static final String XMSGS_OPTION = "-Xmsgs"; 1.76 + public static final String XMSGS_CUSTOM_PREFIX = "-Xmsgs:"; 1.77 + private static final String STATS = "-stats"; 1.78 + 1.79 + // <editor-fold defaultstate="collapsed" desc="Command-line entry point"> 1.80 + public static void main(String... args) { 1.81 + try { 1.82 + new DocLint().run(args); 1.83 + } catch (BadArgs e) { 1.84 + System.err.println(e.getMessage()); 1.85 + System.exit(1); 1.86 + } catch (IOException e) { 1.87 + System.err.println(e); 1.88 + System.exit(2); 1.89 + } 1.90 + } 1.91 + 1.92 + // </editor-fold> 1.93 + 1.94 + // <editor-fold defaultstate="collapsed" desc="Simple API"> 1.95 + 1.96 + public static class BadArgs extends Exception { 1.97 + private static final long serialVersionUID = 0; 1.98 + BadArgs(String code, Object... args) { 1.99 + this.code = code; 1.100 + this.args = args; 1.101 + } 1.102 + 1.103 + final String code; 1.104 + final Object[] args; 1.105 + } 1.106 + 1.107 + /** 1.108 + * Simple API entry point. 1.109 + */ 1.110 + public void run(String... args) throws BadArgs, IOException { 1.111 + PrintWriter out = new PrintWriter(System.out); 1.112 + try { 1.113 + run(out, args); 1.114 + } finally { 1.115 + out.flush(); 1.116 + } 1.117 + } 1.118 + 1.119 + public void run(PrintWriter out, String... args) throws BadArgs, IOException { 1.120 + env = new Env(); 1.121 + processArgs(args); 1.122 + 1.123 + if (needHelp) 1.124 + showHelp(out); 1.125 + 1.126 + if (javacFiles.isEmpty()) { 1.127 + if (!needHelp) 1.128 + System.out.println("no files given"); 1.129 + } 1.130 + 1.131 + JavacTool tool = JavacTool.create(); 1.132 + 1.133 + JavacFileManager fm = new JavacFileManager(new Context(), false, null); 1.134 + fm.setSymbolFileEnabled(false); 1.135 + fm.setLocation(StandardLocation.PLATFORM_CLASS_PATH, javacBootClassPath); 1.136 + fm.setLocation(StandardLocation.CLASS_PATH, javacClassPath); 1.137 + fm.setLocation(StandardLocation.SOURCE_PATH, javacSourcePath); 1.138 + 1.139 + JavacTask task = tool.getTask(out, fm, null, javacOpts, null, 1.140 + fm.getJavaFileObjectsFromFiles(javacFiles)); 1.141 + Iterable<? extends CompilationUnitTree> units = task.parse(); 1.142 + ((JavacTaskImpl) task).enter(); 1.143 + 1.144 + env.init(task); 1.145 + checker = new Checker(env); 1.146 + 1.147 + DeclScanner ds = new DeclScanner() { 1.148 + @Override 1.149 + void visitDecl(Tree tree, Name name) { 1.150 + TreePath p = getCurrentPath(); 1.151 + DocCommentTree dc = env.trees.getDocCommentTree(p); 1.152 + 1.153 + checker.scan(dc, p); 1.154 + } 1.155 + }; 1.156 + 1.157 + ds.scan(units, null); 1.158 + 1.159 + reportStats(out); 1.160 + 1.161 + Context ctx = ((JavacTaskImpl) task).getContext(); 1.162 + JavaCompiler c = JavaCompiler.instance(ctx); 1.163 + c.printCount("error", c.errorCount()); 1.164 + c.printCount("warn", c.warningCount()); 1.165 + } 1.166 + 1.167 + void processArgs(String... args) throws BadArgs { 1.168 + javacOpts = new ArrayList<String>(); 1.169 + javacFiles = new ArrayList<File>(); 1.170 + 1.171 + if (args.length == 0) 1.172 + needHelp = true; 1.173 + 1.174 + for (int i = 0; i < args.length; i++) { 1.175 + String arg = args[i]; 1.176 + if (arg.matches("-Xmax(errs|warns)") && i + 1 < args.length) { 1.177 + if (args[++i].matches("[0-9]+")) { 1.178 + javacOpts.add(arg); 1.179 + javacOpts.add(args[i]); 1.180 + } else { 1.181 + throw new BadArgs("dc.bad.value.for.option", arg, args[i]); 1.182 + } 1.183 + } else if (arg.equals(STATS)) { 1.184 + env.messages.setStatsEnabled(true); 1.185 + } else if (arg.matches("-bootclasspath") && i + 1 < args.length) { 1.186 + javacBootClassPath = splitPath(args[++i]); 1.187 + } else if (arg.matches("-classpath") && i + 1 < args.length) { 1.188 + javacClassPath = splitPath(args[++i]); 1.189 + } else if (arg.matches("-sourcepath") && i + 1 < args.length) { 1.190 + javacSourcePath = splitPath(args[++i]); 1.191 + } else if (arg.equals(XMSGS_OPTION)) { 1.192 + env.messages.setOptions(null); 1.193 + } else if (arg.startsWith(XMSGS_CUSTOM_PREFIX)) { 1.194 + env.messages.setOptions(arg.substring(arg.indexOf(":") + 1)); 1.195 + } else if (arg.equals("-h") || arg.equals("-help") || arg.equals("--help") 1.196 + || arg.equals("-?") || arg.equals("-usage")) { 1.197 + needHelp = true; 1.198 + } else if (arg.startsWith("-")) { 1.199 + throw new BadArgs("dc.bad.option", arg); 1.200 + } else { 1.201 + while (i < args.length) 1.202 + javacFiles.add(new File(args[i++])); 1.203 + } 1.204 + } 1.205 + } 1.206 + 1.207 + void showHelp(PrintWriter out) { 1.208 + out.println("Usage:"); 1.209 + out.println(" doclint [options] source-files..."); 1.210 + out.println(""); 1.211 + out.println("Options:"); 1.212 + out.println(" -Xmsgs "); 1.213 + out.println(" Same as -Xmsgs:all"); 1.214 + out.println(" -Xmsgs:values"); 1.215 + out.println(" Specify categories of issues to be checked, where 'values'"); 1.216 + out.println(" is a comma-separated list of any of the following:"); 1.217 + out.println(" reference show places where comments contain incorrect"); 1.218 + out.println(" references to Java source code elements"); 1.219 + out.println(" syntax show basic syntax errors within comments"); 1.220 + out.println(" html show issues with HTML tags and attributes"); 1.221 + out.println(" accessibility show issues for accessibility"); 1.222 + out.println(" missing show issues with missing documentation"); 1.223 + out.println(" all all of the above"); 1.224 + out.println(" Precede a value with '-' to negate it"); 1.225 + out.println(" Categories may be qualified by one of:"); 1.226 + out.println(" /public /protected /package /private"); 1.227 + out.println(" For positive categories (not beginning with '-')"); 1.228 + out.println(" the qualifier applies to that access level and above."); 1.229 + out.println(" For negative categories (beginning with '-')"); 1.230 + out.println(" the qualifier applies to that access level and below."); 1.231 + out.println(" If a qualifier is missing, the category applies to"); 1.232 + out.println(" all access levels."); 1.233 + out.println(" For example, -Xmsgs:all,-syntax/private"); 1.234 + out.println(" This will enable all messages, except syntax errors"); 1.235 + out.println(" in the doc comments of private methods."); 1.236 + out.println(" If no -Xmsgs options are provided, the default is"); 1.237 + out.println(" equivalent to -Xmsgs:all/protected, meaning that"); 1.238 + out.println(" all messages are reported for protected and public"); 1.239 + out.println(" declarations only. "); 1.240 + out.println(" -h -help --help -usage -?"); 1.241 + out.println(" Show this message."); 1.242 + out.println(""); 1.243 + out.println("The following javac options are also supported"); 1.244 + out.println(" -bootclasspath, -classpath, -sourcepath, -Xmaxerrs, -Xmaxwarns"); 1.245 + out.println(""); 1.246 + out.println("To run doclint on part of a project, put the compiled classes for your"); 1.247 + out.println("project on the classpath (or bootclasspath), then specify the source files"); 1.248 + out.println("to be checked on the command line."); 1.249 + } 1.250 + 1.251 + List<File> splitPath(String path) { 1.252 + List<File> files = new ArrayList<File>(); 1.253 + for (String f: path.split(File.separator)) { 1.254 + if (f.length() > 0) 1.255 + files.add(new File(f)); 1.256 + } 1.257 + return files; 1.258 + } 1.259 + 1.260 + List<File> javacBootClassPath; 1.261 + List<File> javacClassPath; 1.262 + List<File> javacSourcePath; 1.263 + List<String> javacOpts; 1.264 + List<File> javacFiles; 1.265 + boolean needHelp = false; 1.266 + 1.267 + // </editor-fold> 1.268 + 1.269 + // <editor-fold defaultstate="collapsed" desc="javac Plugin"> 1.270 + 1.271 + @Override 1.272 + public String getName() { 1.273 + return "doclint"; 1.274 + } 1.275 + 1.276 + @Override 1.277 + public void call(JavacTask task, String... args) { 1.278 + init(task, args, true); 1.279 + } 1.280 + 1.281 + // </editor-fold> 1.282 + 1.283 + // <editor-fold defaultstate="collapsed" desc="Embedding API"> 1.284 + 1.285 + public void init(JavacTask task, String[] args, boolean addTaskListener) { 1.286 + env = new Env(); 1.287 + for (int i = 0; i < args.length; i++) { 1.288 + String arg = args[i]; 1.289 + if (arg.equals(XMSGS_OPTION)) { 1.290 + env.messages.setOptions(null); 1.291 + } else if (arg.startsWith(XMSGS_CUSTOM_PREFIX)) { 1.292 + env.messages.setOptions(arg.substring(arg.indexOf(":") + 1)); 1.293 + } else 1.294 + throw new IllegalArgumentException(arg); 1.295 + } 1.296 + env.init(task); 1.297 + 1.298 + checker = new Checker(env); 1.299 + 1.300 + if (addTaskListener) { 1.301 + final DeclScanner ds = new DeclScanner() { 1.302 + @Override 1.303 + void visitDecl(Tree tree, Name name) { 1.304 + TreePath p = getCurrentPath(); 1.305 + DocCommentTree dc = env.trees.getDocCommentTree(p); 1.306 + 1.307 + checker.scan(dc, p); 1.308 + } 1.309 + }; 1.310 + 1.311 + TaskListener tl = new TaskListener() { 1.312 + @Override 1.313 + public void started(TaskEvent e) { 1.314 + return; 1.315 + } 1.316 + 1.317 + @Override 1.318 + public void finished(TaskEvent e) { 1.319 + switch (e.getKind()) { 1.320 + case ENTER: 1.321 + ds.scan(e.getCompilationUnit(), null); 1.322 + } 1.323 + } 1.324 + }; 1.325 + 1.326 + task.addTaskListener(tl); 1.327 + } 1.328 + } 1.329 + 1.330 + public void scan(TreePath p) { 1.331 + DocCommentTree dc = env.trees.getDocCommentTree(p); 1.332 + checker.scan(dc, p); 1.333 + } 1.334 + 1.335 + public void reportStats(PrintWriter out) { 1.336 + env.messages.reportStats(out); 1.337 + } 1.338 + 1.339 + // </editor-fold> 1.340 + 1.341 + Env env; 1.342 + Checker checker; 1.343 + 1.344 + public static boolean isValidOption(String opt) { 1.345 + if (opt.equals(XMSGS_OPTION)) 1.346 + return true; 1.347 + if (opt.startsWith(XMSGS_CUSTOM_PREFIX)) 1.348 + return Messages.Options.isValidOptions(opt.substring(XMSGS_CUSTOM_PREFIX.length())); 1.349 + return false; 1.350 + } 1.351 + 1.352 + // <editor-fold defaultstate="collapsed" desc="DeclScanner"> 1.353 + 1.354 + static abstract class DeclScanner extends TreePathScanner<Void, Void> { 1.355 + abstract void visitDecl(Tree tree, Name name); 1.356 + 1.357 + @Override 1.358 + public Void visitClass(ClassTree tree, Void ignore) { 1.359 + visitDecl(tree, tree.getSimpleName()); 1.360 + return super.visitClass(tree, ignore); 1.361 + } 1.362 + 1.363 + @Override 1.364 + public Void visitMethod(MethodTree tree, Void ignore) { 1.365 + visitDecl(tree, tree.getName()); 1.366 + //return super.visitMethod(tree, ignore); 1.367 + return null; 1.368 + } 1.369 + 1.370 + @Override 1.371 + public Void visitVariable(VariableTree tree, Void ignore) { 1.372 + visitDecl(tree, tree.getName()); 1.373 + return super.visitVariable(tree, ignore); 1.374 + } 1.375 + } 1.376 + 1.377 + // </editor-fold> 1.378 + 1.379 +}