Allow arbitrary clinit code in native JsTypes and JsFunction interfaces.

Since clinit on these types are effectively overlays there is
no need to have any restrictions on them.

Change-Id: If0aba24ce6b1a4732461c755f0731ee687cfb01d
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java
index 2e070c2..7c1dbb8 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java
@@ -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;
@@ -135,46 +134,6 @@
         || ((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())
@@ -671,10 +630,6 @@
       logError("Native JsType '%s' cannot have initializer.", type);
     }
 
-    if (!isClinitEmpty(type, true)) {
-      logError("Native JsType '%s' cannot have static initializer.", type);
-    }
-
     return true;
   }
 
@@ -699,10 +654,6 @@
   }
 
   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);
     }
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java
index a110ab3..10f0325 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java
@@ -1148,6 +1148,8 @@
         "public interface Function {",
         "  int getFoo();",
         "  @JsOverlay",
+        "  String s = someString();",
+        "  @JsOverlay",
         "  default void m() {}",
         "  @JsOverlay",
         "  static void n() {}",
@@ -1199,8 +1201,6 @@
         "  default void m() {}",
         "  int f = 0;",
         "  static void n() {}",
-        "  @JsOverlay",
-        "  String s = null;",
         "}",
         "static class NonFinalJsFunction implements Function {",
         "  public int getFoo() { return 0; }",
@@ -1258,7 +1258,7 @@
             + "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 {",
@@ -1268,9 +1268,7 @@
         "  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() {
diff --git a/user/test/com/google/gwt/core/interop/NativeJsTypeTest.java b/user/test/com/google/gwt/core/interop/NativeJsTypeTest.java
index 367d65b..2dc6762 100644
--- a/user/test/com/google/gwt/core/interop/NativeJsTypeTest.java
+++ b/user/test/com/google/gwt/core/interop/NativeJsTypeTest.java
@@ -208,14 +208,22 @@
     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")