Bug 1186517 - Fix SDKProcessor API version detection; r=snorp
authorJim Chen <nchen@mozilla.com>
Wed, 29 Jul 2015 15:11:15 -0400
changeset 281604 86ca0d45483df9231d18c0cad291ce9e8a7e3461
parent 281603 0229401cfa6940f5f659059386dbcda986873024
child 281605 1717cd1f2d95c0dde88dc7c5fdb1650ba7ee9732
push id3894
push usermconley@mozilla.com
push dateThu, 30 Jul 2015 00:27:47 +0000
reviewerssnorp
bugs1186517
milestone42.0a1
Bug 1186517 - Fix SDKProcessor API version detection; r=snorp The API version detection functionality was broken in SDKProcessor because we were passing in "Lpackage/Class;" as the class name rather than just "package/Class". Also, some classes have a weird situation where some methods were moved around in later API versions. For example, some put* and get* methods in Bundle were moved to BaseBundle in API 21. If we only checked BaseBundle.put*, we would think they are API 21+ only. The workaround is to check both the top-level class and the declaring class for a member, and choose the lower API level as the minimal API level for that member. This patch also fixes bugs in including the right class members. For SDKProcessor we want to include all public members of a class, including inherited members, because the private/protected members are not part of the public API. For AnnotationProcessor, we want to include all the members declared in that class, including private and protected members, because we may want to access private/protected members of our own Java classes from C++.
build/annotationProcessors/SDKProcessor.java
build/annotationProcessors/utils/GeneratableElementIterator.java
--- a/build/annotationProcessors/SDKProcessor.java
+++ b/build/annotationProcessors/SDKProcessor.java
@@ -120,40 +120,47 @@ public class SDKProcessor {
                 "} /* mozilla */\n" +
                 "#endif\n");
 
         writeOutputFiles(outdir, generatedFilePrefix, headerFile, implementationFile);
         long e = System.currentTimeMillis();
         System.out.println("SDK processing complete in " + (e - s) + "ms");
     }
 
-    private static Member[] sortAndFilterMembers(Member[] members) {
+    private static int getAPIVersion(Class<?> cls, Member m) {
+        if (m instanceof Method || m instanceof Constructor) {
+            return sApiLookup.getCallVersion(
+                    cls.getName().replace('.', '/'),
+                    Utils.getMemberName(m),
+                    Utils.getSignature(m));
+        } else if (m instanceof Field) {
+            return sApiLookup.getFieldVersion(
+                    Utils.getClassDescriptor(m.getDeclaringClass()), m.getName());
+        } else {
+            throw new IllegalArgumentException("expected member to be Method, Constructor, or Field");
+        }
+    }
+
+    private static Member[] sortAndFilterMembers(Class<?> cls, Member[] members) {
         Arrays.sort(members, new Comparator<Member>() {
             @Override
             public int compare(Member a, Member b) {
                 return a.getName().compareTo(b.getName());
             }
         });
 
         ArrayList<Member> list = new ArrayList<>();
         for (Member m : members) {
-            int version = 0;
-
-            if (m instanceof Method || m instanceof Constructor) {
-                version = sApiLookup.getCallVersion(
-                        Utils.getClassDescriptor(m.getDeclaringClass()),
-                        m.getName(),
-                        Utils.getSignature(m));
-            } else if (m instanceof Field) {
-                version = sApiLookup.getFieldVersion(
-                        Utils.getClassDescriptor(m.getDeclaringClass()), m.getName());
-            } else {
-                throw new IllegalArgumentException("expected member to be Method, Constructor, or Field");
+            // Sometimes (e.g. Bundle) has methods that moved to/from a superclass in a later SDK
+            // version, so we check for both classes and see if we can find a minimum SDK version.
+            int version = getAPIVersion(cls, m);
+            final int version2 = getAPIVersion(m.getDeclaringClass(), m);
+            if (version2 > 0 && version2 < version) {
+                version = version2;
             }
-
             if (version > sMaxSdkVersion) {
                 System.out.println("Skipping " + m.getDeclaringClass().getName() + "." + m.getName() +
                     ", version " + version + " > " + sMaxSdkVersion);
                 continue;
             }
 
             list.add(m);
         }
@@ -163,19 +170,19 @@ public class SDKProcessor {
 
     private static void generateClass(Class<?> clazz,
                                       StringBuilder implementationFile,
                                       StringBuilder headerFile) {
         String generatedName = clazz.getSimpleName();
 
         CodeGenerator generator = new CodeGenerator(new ClassWithOptions(clazz, generatedName));
 
-        generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredConstructors()));
-        generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredMethods()));
-        generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredFields()));
+        generator.generateMembers(sortAndFilterMembers(clazz, clazz.getConstructors()));
+        generator.generateMembers(sortAndFilterMembers(clazz, clazz.getMethods()));
+        generator.generateMembers(sortAndFilterMembers(clazz, clazz.getFields()));
 
         headerFile.append(generator.getHeaderFileContents());
         implementationFile.append(generator.getWrapperFileContents());
     }
 
     private static Vector<String> getClassList(String path) {
         Scanner scanner = null;
         try {
--- a/build/annotationProcessors/utils/GeneratableElementIterator.java
+++ b/build/annotationProcessors/utils/GeneratableElementIterator.java
@@ -26,17 +26,17 @@ public class GeneratableElementIterator 
     private int mElementIndex;
 
     private boolean mIterateEveryEntry;
 
     public GeneratableElementIterator(Class<?> aClass) {
         // Get all the elements of this class as AccessibleObjects.
         Member[] aMethods = aClass.getDeclaredMethods();
         Member[] aFields = aClass.getDeclaredFields();
-        Member[] aCtors = aClass.getConstructors();
+        Member[] aCtors = aClass.getDeclaredConstructors();
 
         // Shove them all into one buffer.
         Member[] objs = new Member[aMethods.length + aFields.length + aCtors.length];
 
         int offset = 0;
         System.arraycopy(aMethods, 0, objs, 0, aMethods.length);
         offset += aMethods.length;
         System.arraycopy(aFields, 0, objs, offset, aFields.length);