6251738: Want a top-level summary page that itemizes all spec documents referenced from javadocs (OEM spec)
Reviewed-by: hannesw
This commit is contained in:
parent
aca4276e89
commit
b88ee1ee22
@ -69,8 +69,6 @@ JAVADOC_TAGS := \
|
||||
-tag beaninfo:X \
|
||||
-tag revised:X \
|
||||
-tag since.unbundled:X \
|
||||
-tag spec:X \
|
||||
-tag specdefault:X \
|
||||
-tag Note:X \
|
||||
-tag ToDo:X \
|
||||
-tag 'apiNote:a:API Note:' \
|
||||
@ -86,6 +84,7 @@ JAVADOC_TAGS := \
|
||||
-tag since \
|
||||
-tag serialData \
|
||||
-tag factory \
|
||||
-tag spec \
|
||||
-tag see \
|
||||
-taglet build.tools.taglet.ExtLink \
|
||||
-taglet build.tools.taglet.Incubating \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2022, 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
|
||||
@ -218,6 +218,14 @@ public interface DocTree {
|
||||
*/
|
||||
SNIPPET("snippet"),
|
||||
|
||||
/**
|
||||
* Used for instances of {@link SpecTree}
|
||||
* representing an {@code @spec} tag.
|
||||
*
|
||||
* @since 20
|
||||
*/
|
||||
SPEC("spec"),
|
||||
|
||||
/**
|
||||
* Used for instances of {@link EndElementTree}
|
||||
* representing the start of an HTML element.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2022, 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
|
||||
@ -302,6 +302,22 @@ public interface DocTreeVisitor<R,P> {
|
||||
return visitOther(node, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a {@code SpecTree} node.
|
||||
*
|
||||
* @implSpec Visits the provided {@code SpecTree} node
|
||||
* by calling {@code visitOther(node, p)}.
|
||||
*
|
||||
* @param node the node being visited
|
||||
* @param p a parameter value
|
||||
* @return a result value
|
||||
*
|
||||
* @since 20
|
||||
*/
|
||||
default R visitSpec(SpecTree node, P p) {
|
||||
return visitOther(node, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a {@code StartElementTree} node.
|
||||
* @param node the node being visited
|
||||
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2022, 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 com.sun.source.doctree;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A tree node for an {@code @spec} block tag.
|
||||
*
|
||||
* <pre>
|
||||
* @spec url title
|
||||
* </pre>
|
||||
*
|
||||
* @since 20
|
||||
*/
|
||||
public interface SpecTree extends BlockTagTree {
|
||||
/**
|
||||
* {@return the URL}
|
||||
*/
|
||||
TextTree getURL();
|
||||
|
||||
/**
|
||||
* {@return the title}
|
||||
*/
|
||||
List<? extends DocTree> getTitle();
|
||||
}
|
@ -59,6 +59,7 @@ import com.sun.source.doctree.SerialFieldTree;
|
||||
import com.sun.source.doctree.SerialTree;
|
||||
import com.sun.source.doctree.SinceTree;
|
||||
import com.sun.source.doctree.SnippetTree;
|
||||
import com.sun.source.doctree.SpecTree;
|
||||
import com.sun.source.doctree.StartElementTree;
|
||||
import com.sun.source.doctree.SummaryTree;
|
||||
import com.sun.source.doctree.SystemPropertyTree;
|
||||
@ -336,6 +337,15 @@ public interface DocTreeFactory {
|
||||
*/
|
||||
SnippetTree newSnippetTree(List<? extends DocTree> attributes, TextTree text);
|
||||
|
||||
/**
|
||||
* Creates a new {@code SpecTree} object, to represent an {@code @spec} tag.
|
||||
* @param url the url
|
||||
* @param title the title
|
||||
* @return a {@code SpecTree} object
|
||||
* @since 20
|
||||
*/
|
||||
SpecTree newSpecTree(TextTree url, List<? extends DocTree> title);
|
||||
|
||||
/**
|
||||
* Creates a new {@code StartElementTree} object, to represent the start of an HTML element.
|
||||
* @param name the name of the HTML element
|
||||
|
@ -515,6 +515,23 @@ public class DocTreeScanner<R,P> implements DocTreeVisitor<R,P> {
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @implSpec This implementation scans the children in left to right order.
|
||||
*
|
||||
* @param node {@inheritDoc}
|
||||
* @param p {@inheritDoc}
|
||||
* @return the result of scanning
|
||||
* @since 20
|
||||
*/
|
||||
@Override
|
||||
public R visitSpec(SpecTree node, P p) {
|
||||
R r = scan(node.getURL(), p);
|
||||
r = scanAndReduce(node.getTitle(), p, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2022, 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
|
||||
@ -463,6 +463,23 @@ public class SimpleDocTreeVisitor<R,P> implements DocTreeVisitor<R, P> {
|
||||
return defaultAction(node, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @implSpec This implementation calls {@code defaultAction}.
|
||||
*
|
||||
* @param node {@inheritDoc}
|
||||
* @param p {@inheritDoc}
|
||||
*
|
||||
* @return the result of {@code defaultAction}
|
||||
*
|
||||
* @since 20
|
||||
*/
|
||||
@Override
|
||||
public R visitSpec(SpecTree node, P p) {
|
||||
return defaultAction(node, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -1551,6 +1551,24 @@ public class DocCommentParser {
|
||||
}
|
||||
},
|
||||
|
||||
// @spec url label
|
||||
new TagParser(TagParser.Kind.BLOCK, DCTree.Kind.SPEC) {
|
||||
@Override
|
||||
public DCTree parse(int pos) throws ParseException {
|
||||
skipWhitespace();
|
||||
DCText url = inlineWord();
|
||||
if (url == null || url.isBlank()) {
|
||||
throw new ParseException("dc.no.url");
|
||||
}
|
||||
skipWhitespace();
|
||||
List<DCTree> title = blockContent();
|
||||
if (title.isEmpty() || DCTree.isBlank(title)) {
|
||||
throw new ParseException("dc.no.title");
|
||||
}
|
||||
return m.at(pos).newSpecTree(url, title);
|
||||
}
|
||||
},
|
||||
|
||||
// {@summary summary-text}
|
||||
new TagParser(TagParser.Kind.INLINE, DCTree.Kind.SUMMARY) {
|
||||
@Override
|
||||
|
@ -3322,6 +3322,12 @@ compiler.err.dc.no.content=\
|
||||
compiler.err.dc.no.tag.name=\
|
||||
no tag name after '@'
|
||||
|
||||
compiler.err.dc.no.url=\
|
||||
no URL
|
||||
|
||||
compiler.err.dc.no.title=\
|
||||
no title
|
||||
|
||||
compiler.err.dc.gt.expected=\
|
||||
''>'' expected
|
||||
|
||||
|
@ -42,7 +42,6 @@ import com.sun.tools.javac.util.Assert;
|
||||
import com.sun.tools.javac.util.DefinedBy;
|
||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
import com.sun.tools.javac.util.JCDiagnostic;
|
||||
import com.sun.tools.javac.util.Position;
|
||||
|
||||
import static com.sun.tools.javac.util.Position.NOPOS;
|
||||
|
||||
@ -225,6 +224,14 @@ public abstract class DCTree implements DocTree {
|
||||
return NOPOS;
|
||||
}
|
||||
|
||||
public boolean isBlank() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isBlank(List<? extends DCTree> list) {
|
||||
return list.stream().allMatch(DCTree::isBlank);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a tree to a pretty-printed string.
|
||||
*/
|
||||
@ -1080,6 +1087,41 @@ public abstract class DCTree implements DocTree {
|
||||
}
|
||||
}
|
||||
|
||||
public static class DCSpec extends DCBlockTag implements SpecTree {
|
||||
public final DCText uri;
|
||||
public final List<DCTree> title;
|
||||
|
||||
DCSpec(DCText uri, List<DCTree> title) {
|
||||
this.uri = uri;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTagName() {
|
||||
return "spec";
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public Kind getKind() {
|
||||
return Kind.SPEC;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public <R, D> R accept(DocTreeVisitor<R, D> v, D d) {
|
||||
return v.visitSpec(this, d);
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public TextTree getURL() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public List<? extends DocTree> getTitle() {
|
||||
return title;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DCStartElement extends DCEndPosTree<DCStartElement> implements StartElementTree {
|
||||
public final Name name;
|
||||
public final List<DCTree> attrs;
|
||||
@ -1170,6 +1212,11 @@ public abstract class DCTree implements DocTree {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlank() {
|
||||
return text.isBlank();
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public Kind getKind() {
|
||||
return Kind.TEXT;
|
||||
|
@ -504,6 +504,20 @@ public class DocPretty implements DocTreeVisitor<Void,Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public Void visitSpec(SpecTree node, Void p) {
|
||||
try {
|
||||
printTagName(node);
|
||||
print(" ");
|
||||
print(node.getURL());
|
||||
print(" ");
|
||||
print(node.getTitle());
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public Void visitStartElement(StartElementTree node, Void p) {
|
||||
try {
|
||||
|
@ -76,6 +76,7 @@ import com.sun.tools.javac.tree.DCTree.DCSerialData;
|
||||
import com.sun.tools.javac.tree.DCTree.DCSerialField;
|
||||
import com.sun.tools.javac.tree.DCTree.DCSince;
|
||||
import com.sun.tools.javac.tree.DCTree.DCSnippet;
|
||||
import com.sun.tools.javac.tree.DCTree.DCSpec;
|
||||
import com.sun.tools.javac.tree.DCTree.DCStartElement;
|
||||
import com.sun.tools.javac.tree.DCTree.DCSummary;
|
||||
import com.sun.tools.javac.tree.DCTree.DCSystemProperty;
|
||||
@ -89,9 +90,7 @@ import com.sun.tools.javac.tree.DCTree.DCVersion;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.DefinedBy;
|
||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
import com.sun.tools.javac.util.DiagnosticSource;
|
||||
import com.sun.tools.javac.util.JCDiagnostic;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
import com.sun.tools.javac.util.ListBuffer;
|
||||
import com.sun.tools.javac.util.Pair;
|
||||
import com.sun.tools.javac.util.Position;
|
||||
@ -124,7 +123,7 @@ public class DocTreeMaker implements DocTreeFactory {
|
||||
|
||||
/** The position at which subsequent trees will be created.
|
||||
*/
|
||||
public int pos = Position.NOPOS;
|
||||
public int pos;
|
||||
|
||||
private final JavacTrees trees;
|
||||
|
||||
@ -238,9 +237,8 @@ public class DocTreeMaker implements DocTreeFactory {
|
||||
}
|
||||
};
|
||||
Pair<List<DCTree>, List<DCTree>> pair = splitBody(fullBody);
|
||||
DCDocComment tree = new DCDocComment(c, fBody, pair.fst, pair.snd, cast(tags),
|
||||
return new DCDocComment(c, fBody, pair.fst, pair.snd, cast(tags),
|
||||
cast(preamble), cast(postamble));
|
||||
return tree;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
@ -421,6 +419,13 @@ public class DocTreeMaker implements DocTreeFactory {
|
||||
return tree;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public DCSpec newSpecTree(TextTree url, List<? extends DocTree> title) {
|
||||
DCSpec tree = new DCSpec((DCText) url, cast(title));
|
||||
tree.pos = pos;
|
||||
return tree;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public DCStartElement newStartElementTree(Name name, List<? extends DocTree> attrs, boolean selfClosing) {
|
||||
DCStartElement tree = new DCStartElement(name, cast(attrs), selfClosing);
|
||||
|
@ -95,6 +95,7 @@ public class Contents {
|
||||
public final Content exceptionClass;
|
||||
public final Content exceptionClasses;
|
||||
public final Content exportedTo;
|
||||
public final Content externalSpecifications;
|
||||
public final Content fieldLabel;
|
||||
public final Content fieldDetailsLabel;
|
||||
public final Content fieldSummaryLabel;
|
||||
@ -169,6 +170,7 @@ public class Contents {
|
||||
public final Content seeAlso;
|
||||
public final Content serializedForm;
|
||||
public final Content servicesLabel;
|
||||
public final Content specificationLabel;
|
||||
public final Content specifiedByLabel;
|
||||
public final Content subclassesLabel;
|
||||
public final Content subinterfacesLabel;
|
||||
@ -239,6 +241,7 @@ public class Contents {
|
||||
exceptionClass = getContent("doclet.ExceptionClass");
|
||||
exceptionClasses = getContent("doclet.ExceptionClasses");
|
||||
exportedTo = getContent("doclet.ExportedTo");
|
||||
externalSpecifications = getContent("doclet.External_Specifications");
|
||||
fieldDetailsLabel = getContent("doclet.Field_Detail");
|
||||
fieldSummaryLabel = getContent("doclet.Field_Summary");
|
||||
fieldLabel = getContent("doclet.Field");
|
||||
@ -313,6 +316,7 @@ public class Contents {
|
||||
seeAlso = getContent("doclet.See_Also");
|
||||
serializedForm = getContent("doclet.Serialized_Form");
|
||||
servicesLabel = getContent("doclet.Services");
|
||||
specificationLabel = getContent("doclet.Specification");
|
||||
specifiedByLabel = getContent("doclet.Specified_By");
|
||||
subclassesLabel = getContent("doclet.Subclasses");
|
||||
subinterfacesLabel = getContent("doclet.Subinterfaces");
|
||||
|
@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2022, 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.doclets.formats.html;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.Predicate;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
import com.sun.source.doctree.DocTree;
|
||||
import com.sun.source.doctree.SpecTree;
|
||||
import com.sun.source.util.DocTreePath;
|
||||
import com.sun.source.util.TreePath;
|
||||
|
||||
import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||
import jdk.javadoc.internal.doclets.toolkit.DocletElement;
|
||||
import jdk.javadoc.internal.doclets.toolkit.OverviewElement;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexItem;
|
||||
|
||||
import static java.util.stream.Collectors.groupingBy;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* Generates the file with the summary of all the references to external specifications.
|
||||
*/
|
||||
public class ExternalSpecsWriter extends HtmlDocletWriter {
|
||||
|
||||
private final Navigation navBar;
|
||||
|
||||
/**
|
||||
* Cached contents of {@code <title>...</title>} tags of the HTML pages.
|
||||
*/
|
||||
final Map<Element, String> titles = new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* Constructs ExternalSpecsWriter object.
|
||||
*
|
||||
* @param configuration The current configuration
|
||||
* @param filename Path to the file which is getting generated.
|
||||
*/
|
||||
public ExternalSpecsWriter(HtmlConfiguration configuration, DocPath filename) {
|
||||
super(configuration, filename);
|
||||
this.navBar = new Navigation(null, configuration, PageMode.EXTERNAL_SPECS, path);
|
||||
}
|
||||
|
||||
public static void generate(HtmlConfiguration configuration) throws DocFileIOException {
|
||||
generate(configuration, DocPaths.EXTERNAL_SPECS);
|
||||
}
|
||||
|
||||
private static void generate(HtmlConfiguration configuration, DocPath fileName) throws DocFileIOException {
|
||||
boolean hasExternalSpecs = configuration.mainIndex != null
|
||||
&& !configuration.mainIndex.getItems(DocTree.Kind.SPEC).isEmpty();
|
||||
if (!hasExternalSpecs) {
|
||||
return;
|
||||
}
|
||||
ExternalSpecsWriter w = new ExternalSpecsWriter(configuration, fileName);
|
||||
w.buildExternalSpecsPage();
|
||||
configuration.conditionalPages.add(HtmlConfiguration.ConditionalPage.EXTERNAL_SPECS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints all the "external specs" to the file.
|
||||
*/
|
||||
protected void buildExternalSpecsPage() throws DocFileIOException {
|
||||
checkUniqueItems();
|
||||
|
||||
String title = resources.getText("doclet.External_Specifications");
|
||||
HtmlTree body = getBody(getWindowTitle(title));
|
||||
Content mainContent = new ContentBuilder();
|
||||
addExternalSpecs(mainContent);
|
||||
body.add(new BodyContents()
|
||||
.setHeader(getHeader(PageMode.EXTERNAL_SPECS))
|
||||
.addMainContent(HtmlTree.DIV(HtmlStyle.header,
|
||||
HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING,
|
||||
contents.getContent("doclet.External_Specifications"))))
|
||||
.addMainContent(mainContent)
|
||||
.setFooter(getFooter()));
|
||||
printHtmlDocument(null, "external specifications", body);
|
||||
|
||||
if (configuration.mainIndex != null) {
|
||||
configuration.mainIndex.add(IndexItem.of(IndexItem.Category.TAGS, title, path));
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkUniqueItems() {
|
||||
Map<String, Map<String, List<IndexItem>>> itemsByURL = new HashMap<>();
|
||||
Map<String, Map<String, List<IndexItem>>> itemsByTitle = new HashMap<>();
|
||||
for (IndexItem ii : configuration.mainIndex.getItems(DocTree.Kind.SPEC)) {
|
||||
if (ii.getDocTree() instanceof SpecTree st) {
|
||||
String url = st.getURL().toString();
|
||||
String title = st.getTitle().toString();
|
||||
itemsByTitle
|
||||
.computeIfAbsent(title, l -> new HashMap<>())
|
||||
.computeIfAbsent(url, u -> new ArrayList<>())
|
||||
.add(ii);
|
||||
itemsByURL
|
||||
.computeIfAbsent(url, u -> new HashMap<>())
|
||||
.computeIfAbsent(title, l -> new ArrayList<>())
|
||||
.add(ii);
|
||||
}
|
||||
}
|
||||
|
||||
itemsByURL.forEach((url, title) -> {
|
||||
if (title.size() > 1) {
|
||||
messages.error("doclet.extSpec.spec.has.multiple.titles", url,
|
||||
title.values().stream().distinct().count());
|
||||
title.forEach((t, list) ->
|
||||
list.forEach(ii ->
|
||||
report(ii, "doclet.extSpec.url.title", url, t)));
|
||||
}
|
||||
});
|
||||
|
||||
itemsByTitle.forEach((title, urls) -> {
|
||||
if (urls.size() > 1) {
|
||||
messages.error("doclet.extSpec.title.for.multiple.specs", title,
|
||||
urls.values().stream().distinct().count());
|
||||
urls.forEach((u, list) ->
|
||||
list.forEach(ii ->
|
||||
report(ii, "doclet.extSpec.title.url", title, u)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void report(IndexItem ii, String key, Object... args) {
|
||||
String message = messages.getResources().getText(key, args);
|
||||
Element e = ii.getElement();
|
||||
if (e == null) {
|
||||
configuration.reporter.print(Diagnostic.Kind.NOTE, message);
|
||||
} else {
|
||||
TreePath tp = utils.getTreePath(e);
|
||||
DocTreePath dtp = new DocTreePath(new DocTreePath(tp, utils.getDocCommentTree(e)), ii.getDocTree());
|
||||
configuration.reporter.print(Diagnostic.Kind.NOTE, dtp, message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all the references to external specifications to the content tree.
|
||||
*
|
||||
* @param content HtmlTree content to which the links will be added
|
||||
*/
|
||||
protected void addExternalSpecs(Content content) {
|
||||
final int USE_DETAILS_THRESHHOLD = 20;
|
||||
Map<String, List<IndexItem>> searchIndexMap = groupExternalSpecs();
|
||||
Table table = new Table(HtmlStyle.summaryTable)
|
||||
.setCaption(contents.externalSpecifications)
|
||||
.setHeader(new TableHeader(contents.specificationLabel, contents.referencedIn))
|
||||
.setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast);
|
||||
for (List<IndexItem> searchIndexItems : searchIndexMap.values()) {
|
||||
Content specName = createSpecLink(searchIndexItems.get(0));
|
||||
Content referencesList = HtmlTree.UL(HtmlStyle.refList, searchIndexItems,
|
||||
item -> HtmlTree.LI(createLink(item)));
|
||||
Content references = searchIndexItems.size() < USE_DETAILS_THRESHHOLD
|
||||
? referencesList
|
||||
: HtmlTree.DETAILS()
|
||||
.add(HtmlTree.SUMMARY(contents.getContent("doclet.references",
|
||||
String.valueOf(searchIndexItems.size()))))
|
||||
.add(referencesList);
|
||||
table.addRow(specName, references);
|
||||
}
|
||||
content.add(table);
|
||||
}
|
||||
|
||||
private Map<String, List<IndexItem>> groupExternalSpecs() {
|
||||
return configuration.mainIndex.getItems(DocTree.Kind.SPEC).stream()
|
||||
.collect(groupingBy(IndexItem::getLabel, () -> new TreeMap<>(getTitleComparator()), toList()));
|
||||
}
|
||||
|
||||
Comparator<String> getTitleComparator() {
|
||||
Collator collator = Collator.getInstance();
|
||||
return new Comparator<>() {
|
||||
@Override
|
||||
public int compare(String s1, String s2) {
|
||||
int i1 = 0;
|
||||
int i2 = 0;
|
||||
while (i1 < s1.length() && i2 < s2.length()) {
|
||||
int j1 = find(s1, i1, Character::isDigit);
|
||||
int j2 = find(s2, i2, Character::isDigit);
|
||||
int cmp = collator.compare(s1.substring(i1, j1), s2.substring(i2, j2));
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
if (j1 == s1.length() || j2 == s2.length()) {
|
||||
i1 = j1;
|
||||
i2 = j2;
|
||||
break;
|
||||
}
|
||||
int k1 = find(s1, j1, ch -> !Character.isDigit(ch));
|
||||
int k2 = find(s2, j2, ch -> !Character.isDigit(ch));
|
||||
cmp = Integer.compare(Integer.parseInt(s1.substring(j1, k1)), Integer.parseInt(s2.substring(j2, k2)));
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
i1 = k1;
|
||||
i2 = k2;
|
||||
}
|
||||
return i1 < s1.length() ? 1 : i2 < s2.length() ? -1 : 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static int find(String s, int start, Predicate<Character> p) {
|
||||
int i = start;
|
||||
while (i < s.length() && !p.test(s.charAt(i))) {
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
private Content createLink(IndexItem i) {
|
||||
assert i.getDocTree().getKind() == DocTree.Kind.SPEC : i;
|
||||
Element element = i.getElement();
|
||||
if (element instanceof OverviewElement) {
|
||||
return links.createLink(pathToRoot.resolve(i.getUrl()),
|
||||
resources.getText("doclet.Overview"));
|
||||
} else if (element instanceof DocletElement) {
|
||||
DocletElement e = (DocletElement) element;
|
||||
// Implementations of DocletElement do not override equals and
|
||||
// hashCode; putting instances of DocletElement in a map is not
|
||||
// incorrect, but might well be inefficient
|
||||
String t = titles.computeIfAbsent(element, utils::getHTMLTitle);
|
||||
if (t.isBlank()) {
|
||||
// The user should probably be notified (a warning?) that this
|
||||
// file does not have a title
|
||||
Path p = Path.of(e.getFileObject().toUri());
|
||||
t = p.getFileName().toString();
|
||||
}
|
||||
ContentBuilder b = new ContentBuilder();
|
||||
b.add(HtmlTree.CODE(Text.of(i.getHolder() + ": ")));
|
||||
// non-program elements should be displayed using a normal font
|
||||
b.add(t);
|
||||
return links.createLink(pathToRoot.resolve(i.getUrl()), b);
|
||||
} else {
|
||||
// program elements should be displayed using a code font
|
||||
Content link = links.createLink(pathToRoot.resolve(i.getUrl()), i.getHolder());
|
||||
return HtmlTree.CODE(link);
|
||||
}
|
||||
}
|
||||
|
||||
private Content createSpecLink(IndexItem i) {
|
||||
assert i.getDocTree().getKind() == DocTree.Kind.SPEC : i;
|
||||
SpecTree specTree = (SpecTree) i.getDocTree();
|
||||
|
||||
Content title = Text.of(i.getLabel());
|
||||
|
||||
URI specURI;
|
||||
try {
|
||||
specURI = new URI(specTree.getURL().getBody());
|
||||
} catch (URISyntaxException e) {
|
||||
// should not happen: items with bad URIs should not make it into the index
|
||||
return title;
|
||||
}
|
||||
|
||||
return HtmlTree.A(resolveExternalSpecURI(specURI), title);
|
||||
}
|
||||
}
|
@ -390,6 +390,15 @@ public class HelpWriter extends HtmlDocletWriter {
|
||||
pageKindsSection.add(section);
|
||||
}
|
||||
|
||||
// External Specification
|
||||
if (configuration.conditionalPages.contains(HtmlConfiguration.ConditionalPage.EXTERNAL_SPECS)) {
|
||||
section = newHelpSection(contents.externalSpecifications, PageMode.EXTERNAL_SPECS, subTOC);
|
||||
Content extSpecsBody = getContent("doclet.help.externalSpecifications.body",
|
||||
links.createLink(DocPaths.EXTERNAL_SPECS, resources.getText("doclet.External_Specifications")));
|
||||
section.add(HtmlTree.P(extSpecsBody));
|
||||
pageKindsSection.add(section);
|
||||
}
|
||||
|
||||
// Index
|
||||
if (options.createIndex()) {
|
||||
if (!configuration.packages.isEmpty()) {
|
||||
|
@ -149,7 +149,7 @@ public class HtmlConfiguration extends BaseConfiguration {
|
||||
// Note: this should (eventually) be merged with Navigation.PageMode,
|
||||
// which performs a somewhat similar role
|
||||
public enum ConditionalPage {
|
||||
CONSTANT_VALUES, DEPRECATED, PREVIEW, SERIALIZED_FORM, SYSTEM_PROPERTIES, NEW
|
||||
CONSTANT_VALUES, DEPRECATED, EXTERNAL_SPECS, PREVIEW, SERIALIZED_FORM, SYSTEM_PROPERTIES, NEW
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,7 +30,14 @@ import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.lang.model.SourceVersion;
|
||||
@ -256,6 +263,7 @@ public class HtmlDoclet extends AbstractDoclet {
|
||||
}
|
||||
|
||||
if (options.createIndex()) {
|
||||
ExternalSpecsWriter.generate(configuration);
|
||||
SystemPropertiesWriter.generate(configuration);
|
||||
configuration.mainIndex.addElements();
|
||||
IndexBuilder allClassesIndex = new IndexBuilder(configuration, nodeprecated, true);
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package jdk.javadoc.internal.doclets.formats.html;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
@ -2176,4 +2177,19 @@ public class HtmlDocletWriter {
|
||||
HtmlTree.CODE(Text.of(className)),
|
||||
links);
|
||||
}
|
||||
|
||||
public URI resolveExternalSpecURI(URI specURI) {
|
||||
if (!specURI.isAbsolute()) {
|
||||
URI baseURI = configuration.getOptions().specBaseURI();
|
||||
if (baseURI == null) {
|
||||
baseURI = URI.create("../specs/");
|
||||
}
|
||||
if (!baseURI.isAbsolute() && !pathToRoot.isEmpty()) {
|
||||
baseURI = URI.create(pathToRoot.getPath() + "/").resolve(baseURI);
|
||||
}
|
||||
specURI = baseURI.resolve(specURI);
|
||||
}
|
||||
return specURI;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.javadoc.internal.doclets.formats.html;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -85,6 +86,7 @@ public class Navigation {
|
||||
CONSTANT_VALUES,
|
||||
DEPRECATED,
|
||||
DOC_FILE,
|
||||
EXTERNAL_SPECS,
|
||||
HELP,
|
||||
INDEX,
|
||||
MODULE,
|
||||
@ -316,6 +318,7 @@ public class Navigation {
|
||||
case ALL_CLASSES:
|
||||
case ALL_PACKAGES:
|
||||
case CONSTANT_VALUES:
|
||||
case EXTERNAL_SPECS:
|
||||
case SERIALIZED_FORM:
|
||||
case SEARCH:
|
||||
case SYSTEM_PROPERTIES:
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
package jdk.javadoc.internal.doclets.formats.html;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
@ -34,6 +36,7 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
@ -54,9 +57,11 @@ import com.sun.source.doctree.ParamTree;
|
||||
import com.sun.source.doctree.ReturnTree;
|
||||
import com.sun.source.doctree.SeeTree;
|
||||
import com.sun.source.doctree.SnippetTree;
|
||||
import com.sun.source.doctree.SpecTree;
|
||||
import com.sun.source.doctree.SystemPropertyTree;
|
||||
import com.sun.source.doctree.TextTree;
|
||||
import com.sun.source.doctree.ThrowsTree;
|
||||
import com.sun.source.doctree.TextTree;
|
||||
import com.sun.source.util.DocTreePath;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
|
||||
@ -80,6 +85,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexItem;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils.PreviewFlagProvider;
|
||||
@ -400,6 +406,20 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
return s.length() > SEE_TAG_MAX_INLINE_LENGTH || s.contains(",");
|
||||
}
|
||||
|
||||
String textOf(List<? extends DocTree> trees) {
|
||||
return trees.stream()
|
||||
.filter(dt -> dt instanceof TextTree)
|
||||
.map(dt -> ((TextTree) dt).getBody().trim())
|
||||
.collect(Collectors.joining(" "));
|
||||
}
|
||||
|
||||
private void appendSeparatorIfNotEmpty(ContentBuilder body) {
|
||||
if (!body.isEmpty()) {
|
||||
body.add(", ");
|
||||
body.add(Text.NL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the output for a single {@code @see} tag}
|
||||
*
|
||||
@ -718,6 +738,54 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
return utils.docTrees.getElement(fabricatedPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Content specTagOutput(Element holder, List<? extends SpecTree> specTags) {
|
||||
ContentBuilder body = new ContentBuilder();
|
||||
for (SpecTree st : specTags) {
|
||||
appendSeparatorIfNotEmpty(body);
|
||||
body.add(specTagToContent(holder, st));
|
||||
}
|
||||
if (body.isEmpty())
|
||||
return body;
|
||||
|
||||
return new ContentBuilder(
|
||||
HtmlTree.DT(contents.externalSpecifications),
|
||||
HtmlTree.DD(body));
|
||||
}
|
||||
|
||||
private Content specTagToContent(Element holder, SpecTree specTree) {
|
||||
String specTreeURL = specTree.getURL().getBody();
|
||||
List<? extends DocTree> specTreeLabel = specTree.getTitle();
|
||||
Content label = htmlWriter.commentTagsToContent(holder, specTreeLabel, isFirstSentence);
|
||||
return getExternalSpecContent(holder, specTree, specTreeURL, textOf(specTreeLabel), label);
|
||||
}
|
||||
|
||||
Content getExternalSpecContent(Element holder, DocTree docTree, String url, String searchText, Content title) {
|
||||
URI specURI;
|
||||
try {
|
||||
// Use the canonical title of the spec if one is available
|
||||
specURI = new URI(url);
|
||||
} catch (URISyntaxException e) {
|
||||
CommentHelper ch = utils.getCommentHelper(holder);
|
||||
DocTreePath dtp = ch.getDocTreePath(docTree);
|
||||
htmlWriter.messages.error(dtp, "doclet.Invalid_URL", e.getMessage());
|
||||
specURI = null;
|
||||
}
|
||||
|
||||
Content titleWithAnchor = createAnchorAndSearchIndex(holder,
|
||||
searchText,
|
||||
title,
|
||||
resources.getText("doclet.External_Specification"),
|
||||
docTree);
|
||||
|
||||
if (specURI == null) {
|
||||
return titleWithAnchor;
|
||||
} else {
|
||||
return HtmlTree.A(htmlWriter.resolveExternalSpecURI(specURI), titleWithAnchor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Content systemPropertyTagOutput(Element element, SystemPropertyTree tag) {
|
||||
String tagText = tag.getPropertyName().toString();
|
||||
@ -810,13 +878,22 @@ public class TagletWriterImpl extends TagletWriter {
|
||||
return htmlWriter.getCurrentPageElement();
|
||||
}
|
||||
|
||||
public HtmlDocletWriter getHtmlWriter() {
|
||||
return htmlWriter;
|
||||
}
|
||||
|
||||
private Content createAnchorAndSearchIndex(Element element, String tagText, String desc, DocTree tree) {
|
||||
return createAnchorAndSearchIndex(element, tagText, Text.of(tagText), desc, tree);
|
||||
}
|
||||
|
||||
@SuppressWarnings("preview")
|
||||
private Content createAnchorAndSearchIndex(Element element, String tagText, Content tagContent, String desc, DocTree tree) {
|
||||
Content result = null;
|
||||
if (context.isFirstSentence && context.inSummary || context.inTags.contains(DocTree.Kind.INDEX)) {
|
||||
result = Text.of(tagText);
|
||||
result = tagContent;
|
||||
} else {
|
||||
HtmlId id = HtmlIds.forText(tagText, htmlWriter.indexAnchorTable);
|
||||
result = HtmlTree.SPAN(id, HtmlStyle.searchTagResult, Text.of(tagText));
|
||||
result = HtmlTree.SPAN(id, HtmlStyle.searchTagResult, tagContent);
|
||||
if (options.createIndex() && !tagText.isEmpty()) {
|
||||
String holder = new SimpleElementVisitor14<String, Void>() {
|
||||
|
||||
|
@ -743,6 +743,11 @@ public enum HtmlStyle {
|
||||
*/
|
||||
docFilePage,
|
||||
|
||||
/**
|
||||
* The class of the {@code body} element for the "external specifications" page.
|
||||
*/
|
||||
externalSpecsPage,
|
||||
|
||||
/**
|
||||
* The class of the {@code body} element for the "help" page.
|
||||
*/
|
||||
@ -1007,6 +1012,11 @@ public enum HtmlStyle {
|
||||
*/
|
||||
packageUses,
|
||||
|
||||
/**
|
||||
* The class for the list of references to an external specification.
|
||||
*/
|
||||
refList,
|
||||
|
||||
/**
|
||||
* The class of a {@code section} element for a package in the serialized
|
||||
* form page.
|
||||
|
@ -387,6 +387,15 @@ public class HtmlTree extends Content {
|
||||
.add(body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an HTML {@code DETAILS} element.
|
||||
*
|
||||
* @return the element
|
||||
*/
|
||||
public static HtmlTree DETAILS() {
|
||||
return new HtmlTree(TagName.DETAILS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an HTML {@code DETAILS} element.
|
||||
*
|
||||
|
@ -160,11 +160,16 @@ doclet.Enclosing_Class=Enclosing class:
|
||||
doclet.Enclosing_Interface=Enclosing interface:
|
||||
doclet.Inheritance_Tree=Inheritance Tree
|
||||
doclet.ReferencedIn=Referenced In
|
||||
doclet.External_Specification=External Specification
|
||||
doclet.External_Specifications=External Specifications
|
||||
doclet.Specification=Specification
|
||||
doclet.System_Property=System Property
|
||||
doclet.systemProperties=System Properties
|
||||
doclet.systemPropertiesSummary=System Properties Summary
|
||||
doclet.Window_Source_title=Source code
|
||||
doclet.Window_Help_title=API Help
|
||||
# 0: number of references (> 1)
|
||||
doclet.references={0} references
|
||||
doclet.Window_Search_title=Search
|
||||
doclet.search.main_heading=Search
|
||||
|
||||
@ -318,6 +323,9 @@ doclet.help.constants.body=\
|
||||
# 0: link to System Properties page
|
||||
doclet.help.systemProperties.body=\
|
||||
The {0} page lists references to system properties.
|
||||
# 0: link to External Specifications page
|
||||
doclet.help.externalSpecifications.body=\
|
||||
The {0} page lists references to external specifications.
|
||||
doclet.help.footnote=\
|
||||
This help file applies to API documentation generated by the standard doclet.
|
||||
doclet.help.enum.intro=\
|
||||
@ -403,6 +411,22 @@ doclet.Error_copying_legal_notices=Error while copying legal notices: {0}
|
||||
# 0: the path; 1: the detail message for the exception
|
||||
doclet.Error_invalid_path_for_legal_notices=Invalid path ''{0}'' for legal notices: {1}
|
||||
|
||||
# 0: URL; 1: an integer
|
||||
doclet.extSpec.spec.has.multiple.titles=\
|
||||
{1} different titles given in @spec tags for the external specification at {0}
|
||||
|
||||
# 0: name; 1: an integer
|
||||
doclet.extSpec.title.for.multiple.specs=\
|
||||
The title "{0}" is used for {1} different external specifications in @spec tags
|
||||
|
||||
# 0: name; 1: url
|
||||
doclet.extSpec.title.url=\
|
||||
title: "{0}", url: {1}
|
||||
|
||||
# 0: url; 1: name
|
||||
doclet.extSpec.url.title=\
|
||||
url: {0}, title: "{1}"
|
||||
|
||||
# option specifiers
|
||||
doclet.usage.add-script.parameters=\
|
||||
<file>
|
||||
@ -663,6 +687,14 @@ doclet.usage.xdoclint-package.description=\
|
||||
of the given package. Prefix the package specifier with - to\n\
|
||||
disable checks for the specified packages.
|
||||
|
||||
doclet.usage.spec-base-url=\
|
||||
<URL>
|
||||
doclet.usage.spec-base-url.description=\
|
||||
Specify a base URL for relative URLs in @spec tags
|
||||
|
||||
doclet.Invalid_URL=\
|
||||
invalid URL: {0}
|
||||
|
||||
# L10N: do not localize the option name --no-frames
|
||||
doclet.NoFrames_specified=\
|
||||
The --no-frames option is no longer required and may be removed\n\
|
||||
|
@ -30,6 +30,9 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
@ -295,6 +298,12 @@ public abstract class BaseOptions {
|
||||
*/
|
||||
private int sourceTabSize;
|
||||
|
||||
/**
|
||||
* Argument for command-line option {@code --spec-base-url}.
|
||||
* The base URL for relative URLs in {@code @spec} tags.
|
||||
*/
|
||||
private URI specBaseURI;
|
||||
|
||||
/**
|
||||
* Value for command-line option {@code --override-methods summary}
|
||||
* or {@code --override-methods detail}.
|
||||
@ -670,6 +679,26 @@ public abstract class BaseOptions {
|
||||
}
|
||||
},
|
||||
|
||||
new Option(resources, "--spec-base-url", 1) {
|
||||
@Override
|
||||
public boolean process(String opt, List<String> args) {
|
||||
String arg = args.get(0);
|
||||
try {
|
||||
if (!arg.endsWith("/")) {
|
||||
// to ensure that URI.resolve works as expected
|
||||
arg += "/";
|
||||
}
|
||||
specBaseURI = new URI(arg);
|
||||
return true;
|
||||
} catch (URISyntaxException e) {
|
||||
config.reporter.print(ERROR,
|
||||
config.getDocResources().getText("doclet.Invalid_URL",
|
||||
e.getMessage()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
new Hidden(resources, "--disable-javafx-strict-checks") {
|
||||
@Override
|
||||
public boolean process(String opt, List<String> args) {
|
||||
@ -1050,6 +1079,14 @@ public abstract class BaseOptions {
|
||||
return sourceTabSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Argument for command-line option {@code --spec-base-url}.
|
||||
* The base URL for relative URLs in {@code @spec} tags.
|
||||
*/
|
||||
public URI specBaseURI() {
|
||||
return specBaseURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Value for command-line option {@code --override-methods summary}
|
||||
* or {@code --override-methods detail}.
|
||||
|
@ -365,6 +365,14 @@ ul.summary-list > li {
|
||||
margin-bottom:15px;
|
||||
line-height:1.4;
|
||||
}
|
||||
ul.ref-list {
|
||||
margin-left:0;
|
||||
padding:0;
|
||||
margin:0;
|
||||
}
|
||||
ul.ref-list > li {
|
||||
list-style:none;
|
||||
}
|
||||
.summary-table dl, .summary-table dl dt, .summary-table dl dd {
|
||||
margin-top:0;
|
||||
margin-bottom:1px;
|
||||
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2022, 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.doclets.toolkit.taglets;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import javax.lang.model.element.Element;
|
||||
|
||||
import com.sun.source.doctree.DocTree;
|
||||
import com.sun.source.doctree.SpecTree;
|
||||
import jdk.javadoc.doclet.Taglet.Location;
|
||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Input;
|
||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||
|
||||
/**
|
||||
* A taglet that represents the {@code @spec} tag.
|
||||
*/
|
||||
public class SpecTaglet extends BaseTaglet implements InheritableTaglet {
|
||||
|
||||
public SpecTaglet() {
|
||||
super(DocTree.Kind.SPEC, true, EnumSet.allOf(Location.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlockTag() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inherit(Input input, DocFinder.Output output) {
|
||||
List<? extends SpecTree> tags = input.utils.getSpecTrees(input.element);
|
||||
if (!tags.isEmpty()) {
|
||||
CommentHelper ch = input.utils.getCommentHelper(input.element);
|
||||
output.holder = input.element;
|
||||
output.holderTag = tags.get(0);
|
||||
output.inlineTags = input.isFirstSentence
|
||||
? ch.getFirstSentenceTrees(output.holderTag)
|
||||
: ch.getTags(output.holderTag);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Content getAllBlockTagOutput(Element holder, TagletWriter writer) {
|
||||
Utils utils = writer.configuration().utils;
|
||||
List<? extends SpecTree> tags = utils.getSpecTrees(holder);
|
||||
Element e = holder;
|
||||
if (tags.isEmpty() && utils.isExecutableElement(holder)) {
|
||||
Input input = new Input(utils, holder, this);
|
||||
DocFinder.Output inheritedDoc = DocFinder.search(writer.configuration(), input);
|
||||
if (inheritedDoc.holder != null) {
|
||||
tags = utils.getSpecTrees(inheritedDoc.holder);
|
||||
e = inheritedDoc.holder;
|
||||
}
|
||||
}
|
||||
return writer.specTagOutput(e, tags);
|
||||
}
|
||||
}
|
@ -621,6 +621,7 @@ public class TagletManager {
|
||||
allTaglets.put(factoryTaglet.getName(), factoryTaglet);
|
||||
|
||||
addStandardTaglet(new SeeTaglet());
|
||||
addStandardTaglet(new SpecTaglet());
|
||||
|
||||
// Standard inline tags
|
||||
addStandardTaglet(new DocRootTaglet());
|
||||
|
@ -35,6 +35,7 @@ import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
|
||||
import com.sun.source.doctree.DocTree;
|
||||
import com.sun.source.doctree.SpecTree;
|
||||
import com.sun.source.doctree.IndexTree;
|
||||
import com.sun.source.doctree.LinkTree;
|
||||
import com.sun.source.doctree.LiteralTree;
|
||||
@ -195,10 +196,20 @@ public abstract class TagletWriter {
|
||||
protected abstract Content snippetTagOutput(Element element, SnippetTree snippetTag, StyledText text,
|
||||
String id, String lang);
|
||||
|
||||
/**
|
||||
* Returns the output for one or more {@code @spec} tags.
|
||||
*
|
||||
* @param element the element that owns the doc comment
|
||||
* @param specTags the array of @spec tags.
|
||||
*
|
||||
* @return the output
|
||||
*/
|
||||
protected abstract Content specTagOutput(Element element, List<? extends SpecTree> specTags);
|
||||
|
||||
/**
|
||||
* Returns the output for a {@code {@systemProperty...}} tag.
|
||||
*
|
||||
* @param element The element that owns the doc comment
|
||||
* @param element the element that owns the doc comment
|
||||
* @param systemPropertyTag the system property tag
|
||||
*
|
||||
* @return the output
|
||||
|
@ -25,28 +25,12 @@
|
||||
|
||||
package jdk.javadoc.internal.doclets.toolkit.util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.ModuleElement;
|
||||
import javax.lang.model.element.PackageElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
|
||||
import com.sun.source.doctree.AttributeTree;
|
||||
import com.sun.source.doctree.AttributeTree.ValueKind;
|
||||
import com.sun.source.doctree.AuthorTree;
|
||||
import com.sun.source.doctree.BlockTagTree;
|
||||
import com.sun.source.doctree.CommentTree;
|
||||
import com.sun.source.doctree.DeprecatedTree;
|
||||
import com.sun.source.doctree.DocCommentTree;
|
||||
import com.sun.source.doctree.DocTree;
|
||||
import com.sun.source.doctree.EndElementTree;
|
||||
import com.sun.source.doctree.EntityTree;
|
||||
import com.sun.source.doctree.IdentifierTree;
|
||||
import com.sun.source.doctree.InlineTagTree;
|
||||
import com.sun.source.doctree.LinkTree;
|
||||
@ -60,7 +44,7 @@ import com.sun.source.doctree.SerialDataTree;
|
||||
import com.sun.source.doctree.SerialFieldTree;
|
||||
import com.sun.source.doctree.SerialTree;
|
||||
import com.sun.source.doctree.SinceTree;
|
||||
import com.sun.source.doctree.StartElementTree;
|
||||
import com.sun.source.doctree.SpecTree;
|
||||
import com.sun.source.doctree.TextTree;
|
||||
import com.sun.source.doctree.ThrowsTree;
|
||||
import com.sun.source.doctree.UnknownBlockTagTree;
|
||||
@ -73,7 +57,18 @@ import com.sun.source.util.SimpleDocTreeVisitor;
|
||||
import com.sun.source.util.TreePath;
|
||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
||||
|
||||
import static com.sun.source.doctree.DocTree.Kind.*;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.ModuleElement;
|
||||
import javax.lang.model.element.PackageElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import java.util.List;
|
||||
|
||||
import static com.sun.source.doctree.DocTree.Kind.SEE;
|
||||
import static com.sun.source.doctree.DocTree.Kind.SERIAL_FIELD;
|
||||
|
||||
/**
|
||||
* A utility class.
|
||||
@ -482,6 +477,11 @@ public class CommentHelper {
|
||||
return node.getDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends DocTree> visitSpec(SpecTree node, Void p) {
|
||||
return node.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends DocTree> visitThrows(ThrowsTree node, Void p) {
|
||||
return node.getDescription();
|
||||
|
@ -64,6 +64,9 @@ public class DocPaths {
|
||||
/** The name of the file for the element list. */
|
||||
public static final DocPath ELEMENT_LIST = DocPath.create("element-list");
|
||||
|
||||
/** The name of the file for all references to external specifications. */
|
||||
public static final DocPath EXTERNAL_SPECS = DocPath.create("external-specs.html");
|
||||
|
||||
/** The name of the image file showing a magnifying glass on the search box. */
|
||||
public static final DocPath GLASS_IMG = DocPath.create("glass.png");
|
||||
|
||||
|
@ -209,7 +209,7 @@ public class IndexItem {
|
||||
Objects.requireNonNull(link);
|
||||
|
||||
switch (docTree.getKind()) {
|
||||
case INDEX, SYSTEM_PROPERTY -> { }
|
||||
case INDEX, SPEC, SYSTEM_PROPERTY -> { }
|
||||
default -> throw new IllegalArgumentException(docTree.getKind().toString());
|
||||
}
|
||||
|
||||
@ -337,7 +337,7 @@ public class IndexItem {
|
||||
|
||||
protected Category getCategory(DocTree docTree) {
|
||||
return switch (docTree.getKind()) {
|
||||
case INDEX, SYSTEM_PROPERTY -> Category.TAGS;
|
||||
case INDEX, SPEC, SYSTEM_PROPERTY -> Category.TAGS;
|
||||
default -> throw new IllegalArgumentException(docTree.getKind().toString());
|
||||
};
|
||||
}
|
||||
@ -562,12 +562,12 @@ public class IndexItem {
|
||||
String holder = getHolder();
|
||||
String description = getDescription();
|
||||
item.append("{")
|
||||
.append("\"l\":\"").append(label).append("\",")
|
||||
.append("\"l\":\"").append(escapeQuotes(label)).append("\",")
|
||||
.append("\"h\":\"").append(holder).append("\",");
|
||||
if (!description.isEmpty()) {
|
||||
item.append("\"d\":\"").append(description).append("\",");
|
||||
item.append("\"d\":\"").append(escapeQuotes(description)).append("\",");
|
||||
}
|
||||
item.append("\"u\":\"").append(url).append("\"")
|
||||
item.append("\"u\":\"").append(escapeQuotes(url)).append("\"")
|
||||
.append("}");
|
||||
break;
|
||||
|
||||
@ -576,4 +576,8 @@ public class IndexItem {
|
||||
}
|
||||
return item.toString();
|
||||
}
|
||||
|
||||
private String escapeQuotes(String s) {
|
||||
return s.replace("\"", "\\\"");
|
||||
}
|
||||
}
|
||||
|
@ -101,6 +101,7 @@ import com.sun.source.doctree.SeeTree;
|
||||
import com.sun.source.doctree.SerialDataTree;
|
||||
import com.sun.source.doctree.SerialFieldTree;
|
||||
import com.sun.source.doctree.SerialTree;
|
||||
import com.sun.source.doctree.SpecTree;
|
||||
import com.sun.source.doctree.StartElementTree;
|
||||
import com.sun.source.doctree.TextTree;
|
||||
import com.sun.source.doctree.ThrowsTree;
|
||||
@ -2402,6 +2403,10 @@ public class Utils {
|
||||
return getBlockTags(field, DocTree.Kind.SERIAL_FIELD, SerialFieldTree.class);
|
||||
}
|
||||
|
||||
public List<? extends SpecTree> getSpecTrees(Element element) {
|
||||
return getBlockTags(element, SPEC, SpecTree.class);
|
||||
}
|
||||
|
||||
public List<ThrowsTree> getThrowsTrees(Element element) {
|
||||
return getBlockTags(element,
|
||||
t -> switch (t.getKind()) { case EXCEPTION, THROWS -> true; default -> false; },
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2022, 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
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8254721
|
||||
* @bug 8254721 6251738
|
||||
* @summary Improve support for conditionally generated files
|
||||
* @library /tools/lib ../../lib
|
||||
* @modules jdk.javadoc/jdk.javadoc.internal.tool
|
||||
@ -73,6 +73,17 @@ public class TestConditionalPages extends JavadocTester {
|
||||
b -> checkOutput("index-all.html", b, "Deprecated"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExternalSpecs(Path base) throws IOException {
|
||||
test(base, """
|
||||
package p;
|
||||
/** @spec http://example.com label. */
|
||||
public class C { }
|
||||
""",
|
||||
"external-specs.html",
|
||||
b -> checkOutput("index-all.html", b, "External Specifications"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerializedForm(Path base) throws IOException {
|
||||
test(base, """
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2022, 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
|
||||
@ -149,6 +149,7 @@ public class TestMetadata extends JavadocTester {
|
||||
"constants-summary-page",
|
||||
"deprecated-list-page",
|
||||
"doc-file-page",
|
||||
"external-specs-page",
|
||||
"help-page",
|
||||
"index-page",
|
||||
"index-redirect-page",
|
||||
@ -215,6 +216,7 @@ public class TestMetadata extends JavadocTester {
|
||||
"ConstantsSummaryWriterImpl",
|
||||
"DeprecatedListWriter",
|
||||
"DocFileWriter",
|
||||
"ExternalSpecsWriter",
|
||||
"HelpWriter",
|
||||
"IndexRedirectWriter",
|
||||
"IndexWriter",
|
||||
@ -343,6 +345,10 @@ public class TestMetadata extends JavadocTester {
|
||||
passed("no constraint for user-provided doc-files");
|
||||
break;
|
||||
|
||||
case "ExternalSpecsWriter":
|
||||
check(generator, content, content.startsWith("external specifications"));
|
||||
break;
|
||||
|
||||
case "HelpWriter":
|
||||
check(generator, content, content.contains("help"));
|
||||
break;
|
||||
@ -396,7 +402,16 @@ public class TestMetadata extends JavadocTester {
|
||||
case PACKAGES:
|
||||
tb.writeJavaFiles(src,
|
||||
"/** Package pA. {@systemProperty exampleProperty} */ package pA;",
|
||||
"/** Class pA.CA. */ package pA; public class CA { @Deprecated public static final int ZERO = 0; }",
|
||||
"""
|
||||
/** Class pA.CA. */
|
||||
package pA; public class CA {
|
||||
/**
|
||||
* First sentence.
|
||||
* @spec http://example.com example reference
|
||||
*/
|
||||
@Deprecated public static final int ZERO = 0;
|
||||
}
|
||||
""",
|
||||
"/** Anno pA.Anno, */ package pA; public @interface Anno { }",
|
||||
"/** Serializable pA.Ser, */ package pA; public class Ser implements java.io.Serializable { }",
|
||||
"/** Package pB. */ package pB;",
|
||||
@ -411,7 +426,17 @@ public class TestMetadata extends JavadocTester {
|
||||
new ModuleBuilder(tb, "mA")
|
||||
.exports("pA")
|
||||
.classes("/** Package mA/pA. */ package pA;")
|
||||
.classes("/** Class mA/pA.CA. */ package pA; public class CA { @Deprecated public static int ZERO = 0; }")
|
||||
.classes("""
|
||||
/** Class mA/pA.CA. */
|
||||
package pA;
|
||||
public class CA {
|
||||
/**
|
||||
* First sentence.
|
||||
* @spec http://example.com example reference
|
||||
*/
|
||||
@Deprecated public static int ZERO = 0;
|
||||
}
|
||||
""")
|
||||
.write(src);
|
||||
new ModuleBuilder(tb, "mB")
|
||||
.exports("pB")
|
||||
|
432
test/langtools/jdk/javadoc/doclet/testSpecTag/TestSpecTag.java
Normal file
432
test/langtools/jdk/javadoc/doclet/testSpecTag/TestSpecTag.java
Normal file
@ -0,0 +1,432 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 2022, 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 6251738 8226279
|
||||
* @summary JDK-8226279 javadoc should support a new at-spec tag
|
||||
* @library /tools/lib ../../lib
|
||||
* @modules jdk.javadoc/jdk.javadoc.internal.tool
|
||||
* @build toolbox.ToolBox javadoc.tester.*
|
||||
* @run main TestSpecTag
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import javadoc.tester.JavadocTester;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
public class TestSpecTag extends JavadocTester {
|
||||
public static void main(String... args) throws Exception {
|
||||
TestSpecTag tester = new TestSpecTag();
|
||||
tester.runTests(m -> new Object[] { Path.of(m.getName()) });
|
||||
}
|
||||
|
||||
ToolBox tb = new ToolBox();
|
||||
|
||||
enum LinkKind { ABSOLUTE, RELATIVE }
|
||||
|
||||
@Test
|
||||
public void testBadSpecBaseURI(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src, "package p; public class C { }");
|
||||
|
||||
javadoc("-d", base.resolve("out").toString(),
|
||||
"--spec-base-url", "http://[",
|
||||
"--source-path", src.toString(),
|
||||
"p");
|
||||
checkExit(Exit.CMDERR);
|
||||
checkOutput(Output.OUT, true,
|
||||
"error: invalid URL: Expected closing bracket for IPv6 address at index 8: http://[");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadSpecURI(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src, "package p; /** @spec http://[ label */ public class C { }");
|
||||
|
||||
javadoc("-d", base.resolve("out").toString(),
|
||||
"--source-path", src.toString(),
|
||||
"p");
|
||||
checkExit(Exit.ERROR);
|
||||
|
||||
checkOutput(Output.OUT, true,
|
||||
"testBadSpecURI/src/p/C.java:1:".replace('/', File.separatorChar)
|
||||
+ " error: invalid URL: Expected closing bracket for IPv6 address at index 8: http://[");
|
||||
|
||||
checkOutput("p/C.html", true,
|
||||
"""
|
||||
<dl class="notes">
|
||||
<dt>External Specifications</dt>
|
||||
<dd><span id="label" class="search-tag-result">label</span></dd>
|
||||
</dl>
|
||||
""");
|
||||
|
||||
checkOutput("external-specs.html", true,
|
||||
"""
|
||||
<div class="col-first even-row-color">label</div>
|
||||
<div class="col-last even-row-color">
|
||||
<ul class="ref-list">
|
||||
<li><code><a href="p/C.html#label">class p.C</a></code></li>
|
||||
</ul>
|
||||
</div>""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNavigation(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src, "package p; /** @spec http://example.com label */ public class C { }");
|
||||
|
||||
javadoc("-d", base.resolve("out").toString(),
|
||||
"--source-path", src.toString(),
|
||||
"p");
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput("external-specs.html", true,
|
||||
"""
|
||||
<!-- ========= START OF TOP NAVBAR ======= -->
|
||||
<div class="top-nav" id="navbar-top"><button id="navbar-toggle-button" aria-controls="navbar-top" aria-expanded="false" aria-label="Toggle navigation links"><span class="nav-bar-toggle-icon"> </span><span class="nav-bar-toggle-icon"> </span><span class="nav-bar-toggle-icon"> </span></button>
|
||||
<div class="skip-nav"><a href="#skip-navbar-top" title="Skip navigation links">Skip navigation links</a></div>
|
||||
<ul id="navbar-top-firstrow" class="nav-list" title="Navigation">
|
||||
<li><a href="p/package-summary.html">Package</a></li>
|
||||
<li>Class</li>
|
||||
<li><a href="p/package-tree.html">Tree</a></li>
|
||||
<li><a href="index-all.html">Index</a></li>
|
||||
<li><a href="help-doc.html#external-specs">Help</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sub-nav">
|
||||
<div id="navbar-sub-list"></div>
|
||||
<div class="nav-list-search"><a href="search.html">SEARCH</a>
|
||||
<input type="text" id="search-input" disabled placeholder="Search">
|
||||
<input type="reset" id="reset-button" disabled value="reset">
|
||||
</div>
|
||||
</div>
|
||||
<!-- ========= END OF TOP NAVBAR ========= -->
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodedURI(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
// The default encoding for OpenJDK source files is ASCII.
|
||||
// The following writes a file using UTF-8 containing a non-ASCII character (section)
|
||||
// and a Unicode escape for another character (plus or minus)
|
||||
tb.writeJavaFiles(src, """
|
||||
package p;
|
||||
/**
|
||||
* @spec http://example.com/a+b space: plus
|
||||
* @spec http://example.com/a%20b space: percent
|
||||
* @spec http://example.com/a\u00A7b other: section; U+00A7, UTF-8 c2 a7
|
||||
* @spec http://example.com/a\\u00B1b unicode: plus or minus; U+00B1, UTF-8 c2 b1
|
||||
*/
|
||||
public class C { }
|
||||
""");
|
||||
|
||||
// Ensure the source file is read using UTF-8
|
||||
javadoc("-d", base.resolve("out").toString(),
|
||||
"--source-path", src.toString(),
|
||||
"-encoding", "UTF-8",
|
||||
"p");
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput("p/C.html", true,
|
||||
"""
|
||||
<dl class="notes">
|
||||
<dt>External Specifications</dt>
|
||||
<dd><a href="http://example.com/a+b"><span id="space:plus" class="search-tag-result">space: plus</span></a>,\s
|
||||
<a href="http://example.com/a%20b"><span id="space:percent" class="search-tag-result">space: percent</span></a>,\s
|
||||
<a href="http://example.com/a%C2%A7b"><span id="other:section;U+00A7,UTF-8c2a7" class="search-tag-result">other: section; U+00A7, UTF-8 c2 a7</span></a>,\s
|
||||
<a href="http://example.com/a%C2%B1b"><span id="unicode:plusorminus;U+00B1,UTF-8c2b1" class="search-tag-result">unicode: plus or minus; U+00B1, UTF-8 c2 b1</span></a></dd>
|
||||
</dl>
|
||||
""");
|
||||
|
||||
checkOutput("external-specs.html", true,
|
||||
"""
|
||||
<div class="table-header col-first">Specification</div>
|
||||
<div class="table-header col-last">Referenced In</div>
|
||||
<div class="col-first even-row-color"><a href="http://example.com/a%C2%A7b">other: section; U+00A7, UTF-8 c2 a7</a></div>
|
||||
<div class="col-last even-row-color">
|
||||
<ul class="ref-list">
|
||||
<li><code><a href="p/C.html#other:section;U+00A7,UTF-8c2a7">class p.C</a></code></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-first odd-row-color"><a href="http://example.com/a%20b">space: percent</a></div>
|
||||
<div class="col-last odd-row-color">
|
||||
<ul class="ref-list">
|
||||
<li><code><a href="p/C.html#space:percent">class p.C</a></code></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-first even-row-color"><a href="http://example.com/a+b">space: plus</a></div>
|
||||
<div class="col-last even-row-color">
|
||||
<ul class="ref-list">
|
||||
<li><code><a href="p/C.html#space:plus">class p.C</a></code></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-first odd-row-color"><a href="http://example.com/a%C2%B1b">unicode: plus or minus; U+00B1, UTF-8 c2 b1</a></div>
|
||||
<div class="col-last odd-row-color">
|
||||
<ul class="ref-list">
|
||||
<li><code><a href="p/C.html#unicode:plusorminus;U+00B1,UTF-8c2b1">class p.C</a></code></li>
|
||||
</ul>
|
||||
</div>""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateRefs(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src, """
|
||||
package p;
|
||||
/**
|
||||
* @spec http://example.com/ example
|
||||
*/
|
||||
public class C {
|
||||
/**
|
||||
* @spec http://example.com/ example
|
||||
*/
|
||||
public void m() { }
|
||||
/**
|
||||
* @spec http://example.com/ example
|
||||
*/
|
||||
public int f;
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc("-d", base.resolve("out").toString(),
|
||||
"--source-path", src.toString(),
|
||||
"p");
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOrder("p/C.html",
|
||||
"<h1 title=\"Class C\" class=\"title\">Class C</h1>",
|
||||
"""
|
||||
<dt>External Specifications</dt>
|
||||
<dd><a href="http://example.com/"><span id="example" class="search-tag-result">example</span></a></dd>
|
||||
""",
|
||||
"<section class=\"field-details\" id=\"field-detail\">",
|
||||
"""
|
||||
<dt>External Specifications</dt>
|
||||
<dd><a href="http://example.com/"><span id="example-1" class="search-tag-result">example</span></a></dd>
|
||||
""",
|
||||
"<section class=\"detail\" id=\"m()\">",
|
||||
"""
|
||||
<dt>External Specifications</dt>
|
||||
<dd><a href="http://example.com/"><span id="example-2" class="search-tag-result">example</span></a></dd>
|
||||
""");
|
||||
|
||||
checkOutput("external-specs.html", true,
|
||||
"""
|
||||
<div class="col-first even-row-color"><a href="http://example.com/">example</a></div>
|
||||
<div class="col-last even-row-color">
|
||||
<ul class="ref-list">
|
||||
<li><code><a href="p/C.html#example">class p.C</a></code></li>
|
||||
<li><code><a href="p/C.html#example-1">p.C.f</a></code></li>
|
||||
<li><code><a href="p/C.html#example-2">p.C.m()</a></code></li>
|
||||
</ul>
|
||||
</div>""");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiple(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src, """
|
||||
package p;
|
||||
/**
|
||||
* First sentence.
|
||||
* @spec http://example.com/1 example-1
|
||||
* @spec http://example.com/2 example-2
|
||||
*/
|
||||
public class C { }
|
||||
""");
|
||||
|
||||
javadoc("-d", base.resolve("out").toString(),
|
||||
"--source-path", src.toString(),
|
||||
"p");
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput("p/C.html", true,
|
||||
"""
|
||||
<dt>External Specifications</dt>
|
||||
<dd><a href="http://example.com/1"><span id="example-1" class="search-tag-result">example-1</span></a>,\s
|
||||
<a href="http://example.com/2"><span id="example-2" class="search-tag-result">example-2</span></a></dd>
|
||||
""");
|
||||
|
||||
checkOutput("external-specs.html", true,
|
||||
"""
|
||||
<div class="col-first even-row-color"><a href="http://example.com/1">example-1</a></div>
|
||||
<div class="col-last even-row-color">
|
||||
<ul class="ref-list">
|
||||
<li><code><a href="p/C.html#example-1">class p.C</a></code></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-first odd-row-color"><a href="http://example.com/2">example-2</a></div>
|
||||
<div class="col-last odd-row-color">
|
||||
<ul class="ref-list">
|
||||
<li><code><a href="p/C.html#example-2">class p.C</a></code></li>
|
||||
</ul>
|
||||
</div>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleTitlesForURL(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src, """
|
||||
package p;
|
||||
/** Class C. */
|
||||
public class C {
|
||||
private C() { }
|
||||
|
||||
/**
|
||||
* Method m1.
|
||||
* @spec http://example.com/index.html first
|
||||
*/
|
||||
public void m1() { }
|
||||
|
||||
/**
|
||||
* Method m2.
|
||||
* @spec http://example.com/index.html second
|
||||
*/
|
||||
public void m2() { }
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc("-d", base.resolve("out").toString(),
|
||||
"--source-path", src.toString(),
|
||||
"p");
|
||||
checkExit(Exit.ERROR);
|
||||
|
||||
checkOutput(Output.OUT, true,
|
||||
"""
|
||||
error: 2 different titles given in @spec tags for the external specification at http://example.com/index.html
|
||||
#FILE#:8: Note: url: http://example.com/index.html, title: "first"
|
||||
* @spec http://example.com/index.html first
|
||||
^
|
||||
#FILE#:14: Note: url: http://example.com/index.html, title: "second"
|
||||
* @spec http://example.com/index.html second
|
||||
^
|
||||
"""
|
||||
.replace("#FILE#", src.resolve("p").resolve("C.java").toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleURLsForTitle(Path base) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src, """
|
||||
package p;
|
||||
/** Class C. */
|
||||
public class C {
|
||||
private C() { }
|
||||
|
||||
/**
|
||||
* Method m1.
|
||||
* @spec http://example.com/index1.html Example Title
|
||||
*/
|
||||
public void m1() { }
|
||||
|
||||
/**
|
||||
* Method m2.
|
||||
* @spec http://example.com/index2.html Example Title
|
||||
*/
|
||||
public void m2() { }
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc("-d", base.resolve("out").toString(),
|
||||
"--source-path", src.toString(),
|
||||
"p");
|
||||
checkExit(Exit.ERROR);
|
||||
|
||||
checkOutput(Output.OUT, true,
|
||||
"""
|
||||
error: The title "Example Title" is used for 2 different external specifications in @spec tags
|
||||
#FILE#:8: Note: title: "Example Title", url: http://example.com/index1.html
|
||||
* @spec http://example.com/index1.html Example Title
|
||||
^
|
||||
#FILE#:14: Note: title: "Example Title", url: http://example.com/index2.html
|
||||
* @spec http://example.com/index2.html Example Title
|
||||
^
|
||||
"""
|
||||
.replace("#FILE#", src.resolve("p").resolve("C.java").toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCombo(Path base) throws IOException {
|
||||
for (LinkKind lk : LinkKind.values()) {
|
||||
test(base, lk);
|
||||
}
|
||||
}
|
||||
|
||||
void test(Path base, LinkKind lk) throws IOException {
|
||||
Path dir = Files.createDirectories(base.resolve(lk.toString()));
|
||||
Path src = genSource(dir, lk);
|
||||
|
||||
javadoc("-d", dir.resolve("out").toString(),
|
||||
"--spec-base-url", "http://example.com/",
|
||||
"--source-path", src.toString(),
|
||||
"p");
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput("p/C.html", true,
|
||||
"""
|
||||
<dl class="notes">
|
||||
<dt>External Specifications</dt>
|
||||
<dd><a href="http://example.com/#LK#"><span id="#LK#reference" \
|
||||
class="search-tag-result">#LK# reference</span></a></dd>
|
||||
</dl>"""
|
||||
.replaceAll("#LK#", lk.toString().toLowerCase()));
|
||||
|
||||
checkOutput("external-specs.html", true,
|
||||
"""
|
||||
<div class="col-first even-row-color"><a href="http://example.com/#LK#">#LK# reference</a></div>
|
||||
<div class="col-last even-row-color">
|
||||
<ul class="ref-list">
|
||||
<li><code><a href="p/C.html##LK#reference">class p.C</a></code></li>
|
||||
</ul>
|
||||
</div>"""
|
||||
.replaceAll("#LK#", lk.toString().toLowerCase()));
|
||||
}
|
||||
|
||||
Path genSource(Path base, LinkKind lk) throws IOException {
|
||||
Path src = base.resolve("src");
|
||||
String template = """
|
||||
/**
|
||||
* First sentence.
|
||||
* @spec #SPEC#
|
||||
*/
|
||||
""";
|
||||
|
||||
String spec = switch (lk) {
|
||||
case ABSOLUTE -> "http://example.com/absolute absolute reference";
|
||||
case RELATIVE -> "relative relative reference";
|
||||
};
|
||||
String comment = template.replace("#SPEC#", spec);
|
||||
tb.writeJavaFiles(src,
|
||||
"package p;\n" + comment + "public class C { }");
|
||||
|
||||
return src;
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
@serialField: block ........ ...... ....... .... ........... ...... field ...... ........
|
||||
@since: block overview module package type constructor method field ...... ........
|
||||
{@snippet}: ..... overview module package type constructor method field inline ........
|
||||
@spec: block overview module package type constructor method field inline ........
|
||||
{@summary}: ..... overview module package type constructor method field inline ........
|
||||
{@systemProperty}: ..... overview module package type constructor method field inline ........
|
||||
@throws: block ........ ...... ....... .... constructor method ..... ...... ........
|
||||
|
@ -66,7 +66,7 @@ public class CheckManPageOptions {
|
||||
|
||||
static final PrintStream out = System.err;
|
||||
|
||||
List<String> MISSING_IN_MAN_PAGE = List.of();
|
||||
List<String> MISSING_IN_MAN_PAGE = List.of("--spec-base-url");
|
||||
|
||||
void run(String... args) throws Exception {
|
||||
var file = args.length == 0 ? findDefaultFile() : Path.of(args[0]);
|
||||
|
32
test/langtools/tools/javac/diags/examples/NoTitle.java
Normal file
32
test/langtools/tools/javac/diags/examples/NoTitle.java
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2022, 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.
|
||||
*/
|
||||
|
||||
// key: compiler.err.dc.no.title
|
||||
// key: compiler.note.note
|
||||
// key: compiler.note.proc.messager
|
||||
// run: backdoor
|
||||
// options: -processor DocCommentProcessor -proc:only
|
||||
|
||||
/** @spec http://example.com */
|
||||
class NoTitle { }
|
||||
|
32
test/langtools/tools/javac/diags/examples/NoURL.java
Normal file
32
test/langtools/tools/javac/diags/examples/NoURL.java
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2022, 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.
|
||||
*/
|
||||
|
||||
// key: compiler.err.dc.no.url
|
||||
// key: compiler.note.note
|
||||
// key: compiler.note.proc.messager
|
||||
// run: backdoor
|
||||
// options: -processor DocCommentProcessor -proc:only
|
||||
|
||||
/** @spec */
|
||||
class NoURL { }
|
||||
|
@ -599,6 +599,18 @@ public class DocCommentTester {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitSpec(SpecTree node, Void p) {
|
||||
header(node);
|
||||
indent(+1);
|
||||
print("url", node.getURL());
|
||||
print("title", node.getTitle());
|
||||
indent(-1);
|
||||
indent();
|
||||
out.println("]");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitSnippet(SnippetTree node, Void p) {
|
||||
header(node);
|
||||
|
94
test/langtools/tools/javac/doctree/SpecTest.java
Normal file
94
test/langtools/tools/javac/doctree/SpecTest.java
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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 6251738 8226279
|
||||
* @summary javadoc should support a new at-spec tag
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.file
|
||||
* jdk.compiler/com.sun.tools.javac.tree
|
||||
* jdk.compiler/com.sun.tools.javac.util
|
||||
* @build DocCommentTester
|
||||
* @run main DocCommentTester SpecTest.java
|
||||
*/
|
||||
|
||||
class SpecTest {
|
||||
|
||||
/**
|
||||
* abc.
|
||||
* @spec http://example.com title
|
||||
*/
|
||||
void block() {}
|
||||
/*
|
||||
DocComment[DOC_COMMENT, pos:1
|
||||
firstSentence: 1
|
||||
Text[TEXT, pos:1, abc.]
|
||||
body: empty
|
||||
block tags: 1
|
||||
Spec[SPEC, pos:7
|
||||
url:
|
||||
Text[TEXT, pos:13, http://example.com]
|
||||
title: 1
|
||||
Text[TEXT, pos:32, title]
|
||||
]
|
||||
]
|
||||
*/
|
||||
|
||||
/**
|
||||
* abc.
|
||||
* @spec
|
||||
*/
|
||||
void bad_no_url() {}
|
||||
/*
|
||||
DocComment[DOC_COMMENT, pos:1
|
||||
firstSentence: 1
|
||||
Text[TEXT, pos:1, abc.]
|
||||
body: empty
|
||||
block tags: 1
|
||||
Erroneous[ERRONEOUS, pos:7, prefPos:11
|
||||
code: compiler.err.dc.no.url
|
||||
body: @spec
|
||||
]
|
||||
]
|
||||
*/
|
||||
|
||||
/**
|
||||
* abc.
|
||||
* @spec http://example.com
|
||||
*/
|
||||
void bad_no_label() {}
|
||||
/*
|
||||
DocComment[DOC_COMMENT, pos:1
|
||||
firstSentence: 1
|
||||
Text[TEXT, pos:1, abc.]
|
||||
body: empty
|
||||
block tags: 1
|
||||
Erroneous[ERRONEOUS, pos:7, prefPos:30
|
||||
code: compiler.err.dc.no.title
|
||||
body: @spec_http://example.com
|
||||
]
|
||||
]
|
||||
*/
|
||||
|
||||
}
|
@ -1142,6 +1142,12 @@ public class DPrinter {
|
||||
return visitBlockTag(node, null);
|
||||
}
|
||||
|
||||
public Void visitSpec(SpecTree node, Void p) {
|
||||
printDocTree("url", node.getURL());
|
||||
printList("title", node.getTitle());
|
||||
return visitBlockTag(node, null);
|
||||
}
|
||||
|
||||
public Void visitStartElement(StartElementTree node, Void p) {
|
||||
printName("name", node.getName());
|
||||
printList("attrs", node.getAttributes());
|
||||
|
Loading…
Reference in New Issue
Block a user