/* * 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; } }