Fix reference error in SDM related to @JsFunction interfaces.
@JsFunction methods were not considered exported by ControlFlowRecorder.
Change-Id: I8d2dd0be25f60255c8cd5e69bfae4407d5236c74
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
index 823554d..dd51b0e 100755
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
@@ -17,6 +17,7 @@
import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.impl.GwtAstBuilder;
+import com.google.gwt.dev.jjs.impl.JjsUtils;
import com.google.gwt.dev.util.StringInterner;
import com.google.gwt.dev.util.collect.Lists;
import com.google.gwt.thirdparty.guava.common.base.Preconditions;
@@ -332,7 +333,7 @@
@Override
public String getJavahSignatureName() {
- return "L" + name.replaceAll("_", "_1").replace('.', '_') + "_2";
+ return JjsUtils.javahSignatureFromName(name);
}
@Override
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowRecorder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowRecorder.java
index 7e45789..23110e6 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowRecorder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowRecorder.java
@@ -137,11 +137,12 @@
overriddenMethodName);
}
- if (x.isExported() || x.isOrOverridesJsTypeMethod()) {
+ if (x.isExported() || x.isOrOverridesJsTypeMethod() || x.isOrOverridesJsFunctionMethod()) {
+ stringAnalyzableTypeEnvironment.recordExportedMethodInType(currentMethodName, typeName);
+
if (x.isStatic() || x.isConstructor()) {
stringAnalyzableTypeEnvironment.recordExportedStaticReferenceInType(typeName);
}
- stringAnalyzableTypeEnvironment.recordExportedMethodInType(currentMethodName, typeName);
}
if (x.isConstructor()) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index 0c8b94f..24045c5 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -3522,14 +3522,11 @@
}
String mangleName(JField x) {
- String s = JjsUtils.mangledNameString(x.getEnclosingType()) + '_' + JjsUtils.mangledNameString(
- x);
- return s;
+ return JjsUtils.mangleMemberName(x.getEnclosingType().getName(), x.getName());
}
String mangleNameForGlobal(JMethod x) {
- String s =
- JjsUtils.mangledNameString(x.getEnclosingType()) + '_' + JjsUtils.mangledNameString(x) + "__";
+ String s = JjsUtils.mangleMemberName(x.getEnclosingType().getName(), x.getName()) + "__";
for (int i = 0; i < x.getOriginalParamTypes().size(); ++i) {
JType type = x.getOriginalParamTypes().get(i);
s += type.getJavahSignatureName();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java
index 8220385..9e6c555 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java
@@ -465,7 +465,7 @@
// Create a field in the class literal holder to hold the object.
field =
- new JField(info, getClassLiteralName(type), typeClassLiteralHolder, program
+ new JField(info, getClassLiteralFieldName(type), typeClassLiteralHolder, program
.getTypeJavaLangClass(), true, Disposition.FINAL);
typeClassLiteralHolder.addField(field);
info.addCorrelation(info.getCorrelator().by(Literal.CLASS));
@@ -480,7 +480,7 @@
return field;
}
- private static String getClassLiteralName(JType type) {
- return type.getJavahSignatureName() + "_classLit";
+ private static String getClassLiteralFieldName(JType type) {
+ return JjsUtils.classLiteralFieldNameFromJavahTypeSignatureName(type.getJavahSignatureName());
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java
index 4b07e67..e651c69 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java
@@ -85,6 +85,13 @@
}
/**
+ * Returns the class literal field name.
+ */
+ public static String classLiteralFieldNameFromJavahTypeSignatureName(String javahSignatureName) {
+ return javahSignatureName + "_classLit";
+ }
+
+ /**
* Java8 Method References such as String::equalsIgnoreCase should produce inner class names
* that are a function of the samInterface (e.g. Runnable), the method being referred to,
* and the qualifying disposition (this::foo vs Class::foo if foo is an instance method)
@@ -300,6 +307,18 @@
}
/**
+ * Mangles a qualified name into a Javah signature.
+ */
+ public static String javahSignatureFromName(String name) {
+ return "L" + mangledNameString(name) + "_2";
+ }
+
+ public static String mangleMemberName(String enclosingTypeName, String fieldName) {
+ return mangledNameString(
+ enclosingTypeName + '_' + mangledNameString(fieldName));
+ }
+
+ /**
* Returns an valid identifier for a named Java entity.
*/
public static String mangledNameString(HasName hasName) {
diff --git a/dev/core/test/com/google/gwt/dev/CompilerTest.java b/dev/core/test/com/google/gwt/dev/CompilerTest.java
index e90eb55..072d027 100644
--- a/dev/core/test/com/google/gwt/dev/CompilerTest.java
+++ b/dev/core/test/com/google/gwt/dev/CompilerTest.java
@@ -27,6 +27,7 @@
import com.google.gwt.dev.javac.testing.impl.MockJavaResource;
import com.google.gwt.dev.javac.testing.impl.MockResource;
import com.google.gwt.dev.jjs.JsOutputOption;
+import com.google.gwt.dev.jjs.impl.JjsUtils;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.OptionJsInteropMode;
import com.google.gwt.dev.util.arg.SourceLevel;
@@ -950,6 +951,70 @@
new MinimalRebuildCache(), emptySet, JsOutputOption.OBFUSCATED);
}
+ /**
+ * Test that some lightly referenced interface through a @JsFunction is included in the output.
+ */
+ public void testReferenceThroughJsFunction() throws Exception {
+ MockJavaResource someJsFunction =
+ JavaResourceBase.createMockJavaResource(
+ "com.foo.SomeJsFunction",
+ "package com.foo;",
+ "import com.google.gwt.core.client.js.JsFunction;",
+ "@JsFunction",
+ "public interface SomeJsFunction {",
+ " void m();",
+ "}");
+
+ MockJavaResource jsFunctionInterfaceImplementation =
+ JavaResourceBase.createMockJavaResource(
+ "com.foo.Impl",
+ "package com.foo;",
+ "public class Impl implements SomeJsFunction {",
+ " public void m() { SomeInterface.class.getName(); } ",
+ "}");
+
+ MockJavaResource someInterface =
+ JavaResourceBase.createMockJavaResource(
+ "com.foo.SomeInterface",
+ "package com.foo;",
+ "public interface SomeInterface {",
+ "}");
+
+ MockJavaResource testEntryPoint =
+ JavaResourceBase.createMockJavaResource(
+ "com.foo.TestEntryPoint",
+ "package com.foo;",
+ "import com.google.gwt.core.client.EntryPoint;",
+ "public class TestEntryPoint implements EntryPoint {",
+ " private static native void f(SomeJsFunction f) /*-{}-*/;",
+ " public void onModuleLoad() {",
+ // Create Impl and pass it to JS but do not explicitly call m
+ " f(new Impl());",
+ " }",
+ "}");
+
+ MockResource moduleResource =
+ JavaResourceBase.createMockResource(
+ "com/foo/TestEntryPoint.gwt.xml",
+ "<module>",
+ " <source path=''/>",
+ " <entry-point class='com.foo.TestEntryPoint'/>",
+ "</module>");
+
+ CompilerOptions compilerOptions = new CompilerOptionsImpl();
+ compilerOptions.setJsInteropMode(OptionJsInteropMode.Mode.JS);
+ String js = compileToJs(compilerOptions, Files.createTempDir(), testEntryPoint.getTypeName(),
+ Lists.newArrayList(moduleResource, testEntryPoint, someJsFunction,
+ jsFunctionInterfaceImplementation, someInterface),
+ new MinimalRebuildCache(), emptySet, JsOutputOption.DETAILED);
+ // Make sure the referenced class literals ends up beign included in the resulting JS.
+ String classliteralHolderVarName =
+ JjsUtils.mangleMemberName("com.google.gwt.lang.ClassLiteralHolder",
+ JjsUtils.classLiteralFieldNameFromJavahTypeSignatureName(
+ JjsUtils.javahSignatureFromName(someInterface.getTypeName())));
+ assertTrue(js.contains("var " + classliteralHolderVarName + " = "));
+ }
+
public void testJsInteropNameCollision() throws Exception {
MinimalRebuildCache minimalRebuildCache = new MinimalRebuildCache();
File applicationDir = Files.createTempDir();
@@ -1452,7 +1517,6 @@
public void checkIncrementalRecompile_classLiteralNewReference(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
- // Tests that when a superclass has a "inherits" a default method,
MockJavaResource interfaceA =
JavaResourceBase.createMockJavaResource(
"com.foo.A",
@@ -1504,7 +1568,6 @@
public void checkIncrementalRecompile_primitiveClassLiteralReference(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
- // Tests that when a superclass has a "inherits" a default method,
MockJavaResource classA =
JavaResourceBase.createMockJavaResource(
"com.foo.A",