[ApiModel] Remove api object database tests
Change-Id: Ib3ab63255520ac95111699ecda0154a34ed10439
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderTemplate.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderTemplate.java
deleted file mode 100644
index 4b21f6e..0000000
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseBuilderTemplate.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.apimodel;
-
-import com.android.tools.r8.androidapi.AndroidApiClass;
-import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.utils.DescriptorUtils;
-import java.util.function.Consumer;
-
-/** This is a template for generating the AndroidApiDatabaseBuilder. */
-public class AndroidApiDatabaseBuilderTemplate /* AndroidApiDatabaseBuilder */ {
-
- public static void visitApiClasses(Consumer<String> classDescriptorConsumer) {
- // Code added dynamically in AndroidApiDatabaseBuilderGenerator.
- placeHolderForVisitApiClasses();
- }
-
- public static AndroidApiClass buildClass(ClassReference classReference) {
- String descriptor = classReference.getDescriptor();
- String packageName = DescriptorUtils.getPackageNameFromDescriptor(descriptor);
- String simpleClassName = DescriptorUtils.getSimpleClassNameFromDescriptor(descriptor);
- // Code added dynamically in AndroidApiDatabaseBuilderGenerator.
- placeHolderForBuildClass();
- return null;
- }
-
- private static void placeHolderForVisitApiClasses() {}
-
- private static void placeHolderForBuildClass() {}
-}
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseClassTemplate.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseClassTemplate.java
deleted file mode 100644
index 1a8b7e3..0000000
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabaseClassTemplate.java
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.apimodel;
-
-import com.android.tools.r8.androidapi.AndroidApiClass;
-import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.FieldReference;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.TraversalContinuation;
-import java.util.function.BiFunction;
-
-/** This is a template for generating AndroidApiDatabaseClass extending AndroidApiClass */
-public class AndroidApiDatabaseClassTemplate extends AndroidApiClass {
-
- protected AndroidApiDatabaseClassTemplate() {
- // Code added dynamically in AndroidApiDatabaseBuilderGenerator.
- super(Reference.classFromDescriptor(placeHolderForInit()));
- }
-
- @Override
- public AndroidApiLevel getApiLevel() {
- // Code added dynamically in AndroidApiDatabaseBuilderGenerator.
- return placeHolderForGetApiLevel();
- }
-
- @Override
- public int getMemberCount() {
- // Code added dynamically in AndroidApiDatabaseBuilderGenerator.
- return placeHolderForGetMemberCount();
- }
-
- @Override
- public TraversalContinuation visitFields(
- BiFunction<FieldReference, AndroidApiLevel, TraversalContinuation> visitor,
- ClassReference holder,
- int minApi) {
- // Code added dynamically in AndroidApiDatabaseBuilderGenerator.
- placeHolderForVisitFields();
- return TraversalContinuation.CONTINUE;
- }
-
- @Override
- public TraversalContinuation visitMethods(
- BiFunction<MethodReference, AndroidApiLevel, TraversalContinuation> visitor,
- ClassReference holder,
- int minApi) {
- // Code added dynamically in AndroidApiDatabaseBuilderGenerator.
- placeHolderForVisitMethods();
- return TraversalContinuation.CONTINUE;
- }
-
- private static String placeHolderForInit() {
- return null;
- }
-
- private static AndroidApiLevel placeHolderForGetApiLevel() {
- return null;
- }
-
- private static int placeHolderForGetMemberCount() {
- return 0;
- }
-
- private static void placeHolderForVisitFields() {}
-
- private static void placeHolderForVisitMethods() {}
-}
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabasePackageTemplate.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabasePackageTemplate.java
deleted file mode 100644
index 3919d11..0000000
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiDatabasePackageTemplate.java
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.apimodel;
-
-import com.android.tools.r8.androidapi.AndroidApiClass;
-
-/** This is a template for generating the AndroidApiDatabasePackage. */
-public class AndroidApiDatabasePackageTemplate {
-
- public static AndroidApiClass buildClass(String className) {
- // Code added dynamically in AndroidApiDatabaseBuilderGenerator.
- placeHolder();
- return null;
- }
-
- private static void placeHolder() {}
-}
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiObjectDatabaseBuilderGenerator.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiObjectDatabaseBuilderGenerator.java
deleted file mode 100644
index c8b6c24..0000000
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiObjectDatabaseBuilderGenerator.java
+++ /dev/null
@@ -1,593 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.apimodel;
-
-import static com.android.tools.r8.utils.FunctionUtils.ignoreArgument;
-import static org.objectweb.asm.Opcodes.AASTORE;
-import static org.objectweb.asm.Opcodes.ACONST_NULL;
-import static org.objectweb.asm.Opcodes.ALOAD;
-import static org.objectweb.asm.Opcodes.ANEWARRAY;
-import static org.objectweb.asm.Opcodes.ARETURN;
-import static org.objectweb.asm.Opcodes.DUP;
-import static org.objectweb.asm.Opcodes.F_SAME1;
-import static org.objectweb.asm.Opcodes.IFEQ;
-import static org.objectweb.asm.Opcodes.ILOAD;
-import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
-import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
-import static org.objectweb.asm.Opcodes.INVOKESTATIC;
-import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
-import static org.objectweb.asm.Opcodes.NEW;
-import static org.objectweb.asm.Opcodes.POP;
-
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.apimodel.AndroidApiVersionsXmlParser.ParsedApiClass;
-import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.references.TypeReference;
-import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
-import com.android.tools.r8.transformers.MethodTransformer;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.IntBox;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.Label;
-import org.objectweb.asm.Opcodes;
-
-public class AndroidApiObjectDatabaseBuilderGenerator extends TestBase {
-
- public static String generatedMainDescriptor() {
- return descriptor(AndroidApiDatabaseBuilderTemplate.class).replace("Template", "");
- }
-
- public static ClassReference ANDROID_API_LEVEL =
- Reference.classFromBinaryName("com/android/tools/r8/utils/AndroidApiLevel");
- public static ClassReference ANDROID_API_CLASS =
- Reference.classFromBinaryName("com/android/tools/r8/androidapi/AndroidApiClass");
- public static ClassReference TRAVERSAL_CONTINUATION =
- Reference.classFromBinaryName("com/android/tools/r8/utils/TraversalContinuation");
-
- /**
- * Generate the classes needed for looking up api level of references in the android.jar.
- *
- * <p>For each api class we generate a from AndroidApiDatabaseClassTemplate, extending
- * AndroidApiClass, such that all members can be traversed. Looking up the class reference
- * directly in one method will generate to much code and would probably be inefficient so we first
- * do a case on the package and then do a check on the simple name.
- *
- * <p>We therefore create a class file for each package, based on
- * AndroidApiDatabasePackageTemplate, that will do the dispatch to create a new
- * AndroidApiDatabaseClass for class in the package.
- *
- * <p>We then have a single entry-point, AndroidApiDatabaseBuilder, based on
- * AndroidApiDatabaseBuilderTemplate, that will do the dispatch to AndroidApiDatabasePackage based
- * on the package name.
- */
- public static void generate(List<ParsedApiClass> apiClasses, BiConsumer<String, byte[]> consumer)
- throws Exception {
- Map<String, List<ParsedApiClass>> packageToClassesMap = new HashMap<>();
- List<String> packages =
- apiClasses.stream()
- .map(
- apiClass -> {
- String packageName =
- DescriptorUtils.getPackageNameFromDescriptor(
- apiClass.getClassReference().getDescriptor());
- packageToClassesMap
- .computeIfAbsent(packageName, ignoreArgument(ArrayList::new))
- .add(apiClass);
- return packageName;
- })
- .sorted()
- .distinct()
- .collect(Collectors.toList());
-
- for (ParsedApiClass apiClass : apiClasses) {
- String apiClassDescriptor = getApiClassReference(apiClass).getDescriptor();
- consumer.accept(
- apiClassDescriptor,
- transformer(AndroidApiDatabaseClassTemplate.class)
- .setClassDescriptor(apiClassDescriptor)
- .addMethodTransformer(getInitTransformer(apiClass))
- .addMethodTransformer(getApiLevelTransformer(apiClass))
- .addMethodTransformer(getGetMemberCountTransformer(apiClass))
- .addMethodTransformer(getVisitFieldsTransformer(apiClass))
- .addMethodTransformer(getVisitMethodsTransformer(apiClass))
- .removeMethods(MethodPredicate.onName("placeHolderForInit"))
- .removeMethods(MethodPredicate.onName("placeHolderForGetApiLevel"))
- .removeMethods(MethodPredicate.onName("placeHolderForGetMemberCount"))
- .removeMethods(MethodPredicate.onName("placeHolderForVisitFields"))
- .removeMethods(MethodPredicate.onName("placeHolderForVisitMethods"))
- .setSourceFile(
- DescriptorUtils.getSimpleClassNameFromDescriptor(apiClassDescriptor) + ".java")
- .computeMaxs()
- .transform(ClassWriter.COMPUTE_MAXS));
- }
-
- for (String pkg : packages) {
- consumer.accept(
- getPackageBuilderDescriptor(pkg),
- transformer(AndroidApiDatabasePackageTemplate.class)
- .setClassDescriptor(getPackageBuilderDescriptor(pkg))
- .addMethodTransformer(getBuildClassTransformer(packageToClassesMap.get(pkg)))
- .removeMethods(MethodPredicate.onName("placeHolder"))
- .computeMaxs()
- .transform(ClassWriter.COMPUTE_MAXS));
- }
-
- consumer.accept(
- generatedMainDescriptor(),
- transformer(AndroidApiDatabaseBuilderTemplate.class)
- .setClassDescriptor(generatedMainDescriptor())
- .addMethodTransformer(getVisitApiClassesTransformer(apiClasses))
- .addMethodTransformer(getBuildPackageTransformer(packages))
- .removeMethods(MethodPredicate.onName("placeHolderForVisitApiClasses"))
- .removeMethods(MethodPredicate.onName("placeHolderForBuildClass"))
- .computeMaxs()
- .transform(ClassWriter.COMPUTE_MAXS));
- }
-
- private static String getPackageBuilderDescriptor(String pkg) {
- return DescriptorUtils.javaTypeToDescriptor(
- AndroidApiDatabasePackageTemplate.class
- .getTypeName()
- .replace("Template", "ForPackage_" + pkg.replace(".", "_")));
- }
-
- private static ClassReference getApiClassReference(ParsedApiClass apiClass) {
- return fromTemplate(apiClass.getClassReference());
- }
-
- private static ClassReference fromTemplate(ClassReference classReference) {
- String descriptor =
- DescriptorUtils.javaTypeToDescriptor(
- AndroidApiDatabaseClassTemplate.class
- .getTypeName()
- .replace("Template", "ForClass_" + classReference.getTypeName().replace(".", "_")));
- return Reference.classFromDescriptor(descriptor);
- }
-
- // The transformer below changes AndroidApiDatabaseClassTemplate.<init> from:
- // super(Reference.classFromDescriptor(placeHolderForInit()));
- // into
- // super(Reference.classFromDescriptor("<class-descriptor>"));
- private static MethodTransformer getInitTransformer(ParsedApiClass apiClass) {
- return replaceCode(
- "placeHolderForInit",
- transformer -> {
- transformer.visitLdcInsn(apiClass.getClassReference().getDescriptor());
- });
- }
-
- // The transformer below changes AndroidApiDatabaseClassTemplate.getApiLevel from:
- // return placeHolderForGetApiLevel();
- // into
- // return AndroidApiLevel.getAndroidApiLevel(<apiLevel>);
- private static MethodTransformer getApiLevelTransformer(ParsedApiClass apiClass) {
- return replaceCode(
- "placeHolderForGetApiLevel",
- transformer -> {
- transformer.visitLdcInsn(apiClass.getApiLevel().getLevel());
- transformer.visitMethodInsn(
- INVOKESTATIC,
- ANDROID_API_LEVEL.getBinaryName(),
- "getAndroidApiLevel",
- "(I)" + ANDROID_API_LEVEL.getDescriptor(),
- false);
- });
- }
-
- // The transformer below changes AndroidApiDatabaseClassTemplate.getMemberCount from:
- // return placeHolderForGetMemberCount();
- // into
- // return <memberCount>;
- private static MethodTransformer getGetMemberCountTransformer(ParsedApiClass apiClass) {
- return replaceCode(
- "placeHolderForGetMemberCount",
- transformer -> transformer.visitLdcInsn(apiClass.getTotalMemberCount()));
- }
-
- // The transformer below changes AndroidApiDatabaseClassTemplate.visitFields from:
- // placeHolder();
- // return TraversalContinuation.CONTINUE;
- // into
- // TraversalContinuation s1 = visitField(visitor, holder, minApiClass, apiLevel1, "field1",
- // "descriptor1")
- // if (s1.shouldBreak()) {
- // return s1;
- // }
- // TraversalContinuation s2 = visitField(visitor, holder, minApiClass, apiLevel2, "field2",
- // // "descriptor2")
- // if (s2.shouldBreak()) {
- // return s2;
- // }
- // ...
- // AndroidApiClassForClass_class_name1() super1 = new AndroidApiClassForClass_class_name1();
- // TraversalContinuation sN = super1.visitFields(
- // visitor, holder, max(minApiClass, minApiForLink));
- // ...
- // return TraversalContinuation.CONTINUE;
- private static MethodTransformer getVisitFieldsTransformer(ParsedApiClass apiClass) {
- IntBox lineNumberBox = new IntBox(0);
- return replaceCode(
- "placeHolderForVisitFields",
- transformer -> {
- apiClass.visitFieldReferences(
- (apiLevel, references) -> {
- references.forEach(
- reference -> {
- Label labelStart = new Label();
- transformer.visitLabel(labelStart);
- transformer.visitLineNumber(lineNumberBox.getAndIncrement(), labelStart);
- transformer.visitVarInsn(ALOAD, 0);
- transformer.visitVarInsn(ALOAD, 1);
- transformer.visitVarInsn(ALOAD, 2);
- transformer.visitVarInsn(ILOAD, 3);
- transformer.visitLdcInsn(apiLevel.getLevel());
- transformer.visitLdcInsn(reference.getFieldName());
- transformer.visitLdcInsn(reference.getFieldType().getDescriptor());
- transformer.visitMethodInsn(
- INVOKEVIRTUAL,
- ANDROID_API_CLASS.getBinaryName(),
- "visitField",
- "(Ljava/util/function/BiFunction;"
- + descriptor(ClassReference.class)
- + "I"
- + "I"
- + "Ljava/lang/String;"
- + "Ljava/lang/String;)"
- + TRAVERSAL_CONTINUATION.getDescriptor(),
- false);
- // Note that instead of storing the result here, we dup it on the stack.
- transformer.visitInsn(DUP);
- transformer.visitMethodInsn(
- INVOKEVIRTUAL,
- TRAVERSAL_CONTINUATION.getBinaryName(),
- "shouldBreak",
- "()Z",
- false);
- Label label = new Label();
- transformer.visitJumpInsn(IFEQ, label);
- transformer.visitInsn(ARETURN);
- transformer.visitLabel(label);
- transformer.visitFrame(
- F_SAME1,
- 0,
- new Object[] {},
- 1,
- new Object[] {TRAVERSAL_CONTINUATION.getBinaryName()});
- // The pop here is needed to remove the dupped value in the case we do not
- // return.
- transformer.visitInsn(POP);
- });
- });
- if (!apiClass.isInterface()) {
- apiClass.visitSuperType(
- (superType, apiLevel) -> {
- addMembersForParent(
- transformer,
- superType,
- "visitFields",
- apiLevel,
- lineNumberBox.getAndIncrement());
- });
- }
- // No need to visit fields on interfaces since they have to be static and should not be
- // called on a super instance.
- });
- }
-
- // The transformer below changes AndroidApiDatabaseClassTemplate.visitMethods from:
- // placeHolderForVisitMethods();
- // return TraversalContinuation.CONTINUE;
- // into
- // TraversalContinuation s1 = visitMethod(visitor, holder, minApiClass, apiLevel1,
- // "method1", new String[] { "param11", ... , "param1X" }, null/return1)
- // if (s1.shouldBreak()) {
- // return s1;
- // }
- // TraversalContinuation s1 = visitMethod(visitor, holder, minApiClass, apiLevel2,
- // "method2", new String[] { "param21", ... , "param2X" }, null/return2)
- // if (s2.shouldBreak()) {
- // return s2;
- // }
- // ...
- // AndroidApiClassForClass_class_name1() super1 = new AndroidApiClassForClass_class_name1();
- // TraversalContinuation sN = super1.visitMethods(
- // visitor, holder, max(minApiClass, minApiForLink));
- // ...
- // return TraversalContinuation.CONTINUE;
- private static MethodTransformer getVisitMethodsTransformer(ParsedApiClass apiClass) {
- IntBox lineNumberBox = new IntBox(0);
- return replaceCode(
- "placeHolderForVisitMethods",
- transformer -> {
- apiClass.visitMethodReferences(
- (apiLevel, references) -> {
- references.forEach(
- reference -> {
- Label labelStart = new Label();
- transformer.visitLabel(labelStart);
- transformer.visitLineNumber(lineNumberBox.getAndIncrement(), labelStart);
- transformer.visitVarInsn(ALOAD, 0);
- transformer.visitVarInsn(ALOAD, 1);
- transformer.visitVarInsn(ALOAD, 2);
- transformer.visitVarInsn(ILOAD, 3);
- transformer.visitLdcInsn(apiLevel.getLevel());
- transformer.visitLdcInsn(reference.getMethodName());
- List<TypeReference> formalTypes = reference.getFormalTypes();
- transformer.visitLdcInsn(formalTypes.size());
- transformer.visitTypeInsn(ANEWARRAY, binaryName(String.class));
- for (int i = 0; i < formalTypes.size(); i++) {
- transformer.visitInsn(DUP);
- transformer.visitLdcInsn(i);
- transformer.visitLdcInsn(formalTypes.get(i).getDescriptor());
- transformer.visitInsn(AASTORE);
- }
- if (reference.getReturnType() != null) {
- transformer.visitLdcInsn(reference.getReturnType().getDescriptor());
- } else {
- transformer.visitInsn(ACONST_NULL);
- }
- transformer.visitMethodInsn(
- INVOKEVIRTUAL,
- ANDROID_API_CLASS.getBinaryName(),
- "visitMethod",
- "(Ljava/util/function/BiFunction;"
- + descriptor(ClassReference.class)
- + "I"
- + "I"
- + "Ljava/lang/String;"
- + "[Ljava/lang/String;"
- + "Ljava/lang/String;)"
- + TRAVERSAL_CONTINUATION.getDescriptor(),
- false);
- // Note that instead of storing the result here, we dup it on the stack.
- transformer.visitInsn(DUP);
- transformer.visitMethodInsn(
- INVOKEVIRTUAL,
- TRAVERSAL_CONTINUATION.getBinaryName(),
- "shouldBreak",
- "()Z",
- false);
- Label label = new Label();
- transformer.visitJumpInsn(IFEQ, label);
- transformer.visitInsn(ARETURN);
- transformer.visitLabel(label);
- transformer.visitFrame(
- F_SAME1,
- 0,
- new Object[] {},
- 1,
- new Object[] {TRAVERSAL_CONTINUATION.getBinaryName()});
- // The pop here is needed to remove the dupped value in the case we do not
- // return.
- transformer.visitInsn(POP);
- });
- });
- if (!apiClass.isInterface()) {
- // Visit super types before interfaces emulating a poor man's resolutions.
- apiClass.visitSuperType(
- (superType, apiLevel) -> {
- addMembersForParent(
- transformer,
- superType,
- "visitMethods",
- apiLevel,
- lineNumberBox.getAndIncrement());
- });
- }
- apiClass.visitInterface(
- (classReference, apiLevel) -> {
- addMembersForParent(
- transformer,
- classReference,
- "visitMethods",
- apiLevel,
- lineNumberBox.getAndIncrement());
- });
- });
- }
-
- private static void addMembersForParent(
- MethodTransformer transformer,
- ClassReference classReference,
- String methodName,
- AndroidApiLevel minApiLevel,
- int lineNumber) {
- String binaryName = fromTemplate(classReference).getBinaryName();
- Label labelStart = new Label();
- transformer.visitLabel(labelStart);
- transformer.visitLineNumber(lineNumber, labelStart);
- transformer.visitTypeInsn(NEW, binaryName);
- transformer.visitInsn(DUP);
- transformer.visitMethodInsn(INVOKESPECIAL, binaryName, "<init>", "()V", false);
- transformer.visitVarInsn(ALOAD, 1);
- transformer.visitVarInsn(ALOAD, 2);
- // Compute the max api level compared to what is passed in.
- transformer.visitLdcInsn(minApiLevel.getLevel());
- transformer.visitVarInsn(ILOAD, 3);
- transformer.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "max", "(II)I", false);
- transformer.visitMethodInsn(
- INVOKEVIRTUAL,
- binaryName,
- methodName,
- "(Ljava/util/function/BiFunction;"
- + descriptor(ClassReference.class)
- + "I)"
- + TRAVERSAL_CONTINUATION.getDescriptor(),
- false);
- // Note that instead of storing the result here, we dup it on the stack.
- transformer.visitInsn(DUP);
- transformer.visitMethodInsn(
- INVOKEVIRTUAL, TRAVERSAL_CONTINUATION.getBinaryName(), "shouldBreak", "()Z", false);
- Label label = new Label();
- transformer.visitJumpInsn(IFEQ, label);
- transformer.visitInsn(ARETURN);
- transformer.visitLabel(label);
- transformer.visitFrame(
- F_SAME1, 0, new Object[] {}, 1, new Object[] {TRAVERSAL_CONTINUATION.getBinaryName()});
- // The pop here is needed to remove the dupped value in the case we do not return.
- transformer.visitInsn(POP);
- }
-
- // The transformer below changes AndroidApiDatabasePackageTemplate.buildClass from:
- // placeHolder();
- // return null;
- // into
- // if ("<simple_class1>".equals(className)) {
- // return new AndroidApiClassForClass_class_name1();
- // }
- // if ("<simple_class2>".equals(className)) {
- // return new AndroidApiClassForClass_class_name2();
- // }
- // ...
- // return null;
- private static MethodTransformer getBuildClassTransformer(List<ParsedApiClass> classesForPackage)
- throws NoSuchMethodException {
- Method equals = Object.class.getMethod("equals", Object.class);
- return replaceCode(
- "placeHolder",
- transformer -> {
- classesForPackage.forEach(
- apiClass -> {
- transformer.visitLdcInsn(
- DescriptorUtils.getSimpleClassNameFromDescriptor(
- apiClass.getClassReference().getDescriptor()));
- transformer.visitVarInsn(ALOAD, 0);
- transformer.visitMethodInsn(
- INVOKEVIRTUAL,
- binaryName(String.class),
- equals.getName(),
- methodDescriptor(equals),
- false);
- Label label = new Label();
- transformer.visitJumpInsn(IFEQ, label);
- String binaryName = getApiClassReference(apiClass).getBinaryName();
- transformer.visitTypeInsn(NEW, binaryName);
- transformer.visitInsn(DUP);
- transformer.visitMethodInsn(INVOKESPECIAL, binaryName, "<init>", "()V", false);
- transformer.visitInsn(ARETURN);
- transformer.visitLabel(label);
- transformer.visitFrame(Opcodes.F_SAME, 0, new Object[] {}, 0, new Object[0]);
- });
- });
- }
-
- // The transformer below changes AndroidApiDatabaseBuilderTemplate.buildClass from:
- // String descriptor = classReference.getDescriptor();
- // String packageName = DescriptorUtils.getPackageNameFromDescriptor(descriptor);
- // String simpleClassName = DescriptorUtils.getSimpleClassNameFromDescriptor(descriptor);
- // placeHolderForBuildClass();
- // return null;
- // into
- // String descriptor = classReference.getDescriptor();
- // String packageName = DescriptorUtils.getPackageNameFromDescriptor(descriptor);
- // String simpleClassName = DescriptorUtils.getSimpleClassNameFromDescriptor(descriptor);
- // if ("<package_name1>".equals(packageName)) {
- // return AndroidApiClassForPackage_package_name1(simpleClassName);
- // }
- // if ("<package_name2>".equals(simpleClassName)) {
- // return AndroidApiClassForPackage_package_name2(simpleClassName);
- // }
- // ...
- // return null;
- private static MethodTransformer getBuildPackageTransformer(List<String> packages)
- throws NoSuchMethodException {
- Method equals = String.class.getMethod("equals", Object.class);
- Method buildClass =
- AndroidApiDatabasePackageTemplate.class.getMethod("buildClass", String.class);
- return replaceCode(
- "placeHolderForBuildClass",
- transformer -> {
- packages.forEach(
- pkg -> {
- transformer.visitLdcInsn(pkg);
- transformer.visitVarInsn(ALOAD, 2);
- transformer.visitMethodInsn(
- INVOKEVIRTUAL,
- binaryName(String.class),
- equals.getName(),
- methodDescriptor(equals),
- false);
- Label label = new Label();
- transformer.visitJumpInsn(IFEQ, label);
- transformer.visitVarInsn(ALOAD, 3);
- transformer.visitMethodInsn(
- INVOKESTATIC,
- DescriptorUtils.getBinaryNameFromDescriptor(getPackageBuilderDescriptor(pkg)),
- buildClass.getName(),
- methodDescriptor(buildClass),
- false);
- transformer.visitInsn(ARETURN);
- transformer.visitLabel(label);
- transformer.visitFrame(
- Opcodes.F_FULL,
- 4,
- new Object[] {
- binaryName(ClassReference.class),
- binaryName(String.class),
- binaryName(String.class),
- binaryName(String.class)
- },
- 0,
- new Object[0]);
- });
- });
- }
-
- // The transformer below changes AndroidApiDatabaseBuilderTemplate.buildClass from:
- // placeHolderForVisitApiClasses();
- // into
- // classDescriptorConsumer.accept("<descriptor_class_1>");
- // classDescriptorConsumer.accept("<descriptor_class_2>");
- // ...
- // return null;
- private static MethodTransformer getVisitApiClassesTransformer(List<ParsedApiClass> apiClasses) {
- return replaceCode(
- "placeHolderForVisitApiClasses",
- transformer -> {
- apiClasses.forEach(
- apiClass -> {
- transformer.visitVarInsn(ALOAD, 0);
- transformer.visitLdcInsn(apiClass.getClassReference().getDescriptor());
- transformer.visitMethodInsn(
- INVOKEINTERFACE,
- binaryName(Consumer.class),
- "accept",
- "(Ljava/lang/Object;)V",
- true);
- });
- });
- }
-
- private static MethodTransformer replaceCode(
- String placeholderName, Consumer<MethodTransformer> consumer) {
- return new MethodTransformer() {
-
- @Override
- public void visitMaxs(int maxStack, int maxLocals) {
- super.visitMaxs(-1, maxLocals);
- }
-
- @Override
- public void visitMethodInsn(
- int opcode, String owner, String name, String descriptor, boolean isInterface) {
- if (name.equals(placeholderName)) {
- consumer.accept(this);
- } else {
- super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
- }
- }
- };
- }
-}
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiObjectDatabaseBuilderGeneratorTest.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiObjectDatabaseBuilderGeneratorTest.java
deleted file mode 100644
index 40b57c5..0000000
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiObjectDatabaseBuilderGeneratorTest.java
+++ /dev/null
@@ -1,421 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.apimodel;
-
-import static com.android.tools.r8.apimodel.AndroidApiObjectDatabaseBuilderGenerator.generatedMainDescriptor;
-import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
-import static org.junit.Assert.assertEquals;
-
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.JvmTestBuilder;
-import com.android.tools.r8.JvmTestRunResult;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRuntime;
-import com.android.tools.r8.TestState;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.apimodel.AndroidApiVersionsXmlParser.ParsedApiClass;
-import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.BooleanBox;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.IntBox;
-import com.android.tools.r8.utils.ListUtils;
-import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.TraversalContinuation;
-import com.android.tools.r8.utils.ZipUtils;
-import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.google.common.collect.ImmutableList;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-import java.util.function.BiFunction;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class AndroidApiObjectDatabaseBuilderGeneratorTest extends TestBase {
-
- protected final TestParameters parameters;
- private static final Path API_VERSIONS_XML =
- Paths.get(ToolHelper.THIRD_PARTY_DIR, "android_jar", "api-versions", "api-versions.xml");
- private static final Path API_DATABASE_JAR =
- Paths.get(ToolHelper.THIRD_PARTY_DIR, "android_jar", "api-database", "api-database.jar");
- private static final AndroidApiLevel API_LEVEL = AndroidApiLevel.S;
-
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withNoneRuntime().build();
- }
-
- public AndroidApiObjectDatabaseBuilderGeneratorTest(TestParameters parameters) {
- this.parameters = parameters;
- }
-
- private static Path generateJar() throws Exception {
- return generateJar(
- AndroidApiVersionsXmlParser.getParsedApiClasses(API_VERSIONS_XML.toFile(), API_LEVEL));
- }
-
- private static Path generateJar(List<ParsedApiClass> apiClasses) throws Exception {
- TemporaryFolder temp = new TemporaryFolder();
- temp.create();
- ZipBuilder builder = ZipBuilder.builder(temp.newFile("out.jar").toPath());
- AndroidApiObjectDatabaseBuilderGenerator.generate(
- apiClasses,
- (descriptor, content) -> {
- try {
- String binaryName = DescriptorUtils.getBinaryNameFromDescriptor(descriptor) + ".class";
- builder.addBytes(binaryName, content);
- } catch (IOException exception) {
- throw new RuntimeException(exception);
- }
- });
- return builder.build();
- }
-
- @Test
- public void testCanParseApiVersionsXml() throws Exception {
- // This tests makes a rudimentary check on the number of classes, fields and methods in
- // api-versions.xml to ensure that the runtime tests do not vacuously succeed.
- List<ParsedApiClass> parsedApiClasses =
- AndroidApiVersionsXmlParser.getParsedApiClasses(API_VERSIONS_XML.toFile(), API_LEVEL);
- IntBox numberOfFields = new IntBox(0);
- IntBox numberOfMethods = new IntBox(0);
- parsedApiClasses.forEach(
- apiClass -> {
- apiClass.visitFieldReferences(
- ((apiLevel, fieldReferences) -> {
- fieldReferences.forEach(field -> numberOfFields.increment());
- }));
- apiClass.visitMethodReferences(
- ((apiLevel, methodReferences) -> {
- methodReferences.forEach(field -> numberOfMethods.increment());
- }));
- });
- // These numbers will change when updating api-versions.xml
- assertEquals(5037, parsedApiClasses.size());
- assertEquals(26362, numberOfFields.get());
- assertEquals(40416, numberOfMethods.get());
- }
-
- @Test
- public void testDatabaseGenerationUpToDate() throws Exception {
- TestBase.filesAreEqual(generateJar(), API_DATABASE_JAR);
- }
-
- /**
- * Main entry point for building a database over references in framework to the api level they
- * were introduced. Running main will generate a new jar and run tests on it to ensure it is
- * compatible with R8 sources and works as expected.
- *
- * <p>The generated jar depends on r8NoManifestWithoutDeps.
- *
- * <p>If the generated jar passes tests it will be moved to third_party/android_jar/api-database/
- * and override the current file in there.
- */
- public static void main(String[] args) throws Exception {
- List<ParsedApiClass> parsedApiClasses =
- AndroidApiVersionsXmlParser.getParsedApiClasses(API_VERSIONS_XML.toFile(), API_LEVEL);
- Path generatedJar = generateJar(parsedApiClasses);
- validateJar(generatedJar, parsedApiClasses);
- Files.move(generatedJar, API_DATABASE_JAR, REPLACE_EXISTING);
- }
-
- private static void validateJar(Path generated, List<ParsedApiClass> apiClasses) {
- List<BiFunction<Path, List<ParsedApiClass>, Boolean>> tests =
- ImmutableList.of(
- AndroidApiObjectDatabaseBuilderGeneratorTest::testGeneratedOutputForVisitClasses,
- AndroidApiObjectDatabaseBuilderGeneratorTest::testBuildClassesContinue,
- AndroidApiObjectDatabaseBuilderGeneratorTest::testBuildClassesBreak,
- AndroidApiObjectDatabaseBuilderGeneratorTest::testNoPlaceHolder);
- tests.forEach(
- test -> {
- try {
- if (!test.apply(generated, apiClasses)) {
- throw new RuntimeException("Generated jar did not pass tests");
- }
- } catch (Exception e) {
- throw new RuntimeException("Generated jar did not pass tests", e);
- }
- });
- }
-
- private static boolean testGeneratedOutputForVisitClasses(
- Path generated, List<ParsedApiClass> parsedApiClasses) {
- String expectedOutput =
- StringUtils.lines(
- ListUtils.map(
- parsedApiClasses, apiClass -> apiClass.getClassReference().getDescriptor()));
- return runTest(generated, TestGeneratedMainVisitClasses.class)
- .getStdOut()
- .equals(expectedOutput);
- }
-
- private static boolean testBuildClassesContinue(
- Path generated, List<ParsedApiClass> parsedApiClasses) {
- return runTest(generated, TestBuildClassesContinue.class)
- .getStdOut()
- .equals(getExpected(parsedApiClasses, false));
- }
-
- private static boolean testBuildClassesBreak(
- Path generated, List<ParsedApiClass> parsedApiClasses) {
- return runTest(generated, TestBuildClassesBreak.class)
- .getStdOut()
- .equals(getExpected(parsedApiClasses, true));
- }
-
- private static boolean testNoPlaceHolder(Path generated, List<ParsedApiClass> parsedApiClasses) {
- try {
- CodeInspector inspector = new CodeInspector(generated);
- inspector
- .allClasses()
- .forEach(
- clazz -> {
- clazz.forAllMethods(
- methods -> {
- if (methods.getFinalName().startsWith("placeHolder")) {
- throw new RuntimeException("Found placeHolder method in generated jar");
- }
- });
- });
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- return true;
- }
-
- private static JvmTestRunResult runTest(Path generated, Class<?> testClass) {
- try {
- TemporaryFolder temporaryFolder = new TemporaryFolder();
- temporaryFolder.create();
- return JvmTestBuilder.create(new TestState(temporaryFolder))
- .addProgramClassFileData(
- transformer(testClass)
- .replaceClassDescriptorInMethodInstructions(
- descriptor(AndroidApiDatabaseBuilderTemplate.class),
- generatedMainDescriptor())
- .transform())
- .addLibraryFiles(
- generated,
- ToolHelper.R8_WITHOUT_DEPS_JAR,
- getDepsWithoutGeneratedApiModelClasses(),
- ToolHelper.getJava8RuntimeJar())
- .run(TestRuntime.getSystemRuntime(), testClass)
- .apply(
- result -> {
- if (result.getExitCode() != 0) {
- throw new RuntimeException(result.getStdErr());
- }
- });
- } catch (IOException | ExecutionException | CompilationFailedException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- private static Path getDepsWithoutGeneratedApiModelClasses() throws IOException {
- Path tempDeps = Files.createTempDirectory("temp_deps");
- ZipUtils.unzip(
- ToolHelper.DEPS.toString(),
- tempDeps.toFile(),
- entry -> !entry.getName().startsWith("com/android/tools/r8/apimodel/"));
- Path modifiedDeps = Files.createTempFile("modified_deps", ".jar");
- ZipUtils.zip(modifiedDeps, tempDeps);
- return modifiedDeps;
- }
-
- private static String getExpected(List<ParsedApiClass> parsedApiClasses, boolean abort) {
- Map<ClassReference, ParsedApiClass> parsedApiClassMap = new HashMap<>(parsedApiClasses.size());
- parsedApiClasses.forEach(
- parsedClass -> parsedApiClassMap.put(parsedClass.getClassReference(), parsedClass));
- List<String> expected = new ArrayList<>();
- parsedApiClasses.forEach(
- apiClass -> {
- expected.add("CLASS: " + apiClass.getClassReference().getDescriptor());
- expected.add(apiClass.getApiLevel().getName());
- expected.add(apiClass.getTotalMemberCount() + "");
- visitApiClass(expected, parsedApiClassMap, apiClass, apiClass.getApiLevel(), true, abort);
- visitApiClass(
- expected, parsedApiClassMap, apiClass, apiClass.getApiLevel(), false, abort);
- });
- return StringUtils.lines(expected);
- }
-
- private static boolean visitApiClass(
- List<String> expected,
- Map<ClassReference, ParsedApiClass> parsedApiClassMap,
- ParsedApiClass apiClass,
- AndroidApiLevel apiLevel,
- boolean visitFields,
- boolean abort) {
- BooleanBox added = new BooleanBox(false);
- if (visitFields) {
- added.set(visitFields(expected, apiClass, apiLevel, abort));
- } else {
- added.set(visitMethods(expected, apiClass, apiLevel, abort));
- }
- if (added.isTrue() && abort) {
- return true;
- }
- // Go through super type methods if not interface.
- if (!apiClass.isInterface()) {
- apiClass.visitSuperType(
- (classReference, linkApiLevel) -> {
- if (added.isTrue() && abort) {
- return;
- }
- ParsedApiClass superApiClass = parsedApiClassMap.get(classReference);
- assert superApiClass != null;
- added.set(
- visitApiClass(
- expected,
- parsedApiClassMap,
- superApiClass,
- linkApiLevel.max(apiLevel),
- visitFields,
- abort));
- });
- }
- if (!visitFields) {
- apiClass.visitInterface(
- (classReference, linkApiLevel) -> {
- if (added.isTrue() && abort) {
- return;
- }
- ParsedApiClass ifaceApiClass = parsedApiClassMap.get(classReference);
- assert ifaceApiClass != null;
- added.set(
- visitApiClass(
- expected,
- parsedApiClassMap,
- ifaceApiClass,
- linkApiLevel.max(apiLevel),
- visitFields,
- abort));
- });
- }
- return added.get();
- }
-
- private static boolean visitFields(
- List<String> expected, ParsedApiClass apiClass, AndroidApiLevel minApiLevel, boolean abort) {
- BooleanBox added = new BooleanBox(false);
- apiClass.visitFieldReferences(
- (apiLevel, fieldReferences) -> {
- fieldReferences.forEach(
- fieldReference -> {
- if (added.isTrue() && abort) {
- return;
- }
- added.set();
- expected.add(fieldReference.getFieldType().getDescriptor());
- expected.add(fieldReference.getFieldName());
- expected.add(apiLevel.max(minApiLevel).getName());
- });
- });
- return added.get();
- }
-
- private static boolean visitMethods(
- List<String> expected, ParsedApiClass apiClass, AndroidApiLevel minApiLevel, boolean abort) {
- BooleanBox added = new BooleanBox(false);
- apiClass.visitMethodReferences(
- (apiLevel, methodReferences) -> {
- methodReferences.forEach(
- methodReference -> {
- if (added.isTrue() && abort) {
- return;
- }
- added.set();
- expected.add(methodReference.getMethodDescriptor());
- expected.add(methodReference.getMethodName());
- expected.add(apiLevel.max(minApiLevel).getName());
- });
- });
- return added.get();
- }
-
- public static class TestGeneratedMainVisitClasses {
-
- public static void main(String[] args) {
- AndroidApiDatabaseBuilderTemplate.visitApiClasses(System.out::println);
- }
- }
-
- public static class TestBuildClassesContinue {
-
- public static void main(String[] args) {
- AndroidApiDatabaseBuilderTemplate.visitApiClasses(
- descriptor -> {
- com.android.tools.r8.androidapi.AndroidApiClass apiClass =
- AndroidApiDatabaseBuilderTemplate.buildClass(
- Reference.classFromDescriptor(descriptor));
- if (apiClass != null) {
- System.out.println("CLASS: " + descriptor);
- System.out.println(apiClass.getApiLevel().getName());
- System.out.println(apiClass.getMemberCount());
- apiClass.visitFields(
- (reference, apiLevel) -> {
- System.out.println(reference.getFieldType().getDescriptor());
- System.out.println(reference.getFieldName());
- System.out.println(apiLevel.getName());
- return TraversalContinuation.CONTINUE;
- });
- apiClass.visitMethods(
- (reference, apiLevel) -> {
- System.out.println(reference.getMethodDescriptor());
- System.out.println(reference.getMethodName());
- System.out.println(apiLevel.getName());
- return TraversalContinuation.CONTINUE;
- });
- }
- });
- }
- }
-
- public static class TestBuildClassesBreak {
-
- public static void main(String[] args) {
- AndroidApiDatabaseBuilderTemplate.visitApiClasses(
- descriptor -> {
- com.android.tools.r8.androidapi.AndroidApiClass apiClass =
- AndroidApiDatabaseBuilderTemplate.buildClass(
- Reference.classFromDescriptor(descriptor));
- if (apiClass != null) {
- System.out.println("CLASS: " + descriptor);
- System.out.println(apiClass.getApiLevel().getName());
- System.out.println(apiClass.getMemberCount());
- apiClass.visitFields(
- (reference, apiLevel) -> {
- System.out.println(reference.getFieldType().getDescriptor());
- System.out.println(reference.getFieldName());
- System.out.println(apiLevel.getName());
- return TraversalContinuation.BREAK;
- });
- apiClass.visitMethods(
- (reference, apiLevel) -> {
- System.out.println(reference.getMethodDescriptor());
- System.out.println(reference.getMethodName());
- System.out.println(apiLevel.getName());
- return TraversalContinuation.BREAK;
- });
- }
- });
- }
- }
-}