Version 2.17.0-270.0.dev

Merge commit '55a99e10c0fbecc4f1d5556cc9780b6c25f4cf23' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_function_declaration.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_function_declaration.dart
new file mode 100644
index 0000000..63cea99
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_function_declaration.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/source/source_range.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
+
+class ConvertToFunctionDeclaration extends CorrectionProducer {
+  @override
+  bool get canBeAppliedInBulk => true;
+
+  @override
+  bool get canBeAppliedToFile => true;
+
+  @override
+  FixKind get fixKind => DartFixKind.CONVERT_TO_FUNCTION_DECLARATION;
+
+  @override
+  FixKind get multiFixKind => DartFixKind.CONVERT_TO_FUNCTION_DECLARATION_MULTI;
+
+  @override
+  Future<void> compute(ChangeBuilder builder) async {
+    var node = this.node;
+    if (node is! VariableDeclaration) return;
+    var equals = node.equals;
+    if (equals == null) return;
+    var initializer = node.initializer;
+
+    var parent = node.parent;
+    if (parent is! VariableDeclarationList) return;
+    var keyword = parent.keyword;
+    var type = parent.type;
+
+    var variables = parent.variables;
+
+    var grandParent = parent.parent;
+    if (grandParent is! VariableDeclarationStatement) return;
+
+    var previous = _previous(variables, node);
+    var next = _next(variables, node);
+
+    await builder.addDartFileEdit(file, (builder) {
+      void replaceWithNewLine(SourceRange range,
+          {String? before, String? after}) {
+        builder.addReplacement(range, (builder) {
+          if (before != null) {
+            builder.write(before);
+          }
+          builder.write(utils.endOfLine);
+          builder.write(utils.getLinePrefix(range.offset));
+          if (after != null) {
+            builder.write(after);
+          }
+        });
+      }
+
+      if (previous == null) {
+        if (keyword != null) {
+          builder.addDeletion(range.startStart(keyword, keyword.next!));
+        }
+        if (type != null) {
+          builder.addDeletion(range.startStart(type, type.endToken.next!));
+        }
+      } else if (previous.initializer is! FunctionExpression) {
+        var r =
+            range.endStart(previous.endToken, previous.endToken.next!.next!);
+        replaceWithNewLine(r, before: ';');
+      }
+
+      builder.addDeletion(range.endStart(equals.previous!, equals.next!));
+
+      if (next != null) {
+        var r = range.endStart(node.endToken, node.endToken.next!.next!);
+        if (next.initializer is FunctionExpression) {
+          replaceWithNewLine(r);
+        } else {
+          var replacement = '';
+          if (keyword != null) {
+            replacement += '$keyword ';
+          }
+          if (type != null) {
+            replacement += utils.getNodeText(type) + ' ';
+          }
+          replaceWithNewLine(r, after: replacement);
+        }
+      } else if (initializer is FunctionExpression &&
+          initializer.body is BlockFunctionBody) {
+        builder.addDeletion(range.token(grandParent.semicolon));
+      }
+    });
+  }
+
+  VariableDeclaration? _next(
+      NodeList<VariableDeclaration> variables, VariableDeclaration variable) {
+    var i = variables.indexOf(variable);
+    return i < variables.length - 1 ? variables[i + 1] : null;
+  }
+
+  VariableDeclaration? _previous(
+      NodeList<VariableDeclaration> variables, VariableDeclaration variable) {
+    var i = variables.indexOf(variable);
+    return i > 0 ? variables[i - 1] : null;
+  }
+
+  /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
+  static ConvertToFunctionDeclaration newInstance() =>
+      ConvertToFunctionDeclaration();
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
index d2f7ccd..a83ddc1 100644
--- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
+++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
@@ -1741,7 +1741,7 @@
 LintCode.prefer_foreach:
   status: needsEvaluation
 LintCode.prefer_function_declarations_over_variables:
-  status: needsEvaluation
+  status: hasFix
 LintCode.prefer_generic_function_type_aliases:
   status: hasFix
 LintCode.prefer_if_elements_to_conditional_expressions:
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 4f359ad..0a1eee9 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -408,6 +408,16 @@
     DartFixKindPriority.IN_FILE,
     "Convert to 'Function' syntax everywhere in file",
   );
+  static const CONVERT_TO_FUNCTION_DECLARATION = FixKind(
+    'dart.fix.convert.toFunctionDeclaration',
+    DartFixKindPriority.DEFAULT,
+    'Convert to function declaration',
+  );
+  static const CONVERT_TO_FUNCTION_DECLARATION_MULTI = FixKind(
+    'dart.fix.convert.toFunctionDeclaration.multi',
+    DartFixKindPriority.IN_FILE,
+    'Convert to function declaration everywhere in file',
+  );
   static const CONVERT_TO_IF_ELEMENT = FixKind(
     'dart.fix.convert.toIfElement',
     DartFixKindPriority.DEFAULT,
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index f70b314..33d338e 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -52,6 +52,7 @@
 import 'package:analysis_server/src/services/correction/dart/convert_to_cascade.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_contains.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_expression_function_body.dart';
+import 'package:analysis_server/src/services/correction/dart/convert_to_function_declaration.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_generic_function_syntax.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_if_null.dart';
 import 'package:analysis_server/src/services/correction/dart/convert_to_initializing_formal.dart';
@@ -531,6 +532,9 @@
     LintNames.prefer_for_elements_to_map_fromIterable: [
       ConvertMapFromIterableToForLiteral.newInstance,
     ],
+    LintNames.prefer_function_declarations_over_variables: [
+      ConvertToFunctionDeclaration.newInstance,
+    ],
     LintNames.prefer_generic_function_type_aliases: [
       ConvertToGenericFunctionSyntax.newInstance,
     ],
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
index fe9d319..996a7c2 100644
--- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -91,6 +91,8 @@
   static const String prefer_final_in_for_each = 'prefer_final_in_for_each';
   static const String prefer_final_locals = 'prefer_final_locals';
   static const String prefer_final_parameters = 'prefer_final_parameters';
+  static const String prefer_function_declarations_over_variables =
+      'prefer_function_declarations_over_variables';
   static const String prefer_for_elements_to_map_fromIterable =
       'prefer_for_elements_to_map_fromIterable';
   static const String prefer_generic_function_type_aliases =
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_function_declaration_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_function_declaration_test.dart
new file mode 100644
index 0000000..98b3421
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_function_declaration_test.dart
@@ -0,0 +1,185 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test/expect.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConvertToFunctionDeclarationBulkTest);
+    defineReflectiveTests(ConvertToFunctionDeclarationInFileTest);
+    defineReflectiveTests(ConvertToFunctionDeclarationTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToFunctionDeclarationBulkTest extends BulkFixProcessorTest {
+  @override
+  String get lintCode => LintNames.prefer_function_declarations_over_variables;
+
+  Future<void> test_bulk() async {
+    await resolveTestCode('''
+void f() {
+  var v1 = () {};
+  var v2 = () {};
+  v1();
+  v2();
+}
+''');
+    await assertHasFix('''
+void f() {
+  v1() {}
+  v2() {}
+  v1();
+  v2();
+}
+''');
+  }
+
+  Future<void> test_declaration_list() async {
+    await resolveTestCode('''
+void f() {
+  var v1 = () {}, v2 = () {};
+  v1();
+  v2();
+}
+''');
+    await assertHasFix('''
+void f() {
+  v1() {}
+  v2() {}
+  v1();
+  v2();
+}
+''');
+  }
+}
+
+@reflectiveTest
+class ConvertToFunctionDeclarationInFileTest extends FixInFileProcessorTest {
+  Future<void> test_file() async {
+    createAnalysisOptionsFile(
+        lints: [LintNames.prefer_function_declarations_over_variables]);
+    await resolveTestCode('''
+void f() {
+  var v = () {
+    var v = () {};
+    v();
+  };
+  v();
+}
+''');
+    var fixes = await getFixesForFirstError();
+    expect(fixes, hasLength(1));
+    assertProduces(fixes.first, '''
+void f() {
+  v() {
+    v() {}
+    v();
+  }
+  v();
+}
+''');
+  }
+}
+
+@reflectiveTest
+class ConvertToFunctionDeclarationTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_TO_FUNCTION_DECLARATION;
+
+  @override
+  String get lintCode => LintNames.prefer_function_declarations_over_variables;
+
+  Future<void> test_block_function_body() async {
+    await resolveTestCode('''
+void f() {
+  var v = () {};
+  v();
+}
+''');
+    await assertHasFix('''
+void f() {
+  v() {}
+  v();
+}
+''');
+  }
+
+  Future<void> test_declaration_different() async {
+    await resolveTestCode('''
+void f() {
+  final v1 = 1, v2 = (x, y) {}, v3 = '';
+  v2(v1, v3);
+}
+''');
+    await assertHasFix('''
+void f() {
+  final v1 = 1;
+  v2(x, y) {}
+  final v3 = '';
+  v2(v1, v3);
+}
+''');
+  }
+
+  Future<void> test_expression_function_body() async {
+    await resolveTestCode('''
+void f() {
+  var v = () => 3;
+  v();
+}
+''');
+    await assertHasFix('''
+void f() {
+  v() => 3;
+  v();
+}
+''');
+  }
+
+  Future<void> test_no_initializer() async {
+    await resolveTestCode('''
+typedef F = void Function();
+
+void f() {
+  final F g = () {}, h;
+  g();
+  h = () {};
+  h();
+}
+''');
+    await assertHasFix('''
+typedef F = void Function();
+
+void f() {
+  g() {}
+  final F h;
+  g();
+  h = () {};
+  h();
+}
+''');
+  }
+
+  Future<void> test_type() async {
+    await resolveTestCode('''
+void f() {
+  final String Function() v = () => throw '';
+  v();
+}
+''');
+    await assertHasFix('''
+void f() {
+  v() => throw '';
+  v();
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index 4f1543a..d2b42a9 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -63,6 +63,8 @@
 import 'convert_to_double_quoted_string_test.dart'
     as convert_to_double_quoted_string;
 import 'convert_to_for_element_test.dart' as convert_to_for_element;
+import 'convert_to_function_declaration_test.dart'
+    as convert_to_function_declaration;
 import 'convert_to_generic_function_syntax_test.dart'
     as convert_to_generic_function_syntax;
 import 'convert_to_if_element_test.dart' as convert_to_if_element;
@@ -279,6 +281,7 @@
     convert_to_contains.main();
     convert_to_double_quoted_string.main();
     convert_to_for_element.main();
+    convert_to_function_declaration.main();
     convert_to_generic_function_syntax.main();
     convert_to_if_element.main();
     convert_to_if_null.main();
diff --git a/pkg/analyzer/lib/src/workspace/bazel.dart b/pkg/analyzer/lib/src/workspace/bazel.dart
index 6da9eb6..f21475c 100644
--- a/pkg/analyzer/lib/src/workspace/bazel.dart
+++ b/pkg/analyzer/lib/src/workspace/bazel.dart
@@ -25,6 +25,23 @@
   BazelFileUriResolver(this.workspace) : super(workspace.provider);
 
   @override
+  Uri pathToUri(String path) {
+    var pathContext = workspace.provider.pathContext;
+    for (var genRoot in [
+      ...workspace.binPaths,
+      workspace.genfiles,
+      workspace.readonly,
+    ]) {
+      if (genRoot != null && pathContext.isWithin(genRoot, path)) {
+        String relative = pathContext.relative(path, from: genRoot);
+        var writablePath = pathContext.join(workspace.root, relative);
+        return pathContext.toUri(writablePath);
+      }
+    }
+    return workspace.provider.pathContext.toUri(path);
+  }
+
+  @override
   Source? resolveAbsolute(Uri uri) {
     if (!ResourceUriResolver.isFileUri(uri)) {
       return null;
diff --git a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
index 5326c4c..7561099 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -53,14 +53,16 @@
 
     var fsState = analysisDriver.fsState;
 
-    // The file is the generated file.
+    // Prepare URI(s).
     var generatedUri = toUri(generatedPath);
+    var writableUri = toUri(writablePath);
+
+    // The file is the generated file.
     var generatedFile = fsState.getFileForUri(generatedUri).t1!;
-    expect(generatedFile.uri, generatedUri);
+    expect(generatedFile.uri, writableUri);
     expect(generatedFile.path, generatedPath);
 
     // The file is cached under the requested URI.
-    var writableUri = toUri(writablePath);
     var writableFile1 = fsState.getFileForUri(writableUri).t1!;
     var writableFile2 = fsState.getFileForUri(writableUri).t1!;
     expect(writableFile1, same(generatedFile));
@@ -79,16 +81,18 @@
 
     var fsState = analysisDriver.fsState;
 
-    // The file is cached under the requested URI.
+    // Prepare URI(s).
+    var generatedUri = toUri(generatedPath);
     var writableUri = toUri(writablePath);
+
+    // The file is cached under the requested URI.
     var writableFile1 = fsState.getFileForUri(writableUri).t1!;
     var writableFile2 = fsState.getFileForUri(writableUri).t1!;
     expect(writableFile2, same(writableFile1));
 
     // The file is the generated file.
-    var generatedUri = toUri(generatedPath);
     var generatedFile = fsState.getFileForUri(generatedUri).t1!;
-    expect(generatedFile.uri, generatedUri);
+    expect(generatedFile.uri, writableUri);
     expect(generatedFile.path, generatedPath);
     expect(writableFile2, same(generatedFile));
   }
diff --git a/pkg/analyzer/test/src/workspace/bazel_test.dart b/pkg/analyzer/test/src/workspace/bazel_test.dart
index 7c01cc1..474d1e5 100644
--- a/pkg/analyzer/test/src/workspace/bazel_test.dart
+++ b/pkg/analyzer/test/src/workspace/bazel_test.dart
@@ -2,6 +2,7 @@
 // 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/file_system/file_system.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
@@ -26,67 +27,133 @@
   late final BazelWorkspace workspace;
   late final BazelFileUriResolver resolver;
 
-  void setUp() {
-    newFile2('/workspace/WORKSPACE', '');
-    newFolder('/workspace/bazel-genfiles');
-    workspace =
-        BazelWorkspace.find(resourceProvider, convertPath('/workspace'))!;
-    resolver = BazelFileUriResolver(workspace);
-    newFile2('/workspace/test.dart', '');
-    newFile2('/workspace/bazel-bin/gen1.dart', '');
-    newFile2('/workspace/bazel-genfiles/gen2.dart', '');
-    expect(workspace.isBazel, isTrue);
-  }
-
-  void test_pathToUri() {
-    Uri uri = toUri('/workspace/test.dart');
-    var source = resolver.resolveAbsolute(uri)!;
-    expect(resolver.pathToUri(source.fullName), uri);
-  }
-
-  void test_resolveAbsolute_doesNotExist() {
-    var source = _resolvePath('/workspace/foo.dart')!;
-    expect(source.exists(), isFalse);
-    expect(source.fullName, convertPath('/workspace/foo.dart'));
-  }
-
-  void test_resolveAbsolute_file() {
-    var source = _resolvePath('/workspace/test.dart')!;
-    expect(source.exists(), isTrue);
-    expect(source.fullName, convertPath('/workspace/test.dart'));
-  }
-
-  void test_resolveAbsolute_folder() {
-    var source = _resolvePath('/workspace');
-    expect(source, isNull);
-  }
-
-  void test_resolveAbsolute_generated_file_exists_one() {
-    var source = _resolvePath('/workspace/gen1.dart')!;
-    expect(source.exists(), isTrue);
-    expect(source.fullName, convertPath('/workspace/bazel-bin/gen1.dart'));
-  }
-
-  void test_resolveAbsolute_generated_file_exists_two() {
-    var source = _resolvePath('/workspace/gen2.dart')!;
-    expect(source.exists(), isTrue);
-    expect(source.fullName, convertPath('/workspace/bazel-genfiles/gen2.dart'));
+  void test_resolveAbsolute_bazelBin_exists() {
+    _addResources([
+      '/workspace/WORKSPACE',
+      '/workspace/bazel-bin/my/test/a.dart',
+    ]);
+    _assertResolve(
+      toUriStr('/workspace/bazel-bin/my/test/a.dart'),
+      getFile('/workspace/bazel-bin/my/test/a.dart'),
+      restoredUriStr: toUriStr('/workspace/my/test/a.dart'),
+    );
   }
 
   void test_resolveAbsolute_notFile_dartUri() {
+    _addResources([
+      '/workspace/WORKSPACE',
+    ]);
     Uri uri = Uri(scheme: 'dart', path: 'core');
     var source = resolver.resolveAbsolute(uri);
     expect(source, isNull);
   }
 
   void test_resolveAbsolute_notFile_httpsUri() {
+    _addResources([
+      '/workspace/WORKSPACE',
+    ]);
     Uri uri = Uri(scheme: 'https', path: '127.0.0.1/test.dart');
     var source = resolver.resolveAbsolute(uri);
     expect(source, isNull);
   }
 
+  void test_resolveAbsolute_outsideOfWorkspace() {
+    _addResources([
+      '/workspace/WORKSPACE',
+    ]);
+    expect(
+      resolver.resolveAbsolute(
+        toUri('/foo'),
+      ),
+      isNull,
+    );
+  }
+
+  void test_resolveAbsolute_workspaceRoot() {
+    _addResources([
+      '/workspace/WORKSPACE',
+    ]);
+    expect(
+      resolver.resolveAbsolute(
+        toUri('/workspace'),
+      ),
+      isNull,
+    );
+  }
+
+  void test_resolveAbsolute_writableUri_bazelBin_hasWritable() {
+    _addResources([
+      '/workspace/WORKSPACE',
+      '/workspace/my/test/a.dart',
+      '/workspace/bazel-bin/my/test/a.dart',
+    ]);
+    _assertResolve(
+      toUriStr('/workspace/my/test/a.dart'),
+      getFile('/workspace/bazel-bin/my/test/a.dart'),
+    );
+  }
+
+  void test_resolveAbsolute_writableUri_bazelBin_noWritable() {
+    _addResources([
+      '/workspace/WORKSPACE',
+      '/workspace/bazel-bin/my/test/a.dart',
+    ]);
+    _assertResolve(
+      toUriStr('/workspace/my/test/a.dart'),
+      getFile('/workspace/bazel-bin/my/test/a.dart'),
+    );
+  }
+
+  void test_resolveAbsolute_writableUri_bazelGenfiles_hasWritable() {
+    _addResources([
+      '/workspace/WORKSPACE',
+      '/workspace/my/test/a.dart',
+      '/workspace/bazel-genfiles/my/test/a.dart',
+    ]);
+    _assertResolve(
+      toUriStr('/workspace/my/test/a.dart'),
+      getFile('/workspace/bazel-genfiles/my/test/a.dart'),
+    );
+  }
+
+  void test_resolveAbsolute_writableUri_bazelGenfiles_noWritable() {
+    _addResources([
+      '/workspace/WORKSPACE',
+      '/workspace/bazel-genfiles/my/test/a.dart',
+    ]);
+    _assertResolve(
+      toUriStr('/workspace/my/test/a.dart'),
+      getFile('/workspace/bazel-genfiles/my/test/a.dart'),
+    );
+  }
+
+  void test_resolveAbsolute_writableUri_writable() {
+    _addResources([
+      '/workspace/WORKSPACE',
+      '/workspace/my/lib/a.dart',
+    ]);
+    _assertResolve(
+      'file:///workspace/my/lib/a.dart',
+      getFile('/workspace/my/lib/a.dart'),
+    );
+  }
+
+  void test_resolveAbsolute_writableUri_writable_doesNotExist() {
+    _addResources([
+      '/workspace/WORKSPACE',
+    ]);
+    _assertResolve(
+      'file:///workspace/my/lib/a.dart',
+      getFile('/workspace/my/lib/a.dart'),
+      exists: false,
+    );
+  }
+
   @Deprecated('Use pathToUri() instead')
   void test_restoreAbsolute() {
+    _addResources([
+      '/workspace/WORKSPACE',
+    ]);
     Uri uri =
         resourceProvider.pathContext.toUri(convertPath('/workspace/test.dart'));
     var source = resolver.resolveAbsolute(uri)!;
@@ -97,10 +164,37 @@
         uri);
   }
 
-  Source? _resolvePath(String absolutePosixPath) {
-    String absolutePath = convertPath(absolutePosixPath);
-    Uri uri = resourceProvider.pathContext.toUri(absolutePath);
-    return resolver.resolveAbsolute(uri);
+  void _addResources(List<String> paths) {
+    for (String path in paths) {
+      if (path.endsWith('/')) {
+        newFolder(path.substring(0, path.length - 1));
+      } else {
+        newFile2(path, '');
+      }
+    }
+    workspace = BazelWorkspace.find(
+      resourceProvider,
+      getFolder('/workspace').path,
+    )!;
+    resolver = BazelFileUriResolver(workspace);
+  }
+
+  void _assertResolve(
+    String uriStr,
+    File file, {
+    bool exists = true,
+    String? restoredUriStr,
+  }) {
+    var uri = Uri.parse(uriStr);
+
+    var source = resolver.resolveAbsolute(uri)!;
+    var path = source.fullName;
+    expect(path, file.path);
+    expect(source.uri, uri);
+    expect(source.exists(), exists);
+
+    restoredUriStr ??= uriStr;
+    expect(resolver.pathToUri(path), Uri.parse(restoredUriStr));
   }
 }
 
diff --git a/samples/ffi/sqlite/pubspec.yaml b/samples/ffi/sqlite/pubspec.yaml
index 1effadc..90e67f4 100644
--- a/samples/ffi/sqlite/pubspec.yaml
+++ b/samples/ffi/sqlite/pubspec.yaml
@@ -6,6 +6,6 @@
 environment:
   sdk: '>=2.12.0-0 <3.0.0'
 dependencies:
-  ffi: ^0.3.1-nullsafety.0
+  ffi: ^1.1.2
 dev_dependencies:
   test: ^1.16.0-nullsafety.12
diff --git a/samples_2/ffi/sqlite/pubspec.yaml b/samples_2/ffi/sqlite/pubspec.yaml
index 16771df..762107f 100644
--- a/samples_2/ffi/sqlite/pubspec.yaml
+++ b/samples_2/ffi/sqlite/pubspec.yaml
@@ -6,6 +6,6 @@
 environment:
   sdk: '>=2.1.0 <3.0.0'
 dependencies:
-  ffi: ^0.3.1-nullsafety.0
+  ffi: ^1.1.2
 dev_dependencies:
   test: ^1.5.3
diff --git a/sdk/lib/_internal/js_runtime/lib/js_array.dart b/sdk/lib/_internal/js_runtime/lib/js_array.dart
index dde10ed..1f4ed72 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_array.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_array.dart
@@ -303,8 +303,14 @@
     }
   }
 
+  @pragma('dart2js:noInline')
   void clear() {
-    length = 0;
+    checkGrowable('clear');
+    _clear();
+  }
+
+  void _clear() {
+    _setLengthUnsafe(0);
   }
 
   void forEach(void f(E element)) {
diff --git a/tools/VERSION b/tools/VERSION
index 1e186b4..812e398 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 269
+PRERELEASE 270
 PRERELEASE_PATCH 0
\ No newline at end of file