Merge commit 'fb689fd74919f5298d94b300f3dcf98234a4b22e' into dev-release
diff --git a/infra/config/global/generated/cr-buildbucket.cfg b/infra/config/global/generated/cr-buildbucket.cfg
index 73e65b4..577a0d0 100644
--- a/infra/config/global/generated/cr-buildbucket.cfg
+++ b/infra/config/global/generated/cr-buildbucket.cfg
@@ -471,6 +471,80 @@
       }
     }
     builders {
+      name: "linux-android-14.0.0"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
+      dimensions: "os:Ubuntu-18.04"
+      dimensions: "pool:luci.r8.ci"
+      exe {
+        cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
+        cipd_version: "refs/heads/master"
+        cmd: "luciexe"
+      }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=14.0.0",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
+      priority: 26
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      build_numbers: YES
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+    }
+    builders {
+      name: "linux-android-14.0.0_release"
+      swarming_host: "chrome-swarming.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "normal:true"
+      dimensions: "os:Ubuntu-18.04"
+      dimensions: "pool:luci.r8.ci"
+      exe {
+        cipd_package: "infra_internal/recipe_bundles/chrome-internal.googlesource.com/chrome/tools/build_limited/scripts/slave"
+        cipd_version: "refs/heads/master"
+        cmd: "luciexe"
+      }
+      properties:
+        '{'
+        '  "builder_group": "internal.client.r8",'
+        '  "recipe": "rex",'
+        '  "test_options": ['
+        '    "--dex_vm=14.0.0",'
+        '    "--all_tests",'
+        '    "--tool=r8",'
+        '    "--no_internal",'
+        '    "--one_line_per_test",'
+        '    "--archive_failures"'
+        '  ]'
+        '}'
+      priority: 26
+      execution_timeout_secs: 21600
+      expiration_secs: 126000
+      build_numbers: YES
+      service_account: "r8-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+    }
+    builders {
       name: "linux-android-4.0.4"
       swarming_host: "chrome-swarming.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/global/generated/luci-milo.cfg b/infra/config/global/generated/luci-milo.cfg
index c550e41..b1481fe 100644
--- a/infra/config/global/generated/luci-milo.cfg
+++ b/infra/config/global/generated/luci-milo.cfg
@@ -96,6 +96,11 @@
     short_name: "13.0.0"
   }
   builders {
+    name: "buildbucket/luci.r8.ci/linux-android-14.0.0"
+    category: "R8"
+    short_name: "14.0.0"
+  }
+  builders {
     name: "buildbucket/luci.r8.ci/windows"
     category: "R8"
     short_name: "windows"
@@ -231,6 +236,11 @@
     short_name: "13.0.0"
   }
   builders {
+    name: "buildbucket/luci.r8.ci/linux-android-14.0.0_release"
+    category: "Release|R8"
+    short_name: "14.0.0"
+  }
+  builders {
     name: "buildbucket/luci.r8.ci/windows_release"
     category: "Release|R8"
     short_name: "windows"
diff --git a/infra/config/global/generated/luci-notify.cfg b/infra/config/global/generated/luci-notify.cfg
index c9717b2..fa8d5b0 100644
--- a/infra/config/global/generated/luci-notify.cfg
+++ b/infra/config/global/generated/luci-notify.cfg
@@ -132,6 +132,30 @@
   }
   builders {
     bucket: "ci"
+    name: "linux-android-14.0.0"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-android-14.0.0_release"
+    repository: "https://r8.googlesource.com/r8"
+  }
+}
+notifiers {
+  notifications {
+    on_failure: true
+    on_new_failure: true
+    notify_blamelist {}
+  }
+  builders {
+    bucket: "ci"
     name: "linux-android-4.0.4"
     repository: "https://r8.googlesource.com/r8"
   }
diff --git a/infra/config/global/generated/luci-scheduler.cfg b/infra/config/global/generated/luci-scheduler.cfg
index b775cde..dbd8f00 100644
--- a/infra/config/global/generated/luci-scheduler.cfg
+++ b/infra/config/global/generated/luci-scheduler.cfg
@@ -195,6 +195,35 @@
   }
 }
 job {
+  id: "linux-android-14.0.0"
+  realm: "ci"
+  acl_sets: "ci"
+  triggering_policy {
+    kind: GREEDY_BATCHING
+    max_concurrent_invocations: 4
+  }
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "ci"
+    builder: "linux-android-14.0.0"
+  }
+}
+job {
+  id: "linux-android-14.0.0_release"
+  realm: "ci"
+  acl_sets: "ci"
+  triggering_policy {
+    kind: GREEDY_BATCHING
+    max_concurrent_invocations: 4
+    max_batch_size: 1
+  }
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "ci"
+    builder: "linux-android-14.0.0_release"
+  }
+}
+job {
   id: "linux-android-4.0.4"
   realm: "ci"
   acl_sets: "ci"
@@ -711,6 +740,17 @@
   }
 }
 trigger {
+  id: "branch-gitiles-8.1-forward"
+  realm: "ci"
+  acl_sets: "ci"
+  triggers: "linux-android-14.0.0_release"
+  gitiles {
+    repo: "https://r8.googlesource.com/r8"
+    refs: "regexp:refs/heads/([8]\\.[1-9]+(\\.[0-9]+)?|[9]\\.[0-9]+(\\.[0-9]+)?)"
+    path_regexps: "src/main/java/com/android/tools/r8/Version.java"
+  }
+}
+trigger {
   id: "branch-gitiles-trigger"
   realm: "ci"
   acl_sets: "ci"
@@ -747,6 +787,7 @@
   triggers: "linux-android-10.0.0"
   triggers: "linux-android-12.0.0"
   triggers: "linux-android-13.0.0"
+  triggers: "linux-android-14.0.0"
   triggers: "linux-android-4.0.4"
   triggers: "linux-android-4.4.4"
   triggers: "linux-android-5.1.1"
diff --git a/infra/config/global/generated/project.cfg b/infra/config/global/generated/project.cfg
index bb18107..90b913a 100644
--- a/infra/config/global/generated/project.cfg
+++ b/infra/config/global/generated/project.cfg
@@ -7,7 +7,7 @@
 name: "r8"
 access: "group:all"
 lucicfg {
-  version: "1.32.1"
+  version: "1.38.1"
   package_dir: ".."
   config_dir: "generated"
   entry_point: "main.star"
diff --git a/infra/config/global/main.star b/infra/config/global/main.star
index 8574aa5..bbbf235 100755
--- a/infra/config/global/main.star
+++ b/infra/config/global/main.star
@@ -109,6 +109,14 @@
 )
 
 luci.gitiles_poller(
+  name = "branch-gitiles-8.1-forward",
+  bucket = "ci",
+  repo = "https://r8.googlesource.com/r8",
+  refs = ["refs/heads/([8]\\.[1-9]+(\\.[0-9]+)?|[9]\\.[0-9]+(\\.[0-9]+)?)"],
+  path_regexps = ["src/main/java/com/android/tools/r8/Version.java"]
+)
+
+luci.gitiles_poller(
   name = "branch-gitiles-3.3-forward",
   bucket = "ci",
   repo = "https://r8.googlesource.com/r8",
@@ -307,6 +315,10 @@
 r8_tester_with_default("linux-android-13.0.0",
     ["--dex_vm=13.0.0", "--all_tests"],
     release_trigger=["branch-gitiles-3.3-forward"])
+r8_tester_with_default("linux-android-14.0.0",
+    ["--dex_vm=14.0.0", "--all_tests"],
+    release_trigger=["branch-gitiles-8.1-forward"])
+
 
 r8_tester_with_default("windows", ["--all_tests"],
     dimensions=get_dimensions(windows=True))
diff --git a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
index ee98d51..96d4bfa 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
@@ -284,7 +284,7 @@
     Builder(InternalOptions options, Timing timing) {
       super(options, timing);
       this.classpathClasses = ClasspathClassCollection.empty();
-      this.libraryClasses = null;
+      this.libraryClasses = LibraryClassCollection.empty();
     }
 
     private Builder(LazyLoadedDexApplication application) {
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 45aa53f..c62d6b1 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
@@ -507,6 +507,15 @@
             .append(" Also supported with covariant return type.")
             .append(HTML_SPLIT);
       }
+      if (!classAnnotation.getUnsupportedFields().isEmpty()) {
+        commentBuilder
+            .append("Some fields (")
+            .append(classAnnotation.getUnsupportedFields().size())
+            .append(") present in Android ")
+            .append(MAX_TESTED_ANDROID_API_LEVEL)
+            .append(" are not supported.")
+            .append(HTML_SPLIT);
+      }
       if (!classAnnotation.getUnsupportedMethods().isEmpty()) {
         commentBuilder
             .append("Some methods (")
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 63dec3c..5bfbe46 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
@@ -51,6 +51,9 @@
 
 public class GenerateLintFiles extends AbstractGenerateFiles {
 
+  // Only recent versions of studio support the format with fields.
+  private static final boolean FORMAT_WITH_FIELD = true;
+
   public static GenerateLintFiles createForTesting(
       Path specification, Set<Path> implementation, Path outputDirectory) throws Exception {
     return new GenerateLintFiles(specification, implementation, outputDirectory);
@@ -181,6 +184,15 @@
                             + method.getReference().proto.toDescriptorString());
                   }
                 });
+            if (FORMAT_WITH_FIELD) {
+              supportedClass.forEachFieldAndAnnotation(
+                  (field, fieldAnnotation) -> {
+                    if (fieldAnnotation == null || !fieldAnnotation.unsupportedInMinApiRange) {
+                      desugaredApisSignatures.add(
+                          classBinaryName + '#' + field.getReference().name);
+                    }
+                  });
+            }
           } else {
             desugaredApisSignatures.add(classBinaryName);
           }
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 8d01c4b..307def9 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
@@ -10,6 +10,7 @@
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.TriConsumer;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSortedMap;
 import java.util.Collection;
@@ -121,8 +122,10 @@
         this.clazz = clazz;
       }
 
-      void forEachMethods(BiConsumer<DexClass, Collection<DexEncodedMethod>> biConsumer) {
-        biConsumer.accept(clazz, supportedMethods.values());
+      public void forEachFieldsAndMethods(
+          TriConsumer<DexClass, Collection<DexEncodedField>, Collection<DexEncodedMethod>>
+              triConsumer) {
+        triConsumer.accept(clazz, supportedFields.values(), supportedMethods.values());
       }
 
       void forEachMethod(BiConsumer<DexClass, DexEncodedMethod> biConsumer) {
@@ -166,10 +169,6 @@
         fieldAnnotations.put(field, annotation.combine(prev));
       }
 
-      MethodAnnotation getMethodAnnotation(DexMethod method) {
-        return methodAnnotations.get(method);
-      }
-
       SupportedClass build() {
         return new SupportedClass(
             clazz,
@@ -196,10 +195,12 @@
       return builder.classAnnotation;
     }
 
-    void forEachClassAndMethods(BiConsumer<DexClass, Collection<DexEncodedMethod>> biConsumer) {
+    void forEachClassFieldsAndMethods(
+        TriConsumer<DexClass, Collection<DexEncodedField>, Collection<DexEncodedMethod>>
+            triConsumer) {
       supportedClassBuilders
           .values()
-          .forEach(classBuilder -> classBuilder.forEachMethods(biConsumer));
+          .forEach(classBuilder -> classBuilder.forEachFieldsAndMethods(triConsumer));
     }
 
     void forEachClassAndMethod(BiConsumer<DexClass, DexEncodedMethod> biConsumer) {
@@ -254,10 +255,16 @@
       annotateMethod(method, annotation);
     }
 
-    MethodAnnotation getMethodAnnotation(DexMethod method) {
-      SupportedClass.Builder classBuilder = supportedClassBuilders.get(method.getHolderType());
+    public Map<DexField, FieldAnnotation> getFieldAnnotations(DexClass clazz) {
+      SupportedClass.Builder classBuilder = supportedClassBuilders.get(clazz.getType());
       assert classBuilder != null;
-      return classBuilder.getMethodAnnotation(method);
+      return classBuilder.fieldAnnotations;
+    }
+
+    Map<DexMethod, MethodAnnotation> getMethodAnnotations(DexClass clazz) {
+      SupportedClass.Builder classBuilder = supportedClassBuilders.get(clazz.getType());
+      assert classBuilder != null;
+      return classBuilder.methodAnnotations;
     }
 
     SupportedClasses build() {
@@ -274,12 +281,18 @@
 
     private final boolean additionalMembersOnClass;
     private final boolean fullySupported;
-    // Methods in latest android.jar but unsupported.
+    // Members in latest android.jar but unsupported.
+    private final List<DexField> unsupportedFields;
     private final List<DexMethod> unsupportedMethods;
 
-    public ClassAnnotation(boolean fullySupported, List<DexMethod> unsupportedMethods) {
+    public ClassAnnotation(
+        boolean fullySupported,
+        List<DexField> unsupportedFields,
+        List<DexMethod> unsupportedMethods) {
       this.additionalMembersOnClass = false;
       this.fullySupported = fullySupported;
+      unsupportedFields.sort(Comparator.naturalOrder());
+      this.unsupportedFields = unsupportedFields;
       unsupportedMethods.sort(Comparator.naturalOrder());
       this.unsupportedMethods = ImmutableList.copyOf(unsupportedMethods);
     }
@@ -287,6 +300,7 @@
     private ClassAnnotation() {
       this.additionalMembersOnClass = true;
       this.fullySupported = false;
+      this.unsupportedFields = ImmutableList.of();
       this.unsupportedMethods = ImmutableList.of();
     }
 
@@ -304,6 +318,10 @@
       return fullySupported;
     }
 
+    public List<DexField> getUnsupportedFields() {
+      return unsupportedFields;
+    }
+
     public List<DexMethod> getUnsupportedMethods() {
       return unsupportedMethods;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClassesGenerator.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClassesGenerator.java
index f286bae..b165a93 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClassesGenerator.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/SupportedClassesGenerator.java
@@ -16,8 +16,11 @@
 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.DexEncodedMember;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMember;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
@@ -82,36 +85,45 @@
 
   private void annotateClasses(
       SupportedClasses.Builder builder, DirectMappedDexApplication appForMax) {
-    builder.forEachClassAndMethods(
-        (clazz, methods) -> {
+    builder.forEachClassFieldsAndMethods(
+        (clazz, fields, methods) -> {
           ClassAnnotation classAnnotation = builder.getClassAnnotation(clazz.type);
           if (classAnnotation != null && classAnnotation.isAdditionalMembersOnClass()) {
             return;
           }
           DexClass maxClass = appForMax.definitionFor(clazz.type);
-          List<DexMethod> missing = new ArrayList<>();
+          List<DexField> missingFields = new ArrayList<>();
+          List<DexMethod> missingMethods = new ArrayList<>();
           boolean fullySupported = true;
-          for (DexEncodedMethod method : maxClass.methods()) {
-            if (!(method.isPublic() || method.isProtectedMethod())) {
-              continue;
-            }
-            // If the method is in android.jar but not in the desugared library, or annotated, then
-            // the class is not marked as fully supported.
-            if (methods.stream().noneMatch(em -> em.getReference() == method.getReference())) {
-              missing.add(method.getReference());
-              fullySupported = false;
-            }
+          fullySupported &= analyzeMissingMembers(maxClass.fields(), fields, missingFields);
+          fullySupported &= analyzeMissingMembers(maxClass.methods(), methods, missingMethods);
+          fullySupported &= builder.getFieldAnnotations(clazz).isEmpty();
+          for (MethodAnnotation methodAnnotation : builder.getMethodAnnotations(clazz).values()) {
+            fullySupported &= methodAnnotation.isCovariantReturnSupported();
           }
-          for (DexEncodedMethod method : clazz.methods()) {
-            MethodAnnotation methodAnnotation = builder.getMethodAnnotation(method.getReference());
-            if (methodAnnotation != null && !methodAnnotation.isCovariantReturnSupported()) {
-              fullySupported = false;
-            }
-          }
-          builder.annotateClass(clazz.type, new ClassAnnotation(fullySupported, missing));
+          builder.annotateClass(
+              clazz.type, new ClassAnnotation(fullySupported, missingFields, missingMethods));
         });
   }
 
+  private <EM extends DexEncodedMember<EM, M>, M extends DexMember<EM, M>>
+      boolean analyzeMissingMembers(
+          Iterable<EM> maxClassMembers, Collection<EM> referenceMembers, List<M> missingMembers) {
+    boolean fullySupported = true;
+    for (EM member : maxClassMembers) {
+      if (!(member.getAccessFlags().isPublic() || member.getAccessFlags().isProtected())) {
+        continue;
+      }
+      // If the field is in android.jar but not in the desugared library, then
+      // the class is not marked as fully supported.
+      if (referenceMembers.stream().noneMatch(em -> em.getReference() == member.getReference())) {
+        missingMembers.add(member.getReference());
+        fullySupported = false;
+      }
+    }
+    return fullySupported;
+  }
+
   private void annotatePartialDesugaringMembers(
       SupportedClasses.Builder builder, Path specification) throws IOException {
     for (int api = AndroidApiLevel.K.getLevel();
diff --git a/src/main/java/com/android/tools/r8/utils/LibraryClassCollection.java b/src/main/java/com/android/tools/r8/utils/LibraryClassCollection.java
index c274aad..d1957a4 100644
--- a/src/main/java/com/android/tools/r8/utils/LibraryClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/LibraryClassCollection.java
@@ -13,6 +13,10 @@
     super(null, classProvider);
   }
 
+  public static LibraryClassCollection empty() {
+    return new LibraryClassCollection(null);
+  }
+
   @Override
   DexLibraryClass resolveClassConflict(DexLibraryClass a, DexLibraryClass b) {
     return a;