Version 2.15.0-249.0.dev

Merge commit '5eb9461a0357b7185c14b80c01c0b2fdcaf5c089' into 'dev'
diff --git a/pkg/analyzer/test/generated/test_support.dart b/pkg/analyzer/test/generated/test_support.dart
index 082c936..be7a535 100644
--- a/pkg/analyzer/test/generated/test_support.dart
+++ b/pkg/analyzer/test/generated/test_support.dart
@@ -59,9 +59,9 @@
   /// The message text of the error or `null` if the message should not be checked.
   final String? message;
 
-  /// A pattern that should be contained in the error message or `null` if the message
-  /// contents should not be checked.
-  final Pattern? messageContains;
+  /// A list of patterns that should be contained in the error message; empty if
+  /// the message contents should not be checked.
+  final List<Pattern> messageContains;
 
   /// The list of context messages that are expected to be associated with the
   /// error.
@@ -71,7 +71,7 @@
   ExpectedError(this.code, this.offset, this.length,
       {this.correctionContains,
       this.message,
-      this.messageContains,
+      this.messageContains = const [],
       this.expectedContextMessages = const <ExpectedContextMessage>[]});
 
   /// Return `true` if the [error] matches this description of what it's
@@ -85,9 +85,10 @@
     if (message != null && error.message != message) {
       return false;
     }
-    if (messageContains != null &&
-        error.message.contains(messageContains!) != true) {
-      return false;
+    for (var pattern in messageContains) {
+      if (!error.message.contains(pattern)) {
+        return false;
+      }
     }
     if (correctionContains != null &&
         !(error.correctionMessage ?? '').contains(correctionContains!)) {
@@ -191,9 +192,11 @@
           buffer.write(', message: ');
           buffer.write(json.encode(expected.message));
         }
-        if (expected.messageContains != null) {
+        if (expected.messageContains.isNotEmpty) {
           buffer.write(', messageContains: ');
-          buffer.write(json.encode(expected.messageContains.toString()));
+          buffer.write(json.encode([
+            for (var pattern in expected.messageContains) pattern.toString()
+          ]));
         }
         if (expected.correctionContains != null) {
           buffer.write(', correctionContains: ');
diff --git a/pkg/analyzer/test/src/dart/resolution/ast_rewrite_test.dart b/pkg/analyzer/test/src/dart/resolution/ast_rewrite_test.dart
index e300c65..1adb108 100644
--- a/pkg/analyzer/test/src/dart/resolution/ast_rewrite_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/ast_rewrite_test.dart
@@ -439,7 +439,7 @@
 ''', [
       error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR, 50,
           5,
-          messageContains: "The constructor 'prefix.A.named'"),
+          messageContains: ["The constructor 'prefix.A.named'"]),
     ]);
 
     var importFind = findElement.importFind('package:test/a.dart');
@@ -478,7 +478,7 @@
 ''', [
       error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR, 48,
           5,
-          messageContains: "The constructor 'prefix.A.new'"),
+          messageContains: ["The constructor 'prefix.A.new'"]),
     ]);
 
     var importFind = findElement.importFind('package:test/a.dart');
@@ -593,7 +593,7 @@
 ''', [
       error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR, 52,
           13,
-          messageContains: "The constructor 'A.named'"),
+          messageContains: ["The constructor 'A.named'"]),
     ]);
 
     var creation = findNode.instanceCreation('named<int, String>(0);');
@@ -631,7 +631,7 @@
 ''', [
       error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR, 48,
           13,
-          messageContains: "The constructor 'A.new'"),
+          messageContains: ["The constructor 'A.new'"]),
     ]);
 
     var creation = findNode.instanceCreation('new<int, String>(0);');
diff --git a/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart b/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart
index b9c66d7..48f946f 100644
--- a/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart
@@ -246,7 +246,7 @@
 ''', [
       error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR, 52,
           5,
-          messageContains: "The constructor 'A.foo'"),
+          messageContains: ["The constructor 'A.foo'"]),
     ]);
 
     var classElement = findElement.class_('A');
@@ -271,7 +271,7 @@
 ''', [
       error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR, 52,
           5,
-          messageContains: "The constructor 'A.new'"),
+          messageContains: ["The constructor 'A.new'"]),
     ]);
 
     var classElement = findElement.class_('A');
diff --git a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
index 92e8e49..2ccdb48 100644
--- a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
@@ -348,7 +348,7 @@
 ''', [
       error(HintCode.UNUSED_ELEMENT, 24, 3),
       error(CompileTimeErrorCode.UNDEFINED_METHOD, 36, 3,
-          messageContains: "for the type 'double'"),
+          messageContains: ["for the type 'double'"]),
     ]);
 
     assertFunctionReference(
@@ -936,7 +936,7 @@
 }
 ''', [
       error(CompileTimeErrorCode.UNDEFINED_METHOD, 24, 3,
-          messageContains: "for the type 'A'"),
+          messageContains: ["for the type 'A'"]),
     ]);
 
     assertFunctionReference(
diff --git a/pkg/analyzer/test/src/dart/resolution/instance_creation_test.dart b/pkg/analyzer/test/src/dart/resolution/instance_creation_test.dart
index c8245ec..63888b5 100644
--- a/pkg/analyzer/test/src/dart/resolution/instance_creation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/instance_creation_test.dart
@@ -175,7 +175,7 @@
 ''', [
       error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR, 53,
           5,
-          messageContains: "The constructor 'Foo.bar'"),
+          messageContains: ["The constructor 'Foo.bar'"]),
     ]);
 
     var creation = findNode.instanceCreation('Foo.bar<int>');
@@ -201,7 +201,7 @@
 ''', [
       error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR, 53,
           5,
-          messageContains: "The constructor 'Foo.new'"),
+          messageContains: ["The constructor 'Foo.new'"]),
     ]);
 
     var creation = findNode.instanceCreation('Foo.new<int>');
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index 6d89730..6f09001 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -858,7 +858,7 @@
   ExpectedError error(ErrorCode code, int offset, int length,
           {Pattern? correctionContains,
           String? text,
-          Pattern? messageContains,
+          List<Pattern> messageContains = const [],
           List<ExpectedContextMessage> contextMessages =
               const <ExpectedContextMessage>[]}) =>
       ExpectedError(code, offset, length,
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 4c7e2f7..79b9f6e 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
@@ -106,7 +106,7 @@
 }
 ''', [
       error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 129, 3,
-          messageContains: "in extension 'E1' and extension 'E2',"),
+          messageContains: ["in extension 'E1' and extension 'E2',"]),
     ]);
   }
 
@@ -131,7 +131,7 @@
 }
 ''', [
       error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 129, 3,
-          messageContains: "in extension 'E1' and extension 'E2',"),
+          messageContains: ["in extension 'E1' and extension 'E2',"]),
     ]);
   }
 
@@ -177,7 +177,7 @@
 }
 ''', [
       error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 129, 3,
-          messageContains: "in extension 'E1' and extension 'E2',"),
+          messageContains: ["in extension 'E1' and extension 'E2',"]),
     ]);
   }
 
@@ -192,8 +192,9 @@
 }
 ''', [
       error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 167, 3,
-          messageContains:
-              "in extension 'E1', extension 'E2', and extension 'E3',"),
+          messageContains: [
+            "in extension 'E1', extension 'E2', and extension 'E3',"
+          ]),
     ]);
   }
 
@@ -369,9 +370,10 @@
 int h(List<B> x) => x();
 ''', [
       error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 167, 1,
-          messageContains:
-              "in unnamed extension on 'List<A>' and unnamed extension on "
-              "'List<B>',"),
+          messageContains: [
+            "in unnamed extension on 'List<A>' and unnamed extension on "
+                "'List<B>',"
+          ]),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/analysis_options/analysis_options_test_support.dart b/pkg/analyzer/test/src/diagnostics/analysis_options/analysis_options_test_support.dart
index 30552bf..95e6ccb 100644
--- a/pkg/analyzer/test/src/diagnostics/analysis_options/analysis_options_test_support.dart
+++ b/pkg/analyzer/test/src/diagnostics/analysis_options/analysis_options_test_support.dart
@@ -21,7 +21,7 @@
   ExpectedError error(ErrorCode code, int offset, int length,
           {Pattern? correctionContains,
           String? text,
-          Pattern? messageContains,
+          List<Pattern> messageContains = const [],
           List<ExpectedContextMessage> contextMessages =
               const <ExpectedContextMessage>[]}) =>
       ExpectedError(code, offset, length,
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_of_do_not_store_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_of_do_not_store_test.dart
index 40ba01a..8ae77f0 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_of_do_not_store_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_of_do_not_store_test.dart
@@ -69,7 +69,7 @@
 }
 ''', [
       error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 106, 5,
-          messageContains: "'v'"),
+          messageContains: ["'v'"]),
     ]);
   }
 
@@ -223,7 +223,8 @@
   final f = '';
 }
 ''', [
-      error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 47, 5, messageContains: "'f'"),
+      error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 47, 5,
+          messageContains: ["'f'"]),
     ]);
   }
 
@@ -251,7 +252,8 @@
 @doNotStore
 String get v => '';
 ''', [
-      error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 47, 1, messageContains: "'v'"),
+      error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 47, 1,
+          messageContains: ["'v'"]),
     ]);
   }
 
@@ -266,7 +268,8 @@
   String v() => '';
 }
 ''', [
-      error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 47, 7, messageContains: "'v'"),
+      error(HintCode.ASSIGNMENT_OF_DO_NOT_STORE, 47, 7,
+          messageContains: ["'v'"]),
     ]);
   }
 
diff --git a/pkg/analyzer/test/src/diagnostics/deprecated_member_use_test.dart b/pkg/analyzer/test/src/diagnostics/deprecated_member_use_test.dart
index 97435e1..4c9a2d6 100644
--- a/pkg/analyzer/test/src/diagnostics/deprecated_member_use_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/deprecated_member_use_test.dart
@@ -205,7 +205,7 @@
 import 'package:aaa/a.dart';
 ''', [
       error(HintCode.DEPRECATED_MEMBER_USE, 24, 28,
-          messageContains: 'package:aaa/a.dart'),
+          messageContains: ['package:aaa/a.dart']),
     ]);
   }
 
diff --git a/pkg/analyzer/test/src/diagnostics/export_internal_library_test.dart b/pkg/analyzer/test/src/diagnostics/export_internal_library_test.dart
index c4eea53..3528d8f 100644
--- a/pkg/analyzer/test/src/diagnostics/export_internal_library_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/export_internal_library_test.dart
@@ -20,7 +20,7 @@
 export 'dart:_internal';
 ''', [
       error(CompileTimeErrorCode.EXPORT_INTERNAL_LIBRARY, 0, 24,
-          messageContains: "library 'dart:_internal' "),
+          messageContains: ["library 'dart:_internal' "]),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/export_of_non_library_test.dart b/pkg/analyzer/test/src/diagnostics/export_of_non_library_test.dart
index fc0bf97..d595b74 100644
--- a/pkg/analyzer/test/src/diagnostics/export_of_non_library_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/export_of_non_library_test.dart
@@ -24,7 +24,7 @@
 export 'lib1.dart';
 ''', [
       error(CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY, 18, 11,
-          messageContains: "library 'lib1.dart' "),
+          messageContains: ["library 'lib1.dart' "]),
     ]);
   }
 
diff --git a/pkg/analyzer/test/src/diagnostics/import_of_non_library_test.dart b/pkg/analyzer/test/src/diagnostics/import_of_non_library_test.dart
index d5ffe46..04c4fc3 100644
--- a/pkg/analyzer/test/src/diagnostics/import_of_non_library_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/import_of_non_library_test.dart
@@ -26,7 +26,7 @@
 var a = new p.A();
 ''', [
       error(CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY, 20, 11,
-          messageContains: "library 'lib1.dart' "),
+          messageContains: ["library 'lib1.dart' "]),
     ]);
   }
 
@@ -41,7 +41,7 @@
 A a = A();
 ''', [
       error(CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY, 20, 11,
-          messageContains: "library 'part.dart' "),
+          messageContains: ["library 'part.dart' "]),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_testing_member_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_testing_member_test.dart
index 2ef124c..530f0ae 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_testing_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_testing_member_test.dart
@@ -306,7 +306,7 @@
     ]);
     await _resolveFile('$testPackageRootPath/lib2.dart', [
       error(HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER, 40, 12,
-          messageContains: 'A.forTesting'),
+          messageContains: ['A.forTesting']),
     ]);
   }
 
diff --git a/pkg/analyzer/test/src/diagnostics/return_of_do_not_store_test.dart b/pkg/analyzer/test/src/diagnostics/return_of_do_not_store_test.dart
index cfbbbe3..bd97b34 100644
--- a/pkg/analyzer/test/src/diagnostics/return_of_do_not_store_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/return_of_do_not_store_test.dart
@@ -90,8 +90,9 @@
 @doNotStore
 String getV3() => v;
 ''', [
-      error(HintCode.RETURN_OF_DO_NOT_STORE, 87, 1, messageContains: 'getV'),
-      error(HintCode.RETURN_OF_DO_NOT_STORE, 111, 1, messageContains: 'getV2'),
+      error(HintCode.RETURN_OF_DO_NOT_STORE, 87, 1, messageContains: ['getV']),
+      error(HintCode.RETURN_OF_DO_NOT_STORE, 111, 1,
+          messageContains: ['getV2']),
     ]);
   }
 
@@ -111,8 +112,8 @@
 @doNotStore
 String get v3 => _v;
 ''', [
-      error(HintCode.RETURN_OF_DO_NOT_STORE, 87, 2, messageContains: 'v'),
-      error(HintCode.RETURN_OF_DO_NOT_STORE, 111, 2, messageContains: 'v2'),
+      error(HintCode.RETURN_OF_DO_NOT_STORE, 87, 2, messageContains: ['v']),
+      error(HintCode.RETURN_OF_DO_NOT_STORE, 111, 2, messageContains: ['v2']),
     ]);
   }
 
@@ -128,8 +129,8 @@
 
 String? get v => _v ?? _v2;
 ''', [
-      error(HintCode.RETURN_OF_DO_NOT_STORE, 112, 2, messageContains: '_v'),
-      error(HintCode.RETURN_OF_DO_NOT_STORE, 118, 3, messageContains: '_v2'),
+      error(HintCode.RETURN_OF_DO_NOT_STORE, 112, 2, messageContains: ['_v']),
+      error(HintCode.RETURN_OF_DO_NOT_STORE, 118, 3, messageContains: ['_v2']),
     ]);
   }
 
@@ -170,8 +171,9 @@
   String getV3() => _v;
 }
 ''', [
-      error(HintCode.RETURN_OF_DO_NOT_STORE, 106, 2, messageContains: 'getV'),
-      error(HintCode.RETURN_OF_DO_NOT_STORE, 135, 2, messageContains: 'getV2'),
+      error(HintCode.RETURN_OF_DO_NOT_STORE, 106, 2, messageContains: ['getV']),
+      error(HintCode.RETURN_OF_DO_NOT_STORE, 135, 2,
+          messageContains: ['getV2']),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/unused_result_test.dart b/pkg/analyzer/test/src/diagnostics/unused_result_test.dart
index 9d42982..4e18f96 100644
--- a/pkg/analyzer/test/src/diagnostics/unused_result_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unused_result_test.dart
@@ -549,7 +549,7 @@
 }
 ''', [
       error(HintCode.UNUSED_RESULT, 131, 2,
-          messageContains: "'m1' should be used."),
+          messageContains: ["'m1' should be used."]),
     ]);
   }
 
diff --git a/tools/VERSION b/tools/VERSION
index bb8c8f5..3483753 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 248
+PRERELEASE 249
 PRERELEASE_PATCH 0
\ No newline at end of file