/* * xtc - The eXTensible Compiler * Copyright (C) 2006-2007 IBM Corp. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program 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 this program; if not, write to the Free Software * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ package xtc.lang; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import xtc.tree.Attribute; import xtc.type.AliasT; import xtc.type.ClassT; import xtc.type.InterfaceT; import xtc.type.MethodT; import xtc.type.Type; import xtc.type.VariableT; import xtc.type.VoidT; import xtc.util.SymbolTable; import xtc.util.Utilities; /** * Uses reflection to construct externally visible types and fill in the symbol * table for entities for which no source code is available. This is not a * visitor, but has similar method names to emphasize the similarities with * JavaExternalAnalyzer. * * @author Martin Hirzel * @version $Revision: 1.27 $ */ public final class JavaNoSourceAnalyzer { public final SymbolTable _table; public JavaNoSourceAnalyzer(final SymbolTable table) { _table = table; } private final Type defineMethod(final List<Attribute> modifiers, MethodT result, final String symbol) { for (final Attribute mod : modifiers) result.addAttribute(mod); _table.current().define(symbol, result); _table.enter(symbol); result.scope(_table.current().getQualifiedName()); _table.exit(); JavaEntities.currentType(_table).getMethods().add(result); assert result.isMethod(); return result; } public final void visitClassBody(final Class clazz) { final Class[] classes = clazz.getDeclaredClasses(); for (int i = 0; i < classes.length; i++) visitClassOrInterface(classes[i]); final Constructor[] constructors = clazz.getDeclaredConstructors(); for (int i = 0; i < constructors.length; i++) visitMethodDeclaration(constructors[i]); final Field[] fields = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) visitFieldDeclaration(fields[i]); final Method[] methods = clazz.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) visitMethodDeclaration(methods[i]); } private static String getQName(final Class clazz) { final Class declaringClass = clazz.getDeclaringClass(); if (null == declaringClass) return clazz.getName(); return Utilities.qualify(getQName(declaringClass), clazz.getSimpleName()); } public final Type visitClassDeclaration(final Class clazz) { if (clazz.isInterface()) throw new Error(clazz.getName()); final List<Attribute> modifiers = visitModifiers(clazz.getModifiers()); final String canonicalName = getQName(clazz); final String simpleName; { final String name = Utilities.getName(canonicalName); final int i = name.lastIndexOf('$'); if (-1 == i) simpleName = name; else simpleName = name.substring(1 + i); } final Type parent; final Class superClass = clazz.getSuperclass(); if (null == superClass) { parent = null; if (!"java.lang.Object".equals(clazz.getName())) throw new Error(); } else { parent = visitType(clazz.getSuperclass()); } final List<Type> interfaces = visitTypeList(clazz.getInterfaces()); final ClassT result = new ClassT(canonicalName, parent, interfaces, new ArrayList<Type>(), new ArrayList<Type>()); for (final Attribute mod : modifiers) result.addAttribute(mod); final String tagName = SymbolTable.toTagName(simpleName); _table.current().define(tagName, result); _table.enter(simpleName); result.scope(_table.current().getQualifiedName()); visitClassBody(clazz); _table.exit(); assert result.isClass(); return result; } public final Type visitClassOrInterface(final Class clazz) { return clazz.isInterface() ? visitInterfaceDeclaration(clazz) : visitClassDeclaration(clazz); } public final Type visitFieldDeclaration(final Field field) { final Type type = visitType(field.getType()); final VariableT result = VariableT.newField(type, field.getName()); for (final Attribute mod : visitModifiers(field.getModifiers())) result.addAttribute(mod); _table.current().define(field.getName(), result); result.scope(_table.current().getQualifiedName()); JavaEntities.currentType(_table).getFields().add(result); assert JavaEntities.isFieldT(result); return result; } public final List<Type> visitFormalParameters(final Class[] types) { final List<Type> result = new ArrayList<Type>(types.length); for (int i = 0; i < types.length; i++) { final VariableT p = VariableT.newParam(visitType(types[i]), "x" + i); assert JavaEntities.isParameterT(p); result.add(p); } return result; } public final Type visitInterfaceDeclaration(final Class interfaze) { if (!interfaze.isInterface()) throw new Error(interfaze.getName()); final List<Attribute> modifiers = visitModifiers(interfaze.getModifiers()); final String canonicalName = interfaze.getName(); final String simpleName; { final String name = Utilities.getName(canonicalName); final int i = name.lastIndexOf('$'); if (-1 == i) simpleName = name; else simpleName = name.substring(1 + i); } final List<Type> interfaces = visitTypeList(interfaze.getInterfaces()); final InterfaceT result = new InterfaceT(canonicalName, interfaces, new ArrayList<Type>(), new ArrayList<Type>()); for (final Attribute mod : modifiers) result.addAttribute(mod); final String tagName = SymbolTable.toTagName(simpleName); _table.current().define(tagName, result); _table.enter(simpleName); result.scope(_table.current().getQualifiedName()); visitClassBody(interfaze); _table.exit(); assert result.isInterface(); return result; } public final Type visitMethodDeclaration(final Constructor method) { final List<Attribute> modifiers = visitModifiers(method.getModifiers()); final Type base = visitType(method.getDeclaringClass()); final List<Type> exceptions = visitTypeList(method.getExceptionTypes()); final String symbol = JavaEntities.methodSymbolFromConstructor(method); final List<Type> parameters = visitFormalParameters(method.getParameterTypes()); final MethodT methodT = JavaEntities.newRawConstructor(base, parameters, exceptions); final Type result = defineMethod(modifiers, methodT, symbol); return result; } public final Type visitMethodDeclaration(final Method method) { final List<Attribute> modifiers = visitModifiers(method.getModifiers()); final Type returnType = visitType(method.getReturnType()); final String name = method.getName(); final List<Type> exceptions = visitTypeList(method.getExceptionTypes()); final String symbol = JavaEntities.methodSymbolFromMethod(method); final List<Type> parameters = visitFormalParameters(method.getParameterTypes()); final MethodT methodT = new MethodT(returnType, name, parameters, false, exceptions); final Type result = defineMethod(modifiers, methodT, symbol); return result; } public final List<Attribute> visitModifiers(final int modifiers) { final List<Attribute> result = new ArrayList<Attribute>(); if (Modifier.isAbstract(modifiers)) result.add(JavaEntities.nameToModifier("abstract")); if (Modifier.isFinal(modifiers)) result.add(JavaEntities.nameToModifier("final")); if (Modifier.isNative(modifiers)) result.add(JavaEntities.nameToModifier("native")); if (Modifier.isPrivate(modifiers)) result.add(JavaEntities.nameToModifier("private")); if (Modifier.isProtected(modifiers)) result.add(JavaEntities.nameToModifier("protected")); if (Modifier.isPublic(modifiers)) result.add(JavaEntities.nameToModifier("public")); if (Modifier.isStatic(modifiers)) result.add(JavaEntities.nameToModifier("static")); if (Modifier.isStrict(modifiers)) result.add(JavaEntities.nameToModifier("strictfp")); if (Modifier.isSynchronized(modifiers)) result.add(JavaEntities.nameToModifier("synchronized")); if (Modifier.isTransient(modifiers)) result.add(JavaEntities.nameToModifier("transient")); if (Modifier.isVolatile(modifiers)) result.add(JavaEntities.nameToModifier("volatile")); return result; } public final Type visitType(final Class clazz) { Class componentC = clazz; int dimensions = 0; while (componentC.isArray()) { componentC = componentC.getComponentType(); dimensions++; } final Type componentT = componentC.isPrimitive() ? visitTypeName(componentC.getName()) : new AliasT(componentC.getName()); final Type result = JavaEntities.typeWithDimensions(componentT, dimensions); assert JavaEntities.isReturnT(result); return result; } public final List<Type> visitTypeList(final Class[] types) { final List<Type> result = new ArrayList<Type>(types.length); for (int i = 0; i < types.length; i++) result.add(visitType(types[i])); return result; } public final Type visitTypeName(final String name) { if (1 == name.length()) { switch (name.charAt(0)) { case 'Z': return JavaEntities.nameToBaseType("boolean"); case 'B': return JavaEntities.nameToBaseType("byte"); case 'C': return JavaEntities.nameToBaseType("char"); case 'D': return JavaEntities.nameToBaseType("double"); case 'F': return JavaEntities.nameToBaseType("float"); case 'I': return JavaEntities.nameToBaseType("int"); case 'J': return JavaEntities.nameToBaseType("long"); case 'S': return JavaEntities.nameToBaseType("short"); } } final Type result = JavaEntities.nameToBaseType(name); assert result.isBoolean() || result.isNumber() || result instanceof VoidT; return result; } }