Version 2.16.0-80.0.dev

Merge commit '3bfb2db3d0b7dfc492be19cd026c9e900653ef79' into 'dev'
diff --git a/pkg/compiler/lib/compiler_new.dart b/pkg/compiler/lib/compiler_new.dart
index 4b1d89f..5a4ccc8 100644
--- a/pkg/compiler/lib/compiler_new.dart
+++ b/pkg/compiler/lib/compiler_new.dart
@@ -82,6 +82,9 @@
   /// Deferred map output.
   deferredMap,
 
+  /// Unused libraries output.
+  dumpUnusedLibraries,
+
   /// Implementation specific output used for debugging the compiler.
   debug,
 }
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 8737b26..18fa4cb 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -175,6 +175,9 @@
   // For backward compatibility the option is still accepted, but it is ignored.
   static const String initializingFormalAccess = '--initializing-formal-access';
 
+  // Whether or not to dump a list of unused libraries.
+  static const String dumpUnusedLibraries = '--dump-unused-libraries';
+
   // Experimental flags.
   static const String resolveOnly = '--resolve-only';
 
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 49838e5..146e093 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -5,6 +5,7 @@
 library dart2js.compiler_base;
 
 import 'dart:async' show Future;
+import 'dart:convert' show jsonEncode;
 
 import 'package:front_end/src/api_unstable/dart2js.dart'
     show clearStringTokenCanonicalizer;
@@ -246,6 +247,31 @@
     return options.readClosedWorldUri != null && options.readDataUri != null;
   }
 
+  /// Dumps a list of unused [ir.Library]'s in the [KernelResult]. This *must*
+  /// be called before [setMainAndTrimComponent], because that method will
+  /// discard the unused [ir.Library]s.
+  void dumpUnusedLibraries(KernelResult result) {
+    var usedUris = result.libraries.toSet();
+    bool isUnused(ir.Library l) => !usedUris.contains(l.importUri);
+    String libraryString(ir.Library library) {
+      return '${library.importUri}(${library.fileUri})';
+    }
+
+    var unusedLibraries =
+        result.component.libraries.where(isUnused).map(libraryString).toList();
+    unusedLibraries.sort();
+    var jsonLibraries = jsonEncode(unusedLibraries);
+    outputProvider.createOutputSink(options.outputUri.pathSegments.last,
+        'unused.json', api.OutputType.dumpUnusedLibraries)
+      ..add(jsonLibraries)
+      ..close();
+    reporter.reportInfo(
+        reporter.createMessage(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, {
+      'text': "${unusedLibraries.length} unused libraries out of "
+          "${result.component.libraries.length}. Dumping to JSON."
+    }));
+  }
+
   Future runInternal() async {
     clearState();
     var compilationTarget = options.compilationTarget;
@@ -324,6 +350,9 @@
         // deserialized modular data because some of this data may reference
         // 'trimmed' elements.
         if (options.fromDill) {
+          if (options.dumpUnusedLibraries) {
+            dumpUnusedLibraries(result);
+          }
           if (options.entryUri != null) {
             result.setMainAndTrimComponent(options.entryUri);
           }
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 7df673c..8a49df4 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -627,6 +627,7 @@
     OptionHandler(Flags.benchmarkingExperiment, passThrough),
     OptionHandler(Flags.soundNullSafety, setNullSafetyMode),
     OptionHandler(Flags.noSoundNullSafety, setNullSafetyMode),
+    OptionHandler(Flags.dumpUnusedLibraries, passThrough),
 
     // TODO(floitsch): remove conditional directives flag.
     // We don't provide the info-message yet, since we haven't publicly
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 79d15b9..d78db4c 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -564,6 +564,9 @@
   /// Verbosity level used for filtering messages during compilation.
   fe.Verbosity verbosity = fe.Verbosity.all;
 
+  // Whether or not to dump a list of unused libraries.
+  bool dumpUnusedLibraries = false;
+
   late FeatureOptions features;
 
   // -------------------------------------------------
@@ -690,6 +693,7 @@
       .._noSoundNullSafety = _hasOption(options, Flags.noSoundNullSafety)
       .._mergeFragmentsThreshold =
           _extractIntOption(options, '${Flags.mergeFragmentsThreshold}=')
+      ..dumpUnusedLibraries = _hasOption(options, Flags.dumpUnusedLibraries)
       ..cfeInvocationModes = fe.InvocationMode.parseArguments(
           _extractStringOption(options, '${Flags.cfeInvocationModes}=', '')!,
           onError: onError)
diff --git a/pkg/compiler/lib/src/source_file_provider.dart b/pkg/compiler/lib/src/source_file_provider.dart
index cc5e875..359fead 100644
--- a/pkg/compiler/lib/src/source_file_provider.dart
+++ b/pkg/compiler/lib/src/source_file_provider.dart
@@ -351,6 +351,7 @@
         uri = out.resolve('$name.$extension');
         break;
       case OutputType.dumpInfo:
+      case OutputType.dumpUnusedLibraries:
       case OutputType.deferredMap:
         if (name == '') {
           name = out.pathSegments.last;
diff --git a/tools/VERSION b/tools/VERSION
index e431a95..7ba8c56 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 16
 PATCH 0
-PRERELEASE 79
+PRERELEASE 80
 PRERELEASE_PATCH 0
\ No newline at end of file