GwtAstBuilder better handling of JSNI refs to constants.

Turns out the target GWT field is not always fully baked, as it was in GenerateJavaAST.  Using JDT to get the compile-time constant is the right approach.

http://gwt-code-reviews.appspot.com/1449818/

Review by: jbrosenberg@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10337 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
index 6a461eb..6b594f7 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
@@ -34,7 +34,6 @@
 import com.google.gwt.dev.jjs.ast.JMethodBody;
 import com.google.gwt.dev.jjs.ast.JNullType;
 import com.google.gwt.dev.jjs.ast.JParameter;
-import com.google.gwt.dev.jjs.ast.JPrimitiveType;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JReferenceType;
 import com.google.gwt.dev.jjs.ast.JType;
@@ -63,7 +62,6 @@
 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.Statement;
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
-import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
 import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
@@ -570,27 +568,9 @@
 
   private JField createField(SourceInfo info, FieldBinding binding, JDeclaredType enclosingType) {
     JType type = getType(binding.type);
-
-    boolean isCompileTimeConstant =
-        binding.isStatic() && (binding.isFinal()) && (binding.constant() != Constant.NotAConstant)
-            && (binding.type.isBaseType());
-    assert (type instanceof JPrimitiveType || !isCompileTimeConstant);
-
-    assert (!binding.isFinal() || !binding.isVolatile());
-    Disposition disposition;
-    if (isCompileTimeConstant) {
-      disposition = Disposition.COMPILE_TIME_CONSTANT;
-    } else if (binding.isFinal()) {
-      disposition = Disposition.FINAL;
-    } else if (binding.isVolatile()) {
-      disposition = Disposition.VOLATILE;
-    } else {
-      disposition = Disposition.NONE;
-    }
-
     JField field =
         program.createField(info, String.valueOf(binding.name), enclosingType, type, binding
-            .isStatic(), disposition);
+            .isStatic(), GwtAstBuilder.getFieldDisposition(binding));
     typeMap.put(binding, field);
     info.addCorrelation(info.getCorrelator().by(field));
     return field;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index 3297187..8fad08b 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -236,6 +236,7 @@
      * Resolves local references to function parameters, and JSNI references.
      */
     private class JsniResolver extends JsModVisitor {
+      private final GenerateJavaScriptLiterals generator = new GenerateJavaScriptLiterals();
       private final JsniMethodBody nativeMethodBody;
 
       private JsniResolver(JsniMethodBody nativeMethodBody) {
@@ -260,8 +261,23 @@
             JType type = typeMap.get((TypeBinding) binding);
             processClassLiteral(x, info, type, ctx);
           } else if (binding instanceof FieldBinding) {
-            JField field = typeMap.get((FieldBinding) binding);
-            processField(x, info, field, ctx);
+            FieldBinding fieldBinding = (FieldBinding) binding;
+            /*
+             * We must replace any compile-time constants with the constant
+             * value of the field.
+             */
+            if (isCompileTimeConstant(fieldBinding)) {
+              assert !ctx.isLvalue();
+              JExpression constant = getConstant(info, fieldBinding.constant());
+              generator.accept(constant);
+              JsExpression result = generator.pop();
+              assert (result != null);
+              ctx.replaceMe(result);
+            } else {
+              // Normal: create a jsniRef.
+              JField field = typeMap.get(fieldBinding);
+              processField(x, info, field, ctx);
+            }
           } else {
             JMethod method = typeMap.get((MethodBinding) binding);
             processMethod(x, info, method);
@@ -276,25 +292,6 @@
       }
 
       private void processField(JsNameRef nameRef, SourceInfo info, JField field, JsContext ctx) {
-        /*
-         * We must replace any compile-time constants with the constant value of
-         * the field.
-         */
-        if (field.isCompileTimeConstant()) {
-          assert !ctx.isLvalue();
-          JLiteral initializer = field.getConstInitializer();
-          JType type = initializer.getType();
-          if (type instanceof JPrimitiveType || initializer instanceof JStringLiteral) {
-            GenerateJavaScriptLiterals generator = new GenerateJavaScriptLiterals();
-            generator.accept(initializer);
-            JsExpression result = generator.peek();
-            assert (result != null);
-            ctx.replaceMe(result);
-            return;
-          }
-        }
-
-        // Normal: create a jsniRef.
         JsniFieldRef fieldRef =
             new JsniFieldRef(info, nameRef.getIdent(), field, curClass.type, ctx.isLvalue());
         nativeMethodBody.addJsniRef(fieldRef);
@@ -2811,6 +2808,20 @@
     return result.toString();
   }
 
+  static Disposition getFieldDisposition(FieldBinding binding) {
+    Disposition disposition;
+    if (isCompileTimeConstant(binding)) {
+      disposition = Disposition.COMPILE_TIME_CONSTANT;
+    } else if (binding.isFinal()) {
+      disposition = Disposition.FINAL;
+    } else if (binding.isVolatile()) {
+      disposition = Disposition.VOLATILE;
+    } else {
+      disposition = Disposition.NONE;
+    }
+    return disposition;
+  }
+
   static String intern(char[] cs) {
     return intern(String.valueOf(cs));
   }
@@ -2823,6 +2834,16 @@
     return binding.isNestedType() && !binding.isStatic();
   }
 
+  private static boolean isCompileTimeConstant(FieldBinding binding) {
+    assert !binding.isFinal() || !binding.isVolatile();
+    boolean isCompileTimeConstant =
+        binding.isStatic() && binding.isFinal() && (binding.constant() != Constant.NotAConstant);
+    if (isCompileTimeConstant) {
+      assert binding.type.isBaseType() || (binding.type.id == TypeIds.T_JavaLangString);
+    }
+    return isCompileTimeConstant;
+  }
+
   /**
    * Returns <code>true</code> if JDT optimized the condition to
    * <code>false</code>.
@@ -2971,26 +2992,9 @@
           new JEnumField(info, intern(binding.name), binding.original().id,
               (JEnumType) enclosingType, (JClassType) type);
     } else {
-      boolean isCompileTimeConstant =
-          binding.isStatic() && (binding.isFinal())
-              && (binding.constant() != Constant.NotAConstant) && (binding.type.isBaseType());
-      assert (type instanceof JPrimitiveType || !isCompileTimeConstant);
-
-      assert (!binding.isFinal() || !binding.isVolatile());
-      Disposition disposition;
-      if (isCompileTimeConstant) {
-        disposition = Disposition.COMPILE_TIME_CONSTANT;
-      } else if (binding.isFinal()) {
-        disposition = Disposition.FINAL;
-      } else if (binding.isVolatile()) {
-        disposition = Disposition.VOLATILE;
-      } else {
-        disposition = Disposition.NONE;
-      }
-
       field =
           new JField(info, intern(binding.name), enclosingType, type, binding.isStatic(),
-              disposition);
+              getFieldDisposition(binding));
     }
     enclosingType.addField(field);
     typeMap.setField(binding, field);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
index 2b19c5c..2d99763 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
@@ -24,7 +24,6 @@
 import com.google.gwt.dev.jjs.ast.JDeclaredType;
 import com.google.gwt.dev.jjs.ast.JEnumType;
 import com.google.gwt.dev.jjs.ast.JField;
-import com.google.gwt.dev.jjs.ast.JField.Disposition;
 import com.google.gwt.dev.jjs.ast.JInterfaceType;
 import com.google.gwt.dev.jjs.ast.JMethod;
 import com.google.gwt.dev.jjs.ast.JNullType;
@@ -34,7 +33,6 @@
 import com.google.gwt.dev.jjs.ast.JType;
 import com.google.gwt.dev.util.StringInterner;
 
-import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
 import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
@@ -242,27 +240,9 @@
 
   private JField createField(FieldBinding binding) {
     JDeclaredType enclosingType = (JDeclaredType) get(binding.declaringClass);
-
-    boolean isCompileTimeConstant =
-        binding.isStatic() && (binding.isFinal()) && (binding.constant() != Constant.NotAConstant)
-            && (binding.type.isBaseType());
-    assert (get(binding.type) instanceof JPrimitiveType || !isCompileTimeConstant);
-
-    assert (!binding.isFinal() || !binding.isVolatile());
-    Disposition disposition;
-    if (isCompileTimeConstant) {
-      disposition = Disposition.COMPILE_TIME_CONSTANT;
-    } else if (binding.isFinal()) {
-      disposition = Disposition.FINAL;
-    } else if (binding.isVolatile()) {
-      disposition = Disposition.VOLATILE;
-    } else {
-      disposition = Disposition.NONE;
-    }
-
     JField field =
         new JField(SourceOrigin.UNKNOWN, intern(binding.name), enclosingType, get(binding.type),
-            binding.isStatic(), disposition);
+            binding.isStatic(), GwtAstBuilder.getFieldDisposition(binding));
     enclosingType.addField(field);
     return field;
   }