/* -*- Mode: JDE; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This file is part of the debugger and core tools for the AspectJ(tm)
* programming language; see http://aspectj.org
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* either http://www.mozilla.org/MPL/ or http://aspectj.org/MPL/.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is AspectJ.
*
* The Initial Developer of the Original Code is Xerox Corporation. Portions
* created by Xerox Corporation are Copyright (C) 1999-2002 Xerox Corporation.
* All Rights Reserved.
*/
package org.aspectj.tools.ajdoc;
import org.aspectj.ajdoc.IntroducedSuperDoc;
import org.aspectj.ajdoc.PointcutDoc;
import org.aspectj.compiler.base.ast.ClassDec;
import org.aspectj.compiler.base.ast.CodeDec;
import org.aspectj.compiler.base.ast.CompilationUnit;
import org.aspectj.compiler.base.ast.Constructor;
import org.aspectj.compiler.base.ast.ConstructorDec;
import org.aspectj.compiler.base.ast.Dec;
import org.aspectj.compiler.base.ast.Field;
import org.aspectj.compiler.base.ast.FieldDec;
import org.aspectj.compiler.base.ast.Import;
import org.aspectj.compiler.base.ast.Imports;
import org.aspectj.compiler.base.ast.InterfaceDec;
import org.aspectj.compiler.base.ast.Method;
import org.aspectj.compiler.base.ast.NameType;
import org.aspectj.compiler.base.ast.SourceLocation;
import org.aspectj.compiler.base.ast.TextSourceLocation;
import org.aspectj.compiler.base.ast.Type;
import org.aspectj.compiler.base.ast.TypeDec;
import org.aspectj.compiler.crosscuts.AspectJCompiler;
import org.aspectj.compiler.crosscuts.ast.AspectDec;
import org.aspectj.compiler.crosscuts.ast.IntroducedSuperDec;
import org.aspectj.compiler.crosscuts.ast.PointcutSO;
import org.aspectj.ajdoc.ClassDoc;
import com.sun.javadoc.ConstructorDoc;
import com.sun.javadoc.FieldDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.PackageDoc;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* This implements ClassDoc and acts as a factory for ClassDocImpl
* and associated DocImpl.
* The factory will excluded new superclasses and introduction classes
* so the caller should take care to include those classes explicitly
* by adding them directly before they are sought indirectly or
* by post-processing them to enable inclusion as appropriate.
*/
public class ClassDocImpl
extends ProgramElementDocImpl
implements org.aspectj.ajdoc.ClassDoc {
/**
* Returns an instance of ClassDoc represented by
* the passed in TypeDec.
*
* @param typeDec instance of TypeDec representing
* the ClassDoc that will be returned.
* @return an instance of ClassDoc mirroring
* the passed in TypeDec.
*/
public final static ClassDocImpl getInstance(TypeDec typeDec) {
return factory.getInstance(typeDec);
}
/**
* Returns an instance of ClassDoc represented by
* the passed in TypeDec and containing ClassDoc (may be null).
*
* @param outerDoc the containing ClassDoc -- may be null.
* @param typeDec instance of TypeDec representing
* the ClassDoc that will be returned.
* @return an instance of ClassDoc mirroring
* the passed in TypeDec.
*/
public final static ClassDocImpl getInstance(ClassDoc outerDoc, TypeDec typeDec) {
return factory.getInstance(outerDoc, typeDec);
}
/**
* Returns the known ClassDocImpl for a given String --
* the returned value may be null.
*
* @return the known ClassDocImpl for a given String --
* the returned value may be null.
*/
public final static ClassDocImpl find(String qualifiedName) {
return factory.find(qualifiedName);
}
/**The factory used to create instances of this class. */
private final static Factory factory = new Factory();
/** The ClassDec to which is delegated. */
private final TypeDec typeDec;
// todo: we know these Collections are FilteredDecList, so declare that?
/** The introductions that affect a ClassDoc. */
private Collection introducers;
/** The array of fields visible in this type. */
private Collection fieldDocs;
/** The array of methods visible in this type. */
private Collection methodDocs;
/** The array of constructors visible in this type.
* The implementation must support iterator().remove().
*/
private Collection constructorDocs;
/** The array of inner classes visible in thie type. */
private Collection innerclassDocs;
/** The array of interfaces this type implements. */
private Collection interfaceDocs;
/** The array of classes this type imports on demand. */
private Collection importedClasses;
/** The array of package this type imports on demand. */
private Collection importedPackages;
/** The array of pointcuts visible in this type. */
private Collection pointcutDocs;
/** cached variant of ((AjdocCompiler)ajc()).getFilter()
*/
private AccessChecker filter;
/**
* Constructs a representation of an AspectJ-compiled class
* using the underlying TypeDec and containning ClassDoc.
* NOTE: This is protected (and maybe should be private)
* because the static method {@link #getInstance(TypeDec)}
* should always be used to get instances of this type. It
* ensures that enclosing types are created before their
* enclosed types.
*
* @param containingClass ClassDoc that encloses this.
* @param typeDec The underlying TypeDec.
*/
protected ClassDocImpl(com.sun.javadoc.ClassDoc containingClass,
TypeDec typeDec) {
super(containingClass);
this.typeDec = typeDec;
//AccessChecker check = getFilter();
// RootDocImpl sets inclusion of world classes
setIncluded(false);
// have to install before creating imports to avoid cycles
factory.put(this, typeDec);
createImports(importedClasses = new ArrayList(),
importedPackages = new ArrayList());
}
/**
* Maps Decs to their counterpart by testing with
* instanceof
*
* @return a MemberDocImpl that has an underlying Dec dec.
*/
public MemberDocImpl docForDec(Dec dec) {
if (dec instanceof FieldDec) {
return docForDec((FieldDec)dec);
}
if (dec instanceof CodeDec) {
return docForDec((CodeDec)dec);
}
// todo: map for inner classes, Type, etc?
return null; //TODO error ???
}
/**
* Returns a FieldDocImpl that has an underlying FieldDec dec.
*
* @return a FieldDocImpl that has an underlying FieldDec dec.
*/
public FieldDocImpl docForDec(FieldDec dec) {
FieldDoc[] fs = fields();
for (int i = 0; i < fs.length; i++) {
FieldDocImpl fd = (FieldDocImpl)fs[i];
if (fd.dec() == dec) return fd;
}
return null;
}
/**
* Returns a CodeDocImpl that has an underlying CodeDec dec.
*
* @return a CodeDocImpl that has an underlying CodeDec dec.
*/
public CodeDocImpl docForDec(CodeDec dec) {
MethodDoc[] ms = methods();
for (int i = 0; i < ms.length; i++) {
CodeDocImpl cd = (CodeDocImpl)ms[i];
if (cd.dec() == dec) return cd;
}
ConstructorDoc[] cs = constructors();
for (int i = 0; i < cs.length; i++) {
CodeDocImpl cd = (CodeDocImpl)cs[i];
if (cd.dec() == dec) return cd;
}
return null;
}
/**
* @todo ??????
*/
public TypeDec nonNullTypeDec() {
if (typeDec().getLexicalType() == null) return typeDec();
return super.nonNullTypeDec();
}
/**
* Returns a Collection of ClassDocImpls that have corresponding
* ClassDecs declared within classDec().
*
* @return a Collection of ClassDocImpls that have corresponding
* ClassDecs declared within classDec().
*/
private Collection createInnerTypes() {
Collection items = ((NameType)typeDec.getType()).getInnerTypes();
FilteredDecList result =
new FilteredDecList(getFilter(), this);
if (items != null) {
for (Iterator i = items.iterator(); i.hasNext();) {
result.add(((NameType)i.next()).getTypeDec());
}
}
Collections.sort(result);
return result;
}
/**
* Creates the two collection of imports -- class and packages --
* used by the file in which classDec() was declared.
*
* @param importClasses the classes to fill.
* @param importPkgs the packages to fill.
*/
private void createImports(final Collection importClasses,
final Collection importPkgs) {
CompilationUnit cu = typeDec.getCompilationUnit();
if (cu != null) {
Imports imports = cu.getImports();
if (imports != null) {
for (int i = 0; i < imports.size(); i++) {
Import imprt = imports.get(i);
if (imprt != null) {
if (imprt.getStar()) {
PackageDoc importedPkg =
PackageDocImpl.getPackageDoc
(imprt.getName());
if (importedPkg != null) {
importPkgs.add(importedPkg);
}
} else {
com.sun.javadoc.ClassDoc importedClass =
findClass(imprt.getName());
if (importedClass != null) {
importClasses.add(importedClass);
}
}
}
}
}
}
}
/**
* Returns a Collection of ClassDocImpl representing the
* interfaces the underlying TypeDec implements.
*
* @return a Collection of ClassDocImpl representing the
* interfaces the underlying TypeDec implements.
*/
private Collection createInterfaces() {
//NameType type = (NameType)typeDec.getType();
Collection items = typeDec.getSuperInterfaceTypes();
FilteredDecList result =
new FilteredDecList(getFilter(), this);
if (items != null) {
for (Iterator i = items.iterator(); i.hasNext();) {
result.add(((NameType)i.next()).getTypeDec());
}
}
Collections.sort(result);
return result;
}
/**
* Called by AjdocCompiler to do pruning once the whole world is created.
* This avoids using aspect before initialized when
* this classdoc constructed as a result of aspect
* initialization.
*/
void postProcess() {
// prune compiler-generated default constructor if unadvised.
// can't do this on construction since advising aspect may exist but be uninitialized
final SourceLocation parentLoc = dec().getSourceLocation();
final int parentLine = (null == parentLoc ? -1 : parentLoc.getBeginLine());
final int parentColumn = (null == parentLoc ? -1 : parentLoc.getBeginColumn());
if (null == constructorDocs) {
if (null == constructors()) {
// XXX harmless error System.err.println("Unable to post-process");
return;
}
}
try {
//ArrayList removed = new ArrayList();
for (Iterator i = constructorDocs.iterator(); i.hasNext(); ) {
ConstructorDocImpl cdi = (ConstructorDocImpl) i.next();
CodeDec cd = cdi.codeDec();
SourceLocation sl = (null == cd ? null : cd.getSourceLocation());
// if ajc changes so typedec start/end not equal to constructor, then can't recognize
if ((null != sl)
&& (parentColumn == sl.getBeginColumn())
&& (parentLine == sl.getBeginLine())) {
Object[] advice = cdi.advice();
if ((null != advice) && (1 > advice.length)) {
i.remove();
//removed.add(cdi);
//System.err.println("removing unadvised generated constructor: " + cdi);
} else {
//System.err.println("keeping advised generated constructor: " + cdi);
}
} else {
//System.err.println("keeping ungenerated constructor: " + cdi);
}
}
// for (Iterator i = removed.iterator(); i.hasNext();) {
// Object dec = i.next();
// if (constructorDocs.contains(dec)) {
// throw new Error("remove failed for " + dec);
// }
// }
} catch (UnsupportedOperationException e) {
System.err.println("Warning: ClassDocImpl.constructorDocs not removable");
}
}
/**
* Returns a Collection of ConstructorDocImpl representing the
* constructors the underlying TypeDec declares.
*
* @return a Collection of ConstructorDocImpl representing the
* constructors the underlying TypeDec declares.
*/
private Collection createConstructors() {
NameType type = (NameType)typeDec.getType();
Collection items = type.getConstructors();
final SourceLocation parentLoc = dec().getSourceLocation();
final int parentLine = (null == parentLoc ? -1 : parentLoc.getBeginLine());
final int parentColumn = (null == parentLoc ? -1 : parentLoc.getBeginColumn());
FilteredDecList result =
new FilteredDecList(getFilter(), this);
if (items != null) {
for (Iterator i = items.iterator(); i.hasNext();) {
Constructor c = (Constructor) i.next();
ConstructorDec cd = c.getConstructorDec();
ConstructorDocImpl impl = new ConstructorDocImpl(this, cd);
// XXX workaround for ajc bug of default constructor source location
SourceLocation sl = (null == cd ? null : cd.getSourceLocation());
// if line/column starts the same, then a generated constructor
if ((null != sl)
&& (parentColumn == sl.getBeginColumn())
&& (parentLine == sl.getBeginLine())) {
// use source location clone without comment from class
TextSourceLocation tsl = new TextSourceLocation(sl.getCompilationUnit(),
sl.getStartPosition(), sl.getEndPosition());
tsl.clearComment();
cd.setSourceLocation(tsl);
}
result.add(impl);
}
}
Collections.sort(result);
return result;
}
/**
* Returns a Collection of PointcutDocImpl representing the
* pointcuts the underlying TypeDec declares.
*
* @return a Collection of PointcutDocImpl representing the
* pointcuts the underlying TypeDec declares.
*/
private Collection createPointcuts() {
NameType type = (NameType)typeDec.getType();
Collection items = type.getPointcuts();
FilteredDecList result =
new FilteredDecList(getFilter(), this);
if (items != null) {
for (Iterator i = items.iterator(); i.hasNext();) {
result.add(((PointcutSO)i.next()).getPointcutDec());
}
}
Collections.sort(result);
return result;
}
/**
* Returns a Collection of MethodDocImpl representing the
* methods the underlying TypeDec declares.
*
* @return a Collection of MethodDocImpl representing the
* methods the underlying TypeDec declares.
*/
private Collection createMethods() {
NameType type = (NameType)typeDec.getType();
Collection methods = type.getMethods();
FilteredDecList result =
new FilteredDecList(getFilter(), this);
if (methods != null) {
for (Iterator i = methods.iterator(); i.hasNext();) {
result.add(((Method)i.next()).getMethodDec());
}
}
Collections.sort(result);
return result;
}
/**
* Returns a Collection of FieldDocImpl representing the
* fields the underlying TypeDec declares.
*
* @return a Collection of FieldDocImpl representing the
* fields the underlying TypeDec declares.
*/
private Collection createFields() {
NameType type = (NameType)typeDec.getType();
Collection fields = type.getFields();
FilteredDecList result =
new FilteredDecList(getFilter(), this);
if (fields != null) {
for (Iterator i = fields.iterator(); i.hasNext();) {
result.add(((Field)i.next()).getFieldDec());
}
}
Collections.sort(result);
return result;
}
/** return (and cache) filter from ajc() */
protected AccessChecker getFilter() {
// nb: called during construction
if (null == filter) {
AspectJCompiler ajc = ajc();
if (ajc instanceof AjdocCompiler) {
filter = ((AjdocCompiler) ajc).getFilter();
}
}
return filter; // still may be null
}
/**
* Returns the underlying Dec -- a TypeDec.
*
* @return the underlying Dec -- a TypeDec.
*/
protected final Dec dec() {
return typeDec();
}
/**
* Returns the underlying TypeDec.
*
* @return the underlying TypeDec.
*/
public final TypeDec typeDec() {
return typeDec;
}
/**
* Returns the fully-qualified name of this TypeDec including
* the package and any enclosing classes.
*
* @return the fully-qualified name of this TypeDec including
* the package and any inclosing classes.
*/
public String qualifiedName() {
return qualifiedTypeName().replace('$','.');
}
/**
* Returns the fully-qualfied name of this class.
*
* @return the fully-qualfied name of this class.
*/
public String toString() {
return qualifiedName();
}
/**
* Returns the single name of this TypeDec excluding the package
* but including enclosing classes. NOTE: All dollar signs
* are replaced by periods.
*
* @return the single name of this TypeDec excluding the package
* but including enclosing classes.
*/
public String name() {
return ((NameType)typeDec().getType()).
getExtendedId().replace('$','.');
}
/**
* Returns the class specified by classname
* from the context of this
. This method may return
* null
denoting the class wasn't found.
* Search proceeds in the following order:
*
*
classname
* from the context of this
.
* @see Util#findClass(ClassDoc,String,JavaCompiler)
* @see
* Javadoc Tool Homepage
*/
public com.sun.javadoc.ClassDoc findClass(String classname) {
// Sanity check
if (classname == null || classname.length() < 1) {
return null;
}
// The result
com.sun.javadoc.ClassDoc desired;
// [0] The trivial case, the classname is this class
if (classname.equals(name()) ||
classname.equals(qualifiedName())) {
return this;
}
// [1] Look up the fully qualified name.
if ((desired = ClassDocImpl.find(classname)) != null) {
return desired;
}
// [2] Search the inner classes. We can assume that if
// classname refers to an inner class it is unqualified
// with respect to its package, because step [1] would have
// picked it up, then. First look to see if the name
// matches, then search the inner class itself. We check two
// values:
// [1] innername: the unqualified inner class name
// [2] classname: the qualified (with outer class) name
// Example:
// /**
// * @see Inner
// * // classname == Inner (f'cked)
// * // innername == Outer.Inner (ok)
// * @see Outer.Inner
// * // classname == Outer.Inner (ok)
// * // innername == Outer.Outer.Inner (f'cked)
// class Outer {
// static class Inner {}
// }
String innername = name() + '.' + classname;
com.sun.javadoc.ClassDoc[] inners = innerClasses();
if (inners != null) {
for (int i = 0; i < inners.length; i++) {
if (classname.equals(inners[i].name()) ||
innername.equals(inners[i].name())) {
return inners[i];
}
}
}
// [3] Search in this package
if ((desired = containingPackage().findClass(classname)) != null) {
return desired;
}
// [4] Search the class imports. The order for this is specified
// by the compiler -- if you don't believe me read for yourself:
// http://java.sun.com/products/jdk/1.2/docs/tooldocs/win32/ (cont't)
// javadoc.html#seesearchorder
// We don't look in other package, so we assume classname
// is full package-qualified.
com.sun.javadoc.ClassDoc[] imports = importedClasses();
if (imports != null) {
for (int i = 0; i < imports.length; i++) {
if (classname.equals(imports[i].name())) {
return imports[i];
}
}
}
// [5] Search the package imports for the fully-qualified name.
PackageDoc[] pkgs = importedPackages();
if (pkgs != null) {
for (int i = 0; i < pkgs.length; i++) {
if ((desired = pkgs[i].findClass(classname)) != null) {
return desired;
}
}
}
// [5 1/2] OK, I lied above, we do search a couple packages,
// it should be java.lang, but we're aspectj, so we'll look in
// org.aspectj.lang, too. We assume the names are package-unqualified
// in this step.
// TODO: check that this is made final, if not, make it static
String[] pkgnames = {"java.lang", "org.aspectj.lang"};
for (int i = 0; i < pkgnames.length; i++) {
PackageDoc pkg = PackageDocImpl.getPackageDoc(pkgnames[i]);
if (pkg != null) {
if ((desired = pkg.findClass(classname)) != null) {
return desired;
}
}
}
// Found nothing.
return null;
}
/**
* Returns the fields visible in this type.
*
* @return an array of FieldDoc representing
* the fields visible in this type.
*/
public FieldDoc[] fields() {
if (fieldDocs == null) {
fieldDocs = createFields();
}
return (FieldDoc[])fieldDocs.toArray
(new org.aspectj.ajdoc.FieldDoc[fieldDocs.size()]);
}
/**
* Returns true
is this type is externalizable.
*
* @return true
is this type is externalizable.
*/
public boolean isExternalizable() {
return false; //TODO
}
/**
* Returns true
if this type is serializable.
*
* @return true
if this type is serializable.
*/
public boolean isSerializable() {
for (Iterator i = typeDec().getSuperInterfaceTypes().iterator();
i.hasNext();) {
if (((Type)i.next()).getId().equals("java.io.Serializable")) {
return true;
}
}
return false;
}
/**
* Returns the methods visible in this type.
*
* @return an array of MethodDoc representing the
* methods visible in this type.
*/
public MethodDoc[] methods() {
if (methodDocs == null) {
methodDocs = createMethods();
}
return (MethodDoc[])methodDocs.toArray
(new org.aspectj.ajdoc.MethodDoc[methodDocs.size()]);
}
/**
* Returns the serializable methods visible in this type.
*
* @return an array of MethodDoc representing the
* serializable methods visible in this type.
*/
public MethodDoc[] serializationMethods() {
List ser = new ArrayList();
MethodDoc[] mds = methods();
for (int i = 0, N = mds.length; i < N; i++) {
if (mds[i].tags("@serialized").length > 1) ser.add(mds[i]);
}
return (MethodDoc[])ser.toArray(new MethodDoc[ser.size()]);
}
/**
* Returns the serializable fields visible in this type.
*
* @return an array of MethodDoc representing the
* serializable fields visible in this type.
*/
public FieldDoc[] serializableFields() {
List ser = new ArrayList();
FieldDoc[] fds = fields();
for (int i = 0, N = fds.length; i < N; i++) {
if (fds[i].serialFieldTags().length > 1) ser.add(fds[i]);
}
return (FieldDoc[])ser.toArray(new FieldDoc[ser.size()]);
}
/**
* Returns true
is this type contains
* visible serializable fields.
*
* @return true
is this type contains
* visible serializable fields.
*/
public boolean definesSerializableFields() {
return serializableFields().length > 0;
}
/**
* Returns the super type of this type. The return value
* is guaranteed to be non-null unless this represents
* java.lang.Object.
*
* @return a ClassDoc representing the super type of this type.
* or null if this represents java.lang.Object.
*/
public com.sun.javadoc.ClassDoc superclass() {
if ("java.lang.Object".equals(qualifiedTypeName())) {
return null;
} else {
TypeDec superType = typeDec().getSuperClassType().getTypeDec();
return ClassDocImpl.getInstance(superType);
}
}
/**
* Returns true
is c
is a
* subtype of this
.
*
* @return true
is c
is a
* subtype of this
.
*/
public boolean subclassOf(com.sun.javadoc.ClassDoc c) {
return c != null && c.equals(superclass());
}
/**
* Returns the interfaces this type implements.
*
* @return an array of ClassDoc representing the
* interfaces this type implements.
*/
public com.sun.javadoc.ClassDoc[] interfaces() {
if (interfaceDocs == null) {
interfaceDocs = createInterfaces();
}
return (ClassDoc[])interfaceDocs.toArray
(new org.aspectj.ajdoc.ClassDoc[interfaceDocs.size()]);
}
/**
* Returns the constructors visible in this type.
*
* @return an array of ConstructorDoc representing the
* visible constructors in this type.
*/
public ConstructorDoc[] constructors() {
if (constructorDocs == null) {
constructorDocs = createConstructors();
}
return (ConstructorDoc[])constructorDocs.toArray
(new org.aspectj.ajdoc.ConstructorDoc[constructorDocs.size()]);
}
/**
* Returns the inner class visible in this type.
*
* @return an array of ClassDoc representing the inner
* classes visible in this type.
*/
public com.sun.javadoc.ClassDoc[] innerClasses() {
if (innerclassDocs == null) {
innerclassDocs = createInnerTypes();
}
final int size = innerclassDocs.size();
return (ClassDoc[])innerclassDocs.toArray
(new org.aspectj.ajdoc.ClassDoc[size]);
}
/**
* Returns the types imported on demand by this type.
*
* @return an array of ClassDoc representing the
* types imported on demand by this type.
*/
public com.sun.javadoc.ClassDoc[] importedClasses() {
return (ClassDoc[])importedClasses.toArray
(new org.aspectj.ajdoc.ClassDoc[importedClasses.size()]);
}
/**
* Returns the packages imported on demand by this type.
*
* @return an array of PackageDoc representing the
* packages imported on demand by this type.
*/
public PackageDoc[] importedPackages() {
return (PackageDoc[])importedPackages.toArray
(new org.aspectj.ajdoc.PackageDoc[importedPackages.size()]);
}
/**
* Returns the pointcuts visible in this type.
*
* @return an array of PointcutDoc representing the
* pointcuts visible in this type.
*/
public PointcutDoc[] pointcuts() {
if (pointcutDocs == null) {
pointcutDocs = createPointcuts();
}
return (PointcutDoc[])pointcutDocs.toArray
(new PointcutDoc[pointcutDocs.size()]);
}
/**
* Returns true
is this type is abstract
.
*
* @return true
is this type is abstract
.
*/
public boolean isAbstract() {
return typeDec().isAbstract();
}
/**
* Returns true
is this type is as exception.
*
* @return true
is this type is an instance
* of java.lang.Exception.
*/
public boolean isException() {
//TODO: make lazy
for (com.sun.javadoc.ClassDoc superclass = superclass();
superclass != null &&
!superclass.qualifiedTypeName().equals("java.lang.Object");
superclass = superclass.superclass()) {
if (superclass.qualifiedTypeName().equals("java.lang.Exception")) {
return true;
}
}
return false;
}
/**
* Returns true
is this type is an error.
*
* @return true
is this type is an instance
* of java.lang.Error.
*/
public boolean isError() {
//TODO: make lazy
for (com.sun.javadoc.ClassDoc superclass = superclass();
superclass != null &&
!superclass.qualifiedTypeName().equals("java.lang.Object");
superclass = superclass.superclass()) {
if (superclass.qualifiedTypeName().equals("java.lang.Error")) {
return true;
}
}
return false;
}
/**
* Returns the introductions affecting a ClassDoc's
* type hierarchy.
*
* @return an array of IntroducedSuperDoc representing the
* introductions of this ClassDoc that affect its
* type hierarchy.
*/
public IntroducedSuperDoc[] introducers() {
if (introducers == null) {
introducers = createIntroducers();
}
return (IntroducedSuperDoc[])introducers.toArray
(new IntroducedSuperDoc[introducers.size()]);
}
/**
* Returns true
is this is an interface
.
*
* @return true
is this is an interface
.
*/
public boolean isInterface() {
return typeDec() instanceof InterfaceDec;
}
/**
* Returns true
is this is a class
.
*
* @return true
is this is a class
.
*/
public boolean isClass() {
return typeDec() instanceof ClassDec;
}
/**
* Returns true
is this is an aspect
.
*
* @return true
is this is an aspect
.
*/
public boolean isAspect() {
return typeDec() instanceof AspectDec;
}
/**
* Returns true
is this class is neither
* an error nor an exception, but this still could be
* an aspect.
*
* @return true
is this class is neither
* an error nor an exception, but this still could be
* an aspect.
*/
public boolean isOrdinaryClass() {
return isClass() && !(isError() || isException());
}
/**
* Returns int modifiers with the 'interface' bit set.
*
* @return int modifiers with the 'interface' bit set.
* @see java.lang.reflect.Modifier.
*/
public int modifierSpecifier() {
return super.modifierSpecifier()
| (isInterface() ? Modifier.INTERFACE : 0);
}
/* ------------------------------------------------------------
* Implementation of Type
* ------------------------------------------------------------
*/
/**
* Returns the declaration of this type -- null if
* this isn't included.
*
* @return the ClassDoc represented by this Type or null
* if this isn't included.
*/
public com.sun.javadoc.ClassDoc asClassDoc() {
return isIncluded() ? this : null;
}
/**
* Returns this type's dimension information as a String.
*
* @return this type's dimension information as a String.
*/
public String dimension() {
return "";
}
/**
* Returns qualified name of type excluding
* any dimension information.
*
* @return qualified name of type excluding
* any dimension information.
*/
public String qualifiedTypeName() {
return typeDec().getFullName().replace('$', '.');
}
/**
* Returns unqualified name of type excluding
* any dimension information.
*
* @return unqualified name of type excluding
* any dimension information.
*/
public String typeName() {
return typeDec().getId().replace('$', '.');
}
/**
* Returns the Collection of IntroducedSuperDec that
* introduce a type intro this's type hierarchy. At the
* same time, the method makes sure this
is
* added to every IntroducedSuperDec's list of targets.
*
* @return Collection of IntroducedSuperDec that
* introduce a type intro this's type hierarchy.
*/
private Collection createIntroducers() {
Set affectedBy = ajc().getCorrespondences().getAffectedBy(typeDec);
if (affectedBy.size() < 1) {
return Collections.EMPTY_LIST;
}
Collection list = new ArrayList();
for (Iterator i = affectedBy.iterator(); i.hasNext();) {
Object o = i.next();
if (o instanceof IntroducedSuperDec) {
IntroducedSuperDec dec = (IntroducedSuperDec)o;
TypeDec owner = ((NameType)dec.getDeclaringType()).getTypeDec();
AspectDocImpl ad = (AspectDocImpl)ClassDocImpl.getInstance(owner);
IntroducedSuperDocImpl id = (IntroducedSuperDocImpl)ad.introDocForDec(dec);
list.add(id);
id.addTarget(this);
}
}
return list;
}
/* ------------------------------------------------------------
* Factory instantiation
* ------------------------------------------------------------
*/
/**
* Inner class in charge of creating instances of ClassDocImpl.
*/
private final static class Factory {
private final Map typeDecsToClassDocs = new HashMap();
private final Map qualifiedNamesToClassDocs = new HashMap();
public final ClassDocImpl find(String qualifiedName) {
return (ClassDocImpl)qualifiedNamesToClassDocs.get(qualifiedName);
}
public final ClassDocImpl getInstance(TypeDec typeDec) {
if (typeDec == null) return null;
ClassDocImpl outerDoc = getInstance(typeDec.getEnclosingTypeDec());
return getInstance(outerDoc, typeDec);
}
public final ClassDocImpl getInstance(ClassDoc outerDoc,
TypeDec typeDec) {
if (typeDec == null) return null;
ClassDocImpl cd = (ClassDocImpl)typeDecsToClassDocs.get(typeDec);
if (cd == null) {
cd = makeInstance(outerDoc, typeDec);
/*
Object o = typeDecsToClassDocs.put(typeDec, cd);
if (null != o) {
throw new Error("new " + cd + " displaced " + o + " for " + typeDec);
}
*/
}
return cd;
}
private final ClassDocImpl makeInstance(ClassDoc outerDoc,
TypeDec typeDec) {
ClassDocImpl result = null;
if (typeDec instanceof AspectDec) {
result = new AspectDocImpl(outerDoc, (AspectDec)typeDec);
} else {
result = new ClassDocImpl(outerDoc, typeDec);
}
if (null == result.containingPackage()) {
System.err.println("Warning: unable to add "
+ result + " to package");
}
return result;
}
/**
* constructor installs itself here before generating imports.
* fyi: not Thread-safe since available from factory before
* construction completes
* @return object displaced, if any - error if not null
*/
private final Object put(ClassDocImpl classdoc, TypeDec typeDec) {
Object result = typeDecsToClassDocs.put(typeDec, classdoc);
if (null == result) {
result = qualifiedNamesToClassDocs.put(classdoc.qualifiedName(), classdoc);
}
return result;
}
} // factory
}