Skip to content

Commit

Permalink
Allow arbitrary clinit code in native JsTypes and JsFunction interfaces.
Browse files Browse the repository at this point in the history
Since clinit on these types are effectively overlays there is
no need to have any restrictions on them.

Change-Id: If0aba24ce6b1a4732461c755f0731ee687cfb01d
  • Loading branch information
rluble committed Jun 23, 2016
1 parent 652cb09 commit 807de3a
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 55 deletions.
Expand Up @@ -25,7 +25,6 @@
import com.google.gwt.dev.jjs.ast.HasType;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JConstructor;
import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JDeclaredType.NestedClassDisposition;
import com.google.gwt.dev.jjs.ast.JExpression;
Expand Down Expand Up @@ -135,46 +134,6 @@ private static boolean isInitEmpty(JDeclaredType type) {
|| ((JMethodBody) type.getInitMethod().getBody()).getStatements().isEmpty();
}

/**
* Returns true if the clinit for a type is locally empty (except for the call to its super
* clinit).
*/
private static boolean isClinitEmpty(JDeclaredType type, final boolean skipDeclaration) {
JMethod clinit = type.getClinitMethod();
List<JStatement> statements = FluentIterable
.from(((JMethodBody) clinit.getBody()).getStatements())
.filter(new Predicate<JStatement>() {
@Override
public boolean apply(JStatement statement) {
if (!(statement instanceof JDeclarationStatement)) {
return true;
}
if (skipDeclaration) {
return false;
}
JDeclarationStatement declarationStatement = (JDeclarationStatement) statement;
JField field = (JField) declarationStatement.getVariableRef().getTarget();
return !field.isCompileTimeConstant();
}
}).toList();
if (statements.isEmpty()) {
return true;
}
return statements.size() == 1 && isClinitCall(statements.get(0), type.getSuperClass());
}

private static boolean isClinitCall(JStatement statement, JClassType superClass) {
if (superClass == null || !(statement instanceof JExpressionStatement)) {
return false;
}

JExpression expression = ((JExpressionStatement) statement).getExpr();
if (!(expression instanceof JMethodCall)) {
return false;
}
return ((JMethodCall) expression).getTarget() == superClass.getClinitMethod();
}

private void checkJsConstructors(JDeclaredType x) {
List<JMethod> jsConstructors = FluentIterable
.from(x.getMethods())
Expand Down Expand Up @@ -671,10 +630,6 @@ private boolean checkNativeJsType(JDeclaredType type) {
logError("Native JsType '%s' cannot have initializer.", type);
}

if (!isClinitEmpty(type, true)) {
logError("Native JsType '%s' cannot have static initializer.", type);
}

return true;
}

Expand All @@ -699,10 +654,6 @@ private void checkMemberOfJsFunction(JMember member) {
}

private void checkJsFunction(JDeclaredType type) {
if (!isClinitEmpty(type, false)) {
logError("JsFunction '%s' cannot have static initializer.", type);
}

if (type.getImplements().size() > 0) {
logError("JsFunction '%s' cannot extend other interfaces.", type);
}
Expand Down
Expand Up @@ -1148,6 +1148,8 @@ public void testJsFunctionSucceeds() throws Exception {
"public interface Function {",
" int getFoo();",
" @JsOverlay",
" String s = someString();",
" @JsOverlay",
" default void m() {}",
" @JsOverlay",
" static void n() {}",
Expand Down Expand Up @@ -1199,8 +1201,6 @@ public void testJsFunctionFails() throws Exception {
" default void m() {}",
" int f = 0;",
" static void n() {}",
" @JsOverlay",
" String s = null;",
"}",
"static class NonFinalJsFunction implements Function {",
" public int getFoo() { return 0; }",
Expand Down Expand Up @@ -1258,7 +1258,7 @@ public void testJsFunctionFails() throws Exception {
+ "implement more than one interface.");
}

public void testNativeJsTypeStaticInitializerFails() {
public void testNativeJsTypeStaticInitializerSucceeds() throws Exception {
addSnippetImport("jsinterop.annotations.JsType");
addSnippetClassDecl(
"@JsType(isNative=true) public static class Buggy {",
Expand All @@ -1268,9 +1268,7 @@ public void testNativeJsTypeStaticInitializerFails() {
" static { Object.class.getName(); }",
"}");

assertBuggyFails(
"Line 4: Native JsType 'EntryPoint.Buggy' cannot have static initializer.",
"Line 7: Native JsType 'EntryPoint.Buggy2' cannot have static initializer.");
assertBuggySucceeds();
}

public void testNativeJsTypeInstanceInitializerFails() {
Expand Down
8 changes: 8 additions & 0 deletions user/test/com/google/gwt/core/interop/NativeJsTypeTest.java
Expand Up @@ -208,14 +208,22 @@ static class NativeJsTypeWithStaticInitializationAndInstanceOverlayMethod {
public final Object getObject() {
return object;
}

static {
clinitCalled++;
}
}

private static int clinitCalled = 0;

public void testNativeJsTypeWithStaticIntializer() {
assertEquals(new Integer(3), NativeJsTypeWithStaticInitializationAndFieldAccess.object);
assertEquals(0, clinitCalled);
assertEquals(
new Integer(4), NativeJsTypeWithStaticInitializationAndStaticOverlayMethod.getObject());
assertEquals(new Integer(5),
new NativeJsTypeWithStaticInitializationAndInstanceOverlayMethod().getObject());
assertEquals(1, clinitCalled);
}

@JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Function")
Expand Down

0 comments on commit 807de3a

Please sign in to comment.