package xapi.dev.test.gwt.rebind; import java.util.Queue; import junit.framework.Assert; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.dev.jjs.MagicMethodGenerator; import com.google.gwt.dev.jjs.SourceInfo; import com.google.gwt.dev.jjs.UnifyAstListener; import com.google.gwt.dev.jjs.UnifyAstView; import com.google.gwt.dev.jjs.ast.Context; import com.google.gwt.dev.jjs.ast.JDeclaredType; import com.google.gwt.dev.jjs.ast.JExpression; import com.google.gwt.dev.jjs.ast.JExpressionStatement; import com.google.gwt.dev.jjs.ast.JField; import com.google.gwt.dev.jjs.ast.JFieldRef; 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.js.JsniMethodBody; import com.google.gwt.dev.jjs.impl.UnifyAst.UnifyVisitor; import xapi.dev.test.gwt.MagicMethodGwtTest; /** * A reference implementation of a magic method generator. * * We use this generator to swap out the method {@link MagicMethodGwtTest#replaceMe()}, * and have it return a different value if production mode. * * We also insert code at the beginning of our entry point, * to test that the {@link UnifyAstListener} api is being implemented correctly. * * @author James X. Nelson (james@wetheinter.net, @james) * */ @SuppressWarnings("deprecation") public class MagicMethodTestGenerator implements MagicMethodGenerator, UnifyAstListener { @Override public JExpression injectMagic(TreeLogger logger, JMethodCall methodCall, JMethod enclosingMethod, Context context, UnifyAstView ast) throws UnableToCompleteException { JDeclaredType testClass = enclosingMethod.getEnclosingType(); for (JField field : testClass.getFields()) { if (field.getName().equals("prodMode")) return new JFieldRef(field.getSourceInfo(), methodCall.getInstance(), field, testClass); } Assert.fail("Did not find field named prodMode in test class " + testClass); return null; } /** * Called before any ast is examined. * * Allows us to insert code before anything else is examined. */ @Override public void onUnifyAstStart(TreeLogger logger, UnifyAstView ast, UnifyVisitor visitor, Queue<JMethod> todo) { // Demonstrates how to insert code into your entry point, (before it, actually) // to execute before anything else in the app. // Grab our test class JDeclaredType type; type = ast.searchForTypeBySource(MagicMethodGwtTest.class.getName()); // Find the method we want to call for (JMethod method : type.getMethods()) { if (method.getName().equals("callFromGenerator")) { // Find the entry point method for (JMethod entry : ast.getProgram().getEntryMethods()) { if (entry.getBody() instanceof JsniMethodBody) { // Skip the jsni $entry method, we _definitely_ don't want to add code here. } else { // Add to the java entry point method // (will be EntryMethodHolder.init(), a virtual method). SourceInfo child = entry.getBody().getSourceInfo().makeChild(); // Create an expression calling the method we want to execute JExpressionStatement statement = new JMethodCall(child, null, method).makeStatement(); // Attach expression to the entry point method. JMethodBody body = (JMethodBody)entry.getBody(); body.getBlock().addStmt(0, statement); } } } } } /** * Called once the todo queue of methods to examine is drained. * * If any UnifyAstListener adds new methods to examine, all listeners will be called again. * * Blindly adding elements to todo will result in looping behavior. */ @Override public boolean onUnifyAstPostProcess(TreeLogger logger, UnifyAstView ast, UnifyVisitor visitor, Queue<JMethod> todo) { return false; } /** * Called once every UnifyAstListener has stopped adding JMethods to the todo queue. */ @Override public void destroy(TreeLogger logger) { } }