Skip to content

Commit

Permalink
Fix bug #8112: don't special case Comparable and Comparator methods a…
Browse files Browse the repository at this point in the history
…nymore.

Before this fix, Comparable.compareTo(Object) and
Comparator.compare(Object,Object) are specially removed and hence only
generic-bound compare() remained in Mono.Android.dll. This resulted in a
side effect that is bug #8112 - when generic information was unavailable,
it still removed Object-based compareTo() and compare(), which were the only
one implementation and resulted in missing method error.

This fix changes the way to lookup methods to save in API XML; only
"really-declared" methods remain. For generic methods JRE automatically
adds overloads for those methods with Object. We now skip them (which
gives consistent output with AOSP XML).
  • Loading branch information
Atsushi Eno committed Nov 6, 2012
1 parent 3a7c404 commit 72a6be6
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 27 deletions.
48 changes: 33 additions & 15 deletions JavaClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,17 @@ else if (tc instanceof TypeVariable<?>)
}

String getSignature (Method method)
{
StringBuffer sig = new StringBuffer ();
sig.append (method.getName ());
for (Class t : method.getParameterTypes ()) {
sig.append (":");
sig.append (t.getName ());
}
return sig.toString ();
}

String getGenericSignature (Method method)
{
StringBuffer sig = new StringBuffer ();
sig.append (method.getName ());
Expand Down Expand Up @@ -461,6 +472,20 @@ public void appendToDocument (Document doc, Element parent)
}
}

Comparator clscmp = new Comparator<Class> () {
public int compare (Class c1, Class c2) {
return c1.getName ().compareTo (c2.getName ());
}
};

boolean isInPublicInheritanceChain (Class cls)
{
for (Class c = cls; c != null; c = c.getSuperclass ())
if ((c.getModifiers () & Modifier.PUBLIC) == 0)
return false;
return true;
}

void doAppendToDocument (Document doc, Element parent)
{
int mods = jclass.getModifiers ();
Expand Down Expand Up @@ -519,6 +544,13 @@ else if (iface instanceof ParameterizedType) {
Class base_class = jclass.getSuperclass ();
Map<String, Method> methods = new HashMap <String, Method> ();
for (Method method : jclass.getDeclaredMethods ()) {
// Skip "synthetic" methods that is automatically supplied by JRE.
// But there is an exception scenario: if the class is derived from non-public class,
// don't do that - it results in excessive removal.
// e.g. in libcore/luni, StringBuilder inherits non-public AbstractStringBuilder.
if (method.isSynthetic () && isInPublicInheritanceChain (jclass))
continue;

int mmods = method.getModifiers ();

/*
Expand Down Expand Up @@ -569,22 +601,8 @@ else if (iface instanceof ParameterizedType) {
}
}
}

Comparator clscmp = new Comparator<Class> () {
public int compare (Class c1, Class c2) {
return c1.getName ().compareTo (c2.getName ());
}
};

// These special rules are required to filter out incorrectly returned compareTo(Object) Comparable<T> implementation (maybe it is due to "erased generics").
if (Arrays.binarySearch (jclass.getInterfaces (), Comparable.class, clscmp) >= 0 && method.getName ().equals ("compareTo") && ptypes [0].equals (Object.class)
// IF this worked in Java ... <code>if (... && ptypes [0] != jclass.GetGenericArguments () [0])</code>
&& !jclass.equals (java.io.ObjectStreamField.class))
continue;
if (Arrays.binarySearch (jclass.getInterfaces (), Comparator.class, clscmp) >= 0 && method.getName ().equals ("compare") && ptypes.length == 2 && ptypes [0].equals (Object.class) && ptypes [1].equals (Object.class))
continue;

String key = getSignature (method);
String key = getGenericSignature (method);
if (methods.containsKey (key)) {
Type method_type = method.getGenericReturnType ();
Method hashed = methods.get (key);
Expand Down
12 changes: 0 additions & 12 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -308,15 +308,3 @@ Now we use ASM to solve the issues below:

android.view.MotionEvent.getSource() is also missing.
</maybe-historical>

** Erased generic issues

<workarounded>
- extraneous "CompareTo(Object)" method
- e.g. android.net.Uri, java.util.Calendar, java.util.Date, java.util.UUID, java.nio.Charset and so on.
- They implement Comparable<T> and since either <T> went away in
android.jar or jar2xml ignores generic type arguments and treats T
arg as Object, this extra method is returned.
- similarly, Comparator<T> brings extra Compare(Object, Object) overloads.

</workarounded>

0 comments on commit 72a6be6

Please sign in to comment.