Path: blob/master/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/DocLint.java
41161 views
/*1* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package jdk.javadoc.internal.doclint;2627import java.io.File;28import java.io.IOException;29import java.io.PrintWriter;30import java.util.ArrayList;31import java.util.LinkedList;32import java.util.List;33import java.util.Queue;3435import javax.lang.model.element.Name;36import javax.lang.model.util.Elements;37import javax.lang.model.util.Types;38import javax.tools.StandardLocation;3940import com.sun.source.doctree.DocCommentTree;41import com.sun.source.tree.BlockTree;42import com.sun.source.tree.ClassTree;43import com.sun.source.tree.CompilationUnitTree;44import com.sun.source.tree.LambdaExpressionTree;45import com.sun.source.tree.ModuleTree;46import com.sun.source.tree.PackageTree;47import com.sun.source.tree.MethodTree;48import com.sun.source.tree.Tree;49import com.sun.source.tree.VariableTree;50import com.sun.source.util.DocTrees;51import com.sun.source.util.JavacTask;52import com.sun.source.util.TaskEvent;53import com.sun.source.util.TaskListener;54import com.sun.source.util.TreePath;55import com.sun.source.util.TreePathScanner;56import com.sun.tools.javac.api.JavacTaskImpl;57import com.sun.tools.javac.api.JavacTool;58import com.sun.tools.javac.file.JavacFileManager;59import com.sun.tools.javac.main.JavaCompiler;60import com.sun.tools.javac.util.Context;61import com.sun.tools.javac.util.DefinedBy;62import com.sun.tools.javac.util.DefinedBy.Api;6364/**65* Multi-function entry point for the doc check utility.66*67* This class can be invoked in the following ways:68* <ul>69* <li>From the command line70* <li>From javac, as a plugin71* <li>Directly, via a simple API72* </ul>73*74* <p><b>This is NOT part of any supported API.75* If you write code that depends on this, you do so at your own76* risk. This code and its internal interfaces are subject to change77* or deletion without notice.</b></p>78*/79public class DocLint extends com.sun.tools.doclint.DocLint {8081public static final String XMSGS_OPTION = "-Xmsgs";82public static final String XMSGS_CUSTOM_PREFIX = "-Xmsgs:";83private static final String STATS = "-stats";84public static final String XCUSTOM_TAGS_PREFIX = "-XcustomTags:";85public static final String XCHECK_PACKAGE = "-XcheckPackage:";86public static final String SEPARATOR = ",";8788// <editor-fold defaultstate="collapsed" desc="Command-line entry point">89public static void main(String... args) {90DocLint dl = new DocLint();91try {92dl.run(args);93} catch (BadArgs e) {94System.err.println(e.getMessage());95System.exit(1);96} catch (IOException e) {97System.err.println(dl.localize("dc.main.ioerror", e.getLocalizedMessage()));98System.exit(2);99}100}101102// </editor-fold>103104// <editor-fold defaultstate="collapsed" desc="Simple API">105106public class BadArgs extends Exception {107private static final long serialVersionUID = 0;108BadArgs(String code, Object... args) {109super(localize(code, args));110this.code = code;111this.args = args;112}113114final String code;115final transient Object[] args;116}117118/**119* Simple API entry point.120* @param args Options and operands for doclint121* @throws BadArgs if an error is detected in any args122* @throws IOException if there are problems with any of the file arguments123*/124public void run(String... args) throws BadArgs, IOException {125PrintWriter out = new PrintWriter(System.out);126try {127run(out, args);128} finally {129out.flush();130}131}132133public void run(PrintWriter out, String... args) throws BadArgs, IOException {134env = new Env();135processArgs(args);136137boolean noFiles = javacFiles.isEmpty();138if (needHelp) {139showHelp(out);140if (noFiles)141return;142} else if (noFiles) {143out.println(localize("dc.main.no.files.given"));144return;145}146147JavacTool tool = JavacTool.create();148149JavacFileManager fm = new JavacFileManager(new Context(), false, null);150fm.setSymbolFileEnabled(false);151if (javacBootClassPath != null) {152fm.setLocation(StandardLocation.PLATFORM_CLASS_PATH, javacBootClassPath);153}154if (javacClassPath != null) {155fm.setLocation(StandardLocation.CLASS_PATH, javacClassPath);156}157if (javacSourcePath != null) {158fm.setLocation(StandardLocation.SOURCE_PATH, javacSourcePath);159}160161JavacTask task = tool.getTask(out, fm, null, javacOpts, null,162fm.getJavaFileObjectsFromFiles(javacFiles));163Iterable<? extends CompilationUnitTree> units = task.parse();164((JavacTaskImpl) task).enter();165166env.init(task);167checker = new Checker(env);168169DeclScanner ds = new DeclScanner(env) {170@Override171void visitDecl(Tree tree, Name name) {172TreePath p = getCurrentPath();173DocCommentTree dc = env.trees.getDocCommentTree(p);174175checker.scan(dc, p);176}177};178179ds.scan(units, null);180181reportStats(out);182183Context ctx = ((JavacTaskImpl) task).getContext();184JavaCompiler c = JavaCompiler.instance(ctx);185c.printCount("error", c.errorCount());186c.printCount("warn", c.warningCount());187}188189void processArgs(String... args) throws BadArgs {190javacOpts = new ArrayList<>();191javacFiles = new ArrayList<>();192193if (args.length == 0)194needHelp = true;195196for (int i = 0; i < args.length; i++) {197String arg = args[i];198if (arg.matches("-Xmax(errs|warns)") && i + 1 < args.length) {199if (args[++i].matches("[0-9]+")) {200javacOpts.add(arg);201javacOpts.add(args[i]);202} else {203throw new BadArgs("dc.bad.value.for.option", arg, args[i]);204}205} else if ((arg.equals("-target") || arg.equals("-source")) && i + 1 < args.length) {206javacOpts.add(arg);207javacOpts.add(args[++i]);208} else if (arg.equals(STATS)) {209env.messages.setStatsEnabled(true);210} else if (arg.equals("-bootclasspath") && i + 1 < args.length) {211javacBootClassPath = splitPath(args[++i]);212} else if (arg.equals("-classpath") && i + 1 < args.length) {213javacClassPath = splitPath(args[++i]);214} else if (arg.equals("-cp") && i + 1 < args.length) {215javacClassPath = splitPath(args[++i]);216} else if (arg.equals("-sourcepath") && i + 1 < args.length) {217javacSourcePath = splitPath(args[++i]);218} else if (arg.equals(XMSGS_OPTION)) {219env.messages.setOptions(null);220} else if (arg.startsWith(XMSGS_CUSTOM_PREFIX)) {221env.messages.setOptions(arg.substring(arg.indexOf(":") + 1));222} else if (arg.startsWith(XCUSTOM_TAGS_PREFIX)) {223env.setCustomTags(arg.substring(arg.indexOf(":") + 1));224} else if (arg.equals("-h") || arg.equals("-help") || arg.equals("--help")225|| arg.equals("-?") || arg.equals("-usage")) {226needHelp = true;227} else if (arg.startsWith("-")) {228throw new BadArgs("dc.bad.option", arg);229} else {230while (i < args.length)231javacFiles.add(new File(args[i++]));232}233}234}235236void showHelp(PrintWriter out) {237String msg = localize("dc.main.usage");238for (String line: msg.split("\n"))239out.println(line);240}241242List<File> splitPath(String path) {243List<File> files = new ArrayList<>();244for (String f: path.split(File.pathSeparator)) {245if (f.length() > 0)246files.add(new File(f));247}248return files;249}250251List<File> javacBootClassPath;252List<File> javacClassPath;253List<File> javacSourcePath;254List<String> javacOpts;255List<File> javacFiles;256boolean needHelp = false;257258// </editor-fold>259260// <editor-fold defaultstate="collapsed" desc="javac Plugin">261262@Override @DefinedBy(Api.COMPILER_TREE)263public String getName() {264return "doclint";265}266267@Override @DefinedBy(Api.COMPILER_TREE)268public void init(JavacTask task, String... args) {269init(task, args, true);270}271272// </editor-fold>273274// <editor-fold defaultstate="collapsed" desc="Embedding API">275276public void init(JavacTask task, String[] args, boolean addTaskListener) {277env = new Env();278env.init(task);279processArgs(env, args);280281checker = new Checker(env);282283if (addTaskListener) {284final DeclScanner ds = new DeclScanner(env) {285@Override286void visitDecl(Tree tree, Name name) {287TreePath p = getCurrentPath();288DocCommentTree dc = env.trees.getDocCommentTree(p);289290checker.scan(dc, p);291}292};293294TaskListener tl = new TaskListener() {295@Override @DefinedBy(Api.COMPILER_TREE)296public void started(TaskEvent e) {297switch (e.getKind()) {298case ANALYZE:299CompilationUnitTree tree;300while ((tree = todo.poll()) != null)301ds.scan(tree, null);302break;303}304}305306@Override @DefinedBy(Api.COMPILER_TREE)307public void finished(TaskEvent e) {308switch (e.getKind()) {309case PARSE:310todo.add(e.getCompilationUnit());311break;312}313}314315Queue<CompilationUnitTree> todo = new LinkedList<>();316};317318task.addTaskListener(tl);319}320}321322public void init(DocTrees trees, Elements elements, Types types, String... args) {323env = new Env();324env.init(trees, elements, types);325processArgs(env, args);326327checker = new Checker(env);328}329330private void processArgs(Env env, String... args) {331for (String arg : args) {332if (arg.equals(XMSGS_OPTION)) {333env.messages.setOptions(null);334} else if (arg.startsWith(XMSGS_CUSTOM_PREFIX)) {335env.messages.setOptions(arg.substring(arg.indexOf(":") + 1));336} else if (arg.startsWith(XCUSTOM_TAGS_PREFIX)) {337env.setCustomTags(arg.substring(arg.indexOf(":") + 1));338} else if (arg.startsWith(XCHECK_PACKAGE)) {339env.setCheckPackages(arg.substring(arg.indexOf(":") + 1));340} else341throw new IllegalArgumentException(arg);342}343}344345public void scan(TreePath p) {346DocCommentTree dc = env.trees.getDocCommentTree(p);347checker.scan(dc, p);348}349350public boolean shouldCheck(CompilationUnitTree unit) {351return env.shouldCheck(unit);352}353354public void reportStats(PrintWriter out) {355env.messages.reportStats(out);356}357358// </editor-fold>359360Env env;361Checker checker;362363public boolean isValidOption(String opt) {364if (opt.equals(XMSGS_OPTION))365return true;366if (opt.startsWith(XMSGS_CUSTOM_PREFIX))367return Messages.Options.isValidOptions(opt.substring(XMSGS_CUSTOM_PREFIX.length()));368if (opt.startsWith(XCHECK_PACKAGE)) {369return Env.validatePackages(opt.substring(opt.indexOf(":") + 1));370}371return false;372}373374private String localize(String code, Object... args) {375Messages m = (env != null) ? env.messages : new Messages(null);376return m.localize(code, args);377}378379// <editor-fold defaultstate="collapsed" desc="DeclScanner">380381static abstract class DeclScanner extends TreePathScanner<Void, Void> {382final Env env;383384public DeclScanner(Env env) {385this.env = env;386}387388abstract void visitDecl(Tree tree, Name name);389390@Override @DefinedBy(Api.COMPILER_TREE)391public Void visitPackage(PackageTree tree, Void ignore) {392visitDecl(tree, null);393return super.visitPackage(tree, ignore);394}395396@Override @DefinedBy(Api.COMPILER_TREE)397public Void visitClass(ClassTree tree, Void ignore) {398visitDecl(tree, tree.getSimpleName());399return super.visitClass(tree, ignore);400}401402@Override @DefinedBy(Api.COMPILER_TREE)403public Void visitMethod(MethodTree tree, Void ignore) {404visitDecl(tree, tree.getName());405return null;406}407408@Override @DefinedBy(Api.COMPILER_TREE)409public Void visitModule(ModuleTree tree, Void ignore) {410visitDecl(tree, null);411return super.visitModule(tree, ignore);412}413414@Override @DefinedBy(Api.COMPILER_TREE)415public Void visitVariable(VariableTree tree, Void ignore) {416visitDecl(tree, tree.getName());417return super.visitVariable(tree, ignore);418}419420@Override @DefinedBy(Api.COMPILER_TREE)421public Void visitCompilationUnit(CompilationUnitTree node, Void p) {422if (!env.shouldCheck(node)) {423return null;424}425return super.visitCompilationUnit(node, p);426}427428@Override @DefinedBy(Api.COMPILER_TREE)429public Void visitBlock(BlockTree tree, Void ignore) {430return null;431}432433@Override @DefinedBy(Api.COMPILER_TREE)434public Void visitLambdaExpression(LambdaExpressionTree tree, Void ignore) {435return null;436}437438}439440// </editor-fold>441442}443444445