Version 2.13.0-213.0.dev

Merge commit 'c5769f66042d1a630d5845ef6fa6eef96cad767a' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index b5ad7d0..e78d7af 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
     "constraint, update this by running tools/generate_package_config.dart."
   ],
   "configVersion": 2,
-  "generated": "2021-04-06T11:20:39.965073",
+  "generated": "2021-04-06T16:51:44.463801",
   "generator": "tools/generate_package_config.dart",
   "packages": [
     {
@@ -659,7 +659,7 @@
       "name": "telemetry",
       "rootUri": "../pkg/telemetry",
       "packageUri": "lib/",
-      "languageVersion": "1.0"
+      "languageVersion": "2.12"
     },
     {
       "name": "term_glyph",
@@ -728,12 +728,6 @@
       "languageVersion": "2.12"
     },
     {
-      "name": "uuid",
-      "rootUri": "../third_party/pkg/uuid",
-      "packageUri": "lib/",
-      "languageVersion": "2.0"
-    },
-    {
       "name": "vector_math",
       "rootUri": "../third_party/pkg/vector_math",
       "packageUri": "lib/",
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index 1a75652..388fbdc 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -229,6 +229,8 @@
         return const [lsp.SymbolKind.Enum];
       case server.DeclarationKind.ENUM_CONSTANT:
         return const [lsp.SymbolKind.EnumMember, lsp.SymbolKind.Enum];
+      case server.DeclarationKind.EXTENSION:
+        return const [lsp.SymbolKind.Class];
       case server.DeclarationKind.FIELD:
         return const [lsp.SymbolKind.Field];
       case server.DeclarationKind.FUNCTION:
diff --git a/pkg/analysis_server/lib/src/search/workspace_symbols.dart b/pkg/analysis_server/lib/src/search/workspace_symbols.dart
index a256782..ec02b7e 100644
--- a/pkg/analysis_server/lib/src/search/workspace_symbols.dart
+++ b/pkg/analysis_server/lib/src/search/workspace_symbols.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// @dart = 2.9
-
 import 'dart:collection';
 
 import 'package:analyzer/source/line_info.dart';
@@ -20,9 +18,9 @@
   final int column;
   final int codeOffset;
   final int codeLength;
-  final String className;
-  final String mixinName;
-  final String parameters;
+  final String? className;
+  final String? mixinName;
+  final String? parameters;
 
   Declaration(
     this.fileIndex,
@@ -46,6 +44,7 @@
   CONSTRUCTOR,
   ENUM,
   ENUM_CONSTANT,
+  EXTENSION,
   FIELD,
   FUNCTION,
   FUNCTION_TYPE_ALIAS,
@@ -62,8 +61,8 @@
   WorkspaceSymbols(this.tracker);
 
   List<Declaration> declarations(
-      RegExp regExp, int maxResults, LinkedHashSet<String> files,
-      {String onlyForFile}) {
+      RegExp? regExp, int? maxResults, LinkedHashSet<String> files,
+      {String? onlyForFile}) {
     _doTrackerWork();
 
     var declarations = <Declaration>[];
@@ -107,14 +106,21 @@
         return;
       }
 
-      String className;
-      if (declaration.parent?.kind == ad.DeclarationKind.CLASS) {
-        className = declaration.parent.name;
+      var parent = declaration.parent;
+
+      String? className;
+      if (parent != null && parent.kind == ad.DeclarationKind.CLASS) {
+        className = parent.name;
       }
 
-      String mixinName;
-      if (declaration.parent?.kind == ad.DeclarationKind.MIXIN) {
-        mixinName = declaration.parent.name;
+      String? mixinName;
+      if (parent != null && parent.kind == ad.DeclarationKind.MIXIN) {
+        mixinName = parent.name;
+      }
+
+      var topKind = _getTopKind(declaration.kind);
+      if (topKind == null) {
+        return;
       }
 
       declarations.add(
@@ -122,7 +128,7 @@
           getPathIndex(path),
           declaration.lineInfo,
           name,
-          _getTopKind(declaration.kind),
+          topKind,
           declaration.locationOffset,
           declaration.locationStartLine,
           declaration.locationStartColumn,
@@ -154,7 +160,7 @@
     }
   }
 
-  static DeclarationKind _getTopKind(ad.DeclarationKind kind) {
+  static DeclarationKind? _getTopKind(ad.DeclarationKind kind) {
     switch (kind) {
       case ad.DeclarationKind.CLASS:
         return DeclarationKind.CLASS;
@@ -166,6 +172,8 @@
         return DeclarationKind.ENUM;
       case ad.DeclarationKind.ENUM_CONSTANT:
         return DeclarationKind.ENUM_CONSTANT;
+      case ad.DeclarationKind.EXTENSION:
+        return DeclarationKind.EXTENSION;
       case ad.DeclarationKind.FIELD:
         return DeclarationKind.FIELD;
       case ad.DeclarationKind.FUNCTION_TYPE_ALIAS:
diff --git a/pkg/analysis_server/test/lsp/workspace_symbols_test.dart b/pkg/analysis_server/test/lsp/workspace_symbols_test.dart
index d20b42e..915a8a3 100644
--- a/pkg/analysis_server/test/lsp/workspace_symbols_test.dart
+++ b/pkg/analysis_server/test/lsp/workspace_symbols_test.dart
@@ -31,7 +31,7 @@
 
     final namedExtensions =
         symbols.firstWhere((s) => s.name == 'StringExtensions');
-    expect(namedExtensions.kind, equals(SymbolKind.Obj));
+    expect(namedExtensions.kind, equals(SymbolKind.Class));
     expect(namedExtensions.containerName, isNull);
 
     // Unnamed extensions are not returned in Workspace Symbols.
diff --git a/pkg/telemetry/lib/crash_reporting.dart b/pkg/telemetry/lib/crash_reporting.dart
index 7b4b958..63d549b 100644
--- a/pkg/telemetry/lib/crash_reporting.dart
+++ b/pkg/telemetry/lib/crash_reporting.dart
@@ -54,7 +54,7 @@
   CrashReportSender._(
     this.crashProductId,
     this.shouldSend, {
-    http.Client httpClient,
+    http.Client? httpClient,
     String endpointPath = _crashEndpointPathStaging,
   })  : _httpClient = httpClient ?? new http.Client(),
         _baseUri = new Uri(
@@ -64,7 +64,7 @@
   CrashReportSender.staging(
     String crashProductId,
     EnablementCallback shouldSend, {
-    http.Client httpClient,
+    http.Client? httpClient,
   }) : this._(crashProductId, shouldSend,
             httpClient: httpClient, endpointPath: _crashEndpointPathStaging);
 
@@ -72,7 +72,7 @@
   CrashReportSender.prod(
     String crashProductId,
     EnablementCallback shouldSend, {
-    http.Client httpClient,
+    http.Client? httpClient,
   }) : this._(crashProductId, shouldSend,
             httpClient: httpClient, endpointPath: _crashEndpointPathProd);
 
@@ -86,7 +86,7 @@
     dynamic error,
     StackTrace stackTrace, {
     List<CrashReportAttachment> attachments = const [],
-    String comment,
+    String? comment,
   }) async {
     if (!shouldSend()) {
       return;
@@ -192,9 +192,9 @@
   final String _value;
 
   CrashReportAttachment.string({
-    @required String field,
-    @required String value,
-  })  : _field = field,
+    required String field,
+    required String value,
+  })   : _field = field,
         _value = value;
 }
 
diff --git a/pkg/telemetry/lib/src/utils.dart b/pkg/telemetry/lib/src/utils.dart
index 04ddace..2c38478 100644
--- a/pkg/telemetry/lib/src/utils.dart
+++ b/pkg/telemetry/lib/src/utils.dart
@@ -14,13 +14,10 @@
   final int bucketSize;
   final Duration replenishDuration;
 
-  int _drops;
-  int _lastReplenish;
+  late int _drops = bucketSize;
+  late int _lastReplenish = new DateTime.now().millisecondsSinceEpoch;
 
-  ThrottlingBucket(this.bucketSize, this.replenishDuration) {
-    _drops = bucketSize;
-    _lastReplenish = new DateTime.now().millisecondsSinceEpoch;
-  }
+  ThrottlingBucket(this.bucketSize, this.replenishDuration);
 
   bool removeDrop() {
     _checkReplenish();
diff --git a/pkg/telemetry/lib/telemetry.dart b/pkg/telemetry/lib/telemetry.dart
index 0c28c7d..e76e622 100644
--- a/pkg/telemetry/lib/telemetry.dart
+++ b/pkg/telemetry/lib/telemetry.dart
@@ -59,7 +59,7 @@
   bool disableForSession = false,
   bool forceEnabled = false,
 }) {
-  Directory dir = getDartStorageDirectory();
+  final dir = getDartStorageDirectory();
   if (dir == null) {
     // Some systems don't support user home directories; for those, fail
     // gracefully by returning a disabled analytics object.
@@ -95,7 +95,7 @@
 /// This can return null under some conditions, including when the user's home
 /// directory does not exist.
 @visibleForTesting
-Directory getDartStorageDirectory() {
+Directory? getDartStorageDirectory() {
   Directory homeDirectory = new Directory(userHomeDir());
   if (!homeDirectory.existsSync()) return null;
 
@@ -114,8 +114,8 @@
     String applicationName,
     String applicationVersion,
     File settingsFile, {
-    @required this.disableForSession,
-    @required this.forceEnabled,
+    required this.disableForSession,
+    required this.forceEnabled,
   }) : super(
           trackingId,
           new IOPersistentProperties.fromFile(settingsFile),
@@ -123,7 +123,7 @@
           applicationName: applicationName,
           applicationVersion: applicationVersion,
         ) {
-    final String locale = getPlatformLocale();
+    final locale = getPlatformLocale();
     if (locale != null) {
       setSessionValue('ul', locale);
     }
@@ -141,7 +141,7 @@
     }
 
     // If there's no explicit setting (enabled or disabled) then we don't send.
-    return (properties['enabled'] as bool) ?? false;
+    return (properties['enabled'] as bool?) ?? false;
   }
 }
 
diff --git a/pkg/telemetry/pubspec.yaml b/pkg/telemetry/pubspec.yaml
index ca646aa..950cf63 100644
--- a/pkg/telemetry/pubspec.yaml
+++ b/pkg/telemetry/pubspec.yaml
@@ -5,7 +5,7 @@
 author: Dart Team <misc@dartlang.org>
 
 environment:
-  sdk: '>=1.0.0 <3.0.0'
+  sdk: '>=2.12.0 <3.0.0'
 
 dependencies:
   http: ^0.12.0
diff --git a/pkg/telemetry/test/crash_reporting_test.dart b/pkg/telemetry/test/crash_reporting_test.dart
index 440eee9..79cf728 100644
--- a/pkg/telemetry/test/crash_reporting_test.dart
+++ b/pkg/telemetry/test/crash_reporting_test.dart
@@ -12,10 +12,10 @@
 
 void main() {
   group('CrashReportSender', () {
-    MockClient mockClient;
-    AnalyticsMock analytics;
+    late MockClient mockClient;
+    late AnalyticsMock analytics;
 
-    Request request;
+    late Request request;
 
     setUp(() {
       mockClient = new MockClient((Request r) async {
diff --git a/pkg/telemetry/test/telemetry_test.dart b/pkg/telemetry/test/telemetry_test.dart
index 8cd4ca3..07dc8f7 100644
--- a/pkg/telemetry/test/telemetry_test.dart
+++ b/pkg/telemetry/test/telemetry_test.dart
@@ -2,15 +2,13 @@
 // 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.
 
-import 'dart:io';
-
 import 'package:telemetry/telemetry.dart';
 import 'package:test/test.dart';
 
 void main() {
   group('telemetry', () {
     test('getDartStorageDirectory', () {
-      Directory dir = getDartStorageDirectory();
+      var dir = getDartStorageDirectory();
       expect(dir, isNotNull);
     });
 
diff --git a/pkg/vm_snapshot_analysis/lib/v8_profile.dart b/pkg/vm_snapshot_analysis/lib/v8_profile.dart
index 404fe66..5ef79af 100644
--- a/pkg/vm_snapshot_analysis/lib/v8_profile.dart
+++ b/pkg/vm_snapshot_analysis/lib/v8_profile.dart
@@ -228,6 +228,12 @@
     }.toString();
   }
 
+  /// Returns the target of an outgoing edge with the given name (if any),
+  /// but first checks for a corresponding artificial edge indicating a dropped
+  /// object.
+  Node possiblyDroppedTarget(String edgeName) =>
+      this[':$edgeName'] ?? this[edgeName];
+
   /// Returns the target of an outgoing edge with the given name (if any).
   Node operator [](String edgeName) => this
       .edges
@@ -398,7 +404,7 @@
   ProgramInfoNode createInfoNodeFor(Node node) {
     switch (node.type) {
       case 'Code':
-        var owner = node[':owner_'] ?? node['owner_'];
+        var owner = node.possiblyDroppedTarget('owner_');
         if (owner.type != 'Type') {
           final ownerNode =
               owner.type == 'Null' ? program.stubs : getInfoNodeFor(owner);
@@ -419,9 +425,10 @@
         if (node.name != '<anonymous signature>') {
           var owner = node['owner_'];
 
-          // Artificial nodes will not have data_ field.
-          if (node['data_']?.type == 'ClosureData') {
-            owner = node['data_']['parent_function_'];
+          // Artificial nodes may not have a data_ field.
+          var data = node['data_'];
+          if (data?.type == 'ClosureData') {
+            owner = data.possiblyDroppedTarget('parent_function_');
           }
           return makeInfoNode(node.index,
               name: node.name,
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index a94e18a..e779915 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #include <memory>
+#include <utility>
 
 #include "vm/clustered_snapshot.h"
 
@@ -1051,6 +1052,12 @@
   }
 };
 
+// If DROPPED_NAME(name) is used for a v8 snapshot profile edge, then
+// possiblyDroppedTarget() should be used to retrieve the edge target in
+// pkg/vm_snapshot_analysis/v8_profile.dart so the artificial node is found
+// instead of its in-snapshot replacement.
+#define DROPPED_NAME(name) (":" #name)
+
 #if !defined(DART_PRECOMPILED_RUNTIME)
 class ClosureDataSerializationCluster : public SerializationCluster {
  public:
@@ -1097,6 +1104,25 @@
     }
   }
 
+  // Some closure data objects have their parent functions dropped from the
+  // snapshot, which makes it is impossible to recover program structure when
+  // analysing snapshot profile. To facilitate analysis of snapshot profiles
+  // we include artificial nodes into profile representing such dropped
+  // parent functions.
+  void WriteDroppedParentFunctionsIntoProfile(Serializer* s) {
+    ASSERT(s->profile_writer() != nullptr);
+
+    for (auto data : objects_) {
+      ObjectPtr parent_function =
+          WeakSerializationReference::Unwrap(data->untag()->parent_function());
+      if (s->CreateArtificialNodeIfNeeded(parent_function)) {
+        AutoTraceObject(data);
+        s->AttributePropertyRef(parent_function, DROPPED_NAME(parent_function_),
+                                /*permit_artificial_ref=*/true);
+      }
+    }
+  }
+
  private:
   GrowableArray<ClosureDataPtr> objects_;
 };
@@ -2035,9 +2061,9 @@
     for (auto code : objects_) {
       ObjectPtr owner =
           WeakSerializationReference::Unwrap(code->untag()->owner_);
-      if (s->CreateArtificalNodeIfNeeded(owner) || Code::IsDiscarded(code)) {
+      if (s->CreateArtificialNodeIfNeeded(owner) || Code::IsDiscarded(code)) {
         AutoTraceObject(code);
-        s->AttributePropertyRef(owner, ":owner_",
+        s->AttributePropertyRef(owner, DROPPED_NAME(owner_),
                                 /*permit_artificial_ref=*/true);
       }
     }
@@ -6194,9 +6220,14 @@
 }
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-bool Serializer::CreateArtificalNodeIfNeeded(ObjectPtr obj) {
+bool Serializer::CreateArtificialNodeIfNeeded(ObjectPtr obj) {
   ASSERT(profile_writer() != nullptr);
 
+  if (obj->GetClassId() == kWeakSerializationReferenceCid) {
+    auto wsr = static_cast<WeakSerializationReferencePtr>(obj);
+    return CreateArtificialNodeIfNeeded(wsr->untag()->target());
+  }
+
   intptr_t id = heap_->GetObjectId(obj);
   if (IsAllocatedReference(id)) {
     return false;
@@ -6210,31 +6241,37 @@
   const char* type = nullptr;
   StringPtr name_string = nullptr;
   const char* name = nullptr;
-  ObjectPtr owner = nullptr;
-  const char* owner_ref_name = nullptr;
+  GrowableArray<std::pair<ObjectPtr, const char*>> links;
   switch (obj->GetClassId()) {
     case kFunctionCid: {
       FunctionPtr func = static_cast<FunctionPtr>(obj);
       type = "Function";
       name = FunctionSerializationCluster::MakeDisambiguatedFunctionName(this,
                                                                          func);
-      owner_ref_name = "owner_";
-      owner = func->untag()->owner();
+      links.Add({func->untag()->owner(), "owner_"});
+      ObjectPtr data = func->untag()->data();
+      if (data->GetClassId() == kClosureDataCid) {
+        links.Add({func->untag()->data(), "data_"});
+      }
+      break;
+    }
+    case kClosureDataCid: {
+      auto data = static_cast<ClosureDataPtr>(obj);
+      type = "ClosureData";
+      links.Add({data->untag()->parent_function(), "parent_function_"});
       break;
     }
     case kClassCid: {
       ClassPtr cls = static_cast<ClassPtr>(obj);
       type = "Class";
       name_string = cls->untag()->name();
-      owner_ref_name = "library_";
-      owner = cls->untag()->library();
+      links.Add({cls->untag()->library(), "library_"});
       break;
     }
     case kPatchClassCid: {
       PatchClassPtr patch_cls = static_cast<PatchClassPtr>(obj);
       type = "PatchClass";
-      owner_ref_name = "patched_class_";
-      owner = patch_cls->untag()->patched_class();
+      links.Add({patch_cls->untag()->patched_class(), "patched_class_"});
       break;
     }
     case kLibraryCid: {
@@ -6254,16 +6291,16 @@
     name = str.ToCString();
   }
 
-  // CreateArtificalNodeIfNeeded might call TraceStartWritingObject
+  // CreateArtificialNodeIfNeeded might call TraceStartWritingObject
   // and these calls don't nest, so we need to call this outside
   // of the tracing scope created below.
-  if (owner != nullptr) {
-    CreateArtificalNodeIfNeeded(owner);
+  for (const auto& link : links) {
+    CreateArtificialNodeIfNeeded(link.first);
   }
 
   TraceStartWritingObject(type, obj, name);
-  if (owner != nullptr) {
-    AttributePropertyRef(owner, owner_ref_name,
+  for (const auto& link : links) {
+    AttributePropertyRef(link.first, link.second,
                          /*permit_artificial_ref=*/true);
   }
   TraceEndWritingObject();
@@ -6817,6 +6854,10 @@
   if (FLAG_write_v8_snapshot_profile_to != nullptr) {
     static_cast<CodeSerializationCluster*>(clusters_by_cid_[kCodeCid])
         ->WriteDroppedOwnersIntoProfile(this);
+    if (auto const cluster = static_cast<ClosureDataSerializationCluster*>(
+            clusters_by_cid_[kClosureDataCid])) {
+      cluster->WriteDroppedParentFunctionsIntoProfile(this);
+    }
   }
 #endif
 
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index 0888bbb..79ef250 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -397,7 +397,7 @@
   // yet gotten an artificial node created for it create an artificial node
   // in the profile representing this object.
   // Returns true if [obj] has an artificial profile node associated with it.
-  bool CreateArtificalNodeIfNeeded(ObjectPtr obj);
+  bool CreateArtificialNodeIfNeeded(ObjectPtr obj);
 
   bool InCurrentLoadingUnit(ObjectPtr obj, bool record = false);
   GrowableArray<LoadingUnitSerializationData*>* loading_units() const {
diff --git a/tools/VERSION b/tools/VERSION
index 0c0a1fb..907806b 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 212
+PRERELEASE 213
 PRERELEASE_PATCH 0
\ No newline at end of file