Version 2.18.0-75.0.dev

Merge commit 'a6042d20f915e039a4745bb7aae9f335fdbfec08' into 'dev'
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
index dfb5f9c..c69cd94 100644
--- a/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_generated.dart
@@ -17989,7 +17989,7 @@
 class Message implements ToJsonable {
   static const jsonHandler = LspJsonHandler(Message.canParse, Message.fromJson);
 
-  Message({required this.jsonrpc});
+  Message({required this.jsonrpc, this.clientRequestTime});
   static Message fromJson(Map<String, Object?> json) {
     if (RequestMessage.canParse(json, nullLspJsonReporter)) {
       return RequestMessage.fromJson(json);
@@ -18002,14 +18002,20 @@
     }
     final jsonrpcJson = json['jsonrpc'];
     final jsonrpc = jsonrpcJson as String;
-    return Message(jsonrpc: jsonrpc);
+    final clientRequestTimeJson = json['clientRequestTime'];
+    final clientRequestTime = clientRequestTimeJson as int?;
+    return Message(jsonrpc: jsonrpc, clientRequestTime: clientRequestTime);
   }
 
+  final int? clientRequestTime;
   final String jsonrpc;
 
   Map<String, Object?> toJson() {
     var __result = <String, Object?>{};
     __result['jsonrpc'] = jsonrpc;
+    if (clientRequestTime != null) {
+      __result['clientRequestTime'] = clientRequestTime;
+    }
     return __result;
   }
 
@@ -18033,6 +18039,16 @@
       } finally {
         reporter.pop();
       }
+      reporter.push('clientRequestTime');
+      try {
+        final clientRequestTime = obj['clientRequestTime'];
+        if (clientRequestTime != null && !(clientRequestTime is int)) {
+          reporter.reportError('must be of type int');
+          return false;
+        }
+      } finally {
+        reporter.pop();
+      }
       return true;
     } else {
       reporter.reportError('must be of type Message');
@@ -18043,13 +18059,15 @@
   @override
   bool operator ==(Object other) {
     if (other is Message && other.runtimeType == Message) {
-      return jsonrpc == other.jsonrpc && true;
+      return jsonrpc == other.jsonrpc &&
+          clientRequestTime == other.clientRequestTime &&
+          true;
     }
     return false;
   }
 
   @override
-  int get hashCode => jsonrpc.hashCode;
+  int get hashCode => Object.hash(jsonrpc, clientRequestTime);
 
   @override
   String toString() => jsonEncoder.convert(toJson());
@@ -18960,7 +18978,10 @@
       NotificationMessage.canParse, NotificationMessage.fromJson);
 
   NotificationMessage(
-      {required this.method, this.params, required this.jsonrpc});
+      {required this.method,
+      this.params,
+      required this.jsonrpc,
+      this.clientRequestTime});
   static NotificationMessage fromJson(Map<String, Object?> json) {
     final methodJson = json['method'];
     final method = Method.fromJson(methodJson as String);
@@ -18968,10 +18989,16 @@
     final params = paramsJson;
     final jsonrpcJson = json['jsonrpc'];
     final jsonrpc = jsonrpcJson as String;
+    final clientRequestTimeJson = json['clientRequestTime'];
+    final clientRequestTime = clientRequestTimeJson as int?;
     return NotificationMessage(
-        method: method, params: params, jsonrpc: jsonrpc);
+        method: method,
+        params: params,
+        jsonrpc: jsonrpc,
+        clientRequestTime: clientRequestTime);
   }
 
+  final int? clientRequestTime;
   final String jsonrpc;
 
   /// The method to be invoked.
@@ -18987,6 +19014,9 @@
       __result['params'] = params;
     }
     __result['jsonrpc'] = jsonrpc;
+    if (clientRequestTime != null) {
+      __result['clientRequestTime'] = clientRequestTime;
+    }
     return __result;
   }
 
@@ -19028,6 +19058,16 @@
       } finally {
         reporter.pop();
       }
+      reporter.push('clientRequestTime');
+      try {
+        final clientRequestTime = obj['clientRequestTime'];
+        if (clientRequestTime != null && !(clientRequestTime is int)) {
+          reporter.reportError('must be of type int');
+          return false;
+        }
+      } finally {
+        reporter.pop();
+      }
       return true;
     } else {
       reporter.reportError('must be of type NotificationMessage');
@@ -19042,13 +19082,14 @@
       return method == other.method &&
           params == other.params &&
           jsonrpc == other.jsonrpc &&
+          clientRequestTime == other.clientRequestTime &&
           true;
     }
     return false;
   }
 
   @override
-  int get hashCode => Object.hash(method, params, jsonrpc);
+  int get hashCode => Object.hash(method, params, jsonrpc, clientRequestTime);
 
   @override
   String toString() => jsonEncoder.convert(toJson());
@@ -21700,7 +21741,8 @@
       {required this.id,
       required this.method,
       this.params,
-      required this.jsonrpc});
+      required this.jsonrpc,
+      this.clientRequestTime});
   static RequestMessage fromJson(Map<String, Object?> json) {
     final idJson = json['id'];
     final id = idJson is int
@@ -21714,10 +21756,18 @@
     final params = paramsJson;
     final jsonrpcJson = json['jsonrpc'];
     final jsonrpc = jsonrpcJson as String;
+    final clientRequestTimeJson = json['clientRequestTime'];
+    final clientRequestTime = clientRequestTimeJson as int?;
     return RequestMessage(
-        id: id, method: method, params: params, jsonrpc: jsonrpc);
+        id: id,
+        method: method,
+        params: params,
+        jsonrpc: jsonrpc,
+        clientRequestTime: clientRequestTime);
   }
 
+  final int? clientRequestTime;
+
   /// The request id.
   final Either2<int, String> id;
   final String jsonrpc;
@@ -21736,6 +21786,9 @@
       __result['params'] = params;
     }
     __result['jsonrpc'] = jsonrpc;
+    if (clientRequestTime != null) {
+      __result['clientRequestTime'] = clientRequestTime;
+    }
     return __result;
   }
 
@@ -21795,6 +21848,16 @@
       } finally {
         reporter.pop();
       }
+      reporter.push('clientRequestTime');
+      try {
+        final clientRequestTime = obj['clientRequestTime'];
+        if (clientRequestTime != null && !(clientRequestTime is int)) {
+          reporter.reportError('must be of type int');
+          return false;
+        }
+      } finally {
+        reporter.pop();
+      }
       return true;
     } else {
       reporter.reportError('must be of type RequestMessage');
@@ -21809,13 +21872,15 @@
           method == other.method &&
           params == other.params &&
           jsonrpc == other.jsonrpc &&
+          clientRequestTime == other.clientRequestTime &&
           true;
     }
     return false;
   }
 
   @override
-  int get hashCode => Object.hash(id, method, params, jsonrpc);
+  int get hashCode =>
+      Object.hash(id, method, params, jsonrpc, clientRequestTime);
 
   @override
   String toString() => jsonEncoder.convert(toJson());
@@ -21970,7 +22035,12 @@
   static const jsonHandler =
       LspJsonHandler(ResponseMessage.canParse, ResponseMessage.fromJson);
 
-  ResponseMessage({this.id, this.result, this.error, required this.jsonrpc});
+  ResponseMessage(
+      {this.id,
+      this.result,
+      this.error,
+      required this.jsonrpc,
+      this.clientRequestTime});
   static ResponseMessage fromJson(Map<String, Object?> json) {
     final idJson = json['id'];
     final id = idJson == null
@@ -21988,10 +22058,18 @@
         : null;
     final jsonrpcJson = json['jsonrpc'];
     final jsonrpc = jsonrpcJson as String;
+    final clientRequestTimeJson = json['clientRequestTime'];
+    final clientRequestTime = clientRequestTimeJson as int?;
     return ResponseMessage(
-        id: id, result: result, error: error, jsonrpc: jsonrpc);
+        id: id,
+        result: result,
+        error: error,
+        jsonrpc: jsonrpc,
+        clientRequestTime: clientRequestTime);
   }
 
+  final int? clientRequestTime;
+
   /// The error object in case a request fails.
   final ResponseError? error;
 
@@ -22007,6 +22085,9 @@
     var __result = <String, Object?>{};
     __result['id'] = id;
     __result['jsonrpc'] = jsonrpc;
+    if (clientRequestTime != null) {
+      __result['clientRequestTime'] = clientRequestTime;
+    }
     if (error != null && result != null) {
       throw 'result and error cannot both be set';
     } else if (error != null) {
@@ -22061,6 +22142,16 @@
       } finally {
         reporter.pop();
       }
+      reporter.push('clientRequestTime');
+      try {
+        final clientRequestTime = obj['clientRequestTime'];
+        if (clientRequestTime != null && !(clientRequestTime is int)) {
+          reporter.reportError('must be of type int');
+          return false;
+        }
+      } finally {
+        reporter.pop();
+      }
       return true;
     } else {
       reporter.reportError('must be of type ResponseMessage');
@@ -22075,13 +22166,15 @@
           result == other.result &&
           error == other.error &&
           jsonrpc == other.jsonrpc &&
+          clientRequestTime == other.clientRequestTime &&
           true;
     }
     return false;
   }
 
   @override
-  int get hashCode => Object.hash(id, result, error, jsonrpc);
+  int get hashCode =>
+      Object.hash(id, result, error, jsonrpc, clientRequestTime);
 
   @override
   String toString() => jsonEncoder.convert(toJson());
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart
index e953ef6..87c6f3b 100644
--- a/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart
@@ -267,6 +267,7 @@
 /// A base class containing the fields common to RequestMessage and
 /// NotificationMessage to simplify handling.
 abstract class IncomingMessage {
+  int? get clientRequestTime;
   Method get method;
   dynamic get params;
 }
diff --git a/pkg/analysis_server/lib/protocol/protocol.dart b/pkg/analysis_server/lib/protocol/protocol.dart
index bea052b..b093fc0 100644
--- a/pkg/analysis_server/lib/protocol/protocol.dart
+++ b/pkg/analysis_server/lib/protocol/protocol.dart
@@ -97,6 +97,15 @@
     return id.hashCode;
   }
 
+  /// Returns the amount of time (in milliseconds) since the client sent this
+  /// request or `null` if the client did not provide [clientRequestTime].
+  int? get timeSinceRequest {
+    var clientRequestTime = this.clientRequestTime;
+    return clientRequestTime != null
+        ? DateTime.now().millisecondsSinceEpoch - clientRequestTime
+        : null;
+  }
+
   @override
   bool operator ==(Object other) {
     return other is Request &&
diff --git a/pkg/analysis_server/lib/src/handler/legacy/completion_get_suggestions.dart b/pkg/analysis_server/lib/src/handler/legacy/completion_get_suggestions.dart
index 3ce2461..ecba1d8 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/completion_get_suggestions.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/completion_get_suggestions.dart
@@ -28,6 +28,7 @@
       return;
     }
 
+    var requestLatency = request.timeSinceRequest;
     var budget = CompletionBudget(server.completionState.budgetDuration);
 
     // extract and validate params
@@ -94,6 +95,7 @@
         final completionPerformance = CompletionPerformance(
           operation: performance,
           path: file,
+          requestLatency: requestLatency,
           content: resolvedUnit.content,
           offset: offset,
         );
diff --git a/pkg/analysis_server/lib/src/handler/legacy/completion_get_suggestions2.dart b/pkg/analysis_server/lib/src/handler/legacy/completion_get_suggestions2.dart
index 48d75db..5b84755 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/completion_get_suggestions2.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/completion_get_suggestions2.dart
@@ -111,6 +111,7 @@
       return;
     }
 
+    var requestLatency = request.timeSinceRequest;
     var params = CompletionGetSuggestions2Params.fromRequest(request);
     var file = params.file;
     var offset = params.offset;
@@ -177,6 +178,7 @@
         final completionPerformance = CompletionPerformance(
           operation: performance,
           path: file,
+          requestLatency: requestLatency,
           content: resolvedUnit.content,
           offset: offset,
         );
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_diagnostic_server.dart b/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_diagnostic_server.dart
index 4eff16c..3c081c8 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_diagnostic_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_diagnostic_server.dart
@@ -19,7 +19,7 @@
 
   @override
   Future<ErrorOr<DartDiagnosticServer>> handle(
-      void _, CancellationToken token) async {
+      void _, MessageInfo message, CancellationToken token) async {
     final diagnosticServer = server.diagnosticServer;
     if (diagnosticServer == null) {
       return error(ServerErrorCodes.FeatureDisabled,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_reanalyze.dart b/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_reanalyze.dart
index 065424d..f3e68d1 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_reanalyze.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_reanalyze.dart
@@ -16,7 +16,8 @@
   LspJsonHandler<void> get jsonHandler => NullJsonHandler;
 
   @override
-  Future<ErrorOr<void>> handle(void _, CancellationToken token) async {
+  Future<ErrorOr<void>> handle(
+      void _, MessageInfo message, CancellationToken token) async {
     server.reanalyze();
     return success(null);
   }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_super.dart b/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_super.dart
index 6cfac88..46ab360 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_super.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/custom/handler_super.dart
@@ -21,8 +21,8 @@
       TextDocumentPositionParams.jsonHandler;
 
   @override
-  Future<ErrorOr<Location?>> handle(
-      TextDocumentPositionParams params, CancellationToken token) async {
+  Future<ErrorOr<Location?>> handle(TextDocumentPositionParams params,
+      MessageInfo message, CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success(null);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_cancel_request.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_cancel_request.dart
index bbda2f8..a2d3280 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_cancel_request.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_cancel_request.dart
@@ -28,7 +28,8 @@
   }
 
   @override
-  ErrorOr<void> handle(CancelParams params, CancellationToken token) {
+  ErrorOr<void> handle(
+      CancelParams params, MessageInfo message, CancellationToken token) {
     // Don't assume this is in the map as it's possible the client sent a
     // cancellation that we processed after already starting to send the response
     // and cleared the token.
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_change_workspace_folders.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_change_workspace_folders.dart
index a171a36..ee5e401 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_change_workspace_folders.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_change_workspace_folders.dart
@@ -21,8 +21,8 @@
       DidChangeWorkspaceFoldersParams.jsonHandler;
 
   @override
-  Future<ErrorOr<void>> handle(
-      DidChangeWorkspaceFoldersParams params, CancellationToken token) async {
+  Future<ErrorOr<void>> handle(DidChangeWorkspaceFoldersParams params,
+      MessageInfo message, CancellationToken token) async {
     // Don't do anything if our analysis roots are not based on open workspaces.
     if (!updateAnalysisRoots) {
       return success(null);
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index 607bdd5..3c7181e 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -61,7 +61,9 @@
 
   @override
   Future<ErrorOr<List<Either2<Command, CodeAction>>>> handle(
-      CodeActionParams params, CancellationToken token) async {
+      CodeActionParams params,
+      MessageInfo message,
+      CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success(const []);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index 2878d4e..ece08b5 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -49,14 +49,15 @@
       CompletionParams.jsonHandler;
 
   @override
-  Future<ErrorOr<CompletionList>> handle(
-      CompletionParams params, CancellationToken token) async {
+  Future<ErrorOr<CompletionList>> handle(CompletionParams params,
+      MessageInfo message, CancellationToken token) async {
     final clientCapabilities = server.clientCapabilities;
     if (clientCapabilities == null) {
       // This should not happen unless a client misbehaves.
       return serverNotInitializedError;
     }
 
+    final requestLatency = message.timeSinceRequest;
     final triggerCharacter = params.context?.triggerCharacter;
     final pos = params.position;
     final path = pathOfDoc(params.textDocument);
@@ -108,25 +109,26 @@
     CompletionPerformance? completionPerformance;
     if (fileExtension == '.dart' && !unit.isError) {
       final result = unit.result;
-      var performanceOperation = OperationPerformanceImpl('<root>');
-
-      serverResultsFuture = await performanceOperation.runAsync(
+      var performance = OperationPerformanceImpl('<root>');
+      serverResultsFuture = performance.runAsync(
         'request',
         (performance) async {
           final thisPerformance = CompletionPerformance(
             operation: performance,
             path: result.path,
+            requestLatency: requestLatency,
             content: result.content,
             offset: offset,
           );
           completionPerformance = thisPerformance;
           server.performanceStats.completion.add(thisPerformance);
 
-          return _getServerDartItems(
+          // `await` required for `performance.runAsync` to count time.
+          return await _getServerDartItems(
             clientCapabilities,
             unit.result,
             thisPerformance,
-            performanceOperation,
+            performance,
             offset,
             triggerCharacter,
             token,
@@ -322,17 +324,21 @@
     }
 
     try {
-      var contributor = DartCompletionManager(
-        budget: CompletionBudget(CompletionBudget.defaultDuration),
-        includedElementKinds: includedElementKinds,
-        includedElementNames: includedElementNames,
-        includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
-      );
+      final serverSuggestions2 =
+          await performance.runAsync('computeSuggestions', (performance) async {
+        var contributor = DartCompletionManager(
+          budget: CompletionBudget(CompletionBudget.defaultDuration),
+          includedElementKinds: includedElementKinds,
+          includedElementNames: includedElementNames,
+          includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
+        );
 
-      final serverSuggestions2 = await contributor.computeSuggestions(
-        completionRequest,
-        performance,
-      );
+        // `await` required for `performance.runAsync` to count time.
+        return await contributor.computeSuggestions(
+          completionRequest,
+          performance,
+        );
+      });
 
       final serverSuggestions = serverSuggestions2.map((serverSuggestion) {
         return serverSuggestion.build();
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
index 56bec62..4a7b49b 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
@@ -37,6 +37,7 @@
   @override
   Future<ErrorOr<CompletionItem>> handle(
     CompletionItem item,
+    MessageInfo message,
     CancellationToken token,
   ) async {
     final resolutionInfo = item.data;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
index 2abf3c3..39e7fe8 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
@@ -71,7 +71,9 @@
 
   @override
   Future<ErrorOr<Either2<List<Location>, List<LocationLink>>>> handle(
-      TextDocumentPositionParams params, CancellationToken token) async {
+      TextDocumentPositionParams params,
+      MessageInfo message,
+      CancellationToken token) async {
     final clientCapabilities = server.clientCapabilities;
     if (clientCapabilities == null) {
       // This should not happen unless a client misbehaves.
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_color.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_color.dart
index 124caa1..d632039 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_color.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_color.dart
@@ -28,8 +28,8 @@
       DocumentColorParams.jsonHandler;
 
   @override
-  Future<ErrorOr<List<ColorInformation>>> handle(
-      DocumentColorParams params, CancellationToken token) async {
+  Future<ErrorOr<List<ColorInformation>>> handle(DocumentColorParams params,
+      MessageInfo message, CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success([]);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_color_presentation.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_color_presentation.dart
index bb1adb4..3a14093 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_color_presentation.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_color_presentation.dart
@@ -32,6 +32,7 @@
   @override
   Future<ErrorOr<List<ColorPresentation>>> handle(
     ColorPresentationParams params,
+    MessageInfo message,
     CancellationToken token,
   ) async {
     if (!isDartDocument(params.textDocument)) {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_highlights.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_highlights.dart
index 56fadb8..4b3bba5 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_highlights.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_highlights.dart
@@ -21,7 +21,9 @@
 
   @override
   Future<ErrorOr<List<DocumentHighlight>?>> handle(
-      TextDocumentPositionParams params, CancellationToken token) async {
+      TextDocumentPositionParams params,
+      MessageInfo message,
+      CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success(const []);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart
index bccc9dc..38754f9 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart
@@ -24,7 +24,8 @@
 
   @override
   Future<ErrorOr<Either2<List<DocumentSymbol>, List<SymbolInformation>>?>>
-      handle(DocumentSymbolParams params, CancellationToken token) async {
+      handle(DocumentSymbolParams params, MessageInfo message,
+          CancellationToken token) async {
     final clientCapabilities = server.clientCapabilities;
     if (clientCapabilities == null || !isDartDocument(params.textDocument)) {
       return success(
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_execute_command.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_execute_command.dart
index b5c5ff6..4cbde68 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_execute_command.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_execute_command.dart
@@ -37,8 +37,8 @@
       ExecuteCommandParams.jsonHandler;
 
   @override
-  Future<ErrorOr<Object?>> handle(
-      ExecuteCommandParams params, CancellationToken cancellationToken) async {
+  Future<ErrorOr<Object?>> handle(ExecuteCommandParams params,
+      MessageInfo message, CancellationToken cancellationToken) async {
     final handler = commandHandlers[params.command];
     if (handler == null) {
       return error(ServerErrorCodes.UnknownCommand,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_exit.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_exit.dart
index 4aeb552..56923e8 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_exit.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_exit.dart
@@ -23,7 +23,8 @@
   LspJsonHandler<void> get jsonHandler => NullJsonHandler;
 
   @override
-  Future<ErrorOr<void>> handle(void _, CancellationToken token) async {
+  Future<ErrorOr<void>> handle(
+      void _, MessageInfo message, CancellationToken token) async {
     // Set a flag that the server shutdown is being controlled here to ensure
     // that the normal code that shuts down the server when the channel closes
     // does not fire.
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart
index 6a3cb20..27590e6 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_folding.dart
@@ -21,8 +21,8 @@
       FoldingRangeParams.jsonHandler;
 
   @override
-  Future<ErrorOr<List<FoldingRange>>> handle(
-      FoldingRangeParams params, CancellationToken token) async {
+  Future<ErrorOr<List<FoldingRange>>> handle(FoldingRangeParams params,
+      MessageInfo message, CancellationToken token) async {
     final path = pathOfDoc(params.textDocument);
 
     return path.mapResult((path) async {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart
index 8359bc7..23cfd7d 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_format_on_type.dart
@@ -36,8 +36,8 @@
   }
 
   @override
-  Future<ErrorOr<List<TextEdit>?>> handle(
-      DocumentOnTypeFormattingParams params, CancellationToken token) async {
+  Future<ErrorOr<List<TextEdit>?>> handle(DocumentOnTypeFormattingParams params,
+      MessageInfo message, CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success(null);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_format_range.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_format_range.dart
index a7eda8c..ab8a7c1 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_format_range.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_format_range.dart
@@ -36,8 +36,8 @@
   }
 
   @override
-  Future<ErrorOr<List<TextEdit>?>> handle(
-      DocumentRangeFormattingParams params, CancellationToken token) async {
+  Future<ErrorOr<List<TextEdit>?>> handle(DocumentRangeFormattingParams params,
+      MessageInfo message, CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success(null);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart
index 9e058a9..10df929 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_formatting.dart
@@ -36,8 +36,8 @@
   }
 
   @override
-  Future<ErrorOr<List<TextEdit>?>> handle(
-      DocumentFormattingParams params, CancellationToken token) async {
+  Future<ErrorOr<List<TextEdit>?>> handle(DocumentFormattingParams params,
+      MessageInfo message, CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success(null);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_hover.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_hover.dart
index ef82f5b..eaebf09 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_hover.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_hover.dart
@@ -22,8 +22,8 @@
       TextDocumentPositionParams.jsonHandler;
 
   @override
-  Future<ErrorOr<Hover?>> handle(
-      TextDocumentPositionParams params, CancellationToken token) async {
+  Future<ErrorOr<Hover?>> handle(TextDocumentPositionParams params,
+      MessageInfo message, CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success(null);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_implementation.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_implementation.dart
index 1bdc73e..dcca7a9 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_implementation.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_implementation.dart
@@ -21,8 +21,8 @@
       TextDocumentPositionParams.jsonHandler;
 
   @override
-  Future<ErrorOr<List<Location>>> handle(
-      TextDocumentPositionParams params, CancellationToken token) async {
+  Future<ErrorOr<List<Location>>> handle(TextDocumentPositionParams params,
+      MessageInfo message, CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success(const []);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
index a6a6a24..0d08fba 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialize.dart
@@ -22,7 +22,7 @@
 
   @override
   ErrorOr<InitializeResult> handle(
-      InitializeParams params, CancellationToken token) {
+      InitializeParams params, MessageInfo message, CancellationToken token) {
     server.handleClientConnection(
       params.capabilities,
       params.initializationOptions,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialized.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialized.dart
index a3e92d9..912ab3c 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_initialized.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_initialized.dart
@@ -21,8 +21,8 @@
       InitializedParams.jsonHandler;
 
   @override
-  Future<ErrorOr<void>> handle(
-      InitializedParams params, CancellationToken token) async {
+  Future<ErrorOr<void>> handle(InitializedParams params, MessageInfo message,
+      CancellationToken token) async {
     server.messageHandler = InitializedStateMessageHandler(
       server,
     );
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_references.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_references.dart
index 7db933a..69aef3b 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_references.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_references.dart
@@ -27,8 +27,8 @@
       ReferenceParams.jsonHandler;
 
   @override
-  Future<ErrorOr<List<Location>?>> handle(
-      ReferenceParams params, CancellationToken token) async {
+  Future<ErrorOr<List<Location>?>> handle(ReferenceParams params,
+      MessageInfo message, CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success(const []);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_reject.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_reject.dart
index dbfe32a..ddc4740 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_reject.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_reject.dart
@@ -20,7 +20,8 @@
   LspJsonHandler<void> get jsonHandler => NullJsonHandler;
 
   @override
-  ErrorOr<void> handle(Object? _, CancellationToken token) {
+  ErrorOr<void> handle(
+      Object? _, MessageInfo message, CancellationToken token) {
     return error(errorCode, errorMessage, null);
   }
 }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart
index a438d7d..bd313fc 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart
@@ -24,7 +24,9 @@
 
   @override
   Future<ErrorOr<RangeAndPlaceholder?>> handle(
-      TextDocumentPositionParams params, CancellationToken token) async {
+      TextDocumentPositionParams params,
+      MessageInfo message,
+      CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success(null);
     }
@@ -98,7 +100,7 @@
 
   @override
   Future<ErrorOr<WorkspaceEdit?>> handle(
-      RenameParams params, CancellationToken token) async {
+      RenameParams params, MessageInfo message, CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success(null);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart
index c567939..34a7f0a 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_select_range.dart
@@ -22,8 +22,8 @@
       SelectionRangeParams.jsonHandler;
 
   @override
-  Future<ErrorOr<List<SelectionRange>?>> handle(
-      SelectionRangeParams params, CancellationToken token) async {
+  Future<ErrorOr<List<SelectionRange>?>> handle(SelectionRangeParams params,
+      MessageInfo message, CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success(null);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_semantic_tokens.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_semantic_tokens.dart
index 452e3d8..cb6ea2a 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_semantic_tokens.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_semantic_tokens.dart
@@ -122,8 +122,8 @@
       SemanticTokensParams.jsonHandler;
 
   @override
-  Future<ErrorOr<SemanticTokens?>> handle(
-          SemanticTokensParams params, CancellationToken token) =>
+  Future<ErrorOr<SemanticTokens?>> handle(SemanticTokensParams params,
+          MessageInfo message, CancellationToken token) =>
       _handleImpl(params.textDocument, token);
 }
 
@@ -139,7 +139,7 @@
       SemanticTokensRangeParams.jsonHandler;
 
   @override
-  Future<ErrorOr<SemanticTokens?>> handle(
-          SemanticTokensRangeParams params, CancellationToken token) =>
+  Future<ErrorOr<SemanticTokens?>> handle(SemanticTokensRangeParams params,
+          MessageInfo message, CancellationToken token) =>
       _handleImpl(params.textDocument, token, range: params.range);
 }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_shutdown.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_shutdown.dart
index ea09041..14a1273 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_shutdown.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_shutdown.dart
@@ -16,7 +16,7 @@
   LspJsonHandler<void> get jsonHandler => NullJsonHandler;
 
   @override
-  ErrorOr<void> handle(void _, CancellationToken token) {
+  ErrorOr<void> handle(void _, MessageInfo message, CancellationToken token) {
     // Move to the Shutting Down state so we won't process any more
     // requests and the Exit notification will know it was a clean shutdown.
     server.messageHandler = ShuttingDownStateMessageHandler(server);
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart
index aebf669..743f981 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart
@@ -22,8 +22,8 @@
       SignatureHelpParams.jsonHandler;
 
   @override
-  Future<ErrorOr<SignatureHelp?>> handle(
-      SignatureHelpParams params, CancellationToken token) async {
+  Future<ErrorOr<SignatureHelp?>> handle(SignatureHelpParams params,
+      MessageInfo message, CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success(null);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
index b05b882..aa59bfc 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
@@ -22,8 +22,8 @@
       DidChangeTextDocumentParams.jsonHandler;
 
   @override
-  FutureOr<ErrorOr<void>> handle(
-      DidChangeTextDocumentParams params, CancellationToken token) {
+  FutureOr<ErrorOr<void>> handle(DidChangeTextDocumentParams params,
+      MessageInfo message, CancellationToken token) {
     final path = pathOfDoc(params.textDocument);
     return path.mapResult((path) => _changeFile(path, params));
   }
@@ -66,8 +66,8 @@
       DidCloseTextDocumentParams.jsonHandler;
 
   @override
-  FutureOr<ErrorOr<void>> handle(
-      DidCloseTextDocumentParams params, CancellationToken token) {
+  FutureOr<ErrorOr<void>> handle(DidCloseTextDocumentParams params,
+      MessageInfo message, CancellationToken token) {
     final path = pathOfDoc(params.textDocument);
     return path.mapResult((path) async {
       await server.removePriorityFile(path);
@@ -91,8 +91,8 @@
       DidOpenTextDocumentParams.jsonHandler;
 
   @override
-  FutureOr<ErrorOr<void>> handle(
-      DidOpenTextDocumentParams params, CancellationToken token) {
+  FutureOr<ErrorOr<void>> handle(DidOpenTextDocumentParams params,
+      MessageInfo message, CancellationToken token) {
     final doc = params.textDocument;
     final path = pathOfDocItem(doc);
     return path.mapResult((path) async {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_type_definition.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_type_definition.dart
index 37461bc..2f75106 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_type_definition.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_type_definition.dart
@@ -33,8 +33,8 @@
       TypeDefinitionParams.jsonHandler;
 
   @override
-  Future<ErrorOr<_LocationsOrLinks>> handle(
-      TypeDefinitionParams params, CancellationToken token) async {
+  Future<ErrorOr<_LocationsOrLinks>> handle(TypeDefinitionParams params,
+      MessageInfo message, CancellationToken token) async {
     if (!isDartDocument(params.textDocument)) {
       return success(_emptyResult);
     }
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_will_rename_files.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_will_rename_files.dart
index fef59a2..a34724b 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_will_rename_files.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_will_rename_files.dart
@@ -19,8 +19,8 @@
       RenameFilesParams.jsonHandler;
 
   @override
-  Future<ErrorOr<WorkspaceEdit?>> handle(
-      RenameFilesParams params, CancellationToken token) async {
+  Future<ErrorOr<WorkspaceEdit?>> handle(RenameFilesParams params,
+      MessageInfo message, CancellationToken token) async {
     final files = params.files;
     // Only single-file rename/moves are currently supported.
     // TODO(dantup): Tweak this when VS Code can correctly pass us cancellation
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_configuration.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_configuration.dart
index aa911f2..092d62b 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_configuration.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_configuration.dart
@@ -18,8 +18,8 @@
       DidChangeConfigurationParams.jsonHandler;
 
   @override
-  Future<ErrorOr<void>> handle(
-      DidChangeConfigurationParams params, CancellationToken token) async {
+  Future<ErrorOr<void>> handle(DidChangeConfigurationParams params,
+      MessageInfo message, CancellationToken token) async {
     // In LSP, the `settings` field no longer contains changed settings because
     // they can be resource-scoped, so this is used only as a notification and
     // to keep settings up-to-date we must re-request them from the client
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_symbols.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_symbols.dart
index be548d8..ad70de7 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_symbols.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_symbols.dart
@@ -19,8 +19,8 @@
       WorkspaceSymbolParams.jsonHandler;
 
   @override
-  Future<ErrorOr<List<SymbolInformation>>> handle(
-      WorkspaceSymbolParams params, CancellationToken token) async {
+  Future<ErrorOr<List<SymbolInformation>>> handle(WorkspaceSymbolParams params,
+      MessageInfo message, CancellationToken token) async {
     final clientCapabilities = server.clientCapabilities;
     if (clientCapabilities == null) {
       // This should not happen unless a client misbehaves.
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
index a312139..4142d81 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
@@ -161,7 +161,8 @@
   /// A handler that can parse and validate JSON params.
   LspJsonHandler<P> get jsonHandler;
 
-  FutureOr<ErrorOr<R>> handle(P params, CancellationToken token);
+  FutureOr<ErrorOr<R>> handle(
+      P params, MessageInfo message, CancellationToken token);
 
   /// Handle the given [message]. If the [message] is a [RequestMessage], then the
   /// return value will be sent back in a [ResponseMessage].
@@ -182,7 +183,25 @@
 
     final params =
         paramsJson != null ? jsonHandler.convertParams(paramsJson) : null as P;
-    return handle(params, token);
+    final messageInfo = MessageInfo(message.clientRequestTime);
+    return handle(params, messageInfo, token);
+  }
+}
+
+/// Additional information about an incoming message (request or notification)
+/// provided to a handler.
+class MessageInfo {
+  final int? clientRequestTime;
+
+  MessageInfo(this.clientRequestTime);
+
+  /// Returns the amount of time (in milliseconds) since the client sent this
+  /// request or `null` if the client did not provide [clientRequestTime].
+  int? get timeSinceRequest {
+    var clientRequestTime = this.clientRequestTime;
+    return clientRequestTime != null
+        ? DateTime.now().millisecondsSinceEpoch - clientRequestTime
+        : null;
   }
 }
 
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index dba5fc2..7617056 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -349,7 +349,7 @@
 
   /// Handle a [message] that was read from the communication channel.
   void handleMessage(Message message) {
-    performance.logRequestTiming(null);
+    performance.logRequestTiming(message.clientRequestTime);
     runZonedGuarded(() async {
       try {
         if (message is ResponseMessage) {
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_performance.dart b/pkg/analysis_server/lib/src/services/completion/completion_performance.dart
index c41731b..069d5df 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_performance.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_performance.dart
@@ -38,18 +38,20 @@
   final OperationPerformance operation;
   final String path;
   final String snippet;
-  int computedSuggestionCount = -1;
-  int transmittedSuggestionCount = -1;
+  final int? requestLatency;
+  int? computedSuggestionCount;
+  int? transmittedSuggestionCount;
 
   CompletionPerformance({
     required this.operation,
     required this.path,
+    this.requestLatency,
     required String content,
     required int offset,
   }) : snippet = _computeCompletionSnippet(content, offset);
 
   String get computedSuggestionCountStr {
-    if (computedSuggestionCount < 1) return '';
+    if (computedSuggestionCount == null) return '';
     return '$computedSuggestionCount';
   }
 
@@ -58,7 +60,7 @@
   }
 
   String get transmittedSuggestionCountStr {
-    if (transmittedSuggestionCount < 1) return '';
+    if (transmittedSuggestionCount == null) return '';
     return '$transmittedSuggestionCount';
   }
 }
diff --git a/pkg/analysis_server/lib/src/status/diagnostics.dart b/pkg/analysis_server/lib/src/status/diagnostics.dart
index 826f5cb..148f1db 100644
--- a/pkg/analysis_server/lib/src/status/diagnostics.dart
+++ b/pkg/analysis_server/lib/src/status/diagnostics.dart
@@ -179,11 +179,14 @@
         '<div id="chart-div" style="width: 700px; height: 300px;"></div>');
     var rowData = StringBuffer();
     for (var i = completions.length - 1; i >= 0; i--) {
-      // [' ', 101.5]
       if (rowData.isNotEmpty) {
         rowData.write(',');
       }
-      rowData.write("[' ', ${completions[i].elapsedInMilliseconds}]");
+      var latency = completions[i].requestLatency ?? 0;
+      var completionTime = completions[i].elapsedInMilliseconds;
+      // label, latency, time
+      // [' ', 21.0, 101.5]
+      rowData.write("[' ', $latency, $completionTime]");
     }
     buf.writeln('''
       <script type="text/javascript">
@@ -191,10 +194,19 @@
       google.charts.setOnLoadCallback(drawChart);
       function drawChart() {
         var data = google.visualization.arrayToDataTable([
-          ['Completions', 'Time'],
+          [ 'Completion', 'Latency', 'Time' ],
           $rowData
         ]);
-        var options = { bars: 'vertical', vAxis: {format: 'decimal'}, height: 300 };
+        var options = {
+          bars: 'vertical',
+          vAxis: {format: 'decimal'},
+          height: 300,
+          isStacked: true,
+          series: {
+            0: { color: '#C0C0C0' },
+            1: { color: '#4285f4' },
+          }
+        };
         var chart = new google.charts.Bar(document.getElementById('chart-div'));
         chart.draw(data, google.charts.Bar.convertOptions(options));
       }
@@ -208,7 +220,7 @@
     for (var completion in completions) {
       var shortName = pathContext.basename(completion.path);
       buf.writeln('<tr>'
-          '<td class="pre right">${printMilliseconds(completion.elapsedInMilliseconds)}</td>'
+          '<td class="pre right">${_formatTiming(completion)}</td>'
           '<td class="right">${completion.computedSuggestionCountStr}</td>'
           '<td class="right">${completion.transmittedSuggestionCountStr}</td>'
           '<td>${escape(shortName)}</td>'
@@ -217,6 +229,21 @@
     }
     buf.writeln('</table>');
   }
+
+  String _formatTiming(CompletionPerformance completion) {
+    var buffer = StringBuffer();
+    buffer.write(printMilliseconds(completion.elapsedInMilliseconds));
+
+    var latency = completion.requestLatency;
+    if (latency != null) {
+      buffer
+        ..write(' <small title="client-to-server latency">(+ ')
+        ..write(printMilliseconds(latency))
+        ..write(')</small>');
+    }
+
+    return buffer.toString();
+  }
 }
 
 class AstPage extends DiagnosticPageWithNav {
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index a5e88ea..5c61998 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -648,6 +648,9 @@
 
   final validProgressTokens = <Either2<num, String>>{};
 
+  /// Whether to include 'clientRequestTime' fields in outgoing messages.
+  bool includeClientRequestTime = false;
+
   /// A stream of [NotificationMessage]s from the server that may be errors.
   Stream<NotificationMessage> get errorNotificationsFromServer {
     return notificationsFromServer.where(_isErrorNotification);
@@ -1416,7 +1419,10 @@
     bool throwOnFailure = true,
     bool allowEmptyRootUri = false,
     bool failTestOnAnyErrorNotification = true,
+    bool includeClientRequestTime = false,
   }) async {
+    this.includeClientRequestTime = includeClientRequestTime;
+
     if (failTestOnAnyErrorNotification) {
       errorNotificationsFromServer.listen((NotificationMessage error) {
         fail('${error.toJson()}');
@@ -1481,7 +1487,13 @@
 
   NotificationMessage makeNotification(Method method, ToJsonable? params) {
     return NotificationMessage(
-        method: method, params: params, jsonrpc: jsonRpcVersion);
+      method: method,
+      params: params,
+      jsonrpc: jsonRpcVersion,
+      clientRequestTime: includeClientRequestTime
+          ? DateTime.now().millisecondsSinceEpoch
+          : null,
+    );
   }
 
   RequestMessage makeRenameRequest(
@@ -1500,7 +1512,14 @@
   RequestMessage makeRequest(Method method, ToJsonable? params) {
     final id = Either2<int, String>.t1(_id++);
     return RequestMessage(
-        id: id, method: method, params: params, jsonrpc: jsonRpcVersion);
+      id: id,
+      method: method,
+      params: params,
+      jsonrpc: jsonRpcVersion,
+      clientRequestTime: includeClientRequestTime
+          ? DateTime.now().millisecondsSinceEpoch
+          : null,
+    );
   }
 
   /// Watches for `client/registerCapability` requests and updates
diff --git a/pkg/analysis_server/test/lsp/server_test.dart b/pkg/analysis_server/test/lsp/server_test.dart
index 48d0109..a1a3ef2 100644
--- a/pkg/analysis_server/test/lsp/server_test.dart
+++ b/pkg/analysis_server/test/lsp/server_test.dart
@@ -21,6 +21,21 @@
 
 @reflectiveTest
 class ServerTest extends AbstractLspAnalysisServerTest {
+  Future<void> test_capturesLatency_afterStartup() async {
+    await initialize(includeClientRequestTime: true);
+    await openFile(mainFileUri, '');
+    await expectLater(
+      getHover(mainFileUri, startOfDocPos),
+      completes,
+    );
+    expect(server.performanceAfterStartup!.latencyCount, isPositive);
+  }
+
+  Future<void> test_capturesLatency_startup() async {
+    await initialize(includeClientRequestTime: true);
+    expect(server.performanceDuringStartup.latencyCount, isPositive);
+  }
+
   Future<void> test_inconsistentStateError() async {
     await initialize(
       // Error is expected and checked below.
diff --git a/pkg/analysis_server/tool/lsp_spec/README.md b/pkg/analysis_server/tool/lsp_spec/README.md
index a27f04c..469cf1c 100644
--- a/pkg/analysis_server/tool/lsp_spec/README.md
+++ b/pkg/analysis_server/tool/lsp_spec/README.md
@@ -113,9 +113,13 @@
 | textDocument/semanticTokens/full | ✅ | ✅ | ✅ | ✅ | ✅ |
 | textDocument/semanticTokens/range | ✅ | ✅ | ✅ | ✅ | ✅ |
 
-## Custom Methods and Notifications
+## Custom Fields, Methods and Notifications
 
-The following custom methods/notifications are also provided by the Dart LSP server:
+The following custom fields/methods/notifications are also provided by the Dart LSP server:
+
+### Message.clientRequestTime Field
+
+The server accepts an optional `int?` on all incoming messages named `clientRequestTime` (alongside `id`, `method`, `params`) containing a timestamp (milliseconds since epoch) of when the client made that request. Providing clientRequestTime helps track how responsive analysis server is to client requests and better address any issues that occur.
 
 ### dart/diagnosticServer Method
 
diff --git a/pkg/analysis_server/tool/lsp_spec/generate_all.dart b/pkg/analysis_server/tool/lsp_spec/generate_all.dart
index b25b7c7..f17f389 100644
--- a/pkg/analysis_server/tool/lsp_spec/generate_all.dart
+++ b/pkg/analysis_server/tool/lsp_spec/generate_all.dart
@@ -198,8 +198,8 @@
     var fieldType =
         array ? ArrayType(Type.identifier(type)) : Type.identifier(type);
 
-    return Field(
-        null, Token.identifier(name), fieldType, false, canBeUndefined);
+    return Field(null, Token.identifier(name), fieldType,
+        allowsNull: false, allowsUndefined: canBeUndefined);
   }
 
   final customTypes = <AstNode>[
@@ -311,6 +311,34 @@
   return customTypes;
 }
 
+/// Gets additional custom fields to be added to LSP Spec classes.
+///
+/// Non-standard fields should generally be avoided and must always allow
+/// undefined.
+List<Field> getCustomFields(String interfaceName) {
+  final additionalFields = <String, List<Field>>{
+    // Allow clients to pass a "clientRequestTime" against any incomine message
+    // so that we can capture latency information for requests for performance
+    // measurements.
+    'Message': [
+      Field(
+        null,
+        Token.identifier('clientRequestTime'),
+        Type.identifier('int'),
+        allowsNull: false,
+        allowsUndefined: true,
+      ),
+    ],
+  };
+
+  final fields = additionalFields[interfaceName] ?? [];
+  assert(
+    fields.every((field) => field.allowsUndefined),
+    'Any additional non-standard LSP field must allow undefined',
+  );
+  return fields;
+}
+
 Future<List<AstNode>> getSpecClasses(ArgResults args) async {
   var download = args[argDownload] as bool;
   if (download) {
@@ -323,6 +351,7 @@
       .map(parseString)
       .expand((f) => f)
       .where(includeTypeDefinitionInOutput)
+      .map(withCustomFields)
       .toList();
 
   // Generate an enum for all of the request methods to avoid strings.
@@ -367,3 +396,23 @@
 
   return true;
 }
+
+/// Returns [node] with any additional custom fields.
+AstNode withCustomFields(AstNode node) {
+  if (node is! Interface) {
+    return node;
+  }
+
+  final customFields = getCustomFields(node.name);
+  if (customFields.isEmpty) {
+    return node;
+  }
+
+  return Interface(
+    node.commentNode,
+    node.nameToken,
+    node.typeArgs,
+    node.baseTypes,
+    [...node.members, ...customFields],
+  );
+}
diff --git a/pkg/analysis_server/tool/lsp_spec/typescript_parser.dart b/pkg/analysis_server/tool/lsp_spec/typescript_parser.dart
index a268eff..032cd2f 100644
--- a/pkg/analysis_server/tool/lsp_spec/typescript_parser.dart
+++ b/pkg/analysis_server/tool/lsp_spec/typescript_parser.dart
@@ -113,10 +113,10 @@
   Field(
     super.comment,
     this.nameToken,
-    this.type,
-    this.allowsNull,
-    this.allowsUndefined,
-  );
+    this.type, {
+    required this.allowsNull,
+    required this.allowsUndefined,
+  });
 
   @override
   String get name => nameToken.lexeme;
@@ -131,7 +131,8 @@
     TypeBase type,
     bool allowsNull,
     bool allowsUndefined,
-  ) : super(comment, nameToken, type, allowsNull, allowsUndefined);
+  ) : super(comment, nameToken, type,
+            allowsNull: allowsNull, allowsUndefined: allowsUndefined);
 }
 
 class Indexer extends Member {
@@ -408,7 +409,8 @@
       // successful response that has no return value, eg. shutdown).
       canBeNull = true;
     }
-    return Field(leadingComment, name, type, canBeNull, canBeUndefined);
+    return Field(leadingComment, name, type,
+        allowsNull: canBeNull, allowsUndefined: canBeUndefined);
   }
 
   Indexer _indexer(String containerName, Comment? leadingComment) {
diff --git a/pkg/analyzer/lib/src/clients/dart_style/rewrite_cascade.dart b/pkg/analyzer/lib/src/clients/dart_style/rewrite_cascade.dart
index 3cccf58..f79d178 100644
--- a/pkg/analyzer/lib/src/clients/dart_style/rewrite_cascade.dart
+++ b/pkg/analyzer/lib/src/clients/dart_style/rewrite_cascade.dart
@@ -4,6 +4,7 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/ast_factory.dart';
 
 /// Parenthesize the target of the [expressionStatement]'s expression (assumed
@@ -44,13 +45,13 @@
 
   // Otherwise, copy `expression` and recurse into its LHS.
   if (expression is AssignmentExpression) {
-    return astFactory.assignmentExpression(
-      insertCascadeTargetIntoExpression(
+    return AssignmentExpressionImpl(
+      leftHandSide: insertCascadeTargetIntoExpression(
         expression: expression.leftHandSide,
         cascadeTarget: cascadeTarget,
-      ),
-      expression.operator,
-      expression.rightHandSide,
+      ) as ExpressionImpl,
+      operator: expression.operator,
+      rightHandSide: expression.rightHandSide as ExpressionImpl,
     );
   } else if (expression is IndexExpression) {
     var expressionTarget = expression.realTarget;
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 631249a..a4fbc57 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -36,7 +36,9 @@
 
   /// Initialize a newly created list of adjacent strings. To be syntactically
   /// valid, the list of [strings] must contain at least two elements.
-  AdjacentStringsImpl(List<StringLiteral> strings) {
+  AdjacentStringsImpl({
+    required List<StringLiteral> strings,
+  }) {
     _strings._initialize(this, strings);
   }
 
@@ -340,8 +342,11 @@
 
   /// Initialize a newly created list of arguments. The list of [arguments] can
   /// be `null` if there are no arguments.
-  ArgumentListImpl(
-      this.leftParenthesis, List<Expression> arguments, this.rightParenthesis) {
+  ArgumentListImpl({
+    required this.leftParenthesis,
+    required List<Expression> arguments,
+    required this.rightParenthesis,
+  }) {
     _arguments._initialize(this, arguments);
   }
 
@@ -422,7 +427,12 @@
   TypeAnnotationImpl _type;
 
   /// Initialize a newly created as expression.
-  AsExpressionImpl(this._expression, this.asOperator, this._type) {
+  AsExpressionImpl({
+    required ExpressionImpl expression,
+    required this.asOperator,
+    required TypeAnnotationImpl type,
+  })  : _expression = expression,
+        _type = type {
     _becomeParentOf(_expression);
     _becomeParentOf(_type);
   }
@@ -497,8 +507,15 @@
   Token rightParenthesis;
 
   /// Initialize a newly created assert initializer.
-  AssertInitializerImpl(this.assertKeyword, this.leftParenthesis,
-      this._condition, this.comma, this._message, this.rightParenthesis) {
+  AssertInitializerImpl({
+    required this.assertKeyword,
+    required this.leftParenthesis,
+    required ExpressionImpl condition,
+    required this.comma,
+    required ExpressionImpl? message,
+    required this.rightParenthesis,
+  })  : _condition = condition,
+        _message = message {
     _becomeParentOf(_condition);
     _becomeParentOf(_message);
   }
@@ -570,8 +587,16 @@
   Token semicolon;
 
   /// Initialize a newly created assert statement.
-  AssertStatementImpl(this.assertKeyword, this.leftParenthesis, this._condition,
-      this.comma, this._message, this.rightParenthesis, this.semicolon) {
+  AssertStatementImpl({
+    required this.assertKeyword,
+    required this.leftParenthesis,
+    required ExpressionImpl condition,
+    required this.comma,
+    required ExpressionImpl? message,
+    required this.rightParenthesis,
+    required this.semicolon,
+  })  : _condition = condition,
+        _message = message {
     _becomeParentOf(_condition);
     _becomeParentOf(_message);
   }
@@ -641,8 +666,12 @@
   MethodElement? staticElement;
 
   /// Initialize a newly created assignment expression.
-  AssignmentExpressionImpl(
-      this._leftHandSide, this.operator, this._rightHandSide) {
+  AssignmentExpressionImpl({
+    required ExpressionImpl leftHandSide,
+    required this.operator,
+    required ExpressionImpl rightHandSide,
+  })  : _leftHandSide = leftHandSide,
+        _rightHandSide = rightHandSide {
     _becomeParentOf(_leftHandSide);
     _becomeParentOf(_rightHandSide);
   }
diff --git a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
index c14099a..6bade88 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
@@ -15,9 +15,6 @@
 final AstFactoryImpl astFactory = AstFactoryImpl();
 
 class AstFactoryImpl {
-  AdjacentStringsImpl adjacentStrings(List<StringLiteral> strings) =>
-      AdjacentStringsImpl(strings);
-
   AnnotationImpl annotation(
           {required Token atSign,
           required Identifier name,
@@ -33,60 +30,6 @@
           constructorName as SimpleIdentifierImpl?,
           arguments as ArgumentListImpl?);
 
-  ArgumentListImpl argumentList(Token leftParenthesis,
-          List<Expression> arguments, Token rightParenthesis) =>
-      ArgumentListImpl(leftParenthesis, arguments, rightParenthesis);
-
-  AsExpressionImpl asExpression(
-          Expression expression, Token asOperator, TypeAnnotation type) =>
-      AsExpressionImpl(
-          expression as ExpressionImpl, asOperator, type as TypeAnnotationImpl);
-
-  AssertInitializerImpl assertInitializer(
-          Token assertKeyword,
-          Token leftParenthesis,
-          Expression condition,
-          Token? comma,
-          Expression? message,
-          Token rightParenthesis) =>
-      AssertInitializerImpl(
-          assertKeyword,
-          leftParenthesis,
-          condition as ExpressionImpl,
-          comma,
-          message as ExpressionImpl?,
-          rightParenthesis);
-
-  AssertStatementImpl assertStatement(
-          Token assertKeyword,
-          Token leftParenthesis,
-          Expression condition,
-          Token? comma,
-          Expression? message,
-          Token rightParenthesis,
-          Token semicolon) =>
-      AssertStatementImpl(
-          assertKeyword,
-          leftParenthesis,
-          condition as ExpressionImpl,
-          comma,
-          message as ExpressionImpl?,
-          rightParenthesis,
-          semicolon);
-
-  AssignmentExpressionImpl assignmentExpression(
-          Expression leftHandSide, Token operator, Expression rightHandSide) =>
-      AssignmentExpressionImpl(leftHandSide as ExpressionImpl, operator,
-          rightHandSide as ExpressionImpl);
-
-  BinaryExpressionImpl binaryExpression(
-          Expression leftOperand, Token operator, Expression rightOperand) =>
-      BinaryExpressionImpl(
-        leftOperand: leftOperand as ExpressionImpl,
-        operator: operator,
-        rightOperand: rightOperand as ExpressionImpl,
-      );
-
   BlockImpl block(
           Token leftBracket, List<Statement> statements, Token rightBracket) =>
       BlockImpl(leftBracket, statements, rightBracket);
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index cf1c0fb..4e67afa 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -17,6 +17,7 @@
 import 'package:analyzer/src/context/source.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/analysis/session.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/ast_factory.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/dart/constant/compute.dart';
@@ -969,10 +970,10 @@
                   StringToken(TokenType.STRING, superclassConstructor.name, -1),
                 )..staticElement = superclassConstructor)
               : null,
-          astFactory.argumentList(
-            Tokens.openParenthesis(),
-            argumentsForSuperInvocation,
-            Tokens.closeParenthesis(),
+          ArgumentListImpl(
+            leftParenthesis: Tokens.openParenthesis(),
+            arguments: argumentsForSuperInvocation,
+            rightParenthesis: Tokens.closeParenthesis(),
           ),
         )..staticElement = superclassConstructor,
       ];
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index dd1ae59..8182731 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -636,8 +636,11 @@
     debugEvent("Arguments");
 
     var expressions = popTypedList2<Expression>(count);
-    ArgumentList arguments =
-        ast.argumentList(leftParenthesis, expressions, rightParenthesis);
+    ArgumentList arguments = ArgumentListImpl(
+      leftParenthesis: leftParenthesis,
+      arguments: expressions,
+      rightParenthesis: rightParenthesis,
+    );
 
     if (!enableNamedArgumentsAnywhere) {
       bool hasSeenNamedArgument = false;
@@ -670,8 +673,8 @@
     assert(kind != Assert.Statement || optionalOrNull(';', semicolon));
     debugEvent("Assert");
 
-    var message = popIfNotNull(comma) as Expression?;
-    var condition = pop() as Expression;
+    var message = popIfNotNull(comma) as ExpressionImpl?;
+    var condition = pop() as ExpressionImpl;
     switch (kind) {
       case Assert.Expression:
         // The parser has already reported an error indicating that assert
@@ -680,19 +683,42 @@
         if (message != null) {
           arguments.add(message);
         }
-        push(ast.functionExpressionInvocation(
+        push(
+          ast.functionExpressionInvocation(
             ast.simpleIdentifier(assertKeyword),
             null,
-            ast.argumentList(
-                leftParenthesis, arguments, leftParenthesis.endGroup!)));
+            ArgumentListImpl(
+              leftParenthesis: leftParenthesis,
+              arguments: arguments,
+              rightParenthesis: leftParenthesis.endGroup!,
+            ),
+          ),
+        );
         break;
       case Assert.Initializer:
-        push(ast.assertInitializer(assertKeyword, leftParenthesis, condition,
-            comma, message, leftParenthesis.endGroup!));
+        push(
+          AssertInitializerImpl(
+            assertKeyword: assertKeyword,
+            leftParenthesis: leftParenthesis,
+            condition: condition,
+            comma: comma,
+            message: message,
+            rightParenthesis: leftParenthesis.endGroup!,
+          ),
+        );
         break;
       case Assert.Statement:
-        push(ast.assertStatement(assertKeyword, leftParenthesis, condition,
-            comma, message, leftParenthesis.endGroup!, semicolon));
+        push(
+          AssertStatementImpl(
+            assertKeyword: assertKeyword,
+            leftParenthesis: leftParenthesis,
+            condition: condition,
+            comma: comma,
+            message: message,
+            rightParenthesis: leftParenthesis.endGroup!,
+            semicolon: semicolon,
+          ),
+        );
         break;
     }
   }
@@ -2613,9 +2639,15 @@
     assert(optional('as', asOperator));
     debugEvent("AsOperator");
 
-    var type = pop() as TypeAnnotation;
-    var expression = pop() as Expression;
-    push(ast.asExpression(expression, asOperator, type));
+    var type = pop() as TypeAnnotationImpl;
+    var expression = pop() as ExpressionImpl;
+    push(
+      AsExpressionImpl(
+        expression: expression,
+        asOperator: asOperator,
+        type: type,
+      ),
+    );
   }
 
   @override
@@ -2623,14 +2655,20 @@
     assert(token.type.isAssignmentOperator);
     debugEvent("AssignmentExpression");
 
-    var rhs = pop() as Expression;
-    var lhs = pop() as Expression;
+    var rhs = pop() as ExpressionImpl;
+    var lhs = pop() as ExpressionImpl;
     if (!lhs.isAssignable) {
       // TODO(danrubel): Update the BodyBuilder to report this error.
       handleRecoverableError(
           messageMissingAssignableSelector, lhs.beginToken, lhs.endToken);
     }
-    push(ast.assignmentExpression(lhs, token, rhs));
+    push(
+      AssignmentExpressionImpl(
+        leftHandSide: lhs,
+        operator: token,
+        rightHandSide: rhs,
+      ),
+    );
     if (!enableTripleShift && token.type == TokenType.GT_GT_GT_EQ) {
       var feature = ExperimentalFeatures.triple_shift;
       handleRecoverableError(
@@ -3925,7 +3963,7 @@
     debugEvent("StringJuxtaposition");
 
     var strings = popTypedList2<StringLiteral>(literalCount);
-    push(ast.adjacentStrings(strings));
+    push(AdjacentStringsImpl(strings: strings));
   }
 
   @override
@@ -4331,7 +4369,11 @@
       ..previous = precedingToken;
     var right = SyntheticToken(TokenType.CLOSE_PAREN, syntheticOffset)
       ..previous = left;
-    return ast.argumentList(left, [], right);
+    return ArgumentListImpl(
+      leftParenthesis: left,
+      arguments: [],
+      rightParenthesis: right,
+    );
   }
 
   SimpleIdentifier _tmpSimpleIdentifier() {
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
index 79a78d7..e8b0fa6 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
@@ -30,9 +30,6 @@
 /// rather than 'integerLiteral'.
 @internal
 class AstTestFactory {
-  static AdjacentStringsImpl adjacentStrings(List<StringLiteral> strings) =>
-      astFactory.adjacentStrings(strings);
-
   static AnnotationImpl annotation(Identifier name) => astFactory.annotation(
       atSign: TokenFactory.tokenFromType(TokenType.AT), name: name);
 
@@ -51,39 +48,19 @@
 
   static ArgumentListImpl argumentList(
           [List<Expression> arguments = const []]) =>
-      astFactory.argumentList(TokenFactory.tokenFromType(TokenType.OPEN_PAREN),
-          arguments, TokenFactory.tokenFromType(TokenType.CLOSE_PAREN));
-
-  static AsExpressionImpl asExpression(
-          Expression expression, TypeAnnotation type) =>
-      astFactory.asExpression(
-          expression, TokenFactory.tokenFromKeyword(Keyword.AS), type);
-
-  static AssertInitializerImpl assertInitializer(
-          Expression condition, Expression message) =>
-      astFactory.assertInitializer(
-          TokenFactory.tokenFromKeyword(Keyword.ASSERT),
-          TokenFactory.tokenFromType(TokenType.OPEN_PAREN),
-          condition,
-          TokenFactory.tokenFromType(TokenType.COMMA),
-          message,
-          TokenFactory.tokenFromType(TokenType.CLOSE_PAREN));
-
-  static AssertStatementImpl assertStatement(Expression condition,
-          [Expression? message]) =>
-      astFactory.assertStatement(
-          TokenFactory.tokenFromKeyword(Keyword.ASSERT),
-          TokenFactory.tokenFromType(TokenType.OPEN_PAREN),
-          condition,
-          message == null ? null : TokenFactory.tokenFromType(TokenType.COMMA),
-          message,
-          TokenFactory.tokenFromType(TokenType.CLOSE_PAREN),
-          TokenFactory.tokenFromType(TokenType.SEMICOLON));
+      ArgumentListImpl(
+        leftParenthesis: TokenFactory.tokenFromType(TokenType.OPEN_PAREN),
+        arguments: arguments,
+        rightParenthesis: TokenFactory.tokenFromType(TokenType.CLOSE_PAREN),
+      );
 
   static AssignmentExpressionImpl assignmentExpression(Expression leftHandSide,
           TokenType operator, Expression rightHandSide) =>
-      astFactory.assignmentExpression(
-          leftHandSide, TokenFactory.tokenFromType(operator), rightHandSide);
+      AssignmentExpressionImpl(
+        leftHandSide: leftHandSide as ExpressionImpl,
+        operator: TokenFactory.tokenFromType(operator),
+        rightHandSide: rightHandSide as ExpressionImpl,
+      );
 
   static BlockFunctionBodyImpl asyncBlockFunctionBody(
           [List<Statement> statements = const []]) =>
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index b1f8333..91ada35 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -193,7 +193,7 @@
 
   AdjacentStrings _readAdjacentStrings() {
     var components = _readNodeList<StringLiteral>();
-    var node = astFactory.adjacentStrings(components);
+    var node = AdjacentStringsImpl(strings: components);
     _readExpressionResolution(node);
     return node;
   }
@@ -218,42 +218,46 @@
   ArgumentList _readArgumentList() {
     var arguments = _readNodeList<Expression>();
 
-    return astFactory.argumentList(
-      Tokens.openParenthesis(),
-      arguments,
-      Tokens.closeParenthesis(),
+    return ArgumentListImpl(
+      leftParenthesis: Tokens.openParenthesis(),
+      arguments: arguments,
+      rightParenthesis: Tokens.closeParenthesis(),
     );
   }
 
   AsExpression _readAsExpression() {
-    var expression = readNode() as Expression;
-    var type = readNode() as TypeAnnotation;
-    var node = astFactory.asExpression(expression, Tokens.as_(), type);
+    var expression = readNode() as ExpressionImpl;
+    var type = readNode() as TypeAnnotationImpl;
+    var node = AsExpressionImpl(
+      expression: expression,
+      asOperator: Tokens.as_(),
+      type: type,
+    );
     _readExpressionResolution(node);
     return node;
   }
 
   AssertInitializer _readAssertInitializer() {
-    var condition = readNode() as Expression;
-    var message = _readOptionalNode() as Expression?;
-    return astFactory.assertInitializer(
-      Tokens.assert_(),
-      Tokens.openParenthesis(),
-      condition,
-      message != null ? Tokens.comma() : null,
-      message,
-      Tokens.closeParenthesis(),
+    var condition = readNode() as ExpressionImpl;
+    var message = _readOptionalNode() as ExpressionImpl?;
+    return AssertInitializerImpl(
+      assertKeyword: Tokens.assert_(),
+      leftParenthesis: Tokens.openParenthesis(),
+      condition: condition,
+      comma: message != null ? Tokens.comma() : null,
+      message: message,
+      rightParenthesis: Tokens.closeParenthesis(),
     );
   }
 
   AssignmentExpression _readAssignmentExpression() {
-    var leftHandSide = readNode() as Expression;
-    var rightHandSide = readNode() as Expression;
+    var leftHandSide = readNode() as ExpressionImpl;
+    var rightHandSide = readNode() as ExpressionImpl;
     var operatorType = UnlinkedTokenType.values[_readByte()];
-    var node = astFactory.assignmentExpression(
-      leftHandSide,
-      Tokens.fromType(operatorType),
-      rightHandSide,
+    var node = AssignmentExpressionImpl(
+      leftHandSide: leftHandSide,
+      operator: Tokens.fromType(operatorType),
+      rightHandSide: rightHandSide,
     );
     node.staticElement = _reader.readElement() as MethodElement?;
     node.readElement = _reader.readElement();
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index 7b8fc96..00bb912 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -262,12 +262,12 @@
                 )
               : null,
         ),
-        astFactory.argumentList(
-          Tokens.openParenthesis(),
-          [
+        ArgumentListImpl(
+          leftParenthesis: Tokens.openParenthesis(),
+          arguments: [
             ...?constant.arguments?.argumentList.arguments,
           ],
-          Tokens.closeParenthesis(),
+          rightParenthesis: Tokens.closeParenthesis(),
         ),
       );
 
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index cfbc48c..004ee23 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -4087,15 +4087,23 @@
   v = 3;
   v; // marker
 }''');
-    assertAssignment(
-      findNode.assignment('= 3'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.localVar('v'),
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
+    assertResolvedNodeText(findNode.assignment('= 3'), r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: v
+    staticElement: v@15
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: v@15
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
     assertTypeDynamic(findNode.simple('v; // marker'));
   }
 
diff --git a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
index 6f7b7b7..7a1569f 100644
--- a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
@@ -25,10 +25,13 @@
 @reflectiveTest
 class ToSourceVisitorTest {
   void test_visitAdjacentStrings() {
+    var findNode = _parseStringToFindNode(r'''
+var v = 'a' 'b';
+''');
     _assertSource(
-        "'a' 'b'",
-        AstTestFactory.adjacentStrings(
-            [AstTestFactory.string2("a"), AstTestFactory.string2("b")]));
+      "'a' 'b'",
+      findNode.adjacentStrings("'a'"),
+    );
   }
 
   void test_visitAnnotation_constant() {
@@ -62,22 +65,37 @@
   }
 
   void test_visitAsExpression() {
+    var findNode = _parseStringToFindNode(r'''
+var v = a as T;
+''');
     _assertSource(
-        "e as T",
-        AstTestFactory.asExpression(
-            AstTestFactory.identifier3("e"), AstTestFactory.namedType4("T")));
+      'a as T',
+      findNode.as_('as T'),
+    );
   }
 
   void test_visitAssertStatement() {
-    _assertSource("assert (a);",
-        AstTestFactory.assertStatement(AstTestFactory.identifier3("a")));
+    var findNode = _parseStringToFindNode(r'''
+void f() {
+  assert(a);
+}
+''');
+    _assertSource(
+      'assert (a);',
+      findNode.assertStatement('assert'),
+    );
   }
 
   void test_visitAssertStatement_withMessage() {
+    var findNode = _parseStringToFindNode(r'''
+void f() {
+  assert(a, b);
+}
+''');
     _assertSource(
-        "assert (a, b);",
-        AstTestFactory.assertStatement(
-            AstTestFactory.identifier3("a"), AstTestFactory.identifier3('b')));
+      'assert (a, b);',
+      findNode.assertStatement('assert'),
+    );
   }
 
   void test_visitAssignmentExpression() {
diff --git a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
index a5588e8..ac8c980 100644
--- a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
@@ -2,7 +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.
 
-import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -16,10 +15,7 @@
 }
 
 @reflectiveTest
-class AssignmentDriverResolutionTest extends PubPackageResolutionTest
-    with AssignmentDriverResolutionTestCases {}
-
-mixin AssignmentDriverResolutionTestCases on PubPackageResolutionTest {
+class AssignmentDriverResolutionTest extends PubPackageResolutionTest {
   test_compound_plus_int_context_int() async {
     await assertNoErrorsInCode('''
 T f<T>() => throw Error();
@@ -30,7 +26,7 @@
 
     assertTypeArgumentTypes(
       findNode.methodInvocation('f()'),
-      [typeStringByNullability(nullable: 'int', legacy: 'num')],
+      ['int'],
     );
   }
 
@@ -44,7 +40,7 @@
 
     assertTypeArgumentTypes(
       findNode.methodInvocation('f()'),
-      [typeStringByNullability(nullable: 'int', legacy: 'num')],
+      ['int'],
     );
   }
 
@@ -60,7 +56,7 @@
 
     assertTypeArgumentTypes(
       findNode.methodInvocation('f()'),
-      [typeStringByNullability(nullable: 'int', legacy: 'num')],
+      ['int'],
     );
   }
 
@@ -77,7 +73,7 @@
 
     assertTypeArgumentTypes(
       findNode.methodInvocation('f()'),
-      [typeStringByNullability(nullable: 'int', legacy: 'num')],
+      ['int'],
     );
 
     assertType(findNode.simple('a);').staticType, 'num');
@@ -95,18 +91,30 @@
 }
 ''');
 
-    assertAssignment(
-      findNode.assignment('[0] += 2'),
-      readElement: findElement.method('[]'),
-      readType: 'int',
-      writeElement: findElement.method('[]='),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
+    var assignment = findNode.assignment('[0] += 2');
+
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    period: ..
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::A::@method::[]
+  readType: int
+  writeElement: self::@class::A::@method::[]=
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_indexExpression_instance_compound() async {
@@ -121,18 +129,33 @@
 }
 ''');
 
-    assertAssignment(
-      findNode.assignment('[0] += 2'),
-      readElement: findElement.method('[]'),
-      readType: 'int',
-      writeElement: findElement.method('[]='),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
+    var assignment = findNode.assignment('[0] += 2');
+
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: a
+      staticElement: a@91
+      staticType: A
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::A::@method::[]
+  readType: int
+  writeElement: self::@class::A::@method::[]=
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_indexExpression_instance_compound_double_num() async {
@@ -147,18 +170,33 @@
 }
 ''');
 
-    assertAssignment(
-      findNode.assignment('[0] += 2.0'),
-      readElement: findElement.method('[]'),
-      readType: 'num',
-      writeElement: findElement.method('[]='),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'double',
-    );
+    var assignment = findNode.assignment('[0] += 2.0');
+
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: a
+      staticElement: a@91
+      staticType: A
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: DoubleLiteral
+    literal: 2.0
+    staticType: double
+  readElement: self::@class::A::@method::[]
+  readType: num
+  writeElement: self::@class::A::@method::[]=
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: double
+''');
   }
 
   test_indexExpression_instance_ifNull() async {
@@ -173,15 +211,33 @@
 }
 ''');
 
-    assertAssignment(
-      findNode.assignment('[0] ??= 2'),
-      readElement: findElement.method('[]'),
-      readType: 'int?',
-      writeElement: findElement.method('[]='),
-      writeType: 'num?',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('[0] ??= 2');
+
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: a
+      staticElement: a@95
+      staticType: A
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: ??=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::A::@method::[]
+  readType: int?
+  writeElement: self::@class::A::@method::[]=
+  writeType: num?
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_indexExpression_instance_simple() async {
@@ -195,15 +251,33 @@
 }
 ''');
 
-    assertAssignment(
-      findNode.assignment('[0] = 2'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.method('[]='),
-      writeType: 'num',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('[0] = 2');
+
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: a
+      staticElement: a@57
+      staticType: A
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@method::[]=
+  writeType: num
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_indexExpression_super_compound() async {
@@ -220,18 +294,32 @@
 }
 ''');
 
-    assertAssignment(
-      findNode.assignment('[0] += 2'),
-      readElement: findElement.method('[]'),
-      readType: 'int',
-      writeElement: findElement.method('[]='),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
+    var assignment = findNode.assignment('[0] += 2');
+
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SuperExpression
+      superKeyword: super
+      staticType: B
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::A::@method::[]
+  readType: int
+  writeElement: self::@class::A::@method::[]=
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_indexExpression_this_compound() async {
@@ -246,18 +334,32 @@
 }
 ''');
 
-    assertAssignment(
-      findNode.assignment('[0] += 2'),
-      readElement: findElement.method('[]'),
-      readType: 'int',
-      writeElement: findElement.method('[]='),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
+    var assignment = findNode.assignment('[0] += 2');
+
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: ThisExpression
+      thisKeyword: this
+      staticType: A
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::A::@method::[]
+  readType: int
+  writeElement: self::@class::A::@method::[]=
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_indexExpression_unresolved1_simple() async {
@@ -271,33 +373,34 @@
     ]);
 
     var assignment = findNode.assignment('a[b] = c');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifier(
-      findNode.simple('a['),
-      element: null,
-      type: 'dynamic',
-    );
-
-    assertSimpleIdentifier(
-      findNode.simple('b]'),
-      element: null,
-      type: 'dynamic',
-    );
-
-    assertSimpleIdentifier(
-      assignment.rightHandSide,
-      element: findElement.parameter('c'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: dynamic
+    leftBracket: [
+    index: SimpleIdentifier
+      token: b
+      staticElement: <null>
+      staticType: dynamic
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: SimpleIdentifier
+    token: c
+    staticElement: c@11
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_indexExpression_unresolved2_simple() async {
@@ -311,33 +414,34 @@
     ]);
 
     var assignment = findNode.assignment('a[b] = c');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifier(
-      findNode.simple('a['),
-      element: findElement.parameter('a'),
-      type: 'int',
-    );
-
-    assertSimpleIdentifier(
-      findNode.simple('b]'),
-      element: null,
-      type: 'dynamic',
-    );
-
-    assertSimpleIdentifier(
-      assignment.rightHandSide,
-      element: findElement.parameter('c'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: a
+      staticElement: a@11
+      staticType: int
+    leftBracket: [
+    index: SimpleIdentifier
+      token: b
+      staticElement: <null>
+      staticType: dynamic
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: SimpleIdentifier
+    token: c
+    staticElement: c@18
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_indexExpression_unresolved3_simple() async {
@@ -354,33 +458,34 @@
     ]);
 
     var assignment = findNode.assignment('a[b] = c');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.method('[]='),
-      writeType: 'num',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifier(
-      findNode.simple('a['),
-      element: findElement.parameter('a'),
-      type: 'A',
-    );
-
-    assertSimpleIdentifier(
-      findNode.simple('b]'),
-      element: null,
-      type: 'dynamic',
-    );
-
-    assertSimpleIdentifier(
-      assignment.rightHandSide,
-      element: findElement.parameter('c'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: a
+      staticElement: a@57
+      staticType: A
+    leftBracket: [
+    index: SimpleIdentifier
+      token: b
+      staticElement: <null>
+      staticType: dynamic
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: SimpleIdentifier
+    token: c
+    staticElement: c@64
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@method::[]=
+  writeType: num
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_notLValue_binaryExpression_compound() async {
@@ -394,19 +499,34 @@
     ]);
 
     var assignment = findNode.assignment('= c');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: 'dynamic',
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'dynamic',
-    );
 
-    assertElement(findNode.simple('a +'), findElement.parameter('a'));
-    assertElement(findNode.simple('b +'), findElement.parameter('b'));
-    assertElement(findNode.simple('c;'), findElement.parameter('c'));
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: BinaryExpression
+    leftOperand: SimpleIdentifier
+      token: a
+      staticElement: a@11
+      staticType: int
+    operator: +
+    rightOperand: SimpleIdentifier
+      token: b
+      staticElement: b@18
+      staticType: int
+    staticElement: dart:core::@class::num::@method::+
+    staticInvokeType: num Function(num)
+    staticType: int
+  operator: +=
+  rightHandSide: SimpleIdentifier
+    token: c
+    staticElement: c@28
+    staticType: double
+  readElement: <null>
+  readType: dynamic
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: dynamic
+''');
   }
 
   test_notLValue_parenthesized_compound() async {
@@ -420,15 +540,38 @@
     ]);
 
     var assignment = findNode.assignment('= c');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: 'dynamic',
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'dynamic',
-    );
+
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: ParenthesizedExpression
+    leftParenthesis: (
+    expression: BinaryExpression
+      leftOperand: SimpleIdentifier
+        token: a
+        staticElement: a@11
+        staticType: int
+      operator: +
+      rightOperand: SimpleIdentifier
+        token: b
+        staticElement: b@18
+        staticType: int
+      staticElement: dart:core::@class::num::@method::+
+      staticInvokeType: num Function(num)
+      staticType: int
+    rightParenthesis: )
+    staticType: int
+  operator: +=
+  rightHandSide: SimpleIdentifier
+    token: c
+    staticElement: c@28
+    staticType: double
+  readElement: <null>
+  readType: dynamic
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: dynamic
+''');
   }
 
   test_notLValue_parenthesized_simple() async {
@@ -442,35 +585,38 @@
     ]);
 
     var assignment = findNode.assignment('= c');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'double',
-    );
 
-    assertType(assignment.leftHandSide, 'int');
-
-    assertSimpleIdentifier(
-      findNode.simple('a + b'),
-      element: findElement.parameter('a'),
-      type: 'int',
-    );
-
-    assertSimpleIdentifier(
-      findNode.simple('b)'),
-      element: findElement.parameter('b'),
-      type: 'int',
-    );
-
-    assertSimpleIdentifier(
-      findNode.simple('c;'),
-      element: findElement.parameter('c'),
-      type: 'double',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: ParenthesizedExpression
+    leftParenthesis: (
+    expression: BinaryExpression
+      leftOperand: SimpleIdentifier
+        token: a
+        staticElement: a@11
+        staticType: int
+      operator: +
+      rightOperand: SimpleIdentifier
+        token: b
+        staticElement: b@18
+        staticType: int
+      staticElement: dart:core::@class::num::@method::+
+      staticInvokeType: num Function(num)
+      staticType: int
+    rightParenthesis: )
+    staticType: int
+  operator: =
+  rightHandSide: SimpleIdentifier
+    token: c
+    staticElement: c@28
+    staticType: double
+  readElement: <null>
+  readType: null
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: double
+''');
   }
 
   test_notLValue_postfixIncrement_compound() async {
@@ -483,21 +629,34 @@
       error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 25, 3),
     ]);
 
-    assertAssignment(
-      findNode.assignment('= y'),
-      readElement: null,
-      readType: 'dynamic',
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'dynamic',
-    );
+    var assignment = findNode.assignment('= y');
 
-    assertSimpleIdentifier(
-      findNode.simple('y;'),
-      element: findElement.parameter('y'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PostfixExpression
+    operand: SimpleIdentifier
+      token: x
+      staticElement: x@11
+      staticType: null
+    operator: ++
+    readElement: x@11
+    readType: num
+    writeElement: x@11
+    writeType: num
+    staticElement: dart:core::@class::num::@method::+
+    staticType: num
+  operator: +=
+  rightHandSide: SimpleIdentifier
+    token: y
+    staticElement: y@18
+    staticType: int
+  readElement: <null>
+  readType: dynamic
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: dynamic
+''');
   }
 
   test_notLValue_postfixIncrement_compound_ifNull() async {
@@ -510,21 +669,34 @@
       error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 25, 3),
     ]);
 
-    assertAssignment(
-      findNode.assignment('= y'),
-      readElement: null,
-      readType: 'dynamic',
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'dynamic',
-    );
+    var assignment = findNode.assignment('= y');
 
-    assertSimpleIdentifier(
-      findNode.simple('y;'),
-      element: findElement.parameter('y'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PostfixExpression
+    operand: SimpleIdentifier
+      token: x
+      staticElement: x@11
+      staticType: null
+    operator: ++
+    readElement: x@11
+    readType: num
+    writeElement: x@11
+    writeType: num
+    staticElement: dart:core::@class::num::@method::+
+    staticType: num
+  operator: ??=
+  rightHandSide: SimpleIdentifier
+    token: y
+    staticElement: y@18
+    staticType: int
+  readElement: <null>
+  readType: dynamic
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: dynamic
+''');
   }
 
   test_notLValue_postfixIncrement_simple() async {
@@ -537,21 +709,34 @@
       error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 25, 3),
     ]);
 
-    assertAssignment(
-      findNode.assignment('= y'),
-      readElement: null,
-      readType: null,
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('= y');
 
-    assertSimpleIdentifier(
-      findNode.simple('y;'),
-      element: findElement.parameter('y'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PostfixExpression
+    operand: SimpleIdentifier
+      token: x
+      staticElement: x@11
+      staticType: null
+    operator: ++
+    readElement: x@11
+    readType: num
+    writeElement: x@11
+    writeType: num
+    staticElement: dart:core::@class::num::@method::+
+    staticType: num
+  operator: =
+  rightHandSide: SimpleIdentifier
+    token: y
+    staticElement: y@18
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_notLValue_prefixIncrement_compound() async {
@@ -564,21 +749,34 @@
       error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 25, 3),
     ]);
 
-    assertAssignment(
-      findNode.assignment('= y'),
-      readElement: null,
-      readType: 'dynamic',
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'dynamic',
-    );
+    var assignment = findNode.assignment('= y');
 
-    assertSimpleIdentifier(
-      findNode.simple('y;'),
-      element: findElement.parameter('y'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixExpression
+    operator: ++
+    operand: SimpleIdentifier
+      token: x
+      staticElement: x@11
+      staticType: null
+    readElement: x@11
+    readType: num
+    writeElement: x@11
+    writeType: num
+    staticElement: dart:core::@class::num::@method::+
+    staticType: num
+  operator: +=
+  rightHandSide: SimpleIdentifier
+    token: y
+    staticElement: y@18
+    staticType: int
+  readElement: <null>
+  readType: dynamic
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: dynamic
+''');
   }
 
   test_notLValue_prefixIncrement_compound_ifNull() async {
@@ -591,21 +789,34 @@
       error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 25, 3),
     ]);
 
-    assertAssignment(
-      findNode.assignment('= y'),
-      readElement: null,
-      readType: 'dynamic',
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'dynamic',
-    );
+    var assignment = findNode.assignment('= y');
 
-    assertSimpleIdentifier(
-      findNode.simple('y;'),
-      element: findElement.parameter('y'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixExpression
+    operator: ++
+    operand: SimpleIdentifier
+      token: x
+      staticElement: x@11
+      staticType: null
+    readElement: x@11
+    readType: num
+    writeElement: x@11
+    writeType: num
+    staticElement: dart:core::@class::num::@method::+
+    staticType: num
+  operator: ??=
+  rightHandSide: SimpleIdentifier
+    token: y
+    staticElement: y@18
+    staticType: int
+  readElement: <null>
+  readType: dynamic
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: dynamic
+''');
   }
 
   test_notLValue_prefixIncrement_simple() async {
@@ -618,21 +829,34 @@
       error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 25, 3),
     ]);
 
-    assertAssignment(
-      findNode.assignment('= y'),
-      readElement: null,
-      readType: null,
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('= y');
 
-    assertSimpleIdentifier(
-      findNode.simple('y;'),
-      element: findElement.parameter('y'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixExpression
+    operator: ++
+    operand: SimpleIdentifier
+      token: x
+      staticElement: x@11
+      staticType: null
+    readElement: x@11
+    readType: num
+    writeElement: x@11
+    writeType: num
+    staticElement: dart:core::@class::num::@method::+
+    staticType: num
+  operator: =
+  rightHandSide: SimpleIdentifier
+    token: y
+    staticElement: y@18
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_notLValue_typeLiteral_class_ambiguous_simple() async {
@@ -648,27 +872,25 @@
       error(CompileTimeErrorCode.AMBIGUOUS_IMPORT, 47, 1),
     ]);
 
-    var matcherC = multiplyDefinedElementMatcher([
-      findElement.importFind('package:test/a.dart').class_('C'),
-      findElement.importFind('package:test/b.dart').class_('C'),
-    ]);
-
     var assignment = findNode.assignment('C = 0');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: matcherC,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: C
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_notLValue_typeLiteral_class_simple() async {
@@ -683,33 +905,35 @@
     ]);
 
     var assignment = findNode.assignment('C = 0');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.class_('C'),
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: C
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::C
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_nullAware_context() async {
-    var question = isNullSafetyEnabled ? '?' : '';
     await assertNoErrorsInCode('''
 T f<T>() => throw Error();
-g(int$question a) {
+g(int? a) {
   a ??= f();
 }
 ''');
 
-    assertTypeArgumentTypes(findNode.methodInvocation('f()'), ['int$question']);
+    assertTypeArgumentTypes(findNode.methodInvocation('f()'), ['int?']);
   }
 
   test_prefixedIdentifier_instance_compound() async {
@@ -725,25 +949,32 @@
 ''');
 
     var assignment = findNode.assignment('x += 2');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('x'),
-      readType: 'int',
-      writeElement: findElement.setter('x'),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
 
-    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
-    assertSimpleIdentifierAssignmentTarget(
-      prefixed.identifier,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: a@58
+      staticType: A
+    period: .
+    identifier: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::A::@getter::x
+  readType: int
+  writeElement: self::@class::A::@setter::x
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_prefixedIdentifier_instance_ifNull() async {
@@ -759,22 +990,32 @@
 ''');
 
     var assignment = findNode.assignment('x ??= 2');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('x'),
-      readType: 'int?',
-      writeElement: findElement.setter('x'),
-      writeType: 'num?',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
-    assertSimpleIdentifierAssignmentTarget(
-      prefixed.identifier,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: a@60
+      staticType: A
+    period: .
+    identifier: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: ??=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::A::@getter::x
+  readType: int?
+  writeElement: self::@class::A::@setter::x
+  writeType: num?
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_prefixedIdentifier_instance_simple() async {
@@ -789,22 +1030,32 @@
 ''');
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('x'),
-      writeType: 'num',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
-    assertSimpleIdentifierAssignmentTarget(
-      prefixed.identifier,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: a@40
+      staticType: A
+    period: .
+    identifier: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::x
+  writeType: num
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_prefixedIdentifier_instanceGetter_simple() async {
@@ -821,22 +1072,32 @@
     ]);
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.getter('x'),
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
-    assertSimpleIdentifierAssignmentTarget(
-      prefixed.identifier,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: a@40
+      staticType: A
+    period: .
+    identifier: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@getter::x
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_prefixedIdentifier_static_simple() async {
@@ -851,22 +1112,32 @@
 ''');
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('x'),
-      writeType: 'num',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
-    assertSimpleIdentifierAssignmentTarget(
-      prefixed.identifier,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: A
+      staticElement: self::@class::A
+      staticType: null
+    period: .
+    identifier: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::x
+  writeType: num
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_prefixedIdentifier_staticGetter_simple() async {
@@ -883,22 +1154,32 @@
     ]);
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.getter('x'),
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
-    assertSimpleIdentifierAssignmentTarget(
-      prefixed.identifier,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: A
+      staticElement: self::@class::A
+      staticType: null
+    period: .
+    identifier: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@getter::x
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_prefixedIdentifier_topLevel_compound() async {
@@ -914,30 +1195,33 @@
 }
 ''');
 
-    var importFind = findElement.importFind('package:test/a.dart');
-
     var assignment = findNode.assignment('x += 2');
-    assertAssignment(
-      assignment,
-      readElement: importFind.topGet('x'),
-      readType: 'int',
-      writeElement: importFind.topSet('x'),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
 
-    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
-    assertImportPrefix(prefixed.prefix, importFind.prefix);
-
-    assertSimpleIdentifierAssignmentTarget(
-      prefixed.identifier,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: p
+      staticElement: self::@prefix::p
+      staticType: null
+    period: .
+    identifier: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: package:test/a.dart::@getter::x
+  readType: int
+  writeElement: package:test/a.dart::@setter::x
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_prefixedIdentifier_typeAlias_static_compound() async {
@@ -955,25 +1239,32 @@
 ''');
 
     var assignment = findNode.assignment('x += 2');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('x'),
-      readType: 'int',
-      writeElement: findElement.setter('x'),
-      writeType: 'int',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
 
-    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
-    assertSimpleIdentifierAssignmentTarget(
-      prefixed.identifier,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: B
+      staticElement: self::@typeAlias::B
+      staticType: null
+    period: .
+    identifier: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::A::@getter::x
+  readType: int
+  writeElement: self::@class::A::@setter::x
+  writeType: int
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_prefixedIdentifier_unresolved1_simple() async {
@@ -986,31 +1277,33 @@
     ]);
 
     var assignment = findNode.assignment('a.b = c');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifier(
-      findNode.simple('a.'),
-      element: null,
-      type: 'dynamic',
-    );
-
-    assertSimpleIdentifierAssignmentTarget(
-      findNode.simple('b ='),
-    );
-
-    assertSimpleIdentifier(
-      assignment.rightHandSide,
-      element: findElement.parameter('c'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: dynamic
+    period: .
+    identifier: SimpleIdentifier
+      token: b
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: SimpleIdentifier
+    token: c
+    staticElement: c@11
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_prefixedIdentifier_unresolved2_compound() async {
@@ -1024,31 +1317,33 @@
     ]);
 
     var assignment = findNode.assignment('a.b += c');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: 'dynamic',
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'dynamic',
-    );
 
-    assertSimpleIdentifier(
-      findNode.simple('a.'),
-      element: findElement.parameter('a'),
-      type: 'int',
-    );
-
-    assertSimpleIdentifierAssignmentTarget(
-      findNode.simple('b +='),
-    );
-
-    assertSimpleIdentifier(
-      assignment.rightHandSide,
-      element: findElement.parameter('c'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: a@11
+      staticType: int
+    period: .
+    identifier: SimpleIdentifier
+      token: b
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: SimpleIdentifier
+    token: c
+    staticElement: c@18
+    staticType: int
+  readElement: <null>
+  readType: dynamic
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: dynamic
+''');
   }
 
   test_propertyAccess_cascade_compound() async {
@@ -1064,25 +1359,27 @@
 ''');
 
     var assignment = findNode.assignment('x += 2');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('x'),
-      readType: 'int',
-      writeElement: findElement.setter('x'),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
 
-    var propertyAccess = assignment.leftHandSide as PropertyAccess;
-    assertSimpleIdentifierAssignmentTarget(
-      propertyAccess.propertyName,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    operator: ..
+    propertyName: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::A::@getter::x
+  readType: int
+  writeElement: self::@class::A::@setter::x
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_propertyAccess_forwardingStub() async {
@@ -1100,17 +1397,41 @@
 ''');
 
     var assignment = findNode.assignment('x = 1');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('x', of: 'A'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: InstanceCreationExpression
+      keyword: new
+      constructorName: ConstructorName
+        type: NamedType
+          name: SimpleIdentifier
+            token: B
+            staticElement: self::@class::B
+            staticType: null
+          type: B
+        staticElement: self::@class::B::@constructor::•
+      argumentList: ArgumentList
+        leftParenthesis: (
+        rightParenthesis: )
+      staticType: B
+    operator: .
+    propertyName: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::x
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_propertyAccess_instance_compound() async {
@@ -1126,25 +1447,35 @@
 ''');
 
     var assignment = findNode.assignment('x += 2');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('x'),
-      readType: 'int',
-      writeElement: findElement.setter('x'),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
 
-    var propertyAccess = assignment.leftHandSide as PropertyAccess;
-    assertSimpleIdentifierAssignmentTarget(
-      propertyAccess.propertyName,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ParenthesizedExpression
+      leftParenthesis: (
+      expression: SimpleIdentifier
+        token: a
+        staticElement: a@58
+        staticType: A
+      rightParenthesis: )
+      staticType: A
+    operator: .
+    propertyName: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::A::@getter::x
+  readType: int
+  writeElement: self::@class::A::@setter::x
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_propertyAccess_instance_fromMixins_compound() async {
@@ -1168,20 +1499,35 @@
 ''');
 
     var assignment = findNode.assignment('x += 2');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('x', of: 'M2'),
-      readType: 'int',
-      writeElement: findElement.setter('x', of: 'M2'),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
 
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ParenthesizedExpression
+      leftParenthesis: (
+      expression: SimpleIdentifier
+        token: c
+        staticElement: c@134
+        staticType: C
+      rightParenthesis: )
+      staticType: C
+    operator: .
+    propertyName: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::M2::@getter::x
+  readType: int
+  writeElement: self::@class::M2::@setter::x
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_propertyAccess_instance_ifNull() async {
@@ -1197,22 +1543,35 @@
 ''');
 
     var assignment = findNode.assignment('x ??= 2');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('x'),
-      readType: 'int?',
-      writeElement: findElement.setter('x'),
-      writeType: 'num?',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    var propertyAccess = assignment.leftHandSide as PropertyAccess;
-    assertSimpleIdentifierAssignmentTarget(
-      propertyAccess.propertyName,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ParenthesizedExpression
+      leftParenthesis: (
+      expression: SimpleIdentifier
+        token: a
+        staticElement: a@60
+        staticType: A
+      rightParenthesis: )
+      staticType: A
+    operator: .
+    propertyName: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: ??=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::A::@getter::x
+  readType: int?
+  writeElement: self::@class::A::@setter::x
+  writeType: num?
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_propertyAccess_instance_simple() async {
@@ -1227,22 +1586,35 @@
 ''');
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('x'),
-      writeType: 'num',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    var propertyAccess = assignment.leftHandSide as PropertyAccess;
-    assertSimpleIdentifierAssignmentTarget(
-      propertyAccess.propertyName,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ParenthesizedExpression
+      leftParenthesis: (
+      expression: SimpleIdentifier
+        token: a
+        staticElement: a@40
+        staticType: A
+      rightParenthesis: )
+      staticType: A
+    operator: .
+    propertyName: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::x
+  writeType: num
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_propertyAccess_super_compound() async {
@@ -1263,26 +1635,30 @@
 ''');
 
     var assignment = findNode.assignment('x += 2');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('x', of: 'A'),
-      readType: 'int',
-      writeElement: findElement.setter('x', of: 'A'),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
 
-    var propertyAccess = assignment.leftHandSide as PropertyAccess;
-    assertSuperExpression(propertyAccess.target);
-    assertSimpleIdentifierAssignmentTarget(
-      propertyAccess.propertyName,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: SuperExpression
+      superKeyword: super
+      staticType: B
+    operator: .
+    propertyName: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::A::@getter::x
+  readType: int
+  writeElement: self::@class::A::@setter::x
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_propertyAccess_this_compound() async {
@@ -1298,25 +1674,30 @@
 ''');
 
     var assignment = findNode.assignment('x += 2');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('x'),
-      readType: 'int',
-      writeElement: findElement.setter('x'),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
 
-    var propertyAccess = assignment.leftHandSide as PropertyAccess;
-    assertSimpleIdentifierAssignmentTarget(
-      propertyAccess.propertyName,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ThisExpression
+      thisKeyword: this
+      staticType: A
+    operator: .
+    propertyName: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::A::@getter::x
+  readType: int
+  writeElement: self::@class::A::@setter::x
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_propertyAccess_unresolved1_simple() async {
@@ -1329,31 +1710,36 @@
     ]);
 
     var assignment = findNode.assignment('(a).b = c');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifier(
-      findNode.simple('a)'),
-      element: null,
-      type: 'dynamic',
-    );
-
-    assertSimpleIdentifierAssignmentTarget(
-      findNode.simple('b ='),
-    );
-
-    assertSimpleIdentifier(
-      findNode.simple('c;'),
-      element: findElement.parameter('c'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ParenthesizedExpression
+      leftParenthesis: (
+      expression: SimpleIdentifier
+        token: a
+        staticElement: <null>
+        staticType: dynamic
+      rightParenthesis: )
+      staticType: dynamic
+    operator: .
+    propertyName: SimpleIdentifier
+      token: b
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: SimpleIdentifier
+    token: c
+    staticElement: c@11
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_propertyAccess_unresolved2_simple() async {
@@ -1366,31 +1752,36 @@
     ]);
 
     var assignment = findNode.assignment('(a).b = c');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifier(
-      findNode.simple('a)'),
-      element: findElement.parameter('a'),
-      type: 'int',
-    );
-
-    assertSimpleIdentifierAssignmentTarget(
-      findNode.simple('b ='),
-    );
-
-    assertSimpleIdentifier(
-      findNode.simple('c;'),
-      element: findElement.parameter('c'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ParenthesizedExpression
+      leftParenthesis: (
+      expression: SimpleIdentifier
+        token: a
+        staticElement: a@11
+        staticType: int
+      rightParenthesis: )
+      staticType: int
+    operator: .
+    propertyName: SimpleIdentifier
+      token: b
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: SimpleIdentifier
+    token: c
+    staticElement: c@18
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_fieldInstance_simple() async {
@@ -1405,21 +1796,24 @@
 ''');
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('x'),
-      writeType: 'num',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::C::@setter::x
+  writeType: num
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_fieldStatic_simple() async {
@@ -1434,21 +1828,24 @@
 ''');
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('x'),
-      writeType: 'num',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::C::@setter::x
+  writeType: num
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_getterInstance_simple() async {
@@ -1465,21 +1862,24 @@
     ]);
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.getter('x'),
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::C::@getter::x
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_getterStatic_simple() async {
@@ -1496,21 +1896,24 @@
     ]);
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.getter('x'),
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::C::@getter::x
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_getterTopLevel_simple() async {
@@ -1525,21 +1928,24 @@
     ]);
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.topGet('x'),
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@getter::x
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_importPrefix_hasSuperSetter_simple() async {
@@ -1561,19 +1967,24 @@
     ]);
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.prefix('x'),
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@prefix::x
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_importPrefix_simple() async {
@@ -1588,21 +1999,24 @@
     ]);
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.prefix('x'),
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@prefix::x
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_localVariable_compound() async {
@@ -1615,24 +2029,24 @@
 ''');
 
     var assignment = findNode.assignment('x += 3');
-    assertAssignment(
-      assignment,
-      readElement: findElement.localVar('x'),
-      readType: 'num',
-      writeElement: findElement.localVar('x'),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'num', // num + int = num
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: x@51
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int
+  readElement: x@51
+  readType: num
+  writeElement: x@51
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: num
+''');
   }
 
   test_simpleIdentifier_localVariable_simple() async {
@@ -1645,21 +2059,24 @@
 ''');
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.localVar('x'),
-      writeType: 'num',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: x@51
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: x@51
+  writeType: num
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_localVariableConst_simple() async {
@@ -1674,21 +2091,24 @@
     ]);
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.localVar('x'),
-      writeType: 'num',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: x@57
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: x@57
+  writeType: num
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_localVariableFinal_simple() async {
@@ -1703,113 +2123,127 @@
     ]);
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.localVar('x'),
-      writeType: 'num',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: x@57
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: x@57
+  writeType: num
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_parameter_compound_ifNull() async {
-    var question = isNullSafetyEnabled ? '?' : '';
     await assertNoErrorsInCode('''
-void f(num$question x) {
+void f(num? x) {
   x ??= 0;
 }
 ''');
 
     var assignment = findNode.assignment('x ??=');
-    assertAssignment(
-      assignment,
-      readElement: findElement.parameter('x'),
-      readType: 'num$question',
-      writeElement: findElement.parameter('x'),
-      writeType: 'num$question',
-      operatorElement: null,
-      type: 'num',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: x@12
+    staticType: null
+  operator: ??=
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: x@12
+  readType: num?
+  writeElement: x@12
+  writeType: num?
+  staticElement: <null>
+  staticType: num
+''');
   }
 
   test_simpleIdentifier_parameter_compound_ifNull2() async {
-    var question = isNullSafetyEnabled ? '?' : '';
-    var errorOffset = isNullSafetyEnabled ? 77 : 76;
     await assertErrorsInCode('''
 class A {}
 class B extends A {}
 class C extends A {}
 
-void f(B$question x) {
+void f(B? x) {
   x ??= C();
 }
 ''', [
-      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, errorOffset, 3),
+      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 77, 3),
     ]);
 
     var assignment = findNode.assignment('x ??=');
-    assertAssignment(
-      assignment,
-      readElement: findElement.parameter('x'),
-      readType: 'B$question',
-      writeElement: findElement.parameter('x'),
-      writeType: 'B$question',
-      operatorElement: null,
-      type: 'A',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'C');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: x@64
+    staticType: null
+  operator: ??=
+  rightHandSide: InstanceCreationExpression
+    constructorName: ConstructorName
+      type: NamedType
+        name: SimpleIdentifier
+          token: C
+          staticElement: self::@class::C
+          staticType: null
+        type: C
+      staticElement: self::@class::C::@constructor::•
+    argumentList: ArgumentList
+      leftParenthesis: (
+      rightParenthesis: )
+    staticType: C
+  readElement: x@64
+  readType: B?
+  writeElement: x@64
+  writeType: B?
+  staticElement: <null>
+  staticType: A
+''');
   }
 
   test_simpleIdentifier_parameter_compound_ifNull_notAssignableType() async {
-    var question = isNullSafetyEnabled ? '?' : '';
-    var code = '''
-void f(double$question a, int b) {
+    await assertErrorsInCode('''
+void f(double? a, int b) {
   a ??= b;
 }
-''';
-    await assertErrorsInCode(code, [
-      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, code.indexOf('b;'), 1),
+''', [
+      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 35, 1),
     ]);
 
     var assignment = findNode.assignment('a ??=');
-    assertAssignment(
-      assignment,
-      readElement: findElement.parameter('a'),
-      readType: 'double$question',
-      writeElement: findElement.parameter('a'),
-      writeType: 'double$question',
-      operatorElement: null,
-      type: 'num',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertSimpleIdentifier(
-      assignment.rightHandSide,
-      element: findElement.parameter('b'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: a
+    staticElement: a@15
+    staticType: null
+  operator: ??=
+  rightHandSide: SimpleIdentifier
+    token: b
+    staticElement: b@22
+    staticType: int
+  readElement: a@15
+  readType: double?
+  writeElement: a@15
+  writeType: double?
+  staticElement: <null>
+  staticType: num
+''');
   }
 
   test_simpleIdentifier_parameter_compound_refineType_int_double() async {
@@ -1857,21 +2291,24 @@
 ''');
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.parameter('x'),
-      writeType: 'num',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: x@11
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: x@11
+  writeType: num
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_parameter_simple_context() async {
@@ -1883,27 +2320,25 @@
 }
 ''');
 
-    var expectedType = typeStringByNullability(
-      nullable: 'double',
-      legacy: 'int',
-    );
-
     var assignment = findNode.assignment('x = 1');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.parameter('x'),
-      writeType: 'Object',
-      operatorElement: null,
-      type: expectedType,
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, expectedType);
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: x@14
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: double
+  readElement: <null>
+  readType: null
+  writeElement: x@14
+  writeType: Object
+  staticElement: <null>
+  staticType: double
+''');
   }
 
   test_simpleIdentifier_parameter_simple_notAssignableType() async {
@@ -1916,21 +2351,24 @@
     ]);
 
     var assignment = findNode.assignment('x = true');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.parameter('x'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'bool',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'bool');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: x@11
+    staticType: null
+  operator: =
+  rightHandSide: BooleanLiteral
+    literal: true
+    staticType: bool
+  readElement: <null>
+  readType: null
+  writeElement: x@11
+  writeType: int
+  staticElement: <null>
+  staticType: bool
+''');
   }
 
   test_simpleIdentifier_parameterFinal_simple() async {
@@ -1943,21 +2381,24 @@
     ]);
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.parameter('x'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: x@17
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: x@17
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_staticGetter_superSetter_simple() async {
@@ -1979,19 +2420,24 @@
     ]);
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.getter('x', of: 'B'),
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::B::@getter::x
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_staticMethod_superSetter_simple() async {
@@ -2013,19 +2459,24 @@
     ]);
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.method('x', of: 'B'),
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::B::@method::x
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_superSetter_simple() async {
@@ -2042,21 +2493,24 @@
 ''');
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('x'),
-      writeType: 'num',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::x
+  writeType: num
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_synthetic_simple() async {
@@ -2069,25 +2523,25 @@
     ]);
 
     var assignment = findNode.assignment('= y');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertSimpleIdentifier(
-      assignment.rightHandSide,
-      element: findElement.parameter('y'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: <empty> <synthetic>
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: SimpleIdentifier
+    token: y
+    staticElement: y@11
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_thisGetter_superGetter_simple() async {
@@ -2106,21 +2560,24 @@
 ''');
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('x', of: 'A'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::x
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_thisGetter_thisSetter_compound() async {
@@ -2136,24 +2593,24 @@
 ''');
 
     var assignment = findNode.assignment('x += 2');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('x'),
-      readType: 'int',
-      writeElement: findElement.setter('x'),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::C::@getter::x
+  readType: int
+  writeElement: self::@class::C::@setter::x
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_thisGetter_thisSetter_fromMixins_compound() async {
@@ -2176,24 +2633,24 @@
 ''');
 
     var assignment = findNode.assignment('x += 2');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('x', of: 'M2'),
-      readType: 'int',
-      writeElement: findElement.setter('x', of: 'M2'),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::M2::@getter::x
+  readType: int
+  writeElement: self::@class::M2::@setter::x
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_thisGetter_thisSetter_ifNull() async {
@@ -2209,21 +2666,24 @@
 ''');
 
     var assignment = findNode.assignment('x ??= 2');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('x'),
-      readType: 'int?',
-      writeElement: findElement.setter('x'),
-      writeType: 'num?',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: ??=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::C::@getter::x
+  readType: int?
+  writeElement: self::@class::C::@setter::x
+  writeType: num?
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_topGetter_superSetter_simple() async {
@@ -2245,21 +2705,24 @@
     ]);
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.topGet('x'),
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@getter::x
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_topGetter_topSetter_compound() async {
@@ -2273,28 +2736,27 @@
 ''');
 
     var assignment = findNode.assignment('x += 2');
-    assertAssignment(
-      assignment,
-      readElement: findElement.topGet('x'),
-      readType: 'int',
-      writeElement: findElement.topSet('x'),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@getter::x
+  readType: int
+  writeElement: self::@setter::x
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_topGetter_topSetter_compound_ifNull2() async {
-    var question = isNullSafetyEnabled ? '?' : '';
     await assertErrorsInCode('''
 void f() {
   x ??= C();
@@ -2304,28 +2766,41 @@
 class B extends A {}
 class C extends A {}
 
-B$question get x => B();
-set x(B$question _) {}
+B? get x => B();
+set x(B? _) {}
 ''', [
       error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 19, 3),
     ]);
 
     var assignment = findNode.assignment('x ??=');
-    assertAssignment(
-      assignment,
-      readElement: findElement.topGet('x'),
-      readType: 'B$question',
-      writeElement: findElement.topSet('x'),
-      writeType: 'B$question',
-      operatorElement: null,
-      type: 'A',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'C');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: ??=
+  rightHandSide: InstanceCreationExpression
+    constructorName: ConstructorName
+      type: NamedType
+        name: SimpleIdentifier
+          token: C
+          staticElement: self::@class::C
+          staticType: null
+        type: C
+      staticElement: self::@class::C::@constructor::•
+    argumentList: ArgumentList
+      leftParenthesis: (
+      rightParenthesis: )
+    staticType: C
+  readElement: self::@getter::x
+  readType: B?
+  writeElement: self::@setter::x
+  writeType: B?
+  staticElement: <null>
+  staticType: A
+''');
   }
 
   test_simpleIdentifier_topGetter_topSetter_fromClass_compound() async {
@@ -2341,18 +2816,24 @@
 ''');
 
     var assignment = findNode.assignment('x += 2');
-    assertAssignment(
-      assignment,
-      readElement: findElement.topGet('x'),
-      readType: 'int',
-      writeElement: findElement.topSet('x'),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
+
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@getter::x
+  readType: int
+  writeElement: self::@setter::x
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
 
     assertSimpleIdentifierAssignmentTarget(
       assignment.leftHandSide,
@@ -2371,21 +2852,24 @@
 ''');
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.topSet('x'),
-      writeType: 'num',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@setter::x
+  writeType: num
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_topLevelVariable_simple_notAssignableType() async {
@@ -2400,21 +2884,24 @@
     ]);
 
     var assignment = findNode.assignment('x = true');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.topSet('x'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'bool',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'bool');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: BooleanLiteral
+    literal: true
+    staticType: bool
+  readElement: <null>
+  readType: null
+  writeElement: self::@setter::x
+  writeType: int
+  staticElement: <null>
+  staticType: bool
+''');
   }
 
   test_simpleIdentifier_topLevelVariableFinal_simple() async {
@@ -2429,21 +2916,24 @@
     ]);
 
     var assignment = findNode.assignment('x = 2');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.topGet('x'),
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@getter::x
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_typeLiteral_compound() async {
@@ -2456,21 +2946,24 @@
     ]);
 
     var assignment = findNode.assignment('int += 3');
-    assertAssignment(
-      assignment,
-      readElement: intElement,
-      readType: 'dynamic',
-      writeElement: intElement,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'dynamic',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: int
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int
+  readElement: dart:core::@class::int
+  readType: dynamic
+  writeElement: dart:core::@class::int
+  writeType: dynamic
+  staticElement: <null>
+  staticType: dynamic
+''');
   }
 
   test_simpleIdentifier_typeLiteral_simple() async {
@@ -2483,21 +2976,24 @@
     ]);
 
     var assignment = findNode.assignment('int = 0');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: intElement,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: int
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: dart:core::@class::int
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_simpleIdentifier_unresolved_compound() async {
@@ -2510,21 +3006,24 @@
     ]);
 
     var assignment = findNode.assignment('x += 1');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: 'dynamic',
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'dynamic',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertType(assignment.rightHandSide, 'int');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: dynamic
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: dynamic
+''');
   }
 
   test_simpleIdentifier_unresolved_simple() async {
@@ -2537,24 +3036,24 @@
     ]);
 
     var assignment = findNode.assignment('x = a');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
 
-    assertSimpleIdentifierAssignmentTarget(
-      assignment.leftHandSide,
-    );
-
-    assertSimpleIdentifier(
-      assignment.rightHandSide,
-      element: findElement.parameter('a'),
-      type: 'int',
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: SimpleIdentifier
+    token: a
+    staticElement: a@11
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 }
diff --git a/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart b/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart
index ed71412..fab02b3 100644
--- a/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart
@@ -737,15 +737,31 @@
   a.foo = 1;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('foo = 1'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    assertResolvedNodeText(findNode.assignment('foo = 1'), r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: a@52
+      staticType: int?
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_instance_setter_fromInstance_nullAware() async {
@@ -758,15 +774,30 @@
   a?.foo = 1;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('foo = 1'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int?',
-    );
+    assertResolvedNodeText(findNode.assignment('foo = 1'), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: SimpleIdentifier
+      token: a
+      staticElement: a@51
+      staticType: int?
+    operator: ?.
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int?
+''');
   }
 }
 
@@ -1299,15 +1330,60 @@
   c[2] = 1;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('[2] ='),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.method('[]=', of: 'C'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('[2] =');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: c
+      staticElement: c@127
+      staticType: C
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 2
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::C::@method::[]=
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: c
+      staticElement: c@127
+      staticType: C*
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 2
+      staticType: int*
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::C::@method::[]=
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_instance_operator_indexEquals_fromExtension_functionType() async {
@@ -1319,15 +1395,60 @@
   f[2] = 3;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('f[2]'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.method('[]=', of: 'E'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('f[2]');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: f
+      staticElement: f@102
+      staticType: int Function(int)
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 2
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@method::[]=
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: f
+      staticElement: f@102
+      staticType: int* Function(int*)*
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 2
+      staticType: int*
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@method::[]=
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_instance_operator_indexEquals_fromExtension_interfaceType() async {
@@ -1340,15 +1461,60 @@
   c[2] = 3;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('c[2]'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.method('[]=', of: 'E'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('c[2]');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: c
+      staticElement: c@81
+      staticType: C
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 2
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@method::[]=
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: c
+      staticElement: c@81
+      staticType: C*
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 2
+      staticType: int*
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@method::[]=
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_instance_operator_postfix_fromExtendedType() async {
@@ -1489,15 +1655,60 @@
   f.a = 1;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('a = 1'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('a'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('a = 1');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: f
+      staticElement: f@75
+      staticType: int Function(int)
+    period: .
+    identifier: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: f
+      staticElement: f@75
+      staticType: int* Function(int*)*
+    period: .
+    identifier: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_instance_setter_oneMatch() async {
@@ -1512,15 +1723,60 @@
   c.a = 1;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('a = 1'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('a'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('a = 1');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: c
+      staticElement: c@56
+      staticType: C
+    period: .
+    identifier: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: c
+      staticElement: c@56
+      staticType: C*
+    period: .
+    identifier: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_instance_tearoff_fromExtension_functionType() async {
@@ -1679,16 +1935,74 @@
   p.E.a = 3;
 }
 ''');
-    var importFind = findElement.importFind('package:test/lib.dart');
-    assertAssignment(
-      findNode.assignment('a = 3'),
-      readElement: null,
-      readType: null,
-      writeElement: importFind.setter('a'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('a = 3');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: PrefixedIdentifier
+      prefix: SimpleIdentifier
+        token: p
+        staticElement: self::@prefix::p
+        staticType: null
+      period: .
+      identifier: SimpleIdentifier
+        token: E
+        staticElement: package:test/lib.dart::@extension::E
+        staticType: null
+      staticElement: package:test/lib.dart::@extension::E
+      staticType: null
+    operator: .
+    propertyName: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: package:test/lib.dart::@extension::E::@setter::a
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: PrefixedIdentifier
+      prefix: SimpleIdentifier
+        token: p
+        staticElement: self::@prefix::p
+        staticType: null
+      period: .
+      identifier: SimpleIdentifier
+        token: E
+        staticElement: package:test/lib.dart::@extension::E
+        staticType: null
+      staticElement: package:test/lib.dart::@extension::E
+      staticType: null
+    operator: .
+    propertyName: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: package:test/lib.dart::@extension::E::@setter::a
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_static_setter_local() async {
@@ -1703,15 +2017,60 @@
   E.a = 3;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('a = 3'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('a'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('a = 3');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: E
+      staticElement: self::@extension::E
+      staticType: null
+    period: .
+    identifier: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: E
+      staticElement: self::@extension::E
+      staticType: null
+    period: .
+    identifier: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_static_tearoff() async {
@@ -1800,15 +2159,44 @@
 ''', [
       error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 104, 3),
     ]);
-    assertAssignment(
-      findNode.assignment('foo = 0'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.getter('foo', of: 'E2'),
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('foo = 0');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: foo
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E2::@getter::foo
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: foo
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E2::@getter::foo
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_instance_getter_fromInstance() async {
@@ -1960,15 +2348,58 @@
   void b() { this[2] = 1; }
 }
 ''');
-    assertAssignment(
-      findNode.assignment('this[2]'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.method('[]=', of: 'C'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('this[2]');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: ThisExpression
+      thisKeyword: this
+      staticType: C
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 2
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::C::@method::[]=
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: ThisExpression
+      thisKeyword: this
+      staticType: C*
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 2
+      staticType: int*
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::C::@method::[]=
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_instance_operator_indexEquals_fromThis_fromExtension() async {
@@ -1979,15 +2410,58 @@
   void b() { this[2] = 3; }
 }
 ''');
-    assertAssignment(
-      findNode.assignment('this[2]'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.method('[]=', of: 'E'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('this[2]');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: ThisExpression
+      thisKeyword: this
+      staticType: C
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 2
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@method::[]=
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: ThisExpression
+      thisKeyword: this
+      staticType: C*
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 2
+      staticType: int*
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@method::[]=
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_instance_operator_unary_fromThis_fromExtendedType() async {
@@ -2051,15 +2525,44 @@
   }
 }
 ''');
-    assertAssignment(
-      findNode.assignment('a = 3'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('a', of: 'E'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('a = 3');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: a
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: a
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_instance_setter_fromThis_fromExtendedType() async {
@@ -2075,15 +2578,56 @@
   }
 }
 ''');
-    assertAssignment(
-      findNode.assignment('a = 3'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('a', of: 'C'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('a = 3');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ThisExpression
+      thisKeyword: this
+      staticType: C
+    operator: .
+    propertyName: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::C::@setter::a
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ThisExpression
+      thisKeyword: this
+      staticType: C*
+    operator: .
+    propertyName: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::C::@setter::a
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_instance_setter_fromThis_fromExtension() async {
@@ -2097,15 +2641,56 @@
   }
 }
 ''');
-    assertAssignment(
-      findNode.assignment('a = 3'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('a', of: 'E'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('a = 3');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ThisExpression
+      thisKeyword: this
+      staticType: C
+    operator: .
+    propertyName: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ThisExpression
+      thisKeyword: this
+      staticType: C*
+    operator: .
+    propertyName: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_instance_tearoff_fromInstance() async {
@@ -2229,15 +2814,44 @@
   }
 }
 ''');
-    assertAssignment(
-      findNode.assignment('a = 3'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('a'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('a = 3');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: a
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: a
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_static_setter_fromStatic() async {
@@ -2251,15 +2865,44 @@
   }
 }
 ''');
-    assertAssignment(
-      findNode.assignment('a = 3'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('a'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('a = 3');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: a
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: a
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_static_tearoff_fromInstance() async {
@@ -2380,15 +3023,44 @@
   }
 }
 ''');
-    assertAssignment(
-      findNode.assignment('a = 0'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.topSet('a'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('a = 0');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: a
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@setter::a
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: a
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@setter::a
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_topLevel_setter_fromStatic() async {
@@ -2405,15 +3077,44 @@
   }
 }
 ''');
-    assertAssignment(
-      findNode.assignment('a = 0'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.topSet('a'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('a = 0');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: a
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@setter::a
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: a
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@setter::a
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 }
 
diff --git a/pkg/analyzer/test/src/dart/resolution/extension_override_test.dart b/pkg/analyzer/test/src/dart/resolution/extension_override_test.dart
index 77648aa..b51bd96 100644
--- a/pkg/analyzer/test/src/dart/resolution/extension_override_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/extension_override_test.dart
@@ -66,15 +66,42 @@
 }
 ''');
 
-    assertAssignment(
-      findNode.assignment('[0] ='),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.method('[]=', of: 'E'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int?',
-    );
+    assertResolvedNodeText(findNode.assignment('[0] ='), r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: ExtensionOverride
+      extensionName: SimpleIdentifier
+        token: E
+        staticElement: self::@extension::E
+        staticType: null
+      argumentList: ArgumentList
+        leftParenthesis: (
+        arguments
+          SimpleIdentifier
+            token: a
+            staticElement: a@76
+            staticType: int?
+        rightParenthesis: )
+      extendedType: int
+      staticType: null
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@method::[]=
+  writeType: int
+  staticElement: <null>
+  staticType: int?
+''');
   }
 
   test_methodInvocation_nullAware() async {
diff --git a/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
index 9ad7b3b..f4bf3b6 100644
--- a/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
@@ -208,7 +208,6 @@
 }
 ''');
 
-    var indexElement = findElement.method('[]');
     var indexEqElement = findElement.method('[]=');
     var numPlusElement = numElement.getMethod('+')!;
 
@@ -219,18 +218,32 @@
     );
 
     var assignment = indexExpression.parent as AssignmentExpression;
-    assertAssignment(
-      assignment,
-      readElement: indexElement,
-      readType: 'num',
-      writeElement: indexEqElement,
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numPlusElement,
-        isLegacy: isLegacyLibrary,
-      ),
-      type: typeStringByNullability(nullable: 'double', legacy: 'num'),
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: a
+      staticElement: a@100
+      staticType: A
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: DoubleLiteral
+    literal: 1.2
+    staticType: double
+  readElement: self::@class::A::@method::[]
+  readType: num
+  writeElement: self::@class::A::@method::[]=
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: double
+''');
+
     assertParameterElement(
       assignment.rightHandSide,
       numPlusElement.parameters[0],
@@ -249,7 +262,6 @@
 }
 ''');
 
-    var indexElement = findElement.method('[]');
     var indexEqElement = findElement.method('[]=');
     var doublePlusElement = doubleElement.getMethod('+')!;
 
@@ -263,24 +275,37 @@
     );
 
     var assignment = indexExpression.parent as AssignmentExpression;
-    assertAssignment(
-      assignment,
-      readElement: elementMatcher(
-        indexElement,
-        substitution: {'T': 'double'},
-      ),
-      readType: 'double',
-      writeElement: elementMatcher(
-        indexEqElement,
-        substitution: {'T': 'double'},
-      ),
-      writeType: 'double',
-      operatorElement: elementMatcher(
-        doublePlusElement,
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'double',
-    );
+
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: a
+      staticElement: a@114
+      staticType: A<double>
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: DoubleLiteral
+    literal: 1.2
+    staticType: double
+  readElement: MethodMember
+    base: self::@class::A::@method::[]
+    substitution: {T: double}
+  readType: double
+  writeElement: MethodMember
+    base: self::@class::A::@method::[]=
+    substitution: {T: double}
+  writeType: double
+  staticElement: dart:core::@class::double::@method::+
+  staticType: double
+''');
+
     assertParameterElement(
       assignment.rightHandSide,
       doublePlusElement.parameters[0],
@@ -299,7 +324,6 @@
 }
 ''');
 
-    var indexElement = findElement.method('[]');
     var indexEqElement = findElement.method('[]=');
     var numPlusElement = numElement.getMethod('+')!;
 
@@ -310,15 +334,33 @@
     );
 
     var assignment = indexExpression.parent as AssignmentExpression;
-    assertAssignment(
-      assignment,
-      readElement: indexElement,
-      readType: 'num',
-      writeElement: indexEqElement,
-      writeType: 'num',
-      operatorElement: numPlusElement,
-      type: 'double?',
-    );
+
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: a
+      staticElement: a@101
+      staticType: A?
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: DoubleLiteral
+    literal: 1.2
+    staticType: double
+  readElement: self::@class::A::@method::[]
+  readType: num
+  writeElement: self::@class::A::@method::[]=
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: double?
+''');
+
     assertParameterElement(
       assignment.rightHandSide,
       numPlusElement.parameters[0],
@@ -345,15 +387,33 @@
     );
 
     var assignment = indexExpression.parent as AssignmentExpression;
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: indexEqElement,
-      writeType: 'num',
-      operatorElement: null,
-      type: 'double',
-    );
+
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: a
+      staticElement: a@66
+      staticType: A
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: DoubleLiteral
+    literal: 1.2
+    staticType: double
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@method::[]=
+  writeType: num
+  staticElement: <null>
+  staticType: double
+''');
+
     assertParameterElement(
       assignment.rightHandSide,
       indexEqElement.parameters[1],
@@ -371,27 +431,58 @@
 }
 ''');
 
-    assertAssignment(
-      findNode.assignment('[0]'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.method('[]='),
-      writeType: 'A',
-      operatorElement: null,
-      type: 'A',
-    );
-
-    assertAssignment(
-      findNode.assignment('[1]'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.method('[]='),
-      writeType: 'A',
-      operatorElement: null,
-      type: 'A',
-    );
-
-    assertType(findNode.cascade('a?'), 'A?');
+    var node = findNode.cascade('a?..');
+    assertResolvedNodeText(node, r'''
+CascadeExpression
+  target: SimpleIdentifier
+    token: a
+    staticElement: a@61
+    staticType: A?
+  cascadeSections
+    AssignmentExpression
+      leftHandSide: IndexExpression
+        period: ?..
+        leftBracket: [
+        index: IntegerLiteral
+          literal: 0
+          staticType: int
+        rightBracket: ]
+        staticElement: <null>
+        staticType: null
+      operator: =
+      rightHandSide: SimpleIdentifier
+        token: a
+        staticElement: a@61
+        staticType: A
+      readElement: <null>
+      readType: null
+      writeElement: self::@class::A::@method::[]=
+      writeType: A
+      staticElement: <null>
+      staticType: A
+    AssignmentExpression
+      leftHandSide: IndexExpression
+        period: ..
+        leftBracket: [
+        index: IntegerLiteral
+          literal: 1
+          staticType: int
+        rightBracket: ]
+        staticElement: <null>
+        staticType: null
+      operator: =
+      rightHandSide: SimpleIdentifier
+        token: a
+        staticElement: a@61
+        staticType: A
+      readElement: <null>
+      readType: null
+      writeElement: self::@class::A::@method::[]=
+      writeType: A
+      staticElement: <null>
+      staticType: A
+  staticType: A?
+''');
   }
 
   test_write_generic() async {
@@ -416,19 +507,36 @@
       ),
     );
 
-    var assignment = indexExpression.parent as AssignmentExpression;
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        indexEqElement,
-        substitution: {'T': 'double'},
-      ),
-      writeType: 'double',
-      operatorElement: null,
-      type: 'double',
-    );
+    var assignment = findNode.assignment('a[0]');
+
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: a
+      staticElement: a@75
+      staticType: A<double>
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: DoubleLiteral
+    literal: 1.2
+    staticType: double
+  readElement: <null>
+  readType: null
+  writeElement: MethodMember
+    base: self::@class::A::@method::[]=
+    substitution: {T: double}
+  writeType: double
+  staticElement: <null>
+  staticType: double
+''');
+
     assertParameterElement(
       assignment.rightHandSide,
       elementMatcher(
@@ -457,16 +565,34 @@
       indexEqElement.parameters[0],
     );
 
-    var assignment = indexExpression.parent as AssignmentExpression;
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: indexEqElement,
-      writeType: 'num',
-      operatorElement: null,
-      type: 'double?',
-    );
+    var assignment = findNode.assignment('a?[0]');
+
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: a
+      staticElement: a@67
+      staticType: A?
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: DoubleLiteral
+    literal: 1.2
+    staticType: double
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@method::[]=
+  writeType: num
+  staticElement: <null>
+  staticType: double?
+''');
+
     assertParameterElement(
       assignment.rightHandSide,
       indexEqElement.parameters[1],
diff --git a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
index 3187d2a..d74ef96 100644
--- a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
@@ -414,14 +414,29 @@
 class X extends A with M {}
 ''');
 
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('foo =');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: SuperExpression
+      superKeyword: super
+      staticType: M
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 }
diff --git a/pkg/analyzer/test/src/dart/resolution/prefixed_identifier_test.dart b/pkg/analyzer/test/src/dart/resolution/prefixed_identifier_test.dart
index 6c71f9f..1b7beb4f 100644
--- a/pkg/analyzer/test/src/dart/resolution/prefixed_identifier_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/prefixed_identifier_test.dart
@@ -2,7 +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.
 
-import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -91,26 +90,31 @@
 ''');
 
     var assignment = findNode.assignment('foo = 1');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
-
-    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
-    assertSimpleIdentifier(
-      prefixed.prefix,
-      element: findElement.parameter('e'),
-      type: 'E',
-    );
-
-    assertSimpleIdentifierAssignmentTarget(
-      prefixed.identifier,
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: e
+      staticElement: e@46
+      staticType: E
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@enum::E::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_hasReceiver_typeAlias_staticGetter() async {
@@ -341,29 +345,61 @@
 ''');
 
     var assignment = findNode.assignment('foo += 1');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('foo'),
-      readType: 'int',
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
-
-    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
-    assertSimpleIdentifier(
-      prefixed.prefix,
-      element: findElement.parameter('a'),
-      type: 'A',
-    );
-
-    assertSimpleIdentifierAssignmentTarget(
-      prefixed.identifier,
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: a@37
+      staticType: A
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: self::@class::A::@getter::foo
+  readType: int
+  writeElement: self::@class::A::@setter::foo
+  writeType: int
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: a@37
+      staticType: A*
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int*
+  readElement: self::@class::A::@getter::foo
+  readType: int*
+  writeElement: self::@class::A::@setter::foo
+  writeType: int*
+  staticElement: MethodMember
+    base: dart:core::@class::num::@method::+
+    isLegacy: true
+  staticType: int*
+''');
+    }
   }
 
   test_class_write() async {
@@ -378,26 +414,59 @@
 ''');
 
     var assignment = findNode.assignment('foo = 1');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
-
-    var prefixed = assignment.leftHandSide as PrefixedIdentifier;
-    assertSimpleIdentifier(
-      prefixed.prefix,
-      element: findElement.parameter('a'),
-      type: 'A',
-    );
-
-    assertSimpleIdentifierAssignmentTarget(
-      prefixed.identifier,
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: a@37
+      staticType: A
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: a@37
+      staticType: A*
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::foo
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_dynamic_explicitCore_withPrefix() async {
diff --git a/pkg/analyzer/test/src/dart/resolution/property_access_test.dart b/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
index d4b57a6..6460408 100644
--- a/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
@@ -239,20 +239,34 @@
 ''');
 
     var assignment = findNode.assignment('foo = 1');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
-
-    var propertyAccess = assignment.leftHandSide as PropertyAccess;
-    assertSimpleIdentifierAssignmentTarget(
-      propertyAccess.propertyName,
-    );
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ParenthesizedExpression
+      leftParenthesis: (
+      expression: SimpleIdentifier
+        token: e
+        staticElement: e@46
+        staticType: E
+      rightParenthesis: )
+      staticType: E
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@enum::E::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 }
 
@@ -299,18 +313,81 @@
 ''');
 
     var assignment = findNode.assignment('foo += 1');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('foo'),
-      readType: 'int',
-      writeElement: findElement.setter('foo'),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ExtensionOverride
+      extensionName: SimpleIdentifier
+        token: E
+        staticElement: self::@extension::E
+        staticType: null
+      argumentList: ArgumentList
+        leftParenthesis: (
+        arguments
+          SimpleIdentifier
+            token: a
+            staticElement: a@83
+            staticType: A
+        rightParenthesis: )
+      extendedType: A
+      staticType: null
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: self::@extension::E::@getter::foo
+  readType: int
+  writeElement: self::@extension::E::@setter::foo
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ExtensionOverride
+      extensionName: SimpleIdentifier
+        token: E
+        staticElement: self::@extension::E
+        staticType: null
+      argumentList: ArgumentList
+        leftParenthesis: (
+        arguments
+          SimpleIdentifier
+            token: a
+            staticElement: a@83
+            staticType: A*
+        rightParenthesis: )
+      extendedType: A*
+      staticType: null
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int*
+  readElement: self::@extension::E::@getter::foo
+  readType: int*
+  writeElement: self::@extension::E::@setter::foo
+  writeType: num*
+  staticElement: MethodMember
+    base: dart:core::@class::num::@method::+
+    isLegacy: true
+  staticType: int*
+''');
+    }
   }
 
   test_extensionOverride_write() async {
@@ -327,15 +404,79 @@
 ''');
 
     var assignment = findNode.assignment('foo = 1');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ExtensionOverride
+      extensionName: SimpleIdentifier
+        token: E
+        staticElement: self::@extension::E
+        staticType: null
+      argumentList: ArgumentList
+        leftParenthesis: (
+        arguments
+          SimpleIdentifier
+            token: a
+            staticElement: a@63
+            staticType: A
+        rightParenthesis: )
+      extendedType: A
+      staticType: null
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ExtensionOverride
+      extensionName: SimpleIdentifier
+        token: E
+        staticElement: self::@extension::E
+        staticType: null
+      argumentList: ArgumentList
+        leftParenthesis: (
+        arguments
+          SimpleIdentifier
+            token: a
+            staticElement: a@63
+            staticType: A*
+        rightParenthesis: )
+      extendedType: A*
+      staticType: null
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::foo
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_functionType_call_read() async {
@@ -389,18 +530,77 @@
 ''');
 
     var assignment = findNode.assignment('foo += 1');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('foo'),
-      readType: 'int',
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: InstanceCreationExpression
+      constructorName: ConstructorName
+        type: NamedType
+          name: SimpleIdentifier
+            token: A
+            staticElement: self::@class::A
+            staticType: null
+          type: A
+        staticElement: self::@class::A::@constructor::•
+      argumentList: ArgumentList
+        leftParenthesis: (
+        rightParenthesis: )
+      staticType: A
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: self::@class::A::@getter::foo
+  readType: int
+  writeElement: self::@class::A::@setter::foo
+  writeType: int
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: InstanceCreationExpression
+      constructorName: ConstructorName
+        type: NamedType
+          name: SimpleIdentifier
+            token: A
+            staticElement: self::@class::A
+            staticType: null
+          type: A*
+        staticElement: self::@class::A::@constructor::•
+      argumentList: ArgumentList
+        leftParenthesis: (
+        rightParenthesis: )
+      staticType: A*
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int*
+  readElement: self::@class::A::@getter::foo
+  readType: int*
+  writeElement: self::@class::A::@setter::foo
+  writeType: int*
+  staticElement: MethodMember
+    base: dart:core::@class::num::@method::+
+    isLegacy: true
+  staticType: int*
+''');
+    }
   }
 
   test_instanceCreation_write() async {
@@ -415,15 +615,75 @@
 ''');
 
     var assignment = findNode.assignment('foo = 1');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: InstanceCreationExpression
+      constructorName: ConstructorName
+        type: NamedType
+          name: SimpleIdentifier
+            token: A
+            staticElement: self::@class::A
+            staticType: null
+          type: A
+        staticElement: self::@class::A::@constructor::•
+      argumentList: ArgumentList
+        leftParenthesis: (
+        rightParenthesis: )
+      staticType: A
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: InstanceCreationExpression
+      constructorName: ConstructorName
+        type: NamedType
+          name: SimpleIdentifier
+            token: A
+            staticElement: self::@class::A
+            staticType: null
+          type: A*
+        staticElement: self::@class::A::@constructor::•
+      argumentList: ArgumentList
+        leftParenthesis: (
+        rightParenthesis: )
+      staticType: A*
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::foo
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_invalid_inDefaultValue_nullAware() async {
@@ -603,18 +863,77 @@
 ''');
 
     var assignment = findNode.assignment('foo += 1');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('foo'),
-      readType: 'int',
-      writeElement: findElement.setter('foo'),
-      writeType: 'num',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: InstanceCreationExpression
+      constructorName: ConstructorName
+        type: NamedType
+          name: SimpleIdentifier
+            token: A
+            staticElement: self::@class::A
+            staticType: null
+          type: A
+        staticElement: self::@class::A::@constructor::•
+      argumentList: ArgumentList
+        leftParenthesis: (
+        rightParenthesis: )
+      staticType: A
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: self::@extension::E::@getter::foo
+  readType: int
+  writeElement: self::@extension::E::@setter::foo
+  writeType: num
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: InstanceCreationExpression
+      constructorName: ConstructorName
+        type: NamedType
+          name: SimpleIdentifier
+            token: A
+            staticElement: self::@class::A
+            staticType: null
+          type: A*
+        staticElement: self::@class::A::@constructor::•
+      argumentList: ArgumentList
+        leftParenthesis: (
+        rightParenthesis: )
+      staticType: A*
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int*
+  readElement: self::@extension::E::@getter::foo
+  readType: int*
+  writeElement: self::@extension::E::@setter::foo
+  writeType: num*
+  staticElement: MethodMember
+    base: dart:core::@class::num::@method::+
+    isLegacy: true
+  staticType: int*
+''');
+    }
   }
 
   test_ofExtension_write() async {
@@ -631,15 +950,75 @@
 ''');
 
     var assignment = findNode.assignment('foo = 1');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: InstanceCreationExpression
+      constructorName: ConstructorName
+        type: NamedType
+          name: SimpleIdentifier
+            token: A
+            staticElement: self::@class::A
+            staticType: null
+          type: A
+        staticElement: self::@class::A::@constructor::•
+      argumentList: ArgumentList
+        leftParenthesis: (
+        rightParenthesis: )
+      staticType: A
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: InstanceCreationExpression
+      constructorName: ConstructorName
+        type: NamedType
+          name: SimpleIdentifier
+            token: A
+            staticElement: self::@class::A
+            staticType: null
+          type: A*
+        staticElement: self::@class::A::@constructor::•
+      argumentList: ArgumentList
+        leftParenthesis: (
+        rightParenthesis: )
+      staticType: A*
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::foo
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_super_read() async {
@@ -687,18 +1066,57 @@
 ''');
 
     var assignment = findNode.assignment('foo += 1');
-    assertAssignment(
-      assignment,
-      readElement: findElement.getter('foo'),
-      readType: 'int',
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: SuperExpression
+      superKeyword: super
+      staticType: B
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: self::@class::A::@getter::foo
+  readType: int
+  writeElement: self::@class::A::@setter::foo
+  writeType: int
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: SuperExpression
+      superKeyword: super
+      staticType: B*
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int*
+  readElement: self::@class::A::@getter::foo
+  readType: int*
+  writeElement: self::@class::A::@setter::foo
+  writeType: int*
+  staticElement: MethodMember
+    base: dart:core::@class::num::@method::+
+    isLegacy: true
+  staticType: int*
+''');
+    }
 
     var propertyAccess = assignment.leftHandSide as PropertyAccess;
     assertSuperExpression(
@@ -720,15 +1138,55 @@
 ''');
 
     var assignment = findNode.assignment('foo = 1');
-    assertAssignment(
-      assignment,
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: SuperExpression
+      superKeyword: super
+      staticType: B
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: SuperExpression
+      superKeyword: super
+      staticType: B*
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::foo
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
 
     var propertyAccess = assignment.leftHandSide as PropertyAccess;
     assertSuperExpression(
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index 7f40418..51a5dd8 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -90,28 +90,6 @@
     newFile(testFilePath, content);
   }
 
-  void assertAssignment(
-    AssignmentExpression node, {
-    required Object? readElement,
-    required String? readType,
-    required Object? writeElement,
-    required String writeType,
-    required Object? operatorElement,
-    required String type,
-  }) {
-    assertCompoundAssignment(
-      node,
-      readElement: readElement,
-      readType: readType,
-      writeElement: writeElement,
-      writeType: writeType,
-    );
-    assertElement(node.staticElement, operatorElement);
-    assertType(node, type);
-
-    _assertUnresolvedAssignmentTarget(node.leftHandSide);
-  }
-
   /// Assert that the given [identifier] is a reference to a class, in the
   /// form that is not a separate expression, e.g. in a static method
   /// invocation like `C.staticMethod()`, or a type annotation `C c = null`.
@@ -121,28 +99,6 @@
     assertTypeNull(identifier);
   }
 
-  void assertCompoundAssignment(
-    CompoundAssignmentExpression node, {
-    required Object? readElement,
-    required String? readType,
-    required Object? writeElement,
-    required String? writeType,
-  }) {
-    assertElement(node.readElement, readElement);
-    if (readType == null) {
-      expect(node.readType, isNull);
-    } else {
-      assertType(node.readType, readType);
-    }
-
-    assertElement(node.writeElement, writeElement);
-    if (writeType == null) {
-      expect(node.writeType, isNull);
-    } else {
-      assertType(node.writeType, writeType);
-    }
-  }
-
   void assertConstructorElement(ConstructorElement? actual, Object? expected) {
     if (actual is ConstructorMember && expected is ConstructorMember) {
       expect(actual.declaration, same(expected.declaration));
@@ -866,22 +822,6 @@
     }
   }
 
-  /// Nodes that are targets of an assignment should not be resolved,
-  /// instead the enclosing [CompoundAssignmentExpression] is resolved.
-  void _assertUnresolvedAssignmentTarget(Expression node) {
-    if (node is IndexExpression) {
-      assertUnresolvedIndexExpression(node);
-    } else if (node is PrefixedIdentifier) {
-      assertUnresolvedPrefixedIdentifier(node);
-    } else if (node is PropertyAccess) {
-      assertUnresolvedPropertyAccess(node);
-    } else if (node is SimpleIdentifier) {
-      assertUnresolvedSimpleIdentifier(node, disableElementCheck: true);
-    } else {
-      // Not LValue.
-    }
-  }
-
   Matcher _elementMatcher(Object? elementOrMatcher) {
     if (elementOrMatcher is Element) {
       return _ElementMatcher(this, declaration: elementOrMatcher);
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/extension_methods_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/extension_methods_test.dart
index 48e4fb1..a0f0291 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/extension_methods_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/extension_methods_test.dart
@@ -180,18 +180,64 @@
   a.foo = 0;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        findElement.setter('foo', of: 'E'),
-        substitution: {'T': 'int'},
-      ),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('foo =');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: a@79
+      staticType: A<int>
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: self::@extension::E::@setter::foo
+    substitution: {T: int}
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: a@79
+      staticType: A<int*>*
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: self::@extension::E::@setter::foo
+    substitution: {T: int*}
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 
   test_implicit_targetTypeParameter_hasBound_methodInvocation() async {
@@ -294,42 +340,87 @@
 }
 ''');
 
-    if (result.libraryElement.isNonNullableByDefault) {
-      assertAssignment(
-        findNode.assignment('(x).test'),
-        readElement: null,
-        readType: null,
-        writeElement: elementMatcher(
-          findElement.setter('test'),
-          substitution: {'T': 'S'},
-        ),
-        writeType: 'S',
-        operatorElement: null,
-        type: 'S',
-      );
-
-      assertTypeArgumentTypes(
-        findNode.methodInvocation('g()'),
-        ['S'],
-      );
+    var assignment = findNode.assignment('(x).test');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ParenthesizedExpression
+      leftParenthesis: (
+      expression: SimpleIdentifier
+        token: x
+        staticElement: x@98
+        staticType: S
+      rightParenthesis: )
+      staticType: S
+    operator: .
+    propertyName: SimpleIdentifier
+      token: test
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: MethodInvocation
+    methodName: SimpleIdentifier
+      token: g
+      staticElement: self::@function::g
+      staticType: T Function<T>()
+    argumentList: ArgumentList
+      leftParenthesis: (
+      rightParenthesis: )
+    staticInvokeType: S Function()
+    staticType: S
+    typeArgumentTypes
+      S
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: self::@extension::Test::@setter::test
+    substitution: {T: S}
+  writeType: S
+  staticElement: <null>
+  staticType: S
+''');
     } else {
-      assertAssignment(
-        findNode.assignment('(x).test'),
-        readElement: null,
-        readType: null,
-        writeElement: elementMatcher(
-          findElement.setter('test'),
-          substitution: {'T': 'num'},
-        ),
-        writeType: 'num',
-        operatorElement: null,
-        type: 'num',
-      );
-
-      assertTypeArgumentTypes(
-        findNode.methodInvocation('g()'),
-        ['num'],
-      );
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ParenthesizedExpression
+      leftParenthesis: (
+      expression: SimpleIdentifier
+        token: x
+        staticElement: x@98
+        staticType: S*
+      rightParenthesis: )
+      staticType: S*
+    operator: .
+    propertyName: SimpleIdentifier
+      token: test
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: MethodInvocation
+    methodName: SimpleIdentifier
+      token: g
+      staticElement: self::@function::g
+      staticType: T* Function<T>()*
+    argumentList: ArgumentList
+      leftParenthesis: (
+      rightParenthesis: )
+    staticInvokeType: num* Function()*
+    staticType: num*
+    typeArgumentTypes
+      num*
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: self::@extension::Test::@setter::test
+    substitution: {T: num*}
+  writeType: num*
+  staticElement: <null>
+  staticType: num*
+''');
     }
   }
 
@@ -469,23 +560,109 @@
   E<num>(a).foo = 1.2;
 }
 ''');
-    var override = findNode.extensionOverride('E<num>(a)');
-    assertElement(override, findElement.extension_('E'));
-    assertElementTypes(override.typeArgumentTypes, ['num']);
-    assertType(override.extendedType, 'A<num>');
 
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        findElement.setter('foo', of: 'E'),
-        substitution: {'T': 'num'},
-      ),
-      writeType: 'num',
-      operatorElement: null,
-      type: 'double',
-    );
+    var assignment = findNode.assignment('foo =');
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ExtensionOverride
+      extensionName: SimpleIdentifier
+        token: E
+        staticElement: self::@extension::E
+        staticType: null
+      typeArguments: TypeArgumentList
+        leftBracket: <
+        arguments
+          NamedType
+            name: SimpleIdentifier
+              token: num
+              staticElement: dart:core::@class::num
+              staticType: null
+            type: num
+        rightBracket: >
+      argumentList: ArgumentList
+        leftParenthesis: (
+        arguments
+          SimpleIdentifier
+            token: a
+            staticElement: a@79
+            staticType: A<int>
+        rightParenthesis: )
+      extendedType: A<num>
+      staticType: null
+      typeArgumentTypes
+        num
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: DoubleLiteral
+    literal: 1.2
+    staticType: double
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: self::@extension::E::@setter::foo
+    substitution: {T: num}
+  writeType: num
+  staticElement: <null>
+  staticType: double
+''');
+    } else {
+      assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ExtensionOverride
+      extensionName: SimpleIdentifier
+        token: E
+        staticElement: self::@extension::E
+        staticType: null
+      typeArguments: TypeArgumentList
+        leftBracket: <
+        arguments
+          NamedType
+            name: SimpleIdentifier
+              token: num
+              staticElement: dart:core::@class::num
+              staticType: null
+            type: num*
+        rightBracket: >
+      argumentList: ArgumentList
+        leftParenthesis: (
+        arguments
+          SimpleIdentifier
+            token: a
+            staticElement: a@79
+            staticType: A<int*>*
+        rightParenthesis: )
+      extendedType: A<num*>*
+      staticType: null
+      typeArgumentTypes
+        num*
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: DoubleLiteral
+    literal: 1.2
+    staticType: double*
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: self::@extension::E::@setter::foo
+    substitution: {T: num*}
+  writeType: num*
+  staticElement: <null>
+  staticType: double*
+''');
+    }
   }
 
   test_override_inferTypeArguments_error_couldNotInfer() async {
@@ -601,23 +778,88 @@
   E(a).foo = 0;
 }
 ''');
-    var override = findNode.extensionOverride('E(a)');
-    assertElement(override, findElement.extension_('E'));
-    assertElementTypes(override.typeArgumentTypes, ['int']);
-    assertType(override.extendedType, 'A<int>');
 
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        findElement.setter('foo', of: 'E'),
-        substitution: {'T': 'int'},
-      ),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(findNode.assignment('foo ='), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ExtensionOverride
+      extensionName: SimpleIdentifier
+        token: E
+        staticElement: self::@extension::E
+        staticType: null
+      argumentList: ArgumentList
+        leftParenthesis: (
+        arguments
+          SimpleIdentifier
+            token: a
+            staticElement: a@79
+            staticType: A<int>
+        rightParenthesis: )
+      extendedType: A<int>
+      staticType: null
+      typeArgumentTypes
+        int
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: self::@extension::E::@setter::foo
+    substitution: {T: int}
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(findNode.assignment('foo ='), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ExtensionOverride
+      extensionName: SimpleIdentifier
+        token: E
+        staticElement: self::@extension::E
+        staticType: null
+      argumentList: ArgumentList
+        leftParenthesis: (
+        arguments
+          SimpleIdentifier
+            token: a
+            staticElement: a@79
+            staticType: A<int*>*
+        rightParenthesis: )
+      extendedType: A<int*>*
+      staticType: null
+      typeArgumentTypes
+        int*
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: self::@extension::E::@setter::foo
+    substitution: {T: int*}
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
+    }
   }
 }
 
diff --git a/pkg/analyzer/test/src/diagnostics/abstract_super_member_reference_test.dart b/pkg/analyzer/test/src/diagnostics/abstract_super_member_reference_test.dart
index 59a6b97..12d705e 100644
--- a/pkg/analyzer/test/src/diagnostics/abstract_super_member_reference_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/abstract_super_member_reference_test.dart
@@ -437,15 +437,29 @@
 
     assertSuperExpression(findNode.super_('super.foo'));
 
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    assertResolvedNodeText(findNode.assignment('foo ='), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: SuperExpression
+      superKeyword: super
+      staticType: B
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_propertyAccess_setter_mixin_implements() async {
@@ -465,15 +479,29 @@
 
     assertSuperExpression(findNode.super_('super.foo'));
 
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    assertResolvedNodeText(findNode.assignment('foo ='), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: SuperExpression
+      superKeyword: super
+      staticType: M
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_propertyAccess_setter_mixinHasNoSuchMethod() async {
@@ -493,15 +521,30 @@
 
     assertSuperExpression(findNode.super_('super.foo'));
 
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo', of: 'A'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    assertResolvedNodeText(findNode.assignment('foo ='), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: SuperExpression
+      superKeyword: super
+      staticType: B
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: SimpleIdentifier
+    token: a
+    staticElement: a@99
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_propertyAccess_setter_superHasNoSuchMethod() async {
@@ -519,15 +562,30 @@
 
     assertSuperExpression(findNode.super_('super.foo'));
 
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo', of: 'A'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    assertResolvedNodeText(findNode.assignment('foo ='), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: SuperExpression
+      superKeyword: super
+      staticType: B
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: SimpleIdentifier
+    token: a
+    staticElement: a@90
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_propertyAccess_setter_superSuperHasConcrete() async {
@@ -549,14 +607,28 @@
 
     assertSuperExpression(findNode.super_('super.foo'));
 
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('foo', of: 'A'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    assertResolvedNodeText(findNode.assignment('foo ='), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: SuperExpression
+      superKeyword: super
+      staticType: C
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/ambiguous_extension_member_access_test.dart b/pkg/analyzer/test/src/diagnostics/ambiguous_extension_member_access_test.dart
index 46fccef..616f384 100644
--- a/pkg/analyzer/test/src/diagnostics/ambiguous_extension_member_access_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/ambiguous_extension_member_access_test.dart
@@ -342,15 +342,30 @@
 ''', [
       error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 88, 1),
     ]);
-    assertAssignment(
-      findNode.assignment('= 3'),
-      readElement: null,
-      readType: null,
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
+
+    assertResolvedNodeText(findNode.assignment('= 3'), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: IntegerLiteral
+      literal: 0
+      staticType: int
+    operator: .
+    propertyName: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 3
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_unnamed_extensions() async {
diff --git a/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart b/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart
index fb52e33..c9f63b1 100644
--- a/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart
@@ -160,15 +160,31 @@
       error(CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER, 72, 1),
     ]);
 
-    assertAssignment(
-      findNode.assignment('a ='),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('a', of: 'E'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    assertResolvedNodeText(findNode.assignment('a ='), r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: c
+      staticElement: c@63
+      staticType: C
+    period: .
+    identifier: SimpleIdentifier
+      token: a
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@extension::E::@setter::a
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_method_reference() async {
diff --git a/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart b/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart
index 52f42c8..d8c9850 100644
--- a/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart
@@ -38,18 +38,34 @@
 }
 ''');
 
-    assertAssignment(
-      findNode.assignment(' = null;'),
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        _import_a.method('[]='),
-        isLegacy: true,
-      ),
-      writeType: 'int*',
-      operatorElement: null,
-      type: 'Null*',
-    );
+    var assignment = findNode.assignment(' = null;');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: a
+      staticElement: a@40
+      staticType: A*
+    leftBracket: [
+    index: NullLiteral
+      literal: null
+      staticType: Null*
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: NullLiteral
+    literal: null
+    staticType: Null*
+  readElement: <null>
+  readType: null
+  writeElement: MethodMember
+    base: package:test/a.dart::@class::A::@method::[]=
+    isLegacy: true
+  writeType: int*
+  staticElement: <null>
+  staticType: Null*
+''');
   }
 
   test_assignment_prefixedIdentifier_instanceTarget_class_field() async {
@@ -66,18 +82,35 @@
   a.foo = 0;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        _import_a.setter('foo'),
-        isLegacy: true,
-      ),
-      writeType: 'int*',
-      operatorElement: null,
-      type: 'int*',
-    );
+
+    var assignment = findNode.assignment('foo =');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: a@40
+      staticType: A*
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: package:test/a.dart::@class::A::@setter::foo
+    isLegacy: true
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
   }
 
   test_assignment_prefixedIdentifier_instanceTarget_extension_setter() async {
@@ -95,18 +128,35 @@
   a.foo = 0;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        _import_a.setter('foo'),
-        isLegacy: true,
-      ),
-      writeType: 'int*',
-      operatorElement: null,
-      type: 'int*',
-    );
+
+    var assignment = findNode.assignment('foo =');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: a
+      staticElement: a@40
+      staticType: A*
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: package:test/a.dart::@extension::E::@setter::foo
+    isLegacy: true
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
   }
 
   test_assignment_prefixedIdentifier_staticTarget_class_field() async {
@@ -123,18 +173,35 @@
   A.foo = 0;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        _import_a.setter('foo'),
-        isLegacy: true,
-      ),
-      writeType: 'int*',
-      operatorElement: null,
-      type: 'int*',
-    );
+
+    var assignment = findNode.assignment('foo =');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: A
+      staticElement: package:test/a.dart::@class::A
+      staticType: null
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: package:test/a.dart::@class::A::@setter::foo
+    isLegacy: true
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
   }
 
   test_assignment_prefixedIdentifier_staticTarget_extension_field() async {
@@ -151,18 +218,35 @@
   E.foo = 0;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        _import_a.setter('foo'),
-        isLegacy: true,
-      ),
-      writeType: 'int*',
-      operatorElement: null,
-      type: 'int*',
-    );
+
+    var assignment = findNode.assignment('foo =');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: E
+      staticElement: package:test/a.dart::@extension::E
+      staticType: null
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: package:test/a.dart::@extension::E::@setter::foo
+    isLegacy: true
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
   }
 
   test_assignment_prefixedIdentifier_topLevelVariable() async {
@@ -177,18 +261,35 @@
   p.foo = 0;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        _import_a.topSet('foo'),
-        isLegacy: true,
-      ),
-      writeType: 'int*',
-      operatorElement: null,
-      type: 'int*',
-    );
+
+    var assignment = findNode.assignment('foo =');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: p
+      staticElement: self::@prefix::p
+      staticType: null
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: package:test/a.dart::@setter::foo
+    isLegacy: true
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
   }
 
   test_assignment_propertyAccess_class_field() async {
@@ -205,18 +306,45 @@
   A().foo = 0;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        _import_a.setter('foo'),
-        isLegacy: true,
-      ),
-      writeType: 'int*',
-      operatorElement: null,
-      type: 'int*',
-    );
+
+    var assignment = findNode.assignment('foo =');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: InstanceCreationExpression
+      constructorName: ConstructorName
+        type: NamedType
+          name: SimpleIdentifier
+            token: A
+            staticElement: package:test/a.dart::@class::A
+            staticType: null
+          type: A*
+        staticElement: ConstructorMember
+          base: package:test/a.dart::@class::A::@constructor::•
+          isLegacy: true
+      argumentList: ArgumentList
+        leftParenthesis: (
+        rightParenthesis: )
+      staticType: A*
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: package:test/a.dart::@class::A::@setter::foo
+    isLegacy: true
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
   }
 
   test_assignment_propertyAccess_extension_setter() async {
@@ -234,18 +362,45 @@
   A().foo = 0;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        _import_a.setter('foo'),
-        isLegacy: true,
-      ),
-      writeType: 'int*',
-      operatorElement: null,
-      type: 'int*',
-    );
+
+    var assignment = findNode.assignment('foo =');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: InstanceCreationExpression
+      constructorName: ConstructorName
+        type: NamedType
+          name: SimpleIdentifier
+            token: A
+            staticElement: package:test/a.dart::@class::A
+            staticType: null
+          type: A*
+        staticElement: ConstructorMember
+          base: package:test/a.dart::@class::A::@constructor::•
+          isLegacy: true
+      argumentList: ArgumentList
+        leftParenthesis: (
+        rightParenthesis: )
+      staticType: A*
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: package:test/a.dart::@extension::E::@setter::foo
+    isLegacy: true
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
   }
 
   test_assignment_propertyAccess_extensionOverride_setter() async {
@@ -263,18 +418,45 @@
   E(a).foo = 0;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        _import_a.setter('foo'),
-        isLegacy: true,
-      ),
-      writeType: 'int*',
-      operatorElement: null,
-      type: 'int*',
-    );
+
+    var assignment = findNode.assignment('foo =');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: ExtensionOverride
+      extensionName: SimpleIdentifier
+        token: E
+        staticElement: package:test/a.dart::@extension::E
+        staticType: null
+      argumentList: ArgumentList
+        leftParenthesis: (
+        arguments
+          SimpleIdentifier
+            token: a
+            staticElement: a@40
+            staticType: A*
+        rightParenthesis: )
+      extendedType: A
+      staticType: null
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: package:test/a.dart::@extension::E::@setter::foo
+    isLegacy: true
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
   }
 
   test_assignment_propertyAccess_superTarget() async {
@@ -293,18 +475,33 @@
   }
 }
 ''');
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        _import_a.setter('foo'),
-        isLegacy: true,
-      ),
-      writeType: 'int*',
-      operatorElement: null,
-      type: 'int*',
-    );
+
+    var assignment = findNode.assignment('foo =');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: SuperExpression
+      superKeyword: super
+      staticType: B*
+    operator: .
+    propertyName: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int*
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: package:test/a.dart::@class::A::@setter::foo
+    isLegacy: true
+  writeType: int*
+  staticElement: <null>
+  staticType: int*
+''');
   }
 
   test_assignment_simpleIdentifier_topLevelVariable() async {
@@ -319,18 +516,27 @@
   foo = null;
 }
 ''');
-    assertAssignment(
-      findNode.assignment('foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: elementMatcher(
-        _import_a.topSet('foo'),
-        isLegacy: true,
-      ),
-      writeType: 'int*',
-      operatorElement: null,
-      type: 'Null*',
-    );
+
+    var assignment = findNode.assignment('foo =');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: foo
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: NullLiteral
+    literal: null
+    staticType: Null*
+  readElement: <null>
+  readType: null
+  writeElement: PropertyAccessorMember
+    base: package:test/a.dart::@setter::foo
+    isLegacy: true
+  writeType: int*
+  staticElement: <null>
+  staticType: Null*
+''');
   }
 
   test_binaryExpression() async {
diff --git a/pkg/analyzer/test/src/diagnostics/private_setter_test.dart b/pkg/analyzer/test/src/diagnostics/private_setter_test.dart
index 37cce24..e0163e8 100644
--- a/pkg/analyzer/test/src/diagnostics/private_setter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/private_setter_test.dart
@@ -31,17 +31,32 @@
       error(CompileTimeErrorCode.PRIVATE_SETTER, 31, 4),
     ]);
 
-    var aImport = findElement.importFind('package:test/a.dart');
-
-    assertAssignment(
-      findNode.assignment('_foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: aImport.setter('_foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('_foo =');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: A
+      staticElement: package:test/a.dart::@class::A
+      staticType: null
+    period: .
+    identifier: SimpleIdentifier
+      token: _foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: package:test/a.dart::@class::A::@setter::_foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_typeLiteral_privateField_sameLibrary() async {
@@ -75,17 +90,32 @@
       error(CompileTimeErrorCode.PRIVATE_SETTER, 31, 4),
     ]);
 
-    var aImport = findElement.importFind('package:test/a.dart');
-
-    assertAssignment(
-      findNode.assignment('_foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: aImport.setter('_foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('_foo =');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: A
+      staticElement: package:test/a.dart::@class::A
+      staticType: null
+    period: .
+    identifier: SimpleIdentifier
+      token: _foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: package:test/a.dart::@class::A::@setter::_foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_typeLiteral_privateSetter_differentLibrary_noGetter() async {
@@ -104,17 +134,32 @@
       error(CompileTimeErrorCode.PRIVATE_SETTER, 31, 4),
     ]);
 
-    var aImport = findElement.importFind('package:test/a.dart');
-
-    assertAssignment(
-      findNode.assignment('_foo ='),
-      readElement: null,
-      readType: null,
-      writeElement: aImport.setter('_foo'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('_foo =');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: A
+      staticElement: package:test/a.dart::@class::A
+      staticType: null
+    period: .
+    identifier: SimpleIdentifier
+      token: _foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: package:test/a.dart::@class::A::@setter::_foo
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_typeLiteral_privateSetter_sameLibrary() async {
diff --git a/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart b/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
index b751b98..1785fe3 100644
--- a/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
@@ -232,17 +232,40 @@
       error(HintCode.DEAD_CODE, 22, 12),
     ]);
 
-    assertAssignment(
-      findNode.assignment('[0] +='),
-      readElement: null,
-      readType: 'dynamic',
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'dynamic',
-    );
-
-    assertType(findNode.binary('1 + 2'), 'int');
+    var assignment = findNode.assignment('[0] +=');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: x
+      staticElement: x@13
+      staticType: Never
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: BinaryExpression
+    leftOperand: IntegerLiteral
+      literal: 1
+      staticType: int
+    operator: +
+    rightOperand: IntegerLiteral
+      literal: 2
+      staticType: int
+    staticElement: dart:core::@class::num::@method::+
+    staticInvokeType: num Function(num)
+    staticType: int
+  readElement: <null>
+  readType: dynamic
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: dynamic
+''');
   }
 
   test_indexExpression_never_write() async {
@@ -326,17 +349,40 @@
           22, 1),
     ]);
 
-    assertAssignment(
-      findNode.assignment('[0] +='),
-      readElement: null,
-      readType: 'dynamic',
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'dynamic',
-    );
-
-    assertType(findNode.binary('1 + 2'), 'int');
+    var assignment = findNode.assignment('[0] +=');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: IndexExpression
+    target: SimpleIdentifier
+      token: x
+      staticElement: x@14
+      staticType: Never?
+    leftBracket: [
+    index: IntegerLiteral
+      literal: 0
+      staticType: int
+    rightBracket: ]
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: BinaryExpression
+    leftOperand: IntegerLiteral
+      literal: 1
+      staticType: int
+    operator: +
+    rightOperand: IntegerLiteral
+      literal: 2
+      staticType: int
+    staticElement: dart:core::@class::num::@method::+
+    staticInvokeType: num Function(num)
+    staticType: int
+  readElement: <null>
+  readType: dynamic
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: dynamic
+''');
   }
 
   test_indexExpression_neverQ_write() async {
@@ -661,15 +707,32 @@
       findNode.simple('foo'),
     );
 
-    assertAssignment(
-      findNode.assignment('foo += 0'),
-      readElement: null,
-      readType: 'dynamic',
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'dynamic',
-    );
+    var assignment = findNode.assignment('foo += 0');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: x
+      staticElement: x@13
+      staticType: Never
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: dynamic
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: dynamic
+''');
   }
 
   test_propertyAccess_never_tearOff_toString() async {
@@ -699,15 +762,32 @@
       findNode.simple('foo'),
     );
 
-    assertAssignment(
-      findNode.assignment('foo = 0'),
-      readElement: null,
-      readType: null,
-      writeElement: null,
-      writeType: 'dynamic',
-      operatorElement: null,
-      type: 'int',
-    );
+    var assignment = findNode.assignment('foo = 0');
+    assertResolvedNodeText(assignment, r'''
+AssignmentExpression
+  leftHandSide: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: x
+      staticElement: x@13
+      staticType: Never
+    period: .
+    identifier: SimpleIdentifier
+      token: foo
+      staticElement: <null>
+      staticType: null
+    staticElement: <null>
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: <null>
+  writeType: dynamic
+  staticElement: <null>
+  staticType: int
+''');
   }
 
   test_propertyAccess_neverQ_read() async {
diff --git a/pkg/analyzer/test/src/diagnostics/use_of_nullable_value_test.dart b/pkg/analyzer/test/src/diagnostics/use_of_nullable_value_test.dart
index 3ef5688..eab579e 100644
--- a/pkg/analyzer/test/src/diagnostics/use_of_nullable_value_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/use_of_nullable_value_test.dart
@@ -411,25 +411,79 @@
           contextMessages: [message('/home/test/lib/test.dart', 56, 1)]),
     ]);
 
-    assertAssignment(
-      findNode.assignment('x = 1'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('x'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int?',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(findNode.assignment('x = 1'), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: PrefixedIdentifier
+      prefix: SimpleIdentifier
+        token: b
+        staticElement: b@79
+        staticType: B
+      period: .
+      identifier: SimpleIdentifier
+        token: a
+        staticElement: self::@class::B::@getter::a
+        staticType: A?
+      staticElement: self::@class::B::@getter::a
+      staticType: A?
+    operator: ?.
+    propertyName: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::x
+  writeType: int
+  staticElement: <null>
+  staticType: int?
+''');
+    } else {
+      assertResolvedNodeText(findNode.assignment('x = 1'), r'''''');
+    }
 
-    assertAssignment(
-      findNode.assignment('x = 2'),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.setter('x'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(findNode.assignment('x = 2'), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: PrefixedIdentifier
+      prefix: SimpleIdentifier
+        token: b
+        staticElement: b@79
+        staticType: B
+      period: .
+      identifier: SimpleIdentifier
+        token: a
+        staticElement: self::@class::B::@getter::a
+        staticType: A?
+      staticElement: self::@class::B::@getter::a
+      staticType: A?
+    operator: .
+    propertyName: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: self::@class::A::@setter::x
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(findNode.assignment('x = 2'), r'''''');
+    }
   }
 
   test_assignment_eq_simpleIdentifier() async {
@@ -440,25 +494,49 @@
 }
 ''');
 
-    assertAssignment(
-      findNode.assignment('x ='),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.parameter('x'),
-      writeType: 'int',
-      operatorElement: null,
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(findNode.assignment('x ='), r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: x@6
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: x@6
+  writeType: int
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(findNode.assignment('x ='), r'''''');
+    }
 
-    assertAssignment(
-      findNode.assignment('y ='),
-      readElement: null,
-      readType: null,
-      writeElement: findElement.parameter('y'),
-      writeType: 'int?',
-      operatorElement: null,
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(findNode.assignment('y ='), r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: y
+    staticElement: y@14
+    staticType: null
+  operator: =
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: <null>
+  readType: null
+  writeElement: y@14
+  writeType: int?
+  staticElement: <null>
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(findNode.assignment('y ='), r'''''');
+    }
   }
 
   test_assignment_plusEq_propertyAccess3() async {
@@ -483,31 +561,79 @@
           115, 2),
     ]);
 
-    assertAssignment(
-      findNode.assignment('x +='),
-      readElement: findElement.getter('x'),
-      readType: 'int',
-      writeElement: findElement.setter('x'),
-      writeType: 'int',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(findNode.assignment('x +='), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: PrefixedIdentifier
+      prefix: SimpleIdentifier
+        token: b
+        staticElement: b@88
+        staticType: B
+      period: .
+      identifier: SimpleIdentifier
+        token: a
+        staticElement: self::@class::B::@getter::a
+        staticType: A
+      staticElement: self::@class::B::@getter::a
+      staticType: A
+    operator: .
+    propertyName: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: self::@class::A::@getter::x
+  readType: int
+  writeElement: self::@class::A::@setter::x
+  writeType: int
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(findNode.assignment('x +='), r'''''');
+    }
 
-    assertAssignment(
-      findNode.assignment('y +='),
-      readElement: findElement.getter('y'),
-      readType: 'int?',
-      writeElement: findElement.setter('y'),
-      writeType: 'int?',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(findNode.assignment('y +='), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: PrefixedIdentifier
+      prefix: SimpleIdentifier
+        token: b
+        staticElement: b@88
+        staticType: B
+      period: .
+      identifier: SimpleIdentifier
+        token: a
+        staticElement: self::@class::B::@getter::a
+        staticType: A
+      staticElement: self::@class::B::@getter::a
+      staticType: A
+    operator: .
+    propertyName: SimpleIdentifier
+      token: y
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: self::@class::A::@getter::y
+  readType: int?
+  writeElement: self::@class::A::@setter::y
+  writeType: int?
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(findNode.assignment('y +='), r'''''');
+    }
   }
 
   test_assignment_plusEq_propertyAccess3_short1() async {
@@ -532,31 +658,71 @@
           contextMessages: [message('/home/test/lib/test.dart', 56, 1)]),
     ]);
 
-    assertAssignment(
-      findNode.assignment('x += 1'),
-      readElement: findElement.getter('x'),
-      readType: 'int',
-      writeElement: findElement.setter('x'),
-      writeType: 'int',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int?',
-    );
+    assertResolvedNodeText(findNode.assignment('x += 1'), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: PrefixedIdentifier
+      prefix: SimpleIdentifier
+        token: b
+        staticElement: b@79
+        staticType: B
+      period: .
+      identifier: SimpleIdentifier
+        token: a
+        staticElement: self::@class::B::@getter::a
+        staticType: A?
+      staticElement: self::@class::B::@getter::a
+      staticType: A?
+    operator: ?.
+    propertyName: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 1
+    staticType: int
+  readElement: self::@class::A::@getter::x
+  readType: int
+  writeElement: self::@class::A::@setter::x
+  writeType: int
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int?
+''');
 
-    assertAssignment(
-      findNode.assignment('x += 2'),
-      readElement: findElement.getter('x'),
-      readType: 'int',
-      writeElement: findElement.setter('x'),
-      writeType: 'int',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
+    assertResolvedNodeText(findNode.assignment('x += 2'), r'''
+AssignmentExpression
+  leftHandSide: PropertyAccess
+    target: PrefixedIdentifier
+      prefix: SimpleIdentifier
+        token: b
+        staticElement: b@79
+        staticType: B
+      period: .
+      identifier: SimpleIdentifier
+        token: a
+        staticElement: self::@class::B::@getter::a
+        staticType: A?
+      staticElement: self::@class::B::@getter::a
+      staticType: A?
+    operator: .
+    propertyName: SimpleIdentifier
+      token: x
+      staticElement: <null>
+      staticType: null
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 2
+    staticType: int
+  readElement: self::@class::A::@getter::x
+  readType: int
+  writeElement: self::@class::A::@setter::x
+  writeType: int
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
   }
 
   test_assignment_plusEq_simpleIdentifier() async {
@@ -570,31 +736,49 @@
           33, 2),
     ]);
 
-    assertAssignment(
-      findNode.assignment('x +='),
-      readElement: findElement.parameter('x'),
-      readType: 'int',
-      writeElement: findElement.parameter('x'),
-      writeType: 'int',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(findNode.assignment('x +='), r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: x
+    staticElement: x@6
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: x@6
+  readType: int
+  writeElement: x@6
+  writeType: int
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(findNode.assignment('x +='), r'''''');
+    }
 
-    assertAssignment(
-      findNode.assignment('y +='),
-      readElement: findElement.parameter('y'),
-      readType: 'int?',
-      writeElement: findElement.parameter('y'),
-      writeType: 'int?',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isLegacyLibrary,
-      ),
-      type: 'int',
-    );
+    if (isNullSafetyEnabled) {
+      assertResolvedNodeText(findNode.assignment('y +='), r'''
+AssignmentExpression
+  leftHandSide: SimpleIdentifier
+    token: y
+    staticElement: y@14
+    staticType: null
+  operator: +=
+  rightHandSide: IntegerLiteral
+    literal: 0
+    staticType: int
+  readElement: y@14
+  readType: int?
+  writeElement: y@14
+  writeType: int?
+  staticElement: dart:core::@class::num::@method::+
+  staticType: int
+''');
+    } else {
+      assertResolvedNodeText(findNode.assignment('y +='), r'''''');
+    }
   }
 
   test_await_nonNullable() async {
diff --git a/tools/VERSION b/tools/VERSION
index 92cff59..cb08dfb 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 74
+PRERELEASE 75
 PRERELEASE_PATCH 0
\ No newline at end of file