8151102: Cleanup javadoc exception handling

Reviewed-by: jjg
This commit is contained in:
Kumar Srinivasan 2016-10-10 06:47:47 -07:00
parent a53b8b8a5d
commit 6f16c4713d
39 changed files with 881 additions and 568 deletions

View file

@ -40,7 +40,6 @@ import jdk.javadoc.internal.doclets.toolkit.builders.AbstractBuilder;
import jdk.javadoc.internal.doclets.toolkit.builders.BuilderFactory; import jdk.javadoc.internal.doclets.toolkit.builders.BuilderFactory;
import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
import jdk.javadoc.internal.doclets.toolkit.util.InternalException; import jdk.javadoc.internal.doclets.toolkit.util.InternalException;
import jdk.javadoc.internal.doclets.toolkit.util.PackageListWriter; import jdk.javadoc.internal.doclets.toolkit.util.PackageListWriter;
import jdk.javadoc.internal.doclets.toolkit.util.ResourceIOException; import jdk.javadoc.internal.doclets.toolkit.util.ResourceIOException;
@ -112,8 +111,6 @@ public abstract class AbstractDoclet implements Doclet {
return false; return false;
} }
boolean dumpOnError = false; // set true to always show stack traces
try { try {
startGeneration(docEnv); startGeneration(docEnv);
return true; return true;
@ -128,16 +125,16 @@ public abstract class AbstractDoclet implements Doclet {
messages.error("doclet.exception.write.file", messages.error("doclet.exception.write.file",
e.fileName.getPath(), e.getCause()); e.fileName.getPath(), e.getCause());
} }
dumpStack(dumpOnError, e); dumpStack(configuration.dumpOnError, e);
} catch (ResourceIOException e) { } catch (ResourceIOException e) {
messages.error("doclet.exception.read.resource", messages.error("doclet.exception.read.resource",
e.resource.getPath(), e.getCause()); e.resource.getPath(), e.getCause());
dumpStack(dumpOnError, e); dumpStack(configuration.dumpOnError, e);
} catch (SimpleDocletException e) { } catch (SimpleDocletException e) {
configuration.reporter.print(ERROR, e.getMessage()); configuration.reporter.print(ERROR, e.getMessage());
dumpStack(dumpOnError, e); dumpStack(configuration.dumpOnError, e);
} catch (InternalException e) { } catch (InternalException e) {
configuration.reporter.print(ERROR, e.getMessage()); configuration.reporter.print(ERROR, e.getMessage());

View file

@ -281,6 +281,8 @@ public abstract class Configuration {
private String pkglistUrlForLinkOffline; private String pkglistUrlForLinkOffline;
public boolean dumpOnError = false;
private List<GroupContainer> groups; private List<GroupContainer> groups;
public abstract Messages getMessages(); public abstract Messages getMessages();
@ -616,6 +618,13 @@ public abstract class Configuration {
showversion = true; showversion = true;
return true; return true;
} }
},
new Hidden(resources, "--dump-on-error") {
@Override
public boolean process(String opt, ListIterator<String> args) {
dumpOnError = true;
return true;
}
} }
}; };
Set<Doclet.Option> set = new TreeSet<>(); Set<Doclet.Option> set = new TreeSet<>();

View file

@ -75,6 +75,7 @@ import jdk.javadoc.doclet.DocletEnvironment;
import jdk.javadoc.doclet.DocletEnvironment.ModuleMode; import jdk.javadoc.doclet.DocletEnvironment.ModuleMode;
import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
import static jdk.javadoc.internal.tool.Main.Result.*;
import static jdk.javadoc.internal.tool.JavadocTool.isValidClassName; import static jdk.javadoc.internal.tool.JavadocTool.isValidClassName;
/** /**
@ -158,6 +159,7 @@ public class ElementsTable {
private final Location location; private final Location location;
private final Modules modules; private final Modules modules;
private final Map<ToolOption, Object> opts; private final Map<ToolOption, Object> opts;
private final Messager messager;
private final Map<String, Entry> entries = new LinkedHashMap<>(); private final Map<String, Entry> entries = new LinkedHashMap<>();
@ -201,6 +203,8 @@ public class ElementsTable {
this.fm = toolEnv.fileManager; this.fm = toolEnv.fileManager;
this.modules = Modules.instance(context); this.modules = Modules.instance(context);
this.opts = opts; this.opts = opts;
this.messager = Messager.instance0(context);
this.location = modules.multiModuleMode this.location = modules.multiModuleMode
? StandardLocation.MODULE_SOURCE_PATH ? StandardLocation.MODULE_SOURCE_PATH
: toolEnv.fileManager.hasLocation(StandardLocation.SOURCE_PATH) : toolEnv.fileManager.hasLocation(StandardLocation.SOURCE_PATH)
@ -339,9 +343,9 @@ public class ElementsTable {
* This is a terminal operation, thus no further modifications * This is a terminal operation, thus no further modifications
* are allowed to the specified data sets. * are allowed to the specified data sets.
* *
* @throws IOException if an error occurs * @throws ToolException if an error occurs
*/ */
void analyze() throws IOException { void analyze() throws ToolException {
// compute the specified element, by expanding module dependencies // compute the specified element, by expanding module dependencies
computeSpecifiedModules(); computeSpecifiedModules();
@ -354,7 +358,6 @@ public class ElementsTable {
// compute the packages belonging to all the specified modules // compute the packages belonging to all the specified modules
Set<PackageElement> expandedModulePackages = computeModulePackages(); Set<PackageElement> expandedModulePackages = computeModulePackages();
initializeIncludedSets(expandedModulePackages); initializeIncludedSets(expandedModulePackages);
} }
ElementsTable classTrees(com.sun.tools.javac.util.List<JCCompilationUnit> classTrees) { ElementsTable classTrees(com.sun.tools.javac.util.List<JCCompilationUnit> classTrees) {
@ -363,16 +366,17 @@ public class ElementsTable {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ElementsTable scanSpecifiedItems() throws IOException { ElementsTable scanSpecifiedItems() throws ToolException {
// scan modules specified on the command line // scan modules specified on the command line
List<String> moduleNames = (List<String>) opts.computeIfAbsent(ToolOption.MODULE, List<String> moduleNames = (List<String>) opts.computeIfAbsent(ToolOption.MODULE,
s -> Collections.EMPTY_LIST); s -> Collections.EMPTY_LIST);
List<String> mlist = new ArrayList<>(); List<String> mlist = new ArrayList<>();
for (String m : moduleNames) { for (String m : moduleNames) {
Location moduleLoc = fm.getModuleLocation(location, m); Location moduleLoc = getModuleLocation(location, m);
if (moduleLoc == null) { if (moduleLoc == null) {
toolEnv.error("main.module_not_found", m); String text = messager.getText("main.module_not_found", m);
throw new ToolException(CMDERR, text);
} else { } else {
mlist.add(m); mlist.add(m);
ModuleSymbol msym = syms.enterModule(names.fromString(m)); ModuleSymbol msym = syms.enterModule(names.fromString(m));
@ -457,7 +461,7 @@ public class ElementsTable {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void computeSubpackages() throws IOException { private void computeSubpackages() throws ToolException {
((List<String>) opts.computeIfAbsent(ToolOption.EXCLUDE, v -> Collections.EMPTY_LIST)) ((List<String>) opts.computeIfAbsent(ToolOption.EXCLUDE, v -> Collections.EMPTY_LIST))
.stream() .stream()
.map((packageName) -> new ModulePackage(packageName)) .map((packageName) -> new ModulePackage(packageName))
@ -469,7 +473,14 @@ public class ElementsTable {
for (ModulePackage modpkg : subPackages) { for (ModulePackage modpkg : subPackages) {
Location packageLocn = getLocation(modpkg); Location packageLocn = getLocation(modpkg);
for (JavaFileObject fo : fm.list(packageLocn, modpkg.packageName, sourceKinds, true)) { Iterable<JavaFileObject> list = null;
try {
list = fm.list(packageLocn, modpkg.packageName, sourceKinds, true);
} catch (IOException ioe) {
String text = messager.getText("main.file.manager.list", modpkg.packageName);
throw new ToolException(SYSERR, text, ioe);
}
for (JavaFileObject fo : list) {
String binaryName = fm.inferBinaryName(packageLocn, fo); String binaryName = fm.inferBinaryName(packageLocn, fo);
String pn = getPackageName(binaryName); String pn = getPackageName(binaryName);
String simpleName = getSimpleName(binaryName); String simpleName = getSimpleName(binaryName);
@ -554,22 +565,28 @@ public class ElementsTable {
specifiedModuleElements = Collections.unmodifiableSet(result); specifiedModuleElements = Collections.unmodifiableSet(result);
} }
private Set<PackageElement> getAllModulePackages(ModuleElement mdle) throws IOException { private Set<PackageElement> getAllModulePackages(ModuleElement mdle) throws ToolException {
Set<PackageElement> result = new HashSet<>(); Set<PackageElement> result = new HashSet<>();
ModuleSymbol msym = (ModuleSymbol)mdle; ModuleSymbol msym = (ModuleSymbol) mdle;
Location msymloc = fm.getModuleLocation(location, msym.name.toString()); Location msymloc = getModuleLocation(location, msym.name.toString());
for (JavaFileObject fo : fm.list(msymloc, "", sourceKinds, true)) { try {
if (fo.getName().endsWith("module-info.java")) for (JavaFileObject fo : fm.list(msymloc, "", sourceKinds, true)) {
continue; if (fo.getName().endsWith("module-info.java"))
String binaryName = fm.inferBinaryName(msymloc, fo); continue;
String pn = getPackageName(binaryName); String binaryName = fm.inferBinaryName(msymloc, fo);
PackageSymbol psym = syms.enterPackage(msym, names.fromString(pn)); String pn = getPackageName(binaryName);
result.add((PackageElement)psym); PackageSymbol psym = syms.enterPackage(msym, names.fromString(pn));
result.add((PackageElement) psym);
}
} catch (IOException ioe) {
String text = messager.getText("main.file.manager.list", msymloc.getName());
throw new ToolException(SYSERR, text, ioe);
} }
return result; return result;
} }
private Set<PackageElement> computeModulePackages() throws IOException { private Set<PackageElement> computeModulePackages() throws ToolException {
final AccessKind accessValue = accessFilter.getAccessValue(ElementKind.PACKAGE); final AccessKind accessValue = accessFilter.getAccessValue(ElementKind.PACKAGE);
final boolean documentAllModulePackages = (accessValue == AccessKind.PACKAGE || final boolean documentAllModulePackages = (accessValue == AccessKind.PACKAGE ||
accessValue == AccessKind.PRIVATE); accessValue == AccessKind.PRIVATE);
@ -662,10 +679,10 @@ public class ElementsTable {
includedTypeElements = Collections.unmodifiableSet(iclasses); includedTypeElements = Collections.unmodifiableSet(iclasses);
} }
/** /*
* Computes the included packages and freezes the specified packages list. * Computes the included packages and freezes the specified packages list.
*/ */
private void computeSpecifiedPackages() throws IOException { private void computeSpecifiedPackages() throws ToolException {
computeSubpackages(); computeSubpackages();
@ -683,7 +700,7 @@ public class ElementsTable {
if (pkg != null) { if (pkg != null) {
packlist.add(pkg); packlist.add(pkg);
} else { } else {
toolEnv.warning("main.package_not_found", modpkg.toString()); messager.printWarningUsingKey("main.package_not_found", modpkg.toString());
} }
}); });
specifiedPackageElements = Collections.unmodifiableSet(packlist); specifiedPackageElements = Collections.unmodifiableSet(packlist);
@ -693,7 +710,7 @@ public class ElementsTable {
* Adds all classes as well as inner classes, to the specified * Adds all classes as well as inner classes, to the specified
* list. * list.
*/ */
private void computeSpecifiedTypes() { private void computeSpecifiedTypes() throws ToolException {
Set<TypeElement> classes = new LinkedHashSet<>(); Set<TypeElement> classes = new LinkedHashSet<>();
classDecList.stream().filter((def) -> (shouldDocument(def.sym))).forEach((def) -> { classDecList.stream().filter((def) -> (shouldDocument(def.sym))).forEach((def) -> {
TypeElement te = (TypeElement) def.sym; TypeElement te = (TypeElement) def.sym;
@ -701,24 +718,28 @@ public class ElementsTable {
addAllClasses(classes, te, true); addAllClasses(classes, te, true);
} }
}); });
classArgList.forEach((className) -> { for (String className : classArgList) {
TypeElement te = toolEnv.loadClass(className); TypeElement te = toolEnv.loadClass(className);
if (te == null) { if (te == null) {
toolEnv.error("javadoc.class_not_found", className); String text = messager.getText("javadoc.class_not_found", className);
throw new ToolException(CMDERR, text);
} else { } else {
addAllClasses(classes, te, true); addAllClasses(classes, te, true);
} }
}); }
specifiedTypeElements = Collections.unmodifiableSet(classes); specifiedTypeElements = Collections.unmodifiableSet(classes);
} }
private void addFilesForParser(Collection<JavaFileObject> result, private void addFilesForParser(Collection<JavaFileObject> result,
Collection<ModulePackage> collection, boolean recurse) throws IOException { Collection<ModulePackage> collection,
boolean recurse) throws ToolException {
for (ModulePackage modpkg : collection) { for (ModulePackage modpkg : collection) {
toolEnv.notice("main.Loading_source_files_for_package", modpkg.toString()); toolEnv.notice("main.Loading_source_files_for_package", modpkg.toString());
List<JavaFileObject> files = getFiles(modpkg, recurse); List<JavaFileObject> files = getFiles(modpkg, recurse);
if (files.isEmpty()) { if (files.isEmpty()) {
toolEnv.error("main.no_source_files_for_package", modpkg.toString()); String text = messager.getText("main.no_source_files_for_package",
modpkg.toString());
throw new ToolException(CMDERR, text);
} else { } else {
result.addAll(files); result.addAll(files);
} }
@ -732,7 +753,7 @@ public class ElementsTable {
* @return a list of java file objects * @return a list of java file objects
* @throws IOException if an error occurs * @throws IOException if an error occurs
*/ */
List<JavaFileObject> getFilesToParse() throws IOException { List<JavaFileObject> getFilesToParse() throws ToolException {
List<JavaFileObject> result = new ArrayList<>(); List<JavaFileObject> result = new ArrayList<>();
addFilesForParser(result, cmdLinePackages, false); addFilesForParser(result, cmdLinePackages, false);
addFilesForParser(result, subPackages, true); addFilesForParser(result, subPackages, true);
@ -744,9 +765,10 @@ public class ElementsTable {
* *
* @param packageName the specified package * @param packageName the specified package
* @return the set of file objects for the specified package * @return the set of file objects for the specified package
* @throws IOException if an error occurs while accessing the files * @throws ToolException if an error occurs while accessing the files
*/ */
private List<JavaFileObject> getFiles(ModulePackage modpkg, boolean recurse) throws IOException { private List<JavaFileObject> getFiles(ModulePackage modpkg,
boolean recurse) throws ToolException {
Entry e = getEntry(modpkg); Entry e = getEntry(modpkg);
// The files may have been found as a side effect of searching for subpackages // The files may have been found as a side effect of searching for subpackages
if (e.files != null) { if (e.files != null) {
@ -759,12 +781,18 @@ public class ElementsTable {
return Collections.emptyList(); return Collections.emptyList();
} }
String pname = modpkg.packageName; String pname = modpkg.packageName;
for (JavaFileObject fo : fm.list(packageLocn, pname, sourceKinds, recurse)) {
String binaryName = fm.inferBinaryName(packageLocn, fo); try {
String simpleName = getSimpleName(binaryName); for (JavaFileObject fo : fm.list(packageLocn, pname, sourceKinds, recurse)) {
if (isValidClassName(simpleName)) { String binaryName = fm.inferBinaryName(packageLocn, fo);
lb.append(fo); String simpleName = getSimpleName(binaryName);
if (isValidClassName(simpleName)) {
lb.append(fo);
}
} }
} catch (IOException ioe) {
String text = messager.getText("main.file.manager.list", pname);
throw new ToolException(SYSERR, text, ioe);
} }
return lb.toList(); return lb.toList();
@ -781,20 +809,30 @@ public class ElementsTable {
return null; return null;
} }
private Location getLocation(ModulePackage modpkg) throws IOException { private Location getLocation(ModulePackage modpkg) throws ToolException {
if (location != StandardLocation.MODULE_SOURCE_PATH) { if (location != StandardLocation.MODULE_SOURCE_PATH) {
return location; return location;
} }
if (modpkg.hasModule()) { if (modpkg.hasModule()) {
return fm.getModuleLocation(location, modpkg.moduleName); return getModuleLocation(location, modpkg.moduleName);
} }
// TODO: handle invalid results better. // TODO: handle invalid results better.
ModuleSymbol msym = findModuleOfPackageName(modpkg.packageName); ModuleSymbol msym = findModuleOfPackageName(modpkg.packageName);
if (msym == null) { if (msym == null) {
return null; return null;
} }
return fm.getModuleLocation(location, msym.name.toString()); return getModuleLocation(location, msym.name.toString());
}
private Location getModuleLocation(Location location, String msymName)
throws ToolException {
try {
return fm.getModuleLocation(location, msymName);
} catch (IOException ioe) {
String text = messager.getText("main.doclet_could_not_get_location", msymName);
throw new ToolException(ERROR, text, ioe);
}
} }
private Entry getEntry(String name) { private Entry getEntry(String name) {
@ -841,7 +879,10 @@ public class ElementsTable {
} }
} }
} catch (CompletionFailure e) { } catch (CompletionFailure e) {
// quietly ignore completion failures if (e.getMessage() != null)
messager.printWarning(e.getMessage());
else
messager.printWarningUsingKey("main.unexpected.exception", e);
} }
} }

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.javadoc.internal.tool;
import static jdk.javadoc.internal.tool.Main.Result.CMDERR;
/**
* Provides a mechanism for the javadoc tool to indicate an option
* decoding issue, arising from command line error.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
class IllegalOptionValue extends OptionException {
private static final long serialVersionUID = 0;
/**
* Constructs an object containing a runnable and a message.
* @param method a method to display suitable usage text
* @param message the detailed message
*/
IllegalOptionValue(Runnable method, String message) {
super(CMDERR, method, message);
}
}

View file

@ -27,7 +27,6 @@ package jdk.javadoc.internal.tool;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
@ -51,6 +50,8 @@ import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Position; import com.sun.tools.javac.util.Position;
import jdk.javadoc.doclet.DocletEnvironment; import jdk.javadoc.doclet.DocletEnvironment;
import static jdk.javadoc.internal.tool.Main.Result.*;
/** /**
* This class could be the main entry point for Javadoc when Javadoc is used as a * This class could be the main entry point for Javadoc when Javadoc is used as a
* component in a larger software system. It provides operations to * component in a larger software system. It provides operations to
@ -120,9 +121,10 @@ public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler {
} }
} }
public DocletEnvironment getEnvironment(Map<ToolOption, Object> jdtoolOpts, public DocletEnvironment getEnvironment(Map<ToolOption,
List<String> javaNames, Object> jdtoolOpts,
Iterable<? extends JavaFileObject> fileObjects) throws IOException { List<String> javaNames,
Iterable<? extends JavaFileObject> fileObjects) throws ToolException {
toolEnv = ToolEnvironment.instance(context); toolEnv = ToolEnvironment.instance(context);
toolEnv.initialize(jdtoolOpts); toolEnv.initialize(jdtoolOpts);
ElementsTable etable = new ElementsTable(context, jdtoolOpts); ElementsTable etable = new ElementsTable(context, jdtoolOpts);
@ -133,10 +135,12 @@ public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler {
if (etable.xclasses) { if (etable.xclasses) {
// If -Xclasses is set, the args should be a list of class names // If -Xclasses is set, the args should be a list of class names
for (String arg: javaNames) { for (String arg: javaNames) {
if (!isValidPackageName(arg)) // checks if (!isValidPackageName(arg)) { // checks
toolEnv.error("main.illegal_class_name", arg); String text = messager.getText("main.illegal_class_name", arg);
throw new ToolException(CMDERR, text);
}
} }
if (messager.nerrors() != 0) { if (messager.hasErrors()) {
return null; return null;
} }
etable.setClassArgList(javaNames); etable.setClassArgList(javaNames);
@ -157,19 +161,23 @@ public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler {
for (String arg: javaNames) { for (String arg: javaNames) {
if (fm != null && arg.endsWith(".java") && new File(arg).exists()) { if (fm != null && arg.endsWith(".java") && new File(arg).exists()) {
if (new File(arg).getName().equals("module-info.java")) { if (new File(arg).getName().equals("module-info.java")) {
toolEnv.warning("main.file_ignored", arg); messager.printWarningUsingKey("main.file_ignored", arg);
} else { } else {
parse(fm.getJavaFileObjects(arg), classTrees, true); parse(fm.getJavaFileObjects(arg), classTrees, true);
} }
} else if (isValidPackageName(arg)) { } else if (isValidPackageName(arg)) {
packageNames.add(arg); packageNames.add(arg);
} else if (arg.endsWith(".java")) { } else if (arg.endsWith(".java")) {
if (fm == null) if (fm == null) {
throw new IllegalArgumentException(); String text = messager.getText("main.assertion.error", "fm == null");
else throw new ToolException(ABNORMAL, text);
toolEnv.error("main.file_not_found", arg); } else {
String text = messager.getText("main.file_not_found", arg);
throw new ToolException(ERROR, text);
}
} else { } else {
toolEnv.error("main.illegal_package_name", arg); String text = messager.getText("main.illegal_package_name", arg);
throw new ToolException(CMDERR, text);
} }
} }
@ -185,7 +193,7 @@ public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler {
parse(etable.getFilesToParse(), packageTrees, false); parse(etable.getFilesToParse(), packageTrees, false);
modules.enter(packageTrees.toList(), null); modules.enter(packageTrees.toList(), null);
if (messager.nerrors() != 0) { if (messager.hasErrors()) {
return null; return null;
} }
@ -197,10 +205,19 @@ public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler {
enterDone = true; enterDone = true;
etable.analyze(); etable.analyze();
} catch (CompletionFailure cf) { } catch (CompletionFailure cf) {
toolEnv.printError(cf.getMessage()); throw new ToolException(ABNORMAL, cf.getMessage(), cf);
} catch (Abort ex) {} } catch (Abort abort) {
if (messager.hasErrors()) {
// presumably a message has been emitted, keep silent
throw new ToolException(ABNORMAL, "", abort);
} else {
String text = messager.getText("main.internal.error");
Throwable t = abort.getCause() == null ? abort : abort.getCause();
throw new ToolException(ABNORMAL, text, t);
}
}
if (messager.nerrors() != 0) if (messager.hasErrors())
return null; return null;
toolEnv.docEnv = new DocEnvImpl(toolEnv, etable); toolEnv.docEnv = new DocEnvImpl(toolEnv, etable);

View file

@ -60,7 +60,7 @@ public class Main {
*/ */
public static int execute(String... args) { public static int execute(String... args) {
Start jdoc = new Start(); Start jdoc = new Start();
return jdoc.begin(args); return jdoc.begin(args).exitCode;
} }
/** /**
@ -72,7 +72,7 @@ public class Main {
*/ */
public static int execute(String[] args, PrintWriter writer) { public static int execute(String[] args, PrintWriter writer) {
Start jdoc = new Start(writer, writer); Start jdoc = new Start(writer, writer);
return jdoc.begin(args); return jdoc.begin(args).exitCode;
} }
/** /**
@ -85,6 +85,36 @@ public class Main {
*/ */
public static int execute(String[] args, PrintWriter outWriter, PrintWriter errWriter) { public static int execute(String[] args, PrintWriter outWriter, PrintWriter errWriter) {
Start jdoc = new Start(outWriter, errWriter); Start jdoc = new Start(outWriter, errWriter);
return jdoc.begin(args); return jdoc.begin(args).exitCode;
}
public static enum Result {
/** completed with no errors */
OK(0),
/** Completed with reported errors */
ERROR(1),
/** Bad command-line arguments */
CMDERR(2),
/** System error or resource exhaustion */
SYSERR(3),
/** Terminated abnormally */
ABNORMAL(4);
private static final long serialVersionUID = 1L;
Result(int exitCode) {
this.exitCode = exitCode;
}
public boolean isOK() {
return (exitCode == 0);
}
public final int exitCode;
@Override
public String toString() {
return name() + '(' + exitCode + ')';
}
} }
} }

View file

@ -48,10 +48,8 @@ import com.sun.tools.javac.util.Log;
/** /**
* Utility for integrating with javadoc tools and for localization. * Utility for integrating with javadoc tools and for localization.
* Handle Resources. Access to error and warning counts. * Handle resources, access to error and warning counts and
* Message formatting. * message formatting.
* <br>
* Also provides implementation for DocErrorReporter.
* *
* <p><b>This is NOT part of any supported API. * <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk. * If you write code that depends on this, you do so at your own risk.
@ -139,10 +137,6 @@ public class Messager extends Log implements Reporter {
} }
} }
public static class ExitJavadoc extends Error {
private static final long serialVersionUID = 0;
}
final String programName; final String programName;
private Locale locale; private Locale locale;
@ -240,7 +234,7 @@ public class Messager extends Log implements Reporter {
report(DiagnosticType.ERROR, prefix, msg); report(DiagnosticType.ERROR, prefix, msg);
return; return;
} }
incrementErrorCount(prefix, msg); printError(prefix, msg);
} }
public void printError(Element e, String msg) { public void printError(Element e, String msg) {
@ -249,10 +243,15 @@ public class Messager extends Log implements Reporter {
report(DiagnosticType.ERROR, prefix, msg); report(DiagnosticType.ERROR, prefix, msg);
return; return;
} }
incrementErrorCount(prefix, msg); printError(prefix, msg);
} }
private void incrementErrorCount(String prefix, String msg) { public void printErrorUsingKey(String key, Object... args) {
printError((Element)null, getText(key, args));
}
// print the error and increment count
private void printError(String prefix, String msg) {
if (nerrors < MaxErrors) { if (nerrors < MaxErrors) {
PrintWriter errWriter = getWriter(WriterKind.ERROR); PrintWriter errWriter = getWriter(WriterKind.ERROR);
printRawLines(errWriter, prefix + ": " + getText("javadoc.error") + " - " + msg); printRawLines(errWriter, prefix + ": " + getText("javadoc.error") + " - " + msg);
@ -272,13 +271,21 @@ public class Messager extends Log implements Reporter {
printWarning((DocTreePath)null, msg); printWarning((DocTreePath)null, msg);
} }
public void printWarningUsingKey(String key, Object... args) {
printWarning((Element)null, getText(key, args));
}
public void printWarning(Element e, String key, Object... args) {
printWarning(getText(key, args));
}
public void printWarning(DocTreePath path, String msg) { public void printWarning(DocTreePath path, String msg) {
String prefix = getDiagSource(path); String prefix = getDiagSource(path);
if (diagListener != null) { if (diagListener != null) {
report(DiagnosticType.WARNING, prefix, msg); report(DiagnosticType.WARNING, prefix, msg);
return; return;
} }
incrementWarningCount(prefix, msg); printWarning(prefix, msg);
} }
public void printWarning(Element e, String msg) { public void printWarning(Element e, String msg) {
@ -287,10 +294,11 @@ public class Messager extends Log implements Reporter {
report(DiagnosticType.WARNING, prefix, msg); report(DiagnosticType.WARNING, prefix, msg);
return; return;
} }
incrementWarningCount(prefix, msg); printWarning(prefix, msg);
} }
private void incrementWarningCount(String prefix, String msg) { // print the warning and increment count
private void printWarning(String prefix, String msg) {
if (nwarnings < MaxWarnings) { if (nwarnings < MaxWarnings) {
PrintWriter warnWriter = getWriter(WriterKind.WARNING); PrintWriter warnWriter = getWriter(WriterKind.WARNING);
printRawLines(warnWriter, prefix + ": " + getText("javadoc.warning") + " - " + msg); printRawLines(warnWriter, prefix + ": " + getText("javadoc.warning") + " - " + msg);
@ -341,50 +349,6 @@ public class Messager extends Log implements Reporter {
noticeWriter.flush(); noticeWriter.flush();
} }
/**
* Print error message, increment error count.
*
* @param key selects message from resource
*/
public void error(Element e, String key, Object... args) {
printError(e, getText(key, args));
}
/**
* Print error message, increment error count.
*
* @param key selects message from resource
*/
public void error(DocTreePath path, String key, Object... args) {
printError(path, getText(key, args));
}
public void error(String key, Object... args) {
printError((Element)null, getText(key, args));
}
public void warning(String key, Object... args) {
printWarning((Element)null, getText(key, args));
}
/**
* Print warning message, increment warning count.
*
* @param key selects message from resource
*/
public void warning(Element e, String key, Object... args) {
printWarning(e, getText(key, args));
}
/**
* Print warning message, increment warning count.
*
* @param key selects message from resource
*/
public void warning(DocTreePath path, String key, Object... args) {
printWarning(path, getText(key, args));
}
/** /**
* Print a message. * Print a message.
* *
@ -395,21 +359,23 @@ public class Messager extends Log implements Reporter {
} }
/** /**
* Return total number of errors, including those recorded * Returns true if errors have been recorded.
* in the compilation log.
*/ */
public int nerrors() { return nerrors; } public boolean hasErrors() {
return nerrors != 0;
}
/** /**
* Return total number of warnings, including those recorded * Returns true if warnings have been recorded.
* in the compilation log.
*/ */
public int nwarnings() { return nwarnings; } public boolean hasWarnings() {
return nwarnings != 0;
}
/** /**
* Print exit message. * Print exit message.
*/ */
public void exitNotice() { public void printErrorWarningCounts() {
if (nerrors > 0) { if (nerrors > 0) {
notice((nerrors > 1) ? "main.errors" : "main.error", notice((nerrors > 1) ? "main.errors" : "main.error",
"" + nerrors); "" + nerrors);

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.javadoc.internal.tool;
import jdk.javadoc.internal.tool.Main.Result;
/**
* Provides a general mechanism for the javadoc tool to indicate an option
* decoding issue.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
class OptionException extends Exception {
private static final long serialVersionUID = 0;
public final Result result;
public final String message;
public final Runnable m;
/**
* Constructs an object with a result, runnable and a message
* to be printed out by the catcher. The runnable can be invoked
* by the catcher to display the usage text.
* @param result the exit code
* @param method the method to invoke
* @param message the detailed message
*/
public OptionException(Result result, Runnable method, String message) {
this.result = result;
this.m = method;
this.message = message;
if (result == null || result.isOK() || method == null || message == null) {
throw new AssertionError("result == null || result.isOK() || " +
"method == null || message == null");
}
}
/**
* Constructs an object with a result and a runnable.
* The runnable can be invoked by the catcher to display the usage text.
* @param result the exit code
* @param method the method to invoke
*/
public OptionException(Result result, Runnable method) {
this.result = result;
this.m = method;
this.message = null;
if (result == null || method == null) {
throw new AssertionError("result == null || method == null");
}
}
}

View file

@ -26,7 +26,6 @@
package jdk.javadoc.internal.tool; package jdk.javadoc.internal.tool;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.nio.file.Path; import java.nio.file.Path;
@ -65,11 +64,12 @@ import com.sun.tools.javac.util.Options;
import jdk.javadoc.doclet.Doclet; import jdk.javadoc.doclet.Doclet;
import jdk.javadoc.doclet.Doclet.Option; import jdk.javadoc.doclet.Doclet.Option;
import jdk.javadoc.doclet.DocletEnvironment; import jdk.javadoc.doclet.DocletEnvironment;
import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.tool.Main.Result;
import static javax.tools.DocumentationTool.Location.*; import static javax.tools.DocumentationTool.Location.*;
import static com.sun.tools.javac.main.Option.*; import static com.sun.tools.javac.main.Option.*;
import static jdk.javadoc.internal.tool.Main.Result.*;
/** /**
* Main program of Javadoc. * Main program of Javadoc.
@ -170,41 +170,28 @@ public class Start extends ToolOption.Helper {
*/ */
@Override @Override
void usage() { void usage() {
usage(true); usage("main.usage", OptionKind.STANDARD, "main.usage.foot");
}
void usage(boolean exit) {
usage("main.usage", "-help", "main.usage.foot");
if (exit)
throw new Messager.ExitJavadoc();
} }
@Override @Override
void Xusage() { void Xusage() {
Xusage(true); usage("main.Xusage", OptionKind.EXTENDED, "main.Xusage.foot");
} }
void Xusage(boolean exit) { private void usage(String headerKey, OptionKind kind, String footerKey) {
usage("main.Xusage", "-X", "main.Xusage.foot"); messager.notice(headerKey);
showToolOptions(kind);
if (exit)
throw new Messager.ExitJavadoc();
}
private void usage(String header, String option, String footer) {
messager.notice(header);
showToolOptions(option.equals("-X") ? OptionKind.EXTENDED : OptionKind.STANDARD);
// let doclet print usage information // let doclet print usage information
if (docletClass != null) { if (docletClass != null) {
String name = doclet.getName(); String name = doclet.getName();
messager.notice("main.doclet.usage.header", name); messager.notice("main.doclet.usage.header", name);
showDocletOptions(option.equals("-X") ? Option.Kind.EXTENDED : Option.Kind.STANDARD); showDocletOptions(kind == OptionKind.EXTENDED
? Option.Kind.EXTENDED
: Option.Kind.STANDARD);
} }
if (footerKey != null)
if (footer != null) messager.notice(footerKey);
messager.notice(footer);
} }
void showToolOptions(OptionKind kind) { void showToolOptions(OptionKind kind) {
@ -326,25 +313,23 @@ public class Start extends ToolOption.Helper {
* of class loader creation, needed to detect the doclet/taglet class variants. * of class loader creation, needed to detect the doclet/taglet class variants.
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
int begin(String... argv) { Result begin(String... argv) {
// Preprocess @file arguments // Preprocess @file arguments
try { try {
argv = CommandLine.parse(argv); argv = CommandLine.parse(argv);
} catch (FileNotFoundException e) {
messager.error("main.cant.read", e.getMessage());
throw new Messager.ExitJavadoc();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(System.err); error("main.cant.read", e.getMessage());
throw new Messager.ExitJavadoc(); return ERROR;
} }
if (argv.length > 0 && "-Xold".equals(argv[0])) { if (argv.length > 0 && "-Xold".equals(argv[0])) {
messager.warning("main.legacy_api"); warn("main.legacy_api");
String[] nargv = Arrays.copyOfRange(argv, 1, argv.length); String[] nargv = Arrays.copyOfRange(argv, 1, argv.length);
return com.sun.tools.javadoc.Main.execute(nargv); return com.sun.tools.javadoc.Main.execute(nargv) == 0
? OK
: ERROR;
} }
boolean ok = begin(Arrays.asList(argv), Collections.<JavaFileObject> emptySet()); return begin(Arrays.asList(argv), Collections.<JavaFileObject> emptySet());
return ok ? 0 : 1;
} }
// Called by 199 API. // Called by 199 API.
@ -356,11 +341,11 @@ public class Start extends ToolOption.Helper {
for (String opt: options) for (String opt: options)
opts.add(opt); opts.add(opt);
return begin(opts, fileObjects); return begin(opts, fileObjects).isOK();
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private boolean begin(List<String> options, Iterable<? extends JavaFileObject> fileObjects) { private Result begin(List<String> options, Iterable<? extends JavaFileObject> fileObjects) {
fileManager = context.get(JavaFileManager.class); fileManager = context.get(JavaFileManager.class);
if (fileManager == null) { if (fileManager == null) {
JavacFileManager.preRegister(context); JavacFileManager.preRegister(context);
@ -369,8 +354,28 @@ public class Start extends ToolOption.Helper {
((BaseFileManager) fileManager).autoClose = true; ((BaseFileManager) fileManager).autoClose = true;
} }
} }
// locale, doclet and maybe taglet, needs to be determined first // locale, doclet and maybe taglet, needs to be determined first
docletClass = preProcess(fileManager, options); try {
docletClass = preprocess(fileManager, options);
} catch (ToolException te) {
if (!te.result.isOK()) {
if (te.message != null) {
messager.printError(te.message);
}
Throwable t = te.getCause();
dumpStack(t == null ? te : t);
}
return te.result;
} catch (OptionException oe) {
if (oe.message != null) {
messager.printError(oe.message);
}
oe.m.run();
Throwable t = oe.getCause();
dumpStack(t == null ? oe : t);
return oe.result;
}
if (jdk.javadoc.doclet.Doclet.class.isAssignableFrom(docletClass)) { if (jdk.javadoc.doclet.Doclet.class.isAssignableFrom(docletClass)) {
// no need to dispatch to old, safe to init now // no need to dispatch to old, safe to init now
initMessager(); initMessager();
@ -379,43 +384,62 @@ public class Start extends ToolOption.Helper {
Object o = docletClass.getConstructor().newInstance(); Object o = docletClass.getConstructor().newInstance();
doclet = (Doclet) o; doclet = (Doclet) o;
} catch (ReflectiveOperationException exc) { } catch (ReflectiveOperationException exc) {
exc.printStackTrace(); if (apiMode) {
if (!apiMode) { throw new ClientCodeException(exc);
error("main.could_not_instantiate_class", docletClass);
throw new Messager.ExitJavadoc();
} }
throw new ClientCodeException(exc); error("main.could_not_instantiate_class", docletClass);
return ERROR;
} }
} else { } else {
if (this.apiMode) { if (apiMode) {
com.sun.tools.javadoc.main.Start ostart com.sun.tools.javadoc.main.Start ostart
= new com.sun.tools.javadoc.main.Start(context); = new com.sun.tools.javadoc.main.Start(context);
return ostart.begin(docletClass, options, fileObjects); return ostart.begin(docletClass, options, fileObjects)
? OK
: ERROR;
} }
warn("main.legacy_api"); warn("main.legacy_api");
String[] array = options.toArray(new String[options.size()]); String[] array = options.toArray(new String[options.size()]);
return com.sun.tools.javadoc.Main.execute(array) == 0; return com.sun.tools.javadoc.Main.execute(array) == 0
? OK
: ERROR;
} }
boolean failed = false; Result result = OK;
try { try {
failed = !parseAndExecute(options, fileObjects); result = parseAndExecute(options, fileObjects)
} catch (Messager.ExitJavadoc exc) { ? OK
// ignore, we just exit this way : ERROR;
} catch (OptionException toe) {
if (toe.message != null)
messager.printError(toe.message);
toe.m.run();
Throwable t = toe.getCause();
dumpStack(t == null ? toe : t);
return toe.result;
} catch (ToolException exc) {
if (exc.message != null) {
messager.printError(exc.message);
}
Throwable t = exc.getCause();
if (result == ABNORMAL) {
reportInternalError(t == null ? exc : t);
} else {
dumpStack(t == null ? exc : t);
}
return exc.result;
} catch (OutOfMemoryError ee) { } catch (OutOfMemoryError ee) {
messager.error("main.out.of.memory"); error("main.out.of.memory");
failed = true; result = SYSERR;
dumpStack(ee);
} catch (ClientCodeException e) { } catch (ClientCodeException e) {
// simply rethrow these exceptions, to be caught and handled by JavadocTaskImpl // simply rethrow these exceptions, to be caught and handled by JavadocTaskImpl
throw e; throw e;
} catch (Error ee) { } catch (Error | Exception ee) {
ee.printStackTrace(System.err); error("main.fatal.error", ee);
messager.error("main.fatal.error"); reportInternalError(ee);
failed = true; result = ABNORMAL;
} catch (Exception ee) {
ee.printStackTrace(System.err);
messager.error("main.fatal.exception");
failed = true;
} finally { } finally {
if (fileManager != null if (fileManager != null
&& fileManager instanceof BaseFileManager && fileManager instanceof BaseFileManager
@ -424,17 +448,34 @@ public class Start extends ToolOption.Helper {
fileManager.close(); fileManager.close();
} catch (IOException ignore) {} } catch (IOException ignore) {}
} }
boolean haveErrorWarnings = messager.nerrors() > 0 || boolean haveErrorWarnings = messager.hasErrors()
(rejectWarnings && messager.nwarnings() > 0); || (rejectWarnings && messager.hasWarnings());
if (failed && !haveErrorWarnings) { if (!result.isOK() && !haveErrorWarnings) {
// the doclet failed, but nothing reported, flag it!. // the doclet failed, but nothing reported, flag it!.
messager.error("main.unknown.error"); error("main.unknown.error");
} }
failed |= haveErrorWarnings; if (haveErrorWarnings && result.isOK()) {
messager.exitNotice(); result = ERROR;
}
messager.printErrorWarningCounts();
messager.flush(); messager.flush();
} }
return !failed; return result;
}
private void reportInternalError(Throwable t) {
messager.printErrorUsingKey("doclet.internal.report.bug");
dumpStack(true, t);
}
private void dumpStack(Throwable t) {
dumpStack(false, t);
}
private void dumpStack(boolean enabled, Throwable t) {
if (t != null && (enabled || dumpOnError)) {
t.printStackTrace(System.err);
}
} }
/** /**
@ -442,7 +483,7 @@ public class Start extends ToolOption.Helper {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private boolean parseAndExecute(List<String> argList, private boolean parseAndExecute(List<String> argList,
Iterable<? extends JavaFileObject> fileObjects) throws IOException { Iterable<? extends JavaFileObject> fileObjects) throws ToolException, OptionException {
long tm = System.currentTimeMillis(); long tm = System.currentTimeMillis();
List<String> javaNames = new ArrayList<>(); List<String> javaNames = new ArrayList<>();
@ -463,17 +504,21 @@ public class Start extends ToolOption.Helper {
if (platformString != null) { if (platformString != null) {
if (compOpts.isSet("-source")) { if (compOpts.isSet("-source")) {
usageError("main.release.bootclasspath.conflict", "-source"); String text = messager.getText("main.release.bootclasspath.conflict", "-source");
throw new ToolException(CMDERR, text);
} }
if (fileManagerOpts.containsKey(BOOT_CLASS_PATH)) { if (fileManagerOpts.containsKey(BOOT_CLASS_PATH)) {
usageError("main.release.bootclasspath.conflict", BOOT_CLASS_PATH.getPrimaryName()); String text = messager.getText("main.release.bootclasspath.conflict",
BOOT_CLASS_PATH.getPrimaryName());
throw new ToolException(CMDERR, text);
} }
PlatformDescription platformDescription = PlatformDescription platformDescription =
PlatformUtils.lookupPlatformDescription(platformString); PlatformUtils.lookupPlatformDescription(platformString);
if (platformDescription == null) { if (platformDescription == null) {
usageError("main.unsupported.release.version", platformString); String text = messager.getText("main.unsupported.release.version", platformString);
throw new IllegalArgumentException(text);
} }
compOpts.put(SOURCE, platformDescription.getSourceVersion()); compOpts.put(SOURCE, platformDescription.getSourceVersion());
@ -485,10 +530,15 @@ public class Start extends ToolOption.Helper {
if (platformCP != null) { if (platformCP != null) {
if (fileManager instanceof StandardJavaFileManager) { if (fileManager instanceof StandardJavaFileManager) {
StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager; StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager;
try {
sfm.setLocationFromPaths(StandardLocation.PLATFORM_CLASS_PATH, platformCP); sfm.setLocationFromPaths(StandardLocation.PLATFORM_CLASS_PATH, platformCP);
} catch (IOException ioe) {
throw new ToolException(SYSERR, ioe.getMessage(), ioe);
}
} else { } else {
usageError("main.release.not.standard.file.manager", platformString); String text = messager.getText("main.release.not.standard.file.manager",
platformString);
throw new ToolException(ABNORMAL, text);
} }
} }
} }
@ -502,7 +552,8 @@ public class Start extends ToolOption.Helper {
s -> Collections.EMPTY_LIST); s -> Collections.EMPTY_LIST);
if (subpkgs.isEmpty()) { if (subpkgs.isEmpty()) {
if (javaNames.isEmpty() && isEmpty(fileObjects)) { if (javaNames.isEmpty() && isEmpty(fileObjects)) {
usageError("main.No_modules_packages_or_classes_specified"); String text = messager.getText("main.No_modules_packages_or_classes_specified");
throw new ToolException(CMDERR, text);
} }
} }
} }
@ -535,7 +586,8 @@ public class Start extends ToolOption.Helper {
} }
Set<Doclet.Option> docletOptions = null; Set<Doclet.Option> docletOptions = null;
int handleDocletOptions(int idx, List<String> args, boolean isToolOption) { int handleDocletOptions(int idx, List<String> args, boolean isToolOption)
throws OptionException {
if (docletOptions == null) { if (docletOptions == null) {
docletOptions = doclet.getSupportedOptions(); docletOptions = doclet.getSupportedOptions();
} }
@ -549,24 +601,25 @@ public class Start extends ToolOption.Helper {
argBase = arg; argBase = arg;
argVal = null; argVal = null;
} }
String text = null;
for (Doclet.Option opt : docletOptions) { for (Doclet.Option opt : docletOptions) {
if (opt.matches(argBase)) { if (opt.matches(argBase)) {
if (argVal != null) { if (argVal != null) {
switch (opt.getArgumentCount()) { switch (opt.getArgumentCount()) {
case 0: case 0:
usageError("main.unnecessary_arg_provided", argBase); text = messager.getText("main.unnecessary_arg_provided", argBase);
break; throw new OptionException(ERROR, this::usage, text);
case 1: case 1:
opt.process(arg, Arrays.asList(argVal).listIterator()); opt.process(arg, Arrays.asList(argVal).listIterator());
break; break;
default: default:
usageError("main.only_one_argument_with_equals", argBase); text = messager.getText("main.only_one_argument_with_equals", argBase);
break; throw new OptionException(ERROR, this::usage, text);
} }
} else { } else {
if (args.size() - idx -1 < opt.getArgumentCount()) { if (args.size() - idx -1 < opt.getArgumentCount()) {
usageError("main.requires_argument", arg); text = messager.getText("main.requires_argument", arg);
throw new OptionException(ERROR, this::usage, text);
} }
opt.process(arg, args.listIterator(idx + 1)); opt.process(arg, args.listIterator(idx + 1));
idx += opt.getArgumentCount(); idx += opt.getArgumentCount();
@ -575,12 +628,15 @@ public class Start extends ToolOption.Helper {
} }
} }
// check if arg is accepted by the tool before emitting error // check if arg is accepted by the tool before emitting error
if (!isToolOption) if (!isToolOption) {
usageError("main.invalid_flag", arg); text = messager.getText("main.invalid_flag", arg);
throw new OptionException(ERROR, this::usage, text);
}
return idx; return idx;
} }
private Class<?> preProcess(JavaFileManager jfm, List<String> argv) { private Class<?> preprocess(JavaFileManager jfm,
List<String> argv) throws ToolException, OptionException {
// doclet specifying arguments // doclet specifying arguments
String userDocletPath = null; String userDocletPath = null;
String userDocletName = null; String userDocletName = null;
@ -593,19 +649,31 @@ public class Start extends ToolOption.Helper {
// Step 1: loop through the args, set locale early on, if found. // Step 1: loop through the args, set locale early on, if found.
for (int i = 0 ; i < argv.size() ; i++) { for (int i = 0 ; i < argv.size() ; i++) {
String arg = argv.get(i); String arg = argv.get(i);
if (arg.equals(ToolOption.LOCALE.primaryName)) { if (arg.equals(ToolOption.DUMPONERROR.primaryName)) {
dumpOnError = true;
} else if (arg.equals(ToolOption.LOCALE.primaryName)) {
checkOneArg(argv, i++); checkOneArg(argv, i++);
String lname = argv.get(i); String lname = argv.get(i);
locale = getLocale(lname); locale = getLocale(lname);
} else if (arg.equals(ToolOption.DOCLET.primaryName)) { } else if (arg.equals(ToolOption.DOCLET.primaryName)) {
checkOneArg(argv, i++); checkOneArg(argv, i++);
if (userDocletName != null) { if (userDocletName != null) {
usageError("main.more_than_one_doclet_specified_0_and_1", if (apiMode) {
throw new IllegalArgumentException("More than one doclet specified (" +
userDocletName + " and " + argv.get(i) + ").");
}
String text = messager.getText("main.more_than_one_doclet_specified_0_and_1",
userDocletName, argv.get(i)); userDocletName, argv.get(i));
throw new ToolException(CMDERR, text);
} }
if (docletName != null) { if (docletName != null) {
usageError("main.more_than_one_doclet_specified_0_and_1", if (apiMode) {
throw new IllegalArgumentException("More than one doclet specified (" +
docletName + " and " + argv.get(i) + ").");
}
String text = messager.getText("main.more_than_one_doclet_specified_0_and_1",
docletName, argv.get(i)); docletName, argv.get(i));
throw new ToolException(CMDERR, text);
} }
userDocletName = argv.get(i); userDocletName = argv.get(i);
} else if (arg.equals(ToolOption.DOCLETPATH.primaryName)) { } else if (arg.equals(ToolOption.DOCLETPATH.primaryName)) {
@ -644,23 +712,37 @@ public class Start extends ToolOption.Helper {
try { try {
((StandardJavaFileManager)fileManager).setLocation(DOCLET_PATH, paths); ((StandardJavaFileManager)fileManager).setLocation(DOCLET_PATH, paths);
} catch (IOException ioe) { } catch (IOException ioe) {
error("main.doclet_could_not_set_location", paths); if (apiMode) {
throw new Messager.ExitJavadoc(); throw new IllegalArgumentException("Could not set location for " +
userDocletPath, ioe);
}
String text = messager.getText("main.doclet_could_not_set_location",
userDocletPath);
throw new ToolException(CMDERR, text, ioe);
} }
} }
cl = fileManager.getClassLoader(DOCLET_PATH); cl = fileManager.getClassLoader(DOCLET_PATH);
if (cl == null) { if (cl == null) {
// despite doclet specified on cmdline no classloader found! // despite doclet specified on cmdline no classloader found!
error("main.doclet_no_classloader_found", userDocletName); if (apiMode) {
throw new Messager.ExitJavadoc(); throw new IllegalArgumentException("Could not obtain classloader to load "
+ userDocletPath);
}
String text = messager.getText("main.doclet_no_classloader_found",
userDocletName);
throw new ToolException(CMDERR, text);
} }
} }
try { try {
Class<?> klass = cl.loadClass(userDocletName); Class<?> klass = cl.loadClass(userDocletName);
return klass; return klass;
} catch (ClassNotFoundException cnfe) { } catch (ClassNotFoundException cnfe) {
error("main.doclet_class_not_found", userDocletName); if (apiMode) {
throw new Messager.ExitJavadoc(); throw new IllegalArgumentException("Cannot find doclet class " + userDocletName,
cnfe);
}
String text = messager.getText("main.doclet_class_not_found", userDocletName);
throw new ToolException(CMDERR, text, cnfe);
} }
} }
@ -669,8 +751,11 @@ public class Start extends ToolOption.Helper {
try { try {
return Class.forName(docletName, true, getClass().getClassLoader()); return Class.forName(docletName, true, getClass().getClassLoader());
} catch (ClassNotFoundException cnfe) { } catch (ClassNotFoundException cnfe) {
error("main.doclet_class_not_found", userDocletName); if (apiMode) {
throw new Messager.ExitJavadoc(); throw new IllegalArgumentException("Cannot find doclet class " + userDocletName);
}
String text = messager.getText("main.doclet_class_not_found", userDocletName);
throw new ToolException(CMDERR, text, cnfe);
} }
} }
@ -690,20 +775,20 @@ public class Start extends ToolOption.Helper {
* nature to take its own course. * nature to take its own course.
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private boolean hasOldTaglet(List<String> tagletNames, List<File> tagletPaths) { private boolean hasOldTaglet(List<String> tagletNames, List<File> tagletPaths) throws ToolException {
if (!fileManager.hasLocation(TAGLET_PATH)) { if (!fileManager.hasLocation(TAGLET_PATH)) {
try { try {
((StandardJavaFileManager) fileManager).setLocation(TAGLET_PATH, tagletPaths); ((StandardJavaFileManager) fileManager).setLocation(TAGLET_PATH, tagletPaths);
} catch (IOException ioe) { } catch (IOException ioe) {
error("main.doclet_could_not_set_location", tagletPaths); String text = messager.getText("main.doclet_could_not_set_location", tagletPaths);
throw new Messager.ExitJavadoc(); throw new ToolException(CMDERR, text, ioe);
} }
} }
ClassLoader cl = fileManager.getClassLoader(TAGLET_PATH); ClassLoader cl = fileManager.getClassLoader(TAGLET_PATH);
if (cl == null) { if (cl == null) {
// no classloader found! // no classloader found!
error("main.doclet_no_classloader_found", tagletNames.get(0)); String text = messager.getText("main.doclet_no_classloader_found", tagletNames.get(0));
throw new Messager.ExitJavadoc(); throw new ToolException(CMDERR, text);
} }
for (String tagletName : tagletNames) { for (String tagletName : tagletNames) {
try { try {
@ -712,14 +797,15 @@ public class Start extends ToolOption.Helper {
return true; return true;
} }
} catch (ClassNotFoundException cnfe) { } catch (ClassNotFoundException cnfe) {
error("main.doclet_class_not_found", tagletName); String text = messager.getText("main.doclet_class_not_found", tagletName);
throw new Messager.ExitJavadoc(); throw new ToolException(CMDERR, text, cnfe);
} }
} }
return false; return false;
} }
private void parseArgs(List<String> args, List<String> javaNames) { private void parseArgs(List<String> args, List<String> javaNames) throws ToolException,
OptionException {
for (int i = 0 ; i < args.size() ; i++) { for (int i = 0 ; i < args.size() ; i++) {
String arg = args.get(i); String arg = args.get(i);
ToolOption o = ToolOption.get(arg); ToolOption o = ToolOption.get(arg);
@ -727,7 +813,6 @@ public class Start extends ToolOption.Helper {
// handle a doclet argument that may be needed however // handle a doclet argument that may be needed however
// don't increment the index, and allow the tool to consume args // don't increment the index, and allow the tool to consume args
handleDocletOptions(i, args, true); handleDocletOptions(i, args, true);
if (o.hasArg) { if (o.hasArg) {
if (arg.startsWith("--") && arg.contains("=")) { if (arg.startsWith("--") && arg.contains("=")) {
o.process(this, arg.substring(arg.indexOf('=') + 1)); o.process(this, arg.substring(arg.indexOf('=') + 1));
@ -763,24 +848,19 @@ public class Start extends ToolOption.Helper {
* Check the one arg option. * Check the one arg option.
* Error and exit if one argument is not provided. * Error and exit if one argument is not provided.
*/ */
private void checkOneArg(List<String> args, int index) { private void checkOneArg(List<String> args, int index) throws OptionException {
if ((index + 1) >= args.size() || args.get(index + 1).startsWith("-d")) { if ((index + 1) >= args.size() || args.get(index + 1).startsWith("-d")) {
usageError("main.requires_argument", args.get(index)); String text = messager.getText("main.requires_argument", args.get(index));
throw new OptionException(CMDERR, this::usage, text);
} }
} }
@Override
void usageError(String key, Object... args) {
error(key, args);
usage(true);
}
void error(String key, Object... args) { void error(String key, Object... args) {
messager.error(key, args); messager.printErrorUsingKey(key, args);
} }
void warn(String key, Object... args) { void warn(String key, Object... args) {
messager.warning(key, args); messager.printWarningUsingKey(key, args);
} }
/** /**
@ -788,7 +868,7 @@ public class Start extends ToolOption.Helper {
* else return null and if locale option is not used * else return null and if locale option is not used
* then return default locale. * then return default locale.
*/ */
private Locale getLocale(String localeName) { private Locale getLocale(String localeName) throws ToolException {
Locale userlocale = null; Locale userlocale = null;
if (localeName == null || localeName.isEmpty()) { if (localeName == null || localeName.isEmpty()) {
return Locale.getDefault(); return Locale.getDefault();
@ -804,8 +884,8 @@ public class Start extends ToolOption.Helper {
if (seconduscore > 0) { if (seconduscore > 0) {
if (seconduscore != firstuscore + 3 if (seconduscore != firstuscore + 3
|| localeName.length() <= seconduscore + 1) { || localeName.length() <= seconduscore + 1) {
usageError("main.malformed_locale_name", localeName); String text = messager.getText("main.malformed_locale_name", localeName);
return null; throw new ToolException(CMDERR, text);
} }
country = localeName.substring(firstuscore + 1, country = localeName.substring(firstuscore + 1,
seconduscore); seconduscore);
@ -813,19 +893,19 @@ public class Start extends ToolOption.Helper {
} else if (localeName.length() == firstuscore + 3) { } else if (localeName.length() == firstuscore + 3) {
country = localeName.substring(firstuscore + 1); country = localeName.substring(firstuscore + 1);
} else { } else {
usageError("main.malformed_locale_name", localeName); String text = messager.getText("main.malformed_locale_name", localeName);
return null; throw new ToolException(CMDERR, text);
} }
} else if (firstuscore == -1 && localeName.length() == 2) { } else if (firstuscore == -1 && localeName.length() == 2) {
language = localeName; language = localeName;
} else { } else {
usageError("main.malformed_locale_name", localeName); String text = messager.getText("main.malformed_locale_name", localeName);
return null; throw new ToolException(CMDERR, text);
} }
userlocale = searchLocale(language, country, variant); userlocale = searchLocale(language, country, variant);
if (userlocale == null) { if (userlocale == null) {
usageError("main.illegal_locale_name", localeName); String text = messager.getText("main.illegal_locale_name", localeName);
return null; throw new ToolException(CMDERR, text);
} else { } else {
return userlocale; return userlocale;
} }
@ -861,4 +941,9 @@ public class Start extends ToolOption.Helper {
} }
}; };
} }
@Override
String getLocalizedMessage(String msg, Object... args) {
return messager.getText(msg, args);
}
} }

View file

@ -87,7 +87,7 @@ public class ToolEnvironment {
return instance; return instance;
} }
private final Messager messager; final Messager messager;
/** Predefined symbols known to the compiler. */ /** Predefined symbols known to the compiler. */
public final Symtab syms; public final Symtab syms;
@ -204,182 +204,8 @@ public class ToolEnvironment {
return path != null; return path != null;
} }
//---------------- print forwarders ----------------//
// ERRORS
/** /**
* Print error message, increment error count. * Print a notice, iff <em>quiet</em> is not specified.
*
* @param msg message to print.
*/
public void printError(String msg) {
messager.printError(msg);
}
// /**
// * Print error message, increment error count.
// *
// * @param key selects message from resource
// */
// public void error(Element element, String key) {
// if (element == null)
// messager.error(key);
// else
// messager.error(element, key);
// }
//
// public void error(String prefix, String key) {
// printError(prefix + ":" + messager.getText(key));
// }
//
// /**
// * Print error message, increment error count.
// *
// * @param path the path to the source
// * @param key selects message from resource
// */
// public void error(DocTreePath path, String key) {
// messager.error(path, key);
// }
//
// /**
// * Print error message, increment error count.
// *
// * @param path the path to the source
// * @param msg message to print.
// */
// public void printError(DocTreePath path, String msg) {
// messager.printError(path, msg);
// }
//
// /**
// * Print error message, increment error count.
// * @param e the target element
// * @param msg message to print.
// */
// public void printError(Element e, String msg) {
// messager.printError(e, msg);
// }
/**
* Print error message, increment error count.
* @param key selects message from resource
* @param args replacement arguments
*/
public void error(String key, String... args) {
error(null, key, args);
}
/**
* Print error message, increment error count.
*
* @param element the source element
* @param key selects message from resource
* @param args replacement arguments
*/
public void error(Element element, String key, String... args) {
if (element == null)
messager.error(key, (Object[]) args);
else
messager.error(element, key, (Object[]) args);
}
// WARNINGS
// /**
// * Print warning message, increment warning count.
// *
// * @param msg message to print.
// */
// public void printWarning(String msg) {
// messager.printWarning(msg);
// }
//
// public void warning(String key) {
// warning((Element)null, key);
// }
public void warning(String key, String... args) {
warning((Element)null, key, args);
}
// /**
// * Print warning message, increment warning count.
// *
// * @param element the source element
// * @param key selects message from resource
// */
// public void warning(Element element, String key) {
// if (element == null)
// messager.warning(key);
// else
// messager.warning(element, key);
// }
//
// /**
// * Print warning message, increment warning count.
// *
// * @param path the path to the source
// * @param msg message to print.
// */
// public void printWarning(DocTreePath path, String msg) {
// messager.printWarning(path, msg);
// }
//
// /**
// * Print warning message, increment warning count.
// *
// * @param e the source element
// * @param msg message to print.
// */
// public void printWarning(Element e, String msg) {
// messager.printWarning(e, msg);
// }
/**
* Print warning message, increment warning count.
*
* @param e the source element
* @param key selects message from resource
* @param args the replace arguments
*/
public void warning(Element e, String key, String... args) {
if (e == null)
messager.warning(key, (Object[]) args);
else
messager.warning(e, key, (Object[]) args);
}
// Note: no longer required
// /**
// * Print a message.
// *
// * @param msg message to print.
// */
// public void printNotice(String msg) {
// if (quiet) {
// return;
// }
// messager.printNotice(msg);
// }
// Note: no longer required
// /**
// * Print a message.
// *
// * @param e the source element
// * @param msg message to print.
// */
// public void printNotice(Element e, String msg) {
// if (quiet) {
// return;
// }
// messager.printNotice(e, msg);
// }
// NOTICES
/**
* Print a message.
* *
* @param key selects message from resource * @param key selects message from resource
*/ */
@ -390,22 +216,8 @@ public class ToolEnvironment {
messager.notice(key); messager.notice(key);
} }
// Note: not used anymore
// /**
// * Print a message.
// *
// * @param path the path to the source
// * @param msg message to print.
// */
// public void printNotice(DocTreePath path, String msg) {
// if (quiet) {
// return;
// }
// messager.printNotice(path, msg);
// }
/** /**
* Print a message. * Print a notice, iff <em>quiet</em> is not specified.
* *
* @param key selects message from resource * @param key selects message from resource
* @param a1 first argument * @param a1 first argument
@ -417,48 +229,6 @@ public class ToolEnvironment {
messager.notice(key, a1); messager.notice(key, a1);
} }
// Note: not used anymore
// /**
// * Print a message.
// *
// * @param key selects message from resource
// * @param a1 first argument
// * @param a2 second argument
// */
// public void notice(String key, String a1, String a2) {
// if (quiet) {
// return;
// }
// messager.notice(key, a1, a2);
// }
//
// Note: not used anymore
// /**
// * Print a message.
// *
// * @param key selects message from resource
// * @param a1 first argument
// * @param a2 second argument
// * @param a3 third argument
// */
// public void notice(String key, String a1, String a2, String a3) {
// if (quiet) {
// return;
// }
// messager.notice(key, a1, a2, a3);
// }
/**
* Exit, reporting errors and warnings.
*/
public void exit() {
// Messager should be replaced by a more general
// compilation environment. This can probably
// subsume DocEnv as well.
throw new Messager.ExitJavadoc();
}
TreePath getTreePath(JCCompilationUnit tree) { TreePath getTreePath(JCCompilationUnit tree) {
TreePath p = treePaths.get(tree); TreePath p = treePaths.get(tree);
if (p == null) if (p == null)

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.javadoc.internal.tool;
import jdk.javadoc.internal.tool.Main.Result;
/**
* Provides a mechanism for the javadoc tool to terminate execution.
* This class is constructed with a result and an error message,
* that can be printed out before termination, a cause can also
* be wrapped to supply extended information about the exception.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
class ToolException extends Exception {
private static final long serialVersionUID = 0;
final String message;
final Result result;
/**
* Constructs an object containing a result and a message to be
* printed out by the catcher.
* @param result the exit code
* @param message the detailed message
*/
ToolException(Result result, String message) {
this.message = message;
this.result = result;
if (result == null || result.isOK() || message == null) {
throw new AssertionError("result == null || result.isOK() || message == null");
}
}
/**
* Constructs an object containing a result, a messages and an underlying cause.
* @param result the exit code
* @param message the detailed message
* @param cause the underlying cause
*/
ToolException(Result result, String message, Throwable cause) {
super(cause);
this.message = message;
this.result = result;
if (result == null || message == null || cause == null || result.isOK()) {
throw new AssertionError("result == null || message == null"
+ " || cause == null || result.isOK()");
}
}
}

View file

@ -40,6 +40,7 @@ import com.sun.tools.javac.main.OptionHelper;
import com.sun.tools.javac.util.Options; import com.sun.tools.javac.util.Options;
import static com.sun.tools.javac.main.Option.OptionKind.*; import static com.sun.tools.javac.main.Option.OptionKind.*;
import static jdk.javadoc.internal.tool.Main.Result.*;
/** /**
* javadoc tool options. * javadoc tool options.
@ -226,63 +227,63 @@ public enum ToolOption {
PACKAGE("-package", STANDARD) { PACKAGE("-package", STANDARD) {
@Override @Override
public void process(Helper helper) { public void process(Helper helper) throws OptionException {
helper.setSimpleFilter("package"); helper.setSimpleFilter("package");
} }
}, },
PRIVATE("-private", STANDARD) { PRIVATE("-private", STANDARD) {
@Override @Override
public void process(Helper helper) { public void process(Helper helper) throws OptionException {
helper.setSimpleFilter("private"); helper.setSimpleFilter("private");
} }
}, },
PROTECTED("-protected", STANDARD) { PROTECTED("-protected", STANDARD) {
@Override @Override
public void process(Helper helper) { public void process(Helper helper) throws OptionException {
helper.setSimpleFilter("protected"); helper.setSimpleFilter("protected");
} }
}, },
PUBLIC("-public", STANDARD) { PUBLIC("-public", STANDARD) {
@Override @Override
public void process(Helper helper) { public void process(Helper helper) throws OptionException {
helper.setSimpleFilter("public"); helper.setSimpleFilter("public");
} }
}, },
SHOW_MEMBERS("--show-members", STANDARD, true) { SHOW_MEMBERS("--show-members", STANDARD, true) {
@Override @Override
public void process(Helper helper, String arg) { public void process(Helper helper, String arg) throws OptionException {
helper.setFilter(this, arg); helper.setFilter(this, arg);
} }
}, },
SHOW_TYPES("--show-types", STANDARD, true) { SHOW_TYPES("--show-types", STANDARD, true) {
@Override @Override
public void process(Helper helper, String arg) { public void process(Helper helper, String arg) throws OptionException {
helper.setFilter(this, arg); helper.setFilter(this, arg);
} }
}, },
SHOW_PACKAGES("--show-packages", STANDARD, true) { SHOW_PACKAGES("--show-packages", STANDARD, true) {
@Override @Override
public void process(Helper helper, String arg) { public void process(Helper helper, String arg) throws OptionException {
helper.setShowPackageAccess(SHOW_PACKAGES, arg); helper.setShowPackageAccess(SHOW_PACKAGES, arg);
} }
}, },
SHOW_MODULE_CONTENTS("--show-module-contents", STANDARD, true) { SHOW_MODULE_CONTENTS("--show-module-contents", STANDARD, true) {
@Override @Override
public void process(Helper helper, String arg) { public void process(Helper helper, String arg) throws OptionException {
helper.setShowModuleContents(SHOW_MODULE_CONTENTS, arg); helper.setShowModuleContents(SHOW_MODULE_CONTENTS, arg);
} }
}, },
EXPAND_REQUIRES("--expand-requires", STANDARD, true) { EXPAND_REQUIRES("--expand-requires", STANDARD, true) {
@Override @Override
public void process(Helper helper, String arg) { public void process(Helper helper, String arg) throws OptionException {
helper.setExpandRequires(EXPAND_REQUIRES, arg); helper.setExpandRequires(EXPAND_REQUIRES, arg);
} }
}, },
@ -342,19 +343,26 @@ public enum ToolOption {
} }
}, },
DUMPONERROR("--dump-on-error", HIDDEN) {
@Override
public void process(Helper helper) {
helper.dumpOnError = true;
}
},
// ----- help options ----- // ----- help options -----
HELP("--help -help", STANDARD) { HELP("--help -help", STANDARD) {
@Override @Override
public void process(Helper helper) { public void process(Helper helper) throws OptionException {
helper.usage(); throw new OptionException(OK, helper::usage);
} }
}, },
X("-X", STANDARD) { X("-X", STANDARD) {
@Override @Override
public void process(Helper helper) { public void process(Helper helper) throws OptionException {
helper.Xusage(); throw new OptionException(OK, helper::Xusage);
} }
}, },
@ -395,9 +403,9 @@ public enum ToolOption {
this.hasSuffix = lastChar == ':' || lastChar == '='; this.hasSuffix = lastChar == ':' || lastChar == '=';
} }
void process(Helper helper, String arg) { } void process(Helper helper, String arg) throws OptionException { }
void process(Helper helper) { } void process(Helper helper) throws OptionException { }
List<String> getNames() { List<String> getNames() {
return names; return names;
@ -451,6 +459,9 @@ public enum ToolOption {
/** Javadoc tool options */ /** Javadoc tool options */
final Map<ToolOption, Object> jdtoolOpts = new EnumMap<>(ToolOption.class); final Map<ToolOption, Object> jdtoolOpts = new EnumMap<>(ToolOption.class);
/** dump stack traces for debugging etc.*/
boolean dumpOnError = false;
/** Set by -breakiterator. */ /** Set by -breakiterator. */
boolean breakiterator = false; boolean breakiterator = false;
@ -470,7 +481,8 @@ public enum ToolOption {
abstract void usage(); abstract void usage();
abstract void Xusage(); abstract void Xusage();
abstract void usageError(String msg, Object... args); abstract String getLocalizedMessage(String msg, Object... args);
abstract OptionHelper getOptionHelper(); abstract OptionHelper getOptionHelper();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -480,7 +492,7 @@ public enum ToolOption {
jdtoolOpts.put(opt, list); jdtoolOpts.put(opt, list);
} }
void setExpandRequires(ToolOption opt, String arg) { void setExpandRequires(ToolOption opt, String arg) throws OptionException {
switch (arg) { switch (arg) {
case "public": case "public":
jdtoolOpts.put(opt, AccessKind.PUBLIC); jdtoolOpts.put(opt, AccessKind.PUBLIC);
@ -489,11 +501,12 @@ public enum ToolOption {
jdtoolOpts.put(opt, AccessKind.PRIVATE); jdtoolOpts.put(opt, AccessKind.PRIVATE);
break; break;
default: default:
usageError("main.illegal_option_value", arg); String text = getLocalizedMessage("main.illegal_option_value", arg);
throw new IllegalOptionValue(this::usage, text);
} }
} }
void setShowModuleContents(ToolOption opt, String arg) { void setShowModuleContents(ToolOption opt, String arg) throws OptionException {
switch (arg) { switch (arg) {
case "api": case "api":
jdtoolOpts.put(opt, AccessKind.PUBLIC); jdtoolOpts.put(opt, AccessKind.PUBLIC);
@ -502,11 +515,12 @@ public enum ToolOption {
jdtoolOpts.put(opt, AccessKind.PRIVATE); jdtoolOpts.put(opt, AccessKind.PRIVATE);
break; break;
default: default:
usageError("main.illegal_option_value", arg); String text = getLocalizedMessage("main.illegal_option_value", arg);
throw new IllegalOptionValue(this::usage, text);
} }
} }
void setShowPackageAccess(ToolOption opt, String arg) { void setShowPackageAccess(ToolOption opt, String arg) throws OptionException {
switch (arg) { switch (arg) {
case "exported": case "exported":
jdtoolOpts.put(opt, AccessKind.PUBLIC); jdtoolOpts.put(opt, AccessKind.PUBLIC);
@ -515,16 +529,17 @@ public enum ToolOption {
jdtoolOpts.put(opt, AccessKind.PRIVATE); jdtoolOpts.put(opt, AccessKind.PRIVATE);
break; break;
default: default:
usageError("main.illegal_option_value", arg); String text = getLocalizedMessage("main.illegal_option_value", arg);
throw new IllegalOptionValue(this::usage, text);
} }
} }
void setFilter(ToolOption opt, String arg) { void setFilter(ToolOption opt, String arg) throws OptionException {
jdtoolOpts.put(opt, getAccessValue(arg)); jdtoolOpts.put(opt, getAccessValue(arg));
} }
void setSimpleFilter(String arg) { void setSimpleFilter(String arg) throws OptionException {
handleSimpleOption(arg); handleSimpleOption(arg);
} }
@ -532,7 +547,7 @@ public enum ToolOption {
fileManagerOpts.put(opt, arg); fileManagerOpts.put(opt, arg);
} }
void handleSimpleOption(String arg) { void handleSimpleOption(String arg) throws OptionException {
populateSimpleAccessMap(getAccessValue(arg)); populateSimpleAccessMap(getAccessValue(arg));
} }
@ -541,7 +556,7 @@ public enum ToolOption {
* -private, so on, in addition to the new ones such as * -private, so on, in addition to the new ones such as
* --show-types:public and so on. * --show-types:public and so on.
*/ */
private AccessKind getAccessValue(String arg) { private AccessKind getAccessValue(String arg) throws OptionException {
int colon = arg.indexOf(':'); int colon = arg.indexOf(':');
String value = (colon > 0) String value = (colon > 0)
? arg.substring(colon + 1) ? arg.substring(colon + 1)
@ -556,8 +571,8 @@ public enum ToolOption {
case "private": case "private":
return AccessKind.PRIVATE; return AccessKind.PRIVATE;
default: default:
usageError("main.illegal_option_value", value); String text = getLocalizedMessage("main.illegal_option_value", value);
return null; throw new IllegalOptionValue(this::usage, text);
} }
} }

View file

@ -265,13 +265,13 @@ main.Loading_source_file=Loading source file {0}...
main.Building_tree=Constructing Javadoc information... main.Building_tree=Constructing Javadoc information...
main.no_source_files_for_package=No source files for package {0} main.no_source_files_for_package=No source files for package {0}
main.package_not_found=Package {0} not found main.package_not_found=Package {0} not found
main.fatal.error=fatal error main.fatal.error=fatal error encountered: {0}
main.fatal.exception=fatal exception
main.out.of.memory=java.lang.OutOfMemoryError: Please increase memory.\n\ main.out.of.memory=java.lang.OutOfMemoryError: Please increase memory.\n\
For example, on the JDK Classic or HotSpot VMs, add the option -J-Xmx\n\ For example, on the JDK Classic or HotSpot VMs, add the option -J-Xmx\n\
such as -J-Xmx32m. such as -J-Xmx32m.
main.done_in=[done in {0} ms] main.done_in=[done in {0} ms]
main.more_than_one_doclet_specified_0_and_1=More than one doclet specified ({0} and {1}). main.more_than_one_doclet_specified_0_and_1=More than one doclet specified ({0} and {1}).
main.doclet_could_not_get_location=Could not get location for {0}
main.doclet_could_not_set_location=Could not set location for {0} main.doclet_could_not_set_location=Could not set location for {0}
main.doclet_no_classloader_found=Could not obtain classloader to load {0} main.doclet_no_classloader_found=Could not obtain classloader to load {0}
main.could_not_instantiate_class=Could not instantiate class {0} main.could_not_instantiate_class=Could not instantiate class {0}
@ -286,7 +286,15 @@ main.illegal_option_value=Illegal option value: "{0}"
main.release.bootclasspath.conflict=option {0} cannot be used together with -release main.release.bootclasspath.conflict=option {0} cannot be used together with -release
main.unsupported.release.version=release version {0} not supported main.unsupported.release.version=release version {0} not supported
main.release.not.standard.file.manager=-release option specified, but the provided JavaFileManager is not a StandardJavaFileManager. main.release.not.standard.file.manager=-release option specified, but the provided JavaFileManager is not a StandardJavaFileManager.
main.file.manager.list=FileManager error listing files: "{0}"
main.assertion.error=assertion failed: "{0}}"
main.unknown.error=an unknown error has occurred main.unknown.error=an unknown error has occurred
main.internal.error=an internal error has occurred
main.unexpected.exception=an unexpected exception was caught: {0}
doclet.internal.report.bug=\
Please file a bug against the javadoc tool via the Java bug reporting page\n\
(http://bugreport.java.com) after checking the Bug Database (http://bugs.java.com)\n\
for duplicates. Include error messages and the following diagnostic in your report. Thank you.
main.legacy_api=The old Doclet and Taglet APIs in the packages\n\ main.legacy_api=The old Doclet and Taglet APIs in the packages\n\
com.sun.javadoc, com.sun.tools.doclets and their implementations\n\ com.sun.javadoc, com.sun.tools.doclets and their implementations\n\
are planned to be removed in a future JDK release. These\n\ are planned to be removed in a future JDK release. These\n\

View file

@ -42,7 +42,7 @@ public class T6735320 extends JavadocTester {
void test() { void test() {
javadoc("-d", "out", javadoc("-d", "out",
testSrc("SerialFieldTest.java")); testSrc("SerialFieldTest.java"));
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
checkOutput(Output.STDERR, false, checkOutput(Output.STDERR, false,
"OutOfBoundsException"); "OutOfBoundsException");
} }

View file

@ -42,7 +42,7 @@ public class TestDupThrowsTags extends JavadocTester {
void test() { void test() {
javadoc("-d", "out", javadoc("-d", "out",
testSrc("TestDupThrowsTags.java")); testSrc("TestDupThrowsTags.java"));
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
checkOutput("TestDupThrowsTags.html", true, checkOutput("TestDupThrowsTags.html", true,
"Test 1 passes", "Test 1 passes",

View file

@ -327,15 +327,27 @@ public abstract class JavadocTester {
outputDirectoryCheck = c; outputDirectoryCheck = c;
} }
/**
* The exit codes returned by the javadoc tool.
* @see jdk.javadoc.internal.tool.Main.Result
*/
public enum Exit { public enum Exit {
OK(0), OK(0), // Javadoc completed with no errors.
FAILED(1); ERROR(1), // Completed but reported errors.
CMDERR(2), // Bad command-line arguments
SYSERR(3), // System error or resource exhaustion.
ABNORMAL(4); // Javadoc terminated abnormally
Exit(int code) { Exit(int code) {
this.code = code; this.code = code;
} }
final int code; final int code;
@Override
public String toString() {
return name() + '(' + code + ')';
}
} }
/** /**
@ -349,7 +361,7 @@ public abstract class JavadocTester {
if (exitCode == expected.code) { if (exitCode == expected.code) {
passed("return code " + exitCode); passed("return code " + exitCode);
} else { } else {
failed("return code " + exitCode +"; expected " + expected.code + " (" + expected + ")"); failed("return code " + exitCode +"; expected " + expected);
} }
} }

View file

@ -50,6 +50,6 @@ public class TestBadSourceFile extends JavadocTester {
javadoc("-Xdoclint:none", javadoc("-Xdoclint:none",
"-d", "out", "-d", "out",
testSrc("C2.java")); testSrc("C2.java"));
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
} }
} }

View file

@ -45,7 +45,7 @@ public class TestConstantValuesPage extends JavadocTester {
javadoc("-d", "out", javadoc("-d", "out",
"-sourcepath", testSrc, "-sourcepath", testSrc,
"foo"); "foo");
checkExit(Exit.FAILED); checkExit(Exit.CMDERR);
checkOutput(Output.OUT, false, checkOutput(Output.OUT, false,
"constant-values.html..."); "constant-values.html...");

View file

@ -52,6 +52,8 @@ public class TestDocErrorReporter extends JavadocTester {
"-encoding", "xyz", "-encoding", "xyz",
testSrc("TestDocErrorReporter.java")); testSrc("TestDocErrorReporter.java"));
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
checkOutput(Output.OUT, true, "error: unsupported encoding: xyz");
} }
} }

View file

@ -111,7 +111,7 @@ public class TestHelpOption extends JavadocTester {
"-helpfile", testSrc("test-help.html"), "-helpfile", testSrc("test-help.html"),
"-helpfile", testSrc("test-help.html"), "-helpfile", testSrc("test-help.html"),
testSrc("Sample.java")); testSrc("Sample.java"));
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
} }
@Test @Test
@ -121,7 +121,7 @@ public class TestHelpOption extends JavadocTester {
"-helpfile", testSrc("test-help.html"), "-helpfile", testSrc("test-help.html"),
"-nohelp", "-nohelp",
testSrc("Sample.java")); testSrc("Sample.java"));
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
} }
private void checkOutput(boolean withOption) { private void checkOutput(boolean withOption) {

View file

@ -57,7 +57,7 @@ public class TestIOException extends JavadocTester {
try { try {
javadoc("-d", outDir.toString(), javadoc("-d", outDir.toString(),
new File(testSrc, "TestIOException.java").getPath()); new File(testSrc, "TestIOException.java").getPath());
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
checkOutput(Output.OUT, true, checkOutput(Output.OUT, true,
"Destination directory not writable: " + outDir); "Destination directory not writable: " + outDir);
} finally { } finally {
@ -85,7 +85,7 @@ public class TestIOException extends JavadocTester {
javadoc("-d", outDir.toString(), javadoc("-d", outDir.toString(),
new File(testSrc, "TestIOException.java").getPath()); new File(testSrc, "TestIOException.java").getPath());
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
checkOutput(Output.OUT, true, checkOutput(Output.OUT, true,
"Error writing file: " + index); "Error writing file: " + index);
} finally { } finally {
@ -123,7 +123,7 @@ public class TestIOException extends JavadocTester {
setOutputDirectoryCheck(DirectoryCheck.NONE); setOutputDirectoryCheck(DirectoryCheck.NONE);
javadoc("-d", outDir.toString(), javadoc("-d", outDir.toString(),
src_p_C.getPath()); src_p_C.getPath());
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
checkOutput(Output.OUT, true, checkOutput(Output.OUT, true,
"Error writing file: " + new File(pkgOutDir, "C.html")); "Error writing file: " + new File(pkgOutDir, "C.html"));
} finally { } finally {
@ -167,7 +167,7 @@ public class TestIOException extends JavadocTester {
javadoc("-d", outDir.toString(), javadoc("-d", outDir.toString(),
"-sourcepath", srcDir.getPath(), "-sourcepath", srcDir.getPath(),
"p"); "p");
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
checkOutput(Output.OUT, true, checkOutput(Output.OUT, true,
"Error writing file: " + new File(docFilesOutDir, "info.txt")); "Error writing file: " + new File(docFilesOutDir, "info.txt"));
} finally { } finally {

View file

@ -42,7 +42,7 @@ public class TestPackageHtml extends JavadocTester {
javadoc("-d", "out-pkg-html", javadoc("-d", "out-pkg-html",
"-sourcepath", testSrc, "-sourcepath", testSrc,
"pkg1"); "pkg1");
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
checkOutput(Output.OUT, true, "package.html:10: error: bad use of '>'"); checkOutput(Output.OUT, true, "package.html:10: error: bad use of '>'");
} }
} }

View file

@ -46,7 +46,7 @@ public class TestParamTaglet extends JavadocTester {
javadoc("-d", "out", javadoc("-d", "out",
"-sourcepath", testSrc, "-sourcepath", testSrc,
"pkg"); "pkg");
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
checkOutput("pkg/C.html", true, checkOutput("pkg/C.html", true,
//Regular param tags. //Regular param tags.

View file

@ -73,7 +73,7 @@ public class TestSearch extends JavadocTester {
void test2a() { void test2a() {
javadoc("-d", "out-2a", "-Xdoclint:all", "-sourcepath", testSrc, javadoc("-d", "out-2a", "-Xdoclint:all", "-sourcepath", testSrc,
"-use", "pkg", "pkg1", "pkg2", "pkg3"); "-use", "pkg", "pkg1", "pkg2", "pkg3");
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
checkDocLintErrors(); checkDocLintErrors();
checkSearchOutput(true); checkSearchOutput(true);
checkSingleIndex(true); checkSingleIndex(true);

View file

@ -44,7 +44,7 @@ public class TestSerializedFormDeprecationInfo extends JavadocTester {
javadoc("-d", "out-default", javadoc("-d", "out-default",
"-sourcepath", testSrc, "-sourcepath", testSrc,
"pkg1"); "pkg1");
checkExit(Exit.FAILED); // TODO: should be OK checkExit(Exit.OK);
checkCommentDeprecated(true); checkCommentDeprecated(true);
checkNoComment(false); checkNoComment(false);
@ -56,7 +56,7 @@ public class TestSerializedFormDeprecationInfo extends JavadocTester {
"-nocomment", "-nocomment",
"-sourcepath", testSrc, "-sourcepath", testSrc,
"pkg1"); "pkg1");
checkExit(Exit.FAILED); // TODO: should be OK checkExit(Exit.OK);
checkNoComment(true); checkNoComment(true);
checkCommentDeprecated(false); checkCommentDeprecated(false);
@ -68,7 +68,7 @@ public class TestSerializedFormDeprecationInfo extends JavadocTester {
"-nodeprecated", "-nodeprecated",
"-sourcepath", testSrc, "-sourcepath", testSrc,
"pkg1"); "pkg1");
checkExit(Exit.FAILED); // TODO: should be OK checkExit(Exit.OK);
checkNoDeprecated(true); checkNoDeprecated(true);
checkNoCommentNoDeprecated(false); checkNoCommentNoDeprecated(false);
@ -81,7 +81,7 @@ public class TestSerializedFormDeprecationInfo extends JavadocTester {
"-nodeprecated", "-nodeprecated",
"-sourcepath", testSrc, "-sourcepath", testSrc,
"pkg1"); "pkg1");
checkExit(Exit.FAILED); // TODO: should be OK checkExit(Exit.OK);
checkNoCommentNoDeprecated(true); checkNoCommentNoDeprecated(true);
checkNoDeprecated(false); checkNoDeprecated(false);
} }
@ -93,7 +93,7 @@ public class TestSerializedFormDeprecationInfo extends JavadocTester {
"<dl>\n" "<dl>\n"
+ "<dt><span class=\"throwsLabel\">Throws:</span></dt>\n" + "<dt><span class=\"throwsLabel\">Throws:</span></dt>\n"
+ "<dd><code>" + "<dd><code>"
+ "java.io.IOException</code></dd>\n" + "java.io.IOException</code> - on error</dd>\n"
+ "<dt><span class=\"seeLabel\">See Also:</span>" + "<dt><span class=\"seeLabel\">See Also:</span>"
+ "</dt>\n" + "</dt>\n"
+ "<dd><a href=\"pkg1/C1.html#setUndecorated-boolean-\">" + "<dd><a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
@ -121,7 +121,7 @@ public class TestSerializedFormDeprecationInfo extends JavadocTester {
+ "<div class=\"block\">Reads the object stream.</div>\n" + "<div class=\"block\">Reads the object stream.</div>\n"
+ "<dl>\n" + "<dl>\n"
+ "<dt><span class=\"throwsLabel\">Throws:</span></dt>\n" + "<dt><span class=\"throwsLabel\">Throws:</span></dt>\n"
+ "<dd><code>java.io.IOException</code></dd>\n" + "<dd><code>java.io.IOException</code> - on error</dd>\n"
+ "</dl>", + "</dl>",
"<span class=\"deprecatedLabel\">Deprecated.</span>" "<span class=\"deprecatedLabel\">Deprecated.</span>"
+ "&nbsp;</div>\n" + "&nbsp;</div>\n"

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -75,7 +75,6 @@ public class C1 implements Serializable {
* @param test boolean value * @param test boolean value
* @exception IllegalArgumentException if the <code>owner</code>'s * @exception IllegalArgumentException if the <code>owner</code>'s
* <code>GraphicsConfiguration</code> is not from a screen device * <code>GraphicsConfiguration</code> is not from a screen device
* @exception HeadlessException
*/ */
public C1(String title, boolean test) { public C1(String title, boolean test) {
@ -98,6 +97,7 @@ public class C1 implements Serializable {
} }
/** /**
* @throws java.io.IOException on error
* @see #setUndecorated(boolean) * @see #setUndecorated(boolean)
*/ */
public void readObject() throws IOException { public void readObject() throws IOException {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -74,7 +74,7 @@ public class C2 implements Serializable {
* Reads the object stream. * Reads the object stream.
* *
* @param s ObjectInputStream * @param s ObjectInputStream
* @throws IOException * @throws IOException on error
* @deprecated As of JDK version 1.5, replaced by * @deprecated As of JDK version 1.5, replaced by
* {@link C1#setUndecorated(boolean) setUndecorated(boolean)}. * {@link C1#setUndecorated(boolean) setUndecorated(boolean)}.
*/ */

View file

@ -45,7 +45,7 @@ public class TestSinceTag extends JavadocTester {
javadoc("-d", "out-since", javadoc("-d", "out-since",
"-sourcepath", testSrc, "-sourcepath", testSrc,
"pkg1"); "pkg1");
checkExit(Exit.FAILED); // TODO: investigate checkExit(Exit.OK);
checkSince(true); checkSince(true);
} }
@ -56,7 +56,7 @@ public class TestSinceTag extends JavadocTester {
"-sourcepath", testSrc, "-sourcepath", testSrc,
"-nosince", "-nosince",
"pkg1"); "pkg1");
checkExit(Exit.FAILED); // TODO: investigate checkExit(Exit.OK);
checkSince(false); checkSince(false);
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -72,7 +72,6 @@ public class C1 implements Serializable {
* @param test boolean value * @param test boolean value
* @exception IllegalArgumentException if the <code>owner</code>'s * @exception IllegalArgumentException if the <code>owner</code>'s
* <code>GraphicsConfiguration</code> is not from a screen device * <code>GraphicsConfiguration</code> is not from a screen device
* @exception HeadlessException
*/ */
public C1(String title, boolean test) { public C1(String title, boolean test) {
} }
@ -93,6 +92,7 @@ public class C1 implements Serializable {
} }
/** /**
* @throws java.io.IOException on error
* @see #setUndecorated(boolean) * @see #setUndecorated(boolean)
*/ */
public void readObject() throws IOException { public void readObject() throws IOException {

View file

@ -52,7 +52,7 @@ public class TestSupplementary extends JavadocTester {
javadoc("-locale", "en_US", javadoc("-locale", "en_US",
"-d", "out", "-d", "out",
testSrc("C.java")); testSrc("C.java"));
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
checkOutput(Output.OUT, true, checkOutput(Output.OUT, true,
"C.java:36: error: unexpected text", "C.java:36: error: unexpected text",

View file

@ -45,7 +45,7 @@ public class TestThrowsTag extends JavadocTester {
javadoc("-d", "out", javadoc("-d", "out",
"-sourcepath", testSrc, "-sourcepath", testSrc,
"pkg"); "pkg");
checkExit(Exit.FAILED); // TODO: investigate why failed checkExit(Exit.OK);
checkOutput("pkg/C.html", true, checkOutput("pkg/C.html", true,
"<dd><code><a href=\"../pkg/T1.html\" title=\"class in pkg\">T1</a></code> - the first throws tag.</dd>\n" + "<dd><code><a href=\"../pkg/T1.html\" title=\"class in pkg\">T1</a></code> - the first throws tag.</dd>\n" +

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,4 +23,4 @@
package pkg; package pkg;
public class T1 extends Exception {} public class T1 extends RuntimeException {}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,4 +23,4 @@
package pkg; package pkg;
public class T2 extends Exception {} public class T2 extends RuntimeException {}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,4 +23,4 @@
package pkg; package pkg;
public class T3 extends Exception {} public class T3 extends RuntimeException {}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,4 +23,4 @@
package pkg; package pkg;
public class T4 extends Exception {} public class T4 extends RuntimeException {}

View file

@ -46,7 +46,7 @@ public class TestValueTag extends JavadocTester {
"-sourcepath", testSrc, "-sourcepath", testSrc,
"-tag", "todo", "-tag", "todo",
"pkg1", "pkg2"); "pkg1", "pkg2");
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
checkOutput("pkg1/Class1.html", true, checkOutput("pkg1/Class1.html", true,
// Base case: using @value on a constant. // Base case: using @value on a constant.

View file

@ -47,7 +47,7 @@ public class TestWarnings extends JavadocTester {
javadoc("-d", "out-default", javadoc("-d", "out-default",
"-sourcepath", testSrc, "-sourcepath", testSrc,
"pkg"); "pkg");
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
checkOutput(Output.OUT, true, checkOutput(Output.OUT, true,
"X.java:23: error: self-closing element not allowed"); "X.java:23: error: self-closing element not allowed");
@ -75,7 +75,7 @@ public class TestWarnings extends JavadocTester {
"-private", "-private",
"-sourcepath", testSrc, "-sourcepath", testSrc,
"pkg"); "pkg");
checkExit(Exit.FAILED); checkExit(Exit.ERROR);
checkOutput("pkg/X.html", true, checkOutput("pkg/X.html", true,
"<a href=\"../pkg/X.html#m--\"><code>m()</code></a><br/>", "<a href=\"../pkg/X.html#m--\"><code>m()</code></a><br/>",

View file

@ -28,7 +28,11 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.function.Predicate; import java.util.function.Predicate;
import jdk.javadoc.internal.tool.Main; import jdk.javadoc.internal.tool.Main;
import jdk.javadoc.internal.tool.Main.Result;
import static jdk.javadoc.internal.tool.Main.Result.*;
/** /**
* @test * @test
@ -43,13 +47,13 @@ public class ReleaseOption {
} }
void run() { void run() {
doRunTest(0, out -> out.contains("compiler.err.doesnt.exist: java.util.stream"), "--release", "7"); doRunTest(OK, out -> out.contains("compiler.err.doesnt.exist: java.util.stream"), "--release", "7");
doRunTest(0, out -> !out.contains("compiler.err.doesnt.exist: java.util.stream"), "--release", "8"); doRunTest(OK, out -> !out.contains("compiler.err.doesnt.exist: java.util.stream"), "--release", "8");
doRunTest(1, out -> true, "--release", "7", "-source", "7"); doRunTest(CMDERR, out -> true, "--release", "7", "-source", "7");
doRunTest(1, out -> true, "--release", "7", "-bootclasspath", "any"); doRunTest(CMDERR, out -> true, "--release", "7", "-bootclasspath", "any");
} }
void doRunTest(int expectedResult, Predicate<String> validate, String... args) { void doRunTest(Result expectedResult, Predicate<String> validate, String... args) {
System.err.println("running with args: " + Arrays.asList(args)); System.err.println("running with args: " + Arrays.asList(args));
List<String> options = new ArrayList<>(); List<String> options = new ArrayList<>();
options.addAll(Arrays.asList(args)); options.addAll(Arrays.asList(args));
@ -60,7 +64,7 @@ public class ReleaseOption {
int actualResult = Main.execute(options.toArray(new String[0]), pw); int actualResult = Main.execute(options.toArray(new String[0]), pw);
System.err.println("actual result=" + actualResult); System.err.println("actual result=" + actualResult);
System.err.println("actual output=" + out.toString()); System.err.println("actual output=" + out.toString());
if (actualResult != expectedResult) if (actualResult != expectedResult.exitCode)
throw new Error("Exit code not as expected"); throw new Error("Exit code not as expected");
if (!validate.test(out.toString())) { if (!validate.test(out.toString())) {
throw new Error("Output not as expected"); throw new Error("Output not as expected");

View file

@ -0,0 +1,146 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8151102
* @summary verify that option --dump-on-error functions correctly
* @library /tools/lib
* @modules
* jdk.javadoc/jdk.javadoc.internal.api
* jdk.javadoc/jdk.javadoc.internal.tool
* jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* @build toolbox.ToolBox toolbox.TestRunner
* @run main TestExceptionHandling
*/
import java.io.File;
import java.io.PrintStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import toolbox.*;
/**
* This class tests if stack traces printed when
* --dump-on-error. The standard doclet is used,
* to test the doclet as well as the tool.
*/
public class TestExceptionHandling extends TestRunner {
final ToolBox tb;
final File testSrcFile;
final PrintStream ostream;
final JavadocTask cmdTask;
final JavadocTask apiTask;
public static void main(String... args) throws Exception {
TestExceptionHandling tester = new TestExceptionHandling();
tester.runTests();
}
TestExceptionHandling() {
super(System.err);
tb = new ToolBox();
ostream = System.err;
testSrcFile = new File(System.getProperty("test.src"), "TestExceptionHandling.java");
cmdTask = new JavadocTask(tb, Task.Mode.CMDLINE);
apiTask = new JavadocTask(tb, Task.Mode.API);
}
@Test
public void testDocletTrace() throws Exception {
Path out = Paths.get("out");
// create a file with the same name as the output
out.toFile().createNewFile();
cmdTask.outdir(out);
cmdTask.options("--dump-on-error");
cmdTask.files(testSrcFile.getAbsolutePath());
Task.Result tr = cmdTask.run(Task.Expect.FAIL);
String errString = "Destination directory is not a directory: " + out.toString();
// check the regular message
assertPresent("javadoc: error - " + errString, tr.getOutputLines(Task.OutputKind.DIRECT));
// check that first line of the stack trace is present
assertPresent("jdk.javadoc.internal.doclets.toolkit.util.SimpleDocletException: " +
errString, tr.getOutputLines(Task.OutputKind.STDERR));
}
@Test
public void testToolTrace() throws Exception {
Path out = Paths.get("out.dir");
cmdTask.options("--dump-on-error", "-doclet", "NonExistentDoclet");
cmdTask.outdir(out);
cmdTask.files(testSrcFile.getAbsolutePath());
Task.Result tr = cmdTask.run(Task.Expect.FAIL);
// check the regular message
assertPresent("javadoc: error - Cannot find doclet class NonExistentDoclet",
tr.getOutputLines(Task.OutputKind.DIRECT));
// check that first line of the stack trace is present
assertPresent("java.lang.ClassNotFoundException: NonExistentDoclet",
tr.getOutputLines(Task.OutputKind.STDERR));
}
@Test
public void testApiModeMissingDoclet() throws Exception {
apiTask.options("-doclet", "MissingDoclet");
try {
Task.Result result = apiTask.run(Task.Expect.FAIL);
} catch (IllegalArgumentException iae) {
// ok got the right exception
return;
}
throw new Exception("expected exception/error not found");
}
@Test
public void testApiModeMultipleDoclets() throws Exception {
apiTask.options("-doclet", "MissingDoclet",
"-doclet", "SomeDoclet");
try {
Task.Result result = apiTask.run(Task.Expect.FAIL);
} catch (IllegalArgumentException iae) {
// ok got the right exception
return;
}
throw new Exception("expected exception/error not found");
}
void assertPresent(String regex, List<String> output) throws Exception {
List<String> gresult = tb.grep(regex, output);
if (gresult.isEmpty()) {
ostream.println("Expected: " + regex);
ostream.println("Output: ");
output.forEach(s -> {
ostream.println(s);
});
throw new Exception("Test fails expected output not found: " + regex);
}
}
}