All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.tools.javadoc.ClassDocImpl Maven / Gradle / Ivy

There is a newer version: 9-dev-r4023-3
Show newest version
/*
 * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.tools.javadoc;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.util.HashSet;
import java.util.Set;

import javax.tools.FileObject;
import javax.tools.JavaFileManager.Location;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;

import com.sun.javadoc.*;
import com.sun.source.util.TreePath;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Kinds;
import com.sun.tools.javac.code.Kinds.KindSelector;
import com.sun.tools.javac.code.Scope;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.ClassType;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCImport;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
import com.sun.tools.javac.util.Position;
import static com.sun.tools.javac.code.Kinds.Kind.*;
import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
import static com.sun.tools.javac.code.TypeTag.CLASS;
import static com.sun.tools.javac.tree.JCTree.Tag.*;

/**
 * Represents a java class and provides access to information
 * about the class, the class' comment and tags, and the
 * members of the class.  A ClassDocImpl only exists if it was
 * processed in this run of javadoc.  References to classes
 * which may or may not have been processed in this run are
 * referred to using Type (which can be converted to ClassDocImpl,
 * if possible).
 *
 *  

This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice. * * @see Type * * @since 1.2 * @author Robert Field * @author Neal Gafter (rewrite) * @author Scott Seligman (generics, enums, annotations) */ public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc { public final ClassType type; // protected->public for debugging protected final ClassSymbol tsym; boolean isIncluded = false; // Set in RootDocImpl private SerializedForm serializedForm; /** * Constructor */ public ClassDocImpl(DocEnv env, ClassSymbol sym) { this(env, sym, null); } /** * Constructor */ public ClassDocImpl(DocEnv env, ClassSymbol sym, TreePath treePath) { super(env, sym, treePath); this.type = (ClassType)sym.type; this.tsym = sym; } public com.sun.javadoc.Type getElementType() { return null; } /** * Returns the flags in terms of javac's flags */ protected long getFlags() { return getFlags(tsym); } /** * Returns the flags of a ClassSymbol in terms of javac's flags */ static long getFlags(ClassSymbol clazz) { try { return clazz.flags(); } catch (CompletionFailure ex) { /* Quietly ignore completion failures and try again - the type * for which the CompletionFailure was thrown shouldn't be completed * again by the completer that threw the CompletionFailure. */ return getFlags(clazz); } } /** * Is a ClassSymbol an annotation type? */ static boolean isAnnotationType(ClassSymbol clazz) { return (getFlags(clazz) & Flags.ANNOTATION) != 0; } /** * Identify the containing class */ protected ClassSymbol getContainingClass() { return tsym.owner.enclClass(); } /** * Return true if this is a class, not an interface. */ @Override public boolean isClass() { return !Modifier.isInterface(getModifiers()); } /** * Return true if this is a ordinary class, * not an enumeration, exception, an error, or an interface. */ @Override public boolean isOrdinaryClass() { if (isEnum() || isInterface() || isAnnotationType()) { return false; } for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) { if (t.tsym == env.syms.errorType.tsym || t.tsym == env.syms.exceptionType.tsym) { return false; } } return true; } /** * Return true if this is an enumeration. * (For legacy doclets, return false.) */ @Override public boolean isEnum() { return (getFlags() & Flags.ENUM) != 0 && !env.legacyDoclet; } /** * Return true if this is an interface, but not an annotation type. * Overridden by AnnotationTypeDocImpl. */ @Override public boolean isInterface() { return Modifier.isInterface(getModifiers()); } /** * Return true if this is an exception class */ @Override public boolean isException() { if (isEnum() || isInterface() || isAnnotationType()) { return false; } for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) { if (t.tsym == env.syms.exceptionType.tsym) { return true; } } return false; } /** * Return true if this is an error class */ @Override public boolean isError() { if (isEnum() || isInterface() || isAnnotationType()) { return false; } for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) { if (t.tsym == env.syms.errorType.tsym) { return true; } } return false; } /** * Return true if this is a throwable class */ public boolean isThrowable() { if (isEnum() || isInterface() || isAnnotationType()) { return false; } for (Type t = type; t.hasTag(CLASS); t = env.types.supertype(t)) { if (t.tsym == env.syms.throwableType.tsym) { return true; } } return false; } /** * Return true if this class is abstract */ public boolean isAbstract() { return Modifier.isAbstract(getModifiers()); } /** * Returns true if this class was synthesized by the compiler. */ public boolean isSynthetic() { return (getFlags() & Flags.SYNTHETIC) != 0; } /** * Return true if this class is included in the active set. * A ClassDoc is included iff either it is specified on the * commandline, or if it's containing package is specified * on the command line, or if it is a member class of an * included class. */ public boolean isIncluded() { if (isIncluded) { return true; } if (env.shouldDocument(tsym)) { // Class is nameable from top-level and // the class and all enclosing classes // pass the modifier filter. if (containingPackage().isIncluded()) { return isIncluded=true; } ClassDoc outer = containingClass(); if (outer != null && outer.isIncluded()) { return isIncluded=true; } } return false; } /** * Return the package that this class is contained in. */ @Override public PackageDoc containingPackage() { PackageDocImpl p = env.getPackageDoc(tsym.packge()); if (p.setDocPath == false) { FileObject docPath; try { Location location = env.fileManager.hasLocation(StandardLocation.SOURCE_PATH) ? StandardLocation.SOURCE_PATH : StandardLocation.CLASS_PATH; docPath = env.fileManager.getFileForInput( location, p.qualifiedName(), "package.html"); } catch (IOException e) { docPath = null; } if (docPath == null) { // fall back on older semantics of looking in same directory as // source file for this class SourcePosition po = position(); if (env.fileManager instanceof StandardJavaFileManager && po instanceof SourcePositionImpl) { URI uri = ((SourcePositionImpl) po).filename.toUri(); if ("file".equals(uri.getScheme())) { File f = new File(uri); File dir = f.getParentFile(); if (dir != null) { File pf = new File(dir, "package.html"); if (pf.exists()) { StandardJavaFileManager sfm = (StandardJavaFileManager) env.fileManager; docPath = sfm.getJavaFileObjects(pf).iterator().next(); } } } } } p.setDocPath(docPath); } return p; } /** * Return the class name without package qualifier - but with * enclosing class qualifier - as a String. *

     * Examples:
     *  for java.util.Hashtable
     *  return Hashtable
     *  for java.util.Map.Entry
     *  return Map.Entry
     * 
*/ public String name() { if (name == null) { name = getClassName(tsym, false); } return name; } private String name; /** * Return the qualified class name as a String. *
     * Example:
     *  for java.util.Hashtable
     *  return java.util.Hashtable
     *  if no qualifier, just return flat name
     * 
*/ public String qualifiedName() { if (qualifiedName == null) { qualifiedName = getClassName(tsym, true); } return qualifiedName; } private String qualifiedName; /** * Return unqualified name of type excluding any dimension information. *

* For example, a two dimensional array of String returns 'String'. */ public String typeName() { return name(); } /** * Return qualified name of type excluding any dimension information. *

* For example, a two dimensional array of String * returns 'java.lang.String'. */ public String qualifiedTypeName() { return qualifiedName(); } /** * Return the simple name of this type. */ public String simpleTypeName() { if (simpleTypeName == null) { simpleTypeName = tsym.name.toString(); } return simpleTypeName; } private String simpleTypeName; /** * Return the qualified name and any type parameters. * Each parameter is a type variable with optional bounds. */ @Override public String toString() { return classToString(env, tsym, true); } /** * Return the class name as a string. If "full" is true the name is * qualified, otherwise it is qualified by its enclosing class(es) only. */ static String getClassName(ClassSymbol c, boolean full) { if (full) { return c.getQualifiedName().toString(); } else { String n = ""; for ( ; c != null; c = c.owner.enclClass()) { n = c.name + (n.equals("") ? "" : ".") + n; } return n; } } /** * Return the class name with any type parameters as a string. * Each parameter is a type variable with optional bounds. * If "full" is true all names are qualified, otherwise they are * qualified by their enclosing class(es) only. */ static String classToString(DocEnv env, ClassSymbol c, boolean full) { StringBuilder s = new StringBuilder(); if (!c.isInner()) { // if c is not an inner class s.append(getClassName(c, full)); } else { // c is an inner class, so include type params of outer. ClassSymbol encl = c.owner.enclClass(); s.append(classToString(env, encl, full)) .append('.') .append(c.name); } s.append(TypeMaker.typeParametersString(env, c, full)); return s.toString(); } /** * Is this class (or any enclosing class) generic? That is, does * it have type parameters? */ static boolean isGeneric(ClassSymbol c) { return c.type.allparams().nonEmpty(); } /** * Return the formal type parameters of this class or interface. * Return an empty array if there are none. */ public TypeVariable[] typeParameters() { if (env.legacyDoclet) { return new TypeVariable[0]; } TypeVariable res[] = new TypeVariable[type.getTypeArguments().length()]; TypeMaker.getTypes(env, type.getTypeArguments(), res); return res; } /** * Return the type parameter tags of this class or interface. */ public ParamTag[] typeParamTags() { return (env.legacyDoclet) ? new ParamTag[0] : comment().typeParamTags(); } /** * Return the modifier string for this class. If it's an interface * exclude 'abstract' keyword from the modifier string */ @Override public String modifiers() { return Modifier.toString(modifierSpecifier()); } @Override public int modifierSpecifier() { int modifiers = getModifiers(); return (isInterface() || isAnnotationType()) ? modifiers & ~Modifier.ABSTRACT : modifiers; } /** * Return the superclass of this class * * @return the ClassDocImpl for the superclass of this class, null * if there is no superclass. */ public ClassDoc superclass() { if (isInterface() || isAnnotationType()) return null; if (tsym == env.syms.objectType.tsym) return null; ClassSymbol c = (ClassSymbol)env.types.supertype(type).tsym; if (c == null || c == tsym) c = (ClassSymbol)env.syms.objectType.tsym; return env.getClassDoc(c); } /** * Return the superclass of this class. Return null if this is an * interface. A superclass is represented by either a * ClassDoc or a ParameterizedType. */ public com.sun.javadoc.Type superclassType() { if (isInterface() || isAnnotationType() || (tsym == env.syms.objectType.tsym)) return null; Type sup = env.types.supertype(type); return TypeMaker.getType(env, (sup.hasTag(TypeTag.NONE)) ? env.syms.objectType : sup); } /** * Test whether this class is a subclass of the specified class. * * @param cd the candidate superclass. * @return true if cd is a superclass of this class. */ public boolean subclassOf(ClassDoc cd) { return tsym.isSubClass(((ClassDocImpl)cd).tsym, env.types); } /** * Return interfaces implemented by this class or interfaces * extended by this interface. * * @return An array of ClassDocImpl representing the interfaces. * Return an empty array if there are no interfaces. */ public ClassDoc[] interfaces() { ListBuffer ta = new ListBuffer<>(); for (Type t : env.types.interfaces(type)) { ta.append(env.getClassDoc((ClassSymbol)t.tsym)); } //### Cache ta here? return ta.toArray(new ClassDocImpl[ta.length()]); } /** * Return interfaces implemented by this class or interfaces extended * by this interface. Includes only directly-declared interfaces, not * inherited interfaces. * Return an empty array if there are no interfaces. */ public com.sun.javadoc.Type[] interfaceTypes() { //### Cache result here? return TypeMaker.getTypes(env, env.types.interfaces(type)); } /** * Return fields in class. * @param filter include only the included fields if filter==true */ public FieldDoc[] fields(boolean filter) { return fields(filter, false); } /** * Return included fields in class. */ public FieldDoc[] fields() { return fields(true, false); } /** * Return the enum constants if this is an enum type. */ public FieldDoc[] enumConstants() { return fields(false, true); } /** * Return fields in class. * @param filter if true, return only the included fields * @param enumConstants if true, return the enum constants instead */ private FieldDoc[] fields(boolean filter, boolean enumConstants) { List fields = List.nil(); for (Symbol sym : tsym.members().getSymbols(NON_RECURSIVE)) { if (sym != null && sym.kind == VAR) { VarSymbol s = (VarSymbol)sym; boolean isEnum = ((s.flags() & Flags.ENUM) != 0) && !env.legacyDoclet; if (isEnum == enumConstants && (!filter || env.shouldDocument(s))) { fields = fields.prepend(env.getFieldDoc(s)); } } } return fields.toArray(new FieldDocImpl[fields.length()]); } /** * Return methods in class. * This method is overridden by AnnotationTypeDocImpl. * * @param filter include only the included methods if filter==true * @return an array of MethodDocImpl for representing the visible * methods in this class. Does not include constructors. */ public MethodDoc[] methods(boolean filter) { Names names = tsym.name.table.names; List methods = List.nil(); for (Symbol sym :tsym.members().getSymbols(NON_RECURSIVE)) { if (sym != null && sym.kind == MTH && sym.name != names.init && sym.name != names.clinit) { MethodSymbol s = (MethodSymbol)sym; if (!filter || env.shouldDocument(s)) { methods = methods.prepend(env.getMethodDoc(s)); } } } //### Cache methods here? return methods.toArray(new MethodDocImpl[methods.length()]); } /** * Return included methods in class. * * @return an array of MethodDocImpl for representing the visible * methods in this class. Does not include constructors. */ public MethodDoc[] methods() { return methods(true); } /** * Return constructors in class. * * @param filter include only the included constructors if filter==true * @return an array of ConstructorDocImpl for representing the visible * constructors in this class. */ public ConstructorDoc[] constructors(boolean filter) { Names names = tsym.name.table.names; List constructors = List.nil(); for (Symbol sym : tsym.members().getSymbols(NON_RECURSIVE)) { if (sym != null && sym.kind == MTH && sym.name == names.init) { MethodSymbol s = (MethodSymbol)sym; if (!filter || env.shouldDocument(s)) { constructors = constructors.prepend(env.getConstructorDoc(s)); } } } //### Cache constructors here? return constructors.toArray(new ConstructorDocImpl[constructors.length()]); } /** * Return included constructors in class. * * @return an array of ConstructorDocImpl for representing the visible * constructors in this class. */ public ConstructorDoc[] constructors() { return constructors(true); } /** * Adds all inner classes of this class, and their * inner classes recursively, to the list l. */ void addAllClasses(ListBuffer l, boolean filtered) { try { if (isSynthetic()) return; // sometimes synthetic classes are not marked synthetic if (!JavadocTool.isValidClassName(tsym.name.toString())) return; if (filtered && !env.shouldDocument(tsym)) return; if (l.contains(this)) return; l.append(this); List more = List.nil(); for (Symbol sym : tsym.members().getSymbols(NON_RECURSIVE)) { if (sym != null && sym.kind == TYP) { ClassSymbol s = (ClassSymbol)sym; ClassDocImpl c = env.getClassDoc(s); if (c.isSynthetic()) continue; if (c != null) more = more.prepend(c); } } // this extra step preserves the ordering from oldjavadoc for (; more.nonEmpty(); more=more.tail) { more.head.addAllClasses(l, filtered); } } catch (CompletionFailure e) { // quietly ignore completion failures } } /** * Return inner classes within this class. * * @param filter include only the included inner classes if filter==true. * @return an array of ClassDocImpl for representing the visible * classes defined in this class. Anonymous and local classes * are not included. */ public ClassDoc[] innerClasses(boolean filter) { ListBuffer innerClasses = new ListBuffer<>(); for (Symbol sym : tsym.members().getSymbols(NON_RECURSIVE)) { if (sym != null && sym.kind == TYP) { ClassSymbol s = (ClassSymbol)sym; if ((s.flags_field & Flags.SYNTHETIC) != 0) continue; if (!filter || env.isVisible(s)) { innerClasses.prepend(env.getClassDoc(s)); } } } //### Cache classes here? return innerClasses.toArray(new ClassDocImpl[innerClasses.length()]); } /** * Return included inner classes within this class. * * @return an array of ClassDocImpl for representing the visible * classes defined in this class. Anonymous and local classes * are not included. */ public ClassDoc[] innerClasses() { return innerClasses(true); } /** * Find a class within the context of this class. * Search order: qualified name, in this class (inner), * in this package, in the class imports, in the package * imports. * Return the ClassDocImpl if found, null if not found. */ //### The specified search order is not the normal rule the //### compiler would use. Leave as specified or change it? public ClassDoc findClass(String className) { ClassDoc searchResult = searchClass(className); if (searchResult == null) { ClassDocImpl enclosingClass = (ClassDocImpl)containingClass(); //Expand search space to include enclosing class. while (enclosingClass != null && enclosingClass.containingClass() != null) { enclosingClass = (ClassDocImpl)enclosingClass.containingClass(); } searchResult = enclosingClass == null ? null : enclosingClass.searchClass(className); } return searchResult; } private ClassDoc searchClass(String className) { Names names = tsym.name.table.names; // search by qualified name first ClassDoc cd = env.lookupClass(className); if (cd != null) { return cd; } // search inner classes //### Add private entry point to avoid creating array? //### Replicate code in innerClasses here to avoid consing? for (ClassDoc icd : innerClasses()) { if (icd.name().equals(className) || //### This is from original javadoc but it looks suspicious to me... //### I believe it is attempting to compensate for the confused //### convention of including the nested class qualifiers in the //### 'name' of the inner class, rather than the true simple name. icd.name().endsWith("." + className)) { return icd; } else { ClassDoc innercd = ((ClassDocImpl) icd).searchClass(className); if (innercd != null) { return innercd; } } } // check in this package cd = containingPackage().findClass(className); if (cd != null) { return cd; } // make sure that this symbol has been completed tsym.complete(); // search imports if (tsym.sourcefile != null) { //### This information is available only for source classes. Env compenv = env.enter.getEnv(tsym); if (compenv == null) return null; Scope s = compenv.toplevel.namedImportScope; for (Symbol sym : s.getSymbolsByName(names.fromString(className))) { if (sym.kind == TYP) { ClassDoc c = env.getClassDoc((ClassSymbol)sym); return c; } } s = compenv.toplevel.starImportScope; for (Symbol sym : s.getSymbolsByName(names.fromString(className))) { if (sym.kind == TYP) { ClassDoc c = env.getClassDoc((ClassSymbol)sym); return c; } } } return null; // not found } private boolean hasParameterTypes(MethodSymbol method, String[] argTypes) { if (argTypes == null) { // wildcard return true; } int i = 0; List types = method.type.getParameterTypes(); if (argTypes.length != types.length()) { return false; } for (Type t : types) { String argType = argTypes[i++]; // For vararg method, "T..." matches type T[]. if (i == argTypes.length) { argType = argType.replace("...", "[]"); } if (!hasTypeName(env.types.erasure(t), argType)) { //###(gj) return false; } } return true; } // where private boolean hasTypeName(Type t, String name) { return name.equals(TypeMaker.getTypeName(t, true)) || name.equals(TypeMaker.getTypeName(t, false)) || (qualifiedName() + "." + name).equals(TypeMaker.getTypeName(t, true)); } /** * Find a method in this class scope. * Search order: this class, interfaces, superclasses, outerclasses. * Note that this is not necessarily what the compiler would do! * * @param methodName the unqualified name to search for. * @param paramTypes the array of Strings for method parameter types. * @return the first MethodDocImpl which matches, null if not found. */ public MethodDocImpl findMethod(String methodName, String[] paramTypes) { // Use hash table 'searched' to avoid searching same class twice. //### It is not clear how this could happen. return searchMethod(methodName, paramTypes, new HashSet()); } private MethodDocImpl searchMethod(String methodName, String[] paramTypes, Set searched) { //### Note that this search is not necessarily what the compiler would do! Names names = tsym.name.table.names; // do not match constructors if (names.init.contentEquals(methodName)) { return null; } ClassDocImpl cdi; MethodDocImpl mdi; if (searched.contains(this)) { return null; } searched.add(this); //DEBUG /*---------------------------------* System.out.print("searching " + this + " for " + methodName); if (paramTypes == null) { System.out.println("()"); } else { System.out.print("("); for (int k=0; k < paramTypes.length; k++) { System.out.print(paramTypes[k]); if ((k + 1) < paramTypes.length) { System.out.print(", "); } } System.out.println(")"); } *---------------------------------*/ // search current class //### Using modifier filter here isn't really correct, //### but emulates the old behavior. Instead, we should //### apply the normal rules of visibility and inheritance. if (paramTypes == null) { // If no parameters specified, we are allowed to return // any method with a matching name. In practice, the old // code returned the first method, which is now the last! // In order to provide textually identical results, we // attempt to emulate the old behavior. MethodSymbol lastFound = null; for (Symbol sym : tsym.members().getSymbolsByName(names.fromString(methodName))) { if (sym.kind == MTH) { //### Should intern methodName as Name. if (sym.name.toString().equals(methodName)) { lastFound = (MethodSymbol)sym; } } } if (lastFound != null) { return env.getMethodDoc(lastFound); } } else { for (Symbol sym : tsym.members().getSymbolsByName(names.fromString(methodName))) { if (sym != null && sym.kind == MTH) { //### Should intern methodName as Name. if (hasParameterTypes((MethodSymbol)sym, paramTypes)) { return env.getMethodDoc((MethodSymbol)sym); } } } } //### If we found a MethodDoc above, but which did not pass //### the modifier filter, we should return failure here! // search superclass cdi = (ClassDocImpl)superclass(); if (cdi != null) { mdi = cdi.searchMethod(methodName, paramTypes, searched); if (mdi != null) { return mdi; } } // search interfaces for (ClassDoc intf : interfaces()) { cdi = (ClassDocImpl) intf; mdi = cdi.searchMethod(methodName, paramTypes, searched); if (mdi != null) { return mdi; } } // search enclosing class cdi = (ClassDocImpl)containingClass(); if (cdi != null) { mdi = cdi.searchMethod(methodName, paramTypes, searched); if (mdi != null) { return mdi; } } //###(gj) As a temporary measure until type variables are better //### handled, try again without the parameter types. //### This should most often find the right method, and occassionally //### find the wrong one. //if (paramTypes != null) { // return findMethod(methodName, null); //} return null; } /** * Find constructor in this class. * * @param constrName the unqualified name to search for. * @param paramTypes the array of Strings for constructor parameters. * @return the first ConstructorDocImpl which matches, null if not found. */ public ConstructorDoc findConstructor(String constrName, String[] paramTypes) { Names names = tsym.name.table.names; for (Symbol sym : tsym.members().getSymbolsByName(names.fromString(""))) { if (sym.kind == MTH) { if (hasParameterTypes((MethodSymbol)sym, paramTypes)) { return env.getConstructorDoc((MethodSymbol)sym); } } } //###(gj) As a temporary measure until type variables are better //### handled, try again without the parameter types. //### This will often find the right constructor, and occassionally //### find the wrong one. //if (paramTypes != null) { // return findConstructor(constrName, null); //} return null; } /** * Find a field in this class scope. * Search order: this class, outerclasses, interfaces, * superclasses. IMP: If see tag is defined in an inner class, * which extends a super class and if outerclass and the super * class have a visible field in common then Java compiler cribs * about the ambiguity, but the following code will search in the * above given search order. * * @param fieldName the unqualified name to search for. * @return the first FieldDocImpl which matches, null if not found. */ public FieldDoc findField(String fieldName) { return searchField(fieldName, new HashSet()); } private FieldDocImpl searchField(String fieldName, Set searched) { Names names = tsym.name.table.names; if (searched.contains(this)) { return null; } searched.add(this); for (Symbol sym : tsym.members().getSymbolsByName(names.fromString(fieldName))) { if (sym.kind == VAR) { //### Should intern fieldName as Name. return env.getFieldDoc((VarSymbol)sym); } } //### If we found a FieldDoc above, but which did not pass //### the modifier filter, we should return failure here! ClassDocImpl cdi = (ClassDocImpl)containingClass(); if (cdi != null) { FieldDocImpl fdi = cdi.searchField(fieldName, searched); if (fdi != null) { return fdi; } } // search superclass cdi = (ClassDocImpl)superclass(); if (cdi != null) { FieldDocImpl fdi = cdi.searchField(fieldName, searched); if (fdi != null) { return fdi; } } // search interfaces for (ClassDoc intf : interfaces()) { cdi = (ClassDocImpl) intf; FieldDocImpl fdi = cdi.searchField(fieldName, searched); if (fdi != null) { return fdi; } } return null; } /** * Get the list of classes declared as imported. * These are called "single-type-import declarations" in the JLS. * This method is deprecated in the ClassDoc interface. * * @return an array of ClassDocImpl representing the imported classes. * * @deprecated Import declarations are implementation details that * should not be exposed here. In addition, not all imported * classes are imported through single-type-import declarations. */ @Deprecated public ClassDoc[] importedClasses() { // information is not available for binary classfiles if (tsym.sourcefile == null) return new ClassDoc[0]; ListBuffer importedClasses = new ListBuffer<>(); Env compenv = env.enter.getEnv(tsym); if (compenv == null) return new ClassDocImpl[0]; Name asterisk = tsym.name.table.names.asterisk; for (JCTree t : compenv.toplevel.defs) { if (t.hasTag(IMPORT)) { JCTree imp = ((JCImport) t).qualid; if ((TreeInfo.name(imp) != asterisk) && imp.type.tsym.kind.matches(KindSelector.TYP)) { importedClasses.append( env.getClassDoc((ClassSymbol)imp.type.tsym)); } } } return importedClasses.toArray(new ClassDocImpl[importedClasses.length()]); } /** * Get the list of packages declared as imported. * These are called "type-import-on-demand declarations" in the JLS. * This method is deprecated in the ClassDoc interface. * * @return an array of PackageDocImpl representing the imported packages. * * ###NOTE: the syntax supports importing all inner classes from a class as well. * @deprecated Import declarations are implementation details that * should not be exposed here. In addition, this method's * return type does not allow for all type-import-on-demand * declarations to be returned. */ @Deprecated public PackageDoc[] importedPackages() { // information is not available for binary classfiles if (tsym.sourcefile == null) return new PackageDoc[0]; ListBuffer importedPackages = new ListBuffer<>(); //### Add the implicit "import java.lang.*" to the result Names names = tsym.name.table.names; importedPackages.append(env.getPackageDoc(env.syms.enterPackage(names.java_lang))); Env compenv = env.enter.getEnv(tsym); if (compenv == null) return new PackageDocImpl[0]; for (JCTree t : compenv.toplevel.defs) { if (t.hasTag(IMPORT)) { JCTree imp = ((JCImport) t).qualid; if (TreeInfo.name(imp) == names.asterisk) { JCFieldAccess sel = (JCFieldAccess)imp; Symbol s = sel.selected.type.tsym; PackageDocImpl pdoc = env.getPackageDoc(s.packge()); if (!importedPackages.contains(pdoc)) importedPackages.append(pdoc); } } } return importedPackages.toArray(new PackageDocImpl[importedPackages.length()]); } /** * Return the type's dimension information. * Always return "", as this is not an array type. */ public String dimension() { return ""; } /** * Return this type as a class, which it already is. */ public ClassDoc asClassDoc() { return this; } /** * Return null (unless overridden), as this is not an annotation type. */ public AnnotationTypeDoc asAnnotationTypeDoc() { return null; } /** * Return null, as this is not a class instantiation. */ public ParameterizedType asParameterizedType() { return null; } /** * Return null, as this is not a type variable. */ public TypeVariable asTypeVariable() { return null; } /** * Return null, as this is not a wildcard type. */ public WildcardType asWildcardType() { return null; } /** * Returns null, as this is not an annotated type. */ public AnnotatedType asAnnotatedType() { return null; } /** * Return false, as this is not a primitive type. */ public boolean isPrimitive() { return false; } //--- Serialization --- //### These methods ignore modifier filter. /** * Return true if this class implements java.io.Serializable. * * Since java.io.Externalizable extends * java.io.Serializable, * Externalizable objects are also Serializable. */ public boolean isSerializable() { try { return env.types.isSubtype(type, env.syms.serializableType); } catch (CompletionFailure ex) { // quietly ignore completion failures return false; } } /** * Return true if this class implements * java.io.Externalizable. */ public boolean isExternalizable() { try { return env.types.isSubtype(type, env.externalizableSym.type); } catch (CompletionFailure ex) { // quietly ignore completion failures return false; } } /** * Return the serialization methods for this class. * * @return an array of MethodDocImpl that represents * the serialization methods for this class. */ public MethodDoc[] serializationMethods() { if (serializedForm == null) { serializedForm = new SerializedForm(env, tsym, this); } //### Clone this? return serializedForm.methods(); } /** * Return the Serializable fields of class.

* * Return either a list of default fields documented by * serial tag
* or return a single FieldDoc for * serialPersistentField member. * There should be a serialField tag for * each Serializable field defined by an ObjectStreamField * array component of serialPersistentField. * * @return an array of {@code FieldDoc} for the Serializable fields * of this class. * * @see #definesSerializableFields() * @see SerialFieldTagImpl */ public FieldDoc[] serializableFields() { if (serializedForm == null) { serializedForm = new SerializedForm(env, tsym, this); } //### Clone this? return serializedForm.fields(); } /** * Return true if Serializable fields are explicitly defined with * the special class member serialPersistentFields. * * @see #serializableFields() * @see SerialFieldTagImpl */ public boolean definesSerializableFields() { if (!isSerializable() || isExternalizable()) { return false; } else { if (serializedForm == null) { serializedForm = new SerializedForm(env, tsym, this); } //### Clone this? return serializedForm.definesSerializableFields(); } } /** * Determine if a class is a RuntimeException. *

* Used only by ThrowsTagImpl. */ boolean isRuntimeException() { return tsym.isSubClass(env.syms.runtimeExceptionType.tsym, env.types); } /** * Return the source position of the entity, or null if * no position is available. */ @Override public SourcePosition position() { if (tsym.sourcefile == null) return null; return SourcePositionImpl.make(tsym.sourcefile, (tree==null) ? Position.NOPOS : tree.pos, lineMap); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy