![JAR search and dependency download from the Maven repository](/logo.png)
com.google.gwt.reflect.rebind.ReflectionUtilAst Maven / Gradle / Ivy
The newest version!
package com.google.gwt.reflect.rebind;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.jjs.UnifyAstView;
import com.google.gwt.dev.jjs.ast.JAbstractMethodBody;
import com.google.gwt.dev.jjs.ast.JCastOperation;
import com.google.gwt.dev.jjs.ast.JClassLiteral;
import com.google.gwt.dev.jjs.ast.JExpression;
import com.google.gwt.dev.jjs.ast.JFieldRef;
import com.google.gwt.dev.jjs.ast.JLocal;
import com.google.gwt.dev.jjs.ast.JLocalRef;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodBody;
import com.google.gwt.dev.jjs.ast.JMethodCall;
import com.google.gwt.dev.jjs.ast.JParameterRef;
import com.google.gwt.dev.jjs.ast.JReturnStatement;
import com.google.gwt.dev.jjs.ast.JStatement;
import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.ast.js.JsniClassLiteral;
import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
import java.util.ArrayList;
import java.util.List;
public final class ReflectionUtilAst {
private static final Type logLevel = Type.DEBUG;
public static final String MAGIC_CLASS_SUFFIX = "_MC";
private ReflectionUtilAst() {}
public static ArrayList getTypeNames(final ArrayList params) {
final ArrayList list = new ArrayList();
for (final JType param : params) {
list.add(param.getName());
}
return list ;
}
public static JClassLiteral extractClassLiteral(final TreeLogger logger, final JExpression inst, final UnifyAstView ast, final boolean strict) throws UnableToCompleteException {
return ReflectionUtilAst.extractImmutableNode(logger, JClassLiteral.class, inst, ast, strict);
}
public static JClassLiteral extractClassLiteral(final TreeLogger logger, final JMethodCall methodCall, final int paramPosition, final UnifyAstView ast) throws UnableToCompleteException {
return extractClassLiteral(logger, methodCall, paramPosition, ast, true);
}
public static JClassLiteral extractClassLiteral(final TreeLogger logger,
final JMethodCall methodCall, final int paramPosition, final UnifyAstView ast,
final boolean strict) throws UnableToCompleteException {
final List args = methodCall.getArgs();
final JExpression arg = args.get(paramPosition);
final JClassLiteral classLit = extractClassLiteral(logger, arg, ast, false);
if (strict && classLit == null) {
logger.log(Type.ERROR, "The method " +
methodCall.getTarget().toSource() + " only accepts class literals." +
" You sent a " + arg.getClass() + " : " + arg.toSource()+" from method "
+ methodCall.toSource()+ " with arguments "
+ methodCall.getArgs()+ ";");
throw new UnableToCompleteException();
}
return classLit;
}
@SuppressWarnings("unchecked")
public static X extractImmutableNode(
final TreeLogger logger, final Class type, JExpression inst,
final UnifyAstView ast, final boolean strict) throws UnableToCompleteException {
final boolean doLog = logger.isLoggable(logLevel);
if (inst == null) {
failIfStrict(logger, strict, inst, type);
return null;
}
if (doLog) {
logger.log(logLevel, "Extracting "+type.getName()+" from "+inst.getClass().getName()+": "+inst);
}
try {
if (type.isAssignableFrom(inst.getClass())) {
// We have a winner!
return (X)inst;
} else if (inst instanceof JLocalRef) {
final JLocal local = ((JLocalRef)inst).getLocal();
if (local.isFinal()) {
final JExpression localInit = local.getInitializer();
if (localInit == null) {
inst = localInit;
} else {
return extractImmutableNode(logger, type, localInit, ast, strict);
}
} else {
if (doLog) {
ReflectionUtilAst.logNonFinalError(logger, inst);
}
}
} else if (inst instanceof JFieldRef) {
com.google.gwt.dev.jjs.ast.JField field = ((JFieldRef)inst).getField();
if (field.isExternal()) {
field = ast.translate(field);
}
if (field.getLiteralInitializer() != null) {
return extractImmutableNode(logger, type, field.getLiteralInitializer(), ast, strict);
} else if (field.isFinal()) {
return extractImmutableNode(logger, type, field.getInitializer(), ast, strict);
} else {
logger.log(logLevel, "Not final "+field);
if (doLog) {
ReflectionUtilAst.logNonFinalError(logger, inst);
}
}
} else if (inst instanceof JCastOperation){
final JCastOperation op = (JCastOperation) inst;
return extractImmutableNode(logger, type, op.getExpr(), ast, strict);
} else if (inst instanceof JMethodCall){
final JMethodCall call = (JMethodCall)inst;
JMethod target = (call).getTarget();
if (isGetMagicClass(target) || isClassCast(target)) {
return extractImmutableNode(logger, type, call.getArgs().get(0), ast, strict);
}
if (target.isExternal()) {
target = ast.translate(target);
}
final JAbstractMethodBody method = target.getBody();
// TODO: maybe enforce final / static on method calls
if (method.isNative()) {
final JsniMethodBody jsni = (JsniMethodBody)method;
if (JClassLiteral.class.isAssignableFrom(type)) {
final List literals = jsni.getClassRefs();
if (literals.size() == 1) {
// Might want to not allow jsni methods to magically tag class literals...
return (X)literals.get(0);
}
}
} else {
final JMethodBody java = (JMethodBody)method;
final ArrayList returns = new ArrayList();
for (final JStatement statement : java.getStatements()) {
if (statement instanceof JReturnStatement) {
returns.add((JReturnStatement)statement);
}
}
if (returns.size() == 1) {
return extractImmutableNode(logger, type, returns.get(0).getExpr(), ast, strict);
} else {
if (doLog) {
logger.log(logLevel, "Java "+type.getName()+" provider method must have one " +
"and only one return statement, which returns a "+ type.getName()+ " " + method);
}
}
}
} else {
if (ReflectionUtilAst.isUnknownType(inst)) {
logger.log(Type.WARN, "Encountered unhandled type while searching for "+
type.getName()+ ": "+ReflectionUtilAst.debug(inst));
}
}
failIfStrict(logger, strict, inst, type);
} catch (final Exception e) {
logger.log(Type.ERROR, "Unknown exception in extractImmutableNode", e);
throw new UnableToCompleteException();
}
return null;
}
public static String debug(final JExpression inst) {
return inst == null ? "null" : inst.getClass()+" ["+inst.toSource()+"] @"+inst.getSourceInfo();
}
private static void failIfStrict(final TreeLogger logger, final boolean strict,
final JExpression inst, final Class> type) throws UnableToCompleteException {
if (strict) {
logger.log(logLevel, "Unable to acquire a " + type.getCanonicalName()
+ " from "+ReflectionUtilAst.debug(inst));
throw new UnableToCompleteException();
}
}
private static boolean isGetMagicClass(final JMethod target) {
return
(target.getName().equals("magicClass") &&
target.getEnclosingType().getName().equals("com.google.gwt.reflect.shared.GwtReflect"))
||
(target.getName().equals("enhanceClass") &&
target.getEnclosingType().getName().endsWith(MAGIC_CLASS_SUFFIX))
;
}
private static boolean isClassCast(final JMethod target) {
return target.getName().equals("cast") &&
target.getEnclosingType().getName().equals(Class.class.getName());
}
private static boolean isUnknownType(final JExpression inst) {
return !(inst instanceof JParameterRef);
}
private static void logNonFinalError(final TreeLogger logger, final JExpression inst) {
logger.log(logLevel, "Traced class literal down to a "+ debug(inst)+","
+ " but this member was not marked final."
+ " Aborting class literal search due to lack of determinism.");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy