Use 'boolean' instead of 'Z' for JSNI primitive type qualifiers.

This change is transitional, we will continue to support the only style for now.

http://gwt-code-reviews.appspot.com/1295805/show

Review by: robertvawter@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9649 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java b/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java
index c5a492b..c2add7d 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java
@@ -280,13 +280,27 @@
         className = className.substring(0, className.length() - 2);
       }
 
-      /*
-       * TODO(bobv): OMG WTF LOL. Okay, but seriously, the LHS of a JSNI ref for
-       * a primitive type should be the keyword, e.g. "int.class".
-       */
-      ReferenceBinding clazz = findClass(className);
-      boolean isPrimitive = (clazz == null) && className.length() == 1
-          && "ZBCDFIJSV".indexOf(className.charAt(0)) >= 0;
+      boolean isPrimitive = false;
+      TypeBinding binding = method.scope.getBaseType(className.toCharArray());
+      if (binding != null) {
+        isPrimitive = true;
+      } else {
+        binding = findClass(className);
+      }
+
+      // TODO(deprecation): remove this support eventually.
+      if (binding == null && className.length() == 1
+          && "ZBCDFIJSV".indexOf(className.charAt(0)) >= 0) {
+        isPrimitive = true;
+        binding = getTypeBinding(className.charAt(0));
+        assert binding != null;
+        JsniCollector.reportJsniWarning(
+            errorInfo,
+            method,
+            "Referencing primitive type '" + className
+                + "': this is deprecated, use '"
+                + String.valueOf(binding.sourceName()) + "' instead");
+      }
 
       if (isArray || isPrimitive) {
         if (!jsniRef.isField() || !jsniRef.memberName().equals("class")) {
@@ -302,26 +316,26 @@
         return;
       }
 
-      // TODO(bobv): uncomment this.
-      // ReferenceBinding clazz = findClass(className);
       if (looksLikeAnonymousClass(jsniRef)
-          || (clazz != null && clazz.isAnonymousType())) {
+          || (binding != null && binding.isAnonymousType())) {
         emitError("Referencing class '" + className
             + ": JSNI references to anonymous classes are illegal");
-      } else if (clazz != null) {
-        if (clazz.isDeprecated()) {
-          emitWarning("deprecation", "Referencing deprecated class '"
-              + className + "'");
-        }
-
-        if (jsniRef.isMethod()) {
-          checkMethodRef(clazz, jsniRef);
-        } else {
-          checkFieldRef(clazz, jsniRef);
-        }
-      } else {
+        return;
+      } else if (binding == null) {
         emitError("JSNI Referencing class '" + className
             + "': unable to resolve class, expect subsequent failures");
+        return;
+      }
+      ReferenceBinding clazz = (ReferenceBinding) binding;
+      if (clazz.isDeprecated()) {
+        emitWarning("deprecation", "Referencing deprecated class '" + className
+            + "'");
+      }
+
+      if (jsniRef.isMethod()) {
+        checkMethodRef(clazz, jsniRef);
+      } else {
+        checkFieldRef(clazz, jsniRef);
       }
     }
 
@@ -406,6 +420,32 @@
       return null;
     }
 
+    @Deprecated
+    private TypeBinding getTypeBinding(char c) {
+      switch (c) {
+        case 'I':
+          return TypeBinding.INT;
+        case 'Z':
+          return TypeBinding.BOOLEAN;
+        case 'V':
+          return TypeBinding.VOID;
+        case 'C':
+          return TypeBinding.CHAR;
+        case 'D':
+          return TypeBinding.DOUBLE;
+        case 'B':
+          return TypeBinding.BYTE;
+        case 'F':
+          return TypeBinding.FLOAT;
+        case 'J':
+          return TypeBinding.LONG;
+        case 'S':
+          return TypeBinding.SHORT;
+        default:
+          return null;
+      }
+    }
+
     private boolean looksLikeAnonymousClass(JsniRef jsniRef) {
       char[][] compoundName = getCompoundName(jsniRef);
       for (char[] part : compoundName) {
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 233c0e9..a4ca996 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
@@ -106,6 +106,11 @@
 
   private static final int IS_NULL = 0;
 
+  private static final Map<String, JPrimitiveType> primitiveTypes = new HashMap<String, JPrimitiveType>();
+  
+  @Deprecated
+  private static final Map<String, JPrimitiveType> primitiveTypesDeprecated = new HashMap<String, JPrimitiveType>();
+
   static {
     INDEX_TYPES_SET.addAll(CODEGEN_TYPES_SET);
 
@@ -133,6 +138,35 @@
         }
       }
     }
+
+    primitiveTypes.put(JPrimitiveType.BOOLEAN.getName(), JPrimitiveType.BOOLEAN);
+    primitiveTypes.put(JPrimitiveType.BYTE.getName(), JPrimitiveType.BYTE);
+    primitiveTypes.put(JPrimitiveType.CHAR.getName(), JPrimitiveType.CHAR);
+    primitiveTypes.put(JPrimitiveType.DOUBLE.getName(), JPrimitiveType.DOUBLE);
+    primitiveTypes.put(JPrimitiveType.FLOAT.getName(), JPrimitiveType.FLOAT);
+    primitiveTypes.put(JPrimitiveType.INT.getName(), JPrimitiveType.INT);
+    primitiveTypes.put(JPrimitiveType.LONG.getName(), JPrimitiveType.LONG);
+    primitiveTypes.put(JPrimitiveType.SHORT.getName(), JPrimitiveType.SHORT);
+    primitiveTypes.put(JPrimitiveType.VOID.getName(), JPrimitiveType.VOID);
+
+    primitiveTypesDeprecated.put(JPrimitiveType.BOOLEAN.getJsniSignatureName(),
+        JPrimitiveType.BOOLEAN);
+    primitiveTypesDeprecated.put(JPrimitiveType.BYTE.getJsniSignatureName(),
+        JPrimitiveType.BYTE);
+    primitiveTypesDeprecated.put(JPrimitiveType.CHAR.getJsniSignatureName(),
+        JPrimitiveType.CHAR);
+    primitiveTypesDeprecated.put(JPrimitiveType.DOUBLE.getJsniSignatureName(),
+        JPrimitiveType.DOUBLE);
+    primitiveTypesDeprecated.put(JPrimitiveType.FLOAT.getJsniSignatureName(),
+        JPrimitiveType.FLOAT);
+    primitiveTypesDeprecated.put(JPrimitiveType.INT.getJsniSignatureName(),
+        JPrimitiveType.INT);
+    primitiveTypesDeprecated.put(JPrimitiveType.LONG.getJsniSignatureName(),
+        JPrimitiveType.LONG);
+    primitiveTypesDeprecated.put(JPrimitiveType.SHORT.getJsniSignatureName(),
+        JPrimitiveType.SHORT);
+    primitiveTypesDeprecated.put(JPrimitiveType.VOID.getJsniSignatureName(),
+        JPrimitiveType.VOID);
   }
 
   /**
@@ -1054,29 +1088,14 @@
       className = className.substring(0, className.length() - 2);
     }
 
-    JType type;
-    if ("Z".equals(className)) {
-      type = getTypePrimitiveBoolean();
-    } else if ("B".equals(className)) {
-      type = getTypePrimitiveByte();
-    } else if ("C".equals(className)) {
-      type = getTypePrimitiveChar();
-    } else if ("D".equals(className)) {
-      type = getTypePrimitiveDouble();
-    } else if ("F".equals(className)) {
-      type = getTypePrimitiveFloat();
-    } else if ("I".equals(className)) {
-      type = getTypePrimitiveInt();
-    } else if ("J".equals(className)) {
-      type = getTypePrimitiveLong();
-    } else if ("S".equals(className)) {
-      type = getTypePrimitiveShort();
-    } else if ("V".equals(className)) {
-      type = getTypeVoid();
-    } else {
+    JType type = primitiveTypes.get(className);
+    if (type == null) {
       type = getFromTypeMap(className);
     }
-
+    // TODO(deprecation): remove support for this.
+    if (type == null) {
+      type = primitiveTypesDeprecated.get(className);
+    }
     if (type == null || dim == 0) {
       return type;
     } else {
diff --git a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
index 9e1e93d..d5ed6ed 100644
--- a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
+++ b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
@@ -208,45 +208,31 @@
      *         class name could not be found
      */
     private Class<?> getClassFromBinaryName(String binaryClassName) {
-      try {
-        int dims = 0;
-        while (binaryClassName.endsWith("[]")) {
-          dims++;
-          binaryClassName = binaryClassName.substring(0,
-              binaryClassName.length() - 2);
-        }
+      int dims = 0;
+      while (binaryClassName.endsWith("[]")) {
+        dims++;
+        binaryClassName = binaryClassName.substring(0,
+            binaryClassName.length() - 2);
+      }
 
-        Class<?> clazz;
-        if ("Z".equals(binaryClassName)) {
-          clazz = boolean.class;
-        } else if ("B".equals(binaryClassName)) {
-          clazz = byte.class;
-        } else if ("C".equals(binaryClassName)) {
-          clazz = char.class;
-        } else if ("D".equals(binaryClassName)) {
-          clazz = double.class;
-        } else if ("F".equals(binaryClassName)) {
-          clazz = float.class;
-        } else if ("I".equals(binaryClassName)) {
-          clazz = int.class;
-        } else if ("J".equals(binaryClassName)) {
-          clazz = long.class;
-        } else if ("S".equals(binaryClassName)) {
-          clazz = short.class;
-        } else if ("V".equals(binaryClassName)) {
-          clazz = void.class;
-        } else {
+      Class<?> clazz = primitiveTypes.get(binaryClassName);
+      if (clazz == null) {
+        try {
           clazz = Class.forName(binaryClassName, false,
               CompilingClassLoader.this);
+        } catch (ClassNotFoundException e) {
         }
-
-        if (dims > 0) {
-          return Array.newInstance(clazz, new int[dims]).getClass();
-        } else {
-          return clazz;
-        }
-      } catch (ClassNotFoundException e) {
-        return null;
+      }
+      // TODO(deprecation): remove this support eventually.
+      if (clazz == null && binaryClassName.length() == 1
+          && "ZBCDFIJSV".indexOf(binaryClassName.charAt(0)) >= 0) {
+        clazz = getDeprecatedPrimitiveType(binaryClassName.charAt(0));
+        assert clazz != null;
+      }
+      if (dims > 0) {
+        return Array.newInstance(clazz, new int[dims]).getClass();
+      } else {
+        return clazz;
       }
     }
 
@@ -320,6 +306,32 @@
       return dispClassInfo;
     }
 
+    @Deprecated
+    private Class<?> getDeprecatedPrimitiveType(char c) {
+      switch (c) {
+        case 'Z':
+          return boolean.class;
+        case 'B':
+          return byte.class;
+        case 'C':
+          return char.class;
+        case 'D':
+          return double.class;
+        case 'F':
+          return float.class;
+        case 'I':
+          return int.class;
+        case 'J':
+          return long.class;
+        case 'S':
+          return short.class;
+        case 'V':
+          return void.class;
+        default:
+          return null;
+      }
+    }
+
     /**
      * Synthesizes a dispatch identifier for the given class and member ids.
      * 
@@ -706,6 +718,20 @@
    */
   private static byte[] javaScriptHostBytes;
 
+  private static final Map<String, Class<?>> primitiveTypes = new HashMap<String, Class<?>>();
+
+  static {
+    primitiveTypes.put(boolean.class.getSimpleName(), boolean.class);
+    primitiveTypes.put(byte.class.getSimpleName(), boolean.class);
+    primitiveTypes.put(char.class.getSimpleName(), boolean.class);
+    primitiveTypes.put(double.class.getSimpleName(), boolean.class);
+    primitiveTypes.put(float.class.getSimpleName(), boolean.class);
+    primitiveTypes.put(int.class.getSimpleName(), boolean.class);
+    primitiveTypes.put(long.class.getSimpleName(), boolean.class);
+    primitiveTypes.put(short.class.getSimpleName(), boolean.class);
+    primitiveTypes.put(void.class.getSimpleName(), boolean.class);
+  }
+
   static {
     for (Class<?> c : BRIDGE_CLASSES) {
       BRIDGE_CLASS_NAMES.put(c.getName(), c);
diff --git a/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java b/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java
index e32b59e..b4006c0 100644
--- a/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java
@@ -466,25 +466,36 @@
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  native void jsniMethod() /*-{\n");
-    code.append("    @Z::blah;\n");
+    code.append("    @boolean::blah;\n");
     code.append("  }-*/;\n");
     code.append("}\n");
     shouldGenerateError(
         code,
         3,
-        "Referencing member 'Z.blah': 'class' is the only legal reference for primitive types");
+        "Referencing member 'boolean.blah': 'class' is the only legal reference for primitive types");
   }
 
   public void testPrimitiveClass() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  native void jsniMethod() /*-{\n");
-    code.append("    @Z::class;\n");
+    code.append("    @boolean::class;\n");
     code.append("  }-*/;\n");
     code.append("}\n");
     shouldGenerateNoWarning(code);
   }
 
+  public void testPrimitiveClassDeprecated() {
+    StringBuffer code = new StringBuffer();
+    code.append("class Buggy {\n");
+    code.append("  native void jsniMethod() /*-{\n");
+    code.append("    @Z::class;\n");
+    code.append("  }-*/;\n");
+    code.append("}\n");
+    shouldGenerateWarning(code, 3,
+        "Referencing primitive type 'Z': this is deprecated, use 'boolean' instead");
+  }
+
   public void testRefInString() {
     {
       StringBuffer code = new StringBuffer();
diff --git a/user/src/com/google/gwt/rpc/rebind/RpcProxyCreator.java b/user/src/com/google/gwt/rpc/rebind/RpcProxyCreator.java
index 19e33bc..7ea1bac 100644
--- a/user/src/com/google/gwt/rpc/rebind/RpcProxyCreator.java
+++ b/user/src/com/google/gwt/rpc/rebind/RpcProxyCreator.java
@@ -323,19 +323,10 @@
       JPrimitiveType serializablePrimitive = serializableType.isPrimitive();
       if (serializableArray != null) {
         sb.append("\n@Rescue(className = \"");
-        if (serializableArray.getLeafType() instanceof JPrimitiveType) {
-          sb.append(serializableArray.getLeafType().getJNISignature());
-          for (int i = 0, j = serializableArray.getRank(); i < j; i++) {
-            sb.append("[]");
-          }
-        } else {
-          sb.append(serializableArray.getQualifiedSourceName());
-        }
+        sb.append(serializableArray.getQualifiedSourceName());
         sb.append("\",\n instantiable = true),");
-
       } else if (serializableClass != null) {
         writeSingleRescue(typeOracle, deserializationSto, sb, serializableClass);
-
       } else if (serializablePrimitive != null) {
         JClassType boxedClass = typeOracle.findType(serializablePrimitive.getQualifiedBoxedSourceName());
         assert boxedClass != null : "No boxed version of "
diff --git a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
index 0f7726a..423591e 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/TypeSerializerCreator.java
@@ -574,20 +574,13 @@
         continue;
       }
 
-      String jsniTypeRef;
-      jsniTypeRef = SerializationUtils.getRpcTypeName(type.getLeafType());
-      while (type.isArray() != null) {
-        jsniTypeRef += "[]";
-        type = type.isArray().getComponentType();
-      }
-
       if (shard && ++shardCount % shardSize == 0) {
         srcWriter.println("})();");
         srcWriter.println("(function() {");
       }
 
       srcWriter.println("result[@com.google.gwt.core.client.impl.Impl::getHashCode(Ljava/lang/Object;)(@"
-          + jsniTypeRef + "::class)] = \"" + typeString + "\";");
+          + type.getQualifiedSourceName() + "::class)] = \"" + typeString + "\";");
     }
 
     if (shard) {