aoqi@0: /* aoqi@0: * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.tools.doclets.internal.toolkit.util; aoqi@0: aoqi@0: import java.io.*; aoqi@0: import java.lang.annotation.ElementType; aoqi@0: import java.util.*; aoqi@0: import javax.tools.StandardLocation; aoqi@0: aoqi@0: import com.sun.javadoc.*; aoqi@0: import com.sun.javadoc.AnnotationDesc.ElementValuePair; aoqi@0: import com.sun.tools.doclets.internal.toolkit.*; aoqi@0: import com.sun.tools.javac.util.StringUtils; aoqi@0: aoqi@0: /** aoqi@0: * Utilities Class for Doclets. aoqi@0: * aoqi@0: *
This is NOT part of any supported API.
aoqi@0: * If you write code that depends on this, you do so at your own risk.
aoqi@0: * This code and its internal interfaces are subject to change or
aoqi@0: * deletion without notice.
aoqi@0: *
aoqi@0: * @author Atul M Dambalkar
aoqi@0: * @author Jamie Ho
aoqi@0: */
aoqi@0: public class Util {
aoqi@0:
aoqi@0: /**
aoqi@0: * Return array of class members whose documentation is to be generated.
aoqi@0: * If the member is deprecated do not include such a member in the
aoqi@0: * returned array.
aoqi@0: *
aoqi@0: * @param members Array of members to choose from.
aoqi@0: * @return ProgramElementDoc[] Array of eligible members for whom
aoqi@0: * documentation is getting generated.
aoqi@0: */
aoqi@0: public static ProgramElementDoc[] excludeDeprecatedMembers(
aoqi@0: ProgramElementDoc[] members) {
aoqi@0: return
aoqi@0: toProgramElementDocArray(excludeDeprecatedMembersAsList(members));
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return array of class members whose documentation is to be generated.
aoqi@0: * If the member is deprecated do not include such a member in the
aoqi@0: * returned array.
aoqi@0: *
aoqi@0: * @param members Array of members to choose from.
aoqi@0: * @return List List of eligible members for whom
aoqi@0: * documentation is getting generated.
aoqi@0: */
aoqi@0: public static List
aoqi@0: * NOTE: You can only link to external classes if they are public or
aoqi@0: * protected.
aoqi@0: *
aoqi@0: * @param classDoc the class to check.
aoqi@0: * @param configuration the current configuration of the doclet.
aoqi@0: *
aoqi@0: * @return true if this class is linkable and false if we can't link to the
aoqi@0: * desired class.
aoqi@0: */
aoqi@0: public static boolean isLinkable(ClassDoc classDoc,
aoqi@0: Configuration configuration) {
aoqi@0: return
aoqi@0: ((classDoc.isIncluded() && configuration.isGeneratedDoc(classDoc))) ||
aoqi@0: (configuration.extern.isExternal(classDoc) &&
aoqi@0: (classDoc.isPublic() || classDoc.isProtected()));
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Given a class, return the closest visible super class.
aoqi@0: *
aoqi@0: * @param classDoc the class we are searching the parent for.
aoqi@0: * @param configuration the current configuration of the doclet.
aoqi@0: * @return the closest visible super class. Return null if it cannot
aoqi@0: * be found (i.e. classDoc is java.lang.Object).
aoqi@0: */
aoqi@0: public static Type getFirstVisibleSuperClass(ClassDoc classDoc,
aoqi@0: Configuration configuration) {
aoqi@0: if (classDoc == null) {
aoqi@0: return null;
aoqi@0: }
aoqi@0: Type sup = classDoc.superclassType();
aoqi@0: ClassDoc supClassDoc = classDoc.superclass();
aoqi@0: while (sup != null &&
aoqi@0: (! (supClassDoc.isPublic() ||
aoqi@0: isLinkable(supClassDoc, configuration))) ) {
aoqi@0: if (supClassDoc.superclass().qualifiedName().equals(supClassDoc.qualifiedName()))
aoqi@0: break;
aoqi@0: sup = supClassDoc.superclassType();
aoqi@0: supClassDoc = supClassDoc.superclass();
aoqi@0: }
aoqi@0: if (classDoc.equals(supClassDoc)) {
aoqi@0: return null;
aoqi@0: }
aoqi@0: return sup;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Given a class, return the closest visible super class.
aoqi@0: *
aoqi@0: * @param classDoc the class we are searching the parent for.
aoqi@0: * @param configuration the current configuration of the doclet.
aoqi@0: * @return the closest visible super class. Return null if it cannot
aoqi@0: * be found (i.e. classDoc is java.lang.Object).
aoqi@0: */
aoqi@0: public static ClassDoc getFirstVisibleSuperClassCD(ClassDoc classDoc,
aoqi@0: Configuration configuration) {
aoqi@0: if (classDoc == null) {
aoqi@0: return null;
aoqi@0: }
aoqi@0: ClassDoc supClassDoc = classDoc.superclass();
aoqi@0: while (supClassDoc != null &&
aoqi@0: (! (supClassDoc.isPublic() ||
aoqi@0: isLinkable(supClassDoc, configuration))) ) {
aoqi@0: supClassDoc = supClassDoc.superclass();
aoqi@0: }
aoqi@0: if (classDoc.equals(supClassDoc)) {
aoqi@0: return null;
aoqi@0: }
aoqi@0: return supClassDoc;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Given a ClassDoc, return the name of its type (Class, Interface, etc.).
aoqi@0: *
aoqi@0: * @param cd the ClassDoc to check.
aoqi@0: * @param lowerCaseOnly true if you want the name returned in lower case.
aoqi@0: * If false, the first letter of the name is capitalized.
aoqi@0: * @return
aoqi@0: */
aoqi@0: public static String getTypeName(Configuration config,
aoqi@0: ClassDoc cd, boolean lowerCaseOnly) {
aoqi@0: String typeName = "";
aoqi@0: if (cd.isOrdinaryClass()) {
aoqi@0: typeName = "doclet.Class";
aoqi@0: } else if (cd.isInterface()) {
aoqi@0: typeName = "doclet.Interface";
aoqi@0: } else if (cd.isException()) {
aoqi@0: typeName = "doclet.Exception";
aoqi@0: } else if (cd.isError()) {
aoqi@0: typeName = "doclet.Error";
aoqi@0: } else if (cd.isAnnotationType()) {
aoqi@0: typeName = "doclet.AnnotationType";
aoqi@0: } else if (cd.isEnum()) {
aoqi@0: typeName = "doclet.Enum";
aoqi@0: }
aoqi@0: return config.getText(
aoqi@0: lowerCaseOnly ? StringUtils.toLowerCase(typeName) : typeName);
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Replace all tabs in a string with the appropriate number of spaces.
aoqi@0: * The string may be a multi-line string.
aoqi@0: * @param configuration the doclet configuration defining the setting for the
aoqi@0: * tab length.
aoqi@0: * @param text the text for which the tabs should be expanded
aoqi@0: * @return the text with all tabs expanded
aoqi@0: */
aoqi@0: public static String replaceTabs(Configuration configuration, String text) {
aoqi@0: if (text.indexOf("\t") == -1)
aoqi@0: return text;
aoqi@0:
aoqi@0: final int tabLength = configuration.sourcetab;
aoqi@0: final String whitespace = configuration.tabSpaces;
aoqi@0: final int textLength = text.length();
aoqi@0: StringBuilder result = new StringBuilder(textLength);
aoqi@0: int pos = 0;
aoqi@0: int lineLength = 0;
aoqi@0: for (int i = 0; i < textLength; i++) {
aoqi@0: char ch = text.charAt(i);
aoqi@0: switch (ch) {
aoqi@0: case '\n': case '\r':
aoqi@0: lineLength = 0;
aoqi@0: break;
aoqi@0: case '\t':
aoqi@0: result.append(text, pos, i);
aoqi@0: int spaceCount = tabLength - lineLength % tabLength;
aoqi@0: result.append(whitespace, 0, spaceCount);
aoqi@0: lineLength += spaceCount;
aoqi@0: pos = i + 1;
aoqi@0: break;
aoqi@0: default:
aoqi@0: lineLength++;
aoqi@0: }
aoqi@0: }
aoqi@0: result.append(text, pos, textLength);
aoqi@0: return result.toString();
aoqi@0: }
aoqi@0:
aoqi@0: public static String normalizeNewlines(String text) {
aoqi@0: StringBuilder sb = new StringBuilder();
aoqi@0: final int textLength = text.length();
aoqi@0: final String NL = DocletConstants.NL;
aoqi@0: int pos = 0;
aoqi@0: for (int i = 0; i < textLength; i++) {
aoqi@0: char ch = text.charAt(i);
aoqi@0: switch (ch) {
aoqi@0: case '\n':
aoqi@0: sb.append(text, pos, i);
aoqi@0: sb.append(NL);
aoqi@0: pos = i + 1;
aoqi@0: break;
aoqi@0: case '\r':
aoqi@0: sb.append(text, pos, i);
aoqi@0: sb.append(NL);
aoqi@0: if (i + 1 < textLength && text.charAt(i + 1) == '\n')
aoqi@0: i++;
aoqi@0: pos = i + 1;
aoqi@0: break;
aoqi@0: }
aoqi@0: }
aoqi@0: sb.append(text, pos, textLength);
aoqi@0: return sb.toString();
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * The documentation for values() and valueOf() in Enums are set by the
aoqi@0: * doclet.
aoqi@0: */
aoqi@0: public static void setEnumDocumentation(Configuration configuration,
aoqi@0: ClassDoc classDoc) {
aoqi@0: MethodDoc[] methods = classDoc.methods();
aoqi@0: for (int j = 0; j < methods.length; j++) {
aoqi@0: MethodDoc currentMethod = methods[j];
aoqi@0: if (currentMethod.name().equals("values") &&
aoqi@0: currentMethod.parameters().length == 0) {
aoqi@0: StringBuilder sb = new StringBuilder();
aoqi@0: sb.append(configuration.getText("doclet.enum_values_doc.main", classDoc.name()));
aoqi@0: sb.append("\n@return ");
aoqi@0: sb.append(configuration.getText("doclet.enum_values_doc.return"));
aoqi@0: currentMethod.setRawCommentText(sb.toString());
aoqi@0: } else if (currentMethod.name().equals("valueOf") &&
aoqi@0: currentMethod.parameters().length == 1) {
aoqi@0: Type paramType = currentMethod.parameters()[0].type();
aoqi@0: if (paramType != null &&
aoqi@0: paramType.qualifiedTypeName().equals(String.class.getName())) {
aoqi@0: StringBuilder sb = new StringBuilder();
aoqi@0: sb.append(configuration.getText("doclet.enum_valueof_doc.main", classDoc.name()));
aoqi@0: sb.append("\n@param name ");
aoqi@0: sb.append(configuration.getText("doclet.enum_valueof_doc.param_name"));
aoqi@0: sb.append("\n@return ");
aoqi@0: sb.append(configuration.getText("doclet.enum_valueof_doc.return"));
aoqi@0: sb.append("\n@throws IllegalArgumentException ");
aoqi@0: sb.append(configuration.getText("doclet.enum_valueof_doc.throws_ila"));
aoqi@0: sb.append("\n@throws NullPointerException ");
aoqi@0: sb.append(configuration.getText("doclet.enum_valueof_doc.throws_npe"));
aoqi@0: currentMethod.setRawCommentText(sb.toString());
aoqi@0: }
aoqi@0: }
aoqi@0: }
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Return true if the given Doc is deprecated.
aoqi@0: *
aoqi@0: * @param doc the Doc to check.
aoqi@0: * @return true if the given Doc is deprecated.
aoqi@0: */
aoqi@0: public static boolean isDeprecated(Doc doc) {
aoqi@0: if (doc.tags("deprecated").length > 0) {
aoqi@0: return true;
aoqi@0: }
aoqi@0: AnnotationDesc[] annotationDescList;
aoqi@0: if (doc instanceof PackageDoc)
aoqi@0: annotationDescList = ((PackageDoc)doc).annotations();
aoqi@0: else
aoqi@0: annotationDescList = ((ProgramElementDoc)doc).annotations();
aoqi@0: for (int i = 0; i < annotationDescList.length; i++) {
aoqi@0: if (annotationDescList[i].annotationType().qualifiedName().equals(
aoqi@0: java.lang.Deprecated.class.getName())){
aoqi@0: return true;
aoqi@0: }
aoqi@0: }
aoqi@0: return false;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * A convenience method to get property name from the name of the
aoqi@0: * getter or setter method.
aoqi@0: * @param name name of the getter or setter method.
aoqi@0: * @return the name of the property of the given setter of getter.
aoqi@0: */
aoqi@0: public static String propertyNameFromMethodName(Configuration configuration, String name) {
aoqi@0: String propertyName = null;
aoqi@0: if (name.startsWith("get") || name.startsWith("set")) {
aoqi@0: propertyName = name.substring(3);
aoqi@0: } else if (name.startsWith("is")) {
aoqi@0: propertyName = name.substring(2);
aoqi@0: }
aoqi@0: if ((propertyName == null) || propertyName.isEmpty()){
aoqi@0: return "";
aoqi@0: }
aoqi@0: return propertyName.substring(0, 1).toLowerCase(configuration.getLocale())
aoqi@0: + propertyName.substring(1);
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * In case of JavaFX mode on, filters out classes that are private,
aoqi@0: * package private or having the @treatAsPrivate annotation. Those are not
aoqi@0: * documented in JavaFX mode.
aoqi@0: *
aoqi@0: * @param classes array of classes to be filtered.
aoqi@0: * @param javafx set to true if in JavaFX mode.
aoqi@0: * @return list of filtered classes.
aoqi@0: */
aoqi@0: public static ClassDoc[] filterOutPrivateClasses(final ClassDoc[] classes,
aoqi@0: boolean javafx) {
aoqi@0: if (!javafx) {
aoqi@0: return classes;
aoqi@0: }
aoqi@0: final List