Merge 1.5 branch changes.
$ svn merge -r 3587:HEAD https://google-web-toolkit.googlecode.com/svn/releases/1.5
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@3630 8db76d5a-ed1c-0410-87a9-c151d255dfc7
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 b284fad..b3f3b9a 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
@@ -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) {
diff --git a/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java b/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java
index a17dbc4..9b1cbfe 100644
--- a/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java
+++ b/dev/core/src/com/google/gwt/dev/shell/DispatchClassInfo.java
@@ -63,11 +63,12 @@
}
private void addMember(Member member, String sig) {
- if (!memberIdByName.containsKey(sig)) {
- memberById.add(member);
- int index = memberById.size() - 1;
- memberIdByName.put(sig, new Integer(index));
+ if (member.isSynthetic()) {
+ return;
}
+ int index = memberById.size();
+ memberById.add(member);
+ memberIdByName.put(sig, index);
}
private String getJsniSignature(Member member) {
@@ -148,7 +149,8 @@
private void lazyInitTargetMembersUsingReflectionHelper(Class<?> targetClass,
boolean addConstructors) {
- // Start by analyzing the superclass recursively.
+ // Start by analyzing the superclass recursively; the concrete class will
+ // clobber on overrides.
Class<?> superclass = targetClass.getSuperclass();
if (superclass != null) {
lazyInitTargetMembersUsingReflectionHelper(superclass, false);
@@ -158,11 +160,10 @@
}
if (addConstructors) {
- Constructor<?>[] constructors = targetClass.getDeclaredConstructors();
- for (Constructor<?> c : constructors) {
- c.setAccessible(true);
- String sig = getJsniSignature(c);
- addMember(c, sig);
+ for (Constructor<?> ctor : targetClass.getDeclaredConstructors()) {
+ ctor.setAccessible(true);
+ String sig = getJsniSignature(ctor);
+ addMember(ctor, sig);
}
}
@@ -180,19 +181,17 @@
*/
// Get the methods on this class/interface.
- //
- Method[] methods = targetClass.getDeclaredMethods();
- for (int i = 0; i < methods.length; i++) {
- methods[i].setAccessible(true);
- String sig = getJsniSignature(methods[i]);
- addMember(methods[i], sig);
+ for (Method method : targetClass.getDeclaredMethods()) {
+ method.setAccessible(true);
+ String sig = getJsniSignature(method);
+ addMember(method, sig);
}
// Get the fields on this class/interface.
Field[] fields = targetClass.getDeclaredFields();
- for (int i = 0; i < fields.length; i++) {
- fields[i].setAccessible(true);
- addMember(fields[i], fields[i].getName());
+ for (Field field : fields) {
+ field.setAccessible(true);
+ addMember(field, field.getName());
}
}
}
diff --git a/distro-source/core/src/release_notes.html b/distro-source/core/src/release_notes.html
index ee3896a..37721ff 100644
--- a/distro-source/core/src/release_notes.html
+++ b/distro-source/core/src/release_notes.html
@@ -66,7 +66,7 @@
</ul>
<p>
See the GWT issue tracker for
- <a href="http://code.google.com/p/google-web-toolkit/issues/list?can=1&q=status%3AFixed%2CFixedNotReleased%20milestone%3A1_5_Final%20type%3Adefect&num=1000">
+ <a href="http://code.google.com/p/google-web-toolkit/issues/list?can=1&q=status%3AFixed%2CFixedNotReleased%20milestone%3A1_5_Final&num=1000">
the complete list of bug fixes and enhancements</a> in this release.
</p>
diff --git a/user/super/com/google/gwt/emul/java/lang/Integer.java b/user/super/com/google/gwt/emul/java/lang/Integer.java
index 28e57ee..6a4c1ad 100644
--- a/user/super/com/google/gwt/emul/java/lang/Integer.java
+++ b/user/super/com/google/gwt/emul/java/lang/Integer.java
@@ -184,19 +184,20 @@
final int bufSize = 33;
char[] buf = new char[bufSize];
+ char[] digits = __Digits.digits;
int pos = bufSize - 1;
if (value >= 0) {
while (value >= radix) {
- buf[pos--] = __Digits.digits[value % radix];
+ buf[pos--] = digits[value % radix];
value /= radix;
}
- buf[pos] = __Digits.digits[value];
+ buf[pos] = digits[value];
} else {
while (value <= -radix) {
- buf[pos--] = __Digits.digits[-(value % radix)];
+ buf[pos--] = digits[-(value % radix)];
value /= radix;
}
- buf[pos--] = __Digits.digits[-value];
+ buf[pos--] = digits[-value];
buf[pos] = '-';
}
return String.__valueOf(buf, pos, bufSize);
@@ -227,19 +228,20 @@
final int bufSize = 32 / shift;
int bitMask = (1 << shift) - 1;
char[] buf = new char[bufSize];
+ char[] digits = __Digits.digits;
int pos = bufSize - 1;
if (value >= 0) {
while (value > bitMask) {
- buf[pos--] = __Digits.digits[value & bitMask];
+ buf[pos--] = digits[value & bitMask];
value >>= shift;
}
} else {
while (pos > 0) {
- buf[pos--] = __Digits.digits[value & bitMask];
+ buf[pos--] = digits[value & bitMask];
value >>= shift;
}
}
- buf[pos] = __Digits.digits[value & bitMask];
+ buf[pos] = digits[value & bitMask];
return String.__valueOf(buf, pos, bufSize);
}
diff --git a/user/super/com/google/gwt/emul/java/lang/Long.java b/user/super/com/google/gwt/emul/java/lang/Long.java
index fb7f338..d544038 100644
--- a/user/super/com/google/gwt/emul/java/lang/Long.java
+++ b/user/super/com/google/gwt/emul/java/lang/Long.java
@@ -225,21 +225,22 @@
final int bufSize = 65;
char[] buf = new char[bufSize];
+ char[] digits = __Digits.digits;
int pos = bufSize - 1;
// Cache a converted version for performance (pure long ops are faster).
long radix = intRadix;
if (value >= 0) {
while (value >= radix) {
- buf[pos--] = __Digits.digits[(int) (value % radix)];
+ buf[pos--] = digits[(int) (value % radix)];
value /= radix;
}
- buf[pos] = __Digits.digits[(int) value];
+ buf[pos] = digits[(int) value];
} else {
while (value <= -radix) {
- buf[pos--] = __Digits.digits[(int) -(value % radix)];
+ buf[pos--] = digits[(int) -(value % radix)];
value /= radix;
}
- buf[pos--] = __Digits.digits[(int) -value];
+ buf[pos--] = digits[(int) -value];
buf[pos] = '-';
}
return String.__valueOf(buf, pos, bufSize);
@@ -292,19 +293,20 @@
final int bufSize = 64 / shift;
long bitMask = (1 << shift) - 1;
char[] buf = new char[bufSize];
+ char[] digits = __Digits.digits;
int pos = bufSize - 1;
if (value >= 0) {
while (value > bitMask) {
- buf[pos--] = __Digits.digits[(int) (value & bitMask)];
+ buf[pos--] = digits[(int) (value & bitMask)];
value >>= shift;
}
} else {
while (pos > 0) {
- buf[pos--] = __Digits.digits[(int) (value & bitMask)];
+ buf[pos--] = digits[(int) (value & bitMask)];
value >>= shift;
}
}
- buf[pos] = __Digits.digits[(int) (value & bitMask)];
+ buf[pos] = digits[(int) (value & bitMask)];
return String.__valueOf(buf, pos, bufSize);
}
diff --git a/user/test/com/google/gwt/dev/jjs/CompilerSuite.java b/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
index 79e0b26..b079d19 100644
--- a/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
+++ b/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
@@ -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;
@@ -62,6 +63,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);
diff --git a/user/test/com/google/gwt/dev/jjs/test/GenericCastTest.java b/user/test/com/google/gwt/dev/jjs/test/GenericCastTest.java
new file mode 100644
index 0000000..228c759
--- /dev/null
+++ b/user/test/com/google/gwt/dev/jjs/test/GenericCastTest.java
@@ -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).
+ */
+@SuppressWarnings("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();
+ }
+}