R8 nest warning and errors

- Tree pruner works with incomplete nest
- Either NestDesugaring or NestReducer raise
  nest warnings and errors.
- Basic version of Nest Reducer added, it is
  an alternative to desugaring for the Cf back-end
  and it tries to remove nests if they do not use
  nest access control.

Bug:132682295
Change-Id: Ib9ac6e1abe4ce513a00ce67fe0b69967bef9ed93
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 0e69108..e92c6f5 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -29,6 +29,7 @@
 import com.android.tools.r8.ir.desugar.R8NestBasedAccessDesugaring;
 import com.android.tools.r8.ir.optimize.EnumOrdinalMapCollector;
 import com.android.tools.r8.ir.optimize.MethodPoolCollection;
+import com.android.tools.r8.ir.optimize.NestReducer;
 import com.android.tools.r8.ir.optimize.SwitchMapCollector;
 import com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization;
 import com.android.tools.r8.ir.optimize.UnusedArgumentsCollector;
@@ -425,7 +426,7 @@
 
       AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
       appView.setGraphLense(new MemberRebindingAnalysis(appViewWithLiveness).run());
-      if (options.enableNestBasedAccessDesugaring) {
+      if (options.enableNestBasedAccessDesugaring && !options.canUseNestBasedAccess()) {
         timing.begin("NestBasedAccessDesugaring");
         R8NestBasedAccessDesugaring analyzer = new R8NestBasedAccessDesugaring(appViewWithLiveness);
         boolean changed =
@@ -437,6 +438,14 @@
                   .rewrittenWithLense(application.asDirect(), appView.graphLense()));
         }
         timing.end();
+      } else {
+        timing.begin("NestReduction");
+        // This pass attempts to reduce the number of nests and nest size
+        // to allow further passes, specifically the class mergers, to do
+        // a better job. This pass is better run before the class merger
+        // but after the publicizer (cannot be run as part of the Enqueuer).
+        new NestReducer(appViewWithLiveness).run(executorService);
+        timing.end();
       }
       if (options.enableHorizontalClassMerging) {
         timing.begin("HorizontalStaticClassMerger");
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
index fc21c3d..0f3944d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/D8NestBasedAccessDesugaring.java
@@ -152,4 +152,14 @@
   protected boolean shouldProcessClassInNest(DexClass clazz, List<DexType> nest) {
     return clazz.isNotProgramClass();
   }
+
+  @Override
+  void reportMissingNestHost(DexClass clazz) {
+    appView.options().nestDesugaringWarningMissingNestHost(clazz);
+  }
+
+  @Override
+  void reportIncompleteNest(List<DexType> nest) {
+    appView.options().nestDesugaringWarningIncompleteNest(nest, appView);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
index 8564183..ddef220 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
@@ -5,9 +5,6 @@
 package com.android.tools.r8.ir.desugar;
 
 import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.errors.IncompleteNestNestDesugarDiagnosic;
-import com.android.tools.r8.errors.MissingNestHostNestDesugarDiagnostic;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ClassAccessFlags;
@@ -26,9 +23,7 @@
 import com.android.tools.r8.graph.NestMemberClassAttribute;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.code.Invoke;
-import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.SynthesizedOrigin;
-import com.android.tools.r8.position.Position;
 import com.android.tools.r8.utils.BooleanUtils;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -76,7 +71,11 @@
     return nestConstructor.type;
   }
 
-  protected DexClass definitionFor(DexType type) {
+  abstract void reportMissingNestHost(DexClass clazz);
+
+  abstract void reportIncompleteNest(List<DexType> nest);
+
+  DexClass definitionFor(DexType type) {
     return appView.definitionFor(appView.graphLense().lookupType(type));
   }
 
@@ -145,79 +144,6 @@
 
   protected abstract boolean shouldProcessClassInNest(DexClass clazz, List<DexType> nest);
 
-  private void reportIncompleteNest(List<DexType> nest) {
-    List<String> programClassesFromNest = new ArrayList<>();
-    List<String> unavailableClasses = new ArrayList<>();
-    List<String> classPathClasses = new ArrayList<>();
-    List<String> libraryClasses = new ArrayList<>();
-    DexClass availableProgramClass = null;
-    for (DexType type : nest) {
-      DexClass clazz = definitionFor(type);
-      if (clazz == null) {
-        unavailableClasses.add(type.getName());
-      } else if (clazz.isLibraryClass()) {
-        libraryClasses.add(type.getName());
-      } else if (clazz.isProgramClass()) {
-        programClassesFromNest.add(type.getName());
-        availableProgramClass = clazz;
-      } else {
-        assert clazz.isClasspathClass();
-        classPathClasses.add(type.getName());
-      }
-    }
-    StringBuilder stringBuilder =
-        new StringBuilder("Compilation of classes ")
-            .append(String.join(", ", programClassesFromNest))
-            .append(" requires its nest mates ");
-    if (!unavailableClasses.isEmpty()) {
-      stringBuilder.append(String.join(", ", unavailableClasses)).append(" (unavailable) ");
-    }
-    if (!libraryClasses.isEmpty()) {
-      stringBuilder.append(String.join(", ", unavailableClasses)).append(" (on library path) ");
-    }
-    stringBuilder.append("to be on program or class path for compilation to succeed)");
-    if (!classPathClasses.isEmpty()) {
-      stringBuilder
-          .append("(Classes ")
-          .append(String.join(", ", classPathClasses))
-          .append(" from the same nest are on class path).");
-    }
-    if (!libraryClasses.isEmpty()) {
-      throw new CompilationError(stringBuilder.toString());
-    }
-    Origin origin;
-    if (availableProgramClass == null) {
-      origin = Origin.unknown();
-    } else {
-      origin = availableProgramClass.getOrigin();
-    }
-    appView
-        .options()
-        .reporter
-        .warning(
-            new IncompleteNestNestDesugarDiagnosic(
-                origin, Position.UNKNOWN, stringBuilder.toString()));
-  }
-
-  private void reportMissingNestHost(DexClass compiledClass) {
-    String nestHostName = compiledClass.getNestHost().getName();
-    String message =
-        "Class "
-            + compiledClass.type.getName()
-            + " requires its nest host "
-            + nestHostName
-            + " to be on program or class path for compilation to succeed.";
-    if (compiledClass.isLibraryClass()) {
-      throw new CompilationError(message);
-    }
-    appView
-        .options()
-        .reporter
-        .warning(
-            new MissingNestHostNestDesugarDiagnostic(
-                compiledClass.getOrigin(), Position.UNKNOWN, message));
-  }
-
   private DexProgramClass createNestAccessConstructor() {
     return new DexProgramClass(
         appView.dexItemFactory().createType(FULL_NEST_CONTRUCTOR_NAME),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java
index 4210ac2..d2a06b9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/R8NestBasedAccessDesugaring.java
@@ -14,8 +14,8 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.utils.ThreadUtils;
+import com.google.common.collect.Sets;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
@@ -41,9 +41,7 @@
 
   public GraphLense run(ExecutorService executorService, DexApplication.Builder<?> appBuilder)
       throws ExecutionException {
-    if (appView.options().canUseNestBasedAccess()) {
-      return appView.graphLense();
-    }
+    assert !appView.options().canUseNestBasedAccess();
     computeAndProcessNestsConcurrently(executorService);
     addDeferredBridgesAndMapMethods();
     clearNestAttributes();
@@ -97,7 +95,8 @@
 
   private void computeAndProcessNestsConcurrently(ExecutorService executorService)
       throws ExecutionException {
-    Set<DexType> nestHosts = Collections.newSetFromMap(new IdentityHashMap<>());
+    Set<DexType> nestHosts = Sets.newIdentityHashSet();
+    ;
     List<Future<?>> futures = new ArrayList<>();
     // It is possible that a nest member is on the program path but its nest host
     // is only in the class path (or missing, raising an error).
@@ -121,4 +120,21 @@
     return true;
   }
 
+  @Override
+  void reportMissingNestHost(DexClass clazz) {
+    if (appView.options().ignoreMissingClasses) {
+      appView.options().nestDesugaringWarningMissingNestHost(clazz);
+    } else {
+      appView.options().errorMissingClassMissingNestHost(clazz);
+    }
+  }
+
+  @Override
+  void reportIncompleteNest(List<DexType> nest) {
+    if (appView.options().ignoreMissingClasses) {
+      appView.options().nestDesugaringWarningIncompleteNest(nest, appView);
+    } else {
+      appView.options().errorMissingClassIncompleteNest(nest, appView);
+    }
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/NestReducer.java b/src/main/java/com/android/tools/r8/ir/optimize/NestReducer.java
new file mode 100644
index 0000000..97c9eb7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/NestReducer.java
@@ -0,0 +1,137 @@
+// Copyright (c) 2019, 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.ir.optimize;
+
+import com.android.tools.r8.graph.AppView;
+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.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.NestMemberClassAttribute;
+import com.android.tools.r8.utils.ThreadUtils;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+// This pass
+// - cleans the nests: it removes missing nest host/members from the input and
+// report them (warning or error).
+// - clears nests which do not use nest based access control to allow other
+// optimizations such as class merging to perform better.
+public class NestReducer {
+
+  private AppView<?> appView;
+
+  public NestReducer(AppView<?> appView) {
+    this.appView = appView;
+  }
+
+  private DexClass definitionFor(DexType type) {
+    assert appView.graphLense().lookupType(type) == type;
+    return appView.definitionFor(appView.graphLense().lookupType(type));
+  }
+
+  public void run(ExecutorService executorService) throws ExecutionException {
+    Set<DexType> nestHosts = Sets.newIdentityHashSet();
+    List<Future<?>> futures = new ArrayList<>();
+    // It is possible that a nest member is on the program path but its nest host
+    // is only in the class path.
+    // Nests are therefore computed the first time a nest member is met, host or not.
+    // The computedNestHosts list is there to avoid processing multiple times the same nest.
+    for (DexProgramClass clazz : appView.appInfo().classes()) {
+      if (clazz.isInANest()) {
+        DexType hostType = clazz.getNestHost();
+        if (!nestHosts.contains(hostType)) {
+          nestHosts.add(hostType);
+          futures.add(
+              executorService.submit(
+                  () -> {
+                    processNestFrom(clazz);
+                    return null; // we want a Callable not a Runnable to be able to throw
+                  }));
+        }
+      }
+    }
+    ThreadUtils.awaitFutures(futures);
+  }
+
+  private void processNestFrom(DexClass clazz) {
+    DexClass nestHost = definitionFor(clazz.getNestHost());
+    if (nestHost == null) {
+      reportMissingNestHost(clazz);
+      clazz.clearNestHost();
+      return;
+    }
+    boolean hasPrivateMembers = hasPrivateMembers(nestHost);
+    Iterator<NestMemberClassAttribute> iterator =
+        nestHost.getNestMembersClassAttributes().iterator();
+    boolean reported = false;
+    while (iterator.hasNext()) {
+      DexClass member = definitionFor(iterator.next().getNestMember());
+      if (member == null) {
+        if (!reported) {
+          reported = true;
+          reportIncompleteNest(nestHost);
+        }
+        iterator.remove();
+      } else {
+        hasPrivateMembers = hasPrivateMembers || hasPrivateMembers(member);
+      }
+    }
+    if (!hasPrivateMembers && appView.options().enableNestReduction) {
+      clearNestAttributes(nestHost);
+    }
+  }
+
+  private void reportMissingNestHost(DexClass clazz) {
+    if (appView.options().ignoreMissingClasses) {
+      appView.options().warningMissingClassMissingNestHost(clazz);
+    } else {
+      appView.options().errorMissingClassMissingNestHost(clazz);
+    }
+  }
+
+  private void reportIncompleteNest(DexClass nestHost) {
+    List<DexType> nest = new ArrayList<>(nestHost.getNestMembersClassAttributes().size() + 1);
+    for (NestMemberClassAttribute attr : nestHost.getNestMembersClassAttributes()) {
+      nest.add(attr.getNestMember());
+    }
+    nest.add(nestHost.type);
+    if (appView.options().ignoreMissingClasses) {
+      appView.options().warningMissingClassIncompleteNest(nest, appView);
+    } else {
+      appView.options().errorMissingClassIncompleteNest(nest, appView);
+    }
+  }
+
+  private void clearNestAttributes(DexClass nestHost) {
+    nestHost.getNestMembersClassAttributes().clear();
+    for (NestMemberClassAttribute attr : nestHost.getNestMembersClassAttributes()) {
+      DexClass member =
+          appView.definitionFor(appView.graphLense().lookupType(attr.getNestMember()));
+      member.clearNestHost();
+    }
+  }
+
+  private boolean hasPrivateMembers(DexClass clazz) {
+    for (DexEncodedMethod method : clazz.methods()) {
+      if (method.accessFlags.isPrivate()) {
+        return true;
+      }
+    }
+    for (DexEncodedField field : clazz.fields()) {
+      if (field.accessFlags.isPrivate()) {
+        return true;
+      }
+    }
+    return false;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index 52b0ce4..97b440d 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -144,21 +144,33 @@
   }
 
   private void clearDeadNestMembers(DexClass nestHost) {
+    // null definition should raise a warning which is raised later on in Nest specific passes.
     nestHost
         .getNestMembersClassAttributes()
-        .removeIf(nestMemberAttr -> !isTypeLive(nestMemberAttr.getNestMember()));
+        .removeIf(
+            nestMemberAttr ->
+                appView.definitionFor(nestMemberAttr.getNestMember()) != null
+                    && !isTypeLive(nestMemberAttr.getNestMember()));
   }
 
   private void claimNestOwnership(DexClass newHost) {
     DexClass previousHost = appView.definitionFor(newHost.getNestHost());
-    assert previousHost != null;
+    if (previousHost == null) {
+      // Nest host will be cleared from all nest members in Nest specific passes.
+      return;
+    }
     newHost.clearNestHost();
     for (NestMemberClassAttribute attr : previousHost.getNestMembersClassAttributes()) {
       if (attr.getNestMember() != newHost.type && isTypeLive(attr.getNestMember())) {
         DexClass nestMember = appView.definitionFor(attr.getNestMember());
-        assert nestMember != null;
-        nestMember.setNestHost(newHost.type);
-        newHost.getNestMembersClassAttributes().add(new NestMemberClassAttribute(nestMember.type));
+        if (nestMember != null) {
+          nestMember.setNestHost(newHost.type);
+        }
+        // We still need to add it, even if the definition is null,
+        // so the warning / error are correctly raised in Nest specific passes.
+        newHost
+            .getNestMembersClassAttributes()
+            .add(new NestMemberClassAttribute(attr.getNestMember()));
       }
     }
   }
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index bd17e99..7fa1866 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -13,9 +13,12 @@
 import com.android.tools.r8.Version;
 import com.android.tools.r8.dex.Marker;
 import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.errors.IncompleteNestNestDesugarDiagnosic;
 import com.android.tools.r8.errors.InterfaceDesugarMissingTypeDiagnostic;
 import com.android.tools.r8.errors.InvalidDebugInfoException;
+import com.android.tools.r8.errors.MissingNestHostNestDesugarDiagnostic;
 import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItem;
@@ -291,6 +294,8 @@
   public boolean enableDesugaring = true;
   // Flag to turn on/off JDK11+ nest-access control
   public boolean enableNestBasedAccessDesugaring = false;
+  // Flag to turn on/off reduction of nest to improve class merging optimizations.
+  public boolean enableNestReduction = true;
   // Defines interface method rewriter behavior.
   public OffOrAuto interfaceMethodDesugaring = OffOrAuto.Auto;
   // Defines try-with-resources rewriter behavior.
@@ -473,6 +478,127 @@
   /** A set of dexitems we have reported missing to dedupe warnings. */
   private final Set<DexItem> reportedMissingForDesugaring = Sets.newConcurrentHashSet();
 
+  public enum NestReportType {
+    FATAL_ERROR,
+    DESUGAR_WARNING,
+    WARNING
+  }
+
+  public void errorMissingClassMissingNestHost(DexClass compiledClass) {
+    throw reporter.fatalError(messageErrorMissingNestHost(compiledClass));
+  }
+
+  public void warningMissingClassMissingNestHost(DexClass compiledClass) {
+    if (compiledClass.isLibraryClass()) {
+      errorMissingClassMissingNestHost(compiledClass);
+    }
+    reporter.warning(new StringDiagnostic(messageWarningMissingNestHost(compiledClass)));
+  }
+
+  public void nestDesugaringWarningMissingNestHost(DexClass compiledClass) {
+    if (compiledClass.isLibraryClass()) {
+      errorMissingClassMissingNestHost(compiledClass);
+    }
+    reporter.warning(
+        new MissingNestHostNestDesugarDiagnostic(
+            compiledClass.getOrigin(),
+            Position.UNKNOWN,
+            messageWarningMissingNestHost(compiledClass)));
+  }
+
+  public void errorMissingClassIncompleteNest(List<DexType> nest, AppView<?> appView) {
+    throw reporter.fatalError(messageErrorIncompleteNest(nest, appView));
+  }
+
+  public void warningMissingClassIncompleteNest(List<DexType> nest, AppView<?> appView) {
+    for (DexType type : nest) {
+      DexClass clazz = appView.definitionFor(type);
+      if (clazz != null && clazz.isLibraryClass()) {
+        errorMissingClassIncompleteNest(nest, appView);
+        return;
+      }
+    }
+    reporter.warning(new StringDiagnostic(messageWarningIncompleteNest(nest, appView)));
+  }
+
+  public void nestDesugaringWarningIncompleteNest(List<DexType> nest, AppView<?> appView) {
+    DexClass availableClass = null;
+    for (DexType type : nest) {
+      DexClass clazz = appView.definitionFor(type);
+      if (clazz != null && clazz.isProgramClass()) {
+        availableClass = clazz;
+      } else if (clazz != null && clazz.isLibraryClass()) {
+        errorMissingClassIncompleteNest(nest, appView);
+        return;
+      }
+    }
+    assert availableClass != null;
+    reporter.warning(
+        new IncompleteNestNestDesugarDiagnosic(
+            availableClass.getOrigin(),
+            Position.UNKNOWN,
+            messageWarningIncompleteNest(nest, appView)));
+  }
+
+  private String messageErrorMissingNestHost(DexClass compiledClass) {
+    String nestHostName = compiledClass.getNestHost().getName();
+    return "Class "
+        + compiledClass.type.getName()
+        + " requires its nest host "
+        + nestHostName
+        + " to be on program or class path. ";
+  }
+
+  private String messageWarningMissingNestHost(DexClass compiledClass) {
+    return messageErrorMissingNestHost(compiledClass)
+        + "Class"
+        + compiledClass.type.getName()
+        + " is considered as not being part of any nest.";
+  }
+
+  private String messageErrorIncompleteNest(List<DexType> nest, AppView<?> appView) {
+    List<String> programClassesFromNest = new ArrayList<>();
+    List<String> unavailableClasses = new ArrayList<>();
+    List<String> classPathClasses = new ArrayList<>();
+    List<String> libraryClasses = new ArrayList<>();
+    for (DexType type : nest) {
+      DexClass clazz = appView.definitionFor(appView.graphLense().lookupType(type));
+      if (clazz == null) {
+        unavailableClasses.add(type.getName());
+      } else if (clazz.isLibraryClass()) {
+        libraryClasses.add(type.getName());
+      } else if (clazz.isProgramClass()) {
+        programClassesFromNest.add(type.getName());
+      } else {
+        assert clazz.isClasspathClass();
+        classPathClasses.add(type.getName());
+      }
+    }
+    StringBuilder stringBuilder =
+        new StringBuilder("Compilation of classes ")
+            .append(String.join(", ", programClassesFromNest))
+            .append(" requires its nest mates ");
+    if (!unavailableClasses.isEmpty()) {
+      stringBuilder.append(String.join(", ", unavailableClasses)).append(" (unavailable) ");
+    }
+    if (!libraryClasses.isEmpty()) {
+      stringBuilder.append(String.join(", ", unavailableClasses)).append(" (on library path) ");
+    }
+    stringBuilder.append("to be on program or class path.");
+    if (!classPathClasses.isEmpty()) {
+      stringBuilder
+          .append("(Classes ")
+          .append(String.join(", ", classPathClasses))
+          .append(" from the same nest are on class path).");
+    }
+    return stringBuilder.toString();
+  }
+
+  private String messageWarningIncompleteNest(List<DexType> nest, AppView<?> appView) {
+    return messageErrorIncompleteNest(nest, appView)
+        + " Unavailable classes are considered as not being part of the nest.";
+  }
+
   public void warningMissingTypeForDesugar(
       Origin origin, Position position, DexType missingType, DexType contextType) {
     if (reportedMissingForDesugaring.add(missingType)) {
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java
index b2adfce..f41f27d 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java
@@ -104,7 +104,11 @@
           .addKeepAllAttributes()
           .setMinApi(parameters.getApiLevel())
           .addProgramFiles(classesOfNest(nestID))
-          .addOptionsModification(options -> options.enableNestBasedAccessDesugaring = true)
+          .addOptionsModification(
+              options -> {
+                options.enableNestBasedAccessDesugaring = true;
+                options.enableNestReduction = false;
+              })
           .compile()
           .run(parameters.getRuntime(), getMainClass(nestID))
           .assertSuccessWithOutput(getExpectedResult(nestID));
@@ -146,6 +150,7 @@
         .addOptionsModification(
             options -> {
               options.enableNestBasedAccessDesugaring = true;
+              options.enableNestReduction = false;
             })
         .addProgramFiles(JAR)
         .setMinApi(minApi)
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
index abc22b7..934de31 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
@@ -94,6 +94,7 @@
                   // unused.
                   options.enableValuePropagation = false;
                   options.enableClassInlining = false;
+                  options.enableNestReduction = false;
                 })
             .enableInliningAnnotations("nestHostExample")
             .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java
index 601e634..48fe91b 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java
@@ -19,6 +19,8 @@
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.errors.IncompleteNestNestDesugarDiagnosic;
+import com.android.tools.r8.errors.MissingNestHostNestDesugarDiagnostic;
 import java.nio.file.Path;
 import java.util.List;
 import org.hamcrest.Matcher;
@@ -49,28 +51,19 @@
 
   @Test
   public void testWarningD8() throws Exception {
-    // TODO (b/132676197): use desugaring handling
     Assume.assumeTrue(parameters.isDexRuntime());
-    testIncompleteNestWarning(true);
-    testMissingNestHostWarning(true);
+    testIncompleteNestWarning(true, true);
+    testMissingNestHostWarning(true, true);
   }
 
   @Test
   public void testWarningR8() throws Exception {
-    // TODO (b/132676197): use desugaring handling
-    // TODO (b/132676197): Cf backend should raise a warning
-    // Remove Assume when fixed.
-    Assume.assumeTrue(parameters.isDexRuntime());
-    testIncompleteNestWarning(false);
-    testMissingNestHostWarning(false);
+    testIncompleteNestWarning(false, parameters.isDexRuntime());
+    testMissingNestHostWarning(false, parameters.isDexRuntime());
   }
 
   @Test
   public void testErrorR8() {
-    // TODO (b/132676197): Cf back should raise an error
-    // TODO (b/132676197): Dex back-end should raise an error
-    // Remove Assume when fixed.
-    Assume.assumeTrue(false);
     testMissingNestHostError();
     testIncompleteNestError();
   }
@@ -111,7 +104,7 @@
       compileOnlyClassesMatching(innerClassMatcher, false, false);
       fail("Should have raised an exception for missing nest host");
     } catch (Exception e) {
-      assertTrue(e.getCause().getMessage().contains("requires its nest host"));
+      assertTrue(e.getCause().getCause().getMessage().contains("requires its nest host"));
     }
   }
 
@@ -121,28 +114,40 @@
       compileOnlyClassesMatching(innerClassMatcher, false, false);
       fail("Should have raised an exception for incomplete nest");
     } catch (Exception e) {
-      assertTrue(e.getCause().getMessage().contains("requires its nest mates"));
+      assertTrue(e.getCause().getCause().getMessage().contains("requires its nest mates"));
     }
   }
 
-  private void testMissingNestHostWarning(boolean d8) throws Exception {
+  private void testMissingNestHostWarning(boolean d8, boolean desugarWarning) throws Exception {
     Matcher<String> innerClassMatcher =
         containsString("BasicNestHostWithInnerClassMethods$BasicNestedClass");
     TestCompileResult compileResult = compileOnlyClassesMatching(innerClassMatcher, d8, true);
     assertTrue(compileResult.getDiagnosticMessages().getWarnings().size() >= 1);
-    assertTrue(
-        compileResult.getDiagnosticMessages().getWarnings().stream()
-            .anyMatch(
-                warning -> warning.getDiagnosticMessage().contains("requires its nest host")));
+    if (desugarWarning) {
+      assertTrue(
+          compileResult.getDiagnosticMessages().getWarnings().stream()
+              .anyMatch(warn -> warn instanceof MissingNestHostNestDesugarDiagnostic));
+    } else if (!d8) {
+      // R8 should raise extra warning when cleaning the nest.
+      assertTrue(
+          compileResult.getDiagnosticMessages().getWarnings().stream()
+              .anyMatch(warn -> warn.getDiagnosticMessage().contains("requires its nest host")));
+    }
   }
 
-  private void testIncompleteNestWarning(boolean d8) throws Exception {
+  private void testIncompleteNestWarning(boolean d8, boolean desugarWarning) throws Exception {
     Matcher<String> innerClassMatcher = endsWith("BasicNestHostWithInnerClassMethods");
     TestCompileResult compileResult = compileOnlyClassesMatching(innerClassMatcher, d8, true);
     assertTrue(compileResult.getDiagnosticMessages().getWarnings().size() >= 1);
-    assertTrue(
-        compileResult.getDiagnosticMessages().getWarnings().stream()
-            .anyMatch(
-                warning -> warning.getDiagnosticMessage().contains("requires its nest mates")));
+    if (desugarWarning) {
+      assertTrue(
+          compileResult.getDiagnosticMessages().getWarnings().stream()
+              .anyMatch(warn -> warn instanceof IncompleteNestNestDesugarDiagnosic));
+    } else if (!d8) {
+      // R8 should raise extra warning when cleaning the nest.
+      assertTrue(
+          compileResult.getDiagnosticMessages().getWarnings().stream()
+              .anyMatch(warn -> warn.getDiagnosticMessage().contains("requires its nest mates")));
+    }
   }
 }