1 /* 2 * Copyright (c) 1997, 2016, 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.javadoc; 27 28 import java.io.DataInputStream; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.text.CollationKey; 32 import java.util.regex.Matcher; 33 import java.util.regex.Pattern; 34 35 import javax.tools.FileObject; 36 37 import com.sun.javadoc.*; 38 import com.sun.source.util.TreePath; 39 import com.sun.tools.doclets.internal.toolkit.util.FatalError; 40 import com.sun.tools.javac.tree.JCTree; 41 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; 42 import com.sun.tools.javac.util.Position; 43 44 /** 45 * abstract base class of all Doc classes. Doc item's are representations 46 * of java language constructs (class, package, method,...) which have 47 * comments and have been processed by this run of javadoc. All Doc items 48 * are unique, that is, they are == comparable. 49 * 50 * <p><b>This is NOT part of any supported API. 51 * If you write code that depends on this, you do so at your own risk. 52 * This code and its internal interfaces are subject to change or 53 * deletion without notice.</b> 54 * 55 * @since 1.2 56 * @author Robert Field 57 * @author Atul M Dambalkar 58 * @author Neal Gafter (rewrite) 59 */ 60 public abstract class DocImpl implements Doc, Comparable<Object> { 61 62 /** 63 * Doc environment 64 */ 65 protected final DocEnv env; //### Rename this everywhere to 'docenv' ? 66 67 /** 68 * Back pointer to the tree node for this doc item. 69 * May be null if there is no associated tree. 70 */ 71 protected TreePath treePath; 72 73 /** 74 * The complex comment object, lazily initialized. 75 */ 76 private Comment comment; 77 78 /** 79 * The cached sort key, to take care of Natural Language Text sorting. 80 */ 81 private CollationKey collationkey = null; 82 83 /** 84 * Raw documentation string. 85 */ 86 protected String documentation; // Accessed in PackageDocImpl, RootDocImpl 87 88 /** 89 * Cached first sentence. 90 */ 91 private Tag[] firstSentence; 92 93 /** 94 * Cached inline tags. 95 */ 96 private Tag[] inlineTags; 97 98 /** 99 * Constructor. 100 */ DocImpl(DocEnv env, TreePath treePath)101 DocImpl(DocEnv env, TreePath treePath) { 102 this.treePath = treePath; 103 this.documentation = getCommentText(treePath); 104 this.env = env; 105 } 106 getCommentText(TreePath p)107 private static String getCommentText(TreePath p) { 108 if (p == null) 109 return null; 110 111 JCCompilationUnit topLevel = (JCCompilationUnit) p.getCompilationUnit(); 112 JCTree tree = (JCTree) p.getLeaf(); 113 return topLevel.docComments.getCommentText(tree); 114 } 115 116 /** 117 * So subclasses have the option to do lazy initialization of 118 * "documentation" string. 119 */ documentation()120 protected String documentation() { 121 if (documentation == null) documentation = ""; 122 return documentation; 123 } 124 125 /** 126 * For lazy initialization of comment. 127 */ comment()128 Comment comment() { 129 if (comment == null) { 130 String d = documentation(); 131 if (env.javaScriptScanner != null) { 132 env.javaScriptScanner.parse(d, new JavaScriptScanner.Reporter() { 133 @Override 134 public void report() { 135 env.error(DocImpl.this, "javadoc.JavaScript_in_comment"); 136 throw new FatalError(); 137 } 138 }); 139 } 140 if (env.doclint != null 141 && treePath != null 142 && d.equals(getCommentText(treePath))) { 143 env.doclint.scan(treePath); 144 } 145 comment = new Comment(this, d); 146 } 147 return comment; 148 } 149 150 /** 151 * Return the text of the comment for this doc item. 152 * TagImpls have been removed. 153 */ commentText()154 public String commentText() { 155 return comment().commentText(); 156 } 157 158 /** 159 * Return all tags in this Doc item. 160 * 161 * @return an array of TagImpl containing all tags on this Doc item. 162 */ tags()163 public Tag[] tags() { 164 return comment().tags(); 165 } 166 167 /** 168 * Return tags of the specified kind in this Doc item. 169 * 170 * @param tagname name of the tag kind to search for. 171 * @return an array of TagImpl containing all tags whose 'kind()' 172 * matches 'tagname'. 173 */ tags(String tagname)174 public Tag[] tags(String tagname) { 175 return comment().tags(tagname); 176 } 177 178 /** 179 * Return the see also tags in this Doc item. 180 * 181 * @return an array of SeeTag containing all @see tags. 182 */ seeTags()183 public SeeTag[] seeTags() { 184 return comment().seeTags(); 185 } 186 inlineTags()187 public Tag[] inlineTags() { 188 if (inlineTags == null) { 189 inlineTags = Comment.getInlineTags(this, commentText()); 190 } 191 return inlineTags; 192 } 193 firstSentenceTags()194 public Tag[] firstSentenceTags() { 195 if (firstSentence == null) { 196 //Parse all sentences first to avoid duplicate warnings. 197 inlineTags(); 198 try { 199 env.setSilent(true); 200 firstSentence = Comment.firstSentenceTags(this, commentText()); 201 } finally { 202 env.setSilent(false); 203 } 204 } 205 return firstSentence; 206 } 207 208 /** 209 * Utility for subclasses which read HTML documentation files. 210 */ readHTMLDocumentation(InputStream input, FileObject filename)211 String readHTMLDocumentation(InputStream input, FileObject filename) throws IOException { 212 byte[] filecontents = new byte[input.available()]; 213 try { 214 DataInputStream dataIn = new DataInputStream(input); 215 dataIn.readFully(filecontents); 216 } finally { 217 input.close(); 218 } 219 String encoding = env.getEncoding(); 220 String rawDoc = (encoding!=null) 221 ? new String(filecontents, encoding) 222 : new String(filecontents); 223 Pattern bodyPat = Pattern.compile("(?is).*<body\\b[^>]*>(.*)</body\\b.*"); 224 Matcher m = bodyPat.matcher(rawDoc); 225 if (m.matches()) { 226 return m.group(1); 227 } else { 228 String key = rawDoc.matches("(?is).*<body\\b.*") 229 ? "javadoc.End_body_missing_from_html_file" 230 : "javadoc.Body_missing_from_html_file"; 231 env.error(SourcePositionImpl.make(filename, Position.NOPOS, null), key); 232 return ""; 233 } 234 } 235 236 /** 237 * Return the full unprocessed text of the comment. Tags 238 * are included as text. Used mainly for store and retrieve 239 * operations like internalization. 240 */ getRawCommentText()241 public String getRawCommentText() { 242 return documentation(); 243 } 244 245 /** 246 * Set the full unprocessed text of the comment. Tags 247 * are included as text. Used mainly for store and retrieve 248 * operations like internalization. 249 */ setRawCommentText(String rawDocumentation)250 public void setRawCommentText(String rawDocumentation) { 251 treePath = null; 252 documentation = rawDocumentation; 253 comment = null; 254 } 255 256 /** 257 * Set the full unprocessed text of the comment and tree path. 258 */ setTreePath(TreePath treePath)259 void setTreePath(TreePath treePath) { 260 this.treePath = treePath; 261 documentation = getCommentText(treePath); 262 comment = null; 263 } 264 265 /** 266 * return a key for sorting. 267 */ key()268 CollationKey key() { 269 if (collationkey == null) { 270 collationkey = generateKey(); 271 } 272 return collationkey; 273 } 274 275 /** 276 * Generate a key for sorting. 277 * <p> 278 * Default is name(). 279 */ generateKey()280 CollationKey generateKey() { 281 String k = name(); 282 // System.out.println("COLLATION KEY FOR " + this + " is \"" + k + "\""); 283 return env.doclocale.collator.getCollationKey(k); 284 } 285 286 /** 287 * Returns a string representation of this Doc item. 288 */ 289 @Override toString()290 public String toString() { 291 return qualifiedName(); 292 } 293 294 /** 295 * Returns the name of this Doc item. 296 * 297 * @return the name 298 */ name()299 public abstract String name(); 300 301 /** 302 * Returns the qualified name of this Doc item. 303 * 304 * @return the name 305 */ qualifiedName()306 public abstract String qualifiedName(); 307 308 /** 309 * Compares this Object with the specified Object for order. Returns a 310 * negative integer, zero, or a positive integer as this Object is less 311 * than, equal to, or greater than the given Object. 312 * <p> 313 * Included so that Doc item are java.lang.Comparable. 314 * 315 * @param obj the {@code Object} to be compared. 316 * @return a negative integer, zero, or a positive integer as this Object 317 * is less than, equal to, or greater than the given Object. 318 * @exception ClassCastException the specified Object's type prevents it 319 * from being compared to this Object. 320 */ compareTo(Object obj)321 public int compareTo(Object obj) { 322 // System.out.println("COMPARE \"" + this + "\" to \"" + obj + "\" = " + key().compareTo(((DocImpl)obj).key())); 323 return key().compareTo(((DocImpl)obj).key()); 324 } 325 326 /** 327 * Is this Doc item a field? False until overridden. 328 * 329 * @return true if it represents a field 330 */ isField()331 public boolean isField() { 332 return false; 333 } 334 335 /** 336 * Is this Doc item an enum constant? False until overridden. 337 * 338 * @return true if it represents an enum constant 339 */ isEnumConstant()340 public boolean isEnumConstant() { 341 return false; 342 } 343 344 /** 345 * Is this Doc item a constructor? False until overridden. 346 * 347 * @return true if it represents a constructor 348 */ isConstructor()349 public boolean isConstructor() { 350 return false; 351 } 352 353 /** 354 * Is this Doc item a method (but not a constructor or annotation 355 * type element)? 356 * False until overridden. 357 * 358 * @return true if it represents a method 359 */ isMethod()360 public boolean isMethod() { 361 return false; 362 } 363 364 /** 365 * Is this Doc item an annotation type element? 366 * False until overridden. 367 * 368 * @return true if it represents an annotation type element 369 */ isAnnotationTypeElement()370 public boolean isAnnotationTypeElement() { 371 return false; 372 } 373 374 /** 375 * Is this Doc item a interface (but not an annotation type)? 376 * False until overridden. 377 * 378 * @return true if it represents a interface 379 */ isInterface()380 public boolean isInterface() { 381 return false; 382 } 383 384 /** 385 * Is this Doc item a exception class? False until overridden. 386 * 387 * @return true if it represents a exception 388 */ isException()389 public boolean isException() { 390 return false; 391 } 392 393 /** 394 * Is this Doc item a error class? False until overridden. 395 * 396 * @return true if it represents a error 397 */ isError()398 public boolean isError() { 399 return false; 400 } 401 402 /** 403 * Is this Doc item an enum type? False until overridden. 404 * 405 * @return true if it represents an enum type 406 */ isEnum()407 public boolean isEnum() { 408 return false; 409 } 410 411 /** 412 * Is this Doc item an annotation type? False until overridden. 413 * 414 * @return true if it represents an annotation type 415 */ isAnnotationType()416 public boolean isAnnotationType() { 417 return false; 418 } 419 420 /** 421 * Is this Doc item an ordinary class (i.e. not an interface, 422 * annotation type, enumeration, exception, or error)? 423 * False until overridden. 424 * 425 * @return true if it represents an ordinary class 426 */ isOrdinaryClass()427 public boolean isOrdinaryClass() { 428 return false; 429 } 430 431 /** 432 * Is this Doc item a class 433 * (and not an interface or annotation type)? 434 * This includes ordinary classes, enums, errors and exceptions. 435 * False until overridden. 436 * 437 * @return true if it represents a class 438 */ isClass()439 public boolean isClass() { 440 return false; 441 } 442 443 /** 444 * return true if this Doc is include in the active set. 445 */ isIncluded()446 public abstract boolean isIncluded(); 447 448 /** 449 * Return the source position of the entity, or null if 450 * no position is available. 451 */ position()452 public SourcePosition position() { return null; } 453 } 454