blob: abffeeb649556409feb1562a6910c6aadac86d7e [file] [log] [blame]
/*
* Copyright 2011 Google Inc.
*
* 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.
*/
package com.google.gwt.dev.jjs.impl.codesplitter;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.CompilerContext;
import com.google.gwt.dev.PrecompileTaskOptions;
import com.google.gwt.dev.PrecompileTaskOptionsImpl;
import com.google.gwt.dev.cfg.BindingProperty;
import com.google.gwt.dev.cfg.ConditionNone;
import com.google.gwt.dev.cfg.ConfigurationProperty;
import com.google.gwt.dev.jjs.JsOutputOption;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JPrimitiveType;
import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.impl.FullCompileTestBase;
import com.google.gwt.dev.jjs.impl.JavaToJavaScriptMap;
import com.google.gwt.dev.js.ast.JsBlock;
import com.google.gwt.dev.js.ast.JsContext;
import com.google.gwt.dev.js.ast.JsExprStmt;
import com.google.gwt.dev.js.ast.JsFunction;
import com.google.gwt.dev.js.ast.JsName;
import com.google.gwt.dev.js.ast.JsNode;
import com.google.gwt.dev.js.ast.JsVisitor;
import com.google.gwt.dev.util.Pair;
import com.google.gwt.thirdparty.guava.common.collect.Sets;
import java.util.List;
import java.util.Set;
/**
* Unit test for {@link com.google.gwt.dev.jjs.impl.codesplitter.CodeSplitter}.
*/
public class CodeSplitterTest extends FullCompileTestBase {
/**
* A {@link MultipleDependencyGraphRecorder} that does nothing.
*/
private static final MultipleDependencyGraphRecorder NULL_RECORDER =
new MultipleDependencyGraphRecorder() {
@Override
public void close() {
}
@Override
public void endDependencyGraph() {
}
@Override
public void methodIsLiveBecause(JMethod liveMethod, List<JMethod> dependencyChain) {
}
@Override
public void open() {
}
@Override
public void startDependencyGraph(String name, String extnds) {
}
};
// These will be the functions that are shared between fragments. This unit test will
// be based for finding these function in the proper fragments.
private final String functionA = "public static void functionA() {}";
private final String functionB = "public static void functionB() {}";
private final String functionC = "public static void functionC() {}";
private final String functionD = "public static void functionD() {}";
private final String initialA = "public static void initialA() {}";
private final String initialB = "public static void initialB() {}";
private final String functionAllocateFooInt = "public static void functionAllocateFooInt() { "
+ "new Foo(42); }";
private final String functionAllocateFooString =
"public static void functionAllocateFooString() { new Foo(\"Hello\"); }";
public int leftOverMergeSize = 0;
public int expectedFragmentCount = 0;
private ConfigurationProperty initialSequenceProp =
new ConfigurationProperty(CodeSplitters.PROP_INITIAL_SEQUENCE, true);
private boolean closureOutputFormat = false;
private JavaToJavaScriptMap currentJjsMap;
@Override
public void setUp() throws Exception {
super.setUp();
// Compilation Configuration Properties.
BindingProperty stackMode = new BindingProperty("compiler.stackMode");
stackMode.addDefinedValue(new ConditionNone(), "STRIP");
setProperties(new BindingProperty[]{stackMode}, new String[]{"STRIP"},
new ConfigurationProperty[]{initialSequenceProp});
currentJjsMap = null;
}
public void testSimple() throws UnableToCompleteException {
StringBuilder code = new StringBuilder();
code.append("package test;\n");
code.append("import com.google.gwt.core.client.GWT;\n");
code.append("import com.google.gwt.core.client.RunAsyncCallback;\n");
code.append("public class EntryPoint {\n");
code.append("static {");
// code.append(" functionC();");
code.append("}");
code.append(functionA);
code.append(functionB);
code.append(functionC);
code.append(" public static void onModuleLoad() {\n");
code.append("functionC();");
// Fragment #1
code.append(createRunAsync("functionA();"));
// Fragment #1 (merged)
code.append(createRunAsync("functionA(); functionB();"));
// Fragment #2
code.append(createRunAsync("functionC();"));
code.append(" }\n");
code.append("}\n");
expectedFragmentCount = 4;
compileSnippetToJS(code.toString());
// init + 2 fragments + leftover.
assertFragmentCount(4);
assertInFragment("functionA", 1);
// Verify that functionA isn't duplicated else where.
assertNotInFragment("functionA", 0);
assertNotInFragment("functionA", 2);
assertNotInFragment("functionA", 3);
assertInFragment("functionB", 1);
// functionC must be in the initial fragment.
assertInFragment("functionC", 0);
}
public void testClosureConstructorPrototypeMovement() throws UnableToCompleteException {
closureOutputFormat = true;
StringBuilder code = new StringBuilder();
code.append("package test;\n");
code.append("import com.google.gwt.core.client.GWT;\n");
code.append("import com.google.gwt.core.client.RunAsyncCallback;\n");
code.append("public class EntryPoint {\n");
code.append("static class Foo {");
code.append(" int x; String y;\n");
code.append(" public Foo(int x) { this.x = x; }\n");
code.append(" public Foo(String y) { this.y = y; }\n");
code.append("};");
code.append(functionAllocateFooInt);
code.append(functionAllocateFooString);
code.append(" public static void onModuleLoad() {\n");
code.append("functionAllocateFooInt();");
// Fragment #1
code.append(createRunAsync("functionAllocateFooString();"));
code.append(" }\n");
code.append("}\n");
expectedFragmentCount = 3;
compileSnippetToJS(code.toString());
// init + 1 fragments + leftover.
assertFragmentCount(3);
// ------- Verify Fragment 0 -------
// Int related function and int ctor, plus prototype ctor in fragment 0
assertInFragment("functionAllocateFooInt", 0);
// assert synthetic prototype ctor is in fragment 0
assertClosureTypeCtorInFragment("EntryPoint$Foo", 0);
// and int ctor in fragment 0
assertClosureMethodInFragment("EntryPoint$Foo", 0, JPrimitiveType.INT);
// we also don't want string related ctor stuff in fragment 0
assertNotInFragment("functionAllocateFooString", 0);
JClassType stringType = jProgram.getTypeJavaLangString();
assertClosureFunctionNotInFragment("EntryPoint$Foo", 0, stringType);
assertPrototypeAssignmentStatementInFragment("EntryPoint$Foo", 0, JPrimitiveType.INT);
assertPrototypeAssignmentStatementNotInFragment("EntryPoint$Foo", 0, stringType);
// ------- Verify fragment 1 -------
// check if string ctor and related code is in fragment 1
assertInFragment("functionAllocateFooString", 1);
assertClosureMethodInFragment("EntryPoint$Foo", 1, stringType);
assertPrototypeAssignmentStatementInFragment("EntryPoint$Foo", 1, stringType);
assertPrototypeAssignmentStatementNotInFragment("EntryPoint$Foo", 1, JPrimitiveType.INT);
// Verify that the Class prototype ctor isn't duplicated here
assertClosureTypeCtorNotInFragment("EntryPoint$Foo", 1);
// but no int related code is here
assertNotInFragment("functionAllocateFooInt", 1);
assertClosureFunctionNotInFragment("EntryPoint$Foo", 1, JPrimitiveType.INT);
// Verify fragment 2 (leftovers)
assertNotInFragment("functionAllocateFooInt", 2);
assertNotInFragment("functionAllocateFooString", 2);
assertClosureFunctionNotInFragment("EntryPoint$Foo", 2, JPrimitiveType.INT);
assertClosureFunctionNotInFragment("EntryPoint$Foo", 2, stringType);
assertClosureTypeCtorNotInFragment("EntryPoint$Foo", 2);
assertPrototypeAssignmentStatementNotInFragment("EntryPoint$Foo", 2, JPrimitiveType.INT);
assertPrototypeAssignmentStatementNotInFragment("EntryPoint$Foo", 2, stringType);
}
public void testPredefinedAsyncGrouping() throws UnableToCompleteException {
StringBuilder code = new StringBuilder();
code.append("package test;\n");
code.append("import com.google.gwt.core.client.GWT;\n");
code.append("import com.google.gwt.core.client.RunAsyncCallback;\n");
code.append("public class EntryPoint {\n");
code.append(functionA);
code.append(functionB);
code.append(functionC);
code.append(functionD);
code.append(createNamedRunAsyncCallback("RunAsyncCallBack1", "functionA(); functionD();"));
code.append(createNamedRunAsyncCallback("RunAsyncCallBack2", "functionB(); functionD();"));
code.append(createNamedRunAsyncCallback("RunAsyncCallBack3", "functionC();"));
code.append(" public static void onModuleLoad() {\n");
// Fragment #1
code.append("createCallBack1();");
// Fragment #2
code.append("createCallBack2();");
code.append("createCallBack3();");
code.append(" }\n");
code.append(" private static void createCallBack1() {\n");
code.append(" GWT.runAsync( new RunAsyncCallBack1() );");
code.append(" }\n");
code.append(" private static void createCallBack2() {\n");
code.append(" GWT.runAsync(RunAsyncCallBack2.class, new RunAsyncCallBack2() );");
code.append(" }\n");
code.append(" private static void createCallBack3() {\n");
code.append(" GWT.runAsync(RunAsyncCallBack2.class, new RunAsyncCallBack3() );");
code.append(" }\n");
code.append("}\n");
// Use 1 to 1 merging.
expectedFragmentCount = -1;
compileSnippetToJS(code.toString());
// 1 initial + 2 fragments + leftover.
assertFragmentCount(4);
// TODO(rluble): using fragment numbers here is kind of tricky as the ordering is not
// guaranteed.
// functionB must be in the fragment #2. As first are all the user specified merges.
assertInFragment("functionA", 2);
// Verify that functionA isn't duplicated else where.
assertNotInFragment("functionA", 0);
assertNotInFragment("functionA", 1);
assertNotInFragment("functionA", 3);
// functionB must be in the fragment #1.
assertInFragment("functionB", 1);
// functionC must be in the fragment #1.
assertInFragment("functionC", 1);
// functionC must be in the leftover.
assertInFragment("functionD", 3);
}
public void testSimpleWithInitialSequence() throws UnableToCompleteException {
// Set up configuration property.
initialSequenceProp.addValue("@test.EntryPoint::createInitialCallBack1()");
initialSequenceProp.addValue("@test.EntryPoint::createInitialCallBack2()");
StringBuilder code = new StringBuilder();
code.append("package test;\n");
code.append("import com.google.gwt.core.client.GWT;\n");
code.append("import com.google.gwt.core.client.RunAsyncCallback;\n");
code.append("public class EntryPoint {\n");
code.append(functionA);
code.append(functionB);
code.append(functionC);
code.append(initialA);
code.append(initialB);
code.append(createNamedRunAsyncCallback("InitialRunAsyncCallBack1", "initialA();"));
code.append(createNamedRunAsyncCallback("InitialRunAsyncCallBack2", "initialB();"));
code.append(" public static void onModuleLoad() {\n");
code.append("functionC();");
// Fragment #3
code.append(createRunAsync("functionA();"));
// Fragment #3 (merged)
code.append(createRunAsync("functionA(); functionB();"));
// Fragment #4
code.append(createRunAsync("functionC();"));
// initial fragments #1, #2
code.append("createInitialCallBack1();");
code.append("createInitialCallBack2();");
code.append(" }\n");
code.append(" private static void createInitialCallBack1() {\n");
code.append(" GWT.runAsync( new InitialRunAsyncCallBack1() );");
code.append(" }\n");
code.append(" private static void createInitialCallBack2() {\n");
code.append(" GWT.runAsync( new InitialRunAsyncCallBack2() );");
code.append(" }\n");
code.append("}\n");
expectedFragmentCount = 6;
compileSnippetToJS(code.toString());
// 3 initial + 2 fragments + leftover.
assertFragmentCount(6);
assertInFragment("functionA", 3);
// Verify that functionA isn't duplicated else where.
assertNotInFragment("functionA", 0);
assertNotInFragment("functionA", 1);
assertNotInFragment("functionA", 2);
assertNotInFragment("functionA", 4);
assertNotInFragment("functionA", 5);
assertInFragment("functionB", 3);
// functionC must be in the initial fragment.
assertInFragment("functionC", 0);
// initialA must be in the initial fragment #1.
assertInFragment("initialA", 1);
// functionC must be in the initial fragment #2.
assertInFragment("initialB", 2);
}
public void testOnSuccessCallCast() throws UnableToCompleteException {
StringBuilder code = new StringBuilder();
code.append("package test;\n");
code.append("import com.google.gwt.core.client.GWT;\n");
code.append("import com.google.gwt.core.client.RunAsyncCallback;\n");
code.append("public class EntryPoint {\n");
code.append(" " + functionA);
code.append(" " + functionB);
code.append(" " + functionC);
code.append(" public static void onModuleLoad() {\n");
code.append(" functionC();");
code.append(" " + createRunAsync("(RunAsyncCallback)", "functionA();"));
code.append(" " + createRunAsync("(RunAsyncCallback)", "functionB();"));
code.append(" }\n");
code.append("}\n");
expectedFragmentCount = 4;
compileSnippetToJS(code.toString());
// init + 2 fragments + leftover.
assertFragmentCount(4);
assertInFragment("functionA", 1);
assertInFragment("functionB", 2);
// Verify that functionA and B aren't in the leftover.
assertNotInFragment("functionA", 3);
assertNotInFragment("functionB", 3);
}
public void testMergeLeftOvers() throws UnableToCompleteException {
StringBuilder code = new StringBuilder();
code.append("package test;\n");
code.append("import com.google.gwt.core.client.GWT;\n");
code.append("import com.google.gwt.core.client.RunAsyncCallback;\n");
code.append("public class EntryPoint {\n");
code.append(functionA);
code.append(functionB);
code.append(functionC);
code.append(" public static void onModuleLoad() {\n");
// Fragment #1
code.append(createRunAsync("functionA();"));
// Fragment #2
code.append(createRunAsync("functionB();"));
// Fragment #3
code.append(createRunAsync("functionC();"));
code.append(" }\n");
code.append("}\n");
expectedFragmentCount = 2;
leftOverMergeSize = 100 * 1024 /* 100k minumum */;
this.compileSnippetToJS(code.toString());
// init + leftover.
assertFragmentCount(2);
assertInFragment("functionA", 1);
assertInFragment("functionB", 1);
assertInFragment("functionC", 1);
}
/**
* Test that the conversion from -XfragmentCount expectCount into number of exclusive fragments
* is correct.
*/
public void testExpectedFragmentCountFromFragmentMerge() {
// Exclusive fragments are totalFragments - (1 + initials) - leftovers.
assertEquals(40, CodeSplitters.getNumberOfExclusiveFragmentFromExpectedFragmentCount(2, 44));
// This is a non negative number always
assertEquals(0, CodeSplitters.getNumberOfExclusiveFragmentFromExpectedFragmentCount(2, 1));
}
public void testDontMergeLeftOvers() throws UnableToCompleteException {
StringBuilder code = new StringBuilder();
code.append("package test;\n");
code.append("import com.google.gwt.core.client.GWT;\n");
code.append("import com.google.gwt.core.client.RunAsyncCallback;\n");
code.append("public class EntryPoint {\n");
code.append(functionA);
code.append(functionB);
code.append(functionC);
code.append(" public static void onModuleLoad() {\n");
// Fragment #1
code.append(createRunAsync("functionA();"));
// Fragment #2
code.append(createRunAsync("functionB();"));
// Fragment #3
code.append(createRunAsync("functionC();"));
code.append(" }\n");
code.append("}\n");
// we want don't want them to be merged
leftOverMergeSize = 10;
expectedFragmentCount = 5;
this.compileSnippetToJS(code.toString());
// init + 3 exlclusive fragments + leftover.
assertFragmentCount(5);
assertNotInFragment("functionA", 4);
assertNotInFragment("functionB", 4);
assertNotInFragment("functionC", 4);
}
public void testNoMergeMoreThanTwo() throws UnableToCompleteException {
StringBuilder code = new StringBuilder();
code.append("package test;\n");
code.append("import com.google.gwt.core.client.GWT;\n");
code.append("import com.google.gwt.core.client.RunAsyncCallback;\n");
code.append("public class EntryPoint {\n");
code.append(functionA);
code.append(functionB);
code.append(functionC);
code.append(" public static void onModuleLoad() {\n");
// Fragment #1
code.append(createRunAsync("functionA();"));
// Fragment #2
code.append(createRunAsync("functionA();"));
// Fragment #3
code.append(createRunAsync("functionA();"));
code.append(" }\n");
code.append("}\n");
expectedFragmentCount = 2;
compileSnippetToJS(code.toString());
// There is no common code shared between any pair.
// init + 3 fragments + leftover.
assertFragmentCount(5);
}
public void testDoubleMerge() throws UnableToCompleteException {
StringBuilder code = new StringBuilder();
code.append("package test;\n");
code.append("import com.google.gwt.core.client.GWT;\n");
code.append("import com.google.gwt.core.client.RunAsyncCallback;\n");
code.append("public class EntryPoint {\n");
code.append(functionA);
code.append(functionB);
code.append(functionC);
code.append(" public static void onModuleLoad() {\n");
// Fragment #1
code.append(createRunAsync("functionA();"));
// Fragment #1
code.append(createRunAsync("functionA(); functionC();"));
// Fragment #2
code.append(createRunAsync("functionB(); functionC();"));
// Fragment #2
code.append(createRunAsync("functionB(); functionC();"));
code.append(" }\n");
code.append("}\n");
expectedFragmentCount = 4;
compileSnippetToJS(code.toString());
// init + 2 fragments + leftover.
assertFragmentCount(4);
assertInFragment("functionA", 1);
assertInFragment("functionB", 2);
assertInFragment("functionC", 3);
}
private void assertFragmentCount(int num) {
assertEquals(num, jsProgram.getFragmentCount());
}
private void assertInFragment(String functionName, int expectedFragmentNumber) {
Set<Integer> fragments = Sets.newHashSet();
for (int fragmentNumber = 0; fragmentNumber < jsProgram.getFragmentCount(); fragmentNumber++) {
JsBlock fragment = jsProgram.getFragmentBlock(fragmentNumber);
if (findFunctionIn(functionName, fragment)) {
fragments.add(fragmentNumber);
}
}
assertTrue("function " + functionName + " should be in fragments " + expectedFragmentNumber +
" but is in " + fragments, fragments.equals(Sets.newHashSet(expectedFragmentNumber)));
}
private void assertClosureTypeCtorInFragment(String functionName, int expectedFragmentNumber) {
Set<Integer> fragments = Sets.newHashSet();
for (int fragmentNumber = 0; fragmentNumber < jsProgram.getFragmentCount(); fragmentNumber++) {
JsBlock fragment = jsProgram.getFragmentBlock(fragmentNumber);
if (findClosureTypeFunctionIn(functionName, fragment)) {
fragments.add(fragmentNumber);
}
}
assertTrue("function " + functionName + " should be in fragments " + expectedFragmentNumber +
" but is in " + fragments, fragments.equals(Sets.newHashSet(expectedFragmentNumber)));
}
private void assertClosureMethodInFragment(String functionName, int expectedFragmentNumber,
JType... args) {
Set<Integer> fragments = Sets.newHashSet();
for (int fragmentNumber = 0; fragmentNumber < jsProgram.getFragmentCount(); fragmentNumber++) {
JsBlock fragment = jsProgram.getFragmentBlock(fragmentNumber);
if (findClosureFunctionIn(functionName, fragment, args)) {
fragments.add(fragmentNumber);
}
}
assertTrue("function " + functionName + " should be in fragments " + expectedFragmentNumber +
" but is in " + fragments, fragments.equals(Sets.newHashSet(expectedFragmentNumber)));
}
private void assertPrototypeAssignmentStatementInFragment(String functionName,
int expectedFragmentNumber, JType... args) {
Set<Integer> fragments = Sets.newHashSet();
for (int fragmentNumber = 0; fragmentNumber < jsProgram.getFragmentCount(); fragmentNumber++) {
JsBlock fragment = jsProgram.getFragmentBlock(fragmentNumber);
if (findPrototypeChainStatementIn(functionName, fragment, args)) {
fragments.add(fragmentNumber);
}
}
assertTrue("Prototype chain assignment for " + functionName + " should be in "
+ "fragments " + expectedFragmentNumber + " but is in " + fragments,
fragments.equals(Sets.newHashSet(expectedFragmentNumber)));
}
private void assertNotInFragment(String functionName, int fragmentNum) {
JsBlock fragment = jsProgram.getFragmentBlock(fragmentNum);
assertFalse("function " + functionName + " should not be in fragment " + fragmentNum,
findFunctionIn(functionName, fragment));
}
private void assertClosureTypeCtorNotInFragment(String functionName, int fragmentNum) {
JsBlock fragment = jsProgram.getFragmentBlock(fragmentNum);
assertFalse("function " + functionName + " should not be in fragment " + fragmentNum,
findClosureTypeFunctionIn(functionName, fragment));
}
private void assertClosureFunctionNotInFragment(String functionName, int fragmentNum, JType...
args) {
JsBlock fragment = jsProgram.getFragmentBlock(fragmentNum);
assertFalse("function " + functionName + " should not be in fragment " + fragmentNum,
findClosureFunctionIn(functionName, fragment, args));
}
private void assertPrototypeAssignmentStatementNotInFragment(String functionName, int
fragmentNum, JType... args) {
JsBlock fragment = jsProgram.getFragmentBlock(fragmentNum);
assertFalse("function " + functionName + " should not be in fragment " + fragmentNum,
findPrototypeChainStatementIn(functionName, fragment, args));
}
/**
* @return true if the function exists in that fragment.
*/
private static boolean findFunctionIn(final String functionName, JsBlock fragment) {
final boolean[] found = {false};
JsVisitor visitor = new JsVisitor() {
@Override
public boolean visit(JsFunction x, JsContext ctx) {
JsName jsName = x.getName();
if (jsName != null && jsName.getShortIdent().equals(functionName)) {
found[0] = true;
}
return false;
}
};
visitor.accept(fragment);
return found[0];
}
/**
* @return true if the function exists in that fragment and it mapes to a classType
*/
private boolean findClosureTypeFunctionIn(final String functionName, JsBlock fragment) {
final boolean[] found = {false};
JsVisitor visitor = new JsVisitor() {
@Override
public boolean visit(JsFunction x, JsContext ctx) {
JsName jsName = x.getName();
if (jsName != null && jsName.getShortIdent().equals(functionName)
&& currentJjsMap.nameToType(jsName) != null) {
found[0] = true;
}
return false;
}
};
visitor.accept(fragment);
return found[0];
}
/**
* @return true if the function exists in that fragment and it maps to a function
* with the expected args.
*/
private boolean findClosureFunctionIn(final String functionName, JsBlock fragment,
final JType... args) {
final boolean[] found = {false};
JsVisitor visitor = new JsVisitor() {
@Override
public boolean visit(JsFunction x, JsContext ctx) {
JsName jsName = x.getName();
if (jsName != null && jsName.getShortIdent().equals(functionName)) {
JMethod meth = currentJjsMap.nameToMethod(jsName);
if (meth != null) {
found[0] = checkArguments(meth, args);
}
}
return false;
}
};
visitor.accept(fragment);
return found[0];
}
/**
* @return true if a statement of the form FunctionName.prototype = ClassFunction.prototype
*/
private boolean findPrototypeChainStatementIn(final String functionName, JsBlock fragment,
final JType... args) {
class PrototypeChainFinderVisitor extends JsVisitor {
boolean found = false;
@Override
public boolean visit(JsExprStmt x, JsContext ctx) {
JMethod method = currentJjsMap.methodForStatement(x);
JsName jsName = currentJjsMap.nameForMethod(method);
if (method != null && jsName != null && jsName.getShortIdent().equals(functionName)) {
found = checkArguments(method, args);
}
return false;
}
};
PrototypeChainFinderVisitor visitor = new PrototypeChainFinderVisitor();
visitor.accept(fragment);
return visitor.found;
}
private boolean checkArguments(JMethod method, JType[] args) {
for (int i = 0; i < args.length; i++) {
if (method.getParams().get(i).getType().getUnderlyingType() != args[i]) {
return false;
}
}
return true;
}
@Override
protected void optimizeJava() {
}
@Override
protected CompilerContext provideCompilerContext() {
PrecompileTaskOptions options = new PrecompileTaskOptionsImpl();
options.setOutput(JsOutputOption.PRETTY);
options.setRunAsyncEnabled(true);
if (closureOutputFormat) {
options.setClosureCompilerFormatEnabled(true);
}
return new CompilerContext.Builder().options(options).build();
}
@Override
protected Pair<JavaToJavaScriptMap, Set<JsNode>> compileSnippetToJS(final String code)
throws UnableToCompleteException {
currentJjsMap = super.compileSnippetToJS(code).getLeft();
CodeSplitter.exec(logger, jProgram, jsProgram, currentJjsMap, expectedFragmentCount,
leftOverMergeSize,
NULL_RECORDER);
return null;
}
private static String createRunAsync(String cast, String body) {
StringBuilder code = new StringBuilder();
code.append("GWT.runAsync(" + cast + "new " + "RunAsyncCallback() {\n");
code.append(" public void onFailure(Throwable reason) {}\n");
code.append(" public void onSuccess() {\n");
code.append(" " + body);
code.append(" }\n");
code.append("});\n");
return code.toString();
}
private static String createNamedRunAsyncCallback(String className, String body) {
StringBuilder code = new StringBuilder();
code.append("private static class " + className + " implements RunAsyncCallback {\n");
code.append(" public void onFailure(Throwable reason) {}\n");
code.append(" public void onSuccess() {\n");
code.append(" " + body);
code.append(" }\n");
code.append("}\n");
return code.toString();
}
private static String createRunAsync(String body) {
return createRunAsync("", body);
}
}