src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java
changeset 55197 0ca8e495bbba
parent 54610 a9ab154b1384
child 55232 9b392b044f64
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java	Tue Jun 04 16:20:42 2019 +0200
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java	Tue Jun 04 16:33:37 2019 +0200
@@ -46,12 +46,14 @@
 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.StringContent;
 import jdk.javadoc.internal.doclets.formats.html.markup.Table;
 import jdk.javadoc.internal.doclets.formats.html.markup.TableHeader;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
 import jdk.javadoc.internal.doclets.toolkit.Resources;
 import jdk.javadoc.internal.doclets.toolkit.taglets.DeprecatedTaglet;
+import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
 import jdk.javadoc.internal.doclets.toolkit.util.Utils;
 
 import static javax.lang.model.element.Modifier.ABSTRACT;
@@ -219,55 +221,6 @@
      */
     protected abstract Content getDeprecatedLink(Element member);
 
-    /**
-     * Add the member name to the content tree.
-     *
-     * @param name the member name to be added to the content tree.
-     * @param htmltree the content tree to which the name will be added.
-     */
-    protected void addName(String name, Content htmltree) {
-        htmltree.add(name);
-    }
-
-    /**
-     * Add the modifier for the member. The modifiers are ordered as specified
-     * by <em>The Java Language Specification</em>.
-     *
-     * @param member the member for which the modifier will be added.
-     * @param htmltree the content tree to which the modifier information will be added.
-     */
-    protected void addModifiers(Element member, Content htmltree) {
-        Set<Modifier> set = new TreeSet<>(member.getModifiers());
-
-        // remove the ones we really don't need
-        set.remove(NATIVE);
-        set.remove(SYNCHRONIZED);
-        set.remove(STRICTFP);
-
-        // According to JLS, we should not be showing public modifier for
-        // interface methods.
-        if ((utils.isField(member) || utils.isMethod(member))
-            && ((writer instanceof ClassWriterImpl
-                 && utils.isInterface(((ClassWriterImpl) writer).getTypeElement())  ||
-                 writer instanceof AnnotationTypeWriterImpl) )) {
-            // Remove the implicit abstract and public modifiers
-            if (utils.isMethod(member) &&
-                (utils.isInterface(member.getEnclosingElement()) ||
-                 utils.isAnnotationType(member.getEnclosingElement()))) {
-                set.remove(ABSTRACT);
-                set.remove(PUBLIC);
-            }
-            if (!utils.isMethod(member)) {
-                set.remove(PUBLIC);
-            }
-        }
-        if (!set.isEmpty()) {
-            String mods = set.stream().map(Modifier::toString).collect(Collectors.joining(" "));
-            htmltree.add(mods);
-            htmltree.add(Entity.NO_BREAK_SPACE);
-        }
-    }
-
     protected CharSequence makeSpace(int len) {
         if (len <= 0) {
             return "";
@@ -563,4 +516,237 @@
         else
             return HtmlTree.LI(HtmlStyle.blockList, memberTree);
     }
+
+    /**
+     * A content builder for member signatures.
+     */
+    class MemberSignature {
+
+        private Element element;
+        private Content typeParameters;
+        private Content returnType;
+        private Content parameters;
+        private Content exceptions;
+
+        // Threshold for length of type parameters before switching from inline to block representation.
+        private final static int TYPE_PARAMS_MAX_INLINE_LENGTH = 50;
+
+        // Threshold for combined length of modifiers, type params and return type before breaking
+        // it up with a line break before the return type.
+        private final static int RETURN_TYPE_MAX_LINE_LENGTH = 50;
+
+        /**
+         * Create a new member signature builder.
+         *
+         * @param element The element for which to create a signature.
+         */
+        MemberSignature(Element element) {
+            this.element = element;
+        }
+
+        /**
+         * Add the type parameters for an executable member.
+         *
+         * @param typeParameters the content tree containing the type parameters to add.
+         * @return this MemberSignature instance
+         */
+        MemberSignature addTypeParameters(Content typeParameters) {
+            this.typeParameters = typeParameters;
+            return this;
+        }
+
+        /**
+         * Add the return type for an executable member.
+         *
+         * @param returnType the content tree containing the return type to add.
+         * @return this MemberSignature instance
+         */
+        MemberSignature addReturnType(Content returnType) {
+            this.returnType = returnType;
+            return this;
+        }
+
+        /**
+         * Add the type information for a non-executable member.
+         *
+         * @param type the type of the member.
+         * @return this MemberSignature instance
+         */
+        MemberSignature addType(TypeMirror type) {
+            this.returnType = writer.getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.MEMBER, type));
+            return this;
+        }
+
+        /**
+         * Add the parameter information of an executable member.
+         *
+         * @param paramTree the content tree containing the parameter information.
+         * @return this MemberSignature instance
+         */
+        MemberSignature addParameters(Content paramTree) {
+            this.parameters = paramTree;
+            return this;
+        }
+
+        /**
+         * Add the exception information of an executable member.
+         *
+         * @param exceptionTree the content tree containing the exception information
+         * @return this MemberSignature instance
+         */
+        MemberSignature addExceptions(Content exceptionTree) {
+            this.exceptions = exceptionTree;
+            return this;
+        }
+
+        /**
+         * Return a HTML tree containing the member signature.
+         *
+         * @return a HTML tree containing the member signature
+         */
+        Content toContent() {
+            Content content = new ContentBuilder();
+            // Position of last line separator.
+            int lastLineSeparator = 0;
+
+            // Annotations
+            Content annotationInfo = writer.getAnnotationInfo(element.getAnnotationMirrors(), true);
+            if (!annotationInfo.isEmpty()) {
+                content.add(HtmlTree.SPAN(HtmlStyle.annotations, annotationInfo));
+                lastLineSeparator = content.charCount();
+            }
+
+            // Modifiers
+            appendModifiers(content);
+
+            // Type parameters
+            if (typeParameters != null && !typeParameters.isEmpty()) {
+                lastLineSeparator = appendTypeParameters(content, lastLineSeparator);
+            }
+
+            // Return type
+            if (returnType != null) {
+                content.add(HtmlTree.SPAN(HtmlStyle.returnType, returnType));
+                content.add(Entity.NO_BREAK_SPACE);
+            }
+
+            // Name
+            HtmlTree nameSpan = new HtmlTree(HtmlTag.SPAN);
+            nameSpan.setStyle(HtmlStyle.memberName);
+            if (configuration.linksource) {
+                Content name = new StringContent(name(element));
+                writer.addSrcLink(element, name, nameSpan);
+            } else {
+                nameSpan.add(name(element));
+            }
+            content.add(nameSpan);
+
+
+            // Parameters and exceptions
+            if (parameters != null) {
+                appendParametersAndExceptions(content, lastLineSeparator);
+            }
+
+            return HtmlTree.DIV(HtmlStyle.memberSignature, content);
+        }
+
+        /**
+         * Add the modifier for the member. The modifiers are ordered as specified
+         * by <em>The Java Language Specification</em>.
+         *
+         * @param htmltree the content tree to which the modifier information will be added.
+         */
+        private void appendModifiers(Content htmltree) {
+            Set<Modifier> set = new TreeSet<>(element.getModifiers());
+
+            // remove the ones we really don't need
+            set.remove(NATIVE);
+            set.remove(SYNCHRONIZED);
+            set.remove(STRICTFP);
+
+            // According to JLS, we should not be showing public modifier for
+            // interface methods.
+            if ((utils.isField(element) || utils.isMethod(element))
+                    && ((writer instanceof ClassWriterImpl
+                    && utils.isInterface(((ClassWriterImpl) writer).getTypeElement())  ||
+                    writer instanceof AnnotationTypeWriterImpl) )) {
+                // Remove the implicit abstract and public modifiers
+                if (utils.isMethod(element) &&
+                        (utils.isInterface(element.getEnclosingElement()) ||
+                                utils.isAnnotationType(element.getEnclosingElement()))) {
+                    set.remove(ABSTRACT);
+                    set.remove(PUBLIC);
+                }
+                if (!utils.isMethod(element)) {
+                    set.remove(PUBLIC);
+                }
+            }
+            if (!set.isEmpty()) {
+                String mods = set.stream().map(Modifier::toString).collect(Collectors.joining(" "));
+                htmltree.add(HtmlTree.SPAN(HtmlStyle.modifiers, new StringContent(mods)));
+                htmltree.add(Entity.NO_BREAK_SPACE);
+            }
+        }
+
+        /**
+         * Append the type parameter information to the HTML tree.
+         *
+         * @param htmltree the HTML tree
+         * @param lastLineSeparator index of last line separator in HTML tree
+         * @return the new index of the last line separator
+         */
+        private int appendTypeParameters(Content htmltree, int lastLineSeparator) {
+            // Apply different wrapping strategies for type parameters
+            // depending of combined length of type parameters and return type.
+            int typeParamLength = typeParameters.charCount();
+
+            if (typeParamLength >= TYPE_PARAMS_MAX_INLINE_LENGTH) {
+                htmltree.add(HtmlTree.SPAN(HtmlStyle.typeParametersLong, typeParameters));
+            } else {
+                htmltree.add(HtmlTree.SPAN(HtmlStyle.typeParameters, typeParameters));
+            }
+
+            int lineLength = htmltree.charCount() - lastLineSeparator;
+            int newLastLineSeparator = lastLineSeparator;
+
+            // sum below includes length of modifiers plus type params added above
+            if (lineLength + returnType.charCount()> RETURN_TYPE_MAX_LINE_LENGTH) {
+                htmltree.add(DocletConstants.NL);
+                newLastLineSeparator = htmltree.charCount();
+            } else {
+                htmltree.add(Entity.NO_BREAK_SPACE);
+            }
+
+            return newLastLineSeparator;
+        }
+
+        /**
+         * Append the parameters and exceptions information to the HTML tree.
+         *
+         * @param htmltree the HTML tree
+         * @param lastLineSeparator the index of the last line separator in HTML tree
+         */
+        private void appendParametersAndExceptions(Content htmltree, int lastLineSeparator) {
+            // Record current position for indentation of exceptions
+            int indentSize = htmltree.charCount() - lastLineSeparator;
+
+            if (parameters.isEmpty()) {
+                htmltree.add("()");
+            } else {
+                parameters.add(")");
+                htmltree.add(Entity.ZERO_WIDTH_SPACE);
+                htmltree.add("(");
+                htmltree.add(HtmlTree.SPAN(HtmlStyle.arguments, parameters));
+            }
+
+            // Exceptions
+            if (exceptions != null && !exceptions.isEmpty()) {
+                CharSequence indent = makeSpace(indentSize + 1 - 7);
+                htmltree.add(DocletConstants.NL);
+                htmltree.add(indent);
+                htmltree.add("throws ");
+                htmltree.add(HtmlTree.SPAN(HtmlStyle.exceptions, exceptions));
+            }
+        }
+    }
 }