Skip to content

Commit

Permalink
Make sure that enums exposed with JsInterop are not ordinalized.
Browse files Browse the repository at this point in the history
Change-Id: I831168f18d4f6450e5cf424e872fb9fc767b62c0
  • Loading branch information
rluble committed Nov 10, 2017
1 parent d112e04 commit 2688d44
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 6 deletions.
11 changes: 6 additions & 5 deletions dev/core/src/com/google/gwt/dev/jjs/impl/EnumOrdinalizer.java
Expand Up @@ -326,16 +326,17 @@ public void endVisit(JClassLiteral x, Context ctx) {
@Override @Override
public void endVisit(JClassType x, Context ctx) { public void endVisit(JClassType x, Context ctx) {
// keep track of all enum classes visited // keep track of all enum classes visited
JEnumType maybeEnum = x.isEnumOrSubclass(); JEnumType enumClass = x.isEnumOrSubclass();
if (maybeEnum == null) { if (enumClass == null) {
return; return;
} }


enumsVisited.add(maybeEnum); enumsVisited.add(enumClass);


// don't need to re-ordinalize a previously ordinalized enum // don't need to re-ordinalize a previously ordinalized enum
if (maybeEnum.isOrdinalized()) { if (enumClass.isOrdinalized()
addToBlackList(maybeEnum, x.getSourceInfo()); || enumClass.canBeReferencedExternally()) {
addToBlackList(enumClass, x.getSourceInfo());
} }
} }


Expand Down
3 changes: 2 additions & 1 deletion dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
Expand Up @@ -192,7 +192,8 @@ public CharSequence getContent() {
"package java.lang;", "package java.lang;",
"import java.io.Serializable;", "import java.io.Serializable;",
"import com.google.gwt.core.client.JavaScriptObject;", "import com.google.gwt.core.client.JavaScriptObject;",
"public abstract class Enum<E extends Enum<E>> implements Serializable {", "import jsinterop.annotations.JsType;",
"@JsType public abstract class Enum<E extends Enum<E>> implements Serializable {",
" public static native <T extends Enum<T>> T valueOf(Class<T> enumType,", " public static native <T extends Enum<T>> T valueOf(Class<T> enumType,",
" String name) /*-{ return enumType + name; }-*/;", " String name) /*-{ return enumType + name; }-*/;",
" public static native <T extends Enum<T>> T valueOf(JavaScriptObject enumType,", " public static native <T extends Enum<T>> T valueOf(JavaScriptObject enumType,",
Expand Down
26 changes: 26 additions & 0 deletions dev/core/test/com/google/gwt/dev/jjs/impl/EnumOrdinalizerTest.java
Expand Up @@ -538,6 +538,32 @@ public void testNotOrdinalizableStaticMethodCallValues()
assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker);
} }


public void testNotOrdinalizableJsTypeEnum()
throws UnableToCompleteException {
setupJsTypeEnums();
addSnippetClassDecl(
"public static JsFruit instanceFruit;",
"public static JsCustom instanceCustom;");
Result result = optimize("void",
"instanceFruit = JsFruit.JSAPPLE;",
"instanceCustom = JsCustom.VALUE1;");

EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker();
assertTrue(tracker.isVisited("test.EntryPoint$JsFruit"));
assertFalse(tracker.isOrdinalized("test.EntryPoint$JsFruit"));

assertTrue(tracker.isVisited("test.EntryPoint$JsCustom"));
assertFalse(tracker.isOrdinalized("test.EntryPoint$JsCustom"));

assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker);
}

private void setupJsTypeEnums() {
addSnippetImport("jsinterop.annotations.JsType");
addSnippetClassDecl("@JsType public enum JsFruit {JSAPPLE, JSORANGE}");
addSnippetClassDecl("@JsType public enum JsCustom {VALUE0, VALUE1 {} }");
}

public void testNotOrdinalizableJsniFieldRef() public void testNotOrdinalizableJsniFieldRef()
throws UnableToCompleteException { throws UnableToCompleteException {
setupFruitEnum(); setupFruitEnum();
Expand Down
26 changes: 26 additions & 0 deletions user/test/com/google/gwt/core/interop/JsTypeTest.java
Expand Up @@ -79,6 +79,32 @@ public void testConcreteJsTypeSubclassAccess() {
assertEquals(10, concreteJsTypeSubclass.publicSubclassMethod()); assertEquals(10, concreteJsTypeSubclass.publicSubclassMethod());
} }


@JsType
enum JsTypeEnum {
JSVALUE0,
JSVALUE1;
}

public void testJsTypeEnum() {
JsTypeEnum value = JsTypeEnum.JSVALUE1;

assertEquals(value.ordinal(), ((TestAccessor) this).callJsTypeEmumOrdinalMethod(value));
}

// Obscure the call with an alias so that the call is not detected by EnumOrdinalizer.
@JsType(isNative = true)
private interface TestAccessor {
@JsMethod
// Receive the JsType enum as its own type so that it is not seen as an upcast by
// EnumOrdinalizer, but actually dispach to a method that takes Object.
int callJsTypeEmumOrdinalMethod(JsTypeEnum value);
}

@JsMethod
private int callJsTypeEmumOrdinalMethod(Object value) {
return callIntFunction(value, "ordinal");
}

public void testConcreteJsTypeNoTypeTightenField() { public void testConcreteJsTypeNoTypeTightenField() {
// If we type-tighten, java side will see no calls and think that field could only AImpl1. // If we type-tighten, java side will see no calls and think that field could only AImpl1.
ConcreteJsType concreteJsType = new ConcreteJsType(); ConcreteJsType concreteJsType = new ConcreteJsType();
Expand Down

0 comments on commit 2688d44

Please sign in to comment.