/* gnu.classpath.tools.gjdoc.ClassDocImpl Copyright (C) 2001 Free Software Foundation, Inc. This file is part of GNU Classpath. GNU Classpath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Classpath 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 for more details. You should have received a copy of the GNU General Public License along with GNU Classpath; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ package gnu.classpath.tools.gjdoc; import com.sun.javadoc.*; import java.util.*; import java.io.*; import gnu.classpath.tools.gjdoc.expr.EvaluatorEnvironment; import gnu.classpath.tools.gjdoc.expr.CircularExpressionException; import gnu.classpath.tools.gjdoc.expr.IllegalExpressionException; import gnu.classpath.tools.gjdoc.expr.UnknownIdentifierException; public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc, WritableType, EvaluatorEnvironment { private ClassDoc baseClassDoc; private ClassDoc[] importedClasses; private PackageDoc[] importedPackages; private boolean definesSerializableFields; private FieldDoc[] serialPersistentField; private MethodDoc[] serializationMethods; private String dimension = ""; public ClassDocImpl(ClassDoc containingClass, PackageDoc containingPackage, int accessLevel, boolean isFinal, boolean isStatic, SourcePosition position) { super(containingClass, containingPackage, accessLevel, isFinal, isStatic, position); this.baseClassDoc = this; } public ClassDocImpl(ClassDoc containingClass, PackageDoc containingPackage, ClassDoc[] importedClasses, PackageDoc[] importedPackages, SourcePosition position) { super(containingClass, containingPackage, position); this.importedClasses=importedClasses; this.importedPackages=importedPackages; this.baseClassDoc = this; } // Return constructors in class. public ConstructorDoc[] constructors() { return constructors(true); } public ConstructorDoc[] constructors(boolean filter) { return filter ? filteredConstructors : unfilteredConstructors; } // Return true if Serializable fields are explicitly defined with the special class member serialPersistentFields. public boolean definesSerializableFields() { return definesSerializableFields; } // Return fields in class. public FieldDoc[] fields() { return fields(true); } public FieldDoc[] fields(boolean filter) { return filter ? filteredFields : unfilteredFields; } private static Set primitiveNames; static { primitiveNames = new HashSet(); primitiveNames.add("int"); primitiveNames.add("long"); primitiveNames.add("char"); primitiveNames.add("short"); primitiveNames.add("byte"); primitiveNames.add("float"); primitiveNames.add("double"); primitiveNames.add("boolean"); } private Map findClassCache = new HashMap(); public ClassDoc findClass(String className, String dimension) { ClassDoc cached = (ClassDoc)findClassCache.get(className + dimension); if (null != cached) { return cached; } else { ClassDoc classDoc = findClass(className); if (null!=classDoc) { try { if (classDoc.dimension().equals(dimension)) { return classDoc; } else { ClassDoc rc = (ClassDoc) ((WritableType)classDoc).clone(); ((WritableType)rc).setDimension(dimension); findClassCache.put(className + dimension, rc); return rc; } } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } else { return null; } } } public ClassDoc findClass(String className) { String qualifiedName = Main.getRootDoc().resolveClassName(className, this); ClassDoc rc=Main.getRootDoc().classNamed(qualifiedName); if (null == rc) { for (ClassDoc cdi=this; cdi!=null; cdi=cdi.containingClass()) { for (ClassDoc sdi=cdi; sdi!=null; sdi=sdi.superclass()) { if (sdi instanceof ClassDocProxy) { ClassDoc realClass = Main.getRootDoc().classNamed(sdi.qualifiedName()); if (null != realClass) { sdi = realClass; } } rc=Main.getRootDoc().classNamed(sdi.qualifiedName()+"."+className); if (rc!=null) return rc; } } } return rc; } // Get the list of classes declared as imported. public ClassDoc[] importedClasses() { return importedClasses; } // Get the list of packages declared as imported. public PackageDoc[] importedPackages() { return importedPackages; } // Return inner classes within this class. public ClassDoc[] innerClasses() { return innerClasses(true); } public ClassDoc[] innerClasses(boolean filtered) { return filtered ? filteredInnerClasses : unfilteredInnerClasses; } void setFilteredInnerClasses(ClassDoc[] filteredInnerClasses) { this.filteredInnerClasses=filteredInnerClasses; } void setInnerClasses(ClassDoc[] unfilteredInnerClasses) { this.unfilteredInnerClasses=unfilteredInnerClasses; } // Return interfaces implemented by this class or interfaces extended by this interface. public ClassDoc[] interfaces() { return interfaces; } public void setInterfaces(ClassDoc[] interfaces) { this.interfaces=interfaces; } // Return true if this class is abstract public boolean isAbstract() { return isAbstract || isInterface(); } public boolean isInterface() { return isInterface; } public boolean isAnnotation() { return isAnnotation; } public boolean isEnum() { return isEnum; } // Return true if this class is abstract public void setIsAbstract(boolean b) { this.isAbstract=b; } // Return true if this class implements java.io.Externalizable. public boolean isExternalizable() { return implementsInterface("java.io.Externalizable"); } // Return true if this class implements java.io.Serializable. public boolean isSerializable() { return implementsInterface("java.io.Serializable"); } public boolean implementsInterface(String name) { for (ClassDoc cdi=this; cdi!=null; cdi=(ClassDoc)cdi.superclass()) { if (cdi instanceof ClassDocImpl) { ClassDoc[] cdiInterfaces=(ClassDoc[])cdi.interfaces(); if (null != cdiInterfaces) { for (int i=0; i<cdiInterfaces.length; ++i) { if (cdiInterfaces[i].qualifiedName().equals(name)) return true; } } } else { //throw new RuntimeException("implementsInterface(\""+name+"\") failed: Not a ClassDocImpl:"+cdi); } } return false; } // Return methods in class. public MethodDoc[] methods() { return methods(true); } // Return methods in class. public MethodDoc[] methods(boolean filter) { return filter ? filteredMethods : unfilteredMethods; } // 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. public FieldDoc[] serializableFields() { if (serialPersistentField!=null) { return serialPersistentField; } else{ return serializableFields; } } // Return the serialization methods for this class. public MethodDoc[] serializationMethods() { return serializationMethods; } // Test whether this class is a subclass of the specified class. public boolean subclassOf(ClassDoc cd) { for (ClassDocImpl cdi=(ClassDocImpl)superclass(); cdi!=null; cdi=(ClassDocImpl)cdi.superclass()) { if (cdi.equals(cd)) return true; } return false; } // Return the superclass of this class public ClassDoc superclass() { return superclass; } // Implementation of Interface Type public ClassDoc asClassDoc() { return (ClassDoc)this; } public String typeName() { return name(); } public String qualifiedTypeName() { return (containingPackage()!=null && !containingPackage().equals(PackageDocImpl.DEFAULT_PACKAGE))?(containingPackage().name()+"."+name()):(name()); } public String qualifiedName() { return qualifiedTypeName(); } public String dimension() { return dimension; } public String toString() { return "ClassDoc{"+qualifiedTypeName()+"}"; } public TypeVariable asTypeVariable() { return null; } public static ClassDocImpl createInstance(ClassDoc containingClass, PackageDoc containingPackage, ClassDoc[] importedClasses, PackageDoc[] importedPackages, char[] source, int startIndex, int endIndex, List importStatementList) throws ParseException, IOException { String superclassName = "java.lang.Object"; ClassDocImpl rc=new ClassDocImpl(containingClass, containingPackage, importedClasses, importedPackages, null); rc.setImportStatementList(importStatementList); List implementedInterfaces = new ArrayList(); String word=""; int item=0; final int STATE_NORMAL = 1; final int STATE_SLASHC = 2; final int STATE_STARC = 3; final int STATE_ANNO = 4; int state=STATE_NORMAL; int varLevel=0; int parLevel=0; char prev=0; for (int ndx=startIndex; ndx<=endIndex; ++ndx) { char c=(ndx==endIndex)?10:source[ndx]; boolean processWord=false; if (state==STATE_SLASHC) { if (c=='\n') { state=STATE_NORMAL; c=0; } } else if (state==STATE_STARC) { if (c=='/' && prev=='*') { state=STATE_NORMAL; c=0; } } else { if (c=='/' && prev=='/') { state=STATE_SLASHC; c=0; word=word.substring(0,word.length()-1); processWord=true; } else if (c=='*' && prev=='/') { state=STATE_STARC; c=0; word=word.substring(0,word.length()-1); processWord=true; } else if (c=='@') { state=STATE_ANNO; word += c; } else if (c=='(' && state==STATE_ANNO) { ++parLevel; word += c; } else if (c==')' && state==STATE_ANNO) { --parLevel; word += c; if (parLevel == 0) state=STATE_NORMAL; } else if (c=='<') { ++varLevel; word += c; } else if (c=='>') { --varLevel; word += c; } else if (c=='{' && parLevel == 0 || c==',' && varLevel == 0 && parLevel == 0 || Parser.WHITESPACE.indexOf(c)>=0 && parLevel == 0 && varLevel == 0) { processWord=true; state=STATE_NORMAL; } else { word+=c; } if (processWord && word.length()>0) { if (item==0) { if (rc.processModifier(word)) { } else if (word.equals("abstract")) { rc.setIsAbstract(true); } else if (word.equals("class")) { rc.setIsInterface(false); item=1; } else if (word.equals("enum")) { rc.setIsEnum(true); item = 1; } else if (word.equals("interface")) { rc.setIsInterface(true); item=1; } else if (word.equals("@interface")) { rc.setIsInterface(true); rc.setIsAnnotation(true); item=1; } else if (word.equals("strictfp")) { } else { Main.getRootDoc().printWarning("unknown modifier '"+word+"'"); } } else if (word.equals("extends") && !rc.isAnnotation()) { if (rc.isInterface()) { item=3; } else { item=2; } } else if (word.equals("implements") && !rc.isAnnotation()) { item=3; } else if (item==1) { int parameterIndex = word.indexOf("<"); if (parameterIndex == -1) rc.setClass(word); else { rc.setClass(word.substring(0, parameterIndex)); parseTypeVariables(rc,word.substring(parameterIndex, word.length())); } } else if (item==2) { //Debug.log(9,"setting baseclass of "+rc+" to "+word); int parameterIndex = word.indexOf("<"); if (parameterIndex == -1) superclassName=word; else { /* FIXME: Parse type parameters */ superclassName=word.substring(0,parameterIndex); } } else if (item==3) { int parameterIndex = word.indexOf("<"); if (parameterIndex == -1) implementedInterfaces.add(word); else { /* FIXME: Parse type parameters */ implementedInterfaces.add(word.substring(0,parameterIndex)); } } word=""; } if (c=='{' && state==STATE_NORMAL) break; } prev=c; } if (null != containingClass && containingClass.isInterface()) { rc.accessLevel = ACCESS_PUBLIC; } if (rc.name()==null) { throw new ParseException("No classdef found in expression \""+new String(source,startIndex,endIndex-startIndex)+"\""); } rc.setPosition(ClassDocImpl.getPosition(rc, source, startIndex)); ClassDoc superclassProxy=new ClassDocProxy(superclassName, rc); if (!rc.qualifiedName().equals("java.lang.Object")) { rc.setSuperclass(superclassProxy); } ClassDoc[] interfaces=new ClassDoc[implementedInterfaces.size()]; for (int i=0; i<interfaces.length; ++i) { interfaces[i]=new ClassDocProxy((String)implementedInterfaces.get(i), rc); } rc.setInterfaces(interfaces); if (rc.isInterface() && rc.containingClass()!=null) { rc.setIsStatic(true); } return rc; } public void setFields(FieldDoc[] fields) { this.unfilteredFields=fields; } public void setFilteredFields(FieldDoc[] fields) { this.filteredFields=fields; } public void setSerializableFields(FieldDoc[] sfields) { this.serializableFields=sfields; } public void setMethods(MethodDoc[] methods) { this.unfilteredMethods=methods; } public void setFilteredMethods(MethodDoc[] methods) { this.filteredMethods=methods; } public void setConstructors(ConstructorDoc[] constructors) { this.unfilteredConstructors=constructors; } public void setFilteredConstructors(ConstructorDoc[] constructors) { this.filteredConstructors=constructors; } // Returns the name of this Doc item. public String name() { if (containingClass==null) { return className; } else { return containingClass.name()+"."+className; } } public String getClassName() { return className; } public void setClass(String className) { this.className=className; } void setSuperclass(ClassDoc superclass) { this.superclass=superclass; } public void resolve() throws ParseException { if (!resolved) { resolved=true; if (containingClass!=null) ((ClassDocImpl)containingClass).resolve(); //Debug.log(9,"resolving class '"+qualifiedName()+"'"); /* for (int i=0; i<importedPackages.length; ++i) { Debug.log(9,"class "+qualifiedName()+" imports "+importedPackages[i].name()); } */ if (superclass instanceof ClassDocProxy) { ClassDoc realClassDoc=findClass(superclass.qualifiedName()); if (realClassDoc==null) { /* if (true) { // Main.recursiveClasses) { throw new ParseException("In class '"+qualifiedName()+"': class '"+className+"' not found."); } */ } else { superclass=realClassDoc; } } if (null != interfaces) { for (int i=0; i<interfaces.length; ++i) { if (interfaces[i] instanceof ClassDocProxy) { //Debug.log(9,"class "+qualifiedName()+" implements "+interfaces[i].qualifiedName()); ClassDoc realClassDoc=findClass(interfaces[i].qualifiedName()); if (realClassDoc==null) { /* if (Main.recursiveClasses) { throw new ParseException("In class '"+qualifiedName()+"': class '"+className+"' not found."); } */ } else { //Debug.log(9,"found class '"+className+"': "+interfaces[i]); interfaces[i]=realClassDoc; } } } } if (unfilteredFields!=null) { for (int i=0; i<unfilteredFields.length; ++i) { ((FieldDocImpl)unfilteredFields[i]).resolve(); if (unfilteredFields[i].name().equals("serialPersistentField")) { serialPersistentField=new FieldDoc[]{unfilteredFields[i]}; definesSerializableFields=true; } } } if (unfilteredMethods!=null) { for (int i=0; i<unfilteredMethods.length; ++i) { ((MethodDocImpl)unfilteredMethods[i]).resolve(); } } if (unfilteredConstructors!=null) { for (int i=0; i<unfilteredConstructors.length; ++i) { ((ConstructorDocImpl)unfilteredConstructors[i]).resolve(); } } List isSerMethodList=new ArrayList(); if (null != maybeSerMethodList) { for (Iterator it=maybeSerMethodList.iterator(); it.hasNext(); ) { MethodDocImpl method=(MethodDocImpl)it.next(); method.resolve(); if (((method.name().equals("readObject") && method.signature().equals("(java.io.ObjectInputStream)")) || (method.name().equals("writeObject") && method.signature().equals("(java.io.ObjectOutputStream)")) || (method.name().equals("readExternal") && method.signature().equals("(java.io.ObjectInput)")) || (method.name().equals("writeExternal") && method.signature().equals("(java.io.ObjectOutput)")) || (method.name().equals("readResolve") && method.signature().equals("()")))) { isSerMethodList.add(method); } } this.serializationMethods=(MethodDoc[])isSerMethodList.toArray(new MethodDoc[0]); maybeSerMethodList=null; } } } public FieldDoc findFieldRec(String name) { return findFieldRec(this, name); } private static FieldDoc findFieldRec(ClassDoc classDoc, String name) { FieldDoc field = findField(classDoc, name); if (null!=field) { return field; } else { ClassDoc[] interfaces = classDoc.interfaces(); for (int i=0; i<interfaces.length; ++i) { field = findFieldRec(interfaces[i], name); if (null != field) { return field; } } if (null != classDoc.superclass()) { return findFieldRec(classDoc.superclass(), name); } else { return null; } } } private static FieldDoc findField(ClassDoc classDoc, String name) { FieldDoc[] fields = classDoc.fields(false); for (int i=0; i<fields.length; ++i) { if (fields[i].name().equals(name)) { return fields[i]; } } return null; } public FieldDoc findField(String fieldName) { for (int i=0; i<filteredFields.length; ++i) { if (filteredFields[i].name().equals(fieldName)) { return filteredFields[i]; } } return null; } public void resolveComments() { super.resolveComments(); if (null != unfilteredFields) { for (int i=0; i<unfilteredFields.length; ++i) { ((FieldDocImpl)unfilteredFields[i]).resolveComments(); } } if (null != serializableFields) { for (int i=0; i<serializableFields.length; ++i) { ((FieldDocImpl)serializableFields[i]).resolveComments(); } } if (null != unfilteredMethods) { for (int i=0; i<unfilteredMethods.length; ++i) { ((MethodDocImpl)unfilteredMethods[i]).resolveComments(); } } if (null != unfilteredConstructors) { for (int i=0; i<unfilteredConstructors.length; ++i) { ((ConstructorDocImpl)unfilteredConstructors[i]).resolveComments(); } } resolveTags(); } private String className=null; private boolean isAbstract; private boolean isInterface; private boolean isAnnotation; private boolean isEnum; private ClassDoc[] interfaces; private ClassDoc[] filteredInnerClasses; private ClassDoc[] unfilteredInnerClasses; private FieldDoc[] filteredFields; private FieldDoc[] unfilteredFields; private FieldDoc[] serializableFields; private MethodDoc[] filteredMethods; private MethodDoc[] unfilteredMethods; private ConstructorDoc[] filteredConstructors; private ConstructorDoc[] unfilteredConstructors; private TypeVariable[] typeParameters; private boolean resolved=false; private ClassDoc superclass; // Is this Doc item a class. public boolean isClass() { return !isInterface; } // return true if this Doc is include in the active set. public boolean isIncluded() { if (this == baseClassDoc) { return isIncluded || (null != containingClass && Main.getInstance().includeAccessLevel(accessLevel)); } else { return baseClassDoc.isIncluded(); } } void setIsIncluded(boolean b) { this.isIncluded=b; } private boolean isIncluded=false; void setImportedClasses(ClassDoc[] importedClasses) { this.importedClasses=importedClasses; } private static Map typeMap = new HashMap(); Type typeForString(String typeName) throws ParseException { String orgTypename=typeName; int ndx=typeName.indexOf('['); String dim=""; if (ndx>=0) { for (int i=ndx; i<typeName.length(); ++i) { if ("[]".indexOf(typeName.charAt(i))>=0) { dim+=typeName.charAt(i); } } typeName=typeName.substring(0,ndx).trim(); } ClassDoc classDoc = findClass(typeName, dim); if (null != classDoc) { return classDoc; } Type type = (Type)typeMap.get(typeName+dim); if (null!=type) { try { if (type.dimension().equals(dim)) { return type; } else { Type rc = (Type) ((WritableType)type).clone(); ((WritableType)rc).setDimension(dim); return rc; } } catch (CloneNotSupportedException e) { throw new ParseException(e.toString()); } } if ("boolean".equals(typeName) || "char".equals(typeName) || "byte".equals(typeName) || "short".equals(typeName) || "int".equals(typeName) || "long".equals(typeName) || "void".equals(typeName) || "float".equals(typeName) || "double".equals(typeName)) { Type rc=new TypeImpl(null, typeName, dim); typeMap.put(typeName+dim, rc); return rc; } if (Main.getInstance().isDocletRunning()) { //System.err.println(findClass("java.lang.String")); //throw new ParseException("Doclet running, class not found: "+typeName+" ("+orgTypename+")"); } Type rc=new ClassDocProxy(typeName, this); ((WritableType)rc).setDimension(dim); return rc; } public boolean isException() { for (ClassDoc cdi=this; cdi!=null; cdi=cdi.superclass()) { if ("java.lang.Exception".equals(cdi.qualifiedName())) return true; } return false; } public boolean isError() { for (ClassDoc cdi=this; cdi!=null; cdi=cdi.superclass()) { if ("java.lang.Error".equals(cdi.qualifiedName())) return true; } return false; } public boolean isOrdinaryClass() { return !isException() && !isError() && !isInterface(); } public void setIsInterface(boolean b) { this.isInterface=b; } public void setIsAnnotation(boolean b) { this.isAnnotation=b; } public void setIsEnum(boolean b) { isEnum = b; } public ExecutableMemberDoc findExecutableRec(String nameAndSignature) { ExecutableMemberDoc rc; for (ClassDoc cdi=this; cdi!=null; ) { rc=findMethod(cdi, nameAndSignature); if (rc!=null) return rc; rc=findConstructor(cdi, nameAndSignature); if (rc!=null) return rc; ClassDoc _superclass = cdi.superclass(); if (null == _superclass) { break; } else { cdi = _superclass; } } return null; } public static ConstructorDoc findConstructor(ClassDoc classDoc, String nameAndSignature) { int ndx=nameAndSignature.indexOf('('); if (ndx<=0) return null; else { String fullSignature = resolveSignature(classDoc, nameAndSignature.substring(ndx)); return findConstructor(classDoc, nameAndSignature.substring(0,ndx), fullSignature); } } public static ConstructorDoc findConstructor(ClassDoc classDoc, String name, String signature) { ConstructorDoc[] filteredConstructors = classDoc.constructors(true); if (null != filteredConstructors) { for (int i=0; i<filteredConstructors.length; ++i) { ConstructorDoc constructor = filteredConstructors[i]; if (constructor.name().equals(name) && constructor.signature().equals(signature)) return constructor; } } return null; } public static MethodDoc findMethod(ClassDoc classDoc, String nameAndSignature) { int ndx=nameAndSignature.indexOf('('); if (ndx<=0) { return null; } else { String name = nameAndSignature.substring(0,ndx); String fullSignature = resolveSignature(classDoc, nameAndSignature.substring(ndx)); return findMethod(classDoc, name, fullSignature); } } private static String resolveSignature(ClassDoc classDoc, String signature) { signature = signature.substring(1, signature.length() - 1).trim(); if (0 == signature.length()) { return "()"; } StringTokenizer st = new StringTokenizer(signature, ","); StringBuffer fullSignature = new StringBuffer("("); while (st.hasMoreTokens()) { String type = st.nextToken().trim(); int ndx = type.length(); while (ndx > 0 && type.charAt(ndx - 1) == '[' || type.charAt(ndx - 1) == ']') { -- ndx; } String dim = type.substring(ndx); type = type.substring(0, ndx); ClassDoc typeClass = classDoc.findClass(type); if (fullSignature.length() > 1) { fullSignature.append(","); } if (null != typeClass) { fullSignature.append(typeClass.qualifiedName()); } else { fullSignature.append(type); } fullSignature.append(dim); } fullSignature.append(')'); return fullSignature.toString(); } public static MethodDoc findMethod(ClassDoc classDoc, String name, String signature) { MethodDoc[] filteredMethods = classDoc.methods(true); if (null != filteredMethods) { for (int i=0; i<filteredMethods.length; ++i) { MethodDoc method = filteredMethods[i]; if (method.name().equals(name) && method.signature().equals(signature)) return method; } } return null; } public boolean equals(Object o) { return (o!=null) && (o instanceof ClassDoc) && ((ClassDoc)o).qualifiedName().equals(qualifiedName()); } private List maybeSerMethodList; void setMaybeSerMethodList(List maybeSerMethodList) { this.maybeSerMethodList=maybeSerMethodList; } public void setDimension(String dimension) { this.dimension = dimension; } public Object clone() throws CloneNotSupportedException { ClassDocImpl result = (ClassDocImpl)super.clone(); result.baseClassDoc = baseClassDoc; return result; } public int superHashCode() { return super.hashCode(); } public int hashCode() { return qualifiedTypeName().hashCode(); } public ClassDoc getBaseClassDoc() { return baseClassDoc; } public FieldDoc getFieldDoc(String name) { for (int i=0; i<unfilteredFields.length; ++i) { if (name.equals(unfilteredFields[i].name())) { return unfilteredFields[i]; } } return null; } public MethodDoc getMethodDoc(String name, String signature) { for (int i=0; i<unfilteredMethods.length; ++i) { if (name.equals(unfilteredMethods[i].name()) && signature.equals(unfilteredMethods[i].signature())) { return unfilteredMethods[i]; } } return null; } public ConstructorDoc getConstructorDoc(String signature) { for (int i=0; i<unfilteredConstructors.length; ++i) { if (signature.equals(unfilteredConstructors[i].signature())) { return unfilteredConstructors[i]; } } return null; } private Object findFieldValue(String identifier, ClassDoc classDoc, String fieldName, Set visitedFields) throws UnknownIdentifierException, IllegalExpressionException { while (classDoc != null) { if (classDoc instanceof ClassDocImpl) { FieldDocImpl fieldDoc = (FieldDocImpl)((ClassDocImpl)classDoc).getFieldDoc(fieldName); if (visitedFields.contains(fieldDoc)) { throw new CircularExpressionException("Circular reference detected"); } else if (null != fieldDoc) { return fieldDoc.constantValue(visitedFields); } } else { ClassDoc[] _interfaces = classDoc.interfaces(); if (null != _interfaces) { for (int i=0; i<_interfaces.length; ++i) { if (_interfaces[i] instanceof ClassDocImpl) { FieldDocImpl fieldDoc = (FieldDocImpl)((ClassDocImpl)_interfaces[i]).getFieldDoc(fieldName); if (visitedFields.contains(fieldDoc)) { throw new CircularExpressionException("Circular reference detected"); } else if (null != fieldDoc) { return fieldDoc.constantValue(visitedFields); } } } } } classDoc = classDoc.superclass(); } throw new UnknownIdentifierException(identifier); } public Object getValue(String identifier, Set visitedFields) throws UnknownIdentifierException, IllegalExpressionException { int ndx = identifier.lastIndexOf('.'); if (ndx >= 0) { String _className = identifier.substring(0, ndx); String _fieldName = identifier.substring(ndx + 1); ClassDoc _classDoc = findClass(_className); if (null != _classDoc) { return findFieldValue(identifier, _classDoc, _fieldName, visitedFields); } else { throw new UnknownIdentifierException(identifier); } } else { return findFieldValue(identifier, this, identifier, visitedFields); } } public boolean isPrimitive() { return false; } // Compares this Object with the specified Object for order. public int compareTo(java.lang.Object o) { int rc; if (o instanceof ClassDocImpl) { ClassDocImpl c1 = this; ClassDocImpl c2 = (ClassDocImpl)o; if (null != c1.containingClass() && null == c2.containingClass()) { rc = c1.containingClass().compareTo(c2); if (0 == rc) { rc = 1; } return rc; } else if (null == c1.containingClass() && null != c2.containingClass()) { rc = c1.compareTo(c2.containingClass()); if (0 == rc) { rc = -1; } return rc; } else if (null != c1.containingClass() && null != c2.containingClass()) { rc = c1.containingClass().compareTo(c2.containingClass()); if (0 != rc) { return rc; } } rc = super.compareTo(o); if (0 == rc) { return Main.getInstance().getCollator().compare(containingPackage().name(), ((ClassDocImpl)o).containingPackage().name()); } else { return rc; } } else { return 1; } } private List importStatementList; public void setImportStatementList(List importStatementList) { this.importStatementList = new LinkedList(); this.importStatementList.addAll(importStatementList); } public List getImportSpecifierList() { return importStatementList; } public TypeVariable[] typeParameters() { return typeParameters; } /** * <p> * Parses the type variables declared in the class definition. * The syntax is: * </p> * <p> * <dl> * <dt>TypeParameters:</dt> * <dd><code>< <em>TypeParameter</em> { <em>, TypeParameter }</code></dd> * <dt>TypeParameter:</dt> * <dd><code><em>Identifier</em> { <strong>extends</strong> <em>Bound</em> * }</dd> * <dt>Bound:</dt> * <dd><code><em>Type</em>{<strong>&</strong> <em>Type</em> } </dd> * </dl> * * @param rc the owning class. * @param typeVariables the string to be parsed. * @throws ParseException if parsing fails. */ public static void parseTypeVariables(ClassDocImpl rc, String typeVariables) throws ParseException { List parsedBounds = null; StringTokenizer parameters = new StringTokenizer(typeVariables, Parser.WHITESPACE + "<>,"); List variables = new ArrayList(); while (parameters.hasMoreTokens()) { String parameter = parameters.nextToken(); StringTokenizer parts = new StringTokenizer(parameter, Parser.WHITESPACE); TypeVariableImpl variable = new TypeVariableImpl(rc.qualifiedName(), parts.nextToken(),"", rc); if (parts.hasMoreTokens()) { if (!parts.nextToken().equals("extends")) throw new ParseException("Invalid type parameter: " + parameter); StringTokenizer bounds = new StringTokenizer(parts.nextToken(), Parser.WHITESPACE + "&"); parsedBounds = new ArrayList(); while (bounds.hasMoreTokens()) { String bound = bounds.nextToken(); int nameSep = bound.lastIndexOf("."); String packageName = bound.substring(0, nameSep); String boundName = bound.substring(nameSep, bound.length()); parsedBounds.add(new TypeImpl(packageName,boundName,"")); } } if (parsedBounds != null) variable.setBounds(parsedBounds); variables.add(variable); } rc.setTypeParameters(variables); } /** * Set the type parameters to the contents of the supplied list. * * @param variables a list of type parameters. */ void setTypeParameters(List variables) { typeParameters = (TypeVariable[]) variables.toArray(new TypeVariable[variables.size()]); } }