@@ -8,7 +8,7 @@ use base_db::Env;
8
8
use cargo_metadata:: { CargoOpt , MetadataCommand } ;
9
9
use la_arena:: { Arena , Idx } ;
10
10
use paths:: { AbsPath , AbsPathBuf , Utf8Path , Utf8PathBuf } ;
11
- use rustc_hash:: { FxHashMap , FxHashSet } ;
11
+ use rustc_hash:: { FxHashMap , FxHashSet , FxHasher } ;
12
12
use serde_derive:: Deserialize ;
13
13
use serde_json:: from_value;
14
14
use span:: Edition ;
@@ -552,6 +552,7 @@ impl CargoWorkspace {
552
552
553
553
pub ( crate ) struct FetchMetadata {
554
554
command : cargo_metadata:: MetadataCommand ,
555
+ manifest_path : ManifestPath ,
555
556
lockfile_path : Option < Utf8PathBuf > ,
556
557
kind : & ' static str ,
557
558
no_deps : bool ,
@@ -655,7 +656,15 @@ impl FetchMetadata {
655
656
}
656
657
. with_context ( || format ! ( "Failed to run `{cargo_command:?}`" ) ) ;
657
658
658
- Self { command, lockfile_path, kind : config. kind , no_deps, no_deps_result, other_options }
659
+ Self {
660
+ manifest_path : cargo_toml. clone ( ) ,
661
+ command,
662
+ lockfile_path,
663
+ kind : config. kind ,
664
+ no_deps,
665
+ no_deps_result,
666
+ other_options,
667
+ }
659
668
}
660
669
661
670
pub ( crate ) fn no_deps_metadata ( & self ) -> Option < & cargo_metadata:: Metadata > {
@@ -672,8 +681,15 @@ impl FetchMetadata {
672
681
locked : bool ,
673
682
progress : & dyn Fn ( String ) ,
674
683
) -> anyhow:: Result < ( cargo_metadata:: Metadata , Option < anyhow:: Error > ) > {
675
- let Self { mut command, lockfile_path, kind, no_deps, no_deps_result, mut other_options } =
676
- self ;
684
+ let Self {
685
+ manifest_path,
686
+ mut command,
687
+ lockfile_path,
688
+ kind,
689
+ no_deps,
690
+ no_deps_result,
691
+ mut other_options,
692
+ } = self ;
677
693
678
694
if no_deps {
679
695
return no_deps_result. map ( |m| ( m, None ) ) ;
@@ -682,8 +698,25 @@ impl FetchMetadata {
682
698
let mut using_lockfile_copy = false ;
683
699
// The manifest is a rust file, so this means its a script manifest
684
700
if let Some ( lockfile) = lockfile_path {
685
- let target_lockfile =
686
- target_dir. join ( "rust-analyzer" ) . join ( "metadata" ) . join ( kind) . join ( "Cargo.lock" ) ;
701
+ // When multiple workspaces share the same target dir, they might overwrite into a
702
+ // single lockfile path.
703
+ // See https://github.com/rust-lang/rust-analyzer/issues/20189#issuecomment-3073520255
704
+ let manifest_path_hash = std:: hash:: BuildHasher :: hash_one (
705
+ & std:: hash:: BuildHasherDefault :: < FxHasher > :: default ( ) ,
706
+ & manifest_path,
707
+ ) ;
708
+ let disambiguator = format ! (
709
+ "{}_{manifest_path_hash}" ,
710
+ manifest_path. components( ) . nth_back( 1 ) . map_or( "" , |c| c. as_str( ) )
711
+ ) ;
712
+
713
+ let target_lockfile = target_dir
714
+ . join ( "rust-analyzer" )
715
+ . join ( "metadata" )
716
+ . join ( "lockfile_copies" )
717
+ . join ( disambiguator)
718
+ . join ( kind)
719
+ . join ( "Cargo.lock" ) ;
687
720
match std:: fs:: copy ( & lockfile, & target_lockfile) {
688
721
Ok ( _) => {
689
722
using_lockfile_copy = true ;
0 commit comments