When tightening method calls, use a more reliable technique to
determine what methods a given method overrides. Use the
override chains determined when JTypeOracle is first built,
rather than trying to compare type signatures of methods.
Review by: scottb
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@3534 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
index ba92608..0d3e6b7 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -135,33 +135,6 @@
return traceMethods.size() > 0;
}
- public static boolean methodsDoMatch(JMethod method1, JMethod method2) {
- // static methods cannot match each other
- if (method1.isStatic() || method2.isStatic()) {
- return false;
- }
-
- // names must be identical
- if (!method1.getName().equals(method2.getName())) {
- return false;
- }
-
- // original parameter types must be identical
- List<JType> params1 = method1.getOriginalParamTypes();
- List<JType> params2 = method2.getOriginalParamTypes();
- int params1size = params1.size();
- if (params1size != params2.size()) {
- return false;
- }
-
- for (int i = 0; i < params1size; ++i) {
- if (params1.get(i) != params2.get(i)) {
- return false;
- }
- }
- return true;
- }
-
private static String dotify(char[][] name) {
StringBuffer result = new StringBuffer();
for (int i = 0; i < name.length; ++i) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
index c822c99..b7774a2 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
@@ -137,6 +137,39 @@
}
}
+ /**
+ * Compare two methods based on name and original argument types
+ * {@link JMethod#getOriginalParamTypes()}. Note that nothing special is done
+ * here regarding methods with type parameters in their argument lists. The
+ * caller must be careful that this level of matching is sufficient.
+ */
+ private static boolean methodsDoMatch(JMethod method1, JMethod method2) {
+ // static methods cannot match each other
+ if (method1.isStatic() || method2.isStatic()) {
+ return false;
+ }
+
+ // names must be identical
+ if (!method1.getName().equals(method2.getName())) {
+ return false;
+ }
+
+ // original parameter types must be identical
+ List<JType> params1 = method1.getOriginalParamTypes();
+ List<JType> params2 = method2.getOriginalParamTypes();
+ int params1size = params1.size();
+ if (params1size != params2.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < params1size; ++i) {
+ if (params1.get(i) != params2.get(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private final Map<JInterfaceType, Set<JClassType>> couldBeImplementedMap = new IdentityHashMap<JInterfaceType, Set<JClassType>>();
private final Map<JClassType, Set<JInterfaceType>> couldImplementMap = new IdentityHashMap<JClassType, Set<JInterfaceType>>();
@@ -573,7 +606,7 @@
private void computeVirtualUpRefs(JClassType type, JInterfaceType intf) {
outer : for (JMethod intfMethod : intf.methods) {
for (JMethod classMethod : type.methods) {
- if (JProgram.methodsDoMatch(intfMethod, classMethod)) {
+ if (methodsDoMatch(intfMethod, classMethod)) {
// this class directly implements the interface method
continue outer;
}
@@ -583,7 +616,7 @@
// if any super classes do, create a virtual up ref
for (JClassType superType = type.extnds; superType != javaLangObject; superType = superType.extnds) {
for (JMethod superMethod : superType.methods) {
- if (JProgram.methodsDoMatch(intfMethod, superMethod)) {
+ if (methodsDoMatch(intfMethod, superMethod)) {
// this super class directly implements the interface method
// create a virtual up ref
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodCallTightener.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodCallTightener.java
index df16a0e..3a33dcd 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodCallTightener.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodCallTightener.java
@@ -44,7 +44,7 @@
*/
public class MethodCallTighteningVisitor extends JModVisitor {
- // @Override
+ @Override
public void endVisit(JMethodCall x, Context ctx) {
JMethod method = x.getTarget();
JExpression instance = x.getInstance();
@@ -86,7 +86,7 @@
&& type != enclosingType; type = type.extnds) {
for (int i = 0; i < type.methods.size(); ++i) {
JMethod methodIt = type.methods.get(i);
- if (JProgram.methodsDoMatch(method, methodIt)) {
+ if (methodOverrides(methodIt, method)) {
foundMethod = methodIt;
break outer;
}
@@ -106,6 +106,31 @@
call.getArgs().addAll(x.getArgs());
ctx.replaceMe(call);
}
+
+ /**
+ * Check whether <code>subMethod</code> overrides <code>supMethod</code>.
+ * For the purposes of this method, indirect overrides are considered
+ * overrides. For example, if method A.m overrides B.m, and B.m overrides
+ * C.m, then A.m is considered to override C.m. Additionally, implementing
+ * an interface is considered
+ * <q>overriding</q>
+ * for the purposes of this method.
+ *
+ */
+ private boolean methodOverrides(JMethod subMethod, JMethod supMethod) {
+ if (subMethod.params.size() != supMethod.params.size()) {
+ // short cut: check the number of parameters
+ return false;
+ }
+
+ if (!subMethod.getName().equals(supMethod.getName())) {
+ // short cut: check the method names
+ return false;
+ }
+
+ // long way: get all overrides and see if supMethod is included
+ return program.typeOracle.getAllOverrides(subMethod).contains(supMethod);
+ }
}
public static boolean exec(JProgram program) {