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