Author: [EMAIL PROTECTED]
Date: Wed Sep  3 15:30:28 2008
New Revision: 3611

Added:
     
releases/1.5/user/test/com/google/gwt/dev/jjs/test/GenericCastTest.java    
(contents, props changed)
Modified:
     
releases/1.5/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
    releases/1.5/user/test/com/google/gwt/dev/jjs/CompilerSuite.java

Log:
Fixes issue #2835; we now rely on JDT to tell us when to implicitly cast  
the result of a field read or method call.  Before, we were doing it ad-hoc  
and sometimes were performing unnecessary type checks that would cause  
different behavior in web mode than hosted.

Review by: spoon


Modified:  
releases/1.5/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
==============================================================================
---  
releases/1.5/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java      
 
(original)
+++  
releases/1.5/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java      
 
Wed Sep  3 15:30:28 2008
@@ -997,7 +997,6 @@
      JExpression processExpression(FieldReference x) {
        SourceInfo info = makeSourceInfo(x);
        FieldBinding fieldBinding = x.binding;
-      JType type = (JType) typeMap.get(x.resolvedType);
        JField field;
        if (fieldBinding.declaringClass == null) {
          // probably array.length
@@ -1012,11 +1011,15 @@
        JExpression fieldRef = new JFieldRef(program, info, instance, field,
            currentClass);

-      /*
-       * Note, this may result in an invalid AST due to an LHS cast  
operation.
-       * We fix this up in FixAssignmentToUnbox.
-       */
-      return maybeCast(type, fieldRef);
+      if (x.genericCast != null) {
+        JType castType = (JType) typeMap.get(x.genericCast);
+        /*
+         * Note, this may result in an invalid AST due to an LHS cast  
operation.
+         * We fix this up in FixAssignmentToUnbox.
+         */
+        return maybeCast(castType, fieldRef);
+      }
+      return fieldRef;
      }

      JExpression processExpression(InstanceOfExpression x) {
@@ -1028,7 +1031,6 @@

      JExpression processExpression(MessageSend x) {
        SourceInfo info = makeSourceInfo(x);
-      JType type = (JType) typeMap.get(x.resolvedType);
        JMethod method = (JMethod) typeMap.get(x.binding);

        JExpression qualifier;
@@ -1064,7 +1066,11 @@
        // The arguments come first...
        addCallArgs(x.arguments, call, x.binding);

-      return maybeCast(type, call);
+      if (x.valueCast != null) {
+        JType castType = (JType) typeMap.get(x.valueCast);
+        return maybeCast(castType, call);
+      }
+      return call;
      }

      @SuppressWarnings("unused")
@@ -1197,6 +1203,10 @@
        JVariable variable = (JVariable) node;

        JExpression curRef = createVariableRef(info, variable, binding);
+      if (x.genericCast != null) {
+        JType castType = (JType) typeMap.get(x.genericCast);
+        curRef = maybeCast(castType, curRef);
+      }

        /*
         * Wackiness: JDT represents multiple field access as an array of  
fields,
@@ -1204,7 +1214,8 @@
         * otherBindings takes the current expression as a qualifier.
         */
        if (x.otherBindings != null) {
-        for (FieldBinding fieldBinding : x.otherBindings) {
+        for (int i = 0; i < x.otherBindings.length; ++i) {
+          FieldBinding fieldBinding = x.otherBindings[i];
            JField field;
            if (fieldBinding.declaringClass == null) {
              // probably array.length
@@ -1217,6 +1228,10 @@
              field = (JField) typeMap.get(fieldBinding);
            }
            curRef = new JFieldRef(program, info, curRef, field,  
currentClass);
+          if (x.otherGenericCasts != null && x.otherGenericCasts[i] !=  
null) {
+            JType castType = (JType) typeMap.get(x.otherGenericCasts[i]);
+            curRef = maybeCast(castType, curRef);
+          }
          }
        }

@@ -1254,15 +1269,22 @@
         * instance. CreateThisRef should compute a "this" access of the
         * appropriate type, unless the field is static.
         */
+      JExpression result = null;
        if (x.syntheticAccessors != null) {
          JField field = (JField) variable;
          if (!field.isStatic()) {
            JExpression instance = createThisRef(info,  
field.getEnclosingType());
-          return new JFieldRef(program, info, instance, field,  
currentClass);
+          result = new JFieldRef(program, info, instance, field,  
currentClass);
          }
        }
-
-      return createVariableRef(info, variable, binding);
+      if (result == null) {
+        result = createVariableRef(info, variable, binding);
+      }
+      if (x.genericCast != null) {
+        JType castType = (JType) typeMap.get(x.genericCast);
+        result = maybeCast(castType, result);
+      }
+      return result;
      }

      JExpression processExpression(SuperReference x) {

Modified: releases/1.5/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
==============================================================================
--- releases/1.5/user/test/com/google/gwt/dev/jjs/CompilerSuite.java     
(original)
+++ releases/1.5/user/test/com/google/gwt/dev/jjs/CompilerSuite.java    Wed  
Sep  3 15:30:28 2008
@@ -24,6 +24,7 @@
  import com.google.gwt.dev.jjs.test.CoverageTest;
  import com.google.gwt.dev.jjs.test.EnhancedForLoopTest;
  import com.google.gwt.dev.jjs.test.EnumsTest;
+import com.google.gwt.dev.jjs.test.GenericCastTest;
  import com.google.gwt.dev.jjs.test.HostedTest;
  import com.google.gwt.dev.jjs.test.InnerClassTest;
  import com.google.gwt.dev.jjs.test.InnerOuterSuperTest;
@@ -61,6 +62,7 @@
      suite.addTestSuite(CoverageTest.class);
      suite.addTestSuite(EnhancedForLoopTest.class);
      suite.addTestSuite(EnumsTest.class);
+    suite.addTestSuite(GenericCastTest.class);
      suite.addTestSuite(HostedTest.class);
      suite.addTestSuite(InnerClassTest.class);
      suite.addTestSuite(InnerOuterSuperTest.class);

Added:  
releases/1.5/user/test/com/google/gwt/dev/jjs/test/GenericCastTest.java
==============================================================================
--- (empty file)
+++ releases/1.5/user/test/com/google/gwt/dev/jjs/test/GenericCastTest.java     
 
Wed Sep  3 15:30:28 2008
@@ -0,0 +1,267 @@
+/*
+ * 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.dev.jjs.test;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests for appropriate generation of type checks when generic  
methods/fields
+ * are referenced. This is actually testing GenerateJavaAST's appropriate  
use of
+ * maybeCast(). We test such references in so many contexts (field,  
method, as
+ * qualifier, etc) to ensures we cover all the code paths, because JDT has  
a lot
+ * of representation variants with respect to fields (SingleNameReference,
+ * QualifiedNameReference, FieldAccess).
+ */
[EMAIL PROTECTED]("unused")
+public class GenericCastTest extends GWTTestCase {
+
+  /**
+   * Always contains an Object internally, the parameterization is a lie.
+   */
+  static class Liar<T> {
+    @SuppressWarnings("unchecked")
+    public final T value = (T) new Object();
+
+    public T get() {
+      return value;
+    }
+  }
+  static class LiarFoo extends Liar<Foo> {
+    public void testOuterField() {
+      new Runnable() {
+        public void run() {
+          // Should succeed
+          Object a = value;
+
+          try {
+            Foo b = value;
+            fail("Expected ClassCastException 1");
+          } catch (ClassCastException expected) {
+          }
+          try {
+            String s = value.bar;
+            fail("Expected ClassCastException 2");
+          } catch (ClassCastException expected) {
+          }
+          try {
+            String s = value.baz();
+            fail("Expected ClassCastException 3");
+          } catch (ClassCastException expected) {
+          }
+        }
+      }.run();
+    }
+
+    public void testOuterMethod() {
+      new Runnable() {
+        public void run() {
+          // Should succeed
+          Object a = get();
+
+          try {
+            Foo b = get();
+            fail("Expected ClassCastException 1");
+          } catch (ClassCastException expected) {
+          }
+          try {
+            String s = get().bar;
+            fail("Expected ClassCastException 2");
+          } catch (ClassCastException expected) {
+          }
+          try {
+            String s = get().baz();
+            fail("Expected ClassCastException 3");
+          } catch (ClassCastException expected) {
+          }
+        }
+      }.run();
+    }
+
+    public void testSuperField() {
+      // Should succeed
+      Object a = value;
+
+      try {
+        Foo b = value;
+        fail("Expected ClassCastException 1");
+      } catch (ClassCastException expected) {
+      }
+      try {
+        String s = value.bar;
+        fail("Expected ClassCastException 2");
+      } catch (ClassCastException expected) {
+      }
+      try {
+        String s = value.baz();
+        fail("Expected ClassCastException 3");
+      } catch (ClassCastException expected) {
+      }
+    }
+
+    public void testSuperMethod() {
+      // Should succeed
+      Object a = get();
+
+      try {
+        Foo b = get();
+        fail("Expected ClassCastException 1");
+      } catch (ClassCastException expected) {
+      }
+      try {
+        String s = get().bar;
+        fail("Expected ClassCastException 2");
+      } catch (ClassCastException expected) {
+      }
+      try {
+        String s = get().baz();
+        fail("Expected ClassCastException 3");
+      } catch (ClassCastException expected) {
+      }
+    }
+
+    void testInternalAccess() {
+      new Runnable() {
+        public void run() {
+          Object a = get();
+          try {
+            Foo b = get();
+            fail("Expected ClassCastException 5a");
+          } catch (ClassCastException expected) {
+          }
+          try {
+            String s = get().bar;
+            fail("Expected ClassCastException 5b");
+          } catch (ClassCastException expected) {
+          }
+          try {
+            String s = get().baz();
+            fail("Expected ClassCastException 5c");
+          } catch (ClassCastException expected) {
+          }
+
+          Object c = value;
+          try {
+            Foo d = value;
+            fail("Expected ClassCastException 6a");
+          } catch (ClassCastException expected) {
+          }
+          try {
+            String s = value.bar;
+            fail("Expected ClassCastException 6b");
+          } catch (ClassCastException expected) {
+          }
+          try {
+            String s = value.baz();
+            fail("Expected ClassCastException 6c");
+          } catch (ClassCastException expected) {
+          }
+        }
+      }.run();
+    }
+  }
+
+  static class Foo {
+    public String bar = "w00t";
+
+    public String baz() {
+      return bar;
+    }
+  }
+
+  public String getModuleName() {
+    return "com.google.gwt.dev.jjs.CompilerSuite";
+  }
+
+  /**
+   * Test explicit references through a local variable qualifier.
+   */
+  public void testExplicitField() {
+    Liar<Foo> bug = new Liar<Foo>();
+
+    // Should succeed
+    Object a = bug.value;
+
+    try {
+      Foo b = bug.value;
+      fail("Expected ClassCastException 1");
+    } catch (ClassCastException expected) {
+    }
+    try {
+      String s = bug.value.bar;
+      fail("Expected ClassCastException 2");
+    } catch (ClassCastException expected) {
+    }
+    try {
+      String s = bug.value.baz();
+      fail("Expected ClassCastException 3");
+    } catch (ClassCastException expected) {
+    }
+  }
+
+  /**
+   * Test explicit references through a local variable qualifier.
+   */
+  public void testExplicitMethod() {
+    Liar<Foo> bug = new Liar<Foo>();
+
+    // Should succeed
+    Object a = bug.get();
+
+    try {
+      Foo b = bug.get();
+      fail("Expected ClassCastException 1");
+    } catch (ClassCastException expected) {
+    }
+    try {
+      String s = bug.get().bar;
+      fail("Expected ClassCastException 2");
+    } catch (ClassCastException expected) {
+    }
+    try {
+      String s = bug.get().baz();
+      fail("Expected ClassCastException 3");
+    } catch (ClassCastException expected) {
+    }
+  }
+
+  /**
+   * Test implicit references through an outer class.
+   */
+  public void testOuterField() {
+    new LiarFoo().testSuperField();
+  }
+
+  /**
+   * Test implicit references through an outer class.
+   */
+  public void testOuterMethod() {
+    new LiarFoo().testSuperMethod();
+  }
+
+  /**
+   * Test implicit references through a super class.
+   */
+  public void testSuperField() {
+    new LiarFoo().testSuperField();
+  }
+
+  /**
+   * Test implicit references through a super class.
+   */
+  public void testSuperMethod() {
+    new LiarFoo().testSuperMethod();
+  }
+}

--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---

Reply via email to