Implemented GWT.isClient(), which returns true when the code is running client-side.  Also added a unit test for GWT.java

Review by: bruce (TBR)


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2285 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
index f00d929..c6f6233 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -17,7 +17,6 @@
 
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.dev.jdt.FindDeferredBindingSitesVisitor;
 import com.google.gwt.dev.jdt.RebindOracle;
 import com.google.gwt.dev.jjs.InternalCompilerException;
 import com.google.gwt.dev.jjs.SourceInfo;
@@ -57,6 +56,7 @@
           "java.lang.Object", "java.lang.String", "java.lang.Class",
           "java.lang.CharSequence", "java.lang.Comparable", "java.lang.Enum",
           "java.lang.Iterable", "java.util.Iterator",
+          "com.google.gwt.core.client.GWT",
           "com.google.gwt.core.client.JavaScriptObject"}));
 
   private static final int IS_ARRAY = 2;
@@ -223,8 +223,6 @@
 
   private Map<JReferenceType, Integer> queryIds;
 
-  private JMethod rebindCreateMethod;
-
   private final RebindOracle rebindOracle;
 
   private final Map<JMethod, JMethod> staticToInstanceMap = new IdentityHashMap<JMethod, JMethod>();
@@ -415,11 +413,7 @@
       x.setBody(new JMethodBody(this, info));
     }
 
-    if (sname.equals(FindDeferredBindingSitesVisitor.REBIND_MAGIC_METHOD)
-        && enclosingType.getName().equals(
-            FindDeferredBindingSitesVisitor.REBIND_MAGIC_CLASS)) {
-      rebindCreateMethod = x;
-    } else if (!isPrivate && indexedTypes.containsValue(enclosingType)) {
+    if (!isPrivate && indexedTypes.containsValue(enclosingType)) {
       indexedMethods.put(enclosingType.getShortName() + '.' + sname, x);
     }
 
@@ -604,10 +598,6 @@
     return integer.intValue();
   }
 
-  public JMethod getRebindCreateMethod() {
-    return rebindCreateMethod;
-  }
-
   public JMethod getStaticImpl(JMethod method) {
     return instanceToStaticMap.get(method);
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
index fe12346..cd0b507 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
@@ -31,7 +31,6 @@
 import com.google.gwt.dev.jjs.ast.JCaseStatement;
 import com.google.gwt.dev.jjs.ast.JCastOperation;
 import com.google.gwt.dev.jjs.ast.JCharLiteral;
-import com.google.gwt.dev.jjs.ast.JClassLiteral;
 import com.google.gwt.dev.jjs.ast.JClassType;
 import com.google.gwt.dev.jjs.ast.JConditional;
 import com.google.gwt.dev.jjs.ast.JContinueStatement;
@@ -374,28 +373,20 @@
             currentClass.methods.remove(2);
           } else {
             tryFindUpRefs(method);
-            JMethodBody body = (JMethodBody) method.getBody();
-            JClassLiteral classLit = program.getLiteralClass(currentClass);
-            body.getStatements().add(
-                new JReturnStatement(program, null, classLit));
+            implementMethod(method, program.getLiteralClass(currentClass));
           }
         }
 
+        // Reimplement GWT.isClient() to return true
+        if (currentClass == program.getIndexedType("GWT")) {
+          JMethod method = program.getIndexedMethod("GWT.isClient");
+          implementMethod(method, program.getLiteralBoolean(true));
+        }
+
         // Implement Class.desiredAssertionStatus
         if (currentClass == program.getTypeJavaLangClass()) {
           JMethod method = program.getIndexedMethod("Class.desiredAssertionStatus");
-          assert method != null;
-          JMethodBody body = (JMethodBody) method.getBody();
-          List<JStatement> statements = body.getStatements();
-
-          // There must always be at least 1 statement, because the method
-          // has a non-void return type.
-          assert statements.size() > 0;
-
-          SourceInfo info = statements.get(0).getSourceInfo();
-          statements.clear();
-          statements.add(new JReturnStatement(program, info,
-              program.getLiteralBoolean(enableAsserts)));
+          implementMethod(method, program.getLiteralBoolean(enableAsserts));
         }
 
         if (currentClass instanceof JEnumType) {
@@ -2192,6 +2183,22 @@
       }
     }
 
+    private void implementMethod(JMethod method, JExpression returnValue) {
+      assert method != null;
+      JMethodBody body = (JMethodBody) method.getBody();
+      List<JStatement> statements = body.getStatements();
+
+      SourceInfo info;
+      if (statements.size() > 0) {
+        info = statements.get(0).getSourceInfo();
+      } else {
+        info = method.getSourceInfo();
+      }
+
+      statements.clear();
+      statements.add(new JReturnStatement(program, info, returnValue));
+    }
+
     private SourceInfo makeSourceInfo(Statement x) {
       int startLine = Util.getLineNumber(x.sourceStart,
           currentSeparatorPositions, 0, currentSeparatorPositions.length - 1);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRebinds.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRebinds.java
index aecc287..c2fabb6 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRebinds.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRebinds.java
@@ -33,10 +33,16 @@
 
   private class RebindVisitor extends JModVisitor {
 
+    private final JMethod rebindCreateMethod;
+
+    public RebindVisitor(JMethod rebindCreateMethod) {
+      this.rebindCreateMethod = rebindCreateMethod;
+    }
+
     // @Override
     public void endVisit(JMethodCall x, Context ctx) {
       JMethod method = x.getTarget();
-      if (method == program.getRebindCreateMethod()) {
+      if (method == rebindCreateMethod) {
         assert (x.getArgs().size() == 1);
         JExpression arg = x.getArgs().get(0);
         assert (arg instanceof JClassLiteral);
@@ -78,7 +84,8 @@
   }
 
   private boolean execImpl() {
-    RebindVisitor rebinder = new RebindVisitor();
+    RebindVisitor rebinder = new RebindVisitor(
+        program.getIndexedMethod("GWT.create"));
     rebinder.accept(program);
     return rebinder.didChange();
   }
diff --git a/user/src/com/google/gwt/core/client/GWT.java b/user/src/com/google/gwt/core/client/GWT.java
index eefc2c1..dc8e0f4 100644
--- a/user/src/com/google/gwt/core/client/GWT.java
+++ b/user/src/com/google/gwt/core/client/GWT.java
@@ -57,6 +57,7 @@
    *          instantiated
    * @return the new instance, which must be typecast to the requested class.
    */
+  @SuppressWarnings("unused")
   public static <T> T create(Class<?> classLiteral) {
     /*
      * In web mode, the compiler directly replaces calls to this method with a
@@ -128,16 +129,29 @@
   }-*/;
 
   /**
+   * Returns <code>true</code> when running inside the normal GWT environment,
+   * either in hosted mode or web mode. Returns <code>false</code> if this
+   * code is running in a plain JVM. This might happen when running shared code
+   * on the server, or during the bootstrap sequence of a GWTTestCase test.
+   */
+  public static boolean isClient() {
+    // Replaced with "true" by compiler and hosted mode.
+    return false;
+  }
+
+  /**
    * Determines whether or not the running program is script or bytecode.
    */
   public static boolean isScript() {
-    return true;
+    // Will return false in hosted mode.
+    return isClient() && true;
   }
 
   /**
    * Logs a message to the development shell logger in hosted mode. Calls are
    * optimized out in web mode.
    */
+  @SuppressWarnings("unused")
   public static void log(String message, Throwable e) {
     // intentionally empty in web mode.
   }
diff --git a/user/src/com/google/gwt/core/client/GWT.java-hosted b/user/src/com/google/gwt/core/client/GWT.java-hosted
index 54d31d3..a44f787 100644
--- a/user/src/com/google/gwt/core/client/GWT.java-hosted
+++ b/user/src/com/google/gwt/core/client/GWT.java-hosted
@@ -1,5 +1,5 @@
 /*

- * Copyright 2007 Google Inc.

+ * Copyright 2008 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

@@ -63,6 +63,11 @@
     return ShellGWT.getVersion();

   };

 

+  public static boolean isClient() {

+    // true in hosted mode

+    return true;

+  }

+

   public static boolean isScript() {

     // false in hosted mode

     return false;

diff --git a/user/test/com/google/gwt/core/CoreSuite.java b/user/test/com/google/gwt/core/CoreSuite.java
index 17c5806..8084e34 100644
--- a/user/test/com/google/gwt/core/CoreSuite.java
+++ b/user/test/com/google/gwt/core/CoreSuite.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.core;
 
+import com.google.gwt.core.client.GWTTest;
 import com.google.gwt.core.client.JavaScriptExceptionTest;
 import com.google.gwt.junit.tools.GWTTestSuite;
 
@@ -29,6 +30,7 @@
 
     // $JUnit-BEGIN$
     suite.addTestSuite(JavaScriptExceptionTest.class);
+    suite.addTestSuite(GWTTest.class);
     // $JUnit-END$
 
     return suite;
diff --git a/user/test/com/google/gwt/core/client/GWTTest.java b/user/test/com/google/gwt/core/client/GWTTest.java
new file mode 100644
index 0000000..57b8a24
--- /dev/null
+++ b/user/test/com/google/gwt/core/client/GWTTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2008 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.core.client;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests for the GWT class.
+ */
+public class GWTTest extends GWTTestCase {
+
+  private static volatile int seven = 7;
+
+  private static volatile int zero = 0;
+
+  private static native boolean canCallNativeMethod() /*-{
+    return true;
+  }-*/;
+
+  private static void jvmTests() {
+    assertFalse(GWT.isClient());
+    assertFalse(GWT.isScript());
+    try {
+      canCallNativeMethod();
+      fail("Expected UnsatisfiedLinkError");
+    } catch (Throwable expected) {
+      assertEquals("java.lang.UnsatisfiedLinkError",
+          expected.getClass().getName());
+    }
+    try {
+      GWT.create(GWTTest.class);
+      fail("Expected UnsupportedOperationException");
+    } catch (UnsupportedOperationException expected) {
+    }
+  }
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.core.Core";
+  }
+
+  public void testCreate() {
+    Object created = GWT.create(GWTTest.class);
+    assertSame(getClass(), created.getClass());
+  }
+
+  public void testGetModuleName() {
+    assertEquals("com.google.gwt.core.Core.JUnit", GWT.getModuleName());
+  }
+
+  @SuppressWarnings("deprecation")
+  public void testGetTypeName() {
+    assertEquals(getClass().getName(), GWT.getTypeName(this));
+  }
+
+  public void testIsClient() {
+    assertTrue(GWT.isClient());
+    assertTrue(canCallNativeMethod());
+  }
+
+  public void testIsScript() {
+    try {
+      double d = seven / zero;
+      if (GWT.isScript()) {
+        assertEquals(Double.NaN, d);
+      } else {
+        fail("Expected ArithmeticException");
+      }
+    } catch (ArithmeticException expected) {
+      assertFalse(GWT.isScript());
+    }
+  }
+
+  @Override
+  protected void setUp() {
+    if (GWT.isClient()) {
+      assertTrue(canCallNativeMethod());
+    } else {
+      jvmTests();
+    }
+  }
+}