src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java

Thu, 31 Aug 2017 15:17:03 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:17:03 +0800
changeset 2525
2eb010b6cb22
parent 2413
fe033d997ddf
parent 0
959103a6100f
permissions
-rw-r--r--

merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 package com.sun.tools.doclets.internal.toolkit.util;
aoqi@0 27
aoqi@0 28 import java.io.*;
aoqi@0 29 import java.lang.annotation.ElementType;
aoqi@0 30 import java.util.*;
aoqi@0 31 import javax.tools.StandardLocation;
aoqi@0 32
aoqi@0 33 import com.sun.javadoc.*;
aoqi@0 34 import com.sun.javadoc.AnnotationDesc.ElementValuePair;
aoqi@0 35 import com.sun.tools.doclets.internal.toolkit.*;
aoqi@0 36 import com.sun.tools.javac.util.StringUtils;
aoqi@0 37
aoqi@0 38 /**
aoqi@0 39 * Utilities Class for Doclets.
aoqi@0 40 *
aoqi@0 41 * <p><b>This is NOT part of any supported API.
aoqi@0 42 * If you write code that depends on this, you do so at your own risk.
aoqi@0 43 * This code and its internal interfaces are subject to change or
aoqi@0 44 * deletion without notice.</b>
aoqi@0 45 *
aoqi@0 46 * @author Atul M Dambalkar
aoqi@0 47 * @author Jamie Ho
aoqi@0 48 */
aoqi@0 49 public class Util {
aoqi@0 50
aoqi@0 51 /**
aoqi@0 52 * Return array of class members whose documentation is to be generated.
aoqi@0 53 * If the member is deprecated do not include such a member in the
aoqi@0 54 * returned array.
aoqi@0 55 *
aoqi@0 56 * @param members Array of members to choose from.
aoqi@0 57 * @return ProgramElementDoc[] Array of eligible members for whom
aoqi@0 58 * documentation is getting generated.
aoqi@0 59 */
aoqi@0 60 public static ProgramElementDoc[] excludeDeprecatedMembers(
aoqi@0 61 ProgramElementDoc[] members) {
aoqi@0 62 return
aoqi@0 63 toProgramElementDocArray(excludeDeprecatedMembersAsList(members));
aoqi@0 64 }
aoqi@0 65
aoqi@0 66 /**
aoqi@0 67 * Return array of class members whose documentation is to be generated.
aoqi@0 68 * If the member is deprecated do not include such a member in the
aoqi@0 69 * returned array.
aoqi@0 70 *
aoqi@0 71 * @param members Array of members to choose from.
aoqi@0 72 * @return List List of eligible members for whom
aoqi@0 73 * documentation is getting generated.
aoqi@0 74 */
aoqi@0 75 public static List<ProgramElementDoc> excludeDeprecatedMembersAsList(
aoqi@0 76 ProgramElementDoc[] members) {
aoqi@0 77 List<ProgramElementDoc> list = new ArrayList<ProgramElementDoc>();
aoqi@0 78 for (int i = 0; i < members.length; i++) {
aoqi@0 79 if (members[i].tags("deprecated").length == 0) {
aoqi@0 80 list.add(members[i]);
aoqi@0 81 }
aoqi@0 82 }
aoqi@0 83 Collections.sort(list);
aoqi@0 84 return list;
aoqi@0 85 }
aoqi@0 86
aoqi@0 87 /**
aoqi@0 88 * Return the list of ProgramElementDoc objects as Array.
aoqi@0 89 */
aoqi@0 90 public static ProgramElementDoc[] toProgramElementDocArray(List<ProgramElementDoc> list) {
aoqi@0 91 ProgramElementDoc[] pgmarr = new ProgramElementDoc[list.size()];
aoqi@0 92 for (int i = 0; i < list.size(); i++) {
aoqi@0 93 pgmarr[i] = list.get(i);
aoqi@0 94 }
aoqi@0 95 return pgmarr;
aoqi@0 96 }
aoqi@0 97
aoqi@0 98 /**
aoqi@0 99 * Return true if a non-public member found in the given array.
aoqi@0 100 *
aoqi@0 101 * @param members Array of members to look into.
aoqi@0 102 * @return boolean True if non-public member found, false otherwise.
aoqi@0 103 */
aoqi@0 104 public static boolean nonPublicMemberFound(ProgramElementDoc[] members) {
aoqi@0 105 for (int i = 0; i < members.length; i++) {
aoqi@0 106 if (!members[i].isPublic()) {
aoqi@0 107 return true;
aoqi@0 108 }
aoqi@0 109 }
aoqi@0 110 return false;
aoqi@0 111 }
aoqi@0 112
aoqi@0 113 /**
aoqi@0 114 * Search for the given method in the given class.
aoqi@0 115 *
aoqi@0 116 * @param cd Class to search into.
aoqi@0 117 * @param method Method to be searched.
aoqi@0 118 * @return MethodDoc Method found, null otherwise.
aoqi@0 119 */
aoqi@0 120 public static MethodDoc findMethod(ClassDoc cd, MethodDoc method) {
aoqi@0 121 MethodDoc[] methods = cd.methods();
aoqi@0 122 for (int i = 0; i < methods.length; i++) {
aoqi@0 123 if (executableMembersEqual(method, methods[i])) {
aoqi@0 124 return methods[i];
aoqi@0 125
aoqi@0 126 }
aoqi@0 127 }
aoqi@0 128 return null;
aoqi@0 129 }
aoqi@0 130
aoqi@0 131 /**
aoqi@0 132 * @param member1 the first method to compare.
aoqi@0 133 * @param member2 the second method to compare.
aoqi@0 134 * @return true if member1 overrides/hides or is overriden/hidden by member2.
aoqi@0 135 */
aoqi@0 136 public static boolean executableMembersEqual(ExecutableMemberDoc member1,
aoqi@0 137 ExecutableMemberDoc member2) {
aoqi@0 138 if (! (member1 instanceof MethodDoc && member2 instanceof MethodDoc))
aoqi@0 139 return false;
aoqi@0 140
aoqi@0 141 MethodDoc method1 = (MethodDoc) member1;
aoqi@0 142 MethodDoc method2 = (MethodDoc) member2;
aoqi@0 143 if (method1.isStatic() && method2.isStatic()) {
aoqi@0 144 Parameter[] targetParams = method1.parameters();
aoqi@0 145 Parameter[] currentParams;
aoqi@0 146 if (method1.name().equals(method2.name()) &&
aoqi@0 147 (currentParams = method2.parameters()).length ==
aoqi@0 148 targetParams.length) {
aoqi@0 149 int j;
aoqi@0 150 for (j = 0; j < targetParams.length; j++) {
aoqi@0 151 if (! (targetParams[j].typeName().equals(
aoqi@0 152 currentParams[j].typeName()) ||
aoqi@0 153 currentParams[j].type() instanceof TypeVariable ||
aoqi@0 154 targetParams[j].type() instanceof TypeVariable)) {
aoqi@0 155 break;
aoqi@0 156 }
aoqi@0 157 }
aoqi@0 158 if (j == targetParams.length) {
aoqi@0 159 return true;
aoqi@0 160 }
aoqi@0 161 }
aoqi@0 162 return false;
aoqi@0 163 } else {
aoqi@0 164 return method1.overrides(method2) ||
aoqi@0 165 method2.overrides(method1) ||
aoqi@0 166 member1 == member2;
aoqi@0 167 }
aoqi@0 168 }
aoqi@0 169
aoqi@0 170 /**
aoqi@0 171 * According to
aoqi@0 172 * <cite>The Java&trade; Language Specification</cite>,
aoqi@0 173 * all the outer classes and static inner classes are core classes.
aoqi@0 174 */
aoqi@0 175 public static boolean isCoreClass(ClassDoc cd) {
aoqi@0 176 return cd.containingClass() == null || cd.isStatic();
aoqi@0 177 }
aoqi@0 178
aoqi@0 179 public static boolean matches(ProgramElementDoc doc1,
aoqi@0 180 ProgramElementDoc doc2) {
aoqi@0 181 if (doc1 instanceof ExecutableMemberDoc &&
aoqi@0 182 doc2 instanceof ExecutableMemberDoc) {
aoqi@0 183 ExecutableMemberDoc ed1 = (ExecutableMemberDoc)doc1;
aoqi@0 184 ExecutableMemberDoc ed2 = (ExecutableMemberDoc)doc2;
aoqi@0 185 return executableMembersEqual(ed1, ed2);
aoqi@0 186 } else {
aoqi@0 187 return doc1.name().equals(doc2.name());
aoqi@0 188 }
aoqi@0 189 }
aoqi@0 190
aoqi@0 191 /**
aoqi@0 192 * Copy the given directory contents from the source package directory
aoqi@0 193 * to the generated documentation directory. For example for a package
aoqi@0 194 * java.lang this method find out the source location of the package using
aoqi@0 195 * {@link SourcePath} and if given directory is found in the source
aoqi@0 196 * directory structure, copy the entire directory, to the generated
aoqi@0 197 * documentation hierarchy.
aoqi@0 198 *
aoqi@0 199 * @param configuration The configuration of the current doclet.
aoqi@0 200 * @param path The relative path to the directory to be copied.
aoqi@0 201 * @param dir The original directory name to copy from.
aoqi@0 202 * @param overwrite Overwrite files if true.
aoqi@0 203 */
aoqi@0 204 public static void copyDocFiles(Configuration configuration, PackageDoc pd) {
aoqi@0 205 copyDocFiles(configuration, DocPath.forPackage(pd).resolve(DocPaths.DOC_FILES));
aoqi@0 206 }
aoqi@0 207
aoqi@0 208 public static void copyDocFiles(Configuration configuration, DocPath dir) {
aoqi@0 209 try {
aoqi@0 210 boolean first = true;
aoqi@0 211 for (DocFile f : DocFile.list(configuration, StandardLocation.SOURCE_PATH, dir)) {
aoqi@0 212 if (!f.isDirectory()) {
aoqi@0 213 continue;
aoqi@0 214 }
aoqi@0 215 DocFile srcdir = f;
aoqi@0 216 DocFile destdir = DocFile.createFileForOutput(configuration, dir);
aoqi@0 217 if (srcdir.isSameFile(destdir)) {
aoqi@0 218 continue;
aoqi@0 219 }
aoqi@0 220
aoqi@0 221 for (DocFile srcfile: srcdir.list()) {
aoqi@0 222 DocFile destfile = destdir.resolve(srcfile.getName());
aoqi@0 223 if (srcfile.isFile()) {
aoqi@0 224 if (destfile.exists() && !first) {
aoqi@0 225 configuration.message.warning((SourcePosition) null,
aoqi@0 226 "doclet.Copy_Overwrite_warning",
aoqi@0 227 srcfile.getPath(), destdir.getPath());
aoqi@0 228 } else {
aoqi@0 229 configuration.message.notice(
aoqi@0 230 "doclet.Copying_File_0_To_Dir_1",
aoqi@0 231 srcfile.getPath(), destdir.getPath());
aoqi@0 232 destfile.copyFile(srcfile);
aoqi@0 233 }
aoqi@0 234 } else if (srcfile.isDirectory()) {
aoqi@0 235 if (configuration.copydocfilesubdirs
aoqi@0 236 && !configuration.shouldExcludeDocFileDir(srcfile.getName())) {
aoqi@0 237 copyDocFiles(configuration, dir.resolve(srcfile.getName()));
aoqi@0 238 }
aoqi@0 239 }
aoqi@0 240 }
aoqi@0 241
aoqi@0 242 first = false;
aoqi@0 243 }
aoqi@0 244 } catch (SecurityException exc) {
aoqi@0 245 throw new DocletAbortException(exc);
aoqi@0 246 } catch (IOException exc) {
aoqi@0 247 throw new DocletAbortException(exc);
aoqi@0 248 }
aoqi@0 249 }
aoqi@0 250
aoqi@0 251 /**
aoqi@0 252 * We want the list of types in alphabetical order. However, types are not
aoqi@0 253 * comparable. We need a comparator for now.
aoqi@0 254 */
aoqi@0 255 private static class TypeComparator implements Comparator<Type> {
aoqi@0 256 public int compare(Type type1, Type type2) {
aoqi@0 257 return type1.qualifiedTypeName().compareToIgnoreCase(
aoqi@0 258 type2.qualifiedTypeName());
aoqi@0 259 }
aoqi@0 260 }
aoqi@0 261
aoqi@0 262 /**
aoqi@0 263 * For the class return all implemented interfaces including the
aoqi@0 264 * superinterfaces of the implementing interfaces, also iterate over for
aoqi@0 265 * all the superclasses. For interface return all the extended interfaces
aoqi@0 266 * as well as superinterfaces for those extended interfaces.
aoqi@0 267 *
aoqi@0 268 * @param type type whose implemented or
aoqi@0 269 * super interfaces are sought.
aoqi@0 270 * @param configuration the current configuration of the doclet.
aoqi@0 271 * @param sort if true, return list of interfaces sorted alphabetically.
aoqi@0 272 * @return List of all the required interfaces.
aoqi@0 273 */
aoqi@0 274 public static List<Type> getAllInterfaces(Type type,
aoqi@0 275 Configuration configuration, boolean sort) {
aoqi@0 276 Map<ClassDoc,Type> results = sort ? new TreeMap<ClassDoc,Type>() : new LinkedHashMap<ClassDoc,Type>();
aoqi@0 277 Type[] interfaceTypes = null;
aoqi@0 278 Type superType = null;
aoqi@0 279 if (type instanceof ParameterizedType) {
aoqi@0 280 interfaceTypes = ((ParameterizedType) type).interfaceTypes();
aoqi@0 281 superType = ((ParameterizedType) type).superclassType();
aoqi@0 282 } else if (type instanceof ClassDoc) {
aoqi@0 283 interfaceTypes = ((ClassDoc) type).interfaceTypes();
aoqi@0 284 superType = ((ClassDoc) type).superclassType();
aoqi@0 285 } else {
aoqi@0 286 interfaceTypes = type.asClassDoc().interfaceTypes();
aoqi@0 287 superType = type.asClassDoc().superclassType();
aoqi@0 288 }
aoqi@0 289
aoqi@0 290 for (int i = 0; i < interfaceTypes.length; i++) {
aoqi@0 291 Type interfaceType = interfaceTypes[i];
aoqi@0 292 ClassDoc interfaceClassDoc = interfaceType.asClassDoc();
aoqi@0 293 if (! (interfaceClassDoc.isPublic() ||
aoqi@0 294 (configuration == null ||
aoqi@0 295 isLinkable(interfaceClassDoc, configuration)))) {
aoqi@0 296 continue;
aoqi@0 297 }
aoqi@0 298 results.put(interfaceClassDoc, interfaceType);
aoqi@0 299 List<Type> superInterfaces = getAllInterfaces(interfaceType, configuration, sort);
aoqi@0 300 for (Iterator<Type> iter = superInterfaces.iterator(); iter.hasNext(); ) {
aoqi@0 301 Type t = iter.next();
aoqi@0 302 results.put(t.asClassDoc(), t);
aoqi@0 303 }
aoqi@0 304 }
aoqi@0 305 if (superType == null)
aoqi@0 306 return new ArrayList<Type>(results.values());
aoqi@0 307 //Try walking the tree.
aoqi@0 308 addAllInterfaceTypes(results,
aoqi@0 309 superType,
aoqi@0 310 interfaceTypesOf(superType),
aoqi@0 311 false, configuration);
aoqi@0 312 List<Type> resultsList = new ArrayList<Type>(results.values());
aoqi@0 313 if (sort) {
aoqi@0 314 Collections.sort(resultsList, new TypeComparator());
aoqi@0 315 }
aoqi@0 316 return resultsList;
aoqi@0 317 }
aoqi@0 318
aoqi@0 319 private static Type[] interfaceTypesOf(Type type) {
aoqi@0 320 if (type instanceof AnnotatedType)
aoqi@0 321 type = ((AnnotatedType)type).underlyingType();
aoqi@0 322 return type instanceof ClassDoc ?
aoqi@0 323 ((ClassDoc)type).interfaceTypes() :
aoqi@0 324 ((ParameterizedType)type).interfaceTypes();
aoqi@0 325 }
aoqi@0 326
aoqi@0 327 public static List<Type> getAllInterfaces(Type type, Configuration configuration) {
aoqi@0 328 return getAllInterfaces(type, configuration, true);
aoqi@0 329 }
aoqi@0 330
aoqi@0 331 private static void findAllInterfaceTypes(Map<ClassDoc,Type> results, ClassDoc c, boolean raw,
aoqi@0 332 Configuration configuration) {
aoqi@0 333 Type superType = c.superclassType();
aoqi@0 334 if (superType == null)
aoqi@0 335 return;
aoqi@0 336 addAllInterfaceTypes(results, superType,
aoqi@0 337 interfaceTypesOf(superType),
aoqi@0 338 raw, configuration);
aoqi@0 339 }
aoqi@0 340
aoqi@0 341 private static void findAllInterfaceTypes(Map<ClassDoc,Type> results, ParameterizedType p,
aoqi@0 342 Configuration configuration) {
aoqi@0 343 Type superType = p.superclassType();
aoqi@0 344 if (superType == null)
aoqi@0 345 return;
aoqi@0 346 addAllInterfaceTypes(results, superType,
aoqi@0 347 interfaceTypesOf(superType),
aoqi@0 348 false, configuration);
aoqi@0 349 }
aoqi@0 350
aoqi@0 351 private static void addAllInterfaceTypes(Map<ClassDoc,Type> results, Type type,
aoqi@0 352 Type[] interfaceTypes, boolean raw,
aoqi@0 353 Configuration configuration) {
aoqi@0 354 for (int i = 0; i < interfaceTypes.length; i++) {
aoqi@0 355 Type interfaceType = interfaceTypes[i];
aoqi@0 356 ClassDoc interfaceClassDoc = interfaceType.asClassDoc();
aoqi@0 357 if (! (interfaceClassDoc.isPublic() ||
aoqi@0 358 (configuration != null &&
aoqi@0 359 isLinkable(interfaceClassDoc, configuration)))) {
aoqi@0 360 continue;
aoqi@0 361 }
aoqi@0 362 if (raw)
aoqi@0 363 interfaceType = interfaceType.asClassDoc();
aoqi@0 364 results.put(interfaceClassDoc, interfaceType);
aoqi@0 365 List<Type> superInterfaces = getAllInterfaces(interfaceType, configuration);
aoqi@0 366 for (Iterator<Type> iter = superInterfaces.iterator(); iter.hasNext(); ) {
aoqi@0 367 Type superInterface = iter.next();
aoqi@0 368 results.put(superInterface.asClassDoc(), superInterface);
aoqi@0 369 }
aoqi@0 370 }
aoqi@0 371 if (type instanceof AnnotatedType)
aoqi@0 372 type = ((AnnotatedType)type).underlyingType();
aoqi@0 373
aoqi@0 374 if (type instanceof ParameterizedType)
aoqi@0 375 findAllInterfaceTypes(results, (ParameterizedType) type, configuration);
aoqi@0 376 else if (((ClassDoc) type).typeParameters().length == 0)
aoqi@0 377 findAllInterfaceTypes(results, (ClassDoc) type, raw, configuration);
aoqi@0 378 else
aoqi@0 379 findAllInterfaceTypes(results, (ClassDoc) type, true, configuration);
aoqi@0 380 }
aoqi@0 381
aoqi@0 382 /**
aoqi@0 383 * Enclose in quotes, used for paths and filenames that contains spaces
aoqi@0 384 */
aoqi@0 385 public static String quote(String filepath) {
aoqi@0 386 return ("\"" + filepath + "\"");
aoqi@0 387 }
aoqi@0 388
aoqi@0 389 /**
aoqi@0 390 * Given a package, return its name.
aoqi@0 391 * @param packageDoc the package to check.
aoqi@0 392 * @return the name of the given package.
aoqi@0 393 */
aoqi@0 394 public static String getPackageName(PackageDoc packageDoc) {
aoqi@0 395 return packageDoc == null || packageDoc.name().length() == 0 ?
aoqi@0 396 DocletConstants.DEFAULT_PACKAGE_NAME : packageDoc.name();
aoqi@0 397 }
aoqi@0 398
aoqi@0 399 /**
aoqi@0 400 * Given a package, return its file name without the extension.
aoqi@0 401 * @param packageDoc the package to check.
aoqi@0 402 * @return the file name of the given package.
aoqi@0 403 */
aoqi@0 404 public static String getPackageFileHeadName(PackageDoc packageDoc) {
aoqi@0 405 return packageDoc == null || packageDoc.name().length() == 0 ?
aoqi@0 406 DocletConstants.DEFAULT_PACKAGE_FILE_NAME : packageDoc.name();
aoqi@0 407 }
aoqi@0 408
aoqi@0 409 /**
aoqi@0 410 * Given a string, replace all occurrences of 'newStr' with 'oldStr'.
aoqi@0 411 * @param originalStr the string to modify.
aoqi@0 412 * @param oldStr the string to replace.
aoqi@0 413 * @param newStr the string to insert in place of the old string.
aoqi@0 414 */
aoqi@0 415 public static String replaceText(String originalStr, String oldStr,
aoqi@0 416 String newStr) {
aoqi@0 417 if (oldStr == null || newStr == null || oldStr.equals(newStr)) {
aoqi@0 418 return originalStr;
aoqi@0 419 }
aoqi@0 420 return originalStr.replace(oldStr, newStr);
aoqi@0 421 }
aoqi@0 422
aoqi@0 423 /**
aoqi@0 424 * Given an annotation, return true if it should be documented and false
aoqi@0 425 * otherwise.
aoqi@0 426 *
aoqi@0 427 * @param annotationDoc the annotation to check.
aoqi@0 428 *
aoqi@0 429 * @return true return true if it should be documented and false otherwise.
aoqi@0 430 */
aoqi@0 431 public static boolean isDocumentedAnnotation(AnnotationTypeDoc annotationDoc) {
aoqi@0 432 AnnotationDesc[] annotationDescList = annotationDoc.annotations();
aoqi@0 433 for (int i = 0; i < annotationDescList.length; i++) {
aoqi@0 434 if (annotationDescList[i].annotationType().qualifiedName().equals(
aoqi@0 435 java.lang.annotation.Documented.class.getName())){
aoqi@0 436 return true;
aoqi@0 437 }
aoqi@0 438 }
aoqi@0 439 return false;
aoqi@0 440 }
aoqi@0 441
aoqi@0 442 private static boolean isDeclarationTarget(AnnotationDesc targetAnno) {
aoqi@0 443 // The error recovery steps here are analogous to TypeAnnotations
aoqi@0 444 ElementValuePair[] elems = targetAnno.elementValues();
aoqi@0 445 if (elems == null
aoqi@0 446 || elems.length != 1
aoqi@0 447 || !"value".equals(elems[0].element().name())
aoqi@0 448 || !(elems[0].value().value() instanceof AnnotationValue[]))
aoqi@0 449 return true; // error recovery
aoqi@0 450
aoqi@0 451 AnnotationValue[] values = (AnnotationValue[])elems[0].value().value();
aoqi@0 452 for (int i = 0; i < values.length; i++) {
aoqi@0 453 Object value = values[i].value();
aoqi@0 454 if (!(value instanceof FieldDoc))
aoqi@0 455 return true; // error recovery
aoqi@0 456
aoqi@0 457 FieldDoc eValue = (FieldDoc)value;
aoqi@0 458 if (Util.isJava5DeclarationElementType(eValue)) {
aoqi@0 459 return true;
aoqi@0 460 }
aoqi@0 461 }
aoqi@0 462
aoqi@0 463 return false;
aoqi@0 464 }
aoqi@0 465
aoqi@0 466 /**
aoqi@0 467 * Returns true if the {@code annotationDoc} is to be treated
aoqi@0 468 * as a declaration annotation, when targeting the
aoqi@0 469 * {@code elemType} element type.
aoqi@0 470 *
aoqi@0 471 * @param annotationDoc the annotationDoc to check
aoqi@0 472 * @param elemType the targeted elemType
aoqi@0 473 * @return true if annotationDoc is a declaration annotation
aoqi@0 474 */
aoqi@0 475 public static boolean isDeclarationAnnotation(AnnotationTypeDoc annotationDoc,
aoqi@0 476 boolean isJava5DeclarationLocation) {
aoqi@0 477 if (!isJava5DeclarationLocation)
aoqi@0 478 return false;
aoqi@0 479 AnnotationDesc[] annotationDescList = annotationDoc.annotations();
aoqi@0 480 // Annotations with no target are treated as declaration as well
aoqi@0 481 if (annotationDescList.length==0)
aoqi@0 482 return true;
aoqi@0 483 for (int i = 0; i < annotationDescList.length; i++) {
aoqi@0 484 if (annotationDescList[i].annotationType().qualifiedName().equals(
aoqi@0 485 java.lang.annotation.Target.class.getName())) {
aoqi@0 486 if (isDeclarationTarget(annotationDescList[i]))
aoqi@0 487 return true;
aoqi@0 488 }
aoqi@0 489 }
aoqi@0 490 return false;
aoqi@0 491 }
aoqi@0 492
aoqi@0 493 /**
aoqi@0 494 * Return true if this class is linkable and false if we can't link to the
aoqi@0 495 * desired class.
aoqi@0 496 * <br>
aoqi@0 497 * <b>NOTE:</b> You can only link to external classes if they are public or
aoqi@0 498 * protected.
aoqi@0 499 *
aoqi@0 500 * @param classDoc the class to check.
aoqi@0 501 * @param configuration the current configuration of the doclet.
aoqi@0 502 *
aoqi@0 503 * @return true if this class is linkable and false if we can't link to the
aoqi@0 504 * desired class.
aoqi@0 505 */
aoqi@0 506 public static boolean isLinkable(ClassDoc classDoc,
aoqi@0 507 Configuration configuration) {
aoqi@0 508 return
aoqi@0 509 ((classDoc.isIncluded() && configuration.isGeneratedDoc(classDoc))) ||
aoqi@0 510 (configuration.extern.isExternal(classDoc) &&
aoqi@0 511 (classDoc.isPublic() || classDoc.isProtected()));
aoqi@0 512 }
aoqi@0 513
aoqi@0 514 /**
aoqi@0 515 * Given a class, return the closest visible super class.
aoqi@0 516 *
aoqi@0 517 * @param classDoc the class we are searching the parent for.
aoqi@0 518 * @param configuration the current configuration of the doclet.
aoqi@0 519 * @return the closest visible super class. Return null if it cannot
aoqi@0 520 * be found (i.e. classDoc is java.lang.Object).
aoqi@0 521 */
aoqi@0 522 public static Type getFirstVisibleSuperClass(ClassDoc classDoc,
aoqi@0 523 Configuration configuration) {
aoqi@0 524 if (classDoc == null) {
aoqi@0 525 return null;
aoqi@0 526 }
aoqi@0 527 Type sup = classDoc.superclassType();
aoqi@0 528 ClassDoc supClassDoc = classDoc.superclass();
aoqi@0 529 while (sup != null &&
aoqi@0 530 (! (supClassDoc.isPublic() ||
aoqi@0 531 isLinkable(supClassDoc, configuration))) ) {
aoqi@0 532 if (supClassDoc.superclass().qualifiedName().equals(supClassDoc.qualifiedName()))
aoqi@0 533 break;
aoqi@0 534 sup = supClassDoc.superclassType();
aoqi@0 535 supClassDoc = supClassDoc.superclass();
aoqi@0 536 }
aoqi@0 537 if (classDoc.equals(supClassDoc)) {
aoqi@0 538 return null;
aoqi@0 539 }
aoqi@0 540 return sup;
aoqi@0 541 }
aoqi@0 542
aoqi@0 543 /**
aoqi@0 544 * Given a class, return the closest visible super class.
aoqi@0 545 *
aoqi@0 546 * @param classDoc the class we are searching the parent for.
aoqi@0 547 * @param configuration the current configuration of the doclet.
aoqi@0 548 * @return the closest visible super class. Return null if it cannot
aoqi@0 549 * be found (i.e. classDoc is java.lang.Object).
aoqi@0 550 */
aoqi@0 551 public static ClassDoc getFirstVisibleSuperClassCD(ClassDoc classDoc,
aoqi@0 552 Configuration configuration) {
aoqi@0 553 if (classDoc == null) {
aoqi@0 554 return null;
aoqi@0 555 }
aoqi@0 556 ClassDoc supClassDoc = classDoc.superclass();
aoqi@0 557 while (supClassDoc != null &&
aoqi@0 558 (! (supClassDoc.isPublic() ||
aoqi@0 559 isLinkable(supClassDoc, configuration))) ) {
aoqi@0 560 supClassDoc = supClassDoc.superclass();
aoqi@0 561 }
aoqi@0 562 if (classDoc.equals(supClassDoc)) {
aoqi@0 563 return null;
aoqi@0 564 }
aoqi@0 565 return supClassDoc;
aoqi@0 566 }
aoqi@0 567
aoqi@0 568 /**
aoqi@0 569 * Given a ClassDoc, return the name of its type (Class, Interface, etc.).
aoqi@0 570 *
aoqi@0 571 * @param cd the ClassDoc to check.
aoqi@0 572 * @param lowerCaseOnly true if you want the name returned in lower case.
aoqi@0 573 * If false, the first letter of the name is capitalized.
aoqi@0 574 * @return
aoqi@0 575 */
aoqi@0 576 public static String getTypeName(Configuration config,
aoqi@0 577 ClassDoc cd, boolean lowerCaseOnly) {
aoqi@0 578 String typeName = "";
aoqi@0 579 if (cd.isOrdinaryClass()) {
aoqi@0 580 typeName = "doclet.Class";
aoqi@0 581 } else if (cd.isInterface()) {
aoqi@0 582 typeName = "doclet.Interface";
aoqi@0 583 } else if (cd.isException()) {
aoqi@0 584 typeName = "doclet.Exception";
aoqi@0 585 } else if (cd.isError()) {
aoqi@0 586 typeName = "doclet.Error";
aoqi@0 587 } else if (cd.isAnnotationType()) {
aoqi@0 588 typeName = "doclet.AnnotationType";
aoqi@0 589 } else if (cd.isEnum()) {
aoqi@0 590 typeName = "doclet.Enum";
aoqi@0 591 }
aoqi@0 592 return config.getText(
aoqi@0 593 lowerCaseOnly ? StringUtils.toLowerCase(typeName) : typeName);
aoqi@0 594 }
aoqi@0 595
aoqi@0 596 /**
aoqi@0 597 * Replace all tabs in a string with the appropriate number of spaces.
aoqi@0 598 * The string may be a multi-line string.
aoqi@0 599 * @param configuration the doclet configuration defining the setting for the
aoqi@0 600 * tab length.
aoqi@0 601 * @param text the text for which the tabs should be expanded
aoqi@0 602 * @return the text with all tabs expanded
aoqi@0 603 */
aoqi@0 604 public static String replaceTabs(Configuration configuration, String text) {
aoqi@0 605 if (text.indexOf("\t") == -1)
aoqi@0 606 return text;
aoqi@0 607
aoqi@0 608 final int tabLength = configuration.sourcetab;
aoqi@0 609 final String whitespace = configuration.tabSpaces;
aoqi@0 610 final int textLength = text.length();
aoqi@0 611 StringBuilder result = new StringBuilder(textLength);
aoqi@0 612 int pos = 0;
aoqi@0 613 int lineLength = 0;
aoqi@0 614 for (int i = 0; i < textLength; i++) {
aoqi@0 615 char ch = text.charAt(i);
aoqi@0 616 switch (ch) {
aoqi@0 617 case '\n': case '\r':
aoqi@0 618 lineLength = 0;
aoqi@0 619 break;
aoqi@0 620 case '\t':
aoqi@0 621 result.append(text, pos, i);
aoqi@0 622 int spaceCount = tabLength - lineLength % tabLength;
aoqi@0 623 result.append(whitespace, 0, spaceCount);
aoqi@0 624 lineLength += spaceCount;
aoqi@0 625 pos = i + 1;
aoqi@0 626 break;
aoqi@0 627 default:
aoqi@0 628 lineLength++;
aoqi@0 629 }
aoqi@0 630 }
aoqi@0 631 result.append(text, pos, textLength);
aoqi@0 632 return result.toString();
aoqi@0 633 }
aoqi@0 634
aoqi@0 635 public static String normalizeNewlines(String text) {
aoqi@0 636 StringBuilder sb = new StringBuilder();
aoqi@0 637 final int textLength = text.length();
aoqi@0 638 final String NL = DocletConstants.NL;
aoqi@0 639 int pos = 0;
aoqi@0 640 for (int i = 0; i < textLength; i++) {
aoqi@0 641 char ch = text.charAt(i);
aoqi@0 642 switch (ch) {
aoqi@0 643 case '\n':
aoqi@0 644 sb.append(text, pos, i);
aoqi@0 645 sb.append(NL);
aoqi@0 646 pos = i + 1;
aoqi@0 647 break;
aoqi@0 648 case '\r':
aoqi@0 649 sb.append(text, pos, i);
aoqi@0 650 sb.append(NL);
aoqi@0 651 if (i + 1 < textLength && text.charAt(i + 1) == '\n')
aoqi@0 652 i++;
aoqi@0 653 pos = i + 1;
aoqi@0 654 break;
aoqi@0 655 }
aoqi@0 656 }
aoqi@0 657 sb.append(text, pos, textLength);
aoqi@0 658 return sb.toString();
aoqi@0 659 }
aoqi@0 660
aoqi@0 661 /**
aoqi@0 662 * The documentation for values() and valueOf() in Enums are set by the
aoqi@0 663 * doclet.
aoqi@0 664 */
aoqi@0 665 public static void setEnumDocumentation(Configuration configuration,
aoqi@0 666 ClassDoc classDoc) {
aoqi@0 667 MethodDoc[] methods = classDoc.methods();
aoqi@0 668 for (int j = 0; j < methods.length; j++) {
aoqi@0 669 MethodDoc currentMethod = methods[j];
aoqi@0 670 if (currentMethod.name().equals("values") &&
aoqi@0 671 currentMethod.parameters().length == 0) {
aoqi@0 672 StringBuilder sb = new StringBuilder();
aoqi@0 673 sb.append(configuration.getText("doclet.enum_values_doc.main", classDoc.name()));
aoqi@0 674 sb.append("\n@return ");
aoqi@0 675 sb.append(configuration.getText("doclet.enum_values_doc.return"));
aoqi@0 676 currentMethod.setRawCommentText(sb.toString());
aoqi@0 677 } else if (currentMethod.name().equals("valueOf") &&
aoqi@0 678 currentMethod.parameters().length == 1) {
aoqi@0 679 Type paramType = currentMethod.parameters()[0].type();
aoqi@0 680 if (paramType != null &&
aoqi@0 681 paramType.qualifiedTypeName().equals(String.class.getName())) {
aoqi@0 682 StringBuilder sb = new StringBuilder();
aoqi@0 683 sb.append(configuration.getText("doclet.enum_valueof_doc.main", classDoc.name()));
aoqi@0 684 sb.append("\n@param name ");
aoqi@0 685 sb.append(configuration.getText("doclet.enum_valueof_doc.param_name"));
aoqi@0 686 sb.append("\n@return ");
aoqi@0 687 sb.append(configuration.getText("doclet.enum_valueof_doc.return"));
aoqi@0 688 sb.append("\n@throws IllegalArgumentException ");
aoqi@0 689 sb.append(configuration.getText("doclet.enum_valueof_doc.throws_ila"));
aoqi@0 690 sb.append("\n@throws NullPointerException ");
aoqi@0 691 sb.append(configuration.getText("doclet.enum_valueof_doc.throws_npe"));
aoqi@0 692 currentMethod.setRawCommentText(sb.toString());
aoqi@0 693 }
aoqi@0 694 }
aoqi@0 695 }
aoqi@0 696 }
aoqi@0 697
aoqi@0 698 /**
aoqi@0 699 * Return true if the given Doc is deprecated.
aoqi@0 700 *
aoqi@0 701 * @param doc the Doc to check.
aoqi@0 702 * @return true if the given Doc is deprecated.
aoqi@0 703 */
aoqi@0 704 public static boolean isDeprecated(Doc doc) {
aoqi@0 705 if (doc.tags("deprecated").length > 0) {
aoqi@0 706 return true;
aoqi@0 707 }
aoqi@0 708 AnnotationDesc[] annotationDescList;
aoqi@0 709 if (doc instanceof PackageDoc)
aoqi@0 710 annotationDescList = ((PackageDoc)doc).annotations();
aoqi@0 711 else
aoqi@0 712 annotationDescList = ((ProgramElementDoc)doc).annotations();
aoqi@0 713 for (int i = 0; i < annotationDescList.length; i++) {
aoqi@0 714 if (annotationDescList[i].annotationType().qualifiedName().equals(
aoqi@0 715 java.lang.Deprecated.class.getName())){
aoqi@0 716 return true;
aoqi@0 717 }
aoqi@0 718 }
aoqi@0 719 return false;
aoqi@0 720 }
aoqi@0 721
aoqi@0 722 /**
aoqi@0 723 * A convenience method to get property name from the name of the
aoqi@0 724 * getter or setter method.
aoqi@0 725 * @param name name of the getter or setter method.
aoqi@0 726 * @return the name of the property of the given setter of getter.
aoqi@0 727 */
aoqi@0 728 public static String propertyNameFromMethodName(Configuration configuration, String name) {
aoqi@0 729 String propertyName = null;
aoqi@0 730 if (name.startsWith("get") || name.startsWith("set")) {
aoqi@0 731 propertyName = name.substring(3);
aoqi@0 732 } else if (name.startsWith("is")) {
aoqi@0 733 propertyName = name.substring(2);
aoqi@0 734 }
aoqi@0 735 if ((propertyName == null) || propertyName.isEmpty()){
aoqi@0 736 return "";
aoqi@0 737 }
aoqi@0 738 return propertyName.substring(0, 1).toLowerCase(configuration.getLocale())
aoqi@0 739 + propertyName.substring(1);
aoqi@0 740 }
aoqi@0 741
aoqi@0 742 /**
aoqi@0 743 * In case of JavaFX mode on, filters out classes that are private,
aoqi@0 744 * package private or having the @treatAsPrivate annotation. Those are not
aoqi@0 745 * documented in JavaFX mode.
aoqi@0 746 *
aoqi@0 747 * @param classes array of classes to be filtered.
aoqi@0 748 * @param javafx set to true if in JavaFX mode.
aoqi@0 749 * @return list of filtered classes.
aoqi@0 750 */
aoqi@0 751 public static ClassDoc[] filterOutPrivateClasses(final ClassDoc[] classes,
aoqi@0 752 boolean javafx) {
aoqi@0 753 if (!javafx) {
aoqi@0 754 return classes;
aoqi@0 755 }
aoqi@0 756 final List<ClassDoc> filteredOutClasses =
aoqi@0 757 new ArrayList<ClassDoc>(classes.length);
aoqi@0 758 for (ClassDoc classDoc : classes) {
aoqi@0 759 if (classDoc.isPrivate() || classDoc.isPackagePrivate()) {
aoqi@0 760 continue;
aoqi@0 761 }
aoqi@0 762 Tag[] aspTags = classDoc.tags("treatAsPrivate");
aoqi@0 763 if (aspTags != null && aspTags.length > 0) {
aoqi@0 764 continue;
aoqi@0 765 }
aoqi@0 766 filteredOutClasses.add(classDoc);
aoqi@0 767 }
aoqi@0 768
aoqi@0 769 return filteredOutClasses.toArray(new ClassDoc[0]);
aoqi@0 770 }
aoqi@0 771
aoqi@0 772 /**
aoqi@0 773 * Test whether the given FieldDoc is one of the declaration annotation ElementTypes
aoqi@0 774 * defined in Java 5.
aoqi@0 775 * Instead of testing for one of the new enum constants added in Java 8, test for
aoqi@0 776 * the old constants. This prevents bootstrapping problems.
aoqi@0 777 *
aoqi@0 778 * @param elt The FieldDoc to test
aoqi@0 779 * @return true, iff the given ElementType is one of the constants defined in Java 5
aoqi@0 780 * @since 1.8
aoqi@0 781 */
aoqi@0 782 public static boolean isJava5DeclarationElementType(FieldDoc elt) {
aoqi@0 783 return elt.name().contentEquals(ElementType.ANNOTATION_TYPE.name()) ||
aoqi@0 784 elt.name().contentEquals(ElementType.CONSTRUCTOR.name()) ||
aoqi@0 785 elt.name().contentEquals(ElementType.FIELD.name()) ||
aoqi@0 786 elt.name().contentEquals(ElementType.LOCAL_VARIABLE.name()) ||
aoqi@0 787 elt.name().contentEquals(ElementType.METHOD.name()) ||
aoqi@0 788 elt.name().contentEquals(ElementType.PACKAGE.name()) ||
aoqi@0 789 elt.name().contentEquals(ElementType.PARAMETER.name()) ||
aoqi@0 790 elt.name().contentEquals(ElementType.TYPE.name());
aoqi@0 791 }
aoqi@0 792 }

mercurial