Version 2.15.0-56.0.dev

Merge commit '92026cec4435bc846b5e30462818dfd9eded3dc2' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f6e9780..5f02905 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -198,8 +198,16 @@
 
 #### Linter
 
-Updated the Linter to `1.9.0`, which includes changes that
-
+Updated the Linter to `1.10.0`, which includes changes that
+- improves regular expression parsing performance for common checks 
+  (`camel_case_types`, `file_names`, etc.).
+- (internal) migrates to analyzer 2.1.0 APIs.
+- fixes false positive in `use_build_context_synchronously` in awaits inside 
+  anonymous functions.
+- fixes `overridden_fields` false positive w/ static fields.
+- fixes false positive in `avoid_null_checks_in_equality_operators` w/ 
+  non-nullable params.
+- fixes false positive for deferred imports in `prefer_const_constructors`.
 - marks `avoid_dynamic_calls` stable.
 - (internal) removes unused `MockPubVisitor` and `MockRule` classes.
 - fixes a `prefer_void_to_null` false positive w/ overridden properties.
diff --git a/DEPS b/DEPS
index 8315824..7d53ee7 100644
--- a/DEPS
+++ b/DEPS
@@ -122,7 +122,7 @@
   "intl_tag": "0.17.0-nullsafety",
   "jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_rev": "7e00f893440a72de0637970325e4ea44bd1e8c8e",
-  "linter_tag": "1.9.0",
+  "linter_tag": "1.10.0",
   "lints_tag": "f9670df2a66e0ec12eb51554e70c1cbf56c8f5d0",
   "logging_rev": "575781ef196e4fed4fb737e38fb4b73d62727187",
   "markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
index 14485d2..a586ac4 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/abstract_producer.dart
@@ -276,9 +276,7 @@
     var selectionEnd = selectionOffset + selectionLength;
     var locator = NodeLocator(selectionOffset, selectionEnd);
     var node = locator.searchWithin(resolvedResult.unit);
-    if (node == null) {
-      return null;
-    }
+    node ??= resolvedResult.unit;
 
     return CorrectionProducerContext._(
       resolvedResult: resolvedResult,
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_eol_at_end_of_file.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_eol_at_end_of_file.dart
new file mode 100644
index 0000000..3dd8cad
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_eol_at_end_of_file.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2021, the Dart 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.
+
+import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/source/source_range.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+
+class AddEolAtEndOfFile extends CorrectionProducer {
+  @override
+  FixKind get fixKind => DartFixKind.ADD_EOL_AT_END_OF_FILE;
+
+  @override
+  Future<void> compute(ChangeBuilder builder) async {
+    var content = resolvedResult.content;
+    if (!content.endsWith(eol)) {
+      await builder.addDartFileEdit(file, (builder) {
+        builder.addSimpleInsertion(content.length, eol);
+      });
+    } else {
+      var index = content.length;
+      while (index > 0) {
+        var char = content[index - 1];
+        if (char != '\r' && char != '\n') {
+          break;
+        }
+        index--;
+      }
+
+      await builder.addDartFileEdit(file, (builder) {
+        builder.addSimpleReplacement(
+            SourceRange(index, content.length - index), eol);
+      });
+    }
+  }
+
+  /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
+  static AddEolAtEndOfFile newInstance() => AddEolAtEndOfFile();
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index fb59750..8ca363e 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -94,6 +94,8 @@
       'dart.fix.add.diagnosticPropertyReference.multi',
       DartFixKindPriority.IN_FILE,
       'Add missing debug property references everywhere in file');
+  static const ADD_EOL_AT_END_OF_FILE = FixKind('dart.fix.add.eolAtEndOfFile',
+      DartFixKindPriority.DEFAULT, 'Add EOL at end of file');
   static const ADD_FIELD_FORMAL_PARAMETERS = FixKind(
       'dart.fix.add.fieldFormalParameters',
       70,
@@ -745,10 +747,8 @@
       'dart.fix.replace.nullWithVoid.multi',
       DartFixKindPriority.DEFAULT,
       "Replace 'Null' with 'void' everywhere in file");
-  static const REPLACE_RETURN_TYPE = FixKind(
-      'dart.fix.replace.returnType',
-      DartFixKindPriority.DEFAULT,
-      "Replace the return type with '{0}'");
+  static const REPLACE_RETURN_TYPE = FixKind('dart.fix.replace.returnType',
+      DartFixKindPriority.DEFAULT, "Replace the return type with '{0}'");
   static const REPLACE_RETURN_TYPE_FUTURE = FixKind(
       'dart.fix.replace.returnTypeFuture',
       DartFixKindPriority.DEFAULT,
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index a67305f..d0e51d0 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -12,6 +12,7 @@
 import 'package:analysis_server/src/services/correction/dart/add_await.dart';
 import 'package:analysis_server/src/services/correction/dart/add_const.dart';
 import 'package:analysis_server/src/services/correction/dart/add_diagnostic_property_reference.dart';
+import 'package:analysis_server/src/services/correction/dart/add_eol_at_end_of_file.dart';
 import 'package:analysis_server/src/services/correction/dart/add_explicit_cast.dart';
 import 'package:analysis_server/src/services/correction/dart/add_field_formal_parameters.dart';
 import 'package:analysis_server/src/services/correction/dart/add_key_to_constructors.dart';
@@ -409,6 +410,9 @@
       RemoveEmptyStatement.newInstance,
       ReplaceWithBrackets.newInstance,
     ],
+    LintNames.eol_at_end_of_file: [
+      AddEolAtEndOfFile.newInstance,
+    ],
     LintNames.exhaustive_cases: [
       AddMissingEnumLikeCaseClauses.newInstance,
     ],
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
index 0f5d7d0..ccafb32 100644
--- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -48,6 +48,7 @@
   static const String empty_catches = 'empty_catches';
   static const String empty_constructor_bodies = 'empty_constructor_bodies';
   static const String empty_statements = 'empty_statements';
+  static const String eol_at_end_of_file = 'eol_at_end_of_file';
   static const String exhaustive_cases = 'exhaustive_cases';
   static const String hash_and_equals = 'hash_and_equals';
   static const String no_duplicate_case_values = 'no_duplicate_case_values';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_eol_at_end_of_file_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_eol_at_end_of_file_test.dart
new file mode 100644
index 0000000..07fb1f4
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_eol_at_end_of_file_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2021, the Dart 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.
+
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(AddEolAtEndOfFileTest);
+  });
+}
+
+@reflectiveTest
+class AddEolAtEndOfFileTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.ADD_EOL_AT_END_OF_FILE;
+
+  @override
+  String get lintCode => LintNames.eol_at_end_of_file;
+
+  Future<void> test_missing_eol() async {
+    await resolveTestCode('''
+void f() {
+}''');
+    await assertHasFix('''
+void f() {
+}
+''');
+  }
+
+  Future<void> test_multiple_eol() async {
+    await resolveTestCode('''
+void f() {
+}
+
+''');
+    await assertHasFix('''
+void f() {
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_comparison_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_comparison_test.dart
index 2de13b2..3e73604 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_comparison_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_comparison_test.dart
@@ -204,7 +204,7 @@
   final String name = '';
 
   @override
-  operator ==(other) =>
+  operator ==(Object? other) =>
           other != null &&
           other is Person &&
           name == other.name;
@@ -214,7 +214,7 @@
   final String name = '';
 
   @override
-  operator ==(other) =>
+  operator ==(Object? other) =>
           other != null &&
           other is Person &&
           name == other.name;
@@ -225,7 +225,7 @@
   final String name = '';
 
   @override
-  operator ==(other) =>
+  operator ==(Object? other) =>
           other is Person &&
           name == other.name;
 }
@@ -234,7 +234,7 @@
   final String name = '';
 
   @override
-  operator ==(other) =>
+  operator ==(Object? other) =>
           other is Person &&
           name == other.name;
 }
@@ -282,7 +282,7 @@
   final String name = '';
 
   @override
-  operator ==(other) =>
+  operator ==(Object? other) =>
           other != null &&
           other is Person &&
           name == other.name;
@@ -293,13 +293,11 @@
   final String name = '';
 
   @override
-  operator ==(other) =>
+  operator ==(Object? other) =>
           other is Person &&
           name == other.name;
 }
-''',
-        errorFilter: (error) =>
-            error.errorCode == HintCode.UNNECESSARY_NULL_COMPARISON_TRUE);
+''');
   }
 
   Future<void> test_functionBody() async {
@@ -308,7 +306,7 @@
   final String name = '';
 
   @override
-  operator ==(other) {
+  operator ==(Object? other) {
     return other != null &&
           other is Person &&
           name == other.name;
@@ -320,14 +318,12 @@
   final String name = '';
 
   @override
-  operator ==(other) {
+  operator ==(Object? other) {
     return other is Person &&
           name == other.name;
   }
 }
-''',
-        errorFilter: (error) =>
-            error.errorCode == HintCode.UNNECESSARY_NULL_COMPARISON_TRUE);
+''');
   }
 
   Future<void> test_ifNullAssignmentStatement() async {
@@ -336,7 +332,7 @@
   final String name = '';
 
   @override
-  operator ==(other) {
+  operator ==(Object? other) {
     if (other is! Person) return false;
     other ??= Person();
     return other.name == name;
@@ -354,7 +350,7 @@
   final String name = '';
 
   @override
-  operator ==(other) {
+  operator ==(Object? other) {
     if (other is! Person) return false;
     final toCompare = other ?? Person();
     return toCompare.name == name;
@@ -367,7 +363,7 @@
   final String name = '';
 
   @override
-  operator ==(other) {
+  operator ==(Object? other) {
     if (other is! Person) return false;
     final toCompare = other;
     return toCompare.name == name;
@@ -386,7 +382,7 @@
   final String name = '';
 
   @override
-  operator ==(other) {
+  operator ==(Object? other) {
     if (other == null) return false;
     return other is Person &&
           name == other.name;
@@ -398,7 +394,7 @@
   final String name = '';
 
   @override
-  operator ==(other) {
+  operator ==(Object? other) {
     return other is Person &&
           name == other.name;
   }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index 5ff6f0d..9d30ea0 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -10,6 +10,7 @@
 import 'add_curly_braces_test.dart' as add_curly_braces;
 import 'add_diagnostic_property_reference_test.dart'
     as add_diagnostic_property_reference;
+import 'add_eol_at_end_of_file_test.dart' as add_eol_at_end_of_file;
 import 'add_explicit_cast_test.dart' as add_explicit_cast;
 import 'add_field_formal_parameters_test.dart' as add_field_formal_parameters;
 import 'add_key_to_constructors_test.dart' as add_key_to_constructors;
@@ -203,6 +204,7 @@
     add_const.main();
     add_curly_braces.main();
     add_diagnostic_property_reference.main();
+    add_eol_at_end_of_file.main();
     add_explicit_cast.main();
     add_field_formal_parameters.main();
     add_key_to_constructors.main();
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 9038287..8acd4ac 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -295,6 +295,9 @@
       _instanceCreationExpressionResolver =
       InstanceCreationExpressionResolver(this);
 
+  late final SimpleIdentifierResolver _simpleIdentifierResolver =
+      SimpleIdentifierResolver(this, flowAnalysis);
+
   /// Initialize a newly created visitor to resolve the nodes in an AST node.
   ///
   /// The [definingLibrary] is the element for the library containing the node
@@ -1857,7 +1860,7 @@
 
   @override
   void visitSimpleIdentifier(covariant SimpleIdentifierImpl node) {
-    SimpleIdentifierResolver(this, flowAnalysis).resolve(node);
+    _simpleIdentifierResolver.resolve(node);
   }
 
   @override
diff --git a/pkg/dds/lib/src/dap/adapters/dart.dart b/pkg/dds/lib/src/dap/adapters/dart.dart
index b2ace33..5099eef 100644
--- a/pkg/dds/lib/src/dap/adapters/dart.dart
+++ b/pkg/dds/lib/src/dap/adapters/dart.dart
@@ -467,11 +467,16 @@
   /// The URI protocol will be changed to ws/wss but otherwise not normalised.
   /// The caller should handle any other normalisation (such as adding /ws to
   /// the end if required).
-  Future<void> connectDebugger(Uri uri) async {
+  ///
+  /// If [resumeIfStarting] is true, isolates waiting to start will
+  /// automatically be resumed. This is usually desired in launch requests, but
+  /// not when attaching.
+  Future<void> connectDebugger(
+    Uri uri, {
+    required bool resumeIfStarting,
+  }) async {
     // Start up a DDS instance for this VM.
     if (enableDds) {
-      // TODO(dantup): Do we need to worry about there already being one connected
-      //   if this URL came from another service that may have started one?
       logger?.call('Starting a DDS instance for $uri');
       try {
         final dds = await DartDevelopmentService.startDartDevelopmentService(
@@ -552,7 +557,8 @@
       final pauseEventKind = isolate.runnable ?? false
           ? vm.EventKind.kIsolateRunnable
           : vm.EventKind.kIsolateStart;
-      await _isolateManager.registerIsolate(isolate, pauseEventKind);
+      final thread =
+          await _isolateManager.registerIsolate(isolate, pauseEventKind);
 
       // If the Isolate already has a Pause event we can give it to the
       // IsolateManager to handle (if it's PausePostStart it will re-configure
@@ -560,9 +566,18 @@
       // runnable - otherwise we'll handle this when it becomes runnable in an
       // event later).
       if (isolate.pauseEvent?.kind?.startsWith('Pause') ?? false) {
-        await _isolateManager.handleEvent(isolate.pauseEvent!);
+        await _isolateManager.handleEvent(
+          isolate.pauseEvent!,
+          resumeIfStarting: resumeIfStarting,
+        );
       } else if (isolate.runnable == true) {
-        await _isolateManager.resumeIsolate(isolate);
+        // If requested, automatically resume. Otherwise send a Stopped event to
+        // inform the client UI the thread is paused.
+        if (resumeIfStarting) {
+          await _isolateManager.resumeIsolate(isolate);
+        } else {
+          _isolateManager.sendStoppedOnEntryEvent(thread.threadId);
+        }
       }
     }));
 
diff --git a/pkg/dds/lib/src/dap/adapters/dart_cli.dart b/pkg/dds/lib/src/dap/adapters/dart_cli.dart
index 7420692..bf0eab9 100644
--- a/pkg/dds/lib/src/dap/adapters/dart_cli.dart
+++ b/pkg/dds/lib/src/dap/adapters/dart_cli.dart
@@ -140,7 +140,7 @@
 
       vmServiceInfoFile = File(serviceInfoFilePath);
       unawaited(waitForVmServiceInfoFile(vmServiceInfoFile)
-          .then((uri) => connectDebugger(uri)));
+          .then((uri) => connectDebugger(uri, resumeIfStarting: true)));
     }
 
     final vmArgs = <String>[
@@ -230,7 +230,7 @@
         ? Uri.parse(vmServiceUri)
         : await waitForVmServiceInfoFile(File(vmServiceInfoFile!));
 
-    unawaited(connectDebugger(uri));
+    unawaited(connectDebugger(uri, resumeIfStarting: false));
   }
 
   /// Calls the client (via a `runInTerminal` request) to spawn the process so
diff --git a/pkg/dds/lib/src/dap/isolate_manager.dart b/pkg/dds/lib/src/dap/isolate_manager.dart
index d579bde..6eb4a24 100644
--- a/pkg/dds/lib/src/dap/isolate_manager.dart
+++ b/pkg/dds/lib/src/dap/isolate_manager.dart
@@ -128,8 +128,14 @@
 
   ThreadInfo? getThread(int threadId) => _threadsByThreadId[threadId];
 
-  /// Handles Isolate and Debug events
-  Future<void> handleEvent(vm.Event event) async {
+  /// Handles Isolate and Debug events.
+  ///
+  /// If [resumeIfStarting] is `true`, PauseStart/PausePostStart events will be
+  /// automatically resumed from.
+  Future<void> handleEvent(
+    vm.Event event, {
+    bool resumeIfStarting = true,
+  }) async {
     final isolateId = event.isolate?.id;
     if (isolateId == null) {
       return;
@@ -151,7 +157,7 @@
     if (eventKind == vm.EventKind.kIsolateExit) {
       _handleExit(event);
     } else if (eventKind?.startsWith('Pause') ?? false) {
-      await _handlePause(event);
+      await _handlePause(event, resumeIfStarting: resumeIfStarting);
     } else if (eventKind == vm.EventKind.kResume) {
       _handleResumed(event);
     }
@@ -163,7 +169,7 @@
   /// New isolates will be configured with the correct pause-exception behaviour,
   /// libraries will be marked as debuggable if appropriate, and breakpoints
   /// sent.
-  Future<void> registerIsolate(
+  Future<ThreadInfo> registerIsolate(
     vm.IsolateRef isolate,
     String eventKind,
   ) async {
@@ -193,6 +199,8 @@
       await _configureIsolate(isolate);
       registrationCompleter.complete();
     }
+
+    return info;
   }
 
   Future<void> resumeIsolate(vm.IsolateRef isolateRef,
@@ -245,6 +253,11 @@
     }
   }
 
+  /// Sends an event informing the client that a thread is stopped at entry.
+  void sendStoppedOnEntryEvent(int threadId) {
+    _adapter.sendEvent(StoppedEventBody(reason: 'entry', threadId: threadId));
+  }
+
   /// Records breakpoints for [uri].
   ///
   /// [breakpoints] represents the new set and entirely replaces anything given
@@ -368,18 +381,23 @@
 
   /// Handles a pause event.
   ///
-  /// For [vm.EventKind.kPausePostRequest] which occurs after a restart, the isolate
-  /// will be re-configured (pause-exception behaviour, debuggable libraries,
-  /// breakpoints) and then resumed.
+  /// For [vm.EventKind.kPausePostRequest] which occurs after a restart, the
+  /// isolate will be re-configured (pause-exception behaviour, debuggable
+  /// libraries, breakpoints) and then (if [resumeIfStarting] is `true`)
+  /// resumed.
   ///
-  /// For [vm.EventKind.kPauseStart], the isolate will be resumed.
+  /// For [vm.EventKind.kPauseStart] and [resumeIfStarting] is `true`, the
+  /// isolate will be resumed.
   ///
   /// For breakpoints with conditions that are not met and for logpoints, the
   /// isolate will be automatically resumed.
   ///
   /// For all other pause types, the isolate will remain paused and a
   /// corresponding "Stopped" event sent to the editor.
-  Future<void> _handlePause(vm.Event event) async {
+  Future<void> _handlePause(
+    vm.Event event, {
+    bool resumeIfStarting = true,
+  }) async {
     final eventKind = event.kind;
     final isolate = event.isolate!;
     final thread = _threadsByIsolateId[isolate.id!];
@@ -396,13 +414,21 @@
     // after a hot restart.
     if (eventKind == vm.EventKind.kPausePostRequest) {
       await _configureIsolate(isolate);
-      await resumeThread(thread.threadId);
+      if (resumeIfStarting) {
+        await resumeThread(thread.threadId);
+      }
     } else if (eventKind == vm.EventKind.kPauseStart) {
       // Don't resume from a PauseStart if this has already happened (see
       // comments on [thread.hasBeenStarted]).
       if (!thread.hasBeenStarted) {
-        thread.hasBeenStarted = true;
-        await resumeThread(thread.threadId);
+        // If requested, automatically resume. Otherwise send a Stopped event to
+        // inform the client UI the thread is paused.
+        if (resumeIfStarting) {
+          thread.hasBeenStarted = true;
+          await resumeThread(thread.threadId);
+        } else {
+          sendStoppedOnEntryEvent(thread.threadId);
+        }
       }
     } else {
       // PauseExit, PauseBreakpoint, PauseInterrupted, PauseException
diff --git a/pkg/dds/test/dap/integration/debug_attach_test.dart b/pkg/dds/test/dap/integration/debug_attach_test.dart
index f0e3f14..3df0fc9 100644
--- a/pkg/dds/test/dap/integration/debug_attach_test.dart
+++ b/pkg/dds/test/dap/integration/debug_attach_test.dart
@@ -31,6 +31,7 @@
       final outputEvents = await dap.client.collectOutput(
         launch: () => dap.client.attach(
           vmServiceUri: vmServiceUri.toString(),
+          autoResume: true,
           cwd: dap.testAppDir.path,
         ),
       );
@@ -81,6 +82,7 @@
       final outputEvents = await dap.client.collectOutput(
         launch: () => dap.client.attach(
           vmServiceInfoFile: vmServiceInfoFilePath,
+          autoResume: true,
           cwd: dap.testAppDir.path,
         ),
       );
diff --git a/pkg/dds/test/dap/integration/test_client.dart b/pkg/dds/test/dap/integration/test_client.dart
index 08d7e8f..77ddc1a 100644
--- a/pkg/dds/test/dap/integration/test_client.dart
+++ b/pkg/dds/test/dap/integration/test_client.dart
@@ -62,6 +62,7 @@
   /// Send an attachRequest to the server, asking it to attach to an existing
   /// Dart program.
   Future<Response> attach({
+    required bool autoResume,
     String? vmServiceUri,
     String? vmServiceInfoFile,
     String? cwd,
@@ -70,12 +71,20 @@
     bool? debugExternalPackageLibraries,
     bool? evaluateGettersInDebugViews,
     bool? evaluateToStringInDebugViews,
-  }) {
+  }) async {
     assert(
       (vmServiceUri == null) != (vmServiceInfoFile == null),
       'Provide exactly one of vmServiceUri/vmServiceInfoFile',
     );
-    return sendRequest(
+
+    // When attaching, the paused VM will not be automatically unpaused, but
+    // instead send a Stopped(reason: 'entry') event. Respond to this by
+    // resuming.
+    final resumeFuture = autoResume
+        ? expectStop('entry').then((event) => continue_(event.threadId!))
+        : null;
+
+    final attachResponse = sendRequest(
       DartAttachRequestArguments(
         vmServiceUri: vmServiceUri,
         vmServiceInfoFile: vmServiceInfoFile,
@@ -94,6 +103,11 @@
       // (DartAttachRequestArguments).
       overrideCommand: 'attach',
     );
+
+    // If we were expecting a pause and to resume, ensure that happens.
+    await resumeFuture;
+
+    return attachResponse;
   }
 
   /// Sends a continue request for the given thread.
@@ -553,17 +567,20 @@
 
     final result =
         await getValidStack(stop.threadId!, startFrame: 0, numFrames: 1);
-    expect(result.stackFrames, hasLength(1));
-    final frame = result.stackFrames[0];
 
-    if (file != null) {
-      expect(frame.source?.path, equals(file.path));
-    }
-    if (sourceName != null) {
-      expect(frame.source?.name, equals(sourceName));
-    }
-    if (line != null) {
-      expect(frame.line, equals(line));
+    if (file != null || line != null || sourceName != null) {
+      expect(result.stackFrames, hasLength(1));
+      final frame = result.stackFrames[0];
+
+      if (file != null) {
+        expect(frame.source?.path, equals(file.path));
+      }
+      if (sourceName != null) {
+        expect(frame.source?.name, equals(sourceName));
+      }
+      if (line != null) {
+        expect(frame.line, equals(line));
+      }
     }
 
     return stop;
diff --git a/runtime/tests/vm/dart/regress_46980_test.dart b/runtime/tests/vm/dart/regress_46980_test.dart
new file mode 100644
index 0000000..a923ba8
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_46980_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2021, the Dart 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.
+
+// VMOptions=--deterministic
+
+// The Dart Project Fuzz Tester (1.91).
+// Program generated as:
+//   dart dartfuzz.dart --seed 929450448 --no-fp --no-ffi --no-flat
+
+import 'dart:collection';
+import 'dart:typed_data';
+
+MapEntry<List<int>, Map<String, String>>? var0 =
+    MapEntry<List<int>, Map<String, String>>(
+        Uint16List.fromList(<int>[-25]), <String, String>{
+  '': 'p8',
+  'VGiZ+x': 'n6\u{1f600}',
+  'j': 'hrNI',
+  '3@kX)\u{1f600}': 'TW+Z',
+  'D': '\u2665Yqu',
+  'wzBa\u{1f600}h': '-k'
+});
+num? var78 = 29;
+MapEntry<String, int> var141 = MapEntry<String, int>('\u{1f600}', 16);
+
+MapEntry<Map<bool, int>, MapEntry<bool, int>>? var2896 =
+    MapEntry<Map<bool, int>, MapEntry<bool, int>>(<bool, int>{
+  true: -79,
+  false: 13,
+  true: 35,
+  true: -84,
+  false: -9223372034707292159
+}, MapEntry<bool, int>(true, 0));
+
+main() {
+  for (var i = 0; i < 1848; i++) {
+    print(var2896);
+  }
+
+  print('$var0\n$var78\n$var141\n');
+}
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index a545c0e..1cd8ece 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -1904,7 +1904,7 @@
       ICData::Handle(zone_, ICData::ICDataOfEntriesArray(ic_data_entries));
 
   const classid_t current_cid = receiver().GetClassId();
-  const classid_t old_cid = ic_data.GetReceiverClassIdAt(0);
+  const classid_t old_cid = Smi::Value(Smi::RawCast(ic_data_entries.At(0)));
   const bool same_receiver = current_cid == old_cid;
 
   // The target didn't change, so we can stay inside monomorphic state.
@@ -1927,6 +1927,7 @@
     // We stay in monomorphic state, patch the code object and keep the same
     // data (old ICData entries array).
     const auto& code = Code::Handle(zone_, target_function.EnsureHasCode());
+    ASSERT(data.ptr() == ic_data.entries());
     CodePatcher::PatchInstanceCallAt(caller_frame_->pc(), caller_code_, data,
                                      code);
     ReturnJIT(code, data, target_function);
diff --git a/tools/VERSION b/tools/VERSION
index 2aaac9b..39cb874 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 55
+PRERELEASE 56
 PRERELEASE_PATCH 0
\ No newline at end of file