Wed, 19 Dec 2012 11:29:56 +0000
8004833: Integrate doclint support into javac
Reviewed-by: mcimadamore
1.1 --- a/src/share/classes/com/sun/tools/javac/main/Main.java Tue Dec 18 18:15:47 2012 -0800 1.2 +++ b/src/share/classes/com/sun/tools/javac/main/Main.java Wed Dec 19 11:29:56 2012 +0000 1.3 @@ -44,6 +44,8 @@ 1.4 1.5 import com.sun.source.util.JavacTask; 1.6 import com.sun.source.util.Plugin; 1.7 +import com.sun.tools.doclint.DocLint; 1.8 +import com.sun.tools.javac.api.BasicJavacTask; 1.9 import com.sun.tools.javac.code.Source; 1.10 import com.sun.tools.javac.file.CacheFSInfo; 1.11 import com.sun.tools.javac.file.JavacFileManager; 1.12 @@ -428,6 +430,7 @@ 1.13 if (batchMode) 1.14 CacheFSInfo.preRegister(context); 1.15 1.16 + // FIXME: this code will not be invoked if using JavacTask.parse/analyze/generate 1.17 // invoke any available plugins 1.18 String plugins = options.get(PLUGIN); 1.19 if (plugins != null) { 1.20 @@ -464,11 +467,32 @@ 1.21 } 1.22 } 1.23 1.24 + comp = JavaCompiler.instance(context); 1.25 + 1.26 + // FIXME: this code will not be invoked if using JavacTask.parse/analyze/generate 1.27 + String xdoclint = options.get(XDOCLINT); 1.28 + String xdoclintCustom = options.get(XDOCLINT_CUSTOM); 1.29 + if (xdoclint != null || xdoclintCustom != null) { 1.30 + Set<String> doclintOpts = new LinkedHashSet<String>(); 1.31 + if (xdoclint != null) 1.32 + doclintOpts.add(DocLint.XMSGS_OPTION); 1.33 + if (xdoclintCustom != null) { 1.34 + for (String s: xdoclintCustom.split("\\s+")) { 1.35 + if (s.isEmpty()) 1.36 + continue; 1.37 + doclintOpts.add(s.replace(XDOCLINT_CUSTOM.text, DocLint.XMSGS_CUSTOM_PREFIX)); 1.38 + } 1.39 + } 1.40 + if (!(doclintOpts.size() == 1 1.41 + && doclintOpts.iterator().next().equals(DocLint.XMSGS_CUSTOM_PREFIX + "none"))) { 1.42 + JavacTask t = BasicJavacTask.instance(context); 1.43 + new DocLint().init(t, doclintOpts.toArray(new String[doclintOpts.size()])); 1.44 + comp.keepComments = true; 1.45 + } 1.46 + } 1.47 + 1.48 fileManager = context.get(JavaFileManager.class); 1.49 1.50 - comp = JavaCompiler.instance(context); 1.51 - if (comp == null) return Result.SYSERR; 1.52 - 1.53 if (!files.isEmpty()) { 1.54 // add filenames to fileObjects 1.55 comp = JavaCompiler.instance(context);
2.1 --- a/src/share/classes/com/sun/tools/javac/main/Option.java Tue Dec 18 18:15:47 2012 -0800 2.2 +++ b/src/share/classes/com/sun/tools/javac/main/Option.java Wed Dec 19 11:29:56 2012 +0000 2.3 @@ -25,28 +25,30 @@ 2.4 2.5 package com.sun.tools.javac.main; 2.6 2.7 +import java.io.File; 2.8 +import java.io.FileWriter; 2.9 +import java.io.PrintWriter; 2.10 import java.util.Collections; 2.11 -import com.sun.tools.javac.util.Log.PrefixKind; 2.12 -import com.sun.tools.javac.util.Log.WriterKind; 2.13 -import com.sun.tools.javac.util.Log; 2.14 +import java.util.EnumSet; 2.15 +import java.util.LinkedHashMap; 2.16 +import java.util.Map; 2.17 +import java.util.Set; 2.18 + 2.19 +import javax.lang.model.SourceVersion; 2.20 + 2.21 +import com.sun.tools.doclint.DocLint; 2.22 import com.sun.tools.javac.code.Lint; 2.23 import com.sun.tools.javac.code.Source; 2.24 import com.sun.tools.javac.code.Type; 2.25 import com.sun.tools.javac.jvm.Target; 2.26 +import com.sun.tools.javac.processing.JavacProcessingEnvironment; 2.27 +import com.sun.tools.javac.util.Log; 2.28 +import com.sun.tools.javac.util.Log.PrefixKind; 2.29 +import com.sun.tools.javac.util.Log.WriterKind; 2.30 import com.sun.tools.javac.util.Options; 2.31 -import com.sun.tools.javac.processing.JavacProcessingEnvironment; 2.32 -import java.io.File; 2.33 -import java.io.FileWriter; 2.34 -import java.io.PrintWriter; 2.35 -import java.util.EnumSet; 2.36 -import java.util.LinkedHashMap; 2.37 -import java.util.Map; 2.38 -import java.util.Set; 2.39 -import javax.lang.model.SourceVersion; 2.40 - 2.41 import static com.sun.tools.javac.main.Option.ChoiceKind.*; 2.42 +import static com.sun.tools.javac.main.Option.OptionGroup.*; 2.43 import static com.sun.tools.javac.main.Option.OptionKind.*; 2.44 -import static com.sun.tools.javac.main.Option.OptionGroup.*; 2.45 2.46 /** 2.47 * Options for javac. The specific Option to handle a command-line option 2.48 @@ -79,6 +81,24 @@ 2.49 XLINT_CUSTOM("-Xlint:", "opt.Xlint.suboptlist", 2.50 EXTENDED, BASIC, ANYOF, getXLintChoices()), 2.51 2.52 + XDOCLINT("-Xdoclint", "opt.Xdoclint", EXTENDED, BASIC), 2.53 + 2.54 + XDOCLINT_CUSTOM("-Xdoclint:", "opt.Xdoclint.subopts", "opt.Xdoclint.custom", EXTENDED, BASIC) { 2.55 + @Override 2.56 + public boolean matches(String option) { 2.57 + return DocLint.isValidOption( 2.58 + option.replace(XDOCLINT_CUSTOM.text, DocLint.XMSGS_CUSTOM_PREFIX)); 2.59 + } 2.60 + 2.61 + @Override 2.62 + public boolean process(OptionHelper helper, String option) { 2.63 + String prev = helper.get(XDOCLINT_CUSTOM); 2.64 + String next = (prev == null) ? option : (prev + " " + option); 2.65 + helper.put(XDOCLINT_CUSTOM.text, next); 2.66 + return false; 2.67 + } 2.68 + }, 2.69 + 2.70 // -nowarn is retained for command-line backward compatibility 2.71 NOWARN("-nowarn", "opt.nowarn", STANDARD, BASIC) { 2.72 @Override
3.1 --- a/src/share/classes/com/sun/tools/javac/resources/javac.properties Tue Dec 18 18:15:47 2012 -0800 3.2 +++ b/src/share/classes/com/sun/tools/javac/resources/javac.properties Wed Dec 19 11:29:56 2012 +0000 3.3 @@ -138,6 +138,14 @@ 3.4 Enable recommended warnings 3.5 javac.opt.Xlint.suboptlist=\ 3.6 Enable or disable specific warnings 3.7 +javac.opt.Xdoclint=\ 3.8 + Enable recommended checks for problems in javadoc comments 3.9 +javac.opt.Xdoclint.subopts = \ 3.10 + (all|[-]<group>)[/<access>] 3.11 +javac.opt.Xdoclint.custom=\n\ 3.12 +\ Enable or disable specific checks for problems in javadoc comments,\n\ 3.13 +\ where <group> is one of accessibility, html, reference, or syntax,\n\ 3.14 +\ and <access> is one of public, protected, package, or private. 3.15 javac.opt.Xstdout=\ 3.16 Redirect standard output 3.17 javac.opt.X=\
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/test/tools/javac/doclint/DocLintTest.java Wed Dec 19 11:29:56 2012 +0000 4.3 @@ -0,0 +1,225 @@ 4.4 +/* 4.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4.7 + * 4.8 + * This code is free software; you can redistribute it and/or modify it 4.9 + * under the terms of the GNU General Public License version 2 only, as 4.10 + * published by the Free Software Foundation. 4.11 + * 4.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 4.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 4.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 4.15 + * version 2 for more details (a copy is included in the LICENSE file that 4.16 + * accompanied this code). 4.17 + * 4.18 + * You should have received a copy of the GNU General Public License version 4.19 + * 2 along with this work; if not, write to the Free Software Foundation, 4.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 4.21 + * 4.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 4.23 + * or visit www.oracle.com if you need additional information or have any 4.24 + * questions. 4.25 + */ 4.26 + 4.27 +/* 4.28 + * @test 4.29 + * @bug 8004833 4.30 + * @summary Integrate doclint support into javac 4.31 + */ 4.32 + 4.33 +import java.io.File; 4.34 +import java.io.PrintWriter; 4.35 +import java.io.StringWriter; 4.36 +import java.net.URI; 4.37 +import java.util.Arrays; 4.38 +import java.util.Collections; 4.39 +import java.util.List; 4.40 + 4.41 +import javax.tools.Diagnostic; 4.42 +import javax.tools.JavaCompiler; 4.43 +import javax.tools.JavaFileObject; 4.44 +import javax.tools.SimpleJavaFileObject; 4.45 +import javax.tools.StandardJavaFileManager; 4.46 +import javax.tools.StandardLocation; 4.47 +import javax.tools.ToolProvider; 4.48 +import static javax.tools.Diagnostic.Kind.*; 4.49 + 4.50 +import com.sun.source.util.JavacTask; 4.51 +import com.sun.tools.javac.main.Main; 4.52 +import java.util.EnumSet; 4.53 +import java.util.Set; 4.54 +import java.util.regex.Matcher; 4.55 +import java.util.regex.Pattern; 4.56 + 4.57 +public class DocLintTest { 4.58 + public static void main(String... args) throws Exception { 4.59 + new DocLintTest().run(); 4.60 + } 4.61 + 4.62 + JavaCompiler javac; 4.63 + StandardJavaFileManager fm; 4.64 + JavaFileObject file; 4.65 + 4.66 + final String code = 4.67 + /* 01 */ "/** Class comment. */\n" + 4.68 + /* 02 */ "public class Test {\n" + 4.69 + /* 03 */ " /** Method comment. */\n" + 4.70 + /* 04 */ " public void method() { }\n" + 4.71 + /* 05 */ "\n" + 4.72 + /* 06 */ " /** Syntax < error. */\n" + 4.73 + /* 07 */ " private void syntaxError() { }\n" + 4.74 + /* 08 */ "\n" + 4.75 + /* 09 */ " /** @see DoesNotExist */\n" + 4.76 + /* 10 */ " protected void referenceError() { }\n" + 4.77 + /* 08 */ "\n" + 4.78 + /* 09 */ " /** @return */\n" + 4.79 + /* 10 */ " public int emptyReturn() { return 0; }\n" + 4.80 + /* 11 */ "}\n"; 4.81 + 4.82 + final String rawDiags = "-XDrawDiagnostics"; 4.83 + private enum Message { 4.84 + // doclint messages 4.85 + DL_ERR6(ERROR, "Test.java:6:16: compiler.err.proc.messager: malformed HTML"), 4.86 + DL_ERR9(ERROR, "Test.java:9:14: compiler.err.proc.messager: reference not found"), 4.87 + DL_WRN12(WARNING, "Test.java:12:9: compiler.warn.proc.messager: no description for @return"), 4.88 + 4.89 + OPT_BADARG(ERROR, "invalid flag: -Xdoclint:badarg"); 4.90 + 4.91 + final Diagnostic.Kind kind; 4.92 + final String text; 4.93 + 4.94 + static Message get(String text) { 4.95 + for (Message m: values()) { 4.96 + if (m.text.equals(text)) 4.97 + return m; 4.98 + } 4.99 + return null; 4.100 + } 4.101 + 4.102 + Message(Diagnostic.Kind kind, String text) { 4.103 + this.kind = kind; 4.104 + this.text = text; 4.105 + } 4.106 + 4.107 + @Override 4.108 + public String toString() { 4.109 + return "[" + kind + ",\"" + text + "\"]"; 4.110 + } 4.111 + } 4.112 + void run() throws Exception { 4.113 + javac = ToolProvider.getSystemJavaCompiler(); 4.114 + fm = javac.getStandardFileManager(null, null, null); 4.115 + fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File("."))); 4.116 + file = new SimpleJavaFileObject(URI.create("Test.java"), JavaFileObject.Kind.SOURCE) { 4.117 + @Override 4.118 + public CharSequence getCharContent(boolean ignoreEncoding) { 4.119 + return code; 4.120 + } 4.121 + }; 4.122 + 4.123 + test(Collections.<String>emptyList(), 4.124 + Main.Result.OK, 4.125 + EnumSet.noneOf(Message.class)); 4.126 + 4.127 + test(Arrays.asList("-Xdoclint:none"), 4.128 + Main.Result.OK, 4.129 + EnumSet.noneOf(Message.class)); 4.130 + 4.131 + test(Arrays.asList(rawDiags, "-Xdoclint"), 4.132 + Main.Result.ERROR, 4.133 + EnumSet.of(Message.DL_ERR6, Message.DL_ERR9, Message.DL_WRN12)); 4.134 + 4.135 + test(Arrays.asList(rawDiags, "-Xdoclint:all/public"), 4.136 + Main.Result.OK, 4.137 + EnumSet.of(Message.DL_WRN12)); 4.138 + 4.139 + test(Arrays.asList(rawDiags, "-Xdoclint:syntax"), 4.140 + Main.Result.ERROR, 4.141 + EnumSet.of(Message.DL_ERR6, Message.DL_WRN12)); 4.142 + 4.143 + test(Arrays.asList(rawDiags, "-Xdoclint:reference"), 4.144 + Main.Result.ERROR, 4.145 + EnumSet.of(Message.DL_ERR9)); 4.146 + 4.147 + test(Arrays.asList(rawDiags, "-Xdoclint:badarg"), 4.148 + Main.Result.CMDERR, 4.149 + EnumSet.of(Message.OPT_BADARG)); 4.150 + 4.151 + if (errors > 0) 4.152 + throw new Exception(errors + " errors occurred"); 4.153 + } 4.154 + 4.155 + void test(List<String> opts, Main.Result expectResult, Set<Message> expectMessages) { 4.156 + System.err.println("test: " + opts); 4.157 + StringWriter sw = new StringWriter(); 4.158 + PrintWriter pw = new PrintWriter(sw); 4.159 + List<JavaFileObject> files = Arrays.asList(file); 4.160 + try { 4.161 + JavacTask t = (JavacTask) javac.getTask(pw, fm, null, opts, null, files); 4.162 + boolean ok = t.call(); 4.163 + pw.close(); 4.164 + String out = sw.toString().replaceAll("[\r\n]+", "\n"); 4.165 + if (!out.isEmpty()) 4.166 + System.err.println(out); 4.167 + if (ok && expectResult != Main.Result.OK) { 4.168 + error("Compilation succeeded unexpectedly"); 4.169 + } else if (!ok && expectResult != Main.Result.ERROR) { 4.170 + error("Compilation failed unexpectedly"); 4.171 + } else 4.172 + check(out, expectMessages); 4.173 + } catch (IllegalArgumentException e) { 4.174 + System.err.println(e); 4.175 + String expectOut = expectMessages.iterator().next().text; 4.176 + if (expectResult != Main.Result.CMDERR) 4.177 + error("unexpected exception caught"); 4.178 + else if (!e.getMessage().equals(expectOut)) { 4.179 + error("unexpected exception message: " 4.180 + + e.getMessage() 4.181 + + " expected: " + expectOut); 4.182 + } 4.183 + } 4.184 + 4.185 +// if (errors > 0) 4.186 +// throw new Error("stop"); 4.187 + } 4.188 + 4.189 + private void check(String out, Set<Message> expect) { 4.190 + Pattern stats = Pattern.compile("^([1-9]+) (error|warning)(s?)"); 4.191 + Set<Message> found = EnumSet.noneOf(Message.class); 4.192 + int e = 0, w = 0; 4.193 + if (!out.isEmpty()) { 4.194 + for (String line: out.split("[\r\n]+")) { 4.195 + Matcher s = stats.matcher(line); 4.196 + if (s.matches()) { 4.197 + int i = Integer.valueOf(s.group(1)); 4.198 + if (s.group(2).equals("error")) 4.199 + e++; 4.200 + else 4.201 + w++; 4.202 + continue; 4.203 + } 4.204 + 4.205 + Message m = Message.get(line); 4.206 + if (m == null) 4.207 + error("Unexpected line: " + line); 4.208 + else 4.209 + found.add(m); 4.210 + } 4.211 + } 4.212 + for (Message m: expect) { 4.213 + if (!found.contains(m)) 4.214 + error("expected message not found: " + m.text); 4.215 + } 4.216 + for (Message m: found) { 4.217 + if (!expect.contains(m)) 4.218 + error("unexpected message found: " + m.text); 4.219 + } 4.220 + } 4.221 + 4.222 + void error(String msg) { 4.223 + System.err.println("Error: " + msg); 4.224 + errors++; 4.225 + } 4.226 + 4.227 + int errors; 4.228 +}