Bug 1086693 - Part 3: Don't generate members that are above a given API version. r=ckitching, a=lsblakk
authorJames Willcox <snorp@snorp.net>
Tue, 18 Nov 2014 17:28:47 -0600
changeset 227356 0b896cfeb63af81f50e93193c44d783a7e1a863a
parent 227355 6a35dcdb17d6e080d1349d0aabe16cd41d1cf517
child 227357 e8970c0331bb9faf3744f39611c3c93d53321a64
push id583
push userbhearsum@mozilla.com
push dateMon, 24 Nov 2014 19:04:58 +0000
treeherdermozilla-release@c107e74250f4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersckitching, lsblakk
bugs1086693
milestone34.0
Bug 1086693 - Part 3: Don't generate members that are above a given API version. r=ckitching, a=lsblakk
build/annotationProcessors/CodeGenerator.java
build/annotationProcessors/Makefile.in
build/annotationProcessors/SDKProcessor.java
build/annotationProcessors/utils/Utils.java
widget/android/bindings/Makefile.in
--- a/build/annotationProcessors/CodeGenerator.java
+++ b/build/annotationProcessors/CodeGenerator.java
@@ -247,16 +247,18 @@ public class CodeGenerator {
             AnnotationInfo info = new AnnotationInfo(name, true, true, true);
             AnnotatableEntity entity = new AnnotatableEntity(m, info);
             if (m instanceof Constructor) {
                 generateConstructor(entity);
             } else if (m instanceof Method) {
                 generateMethod(entity);
             } else if (m instanceof Field) {
                 generateField(entity);
+            } else {
+                throw new IllegalArgumentException("expected member to be Constructor, Method, or Field");
             }
         }
     }
 
     /**
      * Writes the appropriate header and startup code to ensure the existence of a reference to the
      * class specified. If this is already done, does nothing.
      *
--- a/build/annotationProcessors/Makefile.in
+++ b/build/annotationProcessors/Makefile.in
@@ -1,12 +1,12 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 include $(topsrcdir)/config/rules.mk
 
-JAVA_CLASSPATH := $(ANDROID_SDK)/android.jar
+JAVA_CLASSPATH := $(ANDROID_SDK)/android.jar:$(ANDROID_SDK)/../../tools/lib/lint.jar:$(ANDROID_SDK)/../../tools/lib/lint-checks.jar
 
 # Include Android specific java flags, instead of what's in rules.mk.
 include $(topsrcdir)/config/android-common.mk
 
 export:: annotationProcessors.jar
--- a/build/annotationProcessors/SDKProcessor.java
+++ b/build/annotationProcessors/SDKProcessor.java
@@ -1,26 +1,32 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.annotationProcessors;
 
+import com.android.tools.lint.checks.ApiLookup;
+import com.android.tools.lint.LintCliClient;
+
 import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
 import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
 import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader;
 import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator;
+import org.mozilla.gecko.annotationProcessors.utils.Utils;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.Iterator;
+import java.util.Properties;
 import java.util.Scanner;
 import java.util.Vector;
 import java.net.URL;
 import java.net.URLClassLoader;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Member;
@@ -29,29 +35,40 @@ import java.lang.reflect.Modifier;
 
 public class SDKProcessor {
     public static final String GENERATED_COMMENT =
             "// GENERATED CODE\n" +
             "// Generated by the Java program at /build/annotationProcessors at compile time from\n" +
             "// annotations on Java methods. To update, change the annotations on the corresponding Java\n" +
             "// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n";
 
+    private static ApiLookup sApiLookup;
+    private static int sMaxSdkVersion;
+
     public static void main(String[] args) {
         // We expect a list of jars on the commandline. If missing, whinge about it.
-        if (args.length < 4) {
-            System.err.println("Usage: java SDKProcessor sdkjar classlistfile outdir fileprefix");
+        if (args.length < 5) {
+            System.err.println("Usage: java SDKProcessor sdkjar classlistfile outdir fileprefix max-sdk-version");
             System.exit(1);
         }
 
         System.out.println("Processing platform bindings...");
 
         String sdkJar = args[0];
         Vector classes = getClassList(args[1]);
         String outdir = args[2];
         String generatedFilePrefix = args[3];
+        sMaxSdkVersion = Integer.parseInt(args[4]);
+
+        Properties props = System.getProperties();
+        props.setProperty("com.android.tools.lint.bindir",
+            new File(new File(sdkJar).getParentFile(), "../../tools").toString());
+
+        LintCliClient lintClient = new LintCliClient();
+        sApiLookup = ApiLookup.get(lintClient);
 
         // Start the clock!
         long s = System.currentTimeMillis();
 
         // Get an iterator over the classes in the jar files given...
         // Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
 
         StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
@@ -120,39 +137,63 @@ 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[] sortMembers(Member[] members) {
+    private static Member[] sortAndFilterMembers(Member[] members) {
         Arrays.sort(members, new Comparator<Member>() {
             @Override
             public int compare(Member a, Member b) {
                 return a.getName().compareTo(b.getName());
             }
         });
 
-        return members;
+        ArrayList<Member> list = new ArrayList<>();
+        for (Member m : members) {
+            int version = 0;
+
+            if (m instanceof Method || m instanceof Constructor) {
+                version = sApiLookup.getCallVersion(Utils.getTypeSignatureStringForClass(m.getDeclaringClass()),
+                                                    m.getName(),
+                                                    Utils.getTypeSignatureStringForMember(m));
+            } else if (m instanceof Field) {
+                version = sApiLookup.getFieldVersion(Utils.getTypeSignatureStringForClass(m.getDeclaringClass()),
+                                                     m.getName());
+            } else {
+                throw new IllegalArgumentException("expected member to be Method, Constructor, or Field");
+            }
+
+            if (version > sMaxSdkVersion) {
+                System.out.println("Skipping " + m.getDeclaringClass().getName() + "." + m.getName() +
+                    ", version " + version + " > " + sMaxSdkVersion);
+                continue;
+            }
+
+            list.add(m);
+        }
+
+        return list.toArray(new Member[list.size()]);
     }
 
     private static void generateClass(Class<?> clazz,
                                       StringBuilder stubInitializer,
                                       StringBuilder implementationFile,
                                       StringBuilder headerFile) {
         String generatedName = clazz.getSimpleName();
 
         CodeGenerator generator = new CodeGenerator(clazz, generatedName);
         stubInitializer.append("    ").append(generatedName).append("::InitStubs(jEnv);\n");
 
-        generator.generateMembers(sortMembers(clazz.getDeclaredConstructors()));
-        generator.generateMembers(sortMembers(clazz.getDeclaredMethods()));
-        generator.generateMembers(sortMembers(clazz.getDeclaredFields()));
+        generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredConstructors()));
+        generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredMethods()));
+        generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredFields()));
 
         headerFile.append(generator.getHeaderFileContents());
         implementationFile.append(generator.getWrapperFileContents());
     }
 
     private static Vector<String> getClassList(String path) {
         Scanner scanner = null;
         try {
--- a/build/annotationProcessors/utils/Utils.java
+++ b/build/annotationProcessors/utils/Utils.java
@@ -313,16 +313,20 @@ public class Utils {
             return getTypeSignatureStringForMethod((Method) aMember);
         } else if (aMember instanceof Field) {
             return getTypeSignatureStringForField((Field) aMember);
         } else {
             return getTypeSignatureStringForConstructor((Constructor<?>) aMember);
         }
     }
 
+    public static String getTypeSignatureStringForClass(Class<?> clazz) {
+        return clazz.getCanonicalName().replace('.', '/');
+    }
+
     public static String getTypeSignatureString(Constructor<?> aConstructor) {
         Class<?>[] arguments = aConstructor.getParameterTypes();
         StringBuilder sb = new StringBuilder();
         sb.append('(');
 
         // For each argument, write its signature component to the buffer..
         for (int i = 0; i < arguments.length; i++) {
             writeTypeSignature(sb, arguments[i]);
@@ -336,17 +340,17 @@ public class Utils {
     /**
      * Helper method used by getTypeSignatureStringForMethod to build the signature. Write the subsignature
      * of a given type into the buffer.
      *
      * @param sb The buffer to write into.
      * @param c  The type of the element to write the subsignature of.
      */
     private static void writeTypeSignature(StringBuilder sb, Class<?> c) {
-        String name = c.getCanonicalName().replaceAll("\\.", "/");
+        String name = Utils.getTypeSignatureStringForClass(c);
 
         // Determine if this is an array type and, if so, peel away the array operators..
         int len = name.length();
         while (name.endsWith("[]")) {
             sb.append('[');
             name = name.substring(0, len - 2);
             len = len - 2;
         }
@@ -584,17 +588,17 @@ public class Utils {
      * @return The generated code to populate the reference to the class.
      */
     public static String getStartupLineForClass(Class<?> aClass) {
         StringBuilder sb = new StringBuilder();
         sb.append("    ");
         sb.append(getClassReferenceName(aClass));
         sb.append(" = getClassGlobalRef(\"");
 
-        String name = aClass.getCanonicalName().replaceAll("\\.", "/");
+        String name = Utils.getTypeSignatureStringForClass(aClass);
         Class<?> containerClass = aClass.getDeclaringClass();
         if (containerClass != null) {
             // Is an inner class. Add the $ symbol.
             final int lastSlash = name.lastIndexOf('/');
             name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1);
         }
 
         sb.append(name);
--- a/widget/android/bindings/Makefile.in
+++ b/widget/android/bindings/Makefile.in
@@ -1,21 +1,21 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-annotation_processor_jar_files := $(DEPTH)/build/annotationProcessors/annotationProcessors.jar
+annotation_processor_jar_files := $(DEPTH)/build/annotationProcessors/annotationProcessors.jar:$(ANDROID_SDK)/../../tools/lib/lint.jar:$(ANDROID_SDK)/../../tools/lib/lint-checks.jar
 
 MediaCodec.cpp: $(ANDROID_SDK)/android.jar mediacodec-classes.txt
-	$(JAVA) -classpath $(annotation_processor_jar_files) org.mozilla.gecko.annotationProcessors.SDKProcessor $(ANDROID_SDK)/android.jar $(srcdir)/mediacodec-classes.txt $(CURDIR) MediaCodec
+	$(JAVA) -classpath $(annotation_processor_jar_files) org.mozilla.gecko.annotationProcessors.SDKProcessor $(ANDROID_SDK)/android.jar $(srcdir)/mediacodec-classes.txt $(CURDIR) MediaCodec 16
 
 MediaCodec.h: MediaCodec.cpp
 
 SurfaceTexture.cpp: $(ANDROID_SDK)/android.jar surfacetexture-classes.txt
-	$(JAVA) -classpath $(annotation_processor_jar_files) org.mozilla.gecko.annotationProcessors.SDKProcessor $(ANDROID_SDK)/android.jar $(srcdir)/surfacetexture-classes.txt $(CURDIR) SurfaceTexture
+	$(JAVA) -classpath $(annotation_processor_jar_files) org.mozilla.gecko.annotationProcessors.SDKProcessor $(ANDROID_SDK)/android.jar $(srcdir)/surfacetexture-classes.txt $(CURDIR) SurfaceTexture 16
 
 SurfaceTexture.h: SurfaceTexture.cpp
 
 # We'd like these to be defined in a future GENERATED_EXPORTS list.
 bindings_exports_FILES := \
   MediaCodec.h \
   SurfaceTexture.h \
   $(NULL)