Add a Test to Check the Desugar Tool supports all Shadowed Android Platform Fields with Type Converters
PiperOrigin-RevId: 313638848
diff --git a/src/test/java/com/google/devtools/build/android/desugar/corelibadapter/ShadowedPlatformTypeConverterCoverageTest.java b/src/test/java/com/google/devtools/build/android/desugar/corelibadapter/ShadowedPlatformTypeConverterCoverageTest.java
index 7cb8f86..1c1e3f0 100644
--- a/src/test/java/com/google/devtools/build/android/desugar/corelibadapter/ShadowedPlatformTypeConverterCoverageTest.java
+++ b/src/test/java/com/google/devtools/build/android/desugar/corelibadapter/ShadowedPlatformTypeConverterCoverageTest.java
@@ -24,6 +24,8 @@
import static org.objectweb.asm.ClassReader.SKIP_CODE;
import static org.objectweb.asm.ClassReader.SKIP_DEBUG;
import static org.objectweb.asm.ClassReader.SKIP_FRAMES;
+import static org.objectweb.asm.Opcodes.ACC_PROTECTED;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import com.google.auto.value.AutoValue;
import com.google.common.base.Splitter;
@@ -33,6 +35,7 @@
import com.google.common.collect.Sets;
import com.google.devtools.build.android.desugar.io.JarItem;
import com.google.devtools.build.android.desugar.langmodel.ClassName;
+import com.google.devtools.build.android.desugar.langmodel.FieldKey;
import com.google.devtools.build.android.desugar.langmodel.MethodDeclInfo;
import com.google.devtools.build.android.desugar.langmodel.MethodKey;
import java.io.IOError;
@@ -41,11 +44,13 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Set;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -66,11 +71,24 @@
ImmutableList.copyOf(SPACE_SPLITTER.splitToList(System.getProperty("platform_jars")));
private static final String TYPE_CONVERTER_JAR_PATH = System.getProperty("type_converter_jar");
- private final ImmutableMultimap<ClassName, MethodHeaderTypeTrackingLabel>
- shadowedTypesOnPlatformMethodHeaders = getShadowedTypesOnPlatformMethodHeaders();
+ private ImmutableMultimap<ClassName, MethodHeaderTypeTrackingLabel>
+ shadowedTypesOnPlatformMethodHeaders;
+ private ImmutableMultimap<ClassName, FieldTypeTrackingLabel> shadowedTypesOnPlatformFields;
+
private final ImmutableSet<ClassName> shadowedTypesWithTypeConverterSupport =
getShadowedTypesWithTypeConverterSupport();
+ @Before
+ public void setUp() throws Exception {
+ ImmutableMultimap.Builder<ClassName, MethodHeaderTypeTrackingLabel> shadowedMethods =
+ ImmutableMultimap.builder();
+ ImmutableMultimap.Builder<ClassName, FieldTypeTrackingLabel> shadowedFields =
+ ImmutableMultimap.builder();
+ loadShadowedTypesOnPlatformClassMembers(shadowedMethods, shadowedFields);
+ shadowedTypesOnPlatformMethodHeaders = shadowedMethods.build();
+ shadowedTypesOnPlatformFields = shadowedFields.build();
+ }
+
@Test
public void checkTypeConverterSupport_allAndroidPlatformMethodHeadersCovered() {
ImmutableSet<ClassName> shadowedTypesOnPlatform = shadowedTypesOnPlatformMethodHeaders.keySet();
@@ -87,10 +105,26 @@
.isEmpty();
}
- private static ImmutableMultimap<ClassName, MethodHeaderTypeTrackingLabel>
- getShadowedTypesOnPlatformMethodHeaders() {
- ImmutableMultimap.Builder<ClassName, MethodHeaderTypeTrackingLabel> shadowedTypesBuilder =
- ImmutableMultimap.builder();
+ @Test
+ public void checkTypeConverterSupport_allAndroidPlatformFieldsCovered() {
+ ImmutableSet<ClassName> shadowedTypesOnPlatform = shadowedTypesOnPlatformFields.keySet();
+ Set<ClassName> shadowedTypesMissingTypeConverter =
+ Sets.difference(shadowedTypesOnPlatform, shadowedTypesWithTypeConverterSupport);
+
+ assertWithMessage(
+ String.format(
+ "Desugar-shadowable platform types missing a type converter: \n%s\n",
+ shadowedTypesMissingTypeConverter.stream()
+ .flatMap(type -> shadowedTypesOnPlatformFields.get(type).stream())
+ .collect(toImmutableList())))
+ .that(shadowedTypesMissingTypeConverter)
+ .isEmpty();
+ }
+
+ private static void loadShadowedTypesOnPlatformClassMembers(
+ ImmutableMultimap.Builder<ClassName, MethodHeaderTypeTrackingLabel>
+ shadowedMethodTypesBuilder,
+ ImmutableMultimap.Builder<ClassName, FieldTypeTrackingLabel> shadowedFieldTypesBuilder) {
PLATFORM_JAR_PATHS.stream()
.flatMap(jarTextPath -> JarItem.jarItemStream(Paths.get(jarTextPath)))
.filter(
@@ -102,13 +136,13 @@
try (InputStream inputStream = jarItem.getInputStream()) {
ClassReader cr = new ClassReader(inputStream);
ClassVisitor cv =
- new ClassMemberHeaderClassVisitor(shadowedTypesBuilder, jarItem.jarPath());
+ new ClassMemberHeaderClassVisitor(
+ shadowedMethodTypesBuilder, shadowedFieldTypesBuilder, jarItem.jarPath());
cr.accept(cv, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES);
} catch (IOException e) {
throw new IOError(e);
}
});
- return shadowedTypesBuilder.build();
}
private static ImmutableSet<ClassName> getShadowedTypesWithTypeConverterSupport() {
@@ -131,17 +165,21 @@
private static class ClassMemberHeaderClassVisitor extends ClassVisitor {
- private final ImmutableMultimap.Builder<ClassName, MethodHeaderTypeTrackingLabel> shadowedTypes;
+ private final ImmutableMultimap.Builder<ClassName, MethodHeaderTypeTrackingLabel>
+ shadowedMethodTypes;
+ private final ImmutableMultimap.Builder<ClassName, FieldTypeTrackingLabel> shadowedFieldTypes;
private final Path containgJar;
private ClassName className;
private int classAccess;
ClassMemberHeaderClassVisitor(
- ImmutableMultimap.Builder<ClassName, MethodHeaderTypeTrackingLabel> shadowedTypes,
+ ImmutableMultimap.Builder<ClassName, MethodHeaderTypeTrackingLabel> shadowedMethodTypes,
+ ImmutableMultimap.Builder<ClassName, FieldTypeTrackingLabel> shadowedFieldTypes,
Path containingJar) {
super(Opcodes.ASM7);
- this.shadowedTypes = shadowedTypes;
+ this.shadowedMethodTypes = shadowedMethodTypes;
+ this.shadowedFieldTypes = shadowedFieldTypes;
this.containgJar = containingJar;
}
@@ -159,6 +197,25 @@
}
@Override
+ public FieldVisitor visitField(
+ int access, String name, String descriptor, String signature, Object value) {
+ FieldKey fieldKey = FieldKey.create(className, name, descriptor);
+ ClassName fieldType = fieldKey.getFieldTypeName();
+ if (className.isAndroidDomainType()
+ && ((access & ACC_PUBLIC) != 0 || (access & ACC_PROTECTED) != 0)
+ && fieldType.isDesugarShadowedType()) {
+ FieldTypeTrackingLabel trackingLabel =
+ FieldTypeTrackingLabel.builder()
+ .setField(fieldKey)
+ .setShadowedType(fieldType)
+ .setJarPath(containgJar)
+ .build();
+ shadowedFieldTypes.put(trackingLabel.shadowedType(), trackingLabel);
+ }
+ return super.visitField(access, name, descriptor, signature, value);
+ }
+
+ @Override
public MethodVisitor visitMethod(
int access, String name, String descriptor, String signature, String[] exceptions) {
if (className.isAndroidDomainType()) {
@@ -181,7 +238,7 @@
.setExceptionTypePosition(-1)
.setJarPath(containgJar)
.build();
- shadowedTypes.put(trackingLabel.shadowedType(), trackingLabel);
+ shadowedMethodTypes.put(trackingLabel.shadowedType(), trackingLabel);
}
ImmutableList<ClassName> argumentTypes = methodDeclInfo.argumentTypeNames();
@@ -197,7 +254,7 @@
.setExceptionTypePosition(-1)
.setJarPath(containgJar)
.build();
- shadowedTypes.put(trackingLabel.shadowedType(), trackingLabel);
+ shadowedMethodTypes.put(trackingLabel.shadowedType(), trackingLabel);
}
}
@@ -214,7 +271,7 @@
.setExceptionTypePosition(i)
.setJarPath(containgJar)
.build();
- shadowedTypes.put(trackingLabel.shadowedType(), trackingLabel);
+ shadowedMethodTypes.put(trackingLabel.shadowedType(), trackingLabel);
}
}
}
@@ -223,6 +280,33 @@
}
}
+ /** Tracks the origin of a field type. */
+ @AutoValue
+ abstract static class FieldTypeTrackingLabel {
+ abstract ClassName shadowedType();
+
+ abstract FieldKey field();
+
+ abstract Path jarPath();
+
+ static Builder builder() {
+ return new AutoValue_ShadowedPlatformTypeConverterCoverageTest_FieldTypeTrackingLabel
+ .Builder();
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder {
+
+ abstract Builder setShadowedType(ClassName value);
+
+ abstract Builder setField(FieldKey value);
+
+ abstract Builder setJarPath(Path value);
+
+ abstract FieldTypeTrackingLabel build();
+ }
+ }
+
/** Tracks the origin of a method header type, including parameter, return and exception types. */
@AutoValue
abstract static class MethodHeaderTypeTrackingLabel {
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/FieldKey.java b/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/FieldKey.java
index 0ed43e2..48449a7 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/FieldKey.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/FieldKey.java
@@ -103,7 +103,11 @@
Type.getMethodDescriptor(getFieldType(), Type.getObjectType(ownerName()), getFieldType()));
}
- public Type getFieldType() {
+ public final Type getFieldType() {
return Type.getType(descriptor());
}
+
+ public final ClassName getFieldTypeName() {
+ return ClassName.create(getFieldType());
+ }
}