Version 2.15.0-293.0.dev

Merge commit '217367abd1b674e425cdf9333f2d3aefa891f5b5' into 'dev'
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index d4f174f..f695939 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -21,6 +21,7 @@
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
 import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
 import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
+import 'package:analyzer_utilities/check/check.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -1599,7 +1600,7 @@
 
   RequestWithFutureResponse _sendTestCompletionRequest(String id, int offset) {
     var request = CompletionGetSuggestions2Params(
-      testFilePath,
+      testFilePathPlatform,
       0,
       1 << 10,
     ).toRequest(id);
@@ -2794,7 +2795,7 @@
   }
 
   void assertEmpty() {
-    expect(suggestions, isEmpty);
+    check(suggestions).isEmpty;
   }
 
   void assertLength(Object matcher) {
diff --git a/pkg/analyzer_utilities/lib/check/bool.dart b/pkg/analyzer_utilities/lib/check/bool.dart
new file mode 100644
index 0000000..18d5054
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/bool.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check.dart';
+
+extension BoolExtension on CheckTarget<bool> {
+  void get isTrue {
+    if (!value) {
+      fail('is not true');
+    }
+  }
+
+  void get isFalse {
+    if (value) {
+      fail('is not false');
+    }
+  }
+}
diff --git a/pkg/analyzer_utilities/lib/check/check.dart b/pkg/analyzer_utilities/lib/check/check.dart
new file mode 100644
index 0000000..8d3cc4d
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/check.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check_target.dart';
+import 'package:meta/meta.dart';
+
+export 'package:analyzer_utilities/check/check_target.dart';
+export 'package:analyzer_utilities/check/equality.dart';
+export 'package:analyzer_utilities/check/int.dart';
+export 'package:analyzer_utilities/check/iterable.dart';
+export 'package:analyzer_utilities/check/string.dart';
+export 'package:analyzer_utilities/check/type.dart';
+
+@useResult
+CheckTarget<T> check<T>(T value) {
+  return CheckTarget(value, 0, () => '$value');
+}
diff --git a/pkg/analyzer_utilities/lib/check/check_target.dart b/pkg/analyzer_utilities/lib/check/check_target.dart
new file mode 100644
index 0000000..1d0e608
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/check_target.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test/test.dart' as test_package;
+
+class CheckTarget<T> {
+  final T value;
+  final int _depth;
+
+  /// The function that return the description of the value, and of the
+  /// chain how we arrived to this value.
+  final String Function() _describe;
+
+  CheckTarget(this.value, this._depth, this._describe);
+
+  String get _indent => '  ' * (_depth + 1);
+
+  String valueStr(value) {
+    if (value is String) {
+      return "'$value'";
+    }
+    return '$value';
+  }
+
+  Never fail(String message) {
+    test_package.fail(_describe() + '\n' + _indent + message);
+  }
+
+  /// Chains to the given [value]; if a subsequent check fails, [describe]
+  /// will be invoked to describe the [value].
+  CheckTarget<U> nest<U>(
+    U value,
+    String Function(U value) describe,
+  ) {
+    return CheckTarget(value, _depth + 1, () {
+      return _describe() + '\n' + _indent + describe(value);
+    });
+  }
+}
diff --git a/pkg/analyzer_utilities/lib/check/equality.dart b/pkg/analyzer_utilities/lib/check/equality.dart
new file mode 100644
index 0000000..2d265b8
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/equality.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check.dart';
+
+extension EqualityExtension<T> on CheckTarget<T> {
+  void isEqualTo(Object? other) {
+    if (value != other) {
+      fail('is not equal to $other');
+    }
+  }
+
+  void isNotEqualTo(Object? other) {
+    if (value == other) {
+      fail('is equal to $other');
+    }
+  }
+}
diff --git a/pkg/analyzer_utilities/lib/check/int.dart b/pkg/analyzer_utilities/lib/check/int.dart
new file mode 100644
index 0000000..59587b2
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/int.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check.dart';
+
+extension IntExtension on CheckTarget<int> {
+  void get isZero {
+    if (value != 0) {
+      fail('is not zero');
+    }
+  }
+
+  void isGreaterThan(int other) {
+    if (!(value > other)) {
+      fail('is not greater than $other');
+    }
+  }
+}
diff --git a/pkg/analyzer_utilities/lib/check/iterable.dart b/pkg/analyzer_utilities/lib/check/iterable.dart
new file mode 100644
index 0000000..fbadfd9
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/iterable.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check.dart';
+
+extension IterableExtension<T> on CheckTarget<Iterable<T>> {
+  void get isEmpty {
+    if (value.isNotEmpty) {
+      fail('is not empty');
+    }
+  }
+}
diff --git a/pkg/analyzer_utilities/lib/check/string.dart b/pkg/analyzer_utilities/lib/check/string.dart
new file mode 100644
index 0000000..c4dfdf7
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/string.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check.dart';
+import 'package:meta/meta.dart';
+
+extension StringExtension on CheckTarget<String> {
+  void contains(Pattern other) {
+    if (!value.contains(other)) {
+      fail('does not contain ${valueStr(other)}');
+    }
+  }
+
+  void startsWith(Pattern other) {
+    if (!value.startsWith(other)) {
+      fail('does not start with ${valueStr(other)}');
+    }
+  }
+
+  @useResult
+  CheckTarget<int> hasLength() {
+    return nest(
+      value.length,
+      (length) => 'has length $length',
+    );
+  }
+}
diff --git a/pkg/analyzer_utilities/lib/check/type.dart b/pkg/analyzer_utilities/lib/check/type.dart
new file mode 100644
index 0000000..ea28b9e
--- /dev/null
+++ b/pkg/analyzer_utilities/lib/check/type.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_utilities/check/check.dart';
+
+extension IsExtension<T> on CheckTarget<T> {
+  CheckTarget<U> isA<U extends T>() {
+    final value = this.value;
+    if (value is U) {
+      return nest(value, (_) => 'is of type $U');
+    } else {
+      fail('is not of type $U');
+    }
+  }
+}
diff --git a/pkg/analyzer_utilities/pubspec.yaml b/pkg/analyzer_utilities/pubspec.yaml
index a8426e4..d0aac18 100644
--- a/pkg/analyzer_utilities/pubspec.yaml
+++ b/pkg/analyzer_utilities/pubspec.yaml
@@ -9,5 +9,7 @@
   analyzer:
     path: ../analyzer
   html: any
+  meta:
+    path: ../meta
   path: any
   test: any
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 0a3a46e..1ae463a 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -23223,13 +23223,13 @@
   }
 
   /**
-   * Inserts all of the nodes into this node directly before refChild.
+   * Inserts all of the nodes into this node directly before child.
    *
    * See also:
    *
    * * [insertBefore]
    */
-  void insertAllBefore(Iterable<Node> newNodes, Node refChild) {
+  void insertAllBefore(Iterable<Node> newNodes, Node child) {
     if (newNodes is _ChildNodeListLazy) {
       _ChildNodeListLazy otherList = newNodes;
       if (identical(otherList._this, this)) {
@@ -23238,11 +23238,11 @@
 
       // Optimized route for copying between nodes.
       for (var i = 0, len = otherList.length; i < len; ++i) {
-        this.insertBefore(otherList._this.firstChild!, refChild);
+        this.insertBefore(otherList._this.firstChild!, child);
       }
     } else {
       for (var node in newNodes) {
-        this.insertBefore(node, refChild);
+        this.insertBefore(node, child);
       }
     }
   }
@@ -23525,7 +23525,9 @@
   bool hasChildNodes() native;
 
   /**
-   * Inserts all of the nodes into this node directly before refChild.
+   * Inserts the given node into this node directly before child.
+   * If child is `null`, then the given node is inserted at the end
+   * of this node's child nodes.
    *
    * ## Other resources
    *
diff --git a/tools/VERSION b/tools/VERSION
index 87e29e7..8738c13 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 292
+PRERELEASE 293
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/dom/docs/docs.json b/tools/dom/docs/docs.json
index 83d7a05..e1a453b 100644
--- a/tools/dom/docs/docs.json
+++ b/tools/dom/docs/docs.json
@@ -2504,7 +2504,9 @@
         ],
         "insertBefore": [
           "/**",
-          "   * Inserts all of the nodes into this node directly before refChild.",
+          "   * Inserts the given node into this node directly before child.",
+          "   * If child is `null`, then the given node is inserted at the end",
+          "   * of this node's child nodes.",
           "   *",
           "   * ## Other resources",
           "   *",
diff --git a/tools/dom/templates/html/impl/impl_Node.darttemplate b/tools/dom/templates/html/impl/impl_Node.darttemplate
index 23092f5..a411fd9 100644
--- a/tools/dom/templates/html/impl/impl_Node.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Node.darttemplate
@@ -220,13 +220,13 @@
   }
 
   /**
-   * Inserts all of the nodes into this node directly before refChild.
+   * Inserts all of the nodes into this node directly before child.
    *
    * See also:
    *
    * * [insertBefore]
    */
-  void insertAllBefore(Iterable<Node> newNodes, Node refChild) {
+  void insertAllBefore(Iterable<Node> newNodes, Node child) {
     if (newNodes is _ChildNodeListLazy) {
       _ChildNodeListLazy otherList = newNodes;
       if (identical(otherList._this, this)) {
@@ -235,11 +235,11 @@
 
       // Optimized route for copying between nodes.
       for (var i = 0, len = otherList.length; i < len; ++i) {
-        this.insertBefore(otherList._this.firstChild$NULLASSERT, refChild);
+        this.insertBefore(otherList._this.firstChild$NULLASSERT, child);
       }
     } else {
       for (var node in newNodes) {
-        this.insertBefore(node, refChild);
+        this.insertBefore(node, child);
       }
     }
   }