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 } |