Add fields in html doc
We need to discuss with agp on how to introduce fields
Change-Id: I41b1c4b9a3ed6508da78802a2ae680bf00014518
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateHtmlDoc.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateHtmlDoc.java
index 859bc95..d8d787e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateHtmlDoc.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateHtmlDoc.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.lint.SupportedClasses.ClassAnnotation;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.lint.SupportedClasses.FieldAnnotation;
import com.android.tools.r8.ir.desugar.desugaredlibrary.lint.SupportedClasses.MethodAnnotation;
import com.android.tools.r8.ir.desugar.desugaredlibrary.lint.SupportedClasses.SupportedClass;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -24,7 +25,6 @@
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
-import java.util.stream.StreamSupport;
public class GenerateHtmlDoc extends AbstractGenerateFiles {
@@ -92,7 +92,8 @@
private abstract static class SourceBuilder<B extends GenerateHtmlDoc.SourceBuilder> {
protected final DexClass clazz;
- protected List<DexEncodedField> fields = new ArrayList<>();
+ protected Map<DexEncodedField, FieldAnnotation> fields =
+ new TreeMap<>(Comparator.comparing(DexEncodedField::getReference));
protected Map<DexEncodedMethod, MethodAnnotation> constructors =
new TreeMap<>(Comparator.comparing(DexEncodedMethod::getReference));
protected Map<DexEncodedMethod, MethodAnnotation> methods =
@@ -110,8 +111,8 @@
public abstract B self();
- private B addField(DexEncodedField field) {
- fields.add(field);
+ private B addField(DexEncodedField field, FieldAnnotation fieldAnnotation) {
+ fields.put(field, fieldAnnotation);
return self();
}
@@ -396,6 +397,18 @@
return this;
}
+ private String getTextAnnotations(FieldAnnotation annotation) {
+ if (annotation == null) {
+ return "";
+ }
+ StringBuilder stringBuilder = new StringBuilder();
+ if (annotation.unsupportedInMinApiRange) {
+ stringBuilder.append(SUP_3);
+ unsupportedInMinApiRange = true;
+ }
+ return stringBuilder.toString();
+ }
+
private String getTextAnnotations(MethodAnnotation annotation) {
if (annotation == null) {
return "";
@@ -434,13 +447,14 @@
"ul style=\"list-style-position:inside; list-style-type: none !important;"
+ " margin-left:0px;padding-left:0px !important;\"");
if (!fields.isEmpty()) {
- for (DexEncodedField field : fields) {
+ for (DexEncodedField field : fields.keySet()) {
builder.appendLiCode(
accessFlags(field.accessFlags)
+ " "
+ typeInPackage(field.getReference().type)
+ " "
- + field.getReference().name);
+ + field.getReference().name
+ + getTextAnnotations(fields.get(field)));
}
}
if (!constructors.isEmpty()) {
@@ -514,15 +528,13 @@
DexClass clazz = supportedClass.getClazz();
SourceBuilder<HTMLSourceBuilder> builder =
new HTMLSourceBuilder(clazz, supportedClass.getClassAnnotation());
- // We need to extend to support fields.
- StreamSupport.stream(clazz.fields().spliterator(), false)
- .filter(field -> field.accessFlags.isPublic() || field.accessFlags.isProtected())
- .sorted(Comparator.comparing(DexEncodedField::toSourceString))
- .forEach(builder::addField);
+ supportedClass.forEachFieldAndAnnotation(
+ (field, fieldAnnotation) -> {
+ builder.addField(field, fieldAnnotation);
+ });
supportedClass.forEachMethodAndAnnotation(
(method, methodAnnotation) -> {
- if ((method.accessFlags.isPublic() || method.accessFlags.isProtected())
- && !method.accessFlags.isBridge()) {
+ if (!method.accessFlags.isBridge()) {
builder.addMethod(method, methodAnnotation);
}
});
@@ -534,7 +546,7 @@
PrintStream ps = new PrintStream(Files.newOutputStream(outputDirectory.resolve("apis.html")));
SupportedClasses supportedClasses =
- new SupportedMethodsGenerator(options)
+ new SupportedClassesGenerator(options)
.run(desugaredLibraryImplementation, desugaredLibrarySpecificationPath);
// Full classes added.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateLintFiles.java
index b7a1a27..0f35e69 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateLintFiles.java
@@ -244,7 +244,7 @@
AndroidApiLevel compilationLevel =
desugaredLibrarySpecification.getRequiredCompilationApiLevel();
SupportedClasses supportedMethods =
- new SupportedMethodsGenerator(options)
+ new SupportedClassesGenerator(options)
.run(desugaredLibraryImplementation, desugaredLibrarySpecificationPath);
System.out.println("Generating lint files for compile API " + compilationLevel);
generateLintFiles(compilationLevel, AndroidApiLevel.B, supportedMethods);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClasses.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClasses.java
index 32f1bf9..ed82660 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClasses.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClasses.java
@@ -5,7 +5,9 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.lint;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.google.common.collect.ImmutableList;
@@ -36,17 +38,23 @@
private final DexClass clazz;
private final ClassAnnotation classAnnotation;
private final List<DexEncodedMethod> supportedMethods;
+ private final List<DexEncodedField> supportedFields;
private final Map<DexMethod, MethodAnnotation> methodAnnotations;
+ private final Map<DexField, FieldAnnotation> fieldAnnotations;
private SupportedClass(
DexClass clazz,
ClassAnnotation classAnnotation,
List<DexEncodedMethod> supportedMethods,
- Map<DexMethod, MethodAnnotation> methodAnnotations) {
+ List<DexEncodedField> supportedFields,
+ Map<DexMethod, MethodAnnotation> methodAnnotations,
+ Map<DexField, FieldAnnotation> fieldAnnotations) {
this.clazz = clazz;
this.classAnnotation = classAnnotation;
this.supportedMethods = supportedMethods;
+ this.supportedFields = supportedFields;
this.methodAnnotations = methodAnnotations;
+ this.fieldAnnotations = fieldAnnotations;
}
public DexType getType() {
@@ -76,6 +84,16 @@
return methodAnnotations.get(method);
}
+ public void forEachFieldAndAnnotation(BiConsumer<DexEncodedField, FieldAnnotation> biConsumer) {
+ for (DexEncodedField supportedField : supportedFields) {
+ biConsumer.accept(supportedField, getFieldAnnotation(supportedField.getReference()));
+ }
+ }
+
+ public FieldAnnotation getFieldAnnotation(DexField field) {
+ return fieldAnnotations.get(field);
+ }
+
static Builder builder(DexClass clazz) {
return new Builder(clazz);
}
@@ -84,26 +102,39 @@
private final DexClass clazz;
private ClassAnnotation classAnnotation;
- private final Map<DexMethod, DexEncodedMethod> supportedMethods = new IdentityHashMap<>();
+ private final List<DexEncodedMethod> supportedMethods = new ArrayList<>();
+ private final List<DexEncodedField> supportedFields = new ArrayList<>();
private final Map<DexMethod, MethodAnnotation> methodAnnotations = new HashMap<>();
+ private final Map<DexField, FieldAnnotation> fieldAnnotations = new HashMap<>();
private Builder(DexClass clazz) {
this.clazz = clazz;
}
void forEachMethods(BiConsumer<DexClass, Collection<DexEncodedMethod>> biConsumer) {
- biConsumer.accept(clazz, supportedMethods.values());
+ biConsumer.accept(clazz, supportedMethods);
}
void forEachMethod(BiConsumer<DexClass, DexEncodedMethod> biConsumer) {
- for (DexEncodedMethod dexEncodedMethod : supportedMethods.values()) {
+ for (DexEncodedMethod dexEncodedMethod : supportedMethods) {
biConsumer.accept(clazz, dexEncodedMethod);
}
}
+ void forEachField(BiConsumer<DexClass, DexEncodedField> biConsumer) {
+ for (DexEncodedField dexEncodedField : supportedFields) {
+ biConsumer.accept(clazz, dexEncodedField);
+ }
+ }
+
void addSupportedMethod(DexEncodedMethod method) {
assert method.getHolderType() == clazz.type;
- supportedMethods.put(method.getReference(), method);
+ supportedMethods.add(method);
+ }
+
+ void addSupportedField(DexEncodedField field) {
+ assert field.getHolderType() == clazz.type;
+ supportedFields.add(field);
}
void annotateClass(ClassAnnotation annotation) {
@@ -119,18 +150,26 @@
methodAnnotations.put(method, annotation.combine(prev));
}
+ void annotateField(DexField field, FieldAnnotation annotation) {
+ assert field.getHolderType() == clazz.type;
+ FieldAnnotation prev = fieldAnnotations.getOrDefault(field, FieldAnnotation.getDefault());
+ fieldAnnotations.put(field, annotation.combine(prev));
+ }
+
MethodAnnotation getMethodAnnotation(DexMethod method) {
return methodAnnotations.get(method);
}
SupportedClass build() {
- List<DexEncodedMethod> supportedMethodsSorted = new ArrayList<>(supportedMethods.values());
- supportedMethodsSorted.sort(Comparator.comparing(DexEncodedMethod::getReference));
+ supportedMethods.sort(Comparator.comparing(DexEncodedMethod::getReference));
+ supportedFields.sort(Comparator.comparing(DexEncodedField::getReference));
return new SupportedClass(
clazz,
classAnnotation,
- ImmutableList.copyOf(supportedMethodsSorted),
- methodAnnotations);
+ ImmutableList.copyOf(supportedMethods),
+ ImmutableList.copyOf(supportedFields),
+ methodAnnotations,
+ fieldAnnotations);
}
}
}
@@ -155,6 +194,12 @@
.forEach(classBuilder -> classBuilder.forEachMethod(biConsumer));
}
+ void forEachClassAndField(BiConsumer<DexClass, DexEncodedField> biConsumer) {
+ supportedClassBuilders
+ .values()
+ .forEach(classBuilder -> classBuilder.forEachField(biConsumer));
+ }
+
void addSupportedMethod(DexClass holder, DexEncodedMethod method) {
SupportedClass.Builder classBuilder =
supportedClassBuilders.computeIfAbsent(
@@ -162,6 +207,13 @@
classBuilder.addSupportedMethod(method);
}
+ void addSupportedField(DexClass holder, DexEncodedField field) {
+ SupportedClass.Builder classBuilder =
+ supportedClassBuilders.computeIfAbsent(
+ holder.type, clazz -> SupportedClass.builder(holder));
+ classBuilder.addSupportedField(field);
+ }
+
void annotateClass(DexType type, ClassAnnotation annotation) {
SupportedClass.Builder classBuilder = supportedClassBuilders.get(type);
assert classBuilder != null;
@@ -174,6 +226,12 @@
classBuilder.annotateMethod(method, annotation);
}
+ void annotateField(DexField field, FieldAnnotation annotation) {
+ SupportedClass.Builder classBuilder = supportedClassBuilders.get(field.getHolderType());
+ assert classBuilder != null;
+ classBuilder.annotateField(field, annotation);
+ }
+
void annotateMethodIfPresent(DexMethod method, MethodAnnotation annotation) {
SupportedClass.Builder classBuilder = supportedClassBuilders.get(method.getHolderType());
if (classBuilder == null) {
@@ -219,62 +277,17 @@
}
}
- public static class MethodAnnotation {
-
- private static final MethodAnnotation COVARIANT_RETURN_SUPPORTED =
- new MethodAnnotation(false, false, true, false, -1, -1);
- private static final MethodAnnotation DEFAULT =
- new MethodAnnotation(false, false, false, false, -1, -1);
- private static final MethodAnnotation PARALLEL_STREAM_METHOD =
- new MethodAnnotation(true, false, false, false, -1, -1);
- private static final MethodAnnotation MISSING_FROM_LATEST_ANDROID_JAR =
- new MethodAnnotation(false, true, false, false, -1, -1);
-
- // ParallelStream methods are not supported when the runtime api level is strictly below 21.
- final boolean parallelStreamMethod;
- // Methods not in the latest android jar but still fully supported.
- final boolean missingFromLatestAndroidJar;
- // Methods not supported in a given min api range.
+ public abstract static class MemberAnnotation {
final boolean unsupportedInMinApiRange;
- final boolean covariantReturnSupported;
final int minRange;
final int maxRange;
- MethodAnnotation(
- boolean parallelStreamMethod,
- boolean missingFromLatestAndroidJar,
- boolean covariantReturnSupported,
- boolean unsupportedInMinApiRange,
- int minRange,
- int maxRange) {
- this.parallelStreamMethod = parallelStreamMethod;
- this.missingFromLatestAndroidJar = missingFromLatestAndroidJar;
- this.covariantReturnSupported = covariantReturnSupported;
+ MemberAnnotation(boolean unsupportedInMinApiRange, int minRange, int maxRange) {
this.unsupportedInMinApiRange = unsupportedInMinApiRange;
this.minRange = minRange;
this.maxRange = maxRange;
}
- public static MethodAnnotation getCovariantReturnSupported() {
- return COVARIANT_RETURN_SUPPORTED;
- }
-
- public static MethodAnnotation getDefault() {
- return DEFAULT;
- }
-
- public static MethodAnnotation getParallelStreamMethod() {
- return PARALLEL_STREAM_METHOD;
- }
-
- public static MethodAnnotation getMissingFromLatestAndroidJar() {
- return MISSING_FROM_LATEST_ANDROID_JAR;
- }
-
- public static MethodAnnotation createMissingInMinApi(int api) {
- return new MethodAnnotation(false, false, false, true, api, api);
- }
-
public boolean isUnsupportedInMinApiRange() {
return unsupportedInMinApiRange;
}
@@ -287,17 +300,7 @@
return maxRange;
}
- public boolean isCovariantReturnSupported() {
- return covariantReturnSupported;
- }
-
- public MethodAnnotation combine(MethodAnnotation other) {
- if (this == getDefault()) {
- return other;
- }
- if (other == getDefault()) {
- return this;
- }
+ int combineRange(MemberAnnotation other) {
int newMin, newMax;
if (!unsupportedInMinApiRange && !other.unsupportedInMinApiRange) {
newMin = newMax = -1;
@@ -325,6 +328,106 @@
}
}
}
+ assert newMax < (1 << 15) && newMin < (1 << 15);
+ return (newMax << 16) + newMin;
+ }
+ }
+
+ public static class FieldAnnotation extends MemberAnnotation {
+
+ private static final FieldAnnotation DEFAULT = new FieldAnnotation(false, -1, -1);
+
+ FieldAnnotation(boolean unsupportedInMinApiRange, int minRange, int maxRange) {
+ super(unsupportedInMinApiRange, minRange, maxRange);
+ }
+
+ public static FieldAnnotation getDefault() {
+ return DEFAULT;
+ }
+
+ public static FieldAnnotation createMissingInMinApi(int api) {
+ return new FieldAnnotation(true, api, api);
+ }
+
+ public FieldAnnotation combine(FieldAnnotation other) {
+ if (this == getDefault()) {
+ return other;
+ }
+ if (other == getDefault()) {
+ return this;
+ }
+ int newRange = combineRange(other);
+ int newMax = newRange >> 16;
+ int newMin = newRange & 0xFF;
+ return new FieldAnnotation(
+ unsupportedInMinApiRange || other.unsupportedInMinApiRange, newMin, newMax);
+ }
+ }
+
+ public static class MethodAnnotation extends MemberAnnotation {
+
+ private static final MethodAnnotation COVARIANT_RETURN_SUPPORTED =
+ new MethodAnnotation(false, false, true, false, -1, -1);
+ private static final MethodAnnotation DEFAULT =
+ new MethodAnnotation(false, false, false, false, -1, -1);
+ private static final MethodAnnotation PARALLEL_STREAM_METHOD =
+ new MethodAnnotation(true, false, false, false, -1, -1);
+ private static final MethodAnnotation MISSING_FROM_LATEST_ANDROID_JAR =
+ new MethodAnnotation(false, true, false, false, -1, -1);
+
+ // ParallelStream methods are not supported when the runtime api level is strictly below 21.
+ final boolean parallelStreamMethod;
+ // Methods not in the latest android jar but still fully supported.
+ final boolean missingFromLatestAndroidJar;
+ // Methods not supported in a given min api range.
+ final boolean covariantReturnSupported;
+ MethodAnnotation(
+ boolean parallelStreamMethod,
+ boolean missingFromLatestAndroidJar,
+ boolean covariantReturnSupported,
+ boolean unsupportedInMinApiRange,
+ int minRange,
+ int maxRange) {
+ super(unsupportedInMinApiRange, minRange, maxRange);
+ this.parallelStreamMethod = parallelStreamMethod;
+ this.missingFromLatestAndroidJar = missingFromLatestAndroidJar;
+ this.covariantReturnSupported = covariantReturnSupported;
+ }
+
+ public static MethodAnnotation getCovariantReturnSupported() {
+ return COVARIANT_RETURN_SUPPORTED;
+ }
+
+ public static MethodAnnotation getDefault() {
+ return DEFAULT;
+ }
+
+ public static MethodAnnotation getParallelStreamMethod() {
+ return PARALLEL_STREAM_METHOD;
+ }
+
+ public static MethodAnnotation getMissingFromLatestAndroidJar() {
+ return MISSING_FROM_LATEST_ANDROID_JAR;
+ }
+
+ public static MethodAnnotation createMissingInMinApi(int api) {
+ return new MethodAnnotation(false, false, false, true, api, api);
+ }
+
+ public boolean isCovariantReturnSupported() {
+ return covariantReturnSupported;
+ }
+
+ public MethodAnnotation combine(MethodAnnotation other) {
+ if (this == getDefault()) {
+ return other;
+ }
+ if (other == getDefault()) {
+ return this;
+ }
+ int newRange = combineRange(other);
+ int newMax = newRange >> 16;
+ int newMin = newRange & 0xFF;
return new MethodAnnotation(
parallelStreamMethod || other.parallelStreamMethod,
missingFromLatestAndroidJar || other.missingFromLatestAndroidJar,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedMethodsGenerator.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClassesGenerator.java
similarity index 87%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedMethodsGenerator.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClassesGenerator.java
index 752262f..d6c50b4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedMethodsGenerator.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClassesGenerator.java
@@ -15,12 +15,14 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DirectMappedDexApplication;
+import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
@@ -28,6 +30,7 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
import com.android.tools.r8.ir.desugar.desugaredlibrary.lint.SupportedClasses.ClassAnnotation;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.lint.SupportedClasses.FieldAnnotation;
import com.android.tools.r8.ir.desugar.desugaredlibrary.lint.SupportedClasses.MethodAnnotation;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.shaking.MainDexInfo;
@@ -47,13 +50,13 @@
import java.util.Set;
import java.util.concurrent.ExecutorService;
-public class SupportedMethodsGenerator {
+public class SupportedClassesGenerator {
private static final String ANDROID_JAR_PATTERN = "third_party/android_jar/lib-v%d/android.jar";
private final InternalOptions options;
- public SupportedMethodsGenerator(InternalOptions options) {
+ public SupportedClassesGenerator(InternalOptions options) {
this.options = options;
}
@@ -61,7 +64,7 @@
throws IOException {
SupportedClasses.Builder builder = SupportedClasses.builder();
// First analyze everything which is supported when desugaring for api 1.
- collectSupportedMethodsInB(desugaredLibraryImplementation, specification, builder);
+ collectSupportedMembersInB(desugaredLibraryImplementation, specification, builder);
// Second annotate all apis which are partially and/or fully supported.
AndroidApp library =
AndroidApp.builder()
@@ -71,7 +74,7 @@
new ApplicationReader(library, options, Timing.empty()).read().toDirect();
annotateMethodsNotOnLatestAndroidJar(appForMax, builder);
annotateParallelMethods(builder);
- annotatePartialDesugaringMethods(builder, specification);
+ annotatePartialDesugaringMembers(builder, specification);
annotateClasses(builder, appForMax);
return builder.build();
}
@@ -103,7 +106,7 @@
});
}
- private void annotatePartialDesugaringMethods(
+ private void annotatePartialDesugaringMembers(
SupportedClasses.Builder builder, Path specification) throws IOException {
for (int api = AndroidApiLevel.K.getLevel();
api <= MAX_TESTED_ANDROID_API_LEVEL.getLevel();
@@ -149,8 +152,7 @@
if (machineSpecification.getEmulatedInterfaces().containsKey(dexMethod.getHolderType())
&& encodedMethod.isStatic()) {
// Static methods on emulated interfaces are always supported if the emulated
- // interface is
- // supported.
+ // interface is supported.
return;
}
MethodResolutionResult methodResolutionResult =
@@ -163,6 +165,23 @@
builder.annotateMethod(dexMethod, MethodAnnotation.createMissingInMinApi(finalApi));
}
});
+
+ builder.forEachClassAndField(
+ (clazz, encodedField) -> {
+ if (machineSpecification.isContextTypeMaintainedOrRewritten(
+ encodedField.getHolderType())
+ || machineSpecification
+ .getStaticFieldRetarget()
+ .containsKey(encodedField.getReference())) {
+ return;
+ }
+ FieldResolutionResult fieldResolutionResult =
+ appInfo.resolveField(encodedField.getReference());
+ if (fieldResolutionResult.isFailedResolution()) {
+ builder.annotateField(
+ encodedField.getReference(), FieldAnnotation.createMissingInMinApi(finalApi));
+ }
+ });
}
}
@@ -193,7 +212,7 @@
return Paths.get(jar);
}
- private void collectSupportedMethodsInB(
+ private void collectSupportedMembersInB(
Collection<Path> desugaredLibraryImplementation,
Path specification,
SupportedClasses.Builder builder)
@@ -264,6 +283,12 @@
builder.addSupportedMethod(clazz, method);
}
addBackports(clazz, backports, builder, amendedAppForMax);
+ for (DexEncodedField field : clazz.fields()) {
+ if (!field.isPublic() && !field.isProtected()) {
+ continue;
+ }
+ builder.addSupportedField(clazz, field);
+ }
}
}
}
@@ -284,6 +309,24 @@
assert dexEncodedMethod != null;
builder.addSupportedMethod(dexClass, dexEncodedMethod);
});
+
+ machineSpecification
+ .getStaticFieldRetarget()
+ .forEach(
+ (field, rewritten) -> {
+ DexClass dexClass = implementationApplication.definitionFor(field.getHolderType());
+ if (dexClass != null) {
+ DexEncodedField dexEncodedField = dexClass.lookupField(field);
+ if (dexEncodedField != null) {
+ builder.addSupportedField(dexClass, dexEncodedField);
+ return;
+ }
+ }
+ dexClass = amendedAppForMax.definitionFor(field.getHolderType());
+ DexEncodedField dexEncodedField = dexClass.lookupField(field);
+ assert dexEncodedField != null;
+ builder.addSupportedField(dexClass, dexEncodedField);
+ });
}
private void addBackports(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PartialDesugaringTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PartialDesugaringTest.java
index 7240267..6e3ea69 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PartialDesugaringTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PartialDesugaringTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_MINIMAL;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
@@ -12,9 +13,12 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMember;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.ir.desugar.desugaredlibrary.lint.SupportedClasses;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.lint.SupportedMethodsGenerator;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.lint.SupportedClasses.MemberAnnotation;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.lint.SupportedClassesGenerator;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.ImmutableList;
@@ -116,36 +120,66 @@
+ " java.time.format.DateTimeFormatterBuilder.appendGenericZoneText(java.time.format.TextStyle,"
+ " java.util.Set)");
+ private static final Set<String> FAILURES_JAPANESE_ERA =
+ ImmutableSet.of("Field java.time.chrono.JapaneseEra java.time.chrono.JapaneseEra.REIWA");
+
@Test
public void test() throws Exception {
SupportedClasses supportedClasses =
- new SupportedMethodsGenerator(new InternalOptions())
+ new SupportedClassesGenerator(new InternalOptions())
.run(librarySpecification.getDesugarJdkLibs(), librarySpecification.getSpecification());
for (AndroidApiLevel api : getRelevantApiLevels()) {
- Set<DexMethod> localFailures = Sets.newIdentityHashSet();
+
+ Set<DexMethod> localMethodFailures = Sets.newIdentityHashSet();
+ Set<DexField> localFieldFailures = Sets.newIdentityHashSet();
+
supportedClasses.forEachClass(
- supportedClass ->
- supportedClass.forEachMethodAndAnnotation(
- (method, annotation) -> {
- if (annotation != null && annotation.isUnsupportedInMinApiRange()) {
- if (api.getLevel() >= annotation.getMinRange()
- && api.getLevel() <= annotation.getMaxRange()) {
- localFailures.add(method.getReference());
- }
- }
- }));
- Set<String> expectedFailures = getExpectedFailures(api);
- Set<String> apiFailuresString =
- localFailures.stream().map(DexMethod::toString).collect(Collectors.toSet());
- if (!expectedFailures.equals(apiFailuresString)) {
- System.out.println("Failure for api " + api);
- assertEquals(expectedFailures, apiFailuresString);
- }
+ supportedClass -> {
+ supportedClass.forEachMethodAndAnnotation(
+ (method, annotation) -> {
+ if (missingFromRange(api, annotation)) {
+ localMethodFailures.add(method.getReference());
+ }
+ });
+ supportedClass.forEachFieldAndAnnotation(
+ (field, annotation) -> {
+ if (missingFromRange(api, annotation)) {
+ localFieldFailures.add(field.getReference());
+ }
+ });
+ });
+
+ assertStringEqualsAtApi(localFieldFailures, getExpectedFieldFailures(api), api);
+ assertStringEqualsAtApi(localMethodFailures, getExpectedMethodFailures(api), api);
}
}
- private Set<String> getExpectedFailures(AndroidApiLevel api) {
+ private void assertStringEqualsAtApi(
+ Set<? extends DexMember<?, ?>> found, Set<String> expected, AndroidApiLevel api) {
+ Set<String> apiFailuresString =
+ found.stream().map(DexMember::toString).collect(Collectors.toSet());
+ assertEquals("Failure for api " + api, expected, apiFailuresString);
+ }
+
+ private boolean missingFromRange(AndroidApiLevel api, MemberAnnotation annotation) {
+ if (annotation != null && annotation.isUnsupportedInMinApiRange()) {
+ return api.getLevel() >= annotation.getMinRange()
+ && api.getLevel() <= annotation.getMaxRange();
+ }
+ return false;
+ }
+
+ private Set<String> getExpectedFieldFailures(AndroidApiLevel api) {
+ if (librarySpecification == JDK11 || librarySpecification == JDK11_PATH) {
+ if (api.isGreaterThanOrEqualTo(AndroidApiLevel.O) && api.isLessThan(AndroidApiLevel.R)) {
+ return FAILURES_JAPANESE_ERA;
+ }
+ }
+ return ImmutableSet.of();
+ }
+
+ private Set<String> getExpectedMethodFailures(AndroidApiLevel api) {
Set<String> expectedFailures = new HashSet<>();
boolean jdk11NonMinimal = librarySpecification != JDK8 && librarySpecification != JDK11_MINIMAL;
if (jdk11NonMinimal && api.isGreaterThanOrEqualTo(AndroidApiLevel.N)) {