1 /*
   2  * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.javadoc.internal.doclets.formats.html;
  27 
  28 import java.util.*;
  29 
  30 import javax.lang.model.element.AnnotationMirror;
  31 import javax.lang.model.element.Element;
  32 import javax.lang.model.element.ModuleElement;
  33 import javax.lang.model.element.PackageElement;
  34 import javax.lang.model.element.TypeElement;
  35 import javax.lang.model.type.TypeMirror;
  36 import javax.lang.model.util.SimpleElementVisitor8;
  37 
  38 import com.sun.source.doctree.DocTree;
  39 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
  40 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
  41 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
  42 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
  43 import jdk.javadoc.internal.doclets.formats.html.markup.Links;
  44 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
  45 import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
  46 import jdk.javadoc.internal.doclets.toolkit.Content;
  47 import jdk.javadoc.internal.doclets.toolkit.builders.MemberSummaryBuilder;
  48 import jdk.javadoc.internal.doclets.toolkit.taglets.ParamTaglet;
  49 import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
  50 import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
  51 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
  52 import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
  53 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
  54 import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
  55 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap;
  56 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap.Kind;
  57 
  58 /**
  59  * Generate the Class Information Page.
  60  *
  61  *  <p><b>This is NOT part of any supported API.
  62  *  If you write code that depends on this, you do so at your own risk.
  63  *  This code and its internal interfaces are subject to change or
  64  *  deletion without notice.</b>
  65  *
  66  * @see javax.lang.model.element.TypeElement
  67  * @see java.util.Collections
  68  * @see java.util.List
  69  * @see java.util.ArrayList
  70  * @see java.util.HashMap
  71  *
  72  * @author Atul M Dambalkar
  73  * @author Robert Field
  74  * @author Bhavesh Patel (Modified)
  75  */
  76 public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWriter {
  77 
  78     protected final TypeElement typeElement;
  79 
  80     protected final ClassTree classtree;
  81 
  82     protected final TypeElement prev;
  83 
  84     protected final TypeElement next;
  85 
  86     /**
  87      * @param configuration the configuration data for the doclet
  88      * @param typeElement the class being documented.
  89      * @param prevClass the previous class that was documented.
  90      * @param nextClass the next class being documented.
  91      * @param classTree the class tree for the given class.
  92      */
  93     public ClassWriterImpl(HtmlConfiguration configuration, TypeElement typeElement,
  94                            TypeElement prevClass, TypeElement nextClass, ClassTree classTree) {
  95         super(configuration, configuration.docPaths.forClass(typeElement));
  96         this.typeElement = typeElement;
  97         configuration.currentTypeElement = typeElement;
  98         this.classtree = classTree;
  99         this.prev = prevClass;
 100         this.next = nextClass;
 101     }
 102 
 103     /**
 104      * Get the module link.
 105      *
 106      * @return a content tree for the module link
 107      */
 108     @Override
 109     protected Content getNavLinkModule() {
 110         Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(typeElement),
 111                 contents.moduleLabel);
 112         Content li = HtmlTree.LI(linkContent);
 113         return li;
 114     }
 115 
 116     /**
 117      * Get this package link.
 118      *
 119      * @return a content tree for the package link
 120      */
 121     @Override
 122     protected Content getNavLinkPackage() {
 123         Content linkContent = links.createLink(DocPaths.PACKAGE_SUMMARY,
 124                 contents.packageLabel);
 125         Content li = HtmlTree.LI(linkContent);
 126         return li;
 127     }
 128 
 129     /**
 130      * Get the class link.
 131      *
 132      * @return a content tree for the class link
 133      */
 134     @Override
 135     protected Content getNavLinkClass() {
 136         Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.classLabel);
 137         return li;
 138     }
 139 
 140     /**
 141      * Get the class use link.
 142      *
 143      * @return a content tree for the class use link
 144      */
 145     @Override
 146     protected Content getNavLinkClassUse() {
 147         Content linkContent = links.createLink(DocPaths.CLASS_USE.resolve(filename), contents.useLabel);
 148         Content li = HtmlTree.LI(linkContent);
 149         return li;
 150     }
 151 
 152     /**
 153      * Get link to previous class.
 154      *
 155      * @return a content tree for the previous class link
 156      */
 157     @Override
 158     public Content getNavLinkPrevious() {
 159         Content li;
 160         if (prev != null) {
 161             Content prevLink = getLink(new LinkInfoImpl(configuration,
 162                     LinkInfoImpl.Kind.CLASS, prev)
 163                     .label(contents.prevClassLabel).strong(true));
 164             li = HtmlTree.LI(prevLink);
 165         }
 166         else
 167             li = HtmlTree.LI(contents.prevClassLabel);
 168         return li;
 169     }
 170 
 171     /**
 172      * Get link to next class.
 173      *
 174      * @return a content tree for the next class link
 175      */
 176     @Override
 177     public Content getNavLinkNext() {
 178         Content li;
 179         if (next != null) {
 180             Content nextLink = getLink(new LinkInfoImpl(configuration,
 181                     LinkInfoImpl.Kind.CLASS, next)
 182                     .label(contents.nextClassLabel).strong(true));
 183             li = HtmlTree.LI(nextLink);
 184         }
 185         else
 186             li = HtmlTree.LI(contents.nextClassLabel);
 187         return li;
 188     }
 189 
 190     /**
 191      * {@inheritDoc}
 192      */
 193     @Override
 194     public Content getHeader(String header) {
 195         HtmlTree bodyTree = getBody(true, getWindowTitle(utils.getSimpleName(typeElement)));
 196         HtmlTree htmlTree = (configuration.allowTag(HtmlTag.HEADER))
 197                 ? HtmlTree.HEADER()
 198                 : bodyTree;
 199         addTop(htmlTree);
 200         addNavLinks(true, htmlTree);
 201         if (configuration.allowTag(HtmlTag.HEADER)) {
 202             bodyTree.addContent(htmlTree);
 203         }
 204         bodyTree.addContent(HtmlConstants.START_OF_CLASS_DATA);
 205         HtmlTree div = new HtmlTree(HtmlTag.DIV);
 206         div.setStyle(HtmlStyle.header);
 207         if (configuration.showModules) {
 208             ModuleElement mdle = configuration.docEnv.getElementUtils().getModuleOf(typeElement);
 209             Content classModuleLabel = HtmlTree.SPAN(HtmlStyle.moduleLabelInType, contents.moduleLabel);
 210             Content moduleNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, classModuleLabel);
 211             moduleNameDiv.addContent(Contents.SPACE);
 212             moduleNameDiv.addContent(getModuleLink(mdle,
 213                     new StringContent(mdle.getQualifiedName().toString())));
 214             div.addContent(moduleNameDiv);
 215         }
 216         PackageElement pkg = utils.containingPackage(typeElement);
 217         if (!pkg.isUnnamed()) {
 218             Content classPackageLabel = HtmlTree.SPAN(HtmlStyle.packageLabelInType, contents.packageLabel);
 219             Content pkgNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, classPackageLabel);
 220             pkgNameDiv.addContent(Contents.SPACE);
 221             Content pkgNameContent = getPackageLink(pkg,
 222                     new StringContent(utils.getPackageName(pkg)));
 223             pkgNameDiv.addContent(pkgNameContent);
 224             div.addContent(pkgNameDiv);
 225         }
 226         LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
 227                 LinkInfoImpl.Kind.CLASS_HEADER, typeElement);
 228         //Let's not link to ourselves in the header.
 229         linkInfo.linkToSelf = false;
 230         Content headerContent = new StringContent(header);
 231         Content heading = HtmlTree.HEADING(HtmlConstants.CLASS_PAGE_HEADING, true,
 232                 HtmlStyle.title, headerContent);
 233         heading.addContent(getTypeParameterLinks(linkInfo));
 234         div.addContent(heading);
 235         if (configuration.allowTag(HtmlTag.MAIN)) {
 236             mainTree.addContent(div);
 237         } else {
 238             bodyTree.addContent(div);
 239         }
 240         return bodyTree;
 241     }
 242 
 243     /**
 244      * {@inheritDoc}
 245      */
 246     @Override
 247     public Content getClassContentHeader() {
 248         return getContentHeader();
 249     }
 250 
 251     /**
 252      * {@inheritDoc}
 253      */
 254     @Override
 255     public void addFooter(Content contentTree) {
 256         contentTree.addContent(HtmlConstants.END_OF_CLASS_DATA);
 257         Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
 258                 ? HtmlTree.FOOTER()
 259                 : contentTree;
 260         addNavLinks(false, htmlTree);
 261         addBottom(htmlTree);
 262         if (configuration.allowTag(HtmlTag.FOOTER)) {
 263             contentTree.addContent(htmlTree);
 264         }
 265     }
 266 
 267     /**
 268      * {@inheritDoc}
 269      */
 270     @Override
 271     public void printDocument(Content contentTree) throws DocFileIOException {
 272         printHtmlDocument(configuration.metakeywords.getMetaKeywords(typeElement),
 273                 true, contentTree);
 274     }
 275 
 276     /**
 277      * {@inheritDoc}
 278      */
 279     @Override
 280     public Content getClassInfoTreeHeader() {
 281         return getMemberTreeHeader();
 282     }
 283 
 284     /**
 285      * {@inheritDoc}
 286      */
 287     @Override
 288     public Content getClassInfo(Content classInfoTree) {
 289         return getMemberTree(HtmlStyle.description, classInfoTree);
 290     }
 291 
 292     /**
 293      * {@inheritDoc}
 294      */
 295     @Override
 296     public void addClassSignature(String modifiers, Content classInfoTree) {
 297         Content hr = new HtmlTree(HtmlTag.HR);
 298         classInfoTree.addContent(hr);
 299         Content pre = new HtmlTree(HtmlTag.PRE);
 300         addAnnotationInfo(typeElement, pre);
 301         pre.addContent(modifiers);
 302         LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
 303                 LinkInfoImpl.Kind.CLASS_SIGNATURE, typeElement);
 304         //Let's not link to ourselves in the signature.
 305         linkInfo.linkToSelf = false;
 306         Content className = new StringContent(utils.getSimpleName(typeElement));
 307         Content parameterLinks = getTypeParameterLinks(linkInfo);
 308         if (configuration.linksource) {
 309             addSrcLink(typeElement, className, pre);
 310             pre.addContent(parameterLinks);
 311         } else {
 312             Content span = HtmlTree.SPAN(HtmlStyle.typeNameLabel, className);
 313             span.addContent(parameterLinks);
 314             pre.addContent(span);
 315         }
 316         if (!utils.isInterface(typeElement)) {
 317             TypeMirror superclass = utils.getFirstVisibleSuperClass(typeElement);
 318             if (superclass != null) {
 319                 pre.addContent(DocletConstants.NL);
 320                 pre.addContent("extends ");
 321                 Content link = getLink(new LinkInfoImpl(configuration,
 322                         LinkInfoImpl.Kind.CLASS_SIGNATURE_PARENT_NAME,
 323                         superclass));
 324                 pre.addContent(link);
 325             }
 326         }
 327         List<? extends TypeMirror> interfaces = typeElement.getInterfaces();
 328         if (!interfaces.isEmpty()) {
 329             boolean isFirst = true;
 330             for (TypeMirror type : interfaces) {
 331                 TypeElement tDoc = utils.asTypeElement(type);
 332                 if (!(utils.isPublic(tDoc) || utils.isLinkable(tDoc))) {
 333                     continue;
 334                 }
 335                 if (isFirst) {
 336                     pre.addContent(DocletConstants.NL);
 337                     pre.addContent(utils.isInterface(typeElement) ? "extends " : "implements ");
 338                     isFirst = false;
 339                 } else {
 340                     pre.addContent(", ");
 341                 }
 342                 Content link = getLink(new LinkInfoImpl(configuration,
 343                                                         LinkInfoImpl.Kind.CLASS_SIGNATURE_PARENT_NAME,
 344                                                         type));
 345                 pre.addContent(link);
 346             }
 347         }
 348         classInfoTree.addContent(pre);
 349     }
 350 
 351     /**
 352      * {@inheritDoc}
 353      */
 354     @Override
 355     public void addClassDescription(Content classInfoTree) {
 356         if(!configuration.nocomment) {
 357             // generate documentation for the class.
 358             if (!utils.getFullBody(typeElement).isEmpty()) {
 359                 addInlineComment(typeElement, classInfoTree);
 360             }
 361         }
 362     }
 363 
 364     /**
 365      * {@inheritDoc}
 366      */
 367     @Override
 368     public void addClassTagInfo(Content classInfoTree) {
 369         if(!configuration.nocomment) {
 370             // Print Information about all the tags here
 371             addTagsInfo(typeElement, classInfoTree);
 372         }
 373     }
 374 
 375     /**
 376      * Get the class hierarchy tree for the given class.
 377      *
 378      * @param type the class to print the hierarchy for
 379      * @return a content tree for class inheritence
 380      */
 381     private Content getClassInheritenceTree(TypeMirror type) {
 382         TypeMirror sup;
 383         HtmlTree classTreeUl = new HtmlTree(HtmlTag.UL);
 384         classTreeUl.setStyle(HtmlStyle.inheritance);
 385         Content liTree = null;
 386         do {
 387             sup = utils.getFirstVisibleSuperClass(type);
 388             if (sup != null) {
 389                 HtmlTree ul = new HtmlTree(HtmlTag.UL);
 390                 ul.setStyle(HtmlStyle.inheritance);
 391                 ul.addContent(getTreeForClassHelper(type));
 392                 if (liTree != null)
 393                     ul.addContent(liTree);
 394                 Content li = HtmlTree.LI(ul);
 395                 liTree = li;
 396                 type = sup;
 397             } else
 398                 classTreeUl.addContent(getTreeForClassHelper(type));
 399         } while (sup != null);
 400         if (liTree != null)
 401             classTreeUl.addContent(liTree);
 402         return classTreeUl;
 403     }
 404 
 405     /**
 406      * Get the class helper tree for the given class.
 407      *
 408      * @param type the class to print the helper for
 409      * @return a content tree for class helper
 410      */
 411     private Content getTreeForClassHelper(TypeMirror type) {
 412         Content li = new HtmlTree(HtmlTag.LI);
 413         if (type.equals(typeElement.asType())) {
 414             Content typeParameters = getTypeParameterLinks(
 415                     new LinkInfoImpl(configuration, LinkInfoImpl.Kind.TREE,
 416                     typeElement));
 417             if (configuration.shouldExcludeQualifier(utils.containingPackage(typeElement).toString())) {
 418                 li.addContent(utils.asTypeElement(type).getSimpleName());
 419                 li.addContent(typeParameters);
 420             } else {
 421                 li.addContent(utils.asTypeElement(type).getQualifiedName());
 422                 li.addContent(typeParameters);
 423             }
 424         } else {
 425             Content link = getLink(new LinkInfoImpl(configuration,
 426                     LinkInfoImpl.Kind.CLASS_TREE_PARENT, type)
 427                     .label(configuration.getClassName(utils.asTypeElement(type))));
 428             li.addContent(link);
 429         }
 430         return li;
 431     }
 432 
 433     /**
 434      * {@inheritDoc}
 435      */
 436     @Override
 437     public void addClassTree(Content classContentTree) {
 438         if (!utils.isClass(typeElement)) {
 439             return;
 440         }
 441         classContentTree.addContent(getClassInheritenceTree(typeElement.asType()));
 442     }
 443 
 444     /**
 445      * {@inheritDoc}
 446      */
 447     @Override
 448     public void addTypeParamInfo(Content classInfoTree) {
 449         if (!utils.getTypeParamTrees(typeElement).isEmpty()) {
 450             Content typeParam = (new ParamTaglet()).getTagletOutput(typeElement,
 451                     getTagletWriterInstance(false));
 452             Content dl = HtmlTree.DL(typeParam);
 453             classInfoTree.addContent(dl);
 454         }
 455     }
 456 
 457     /**
 458      * {@inheritDoc}
 459      */
 460     @Override
 461     public void addSubClassInfo(Content classInfoTree) {
 462         if (utils.isClass(typeElement)) {
 463             if (typeElement.getQualifiedName().toString().equals("java.lang.Object") ||
 464                     typeElement.getQualifiedName().toString().equals("org.omg.CORBA.Object")) {
 465                 return;    // Don't generate the list, too huge
 466             }
 467             Set<TypeElement> subclasses = classtree.directSubClasses(typeElement, false);
 468             if (!subclasses.isEmpty()) {
 469                 Content label = contents.subclassesLabel;
 470                 Content dt = HtmlTree.DT(label);
 471                 Content dl = HtmlTree.DL(dt);
 472                 dl.addContent(getClassLinks(LinkInfoImpl.Kind.SUBCLASSES,
 473                         subclasses));
 474                 classInfoTree.addContent(dl);
 475             }
 476         }
 477     }
 478 
 479     /**
 480      * {@inheritDoc}
 481      */
 482     @Override
 483     public void addSubInterfacesInfo(Content classInfoTree) {
 484         if (utils.isInterface(typeElement)) {
 485             Set<TypeElement> subInterfaces = classtree.allSubClasses(typeElement, false);
 486             if (!subInterfaces.isEmpty()) {
 487                 Content label = contents.subinterfacesLabel;
 488                 Content dt = HtmlTree.DT(label);
 489                 Content dl = HtmlTree.DL(dt);
 490                 dl.addContent(getClassLinks(LinkInfoImpl.Kind.SUBINTERFACES,
 491                         subInterfaces));
 492                 classInfoTree.addContent(dl);
 493             }
 494         }
 495     }
 496 
 497     /**
 498      * {@inheritDoc}
 499      */
 500     @Override
 501     public void addInterfaceUsageInfo (Content classInfoTree) {
 502         if (!utils.isInterface(typeElement)) {
 503             return;
 504         }
 505         if (typeElement.getQualifiedName().toString().equals("java.lang.Cloneable") ||
 506                 typeElement.getQualifiedName().toString().equals("java.io.Serializable")) {
 507             return;   // Don't generate the list, too big
 508         }
 509         Set<TypeElement> implcl = classtree.implementingClasses(typeElement);
 510         if (!implcl.isEmpty()) {
 511             Content label = contents.implementingClassesLabel;
 512             Content dt = HtmlTree.DT(label);
 513             Content dl = HtmlTree.DL(dt);
 514             dl.addContent(getClassLinks(LinkInfoImpl.Kind.IMPLEMENTED_CLASSES,
 515                     implcl));
 516             classInfoTree.addContent(dl);
 517         }
 518     }
 519 
 520     /**
 521      * {@inheritDoc}
 522      */
 523     @Override
 524     public void addImplementedInterfacesInfo(Content classInfoTree) {
 525         SortedSet<TypeMirror> interfaces = new TreeSet<>(utils.makeTypeMirrorClassUseComparator());
 526         interfaces.addAll(utils.getAllInterfaces(typeElement));
 527         if (utils.isClass(typeElement) && !interfaces.isEmpty()) {
 528             Content label = contents.allImplementedInterfacesLabel;
 529             Content dt = HtmlTree.DT(label);
 530             Content dl = HtmlTree.DL(dt);
 531             dl.addContent(getClassLinks(LinkInfoImpl.Kind.IMPLEMENTED_INTERFACES, interfaces));
 532             classInfoTree.addContent(dl);
 533         }
 534     }
 535 
 536     /**
 537      * {@inheritDoc}
 538      */
 539     @Override
 540     public void addSuperInterfacesInfo(Content classInfoTree) {
 541         SortedSet<TypeMirror> interfaces =
 542                 new TreeSet<>(utils.makeTypeMirrorIndexUseComparator());
 543         interfaces.addAll(utils.getAllInterfaces(typeElement));
 544 
 545         if (utils.isInterface(typeElement) && !interfaces.isEmpty()) {
 546             Content label = contents.allSuperinterfacesLabel;
 547             Content dt = HtmlTree.DT(label);
 548             Content dl = HtmlTree.DL(dt);
 549             dl.addContent(getClassLinks(LinkInfoImpl.Kind.SUPER_INTERFACES, interfaces));
 550             classInfoTree.addContent(dl);
 551         }
 552     }
 553 
 554     /**
 555      * {@inheritDoc}
 556      */
 557     @Override
 558     public void addNestedClassInfo(final Content classInfoTree) {
 559         Element outerClass = typeElement.getEnclosingElement();
 560         if (outerClass == null)
 561             return;
 562         new SimpleElementVisitor8<Void, Void>() {
 563             @Override
 564             public Void visitType(TypeElement e, Void p) {
 565                 Content label = utils.isInterface(e)
 566                         ? contents.enclosingInterfaceLabel
 567                         : contents.enclosingClassLabel;
 568                 Content dt = HtmlTree.DT(label);
 569                 Content dl = HtmlTree.DL(dt);
 570                 Content dd = new HtmlTree(HtmlTag.DD);
 571                 dd.addContent(getLink(new LinkInfoImpl(configuration,
 572                         LinkInfoImpl.Kind.CLASS, e)));
 573                 dl.addContent(dd);
 574                 classInfoTree.addContent(dl);
 575                 return null;
 576             }
 577         }.visit(outerClass);
 578     }
 579 
 580     /**
 581      * {@inheritDoc}
 582      */
 583     @Override
 584     public void addFunctionalInterfaceInfo (Content classInfoTree) {
 585         if (isFunctionalInterface()) {
 586             Content dt = HtmlTree.DT(contents.functionalInterface);
 587             Content dl = HtmlTree.DL(dt);
 588             Content dd = new HtmlTree(HtmlTag.DD);
 589             dd.addContent(contents.functionalInterfaceMessage);
 590             dl.addContent(dd);
 591             classInfoTree.addContent(dl);
 592         }
 593     }
 594 
 595     public boolean isFunctionalInterface() {
 596         List<? extends AnnotationMirror> annotationMirrors = ((Element) typeElement).getAnnotationMirrors();
 597         for (AnnotationMirror anno : annotationMirrors) {
 598             if (utils.isFunctionalInterface(anno)) {
 599                 return true;
 600             }
 601         }
 602         return false;
 603     }
 604 
 605 
 606     /**
 607      * {@inheritDoc}
 608      */
 609     @Override
 610     public void addClassDeprecationInfo(Content classInfoTree) {
 611         List<? extends DocTree> deprs = utils.getBlockTags(typeElement, DocTree.Kind.DEPRECATED);
 612         if (utils.isDeprecated(typeElement)) {
 613             Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(typeElement));
 614             Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprLabel);
 615             if (!deprs.isEmpty()) {
 616                 CommentHelper ch = utils.getCommentHelper(typeElement);
 617                 DocTree dt = deprs.get(0);
 618                 List<? extends DocTree> commentTags = ch.getBody(configuration, dt);
 619                 if (!commentTags.isEmpty()) {
 620                     addInlineDeprecatedComment(typeElement, deprs.get(0), div);
 621                 }
 622             }
 623             classInfoTree.addContent(div);
 624         }
 625     }
 626 
 627     /**
 628      * Get links to the given classes.
 629      *
 630      * @param context the id of the context where the link will be printed
 631      * @param list the list of classes
 632      * @return a content tree for the class list
 633      */
 634     private Content getClassLinks(LinkInfoImpl.Kind context, Collection<?> list) {
 635         Content dd = new HtmlTree(HtmlTag.DD);
 636         boolean isFirst = true;
 637         for (Object type : list) {
 638             if (!isFirst) {
 639                 Content separator = new StringContent(", ");
 640                 dd.addContent(separator);
 641             } else {
 642                 isFirst = false;
 643             }
 644             // TODO: should we simply split this method up to avoid instanceof ?
 645             if (type instanceof TypeElement) {
 646                 Content link = getLink(
 647                         new LinkInfoImpl(configuration, context, (TypeElement)(type)));
 648                 dd.addContent(HtmlTree.CODE(link));
 649             } else {
 650                 Content link = getLink(
 651                         new LinkInfoImpl(configuration, context, ((TypeMirror)type)));
 652                 dd.addContent(HtmlTree.CODE(link));
 653             }
 654         }
 655         return dd;
 656     }
 657 
 658     /**
 659      * {@inheritDoc}
 660      */
 661     @Override
 662     protected Content getNavLinkTree() {
 663         Content treeLinkContent = links.createLink(DocPaths.PACKAGE_TREE,
 664                 contents.treeLabel, "", "");
 665         Content li = HtmlTree.LI(treeLinkContent);
 666         return li;
 667     }
 668 
 669     /**
 670      * Add summary details to the navigation bar.
 671      *
 672      * @param subDiv the content tree to which the summary detail links will be added
 673      */
 674     @Override
 675     protected void addSummaryDetailLinks(Content subDiv) {
 676         Content div = HtmlTree.DIV(getNavSummaryLinks());
 677         div.addContent(getNavDetailLinks());
 678         subDiv.addContent(div);
 679     }
 680 
 681     /**
 682      * Get summary links for navigation bar.
 683      *
 684      * @return the content tree for the navigation summary links
 685      */
 686     protected Content getNavSummaryLinks() {
 687         Content li = HtmlTree.LI(contents.summaryLabel);
 688         li.addContent(Contents.SPACE);
 689         Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
 690         MemberSummaryBuilder memberSummaryBuilder =
 691                 configuration.getBuilderFactory().getMemberSummaryBuilder(this);
 692         for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.summarySet) {
 693             Content liNav = new HtmlTree(HtmlTag.LI);
 694             if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !utils.isEnum(typeElement)) {
 695                 continue;
 696             }
 697             if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && utils.isEnum(typeElement)) {
 698                 continue;
 699             }
 700             AbstractMemberWriter writer =
 701                 ((AbstractMemberWriter) memberSummaryBuilder.getMemberSummaryWriter(kind));
 702             if (writer == null) {
 703                 liNav.addContent(contents.getContent(VisibleMemberMap.Kind.getNavLinkLabels(kind)));
 704             } else {
 705                 writer.addNavSummaryLink(
 706                         memberSummaryBuilder.members(kind),
 707                         memberSummaryBuilder.getVisibleMemberMap(kind), liNav);
 708             }
 709             if (kind != Kind.METHODS) {
 710                 addNavGap(liNav);
 711             }
 712             ulNav.addContent(liNav);
 713         }
 714         return ulNav;
 715     }
 716 
 717     /**
 718      * Get detail links for the navigation bar.
 719      *
 720      * @return the content tree for the detail links
 721      */
 722     protected Content getNavDetailLinks() {
 723         Content li = HtmlTree.LI(contents.detailLabel);
 724         li.addContent(Contents.SPACE);
 725         Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
 726         MemberSummaryBuilder memberSummaryBuilder =
 727                 configuration.getBuilderFactory().getMemberSummaryBuilder(this);
 728         for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.detailSet) {
 729             Content liNav = new HtmlTree(HtmlTag.LI);
 730             AbstractMemberWriter writer =
 731                     ((AbstractMemberWriter) memberSummaryBuilder.
 732                     getMemberSummaryWriter(kind));
 733             if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !utils.isEnum(typeElement)) {
 734                 continue;
 735             }
 736             if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && utils.isEnum(typeElement)) {
 737                 continue;
 738             }
 739             if (writer == null) {
 740                 liNav.addContent(contents.getContent(VisibleMemberMap.Kind.getNavLinkLabels(kind)));
 741             } else {
 742                 writer.addNavDetailLink(memberSummaryBuilder.members(kind), liNav);
 743             }
 744             if (kind != Kind.METHODS) {
 745                 addNavGap(liNav);
 746             }
 747             ulNav.addContent(liNav);
 748         }
 749         return ulNav;
 750     }
 751 
 752     /**
 753      * Return the TypeElement being documented.
 754      *
 755      * @return the TypeElement being documented.
 756      */
 757     @Override
 758     public TypeElement getTypeElement() {
 759         return typeElement;
 760     }
 761 }