diff --git a/make/Docs.gmk b/make/Docs.gmk index c1c9f7330ba..0cc5309813f 100644 --- a/make/Docs.gmk +++ b/make/Docs.gmk @@ -1,4 +1,4 @@ -# Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 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 @@ -80,6 +80,7 @@ JAVADOC_TAGS := \ -taglet build.tools.taglet.JSpec\$$JLS \ -taglet build.tools.taglet.JSpec\$$JVMS \ -taglet build.tools.taglet.ModuleGraph \ + -taglet build.tools.taglet.SealedGraph \ -taglet build.tools.taglet.ToolGuide \ -tag since \ -tag serialData \ @@ -187,25 +188,55 @@ JAVASE_LONG_NAME := Java® Platform, Standard Edition # Functions # Helper function for creating a svg file from a dot file generated by the -# GenGraphs tool. +# GenGraphs tool for a module. # param 1: SetupJavadocGeneration namespace ($1) # param 2: module name # -define setup_gengraph_dot_to_svg - $1_$2_DOT_SRC := $$($1_GENGRAPHS_DIR)/$2.dot +define setup_module_graph_dot_to_svg + $1_$2_DOT_SRC := $$($1_MODULE_GRAPHS_DIR)/$2.dot $1_$2_SVG_TARGET := $$($1_TARGET_DIR)/$2/module-graph.svg # For each module needing a graph, create a svg file from the dot file # generated by the GenGraphs tool and store it in the target dir. - $$(eval $$(call SetupExecute, gengraphs_svg_$1_$2, \ + $$(eval $$(call SetupExecute, module_graphs_svg_$1_$2, \ INFO := Running dot for module graphs for $2, \ - DEPS := $$(gengraphs_$1_TARGET), \ + DEPS := $$(module_graphs_dot_$1_TARGET), \ OUTPUT_FILE := $$($1_$2_SVG_TARGET), \ - SUPPORT_DIR := $$($1_GENGRAPHS_DIR), \ + SUPPORT_DIR := $$($1_MODULE_GRAPHS_DIR), \ COMMAND := $$(DOT) -Tsvg -o $$($1_$2_SVG_TARGET) $$($1_$2_DOT_SRC), \ )) - $1_MODULEGRAPH_TARGETS += $$($1_$2_SVG_TARGET) + $1_GRAPHS_TARGETS += $$($1_$2_SVG_TARGET) +endef + +# Helper function for creating a svg file for a class for which the SealedGraph +# taglet has generated a dot file. The dot file has a special name which +# encodes the module and class the graph belongs to. +# +# param 1: SetupJavadocGeneration namespace ($1) +# param 2: dot file name +# +define setup_sealed_graph_dot_to_svg + $1_$2_DOT_SRC := $$($1_SEALED_GRAPHS_DIR)/$2.dot + $1_$2_TARGET_CLASS := $$(word 2, $$(subst _, , $2)) + $1_$2_SLASHED_NAME := $$(subst .,/, $$($1_$2_TARGET_CLASS)) + $1_$2_TARGET_MODULE := $$(word 1, $$(subst _, , $2)) + $1_$2_TARGET_PATH := $$($1_TARGET_DIR)/$$($1_$2_TARGET_MODULE)/$$(dir $$($1_$2_SLASHED_NAME)) + $1_$2_TARGET_NAME := $$(notdir $$($1_$2_SLASHED_NAME)) + $1_$2_SVG_TARGET := $$($1_$2_TARGET_PATH)/$$($1_$2_TARGET_NAME)-sealed-graph.svg + $$(call MakeDir, $$($1_$2_TARGET_PATH)) + + # For each class needing a graph, create a svg file from the dot file + # generated by the SealedGraph taglet and store it in the target dir. + $$(eval $$(call SetupExecute, sealed_graphs_svg_$1_$2, \ + INFO := Running dot for sealed graphs for $$($1_$2_TARGET_MODULE)/$$($1_$2_TARGET_CLASS), \ + DEPS := $$($1_$2_DOT_SRC), \ + OUTPUT_FILE := $$($1_$2_SVG_TARGET), \ + SUPPORT_DIR := $$($1_SEALED_GRAPHS_DIR), \ + COMMAND := $$(DOT) -Tsvg -o $$($1_$2_SVG_TARGET) $$($1_$2_DOT_SRC), \ + )) + + $1_GRAPHS_TARGETS += $$($1_$2_SVG_TARGET) endef # Helper function to create the overview.html file to use with the -overview @@ -253,7 +284,7 @@ endef # # Parameter 1 is the name of the rule. This name is used as variable prefix. # Targets generated are returned as $1_JAVADOC_TARGETS and -# $1_MODULEGRAPH_TARGETS. Note that the index.html file will work as a "touch +# $1_GRAPHS_TARGETS. Note that the index.html file will work as a "touch # file" for all the magnitude of files that are generated by javadoc. # # Remaining parameters are named arguments. These include: @@ -276,9 +307,12 @@ define SetupApiDocsGenerationBody -Djspec.version=$$(VERSION_SPECIFICATION) ifeq ($$(ENABLE_FULL_DOCS), true) - # Tell the ModuleGraph taglet to generate html links to soon-to-be-created - # svg files with module graphs. - $1_JAVA_ARGS += -DenableModuleGraph=true + $1_SEALED_GRAPHS_DIR := $$(SUPPORT_OUTPUTDIR)/docs/$1-sealed-graphs + + # Tell the ModuleGraph and SealedGraph taglets to generate html links to + # soon-to-be-created svg files with module/sealed graphs. + $1_JAVA_ARGS += -DenableModuleGraph=true -DsealedDotOutputDir=$$($1_SEALED_GRAPHS_DIR) + $$(call MakeDir, $$($1_SEALED_GRAPHS_DIR)) endif # Start with basic options and tags @@ -384,30 +418,46 @@ define SetupApiDocsGenerationBody # First we run the GenGraph tool. It will query the module structure of the # running JVM and output .dot files for all existing modules. - GENGRAPHS_PROPS := \ + MODULE_GRAPHS_PROPS := \ $$(TOPDIR)/make/jdk/src/classes/build/tools/jigsaw/javadoc-graphs.properties - $1_GENGRAPHS_DIR := $$(SUPPORT_OUTPUTDIR)/docs/$1-gengraphs + $1_MODULE_GRAPHS_DIR := $$(SUPPORT_OUTPUTDIR)/docs/$1-module-graphs - $$(eval $$(call SetupExecute, gengraphs_$1, \ - INFO := Running gengraphs for $1 documentation, \ - DEPS := $$(BUILD_JIGSAW_TOOLS) $$(GENGRAPHS_PROPS), \ - OUTPUT_DIR := $$($1_GENGRAPHS_DIR), \ - COMMAND := $$(TOOL_GENGRAPHS) --spec --output $$($1_GENGRAPHS_DIR) \ - --dot-attributes $$(GENGRAPHS_PROPS), \ + $$(eval $$(call SetupExecute, module_graphs_dot_$1, \ + INFO := Generating module graphs for $1 documentation, \ + DEPS := $$(BUILD_JIGSAW_TOOLS) $$(MODULE_GRAPHS_PROPS), \ + OUTPUT_DIR := $$($1_MODULE_GRAPHS_DIR), \ + COMMAND := $$(TOOL_GENGRAPHS) --spec --output $$($1_MODULE_GRAPHS_DIR) \ + --dot-attributes $$(MODULE_GRAPHS_PROPS), \ )) # For each module needing a graph, create a svg file from the dot file # generated by the GenGraphs tool and store it in the target dir. - # They will depend on gengraphs_$1_TARGET, and will be added to $1. + # They will depend on module_graphs_dot_$1_TARGET, and will be added to + # $1_GRAPHS_TARGETS. $$(foreach m, $$($1_MODULES_NEEDING_GRAPH), \ - $$(eval $$(call setup_gengraph_dot_to_svg,$1,$$m)) \ + $$(eval $$(call setup_module_graph_dot_to_svg,$1,$$m)) \ + ) + + # We have asked SealedGraph to generate dot files and links to svg files. + # Now we must produce the svg files from the dot files. + + # Get a list of classes for which SealedGraph has generated dot files + $1_SEALED_CLASSES := $$(patsubst %.dot,%,$$(patsubst \ + $$($1_SEALED_GRAPHS_DIR)/%,%, \ + $$(wildcard $$($1_SEALED_GRAPHS_DIR)/*.dot))) + + # For each class needing a graph, create a svg file from the dot file + # generated by the SealedGraph taglet and store it in the target dir. + # They will will be added to $1_GRAPHS_TARGETS. + $$(foreach c, $$($1_SEALED_CLASSES), \ + $$(eval $$(call setup_sealed_graph_dot_to_svg,$1,$$c)) \ ) endif endef ################################################################################ -# Setup generation of the JDK API documentation (javadoc + modulegraph) +# Setup generation of the JDK API documentation (javadoc + graphs) # Define the groups of the JDK API documentation JavaSE_GROUP_NAME := Java SE @@ -456,10 +506,10 @@ $(eval $(call SetupApiDocsGeneration, JDK_API, \ )) # Targets generated are returned in JDK_API_JAVADOC_TARGETS and -# JDK_API_MODULEGRAPH_TARGETS. +# JDK_API_GRAPHS_TARGETS. ################################################################################ -# Setup generation of the Java SE API documentation (javadoc + modulegraph) +# Setup generation of the Java SE API documentation (javadoc + graphs) # The Java SE module scope is just java.se and its transitive indirect # exports. @@ -473,10 +523,10 @@ $(eval $(call SetupApiDocsGeneration, JAVASE_API, \ )) # Targets generated are returned in JAVASE_API_JAVADOC_TARGETS and -# JAVASE_API_MODULEGRAPH_TARGETS. +# JAVASE_API_GRAPHS_TARGETS. ################################################################################ -# Setup generation of the reference Java SE API documentation (javadoc + modulegraph) +# Setup generation of the reference Java SE API documentation (javadoc + graphs) # The reference javadoc is just the same as javase, but using the BootJDK javadoc # and a stable set of javadoc options. Typically it is used for generating @@ -494,7 +544,7 @@ $(eval $(call SetupApiDocsGeneration, REFERENCE_API, \ )) # Targets generated are returned in REFERENCE_API_JAVADOC_TARGETS and -# REFERENCE_API_MODULEGRAPH_TARGETS. +# REFERENCE_API_GRAPHS_TARGETS. ################################################################################ @@ -711,7 +761,7 @@ JAVADOC_ZIP_FILE := $(OUTPUTDIR)/bundles/$(JAVADOC_ZIP_NAME) $(eval $(call SetupZipArchive, BUILD_JAVADOC_ZIP, \ SRC := $(DOCS_OUTPUTDIR), \ ZIP := $(JAVADOC_ZIP_FILE), \ - EXTRA_DEPS := $(JDK_API_JAVADOC_TARGETS) $(JDK_API_MODULEGRAPH_TARGETS) \ + EXTRA_DEPS := $(JDK_API_JAVADOC_TARGETS) $(JDK_API_GRAPHS_TARGETS) \ $(JDK_SPECS_TARGETS), \ )) @@ -739,15 +789,15 @@ SPECS_ZIP_TARGETS += $(BUILD_SPECS_ZIP) docs-jdk-api-javadoc: $(JDK_API_JAVADOC_TARGETS) $(JDK_API_CUSTOM_TARGETS) -docs-jdk-api-modulegraph: $(JDK_API_MODULEGRAPH_TARGETS) +docs-jdk-api-graphs: $(JDK_API_GRAPHS_TARGETS) docs-javase-api-javadoc: $(JAVASE_API_JAVADOC_TARGETS) $(JAVASE_API_CUSTOM_TARGETS) -docs-javase-api-modulegraph: $(JAVASE_API_MODULEGRAPH_TARGETS) +docs-javase-api-graphs: $(JAVASE_API_GRAPHS_TARGETS) docs-reference-api-javadoc: $(REFERENCE_API_JAVADOC_TARGETS) $(REFERENCE_API_CUSTOM_TARGETS) -docs-reference-api-modulegraph: $(REFERENCE_API_MODULEGRAPH_TARGETS) +docs-reference-api-graphs: $(REFERENCE_API_GRAPHS_TARGETS) docs-jdk-specs: $(JDK_SPECS_TARGETS) @@ -757,12 +807,12 @@ docs-zip: $(ZIP_TARGETS) docs-specs-zip: $(SPECS_ZIP_TARGETS) -all: docs-jdk-api-javadoc docs-jdk-api-modulegraph docs-javase-api-javadoc \ - docs-javase-api-modulegraph docs-reference-api-javadoc \ - docs-reference-api-modulegraph docs-jdk-specs docs-jdk-index docs-zip \ +all: docs-jdk-api-javadoc docs-jdk-api-graphs docs-javase-api-javadoc \ + docs-javase-api-graphs docs-reference-api-javadoc \ + docs-reference-api-graphs docs-jdk-specs docs-jdk-index docs-zip \ docs-specs-zip -.PHONY: default all docs-jdk-api-javadoc docs-jdk-api-modulegraph \ - docs-javase-api-javadoc docs-javase-api-modulegraph \ - docs-reference-api-javadoc docs-reference-api-modulegraph docs-jdk-specs \ +.PHONY: default all docs-jdk-api-javadoc docs-jdk-api-graphs \ + docs-javase-api-javadoc docs-javase-api-graphs \ + docs-reference-api-javadoc docs-reference-api-graphs docs-jdk-specs \ docs-jdk-index docs-zip docs-specs-zip diff --git a/make/Main.gmk b/make/Main.gmk index 45bed0d0457..fec5d268301 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -466,15 +466,15 @@ ALL_TARGETS += bootcycle-images # Docs targets # If building full docs, to complete docs-*-api we need both the javadoc and -# modulegraph targets. +# graphs targets. $(eval $(call SetupTarget, docs-jdk-api-javadoc, \ MAKEFILE := Docs, \ TARGET := docs-jdk-api-javadoc, \ )) -$(eval $(call SetupTarget, docs-jdk-api-modulegraph, \ +$(eval $(call SetupTarget, docs-jdk-api-graphs, \ MAKEFILE := Docs, \ - TARGET := docs-jdk-api-modulegraph, \ + TARGET := docs-jdk-api-graphs, \ DEPS := buildtools-modules runnable-buildjdk, \ )) @@ -483,9 +483,9 @@ $(eval $(call SetupTarget, docs-javase-api-javadoc, \ TARGET := docs-javase-api-javadoc, \ )) -$(eval $(call SetupTarget, docs-javase-api-modulegraph, \ +$(eval $(call SetupTarget, docs-javase-api-graphs, \ MAKEFILE := Docs, \ - TARGET := docs-javase-api-modulegraph, \ + TARGET := docs-javase-api-graphs, \ DEPS := buildtools-modules runnable-buildjdk, \ )) @@ -494,9 +494,9 @@ $(eval $(call SetupTarget, docs-reference-api-javadoc, \ TARGET := docs-reference-api-javadoc, \ )) -$(eval $(call SetupTarget, docs-reference-api-modulegraph, \ +$(eval $(call SetupTarget, docs-reference-api-graphs, \ MAKEFILE := Docs, \ - TARGET := docs-reference-api-modulegraph, \ + TARGET := docs-reference-api-graphs, \ DEPS := buildtools-modules runnable-buildjdk, \ )) @@ -1107,9 +1107,14 @@ docs-reference-api: docs-reference-api-javadoc # If we're building full docs, we must also generate the module graphs to # get non-broken api documentation. ifeq ($(ENABLE_FULL_DOCS), true) - docs-jdk-api: docs-jdk-api-modulegraph - docs-javase-api: docs-javase-api-modulegraph - docs-reference-api: docs-reference-api-modulegraph + docs-jdk-api: docs-jdk-api-graphs + docs-javase-api: docs-javase-api-graphs + docs-reference-api: docs-reference-api-graphs + + # We must generate javadoc first so we know what graphs are needed + docs-jdk-api-graphs: docs-jdk-api-javadoc + docs-javase-api-graphs: docs-javase-api-javadoc + docs-reference-api-graphs: docs-reference-api-javadoc endif docs-jdk: docs-jdk-api docs-jdk-specs docs-jdk-index diff --git a/make/jdk/src/classes/build/tools/taglet/SealedGraph.java b/make/jdk/src/classes/build/tools/taglet/SealedGraph.java new file mode 100644 index 00000000000..da79c17b387 --- /dev/null +++ b/make/jdk/src/classes/build/tools/taglet/SealedGraph.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2017, 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 build.tools.taglet; + +import com.sun.source.doctree.DocTree; +import jdk.javadoc.doclet.Doclet; +import jdk.javadoc.doclet.DocletEnvironment; +import jdk.javadoc.doclet.Taglet; + +import javax.lang.model.element.*; +import javax.lang.model.type.DeclaredType; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.stream.Collectors; + +import static java.lang.System.lineSeparator; +import static java.nio.file.StandardOpenOption.*; +import static jdk.javadoc.doclet.Taglet.Location.TYPE; + +/** + * A block tag to optionally insert a reference to a sealed class hierarchy graph, + * and generate the corresponding dot file. + */ +public final class SealedGraph implements Taglet { + private static final String sealedDotOutputDir = + System.getProperty("sealedDotOutputDir"); + + private DocletEnvironment docletEnvironment; + + /** + * Returns the set of locations in which a taglet may be used. + */ + @Override + public Set getAllowedLocations() { + return EnumSet.of(TYPE); + } + + @Override + public boolean isInlineTag() { + return false; + } + + @Override + public String getName() { + return "sealedGraph"; + } + + @Override + public void init(DocletEnvironment env, Doclet doclet) { + docletEnvironment = env; + } + + @Override + public String toString(List tags, Element element) { + if (sealedDotOutputDir == null || sealedDotOutputDir.isEmpty()) { + return ""; + } + if (docletEnvironment == null || !(element instanceof TypeElement typeElement)) { + return ""; + } + + ModuleElement module = docletEnvironment.getElementUtils().getModuleOf(element); + Path dotFile = Path.of(sealedDotOutputDir, + module.getQualifiedName() + "_" + typeElement.getQualifiedName() + ".dot"); + + Set exports = module.getDirectives().stream() + .filter(ModuleElement.ExportsDirective.class::isInstance) + .map(ModuleElement.ExportsDirective.class::cast) + // Only include packages that are globally exported (i.e. no "to" exports) + .filter(ed -> ed.getTargetModules() == null) + .map(ModuleElement.ExportsDirective::getPackage) + .map(PackageElement::getQualifiedName) + .map(Objects::toString) + .collect(Collectors.toUnmodifiableSet()); + + String dotContent = Renderer.graph(typeElement, exports); + + try { + Files.writeString(dotFile, dotContent, WRITE, CREATE, TRUNCATE_EXISTING); + } catch (IOException e) { + throw new RuntimeException(e); + } + + String simpleTypeName = element.getSimpleName().toString(); + String imageFile = simpleTypeName + "-sealed-graph.svg"; + int thumbnailHeight = 100; // also appears in the stylesheet + String hoverImage = "" + + getImage(simpleTypeName, imageFile, -1, true) + + ""; + + return "
Sealed Class Hierarchy Graph:
" + + "
" + + "" + + getImage(simpleTypeName, imageFile, thumbnailHeight, false) + + hoverImage + + "" + + "
"; + } + + private static final String VERTICAL_ALIGN = "vertical-align:top"; + private static final String BORDER = "border: solid lightgray 1px;"; + + private String getImage(String typeName, String file, int height, boolean useBorder) { + return String.format("\"Sealed", + useBorder ? BORDER + " " + VERTICAL_ALIGN : VERTICAL_ALIGN, + typeName, + file, + (height <= 0 ? "" : " height=\"" + height + "\"")); + } + + private static final class Renderer { + + private Renderer() { + } + + // Generates a graph in DOT format + static String graph(TypeElement rootClass, Set exports) { + final State state = new State(rootClass); + traverse(state, rootClass, exports); + return state.render(); + } + + static void traverse(State state, TypeElement node, Set exports) { + state.addNode(node); + for (TypeElement subNode : permittedSubclasses(node, exports)) { + if (isInPublicApi(node, exports) && isInPublicApi(subNode, exports)) { + state.addEdge(node, subNode); + } + traverse(state, subNode, exports); + } + } + + private static final class State { + + private static final String LABEL = "label"; + private static final String TOOLTIP = "tooltip"; + private static final String STYLE = "style"; + + private final StringBuilder builder; + + private final Map> nodeStyleMap; + + public State(TypeElement rootNode) { + nodeStyleMap = new LinkedHashMap<>(); + builder = new StringBuilder() + .append("digraph G {") + .append(lineSeparator()) + .append(" nodesep=0.500000;") + .append(lineSeparator()) + .append(" ranksep=0.600000;") + .append(lineSeparator()) + .append(" pencolor=transparent;") + .append(lineSeparator()) + .append(" node [shape=plaintext, fontcolor=\"#e76f00\", fontname=\"DejaVuSans\", fontsize=12, margin=\".2,.2\"];") + .append(lineSeparator()) + .append(" edge [penwidth=2, color=\"#999999\", arrowhead=open, arrowsize=1];") + .append(lineSeparator()) + .append(" rankdir=\"BT\";") + .append(lineSeparator()); + } + + public void addNode(TypeElement node) { + var styles = nodeStyleMap.computeIfAbsent(id(node), n -> new LinkedHashMap<>()); + styles.put(LABEL, node.getSimpleName().toString()); + styles.put(TOOLTIP, node.getQualifiedName().toString()); + if (!(node.getModifiers().contains(Modifier.SEALED) || node.getModifiers().contains(Modifier.FINAL))) { + // This indicates that the hierarchy is not closed + styles.put(STYLE, "dashed"); + } + } + + public void addEdge(TypeElement node, TypeElement subNode) { + builder.append(" ") + .append(quotedId(subNode)) + .append(" -> ") + .append(quotedId(node)) + .append(";") + .append(lineSeparator()); + } + + public String render() { + nodeStyleMap.forEach((nodeName, styles) -> { + builder.append(" ") + .append('"').append(nodeName).append("\" ") + .append(styles.entrySet().stream() + .map(e -> e.getKey() + "=\"" + e.getValue() + "\"") + .collect(Collectors.joining(" ", "[", "]"))) + .append(System.lineSeparator()); + }); + builder.append("}"); + return builder.toString(); + } + + private String id(TypeElement node) { + return node.getQualifiedName().toString(); + } + + private String quotedId(TypeElement node) { + return "\"" + id(node) + "\""; + } + + private String simpleName(String name) { + int lastDot = name.lastIndexOf('.'); + return lastDot < 0 + ? name + : name.substring(lastDot); + } + + } + + private static List permittedSubclasses(TypeElement node, Set exports) { + return node.getPermittedSubclasses().stream() + .filter(DeclaredType.class::isInstance) + .map(DeclaredType.class::cast) + .map(DeclaredType::asElement) + .filter(TypeElement.class::isInstance) + .map(TypeElement.class::cast) + .filter(te -> isInPublicApi(te, exports)) + .toList(); + } + + private static boolean isInPublicApi(TypeElement typeElement, Set exports) { + return (exports.contains(packageName(typeElement.getQualifiedName().toString())) || + exports.contains(packageName(typeElement.getSuperclass().toString()))) && + typeElement.getModifiers().contains(Modifier.PUBLIC); + } + + private static String packageName(String name) { + int lastDot = name.lastIndexOf('.'); + return lastDot < 0 + ? "" + : name.substring(0, lastDot); + } + } +} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css index 29463ad9d90..cb8f9159b16 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css @@ -835,11 +835,11 @@ button.page-search-header { span#page-search-link { text-decoration: underline; } -.module-graph span { +.module-graph span, .sealed-graph span { display:none; position:absolute; } -.module-graph:hover span { +.module-graph:hover span, .sealed-graph:hover span { display:block; margin: -100px 0 0 100px; z-index: 1; diff --git a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java index bdcc957592f..5ec8284244f 100644 --- a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java +++ b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java @@ -142,6 +142,7 @@ public class CheckStylesheetClasses { // very JDK specific styleSheetNames.remove("module-graph"); + styleSheetNames.remove("sealed-graph"); boolean ok = check(htmlStyleNames, "HtmlStyle", styleSheetNames, "stylesheet") & check(styleSheetNames, "stylesheet", htmlStyleNames, "HtmlStyle");