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
-~----------~----~----~----~------~----~------~--~---