1 /* 2 * Copyright (c) 2003, 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.util; 27 28 import java.util.*; 29 30 import com.sun.javadoc.*; 31 import com.sun.tools.doclets.internal.toolkit.Configuration; 32 import com.sun.tools.doclets.internal.toolkit.taglets.*; 33 34 /** 35 * Search for the requested documentation. Inherit documentation if necessary. 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.5 44 */ 45 public class DocFinder { 46 47 /** 48 * The class that encapsulates the input. 49 */ 50 public static class Input { 51 /** 52 * The element to search documentation from. 53 */ 54 public ProgramElementDoc element; 55 /** 56 * The taglet to search for documentation on behalf of. Null if we want 57 * to search for overall documentation. 58 */ 59 public InheritableTaglet taglet = null; 60 61 /** 62 * The id of the tag to retrieve documentation for. 63 */ 64 public String tagId = null; 65 66 /** 67 * The tag to retrieve documentation for. This is only used for the 68 * inheritDoc tag. 69 */ 70 public Tag tag = null; 71 72 /** 73 * True if we only want to search for the first sentence. 74 */ 75 public boolean isFirstSentence = false; 76 77 /** 78 * True if we are looking for documentation to replace the inheritDocTag. 79 */ 80 public boolean isInheritDocTag = false; 81 82 /** 83 * Used to distinguish between type variable param tags and regular 84 * param tags. 85 */ 86 public boolean isTypeVariableParamTag = false; 87 88 public Input(ProgramElementDoc element, InheritableTaglet taglet, Tag tag, 89 boolean isFirstSentence, boolean isInheritDocTag) { 90 this(element); 91 this.taglet = taglet; 92 this.tag = tag; 93 this.isFirstSentence = isFirstSentence; 94 this.isInheritDocTag = isInheritDocTag; 95 } 96 97 public Input(ProgramElementDoc element, InheritableTaglet taglet, String tagId) { 98 this(element); 99 this.taglet = taglet; 100 this.tagId = tagId; 101 } 102 103 public Input(ProgramElementDoc element, InheritableTaglet taglet, String tagId, 104 boolean isTypeVariableParamTag) { 105 this(element); 106 this.taglet = taglet; 107 this.tagId = tagId; 108 this.isTypeVariableParamTag = isTypeVariableParamTag; 109 } 110 111 public Input(ProgramElementDoc element, InheritableTaglet taglet) { 112 this(element); 113 this.taglet = taglet; 114 } 115 116 public Input(ProgramElementDoc element) { 117 if (element == null) 118 throw new NullPointerException(); 119 this.element = element; 120 } 121 122 public Input(ProgramElementDoc element, boolean isFirstSentence) { 123 this(element); 124 this.isFirstSentence = isFirstSentence; 125 } 126 127 public Input copy() { 128 Input clone = new Input(this.element); 129 clone.taglet = this.taglet; 130 clone.tagId = this.tagId; 131 clone.tag = this.tag; 132 clone.isFirstSentence = this.isFirstSentence; 133 clone.isInheritDocTag = this.isInheritDocTag; 134 clone.isTypeVariableParamTag = this.isTypeVariableParamTag; 135 if (clone.element == null) 136 throw new NullPointerException(); 137 return clone; 138 139 } 140 } 141 142 /** 143 * The class that encapsulates the output. 144 */ 145 public static class Output { 146 /** 147 * The tag that holds the documentation. Null if documentation 148 * is not held by a tag. 149 */ 150 public Tag holderTag; 151 152 /** 153 * The Doc object that holds the documentation. 154 */ 155 public Doc holder; 156 157 /** 158 * The inherited documentation. 159 */ 160 public Tag[] inlineTags = new Tag[] {}; 161 162 /** 163 * False if documentation could not be inherited. 164 */ 165 public boolean isValidInheritDocTag = true; 166 167 /** 168 * When automatically inheriting throws tags, you sometime must inherit 169 * more than one tag. For example if the element declares that it throws 170 * IOException and the overridden element has throws tags for IOException and 171 * ZipException, both tags would be inherited because ZipException is a 172 * subclass of IOException. This subclass of DocFinder.Output allows 173 * multiple tag inheritence. 174 */ 175 public List<Tag> tagList = new ArrayList<>(); 176 } 177 178 /** 179 * Search for the requested comments in the given element. If it does not 180 * have comments, return documentation from the overriden element if possible. 181 * If the overriden element does not exist or does not have documentation to 182 * inherit, search for documentation to inherit from implemented methods. 183 * 184 * @param input the input object used to perform the search. 185 * 186 * @return an Output object representing the documentation that was found. 187 */ 188 public static Output search(Configuration configuration, Input input) { 189 Output output = new Output(); 190 if (input.isInheritDocTag) { 191 //Do nothing because "element" does not have any documentation. 192 //All it has it {@inheritDoc}. 193 } else if (input.taglet == null) { 194 //We want overall documentation. 195 output.inlineTags = input.isFirstSentence ? 196 input.element.firstSentenceTags() : 197 input.element.inlineTags(); 198 output.holder = input.element; 199 } else { 200 input.taglet.inherit(input, output); 201 } 202 203 if (output.inlineTags != null && output.inlineTags.length > 0) { 204 return output; 205 } 206 output.isValidInheritDocTag = false; 207 Input inheritedSearchInput = input.copy(); 208 inheritedSearchInput.isInheritDocTag = false; 209 if (input.element instanceof MethodDoc) { 210 MethodDoc overriddenMethod = ((MethodDoc) input.element).overriddenMethod(); 211 if (overriddenMethod != null) { 212 inheritedSearchInput.element = overriddenMethod; 213 output = search(configuration, inheritedSearchInput); 214 output.isValidInheritDocTag = true; 215 if (output.inlineTags.length > 0) { 216 return output; 217 } 218 } 219 //NOTE: When we fix the bug where ClassDoc.interfaceTypes() does 220 // not pass all implemented interfaces, we will use the 221 // appropriate element here. 222 MethodDoc[] implementedMethods = 223 (new ImplementedMethods((MethodDoc) input.element, configuration)).build(false); 224 for (MethodDoc implementedMethod : implementedMethods) { 225 inheritedSearchInput.element = implementedMethod; 226 output = search(configuration, inheritedSearchInput); 227 output.isValidInheritDocTag = true; 228 if (output.inlineTags.length > 0) { 229 return output; 230 } 231 } 232 } else if (input.element instanceof ClassDoc) { 233 ProgramElementDoc superclass = ((ClassDoc) input.element).superclass(); 234 if (superclass != null) { 235 inheritedSearchInput.element = superclass; 236 output = search(configuration, inheritedSearchInput); 237 output.isValidInheritDocTag = true; 238 if (output.inlineTags.length > 0) { 239 return output; 240 } 241 } 242 } 243 return output; 244 } 245 }