src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ThrowsTaglet.java

Print this page


   1 /*
   2  * Copyright (c) 2001, 2014, 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 com.sun.tools.doclets.internal.toolkit.taglets;
  27 
  28 import java.util.*;

  29 
  30 import com.sun.javadoc.*;
  31 import com.sun.tools.doclets.internal.toolkit.Content;
  32 import com.sun.tools.doclets.internal.toolkit.util.*;

  33 









  34 /**
  35  * A taglet that represents the @throws tag.
  36  *
  37  *  <p><b>This is NOT part of any supported API.
  38  *  If you write code that depends on this, you do so at your own risk.
  39  *  This code and its internal interfaces are subject to change or
  40  *  deletion without notice.</b>
  41  *
  42  * @author Jamie Ho
  43  * @since 1.4
  44  */
  45 public class ThrowsTaglet extends BaseExecutableMemberTaglet
  46     implements InheritableTaglet {
  47 
  48     public ThrowsTaglet() {
  49         name = "throws";
  50     }
  51 
  52     /**
  53      * {@inheritDoc}
  54      */

  55     public void inherit(DocFinder.Input input, DocFinder.Output output) {
  56         ClassDoc exception;


  57         if (input.tagId == null) {
  58             ThrowsTag throwsTag = (ThrowsTag) input.tag;
  59             exception = throwsTag.exception();
  60             input.tagId = exception == null ?
  61                 throwsTag.exceptionName() :
  62                 throwsTag.exception().qualifiedName();
  63         } else {
  64             exception = input.element.containingClass().findClass(input.tagId);

  65         }
  66 
  67         for (ThrowsTag tag : ((MethodDoc)input.element).throwsTags()) {
  68             if (input.tagId.equals(tag.exceptionName()) ||
  69                 (tag.exception() != null &&
  70                  (input.tagId.equals(tag.exception().qualifiedName())))) {
  71                 output.holder = input.element;
  72                 output.holderTag = tag;
  73                 output.inlineTags = input.isFirstSentence ?
  74                                     tag.firstSentenceTags() : tag.inlineTags();
  75                 output.tagList.add(tag);
  76             } else if (exception != null && tag.exception() != null &&
  77                      tag.exception().subclassOf(exception)) {
  78                 output.tagList.add(tag);
  79             }
  80         }
  81     }
  82 
  83     /**
  84      * Add links for exceptions that are declared but not documented.
  85      */
  86     private Content linkToUndocumentedDeclaredExceptions(
  87             Type[] declaredExceptionTypes, Set<String> alreadyDocumented,
  88             TagletWriter writer) {
  89         Content result = writer.getOutputInstance();
  90         //Add links to the exceptions declared but not documented.
  91         for (Type declaredExceptionType : declaredExceptionTypes) {
  92             if (declaredExceptionType.asClassDoc() != null &&
  93                 !alreadyDocumented.contains(
  94                         declaredExceptionType.asClassDoc().name()) &&
  95                 !alreadyDocumented.contains(
  96                         declaredExceptionType.asClassDoc().qualifiedName())) {
  97                 if (alreadyDocumented.size() == 0) {
  98                     result.addContent(writer.getThrowsHeader());
  99                 }
 100                 result.addContent(writer.throwsTagOutput(declaredExceptionType));
 101                 alreadyDocumented.add(declaredExceptionType.asClassDoc().name());
 102             }
 103         }
 104         return result;
 105     }
 106 
 107     /**
 108      * Inherit throws documentation for exceptions that were declared but not
 109      * documented.
 110      */
 111     private Content inheritThrowsDocumentation(Doc holder,
 112             Type[] declaredExceptionTypes, Set<String> alreadyDocumented,
 113             TagletWriter writer) {

 114         Content result = writer.getOutputInstance();
 115         if (holder instanceof MethodDoc) {
 116             Set<Tag> declaredExceptionTags = new LinkedHashSet<>();
 117             for (Type declaredExceptionType : declaredExceptionTypes) {
 118                 DocFinder.Output inheritedDoc =
 119                         DocFinder.search(writer.configuration(), new DocFinder.Input((MethodDoc) holder, this,
 120                                                              declaredExceptionType.typeName()));
 121                 if (inheritedDoc.tagList.size() == 0) {
 122                     inheritedDoc = DocFinder.search(writer.configuration(), new DocFinder.Input(
 123                             (MethodDoc) holder, this,
 124                             declaredExceptionType.qualifiedTypeName()));
 125                 }
 126                 declaredExceptionTags.addAll(inheritedDoc.tagList);


 127             }
 128             result.addContent(throwsTagsOutput(
 129                 declaredExceptionTags.toArray(new ThrowsTag[] {}),
 130                 writer, alreadyDocumented, false));
 131         }



 132         return result;
 133     }
 134 
 135     /**
 136      * {@inheritDoc}
 137      */
 138     public Content getTagletOutput(Doc holder, TagletWriter writer) {
 139         ExecutableMemberDoc execHolder = (ExecutableMemberDoc) holder;
 140         ThrowsTag[] tags = execHolder.throwsTags();


 141         Content result = writer.getOutputInstance();
 142         HashSet<String> alreadyDocumented = new HashSet<>();
 143         if (tags.length > 0) {
 144             result.addContent(throwsTagsOutput(
 145                 execHolder.throwsTags(), writer, alreadyDocumented, true));
 146         }
 147         result.addContent(inheritThrowsDocumentation(holder,
 148             execHolder.thrownExceptionTypes(), alreadyDocumented, writer));
 149         result.addContent(linkToUndocumentedDeclaredExceptions(
 150             execHolder.thrownExceptionTypes(), alreadyDocumented, writer));
 151         return result;
 152     }
 153 
 154 
 155     /**
 156      * Given an array of <code>Tag</code>s representing this custom
 157      * tag, return its string representation.
 158      * @param throwTags the array of <code>ThrowsTag</code>s to convert.
 159      * @param writer the TagletWriter that will write this tag.
 160      * @param alreadyDocumented the set of exceptions that have already
 161      *        been documented.
 162      * @param allowDups True if we allow duplicate throws tags to be documented.
 163      * @return the Content representation of this <code>Tag</code>.
 164      */
 165     protected Content throwsTagsOutput(ThrowsTag[] throwTags,
 166         TagletWriter writer, Set<String> alreadyDocumented, boolean allowDups) {

 167         Content result = writer.getOutputInstance();
 168         if (throwTags.length > 0) {
 169             for (ThrowsTag tt : throwTags) {
 170                 ClassDoc cd = tt.exception();
 171                 if ((!allowDups) && (alreadyDocumented.contains(tt.exceptionName()) ||
 172                                      (cd != null && alreadyDocumented.contains(cd.qualifiedName())))) {





 173                     continue;
 174                 }
 175                 if (alreadyDocumented.size() == 0) {
 176                     result.addContent(writer.getThrowsHeader());
 177                 }
 178                 result.addContent(writer.throwsTagOutput(tt));
 179                 alreadyDocumented.add(cd != null ?
 180                                       cd.qualifiedName() : tt.exceptionName());

 181             }
 182         }

 183         return result;
 184     }
 185 }
   1 /*
   2  * Copyright (c) 2001, 2015, 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.toolkit.taglets;
  27 
  28 import java.util.*;
  29 import java.util.Map.Entry;
  30 
  31 import javax.lang.model.element.Element;
  32 import javax.lang.model.element.ExecutableElement;
  33 import javax.lang.model.element.TypeElement;
  34 import javax.lang.model.type.TypeMirror;
  35 
  36 import com.sun.source.doctree.DocTree;
  37 import jdk.javadoc.internal.doclets.toolkit.Content;
  38 import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
  39 import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
  40 import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Input;
  41 import jdk.javadoc.internal.doclets.toolkit.util.Utils;
  42 
  43 import static com.sun.source.doctree.DocTree.Kind.*;
  44 
  45 /**
  46  * A taglet that represents the @throws tag.
  47  *
  48  *  <p><b>This is NOT part of any supported API.
  49  *  If you write code that depends on this, you do so at your own risk.
  50  *  This code and its internal interfaces are subject to change or
  51  *  deletion without notice.</b>
  52  *
  53  * @author Jamie Ho
  54  * @since 1.4
  55  */
  56 public class ThrowsTaglet extends BaseExecutableMemberTaglet
  57     implements InheritableTaglet {
  58 
  59     public ThrowsTaglet() {
  60         name = THROWS.tagName;
  61     }
  62 
  63     /**
  64      * {@inheritDoc}
  65      */
  66     @Override
  67     public void inherit(DocFinder.Input input, DocFinder.Output output) {
  68         Utils utils = input.utils;
  69         Element exception;
  70         CommentHelper ch = utils.getCommentHelper(input.element);
  71         if (input.tagId == null) {
  72             exception = ch.getException(utils.configuration, input.docTreeInfo.docTree);
  73             input.tagId = exception == null
  74                     ? ch.getExceptionName(input.docTreeInfo.docTree).getSignature()
  75                     : utils.getFullyQualifiedName(exception);

  76         } else {
  77             TypeElement element = input.utils.findClass(input.element, input.tagId);
  78             exception = (element == null) ? null : element;
  79         }
  80 
  81         for (DocTree dt : input.utils.getThrowsTrees(input.element)) {
  82             Element texception = ch.getException(utils.configuration, dt);
  83             if (texception != null && (input.tagId.equals(utils.getSimpleName(texception)) ||
  84                  (input.tagId.equals(utils.getFullyQualifiedName(texception))))) {
  85                 output.holder = input.element;
  86                 output.holderTag = dt;
  87                 output.inlineTags = ch.getBody(input.utils.configuration, output.holderTag);
  88                 output.tagList.add(dt);
  89             } else if (exception != null && texception != null &&
  90                     utils.isTypeElement(texception) && utils.isTypeElement(exception) &&
  91                     utils.isSubclassOf((TypeElement)texception, (TypeElement)exception)) {
  92                 output.tagList.add(dt);
  93             }
  94         }
  95     }
  96 
  97     /**
  98      * Add links for exceptions that are declared but not documented.
  99      */
 100     private Content linkToUndocumentedDeclaredExceptions(List<? extends TypeMirror> declaredExceptionTypes,
 101             Set<String> alreadyDocumented, TagletWriter writer) {
 102         Utils utils = writer.configuration().utils;
 103         Content result = writer.getOutputInstance();
 104         //Add links to the exceptions declared but not documented.
 105         for (TypeMirror declaredExceptionType : declaredExceptionTypes) {
 106             TypeElement klass = utils.asTypeElement(declaredExceptionType);
 107             if (klass != null &&
 108                 !alreadyDocumented.contains(utils.getSimpleName(klass)) &&
 109                 !alreadyDocumented.contains(utils.getFullyQualifiedName(klass))) {
 110                 if (alreadyDocumented.isEmpty()) {

 111                     result.addContent(writer.getThrowsHeader());
 112                 }
 113                 result.addContent(writer.throwsTagOutput(declaredExceptionType));
 114                 alreadyDocumented.add(utils.getSimpleName(klass));
 115             }
 116         }
 117         return result;
 118     }
 119 
 120     /**
 121      * Inherit throws documentation for exceptions that were declared but not
 122      * documented.
 123      */
 124     private Content inheritThrowsDocumentation(Element holder,
 125             List<? extends TypeMirror> declaredExceptionTypes, Set<String> alreadyDocumented,
 126             TagletWriter writer) {
 127         Utils utils = writer.configuration().utils;
 128         Content result = writer.getOutputInstance();
 129         if (utils.isExecutableElement(holder)) {
 130             Map<List<? extends DocTree>, ExecutableElement> declaredExceptionTags = new LinkedHashMap<>();
 131             for (TypeMirror declaredExceptionType : declaredExceptionTypes) {
 132                 Input input = new DocFinder.Input(utils, holder, this,
 133                         utils.getTypeName(declaredExceptionType, false));
 134                 DocFinder.Output inheritedDoc = DocFinder.search(writer.configuration(), input);
 135                 if (inheritedDoc.tagList.isEmpty()) {
 136                     String typeName = utils.getTypeName(declaredExceptionType, true);
 137                     input = new DocFinder.Input(utils, holder, this, typeName);
 138                     inheritedDoc = DocFinder.search(writer.configuration(), input);
 139                 }
 140                 if (!inheritedDoc.tagList.isEmpty()) {
 141                     if (inheritedDoc.holder == null) {
 142                         inheritedDoc.holder = holder;
 143                     }
 144                     declaredExceptionTags.put(inheritedDoc.tagList, (ExecutableElement)inheritedDoc.holder);


 145                 }
 146             }
 147             result.addContent(throwsTagsOutput(declaredExceptionTags, writer, alreadyDocumented, false));
 148         }
 149         return result;
 150     }
 151 
 152     /**
 153      * {@inheritDoc}
 154      */
 155     public Content getTagletOutput(Element holder, TagletWriter writer) {
 156         Utils utils = writer.configuration().utils;
 157         ExecutableElement execHolder = (ExecutableElement) holder;
 158         Map<List<? extends DocTree>, ExecutableElement> tagsMap = new LinkedHashMap<>();
 159         tagsMap.put(utils.getThrowsTrees(execHolder), execHolder);
 160         Content result = writer.getOutputInstance();
 161         HashSet<String> alreadyDocumented = new HashSet<>();
 162         if (!tagsMap.isEmpty()) {
 163             result.addContent(throwsTagsOutput(tagsMap, writer, alreadyDocumented, true));

 164         }
 165         result.addContent(inheritThrowsDocumentation(holder,
 166             execHolder.getThrownTypes(), alreadyDocumented, writer));
 167         result.addContent(linkToUndocumentedDeclaredExceptions(
 168             execHolder.getThrownTypes(), alreadyDocumented, writer));
 169         return result;
 170     }
 171 

 172     /**
 173      * Given an array of <code>Tag</code>s representing this custom
 174      * tag, return its string representation.
 175      * @param throwTags the array of <code>ThrowsTag</code>s to convert.
 176      * @param writer the TagletWriter that will write this tag.
 177      * @param alreadyDocumented the set of exceptions that have already
 178      *        been documented.
 179      * @param allowDups True if we allow duplicate throws tags to be documented.
 180      * @return the Content representation of this <code>Tag</code>.
 181      */
 182     protected Content throwsTagsOutput(Map<List<? extends DocTree>, ExecutableElement> throwTags,
 183         TagletWriter writer, Set<String> alreadyDocumented, boolean allowDups) {
 184         Utils utils = writer.configuration().utils;
 185         Content result = writer.getOutputInstance();
 186         if (!throwTags.isEmpty()) {
 187             for (Entry<List<? extends DocTree>, ExecutableElement> entry : throwTags.entrySet()) {
 188                 CommentHelper ch = utils.getCommentHelper(entry.getValue());
 189                 Element e = entry.getValue();
 190                 for (DocTree dt : entry.getKey()) {
 191                     Element te = ch.getException(utils.configuration, dt);
 192                     String excName = ch.getExceptionName(dt).toString();
 193                     if ((!allowDups) &&
 194                         (alreadyDocumented.contains(excName) ||
 195                         (te != null && alreadyDocumented.contains(utils.getFullyQualifiedName(te))))) {
 196                         continue;
 197                     }
 198                     if (alreadyDocumented.isEmpty()) {
 199                         result.addContent(writer.getThrowsHeader());
 200                     }
 201                     result.addContent(writer.throwsTagOutput(e, dt));
 202                     alreadyDocumented.add(te != null
 203                             ? utils.getFullyQualifiedName(te)
 204                             : excName);
 205                 }
 206             }
 207         }
 208         return result;
 209     }
 210 }