src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java
/*
* Copyright (c) 1998, 2018, 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 jdk.javadoc.internal.doclets.formats.html.markup.Head;
import jdk.javadoc.internal.doclets.formats.html.markup.TableHeader;
import java.util.*;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
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.Name;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.SimpleAnnotationValueVisitor9;
import javax.lang.model.util.SimpleElementVisitor9;
import javax.lang.model.util.SimpleTypeVisitor9;
import com.sun.source.doctree.AttributeTree;
import com.sun.source.doctree.AttributeTree.ValueKind;
import com.sun.source.doctree.CommentTree;
import com.sun.source.doctree.DocRootTree;
import com.sun.source.doctree.DocTree;
import com.sun.source.doctree.DocTree.Kind;
import com.sun.source.doctree.EndElementTree;
import com.sun.source.doctree.EntityTree;
import com.sun.source.doctree.ErroneousTree;
import com.sun.source.doctree.IndexTree;
import com.sun.source.doctree.InheritDocTree;
import com.sun.source.doctree.LinkTree;
import com.sun.source.doctree.LiteralTree;
import com.sun.source.doctree.SeeTree;
import com.sun.source.doctree.StartElementTree;
import com.sun.source.doctree.SummaryTree;
import com.sun.source.doctree.TextTree;
import com.sun.source.util.SimpleDocTreeVisitor;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.DocType;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocument;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
import jdk.javadoc.internal.doclets.formats.html.markup.Links;
import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
import jdk.javadoc.internal.doclets.formats.html.markup.Script;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeWriter;
import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.Messages;
import jdk.javadoc.internal.doclets.toolkit.PackageSummaryWriter;
import jdk.javadoc.internal.doclets.toolkit.Resources;
import jdk.javadoc.internal.doclets.toolkit.taglets.DocRootTaglet;
import jdk.javadoc.internal.doclets.toolkit.taglets.TagletWriter;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
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.Utils;
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
import static com.sun.source.doctree.DocTree.Kind.*;
import static jdk.javadoc.internal.doclets.toolkit.util.CommentHelper.SPACER;
/**
* Class for the Html Format Code Generation specific to JavaDoc.
* This Class contains methods related to the Html Code Generation which
* are used extensively while generating the entire documentation.
*
* <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>
*
* @author Atul M Dambalkar
* @author Robert Field
* @author Bhavesh Patel (Modified)
*/
public class HtmlDocletWriter {
/**
* Relative path from the file getting generated to the destination
* directory. For example, if the file getting generated is
* "java/lang/Object.html", then the path to the root is "../..".
* This string can be empty if the file getting generated is in
* the destination directory.
*/
public final DocPath pathToRoot;
/**
* Platform-independent path from the current or the
* destination directory to the file getting generated.
* Used when creating the file.
*/
public final DocPath path;
/**
* Name of the file getting generated. If the file getting generated is
* "java/lang/Object.html", then the filename is "Object.html".
*/
public final DocPath filename;
/**
* The global configuration information for this run.
*/
public final HtmlConfiguration configuration;
protected final Utils utils;
protected final Contents contents;
protected final Messages messages;
protected final Resources resources;
protected final Links links;
protected final DocPaths docPaths;
/**
* To check whether annotation heading is printed or not.
*/
protected boolean printedAnnotationHeading = false;
/**
* To check whether annotation field heading is printed or not.
*/
protected boolean printedAnnotationFieldHeading = false;
/**
* To check whether the repeated annotations is documented or not.
*/
private boolean isAnnotationDocumented = false;
/**
* To check whether the container annotations is documented or not.
*/
private boolean isContainerDocumented = false;
HtmlTree fixedNavDiv = new HtmlTree(HtmlTag.DIV);
/**
* The window title of this file.
*/
protected String winTitle;
protected Script mainBodyScript;
/**
* Constructor to construct the HtmlStandardWriter object.
*
* @param configuration the configuration for this doclet
* @param path the file to be generated.
*/
public HtmlDocletWriter(HtmlConfiguration configuration, DocPath path) {
this.configuration = configuration;
this.contents = configuration.contents;
this.messages = configuration.messages;
this.resources = configuration.resources;
this.links = new Links(path, configuration.htmlVersion);
this.utils = configuration.utils;
this.path = path;
this.pathToRoot = path.parent().invert();
this.filename = path.basename();
this.docPaths = configuration.docPaths;
messages.notice("doclet.Generating_0",
DocFile.createFileForOutput(configuration, path).getPath());
}
/**
* Replace {@docRoot} tag used in options that accept HTML text, such
* as -header, -footer, -top and -bottom, and when converting a relative
* HREF where commentTagsToString inserts a {@docRoot} where one was
* missing. (Also see DocRootTaglet for {@docRoot} tags in doc
* comments.)
* <p>
* Replace {@docRoot} tag in htmlstr with the relative path to the
* destination directory from the directory where the file is being
* written, looping to handle all such tags in htmlstr.
* <p>
* For example, for "-d docs" and -header containing {@docRoot}, when
* the HTML page for source file p/C1.java is being generated, the
* {@docRoot} tag would be inserted into the header as "../",
* the relative path from docs/p/ to docs/ (the document root).
* <p>
* Note: This doc comment was written with '&#064;' representing '@'
* to prevent the inline tag from being interpreted.
*/
public String replaceDocRootDir(String htmlstr) {
// Return if no inline tags exist
int index = htmlstr.indexOf("{@");
if (index < 0) {
return htmlstr;
}
Matcher docrootMatcher = docrootPattern.matcher(htmlstr);
if (!docrootMatcher.find()) {
return htmlstr;
}
StringBuilder buf = new StringBuilder();
int prevEnd = 0;
do {
int match = docrootMatcher.start();
// append htmlstr up to start of next {@docroot}
buf.append(htmlstr.substring(prevEnd, match));
prevEnd = docrootMatcher.end();
if (configuration.docrootparent.length() > 0 && htmlstr.startsWith("/..", prevEnd)) {
// Insert the absolute link if {@docRoot} is followed by "/..".
buf.append(configuration.docrootparent);
prevEnd += 3;
} else {
// Insert relative path where {@docRoot} was located
buf.append(pathToRoot.isEmpty() ? "." : pathToRoot.getPath());
}
// Append slash if next character is not a slash
if (prevEnd < htmlstr.length() && htmlstr.charAt(prevEnd) != '/') {
buf.append('/');
}
} while (docrootMatcher.find());
buf.append(htmlstr.substring(prevEnd));
return buf.toString();
}
//where:
// Note: {@docRoot} is not case sensitive when passed in w/command line option:
private static final Pattern docrootPattern =
Pattern.compile(Pattern.quote("{@docroot}"), Pattern.CASE_INSENSITIVE);
/**
* Get the script to show or hide the All classes link.
*
* @param id id of the element to show or hide
* @return a content tree for the script
*/
public Content getAllClassesLinkScript(String id) {
Script script = new Script("<!--\n" +
" allClassesLink = document.getElementById(")
.appendStringLiteral(id)
.append(");\n" +
" if(window==top) {\n" +
" allClassesLink.style.display = \"block\";\n" +
" }\n" +
" else {\n" +
" allClassesLink.style.display = \"none\";\n" +
" }\n" +
" //-->\n");
Content div = HtmlTree.DIV(script.asContent());
Content div_noscript = HtmlTree.DIV(contents.noScriptMessage);
Content noScript = HtmlTree.NOSCRIPT(div_noscript);
div.addContent(noScript);
return div;
}
/**
* Add method information.
*
* @param method the method to be documented
* @param dl the content tree to which the method information will be added
*/
private void addMethodInfo(ExecutableElement method, Content dl) {
TypeElement enclosing = utils.getEnclosingTypeElement(method);
List<? extends TypeMirror> intfacs = enclosing.getInterfaces();
ExecutableElement overriddenMethod = utils.overriddenMethod(method);
VisibleMemberTable vmt = configuration.getVisibleMemberTable(enclosing);
// Check whether there is any implementation or overridden info to be
// printed. If no overridden or implementation info needs to be
// printed, do not print this section.
if ((!intfacs.isEmpty()
&& vmt.getImplementedMethods(method).isEmpty() == false)
|| overriddenMethod != null) {
MethodWriterImpl.addImplementsInfo(this, method, dl);
if (overriddenMethod != null) {
MethodWriterImpl.addOverridden(this,
utils.overriddenType(method),
overriddenMethod,
dl);
}
}
}
/**
* Adds the tags information.
*
* @param e the Element for which the tags will be generated
* @param htmltree the documentation tree to which the tags will be added
*/
protected void addTagsInfo(Element e, Content htmltree) {
if (configuration.nocomment) {
return;