blob: 45af4aa30576d0ed751a807f374e4de7a10d9881 [file] [log] [blame]
// Copyright 2006 Google Inc. All Rights Reserved.
package com.google.gwt.dev.jjs;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
import com.google.gwt.dev.jdt.SourceOracle;
import com.google.gwt.dev.jdt.StaticCompilationUnitProvider;
import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd;
import com.google.gwt.dev.util.log.AbstractTreeLogger;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import junit.framework.TestCase;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class ReflectiveWebModeCompilerTestCase extends TestCase {
public ReflectiveWebModeCompilerTestCase() {
// Build a map of packages and classes.
// Each package P is represented by a nested class named
// "Package_P", whose methods are declared as "src_T()",
// where T is the name of a type within logical package P.
// Calling src_T() produces the source for type T.
// The default package class should be called "Package_".
//
ctorMapPackagesInTestCase(getClass());
}
public void compile(String appClass, Map rebinds)
throws UnableToCompleteException {
rebinds = rebinds != null ? rebinds : new HashMap();
AbstractTreeLogger logger = new PrintWriterTreeLogger();
logger.setMaxDetail(TreeLogger.INFO);
RebindPermOracleImpl rpoi = new RebindPermOracleImpl(rebinds);
SourceOracleReflectiveDecorator soi = new SourceOracleReflectiveDecorator();
WebModeCompilerFrontEnd astCompiler = new WebModeCompilerFrontEnd(soi, rpoi);
JavaToJavaScriptCompiler jjs = new JavaToJavaScriptCompiler(logger,
astCompiler, new String[]{appClass});
jjs.compile(logger, rpoi);
}
private class SourceOracleReflectiveDecorator implements SourceOracle {
private final SourceOracle inner = new SourceOracleImpl();
public CompilationUnitProvider findCompilationUnit(TreeLogger logger,
String sourceTypeName) throws UnableToCompleteException {
CompilationUnitProvider result = inner.findCompilationUnit(logger,
sourceTypeName);
if (result == null) {
int lastDot = sourceTypeName.lastIndexOf('.');
String packageName = "";
String simpleName = sourceTypeName;
if (lastDot != -1) {
packageName = sourceTypeName.substring(0, lastDot);
simpleName = sourceTypeName.substring(lastDot + 1);
}
String mangledPackageName = makeMangledPackageName(packageName);
Map methodsByMangledClassName = (Map) methodMapByPackageName
.get(mangledPackageName);
if (methodsByMangledClassName != null) {
String mangledSimpleName = makeMangledSimpleName(simpleName);
Method method = (Method) methodsByMangledClassName
.get(mangledSimpleName);
if (method != null) {
try {
String source = (String) method.invoke(null, new Object[0]);
result = new StaticCompilationUnitProvider(packageName,
simpleName, source.toCharArray());
} catch (IllegalArgumentException e) {
e.printStackTrace();
return null;
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
} catch (InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
}
}
return result;
}
public boolean isPackage(String possiblePackageName) {
boolean result = inner.isPackage(possiblePackageName);
if (!result) {
String mangledName = makeMangledPackageName(possiblePackageName);
// Any matching prefix qualifies.
//
for (Iterator iter = methodMapByPackageName.keySet().iterator(); iter
.hasNext();) {
String testMangledPackageName = (String) iter.next();
if (testMangledPackageName.startsWith(mangledName))
return true;
}
}
return result;
}
}
private void ctorMapMethodsInPackage(Class packageClass,
Map/* <String, Method> */methodByName) {
// We build the map from the top of the hierachy downward, so that map
// inserts in derived classes will override those in superclasses.
//
Class superClass = packageClass.getSuperclass();
if (superClass != null)
ctorMapMethodsInPackage(superClass, methodByName);
// Now contribute to the map on behalf of packageClass.
//
Method[] methods = packageClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
String methodName = method.getName();
if (methodName.startsWith("src_")) {
if (method.getParameterTypes().length == 0) {
int modifiers = method.getModifiers();
if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)) {
// This counts as a source-producing method.
//
method.setAccessible(true);
methodByName.put(methodName, method);
} else {
System.err.println("Source method " + methodName + " in class "
+ packageClass.getName() + " should be 'public' and 'static'");
}
}
}
}
}
private void ctorMapPackagesInTestCase(Class testCaseClass) {
// We build the map from the top of the hierachy downward, so that map
// inserts in derived classes will override those in superclasses.
//
if (!testCaseClass.equals(ReflectiveWebModeCompilerTestCase.class)) {
Class superClass = testCaseClass.getSuperclass();
if (superClass != null)
ctorMapPackagesInTestCase(superClass);
}
// Now contribute to the map on behalf of containingClass.
//
Class[] nestedClasses = testCaseClass.getDeclaredClasses();
for (int i = 0; i < nestedClasses.length; i++) {
Class nestedClass = nestedClasses[i];
String nestedClassName = nestedClass.getName();
int indexOfSimpleName = nestedClassName.lastIndexOf('$') + 1;
nestedClassName = nestedClassName.substring(indexOfSimpleName);
if (nestedClassName.startsWith("Package_")) {
int modifiers = nestedClass.getModifiers();
if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)) {
// This counts as a package.
//
Map/* <String, Method> */methodMap = (Map) methodMapByPackageName
.get(nestedClassName);
if (methodMap == null) {
methodMap = new HashMap();
methodMapByPackageName.put(nestedClassName, methodMap);
}
// Add source-producing methods.
//
ctorMapMethodsInPackage(nestedClass, methodMap);
} else {
System.err.println("Package class " + nestedClassName + " in class "
+ testCaseClass.getName() + " should be 'public' and 'static'");
}
}
}
}
private String makeMangledPackageName(String packageName) {
packageName = "Package_" + packageName.replace('.', '_');
return packageName;
}
private String makeMangledSimpleName(String typeName) {
return "src_" + typeName;
}
private final Map/* <String, Map<String, Method>> */methodMapByPackageName = new HashMap();
}