Fixes issue #1989; JSNI references to instance fields/methods on uninstantiable types were causing ICEs when GenerateJavaAST would try to resolve them.

Review by: bobv (postmortem)


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1911 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
index b76cede..271ef66 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
@@ -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
@@ -97,7 +97,7 @@
               "Could not find enum values() method");
         }
         JsniMethodRef jsniMethodRef = new JsniMethodRef(program.program, null,
-            valuesMethod);
+            null, valuesMethod);
         call.getArgs().add(jsniMethodRef);
       }
     } else {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniFieldRef.java b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniFieldRef.java
index 4480cc6..7245843 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniFieldRef.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniFieldRef.java
@@ -28,10 +28,17 @@
  */
 public class JsniFieldRef extends JFieldRef {
 
-  public JsniFieldRef(JProgram program, SourceInfo info, JField field,
-      JReferenceType enclosingType) {
+  private final String ident;
+
+  public JsniFieldRef(JProgram program, SourceInfo info, String ident,
+      JField field, JReferenceType enclosingType) {
     super(program, info, field.isStatic() ? null : program.getLiteralNull(),
         field, enclosingType);
+    this.ident = ident;
+  }
+
+  public String getIdent() {
+    return ident;
   }
 
   public void traverse(JVisitor visitor, Context ctx) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodRef.java b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodRef.java
index a0fd09b..d035c98 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodRef.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodRef.java
@@ -29,10 +29,18 @@
  */
 public class JsniMethodRef extends JMethodCall {
 
-  public JsniMethodRef(JProgram program, SourceInfo info, JMethod method) {
+  private final String ident;
+
+  public JsniMethodRef(JProgram program, SourceInfo info, String ident,
+      JMethod method) {
     // Just use a null literal as the qualifier on a non-static method
     super(program, info, method.isStatic() ? null : program.getLiteralNull(),
         method);
+    this.ident = ident;
+  }
+
+  public String getIdent() {
+    return ident;
   }
 
   @Override
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 5f56942..4880242 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
@@ -321,8 +321,8 @@
         }
 
         // Normal: create a jsniRef.
-        JsniFieldRef fieldRef = new JsniFieldRef(program, info, field,
-            currentClass);
+        JsniFieldRef fieldRef = new JsniFieldRef(program, info,
+            nameRef.getIdent(), field, currentClass);
         nativeMethodBody.jsniFieldRefs.add(fieldRef);
       }
 
@@ -338,7 +338,8 @@
                   + method.getName());
         }
 
-        JsniMethodRef methodRef = new JsniMethodRef(program, info, method);
+        JsniMethodRef methodRef = new JsniMethodRef(program, info,
+            nameRef.getIdent(), method);
         nativeMethodBody.jsniMethodRefs.add(methodRef);
       }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
index 043de05..e0257e7 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
@@ -17,6 +17,7 @@
 
 import com.google.gwt.dev.jjs.ast.CanBeStatic;
 import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.HasEnclosingType;
 import com.google.gwt.dev.jjs.ast.JAbsentArrayDimension;
 import com.google.gwt.dev.jjs.ast.JArrayType;
 import com.google.gwt.dev.jjs.ast.JBinaryOperation;
@@ -112,16 +113,6 @@
       }
     }
 
-    @Override
-    public void endVisit(JMethod x, Context ctx) {
-      JType type = x.getType();
-      if (type instanceof JReferenceType) {
-        if (!program.typeOracle.isInstantiatedType((JReferenceType) type)) {
-          x.setType(program.getTypeNull());
-        }
-      }
-    }
-
     public void endVisit(JLocalDeclarationStatement x, Context ctx) {
       // The variable may have been pruned.
       if (!referencedNonTypes.contains(x.getLocalRef().getTarget())) {
@@ -142,6 +133,16 @@
     }
 
     @Override
+    public void endVisit(JMethod x, Context ctx) {
+      JType type = x.getType();
+      if (type instanceof JReferenceType) {
+        if (!program.typeOracle.isInstantiatedType((JReferenceType) type)) {
+          x.setType(program.getTypeNull());
+        }
+      }
+    }
+
+    @Override
     public void endVisit(JMethodCall x, Context ctx) {
       JMethod method = x.getTarget();
 
@@ -190,6 +191,38 @@
         ctx.replaceMe(newCall);
       }
     }
+
+    @Override
+    public void endVisit(JsniFieldRef x, Context ctx) {
+      if (isUninstantiable(x.getField())) {
+        String ident = x.getIdent();
+        JField nullField = program.getNullField();
+        program.jsniMap.put(ident, nullField);
+        JsniFieldRef nullFieldRef = new JsniFieldRef(program,
+            x.getSourceInfo(), ident, nullField, x.getEnclosingType());
+        ctx.replaceMe(nullFieldRef);
+      }
+    }
+
+    @Override
+    public void endVisit(JsniMethodRef x, Context ctx) {
+      // Redirect JSNI refs to uninstantiable types to the null method.
+      if (isUninstantiable(x.getTarget())) {
+        String ident = x.getIdent();
+        JMethod nullMethod = program.getNullMethod();
+        program.jsniMap.put(ident, nullMethod);
+        JsniMethodRef nullMethodRef = new JsniMethodRef(program,
+            x.getSourceInfo(), ident, nullMethod);
+        ctx.replaceMe(nullMethodRef);
+      }
+    }
+
+    private <T extends HasEnclosingType & CanBeStatic> boolean isUninstantiable(
+        T node) {
+      JReferenceType enclosingType = node.getEnclosingType();
+      return !node.isStatic() && enclosingType != null
+          && !program.typeOracle.isInstantiatedType(enclosingType);
+    }
   }
 
   /**
@@ -831,10 +864,10 @@
     return new Pruner(program, noSpecialTypes).execImpl();
   }
 
+  private final Map<JMethod, ArrayList<JParameter>> methodToOriginalParamsMap = new HashMap<JMethod, ArrayList<JParameter>>();
   private final JProgram program;
   private final Set<JNode> referencedNonTypes = new HashSet<JNode>();
   private final Set<JReferenceType> referencedTypes = new HashSet<JReferenceType>();
-  private final Map<JMethod, ArrayList<JParameter>> methodToOriginalParamsMap = new HashMap<JMethod, ArrayList<JParameter>>();
   private final boolean saveCodeGenTypes;
   private JMethod stringValueOfChar = null;
 
diff --git a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
index 9a3533d..94ad4cf 100644
--- a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
@@ -137,7 +137,7 @@
   private static int sideEffectChecker;
 
   private static native void accessUninstantiableField(UninstantiableType u) /*-{
-    u.@com.google.gwt.dev.jjs.test.CompilerTest$UninstantiableType::field;
+    u.@com.google.gwt.dev.jjs.test.CompilerTest$UninstantiableType::field.toString();
   }-*/;
 
   private static native void accessUninstantiableMethod(UninstantiableType u) /*-{