/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import com.sun.javadoc.*;
import com.sun.tools.doclets.*;
import org.clearsilver.HDF;
import org.clearsilver.CS;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
public class Converter
{
private static RootDoc root;
public static void makeInfo(RootDoc r)
{
root = r;
int N, i;
// create the objects
ClassDoc[] classDocs = r.classes();
N = classDocs.length;
for (i=0; i<N; i++) {
Converter.obtainClass(classDocs[i]);
}
ArrayList<ClassInfo> classesNeedingInit2 = new ArrayList<ClassInfo>();
// fill in the fields that reference other classes
while (mClassesNeedingInit.size() > 0) {
i = mClassesNeedingInit.size()-1;
ClassNeedingInit clni = mClassesNeedingInit.get(i);
mClassesNeedingInit.remove(i);
initClass(clni.c, clni.cl);
classesNeedingInit2.add(clni.cl);
}
mClassesNeedingInit = null;
for (ClassInfo cl: classesNeedingInit2) {
cl.init2();
}
finishAnnotationValueInit();
// fill in the "root" stuff
mRootClasses = Converter.convertClasses(r.classes());
}
private static ClassInfo[] mRootClasses;
public static ClassInfo[] rootClasses()
{
return mRootClasses;
}
public static ClassInfo[] allClasses() {
return (ClassInfo[])mClasses.all();
}
private static void initClass(ClassDoc c, ClassInfo cl)
{
MethodDoc[] annotationElements;
if (c instanceof AnnotationTypeDoc) {
annotationElements = ((AnnotationTypeDoc)c).elements();
} else {
annotationElements = new MethodDoc[0];
}
cl.init(Converter.obtainType(c),
Converter.convertClasses(c.interfaces()),
Converter.convertTypes(c.interfaceTypes()),
Converter.convertClasses(c.innerClasses()),
Converter.convertMethods(c.constructors(false)),
Converter.convertMethods(c.methods(false)),
Converter.convertMethods(annotationElements),
Converter.convertFields(c.fields(false)),
Converter.convertFields(c.enumConstants()),
Converter.obtainPackage(c.containingPackage()),
Converter.obtainClass(c.containingClass()),
Converter.obtainClass(c.superclass()),
Converter.obtainType(c.superclassType()),
Converter.convertAnnotationInstances(c.annotations())
);
cl.setHiddenMethods(Converter.getHiddenMethods(c.methods(false)));
cl.setNonWrittenConstructors(Converter.convertNonWrittenConstructors(c.constructors(false)));
cl.init3(Converter.convertTypes(c.typeParameters()), Converter.convertClasses(c.innerClasses(false)));
}
public static ClassInfo obtainClass(String className)
{
return Converter.obtainClass(root.classNamed(className));
}
public static PackageInfo obtainPackage(String packageName)
{
return Converter.obtainPackage(root.packageNamed(packageName));
}
private static TagInfo convertTag(Tag tag)
{
return new TextTagInfo(tag.name(), tag.kind(), tag.text(),
Converter.convertSourcePosition(tag.position()));
}
private static ThrowsTagInfo convertThrowsTag(ThrowsTag tag,
ContainerInfo base)
{
return new ThrowsTagInfo(tag.name(), tag.text(), tag.kind(),
Converter.obtainClass(tag.exception()),
tag.exceptionComment(), base,
Converter.convertSourcePosition(tag.position()));
}
private static ParamTagInfo convertParamTag(ParamTag tag,
ContainerInfo base)
{
return new ParamTagInfo(tag.name(), tag.kind(), tag.text(),
tag.isTypeParameter(), tag.parameterComment(),
tag.parameterName(),
base,
Converter.convertSourcePosition(tag.position()));
}
private static SeeTagInfo convertSeeTag(SeeTag tag, ContainerInfo base)
{
return new SeeTagInfo(tag.name(), tag.kind(), tag.text(), base,
Converter.convertSourcePosition(tag.position()));
}
private static SourcePositionInfo convertSourcePosition(SourcePosition sp)
{
if (sp == null) {
return null;
}
return new SourcePositionInfo(sp.file().toString(), sp.line(),
sp.column());
}
public static TagInfo[] convertTags(Tag[] tags, ContainerInfo base)
{
int len = tags.length;
TagInfo[] out = new TagInfo[len];
for (int i=0; i<len; i++) {
Tag t = tags[i];
/*
System.out.println("Tag name='" + t.name() + "' kind='"
+ t.kind() + "'");
*/
if (t instanceof SeeTag) {
out[i] = Converter.convertSeeTag((SeeTag)t, base);
}
else if (t instanceof ThrowsTag) {
out[i] = Converter.convertThrowsTag((ThrowsTag)t, base);
}
else if (t instanceof ParamTag) {
out[i] = Converter.convertParamTag((ParamTag)t, base);
}
else {
out[i] = Converter.convertTag(t);
}
}
return out;
}
public static ClassInfo[] convertClasses(ClassDoc[] classes)
{
if (classes == null) return null;
int N = classes.length;
ClassInfo[] result = new ClassInfo[N];
for (int i=0; i<N; i++) {
result[i] = Converter.obtainClass(classes[i]);
}
return result;
}
private static ParameterInfo convertParameter(Parameter p, SourcePosition pos)
{
if (p == null) return null;
ParameterInfo pi = new ParameterInfo(p.name(), p.typeName(),
Converter.obtainType(p.type()),
Converter.convertSourcePosition(pos));
return pi;
}
private static ParameterInfo[] convertParameters(Parameter[] p, MemberDoc m)
{
SourcePosition pos = m.position();
int len = p.length;
ParameterInfo[] q = new ParameterInfo[len];
for (int i=0; i<len; i++) {
q[i] = Converter.convertParameter(p[i], pos);
}
return q;
}
private static TypeInfo[] convertTypes(Type[] p)
{
if (p == null) return null;
int len = p.length;
TypeInfo[] q = new TypeInfo[len];
for (int i=0; i<len; i++) {
q[i] = Converter.obtainType(p[i]);
}
return q;
}
private Converter()
{
}
private static class ClassNeedingInit
{
ClassNeedingInit(ClassDoc c, ClassInfo cl)
{
this.c = c;
this.cl = cl;
}
ClassDoc c;
ClassInfo cl;
};
private static ArrayList<ClassNeedingInit> mClassesNeedingInit
= new ArrayList<ClassNeedingInit>();
static ClassInfo obtainClass(ClassDoc o)
{
return (ClassInfo)mClasses.obtain(o);
}
private static Cache mClasses = new Cache()
{
@Override
protected Object make(Object o)
{
ClassDoc c = (ClassDoc)o;
ClassInfo cl = new ClassInfo(
c,
c.getRawCommentText(),
Converter.convertSourcePosition(c.position()),
c.isPublic(),
c.isProtected(),
c.isPackagePrivate(),
c.isPrivate(),
c.isStatic(),
c.isInterface(),
c.isAbstract(),
c.isOrdinaryClass(),
c.isException(),
c.isError(),
c.isEnum(),
(c instanceof AnnotationTypeDoc),
c.isFinal(),
c.isIncluded(),
c.name(),
c.qualifiedName(),
c.qualifiedTypeName(),
c.isPrimitive());
if (mClassesNeedingInit != null) {
mClassesNeedingInit.add(new ClassNeedingInit(c, cl));
}
return cl;
}
@Override
protected void made(Object o, Object r)
{
if (mClassesNeedingInit == null) {
initClass((ClassDoc)o, (ClassInfo)r);
((ClassInfo)r).init2();
}
}
@Override
ClassInfo[] all()
{
return (ClassInfo[])mCache.values().toArray(new ClassInfo[mCache.size()]);
}
};
private static MethodInfo[] getHiddenMethods(MethodDoc[] methods){
if (methods == null) return null;
ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
int N = methods.length;
for (int i=0; i<N; i++) {
MethodInfo m = Converter.obtainMethod(methods[i]);
//System.out.println(m.toString() + ": ");
//for (TypeInfo ti : m.getTypeParameters()){
// if (ti.asClassInfo() != null){
//System.out.println(" " +ti.asClassInfo().toString());
//} else {
//System.out.println(" null");
//}
//}
if (m.isHidden()) {
out.add(m);
}
}
return out.toArray(new MethodInfo[out.size()]);
}
/**
* Convert MethodDoc[] into MethodInfo[]. Also filters according
* to the -private, -public option, because the filtering doesn't seem
* to be working in the ClassDoc.constructors(boolean) call.
*/
private static MethodInfo[] convertMethods(MethodDoc[] methods)
{
if (methods == null) return null;
ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
int N = methods.length;
for (int i=0; i<N; i++) {
MethodInfo m = Converter.obtainMethod(methods[i]);
//System.out.println(m.toString() + ": ");
//for (TypeInfo ti : m.getTypeParameters()){
// if (ti.asClassInfo() != null){
//System.out.println(" " +ti.asClassInfo().toString());
//} else {
//System.out.println(" null");
//}
//}
if (m.checkLevel()) {
out.add(m);
}
}
return out.toArray(new MethodInfo[out.size()]);
}
private static MethodInfo[] convertMethods(ConstructorDoc[] methods)
{
if (methods == null) return null;
ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
int N = methods.length;
for (int i=0; i<N; i++) {
MethodInfo m = Converter.obtainMethod(methods[i]);
if (m.checkLevel()) {
out.add(m);
}
}
return out.toArray(new MethodInfo[out.size()]);
}
private static MethodInfo[] convertNonWrittenConstructors(ConstructorDoc[] methods)
{
if (methods == null) return null;
ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
int N = methods.length;
for (int i=0; i<N; i++) {
MethodInfo m = Converter.obtainMethod(methods[i]);
if (!m.checkLevel()) {
out.add(m);
}
}
return out.toArray(new MethodInfo[out.size()]);
}
private static MethodInfo obtainMethod(MethodDoc o)
{
return (MethodInfo)mMethods.obtain(o);
}
private static MethodInfo obtainMethod(ConstructorDoc o)
{
return (MethodInfo)mMethods.obtain(o);
}
private static Cache mMethods = new Cache()
{
@Override
protected Object make(Object o)
{
if (o instanceof AnnotationTypeElementDoc) {
AnnotationTypeElementDoc m = (AnnotationTypeElementDoc)o;
MethodInfo result = new MethodInfo(
m.getRawCommentText(),
Converter.convertTypes(m.typeParameters()),
m.name(), m.signature(),
Converter.obtainClass(m.containingClass()),
Converter.obtainClass(m.containingClass()),
m.isPublic(), m.isProtected(),
m.isPackagePrivate(), m.isPrivate(),
m.isFinal(), m.isStatic(), m.isSynthetic(),
m.isAbstract(), m.isSynchronized(), m.isNative(), true,
"annotationElement",
m.flatSignature(),
Converter.obtainMethod(m.overriddenMethod()),
Converter.obtainType(m.returnType()),
Converter.convertParameters(m.parameters(), m),
Converter.convertClasses(m.thrownExceptions()),
Converter.convertSourcePosition(m.position()),
Converter.convertAnnotationInstances(m.annotations())
);
result.setVarargs(m.isVarArgs());
result.init(Converter.obtainAnnotationValue(m.defaultValue(), result));
return result;
}
else if (o instanceof MethodDoc) {
MethodDoc m = (MethodDoc)o;
MethodInfo result = new MethodInfo(
m.getRawCommentText(),
Converter.convertTypes(m.typeParameters()),
m.name(), m.signature(),
Converter.obtainClass(m.containingClass()),
Converter.obtainClass(m.containingClass()),
m.isPublic(), m.isProtected(),
m.isPackagePrivate(), m.isPrivate(),
m.isFinal(), m.isStatic(), m.isSynthetic(),
m.isAbstract(), m.isSynchronized(), m.isNative(), false,
"method",
m.flatSignature(),
Converter.obtainMethod(m.overriddenMethod()),
Converter.obtainType(m.returnType()),
Converter.convertParameters(m.parameters(), m),
Converter.convertClasses(m.thrownExceptions()),
Converter.convertSourcePosition(m.position()),
Converter.convertAnnotationInstances(m.annotations())
);
result.setVarargs(m.isVarArgs());
result.init(null);
return result;
}
else {
ConstructorDoc m = (ConstructorDoc)o;
MethodInfo result = new MethodInfo(
m.getRawCommentText(),
Converter.convertTypes(m.typeParameters()),
m.name(), m.signature(),
Converter.obtainClass(m.containingClass()),
Converter.obtainClass(m.containingClass()),
m.isPublic(), m.isProtected(),
m.isPackagePrivate(), m.isPrivate(),
m.isFinal(), m.isStatic(), m.isSynthetic(),
false, m.isSynchronized(), m.isNative(), false,
"constructor",
m.flatSignature(),
null,
null,
Converter.convertParameters(m.parameters(), m),
Converter.convertClasses(m.thrownExceptions()),
Converter.convertSourcePosition(m.position()),
Converter.convertAnnotationInstances(m.annotations())
);
result.setVarargs(m.isVarArgs());
result.init(null);
return result;
}
}
};
private static FieldInfo[] convertFields(FieldDoc[] fields)
{
if (fields == null) return null;
ArrayList<FieldInfo> out = new ArrayList<FieldInfo>();
int N = fields.length;
for (int i=0; i<N; i++) {
FieldInfo f = Converter.obtainField(fields[i]);
if (f.checkLevel()) {
out.add(f);
}
}
return out.toArray(new FieldInfo[out.size()]);
}
private static FieldInfo obtainField(FieldDoc o)
{
return (FieldInfo)mFields.obtain(o);
}
private static FieldInfo obtainField(ConstructorDoc o)
{
return (FieldInfo)mFields.obtain(o);
}
private static Cache mFields = new Cache()
{
@Override
protected Object make(Object o)
{
FieldDoc f = (FieldDoc)o;
return new FieldInfo(f.name(),
Converter.obtainClass(f.containingClass()),
Converter.obtainClass(f.containingClass()),
f.isPublic(), f.isProtected(),
f.isPackagePrivate(), f.isPrivate(),
f.isFinal(), f.isStatic(), f.isTransient(), f.isVolatile(),
f.isSynthetic(),
Converter.obtainType(f.type()),
f.getRawCommentText(), f.constantValue(),
Converter.convertSourcePosition(f.position()),
Converter.convertAnnotationInstances(f.annotations())
);
}
};
private static PackageInfo obtainPackage(PackageDoc o)
{
return (PackageInfo)mPackagees.obtain(o);
}
private static Cache mPackagees = new Cache()
{
@Override
protected Object make(Object o)
{
PackageDoc p = (PackageDoc)o;
return new PackageInfo(p, p.name(),
Converter.convertSourcePosition(p.position()));
}
};
private static TypeInfo obtainType(Type o)
{
return (TypeInfo)mTypes.obtain(o);
}
private static Cache mTypes = new Cache()
{
@Override
protected Object make(Object o)
{
Type t = (Type)o;
String simpleTypeName;
if (t instanceof ClassDoc) {
simpleTypeName = ((ClassDoc)t).name();
} else {
simpleTypeName = t.simpleTypeName();
}
TypeInfo ti = new TypeInfo(t.isPrimitive(), t.dimension(),
simpleTypeName, t.qualifiedTypeName(),
Converter.obtainClass(t.asClassDoc()));
return ti;
}
@Override
protected void made(Object o, Object r)
{
Type t = (Type)o;
TypeInfo ti = (TypeInfo)r;
if (t.asParameterizedType() != null) {
ti.setTypeArguments(Converter.convertTypes(
t.asParameterizedType().typeArguments()));
}
else if (t instanceof ClassDoc) {
ti.setTypeArguments(Converter.convertTypes(((ClassDoc)t).typeParameters()));
}
else if (t.asTypeVariable() != null) {
ti.setBounds(null, Converter.convertTypes((t.asTypeVariable().bounds())));
ti.setIsTypeVariable(true);
}
else if (t.asWildcardType() != null) {
ti.setIsWildcard(true);
ti.setBounds(Converter.convertTypes(t.asWildcardType().superBounds()),
Converter.convertTypes(t.asWildcardType().extendsBounds()));
}
}
@Override
protected Object keyFor(Object o)
{
Type t = (Type)o;
String keyString = o.getClass().getName() + "/" + o.toString() + "/";
if (t.asParameterizedType() != null){
keyString += t.asParameterizedType().toString() +"/";
if (t.asParameterizedType().typeArguments() != null){
for(Type ty : t.asParameterizedType().typeArguments()){
keyString += ty.toString() + "/";
}
}
}else{
keyString += "NoParameterizedType//";
}
if (t.asTypeVariable() != null){
keyString += t.asTypeVariable().toString() +"/";
if (t.asTypeVariable().bounds() != null){
for(Type ty : t.asTypeVariable().bounds()){
keyString += ty.toString() + "/";
}
}
}else{
keyString += "NoTypeVariable//";
}
if (t.asWildcardType() != null){
keyString += t.asWildcardType().toString() +"/";
if (t.asWildcardType().superBounds() != null){
for(Type ty : t.asWildcardType().superBounds()){
keyString += ty.toString() + "/";
}
}
if (t.asWildcardType().extendsBounds() != null){
for(Type ty : t.asWildcardType().extendsBounds()){
keyString += ty.toString() + "/";
}
}
}else{
keyString += "NoWildCardType//";
}
return keyString;
}
};
private static MemberInfo obtainMember(MemberDoc o)
{
return (MemberInfo)mMembers.obtain(o);
}
private static Cache mMembers = new Cache()
{
@Override
protected Object make(Object o)
{
if (o instanceof MethodDoc) {
return Converter.obtainMethod((MethodDoc)o);
}
else if (o instanceof ConstructorDoc) {
return Converter.obtainMethod((ConstructorDoc)o);
}
else if (o instanceof FieldDoc) {
return Converter.obtainField((FieldDoc)o);
}
else {
return null;
}
}
};
private static AnnotationInstanceInfo[] convertAnnotationInstances(AnnotationDesc[] orig)
{
int len = orig.length;
AnnotationInstanceInfo[] out = new AnnotationInstanceInfo[len];
for (int i=0; i<len; i++) {
out[i] = Converter.obtainAnnotationInstance(orig[i]);
}
return out;
}
private static AnnotationInstanceInfo obtainAnnotationInstance(AnnotationDesc o)
{
return (AnnotationInstanceInfo)mAnnotationInstances.obtain(o);
}
private static Cache mAnnotationInstances = new Cache()
{
@Override
protected Object make(Object o)
{
AnnotationDesc a = (AnnotationDesc)o;
ClassInfo annotationType = Converter.obtainClass(a.annotationType());
AnnotationDesc.ElementValuePair[] ev = a.elementValues();
AnnotationValueInfo[] elementValues = new AnnotationValueInfo[ev.length];
for (int i=0; i<ev.length; i++) {
elementValues[i] = obtainAnnotationValue(ev[i].value(),
Converter.obtainMethod(ev[i].element()));
}
return new AnnotationInstanceInfo(annotationType, elementValues);
}
};
private abstract static class Cache
{
void put(Object key, Object value)
{
mCache.put(key, value);
}
Object obtain(Object o)
{
if (o == null ) {
return null;
}
Object k = keyFor(o);
Object r = mCache.get(k);
if (r == null) {
r = make(o);
mCache.put(k, r);
made(o, r);
}
return r;
}
protected HashMap<Object,Object> mCache = new HashMap<Object,Object>();
protected abstract Object make(Object o);
protected void made(Object o, Object r)
{
}
protected Object keyFor(Object o) { return o; }
Object[] all() { return null; }
}
// annotation values
private static HashMap<AnnotationValue,AnnotationValueInfo> mAnnotationValues = new HashMap();
private static HashSet<AnnotationValue> mAnnotationValuesNeedingInit = new HashSet();
private static AnnotationValueInfo obtainAnnotationValue(AnnotationValue o, MethodInfo element)
{
if (o == null) {
return null;
}
AnnotationValueInfo v = mAnnotationValues.get(o);
if (v != null) return v;
v = new AnnotationValueInfo(element);
mAnnotationValues.put(o, v);
if (mAnnotationValuesNeedingInit != null) {
mAnnotationValuesNeedingInit.add(o);
} else {
initAnnotationValue(o, v);
}
return v;
}
private static void initAnnotationValue(AnnotationValue o, AnnotationValueInfo v) {
Object orig = o.value();
Object converted;
if (orig instanceof Type) {
// class literal
converted = Converter.obtainType((Type)orig);
}
else if (orig instanceof FieldDoc) {
// enum constant
converted = Converter.obtainField((FieldDoc)orig);
}
else if (orig instanceof AnnotationDesc) {
// annotation instance
converted = Converter.obtainAnnotationInstance((AnnotationDesc)orig);
}
else if (orig instanceof AnnotationValue[]) {
AnnotationValue[] old = (AnnotationValue[])orig;
AnnotationValueInfo[] array = new AnnotationValueInfo[old.length];
for (int i=0; i<array.length; i++) {
array[i] = Converter.obtainAnnotationValue(old[i], null);
}
converted = array;
}
else {
converted = orig;
}
v.init(converted);
}
private static void finishAnnotationValueInit()
{
int depth = 0;
while (mAnnotationValuesNeedingInit.size() > 0) {
HashSet<AnnotationValue> set = mAnnotationValuesNeedingInit;
mAnnotationValuesNeedingInit = new HashSet();
for (AnnotationValue o: set) {
AnnotationValueInfo v = mAnnotationValues.get(o);
initAnnotationValue(o, v);
}
depth++;
}
mAnnotationValuesNeedingInit = null;
}
}