Version 2.16.0-40.0.dev

Merge commit '6e857a62bc515048f2191f2411f38d00b690b6da' into 'dev'
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index a58388c..532447a 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -854,7 +854,7 @@
 
     FileState? file = _uriToFile[uri];
     if (file == null) {
-      Source? uriSource = _sourceFactory.resolveUri(null, uri.toString());
+      Source? uriSource = _sourceFactory.forUri2(uri);
 
       // If the URI cannot be resolved, for example because the factory
       // does not understand the scheme, return the unresolved file instance.
@@ -863,15 +863,22 @@
       }
 
       String path = uriSource.fullName;
+
+      // Check if already resolved to this path via different URI.
+      // That different URI must be the canonical one.
+      file = _pathToFile[path];
+      if (file != null) {
+        return Either2.t1(file);
+      }
+
       File resource = _resourceProvider.getFile(path);
 
       var rewrittenUri = rewriteFileToPackageUri(_sourceFactory, uri);
       if (rewrittenUri == null) {
         return Either2.t1(null);
       }
-      uri = rewrittenUri;
 
-      file = _newFile(resource, path, uri);
+      file = _newFile(resource, path, rewrittenUri);
     }
     return Either2.t1(file);
   }
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 b7e3039..f0a3e1f 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -23,19 +23,78 @@
 import 'package:analyzer/src/source/package_map_resolver.dart';
 import 'package:analyzer/src/test_utilities/mock_sdk.dart';
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+import 'package:analyzer/src/util/either.dart';
 import 'package:analyzer/src/workspace/basic.dart';
 import 'package:convert/convert.dart';
 import 'package:crypto/crypto.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import '../resolution/context_collection_resolution.dart';
+
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(FileSystemStateTest);
+    defineReflectiveTests(FileSystemState_BazelWorkspaceTest);
   });
 }
 
 @reflectiveTest
+class FileSystemState_BazelWorkspaceTest extends BazelWorkspaceResolutionTest {
+  void test_getFileForUri_hasGenerated_askGeneratedFirst() async {
+    var relPath = 'dart/my/test/a.dart';
+    var writablePath = convertPath('$workspaceRootPath/$relPath');
+    var generatedPath = convertPath('$workspaceRootPath/bazel-bin/$relPath');
+
+    // This generated file should be used instead of the writable.
+    newFile(generatedPath);
+
+    var analysisDriver = driverFor(convertPath(testFilePath));
+
+    var fsState = analysisDriver.fsState;
+
+    // The file is the generated file.
+    var generatedUri = toUri(generatedPath);
+    var generatedFile = fsState.getFileForUri(generatedUri).t1!;
+    expect(generatedFile.uri, generatedUri);
+    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));
+    expect(writableFile2, same(generatedFile));
+  }
+
+  void test_getFileForUri_hasGenerated_askWritableFirst() async {
+    var relPath = 'dart/my/test/a.dart';
+    var writablePath = convertPath('$workspaceRootPath/$relPath');
+    var generatedPath = convertPath('$workspaceRootPath/bazel-bin/$relPath');
+
+    // This generated file should be used instead of the writable.
+    newFile(generatedPath);
+
+    var analysisDriver = driverFor(convertPath(testFilePath));
+
+    var fsState = analysisDriver.fsState;
+
+    // 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(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.path, generatedPath);
+    expect(writableFile2, same(generatedFile));
+  }
+}
+
+@reflectiveTest
 class FileSystemStateTest with ResourceProviderMixin {
   final ByteStore byteStore = MemoryByteStore();
   final FileContentOverlay contentOverlay = FileContentOverlay();
@@ -756,3 +815,14 @@
     throw StateError('Unexpected invocation of ${invocation.memberName}');
   }
 }
+
+extension _Either2Extension<T1, T2> on Either2<T1, T2> {
+  T1 get t1 {
+    late T1 result;
+    map(
+      (t1) => result = t1,
+      (_) => throw 'Expected T1',
+    );
+    return result;
+  }
+}
diff --git a/tools/VERSION b/tools/VERSION
index 076e78e..c982ee7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 16
 PATCH 0
-PRERELEASE 39
+PRERELEASE 40
 PRERELEASE_PATCH 0
\ No newline at end of file