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

Tue, 17 Dec 2013 10:55:59 +0100

author
jlahoda
date
Tue, 17 Dec 2013 10:55:59 +0100
changeset 2413
fe033d997ddf
parent 1985
0e6577980181
child 2525
2eb010b6cb22
permissions
-rw-r--r--

8029800: Flags.java uses String.toLowerCase without specifying Locale
Summary: Introducing StringUtils.toLowerCase/toUpperCase independent on the default locale, converting almost all usages of String.toLowerCase/toUpperCase to use the new methods.
Reviewed-by: jjg, bpatel

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

mercurial