@@ -552,6 +552,7 @@ impl CargoWorkspace {
552552
553553pub ( crate ) struct FetchMetadata {
554554 command : cargo_metadata:: MetadataCommand ,
555+ manifest_path : ManifestPath ,
555556 lockfile_path : Option < Utf8PathBuf > ,
556557 kind : & ' static str ,
557558 no_deps : bool ,
@@ -655,7 +656,15 @@ impl FetchMetadata {
655656 }
656657 . with_context ( || format ! ( "Failed to run `{cargo_command:?}`" ) ) ;
657658
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+ }
659668 }
660669
661670 pub ( crate ) fn no_deps_metadata ( & self ) -> Option < & cargo_metadata:: Metadata > {
@@ -672,18 +681,47 @@ impl FetchMetadata {
672681 locked : bool ,
673682 progress : & dyn Fn ( String ) ,
674683 ) -> 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+ mut command,
686+ manifest_path,
687+ lockfile_path,
688+ kind,
689+ no_deps,
690+ no_deps_result,
691+ mut other_options,
692+ } = self ;
677693
678694 if no_deps {
679695 return no_deps_result. map ( |m| ( m, None ) ) ;
680696 }
681697
682698 let mut using_lockfile_copy = false ;
699+ let mut _temp_dir_guard = None ;
683700 // The manifest is a rust file, so this means its a script manifest
684701 if let Some ( lockfile) = lockfile_path {
685- let target_lockfile =
686- target_dir. join ( "rust-analyzer" ) . join ( "metadata" ) . join ( kind) . join ( "Cargo.lock" ) ;
702+ _temp_dir_guard = temp_dir:: TempDir :: with_prefix ( "rust-analyzer" ) . ok ( ) ;
703+ let target_lockfile = _temp_dir_guard
704+ . and_then ( |tmp| tmp. path ( ) . join ( "Cargo.lock" ) . try_into ( ) . ok ( ) )
705+ . unwrap_or_else ( || {
706+ // When multiple workspaces share the same target dir, they might overwrite into a
707+ // single lockfile path.
708+ // See https://github.com/rust-lang/rust-analyzer/issues/20189#issuecomment-3073520255
709+ let manifest_path_hash = std:: hash:: BuildHasher :: hash_one (
710+ & std:: hash:: BuildHasherDefault :: < rustc_hash:: FxHasher > :: default ( ) ,
711+ & manifest_path,
712+ ) ;
713+ let disambiguator = format ! (
714+ "{}_{manifest_path_hash}" ,
715+ manifest_path. components( ) . nth_back( 1 ) . map_or( "" , |c| c. as_str( ) )
716+ ) ;
717+
718+ target_dir
719+ . join ( "rust-analyzer" )
720+ . join ( "metadata" )
721+ . join ( kind)
722+ . join ( disambiguator)
723+ . join ( "Cargo.lock" )
724+ } ) ;
687725 match std:: fs:: copy ( & lockfile, & target_lockfile) {
688726 Ok ( _) => {
689727 using_lockfile_copy = true ;
0 commit comments