1 /*
   2  * Copyright (c) 1997, 2019, 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.Collection;
  29 import java.util.List;
  30 import java.util.Set;
  31 import java.util.SortedSet;
  32 import java.util.TreeSet;
  33 
  34 import javax.lang.model.element.AnnotationMirror;
  35 import javax.lang.model.element.Element;
  36 import javax.lang.model.element.ModuleElement;
  37 import javax.lang.model.element.PackageElement;
  38 import javax.lang.model.element.RecordComponentElement;
  39 import javax.lang.model.element.TypeElement;
  40 import javax.lang.model.type.TypeMirror;
  41 import javax.lang.model.util.SimpleElementVisitor8;
  42 
  43 import com.sun.source.doctree.DocTree;
  44 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
  45 import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
  46 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
  47 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
  48 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
  49 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
  50 import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
  51 import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
  52 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
  53 import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
  54 import jdk.javadoc.internal.doclets.toolkit.Content;
  55 import jdk.javadoc.internal.doclets.toolkit.taglets.ParamTaglet;
  56 import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
  57 import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
  58 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
  59 import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
  60 import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
  61 
  62 /**
  63  * Generate the Class Information Page.
  64  *
  65  *  <p><b>This is NOT part of any supported API.
  66  *  If you write code that depends on this, you do so at your own risk.
  67  *  This code and its internal interfaces are subject to change or
  68  *  deletion without notice.</b>
  69  *
  70  * @see javax.lang.model.element.TypeElement
  71  * @see java.util.Collections
  72  * @see java.util.List
  73  * @see java.util.ArrayList
  74  * @see java.util.HashMap
  75  *
  76  * @author Atul M Dambalkar
  77  * @author Robert Field
  78  * @author Bhavesh Patel (Modified)
  79  */
  80 public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWriter {
  81 
  82     private static final Set<String> suppressSubtypesSet
  83             = Set.of("java.lang.Object",
  84                      "org.omg.CORBA.Object");
  85 
  86     private static final Set<String> suppressImplementingSet
  87             = Set.of( "java.lang.Cloneable",
  88                     "java.lang.constant.Constable",
  89                     "java.lang.constant.ConstantDesc",
  90                     "java.io.Serializable");
  91 
  92     protected final TypeElement typeElement;
  93 
  94     protected final ClassTree classtree;
  95 
  96     private final Navigation navBar;
  97 
  98     /**
  99      * @param configuration the configuration data for the doclet
 100      * @param typeElement the class being documented.
 101      * @param classTree the class tree for the given class.
 102      */
 103     public ClassWriterImpl(HtmlConfiguration configuration, TypeElement typeElement,
 104                            ClassTree classTree) {
 105         super(configuration, configuration.docPaths.forClass(typeElement));
 106         this.typeElement = typeElement;
 107         configuration.currentTypeElement = typeElement;
 108         this.classtree = classTree;
 109         this.navBar = new Navigation(typeElement, configuration, fixedNavDiv, PageMode.CLASS, path);
 110     }
 111 
 112     /**
 113      * {@inheritDoc}
 114      */
 115     @Override
 116     public Content getHeader(String header) {
 117         HtmlTree bodyTree = getBody(getWindowTitle(utils.getSimpleName(typeElement)));
 118         HtmlTree htmlTree = HtmlTree.HEADER();
 119         addTop(htmlTree);
 120         Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(typeElement),
 121                 contents.moduleLabel);
 122         navBar.setNavLinkModule(linkContent);
 123         navBar.setMemberSummaryBuilder(configuration.getBuilderFactory().getMemberSummaryBuilder(this));
 124         navBar.setUserHeader(getUserHeaderFooter(true));
 125         htmlTree.add(navBar.getContent(true));
 126         bodyTree.add(htmlTree);
 127         bodyTree.add(MarkerComments.START_OF_CLASS_DATA);
 128         HtmlTree div = new HtmlTree(HtmlTag.DIV);
 129         div.setStyle(HtmlStyle.header);
 130         if (configuration.showModules) {
 131             ModuleElement mdle = configuration.docEnv.getElementUtils().getModuleOf(typeElement);
 132             Content classModuleLabel = HtmlTree.SPAN(HtmlStyle.moduleLabelInType, contents.moduleLabel);
 133             Content moduleNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, classModuleLabel);
 134             moduleNameDiv.add(Entity.NO_BREAK_SPACE);
 135             moduleNameDiv.add(getModuleLink(mdle,
 136                     new StringContent(mdle.getQualifiedName())));
 137             div.add(moduleNameDiv);
 138         }
 139         PackageElement pkg = utils.containingPackage(typeElement);
 140         if (!pkg.isUnnamed()) {
 141             Content classPackageLabel = HtmlTree.SPAN(HtmlStyle.packageLabelInType, contents.packageLabel);
 142             Content pkgNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, classPackageLabel);
 143             pkgNameDiv.add(Entity.NO_BREAK_SPACE);
 144             Content pkgNameContent = getPackageLink(pkg,
 145                     new StringContent(utils.getPackageName(pkg)));
 146             pkgNameDiv.add(pkgNameContent);
 147             div.add(pkgNameDiv);
 148         }
 149         LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
 150                 LinkInfoImpl.Kind.CLASS_HEADER, typeElement);
 151         //Let's not link to ourselves in the header.
 152         linkInfo.linkToSelf = false;
 153         Content headerContent = new StringContent(header);
 154         Content heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, true,
 155                 HtmlStyle.title, headerContent);
 156         heading.add(getTypeParameterLinks(linkInfo));
 157         div.add(heading);
 158         mainTree.add(div);
 159         return bodyTree;
 160     }
 161 
 162     /**
 163      * {@inheritDoc}
 164      */
 165     @Override
 166     public Content getClassContentHeader() {
 167         return getContentHeader();
 168     }
 169 
 170     /**
 171      * {@inheritDoc}
 172      */
 173     @Override
 174     public void addFooter(Content contentTree) {
 175         contentTree.add(MarkerComments.END_OF_CLASS_DATA);
 176         Content htmlTree = HtmlTree.FOOTER();
 177         navBar.setUserFooter(getUserHeaderFooter(false));
 178         htmlTree.add(navBar.getContent(false));
 179         addBottom(htmlTree);
 180         contentTree.add(htmlTree);
 181     }
 182 
 183     /**
 184      * {@inheritDoc}
 185      */
 186     @Override
 187     public void printDocument(Content contentTree) throws DocFileIOException {
 188         String description = getDescription("declaration", typeElement);
 189         PackageElement pkg = utils.containingPackage(typeElement);
 190         List<DocPath> localStylesheets = getLocalStylesheets(pkg);
 191         printHtmlDocument(configuration.metakeywords.getMetaKeywords(typeElement),
 192                 description, localStylesheets, contentTree);
 193     }
 194 
 195     /**
 196      * {@inheritDoc}
 197      */
 198     @Override
 199     public Content getClassInfoTreeHeader() {
 200         return getMemberTreeHeader();
 201     }
 202 
 203     /**
 204      * {@inheritDoc}
 205      */
 206     @Override
 207     public Content getClassInfo(Content classInfoTree) {
 208         return getMemberTree(HtmlStyle.description, classInfoTree);
 209     }
 210 
 211     /**
 212      * {@inheritDoc}
 213      */
 214     @Override @SuppressWarnings("preview")
 215     public void addClassSignature(String modifiers, Content classInfoTree) {
 216         Content hr = new HtmlTree(HtmlTag.HR);
 217         classInfoTree.add(hr);
 218         Content pre = new HtmlTree(HtmlTag.PRE);
 219         addAnnotationInfo(typeElement, pre);
 220         pre.add(modifiers);
 221         LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
 222                 LinkInfoImpl.Kind.CLASS_SIGNATURE, typeElement);
 223         //Let's not link to ourselves in the signature.
 224         linkInfo.linkToSelf = false;
 225         Content className = new StringContent(utils.getSimpleName(typeElement));
 226         Content parameterLinks = getTypeParameterLinks(linkInfo);
 227         if (configuration.linksource) {
 228             addSrcLink(typeElement, className, pre);
 229             pre.add(parameterLinks);
 230         } else {
 231             Content span = HtmlTree.SPAN(HtmlStyle.typeNameLabel, className);
 232             span.add(parameterLinks);
 233             pre.add(span);
 234         }
 235         if (utils.isRecord(typeElement)) {
 236             pre.add(getRecordComponents(typeElement));
 237         }
 238         if (!utils.isInterface(typeElement)) {
 239             TypeMirror superclass = utils.getFirstVisibleSuperClass(typeElement);
 240             if (superclass != null) {
 241                 pre.add(DocletConstants.NL);
 242                 pre.add("extends ");
 243                 Content link = getLink(new LinkInfoImpl(configuration,
 244                         LinkInfoImpl.Kind.CLASS_SIGNATURE_PARENT_NAME,
 245                         superclass));
 246                 pre.add(link);
 247             }
 248         }
 249         List<? extends TypeMirror> interfaces = typeElement.getInterfaces();
 250         if (!interfaces.isEmpty()) {
 251             boolean isFirst = true;
 252             for (TypeMirror type : interfaces) {
 253                 TypeElement tDoc = utils.asTypeElement(type);
 254                 if (!(utils.isPublic(tDoc) || utils.isLinkable(tDoc))) {
 255                     continue;
 256                 }
 257                 if (isFirst) {
 258                     pre.add(DocletConstants.NL);
 259                     pre.add(utils.isInterface(typeElement) ? "extends " : "implements ");
 260                     isFirst = false;
 261                 } else {
 262                     pre.add(", ");
 263                 }
 264                 Content link = getLink(new LinkInfoImpl(configuration,
 265                                                         LinkInfoImpl.Kind.CLASS_SIGNATURE_PARENT_NAME,
 266                                                         type));
 267                 pre.add(link);
 268             }
 269         }
 270         classInfoTree.add(pre);
 271     }
 272 
 273     @SuppressWarnings("preview")
 274     private Content getRecordComponents(TypeElement typeElem) {
 275         Content content = new ContentBuilder();
 276         content.add("(");
 277         String sep = "";
 278         for (RecordComponentElement e : typeElement.getRecordComponents()) {
 279             content.add(sep);
 280             getAnnotations(e.getAnnotationMirrors(), false).stream()
 281                     .forEach(a -> { content.add(a); content.add(" "); });
 282             Content link = getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.RECORD_COMPONENT,
 283                     e.asType()));
 284             content.add(link);
 285             content.add(Entity.NO_BREAK_SPACE);
 286             content.add(e.getSimpleName());
 287             sep = ", ";
 288         }
 289         content.add(")");
 290         return content;
 291     }
 292 
 293     /**
 294      * {@inheritDoc}
 295      */
 296     @Override
 297     public void addClassDescription(Content classInfoTree) {
 298         if(!configuration.nocomment) {
 299             // generate documentation for the class.
 300             if (!utils.getFullBody(typeElement).isEmpty()) {
 301                 addInlineComment(typeElement, classInfoTree);
 302             }
 303         }
 304     }
 305 
 306     /**
 307      * {@inheritDoc}
 308      */
 309     @Override
 310     public void addClassTagInfo(Content classInfoTree) {
 311         if(!configuration.nocomment) {
 312             // Print Information about all the tags here
 313             addTagsInfo(typeElement, classInfoTree);
 314         }
 315     }
 316 
 317     /**
 318      * Get the class hierarchy tree for the given class.
 319      *
 320      * @param type the class to print the hierarchy for
 321      * @return a content tree for class inheritance
 322      */
 323     private Content getClassInheritanceTree(TypeMirror type) {
 324         TypeMirror sup;
 325         HtmlTree classTree = null;
 326         do {
 327             sup = utils.getFirstVisibleSuperClass(type);
 328             HtmlTree htmlElement = HtmlTree.DIV(HtmlStyle.inheritance, getTreeForClassHelper(type));
 329             if (classTree != null)
 330                 htmlElement.add(classTree);
 331             classTree = htmlElement;
 332             type = sup;
 333         } while (sup != null);
 334         classTree.put(HtmlAttr.TITLE, contents.getContent("doclet.Inheritance_Tree").toString());
 335         return classTree;
 336     }
 337 
 338     /**
 339      * Get the class helper tree for the given class.
 340      *
 341      * @param type the class to print the helper for
 342      * @return a content tree for class helper
 343      */
 344     private Content getTreeForClassHelper(TypeMirror type) {
 345         Content content = new ContentBuilder();
 346         if (type.equals(typeElement.asType())) {
 347             Content typeParameters = getTypeParameterLinks(
 348                     new LinkInfoImpl(configuration, LinkInfoImpl.Kind.TREE,
 349                     typeElement));
 350             if (configuration.shouldExcludeQualifier(utils.containingPackage(typeElement).toString())) {
 351                 content.add(utils.asTypeElement(type).getSimpleName());
 352                 content.add(typeParameters);
 353             } else {
 354                 content.add(utils.asTypeElement(type).getQualifiedName());
 355                 content.add(typeParameters);
 356             }
 357         } else {
 358             Content link = getLink(new LinkInfoImpl(configuration,
 359                     LinkInfoImpl.Kind.CLASS_TREE_PARENT, type)
 360                     .label(configuration.getClassName(utils.asTypeElement(type))));
 361             content.add(link);
 362         }
 363         return content;
 364     }
 365 
 366     /**
 367      * {@inheritDoc}
 368      */
 369     @Override
 370     public void addClassTree(Content classContentTree) {
 371         if (!utils.isClass(typeElement)) {
 372             return;
 373         }
 374         classContentTree.add(getClassInheritanceTree(typeElement.asType()));
 375     }
 376 
 377     /**
 378      * {@inheritDoc}
 379      */
 380     @Override
 381     public void addParamInfo(Content classInfoTree) {
 382         if (utils.hasBlockTag(typeElement, DocTree.Kind.PARAM)) {
 383             Content paramInfo = (new ParamTaglet()).getTagletOutput(typeElement,
 384                     getTagletWriterInstance(false));
 385             if (!paramInfo.isEmpty()) {
 386                 classInfoTree.add(HtmlTree.DL(paramInfo));
 387             }
 388         }
 389     }
 390 
 391     /**
 392      * {@inheritDoc}
 393      */
 394     @Override
 395     public void addSubClassInfo(Content classInfoTree) {
 396         if (utils.isClass(typeElement)) {
 397             for (String s : suppressSubtypesSet) {
 398                 if (typeElement.getQualifiedName().contentEquals(s)) {
 399                     return;    // Don't generate the list, too huge
 400                 }
 401             }
 402             Set<TypeElement> subclasses = classtree.directSubClasses(typeElement, false);
 403             if (!subclasses.isEmpty()) {
 404                 Content label = contents.subclassesLabel;
 405                 Content dt = HtmlTree.DT(label);
 406                 Content dl = HtmlTree.DL(dt);
 407                 dl.add(getClassLinks(LinkInfoImpl.Kind.SUBCLASSES,
 408                         subclasses));
 409                 classInfoTree.add(dl);
 410             }
 411         }
 412     }
 413 
 414     /**
 415      * {@inheritDoc}
 416      */
 417     @Override
 418     public void addSubInterfacesInfo(Content classInfoTree) {
 419         if (utils.isInterface(typeElement)) {
 420             Set<TypeElement> subInterfaces = classtree.allSubClasses(typeElement, false);
 421             if (!subInterfaces.isEmpty()) {
 422                 Content label = contents.subinterfacesLabel;
 423                 Content dt = HtmlTree.DT(label);
 424                 Content dl = HtmlTree.DL(dt);
 425                 dl.add(getClassLinks(LinkInfoImpl.Kind.SUBINTERFACES,
 426                         subInterfaces));
 427                 classInfoTree.add(dl);
 428             }
 429         }
 430     }
 431 
 432     /**
 433      * {@inheritDoc}
 434      */
 435     @Override
 436     public void addInterfaceUsageInfo (Content classInfoTree) {
 437         if (!utils.isInterface(typeElement)) {
 438             return;
 439         }
 440         for (String s : suppressImplementingSet) {
 441             if (typeElement.getQualifiedName().contentEquals(s)) {
 442                 return;    // Don't generate the list, too huge
 443             }
 444         }
 445         Set<TypeElement> implcl = classtree.implementingClasses(typeElement);
 446         if (!implcl.isEmpty()) {
 447             Content label = contents.implementingClassesLabel;
 448             Content dt = HtmlTree.DT(label);
 449             Content dl = HtmlTree.DL(dt);
 450             dl.add(getClassLinks(LinkInfoImpl.Kind.IMPLEMENTED_CLASSES,
 451                     implcl));
 452             classInfoTree.add(dl);
 453         }
 454     }
 455 
 456     /**
 457      * {@inheritDoc}
 458      */
 459     @Override
 460     public void addImplementedInterfacesInfo(Content classInfoTree) {
 461         SortedSet<TypeMirror> interfaces = new TreeSet<>(utils.makeTypeMirrorClassUseComparator());
 462         interfaces.addAll(utils.getAllInterfaces(typeElement));
 463         if (utils.isClass(typeElement) && !interfaces.isEmpty()) {
 464             Content label = contents.allImplementedInterfacesLabel;
 465             Content dt = HtmlTree.DT(label);
 466             Content dl = HtmlTree.DL(dt);
 467             dl.add(getClassLinks(LinkInfoImpl.Kind.IMPLEMENTED_INTERFACES, interfaces));
 468             classInfoTree.add(dl);
 469         }
 470     }
 471 
 472     /**
 473      * {@inheritDoc}
 474      */
 475     @Override
 476     public void addSuperInterfacesInfo(Content classInfoTree) {
 477         SortedSet<TypeMirror> interfaces =
 478                 new TreeSet<>(utils.makeTypeMirrorIndexUseComparator());
 479         interfaces.addAll(utils.getAllInterfaces(typeElement));
 480 
 481         if (utils.isInterface(typeElement) && !interfaces.isEmpty()) {
 482             Content label = contents.allSuperinterfacesLabel;
 483             Content dt = HtmlTree.DT(label);
 484             Content dl = HtmlTree.DL(dt);
 485             dl.add(getClassLinks(LinkInfoImpl.Kind.SUPER_INTERFACES, interfaces));
 486             classInfoTree.add(dl);
 487         }
 488     }
 489 
 490     /**
 491      * {@inheritDoc}
 492      */
 493     @Override
 494     public void addNestedClassInfo(final Content classInfoTree) {
 495         Element outerClass = typeElement.getEnclosingElement();
 496         if (outerClass == null)
 497             return;
 498         new SimpleElementVisitor8<Void, Void>() {
 499             @Override
 500             public Void visitType(TypeElement e, Void p) {
 501                 Content label = utils.isInterface(e)
 502                         ? contents.enclosingInterfaceLabel
 503                         : contents.enclosingClassLabel;
 504                 Content dt = HtmlTree.DT(label);
 505                 Content dl = HtmlTree.DL(dt);
 506                 Content dd = new HtmlTree(HtmlTag.DD);
 507                 dd.add(getLink(new LinkInfoImpl(configuration,
 508                         LinkInfoImpl.Kind.CLASS, e)));
 509                 dl.add(dd);
 510                 classInfoTree.add(dl);
 511                 return null;
 512             }
 513         }.visit(outerClass);
 514     }
 515 
 516     /**
 517      * {@inheritDoc}
 518      */
 519     @Override
 520     public void addFunctionalInterfaceInfo (Content classInfoTree) {
 521         if (isFunctionalInterface()) {
 522             Content dt = HtmlTree.DT(contents.functionalInterface);
 523             Content dl = HtmlTree.DL(dt);
 524             Content dd = new HtmlTree(HtmlTag.DD);
 525             dd.add(contents.functionalInterfaceMessage);
 526             dl.add(dd);
 527             classInfoTree.add(dl);
 528         }
 529     }
 530 
 531     public boolean isFunctionalInterface() {
 532         List<? extends AnnotationMirror> annotationMirrors = ((Element) typeElement).getAnnotationMirrors();
 533         for (AnnotationMirror anno : annotationMirrors) {
 534             if (utils.isFunctionalInterface(anno)) {
 535                 return true;
 536             }
 537         }
 538         return false;
 539     }
 540 
 541 
 542     /**
 543      * {@inheritDoc}
 544      */
 545     @Override
 546     public void addClassDeprecationInfo(Content classInfoTree) {
 547         List<? extends DocTree> deprs = utils.getBlockTags(typeElement, DocTree.Kind.DEPRECATED);
 548         if (utils.isDeprecated(typeElement)) {
 549             Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(typeElement));
 550             Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprLabel);
 551             if (!deprs.isEmpty()) {
 552                 CommentHelper ch = utils.getCommentHelper(typeElement);
 553                 DocTree dt = deprs.get(0);
 554                 List<? extends DocTree> commentTags = ch.getBody(configuration, dt);
 555                 if (!commentTags.isEmpty()) {
 556                     addInlineDeprecatedComment(typeElement, deprs.get(0), div);
 557                 }
 558             }
 559             classInfoTree.add(div);
 560         }
 561     }
 562 
 563     /**
 564      * Get links to the given classes.
 565      *
 566      * @param context the id of the context where the link will be printed
 567      * @param list the list of classes
 568      * @return a content tree for the class list
 569      */
 570     private Content getClassLinks(LinkInfoImpl.Kind context, Collection<?> list) {
 571         Content dd = new HtmlTree(HtmlTag.DD);
 572         boolean isFirst = true;
 573         for (Object type : list) {
 574             if (!isFirst) {
 575                 Content separator = new StringContent(", ");
 576                 dd.add(separator);
 577             } else {
 578                 isFirst = false;
 579             }
 580             // TODO: should we simply split this method up to avoid instanceof ?
 581             if (type instanceof TypeElement) {
 582                 Content link = getLink(
 583                         new LinkInfoImpl(configuration, context, (TypeElement)(type)));
 584                 dd.add(HtmlTree.CODE(link));
 585             } else {
 586                 Content link = getLink(
 587                         new LinkInfoImpl(configuration, context, ((TypeMirror)type)));
 588                 dd.add(HtmlTree.CODE(link));
 589             }
 590         }
 591         return dd;
 592     }
 593 
 594     /**
 595      * Return the TypeElement being documented.
 596      *
 597      * @return the TypeElement being documented.
 598      */
 599     @Override
 600     public TypeElement getTypeElement() {
 601         return typeElement;
 602     }
 603 }