mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-08-18 09:30:31 +00:00
Auto merge of #14599 - HKalbasi:dev2, r=HKalbasi
Detect sysroot dependencies using symlink copy cc #7637 It is currently in a proof of concept stage, and it doesn't generates a copy. You need to provide your own sysroot copy in `/tmp/ra-sysroot-hack` in a way that `/tmp/ra-sysroot-hack/library/std/lib.rs` exists and `/tmp/ra-sysroot-hack/Cargo.toml` is [the one from this comment](https://github.com/rust-lang/rust-analyzer/issues/7637#issuecomment-1495008329). I will add the symlink code if we decide that this approach is not a dead end. It seems to somehow work on my system. Go to definition into std dependencies works, type checking can look through fields if I make them public and `cfg_if` appears to work (I tested it by hovering both sides and seeing that the correct one is enabled). Though finding layout of `HashMap` didn't work. Please try it and let me know if I should go forward in this direction or not.
This commit is contained in:
commit
0289dfa261
3 changed files with 175 additions and 39 deletions
|
@ -386,6 +386,37 @@ impl CrateGraph {
|
||||||
self.arena.alloc(data)
|
self.arena.alloc(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove the crate from crate graph. If any crates depend on this crate, the dependency would be replaced
|
||||||
|
/// with the second input.
|
||||||
|
pub fn remove_and_replace(
|
||||||
|
&mut self,
|
||||||
|
id: CrateId,
|
||||||
|
replace_with: CrateId,
|
||||||
|
) -> Result<(), CyclicDependenciesError> {
|
||||||
|
for (x, data) in self.arena.iter() {
|
||||||
|
if x == id {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for edge in &data.dependencies {
|
||||||
|
if edge.crate_id == id {
|
||||||
|
self.check_cycle_after_dependency(edge.crate_id, replace_with)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if everything was ok, start to replace
|
||||||
|
for (x, data) in self.arena.iter_mut() {
|
||||||
|
if x == id {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for edge in &mut data.dependencies {
|
||||||
|
if edge.crate_id == id {
|
||||||
|
edge.crate_id = replace_with;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_dep(
|
pub fn add_dep(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: CrateId,
|
from: CrateId,
|
||||||
|
@ -393,20 +424,29 @@ impl CrateGraph {
|
||||||
) -> Result<(), CyclicDependenciesError> {
|
) -> Result<(), CyclicDependenciesError> {
|
||||||
let _p = profile::span("add_dep");
|
let _p = profile::span("add_dep");
|
||||||
|
|
||||||
// Check if adding a dep from `from` to `to` creates a cycle. To figure
|
self.check_cycle_after_dependency(from, dep.crate_id)?;
|
||||||
// that out, look for a path in the *opposite* direction, from `to` to
|
|
||||||
// `from`.
|
|
||||||
if let Some(path) = self.find_path(&mut FxHashSet::default(), dep.crate_id, from) {
|
|
||||||
let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect();
|
|
||||||
let err = CyclicDependenciesError { path };
|
|
||||||
assert!(err.from().0 == from && err.to().0 == dep.crate_id);
|
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.arena[from].add_dep(dep);
|
self.arena[from].add_dep(dep);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if adding a dep from `from` to `to` creates a cycle. To figure
|
||||||
|
/// that out, look for a path in the *opposite* direction, from `to` to
|
||||||
|
/// `from`.
|
||||||
|
fn check_cycle_after_dependency(
|
||||||
|
&self,
|
||||||
|
from: CrateId,
|
||||||
|
to: CrateId,
|
||||||
|
) -> Result<(), CyclicDependenciesError> {
|
||||||
|
if let Some(path) = self.find_path(&mut FxHashSet::default(), to, from) {
|
||||||
|
let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect();
|
||||||
|
let err = CyclicDependenciesError { path };
|
||||||
|
assert!(err.from().0 == from && err.to().0 == to);
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.arena.is_empty()
|
self.arena.is_empty()
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,15 @@ use la_arena::{Arena, Idx};
|
||||||
use paths::{AbsPath, AbsPathBuf};
|
use paths::{AbsPath, AbsPathBuf};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::{utf8_stdout, ManifestPath};
|
use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct Sysroot {
|
pub struct Sysroot {
|
||||||
root: AbsPathBuf,
|
root: AbsPathBuf,
|
||||||
src_root: AbsPathBuf,
|
src_root: AbsPathBuf,
|
||||||
crates: Arena<SysrootCrateData>,
|
crates: Arena<SysrootCrateData>,
|
||||||
|
/// Stores the result of `cargo metadata` of the `RA_UNSTABLE_SYSROOT_HACK` workspace.
|
||||||
|
pub hack_cargo_workspace: Option<CargoWorkspace>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type SysrootCrate = Idx<SysrootCrateData>;
|
pub(crate) type SysrootCrate = Idx<SysrootCrateData>;
|
||||||
|
@ -125,9 +127,31 @@ impl Sysroot {
|
||||||
Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
|
Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Sysroot {
|
pub fn load(sysroot_dir: AbsPathBuf, mut sysroot_src_dir: AbsPathBuf) -> Sysroot {
|
||||||
let mut sysroot =
|
// FIXME: Remove this `hack_cargo_workspace` field completely once we support sysroot dependencies
|
||||||
Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() };
|
let hack_cargo_workspace = if let Ok(path) = std::env::var("RA_UNSTABLE_SYSROOT_HACK") {
|
||||||
|
let cargo_toml = ManifestPath::try_from(
|
||||||
|
AbsPathBuf::try_from(&*format!("{path}/Cargo.toml")).unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
sysroot_src_dir = AbsPathBuf::try_from(&*path).unwrap().join("library");
|
||||||
|
CargoWorkspace::fetch_metadata(
|
||||||
|
&cargo_toml,
|
||||||
|
&AbsPathBuf::try_from("/").unwrap(),
|
||||||
|
&CargoConfig::default(),
|
||||||
|
&|_| (),
|
||||||
|
)
|
||||||
|
.map(CargoWorkspace::new)
|
||||||
|
.ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let mut sysroot = Sysroot {
|
||||||
|
root: sysroot_dir,
|
||||||
|
src_root: sysroot_src_dir,
|
||||||
|
crates: Arena::default(),
|
||||||
|
hack_cargo_workspace,
|
||||||
|
};
|
||||||
|
|
||||||
for path in SYSROOT_CRATES.trim().lines() {
|
for path in SYSROOT_CRATES.trim().lines() {
|
||||||
let name = path.split('/').last().unwrap();
|
let name = path.split('/').last().unwrap();
|
||||||
|
|
|
@ -622,6 +622,7 @@ impl ProjectWorkspace {
|
||||||
sysroot.as_ref().ok(),
|
sysroot.as_ref().ok(),
|
||||||
rustc_cfg.clone(),
|
rustc_cfg.clone(),
|
||||||
cfg_overrides,
|
cfg_overrides,
|
||||||
|
None,
|
||||||
build_scripts,
|
build_scripts,
|
||||||
match target_layout.as_ref() {
|
match target_layout.as_ref() {
|
||||||
Ok(it) => Ok(Arc::from(it.as_str())),
|
Ok(it) => Ok(Arc::from(it.as_str())),
|
||||||
|
@ -821,6 +822,8 @@ fn cargo_to_crate_graph(
|
||||||
sysroot: Option<&Sysroot>,
|
sysroot: Option<&Sysroot>,
|
||||||
rustc_cfg: Vec<CfgFlag>,
|
rustc_cfg: Vec<CfgFlag>,
|
||||||
override_cfg: &CfgOverrides,
|
override_cfg: &CfgOverrides,
|
||||||
|
// Don't compute cfg and use this if present
|
||||||
|
forced_cfg: Option<CfgOptions>,
|
||||||
build_scripts: &WorkspaceBuildScripts,
|
build_scripts: &WorkspaceBuildScripts,
|
||||||
target_layout: TargetLayoutLoadResult,
|
target_layout: TargetLayoutLoadResult,
|
||||||
channel: Option<ReleaseChannel>,
|
channel: Option<ReleaseChannel>,
|
||||||
|
@ -858,7 +861,7 @@ fn cargo_to_crate_graph(
|
||||||
for pkg in cargo.packages() {
|
for pkg in cargo.packages() {
|
||||||
has_private |= cargo[pkg].metadata.rustc_private;
|
has_private |= cargo[pkg].metadata.rustc_private;
|
||||||
|
|
||||||
let cfg_options = {
|
let cfg_options = forced_cfg.clone().unwrap_or_else(|| {
|
||||||
let mut cfg_options = cfg_options.clone();
|
let mut cfg_options = cfg_options.clone();
|
||||||
|
|
||||||
// Add test cfg for local crates
|
// Add test cfg for local crates
|
||||||
|
@ -882,7 +885,7 @@ fn cargo_to_crate_graph(
|
||||||
cfg_options.apply_diff(overrides.clone());
|
cfg_options.apply_diff(overrides.clone());
|
||||||
};
|
};
|
||||||
cfg_options
|
cfg_options
|
||||||
};
|
});
|
||||||
|
|
||||||
let mut lib_tgt = None;
|
let mut lib_tgt = None;
|
||||||
for &tgt in cargo[pkg].targets.iter() {
|
for &tgt in cargo[pkg].targets.iter() {
|
||||||
|
@ -1280,31 +1283,43 @@ fn sysroot_to_crate_graph(
|
||||||
) -> (SysrootPublicDeps, Option<CrateId>) {
|
) -> (SysrootPublicDeps, Option<CrateId>) {
|
||||||
let _p = profile::span("sysroot_to_crate_graph");
|
let _p = profile::span("sysroot_to_crate_graph");
|
||||||
let mut cfg_options = CfgOptions::default();
|
let mut cfg_options = CfgOptions::default();
|
||||||
cfg_options.extend(rustc_cfg);
|
cfg_options.extend(rustc_cfg.clone());
|
||||||
let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot
|
let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = match &sysroot.hack_cargo_workspace {
|
||||||
.crates()
|
Some(cargo) => handle_hack_cargo_workspace(
|
||||||
.filter_map(|krate| {
|
load,
|
||||||
let file_id = load(&sysroot[krate].root)?;
|
cargo,
|
||||||
|
rustc_cfg,
|
||||||
let env = Env::default();
|
cfg_options,
|
||||||
let display_name = CrateDisplayName::from_canonical_name(sysroot[krate].name.clone());
|
target_layout,
|
||||||
let crate_id = crate_graph.add_crate_root(
|
channel,
|
||||||
file_id,
|
crate_graph,
|
||||||
Edition::CURRENT,
|
sysroot,
|
||||||
Some(display_name),
|
),
|
||||||
None,
|
None => sysroot
|
||||||
cfg_options.clone(),
|
.crates()
|
||||||
None,
|
.filter_map(|krate| {
|
||||||
env,
|
let file_id = load(&sysroot[krate].root)?;
|
||||||
false,
|
|
||||||
CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)),
|
|
||||||
target_layout.clone(),
|
|
||||||
channel,
|
|
||||||
);
|
|
||||||
Some((krate, crate_id))
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
|
let env = Env::default();
|
||||||
|
let display_name =
|
||||||
|
CrateDisplayName::from_canonical_name(sysroot[krate].name.clone());
|
||||||
|
let crate_id = crate_graph.add_crate_root(
|
||||||
|
file_id,
|
||||||
|
Edition::CURRENT,
|
||||||
|
Some(display_name),
|
||||||
|
None,
|
||||||
|
cfg_options.clone(),
|
||||||
|
None,
|
||||||
|
env,
|
||||||
|
false,
|
||||||
|
CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)),
|
||||||
|
target_layout.clone(),
|
||||||
|
channel,
|
||||||
|
);
|
||||||
|
Some((krate, crate_id))
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
for from in sysroot.crates() {
|
for from in sysroot.crates() {
|
||||||
for &to in sysroot[from].deps.iter() {
|
for &to in sysroot[from].deps.iter() {
|
||||||
let name = CrateName::new(&sysroot[to].name).unwrap();
|
let name = CrateName::new(&sysroot[to].name).unwrap();
|
||||||
|
@ -1325,6 +1340,63 @@ fn sysroot_to_crate_graph(
|
||||||
(public_deps, libproc_macro)
|
(public_deps, libproc_macro)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_hack_cargo_workspace(
|
||||||
|
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
|
||||||
|
cargo: &CargoWorkspace,
|
||||||
|
rustc_cfg: Vec<CfgFlag>,
|
||||||
|
cfg_options: CfgOptions,
|
||||||
|
target_layout: Result<Arc<str>, Arc<str>>,
|
||||||
|
channel: Option<ReleaseChannel>,
|
||||||
|
crate_graph: &mut CrateGraph,
|
||||||
|
sysroot: &Sysroot,
|
||||||
|
) -> FxHashMap<SysrootCrate, CrateId> {
|
||||||
|
let (cg, mut pm) = cargo_to_crate_graph(
|
||||||
|
load,
|
||||||
|
None,
|
||||||
|
cargo,
|
||||||
|
None,
|
||||||
|
rustc_cfg,
|
||||||
|
&CfgOverrides::default(),
|
||||||
|
Some(cfg_options),
|
||||||
|
&WorkspaceBuildScripts::default(),
|
||||||
|
target_layout,
|
||||||
|
channel,
|
||||||
|
);
|
||||||
|
crate_graph.extend(cg, &mut pm);
|
||||||
|
for crate_name in ["std", "alloc", "core"] {
|
||||||
|
let original = crate_graph
|
||||||
|
.iter()
|
||||||
|
.find(|x| {
|
||||||
|
crate_graph[*x]
|
||||||
|
.display_name
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| x.canonical_name() == crate_name)
|
||||||
|
.unwrap_or(false)
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
let fake_crate_name = format!("rustc-std-workspace-{}", crate_name);
|
||||||
|
let fake = crate_graph
|
||||||
|
.iter()
|
||||||
|
.find(|x| {
|
||||||
|
crate_graph[*x]
|
||||||
|
.display_name
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| x.canonical_name() == fake_crate_name)
|
||||||
|
.unwrap_or(false)
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
crate_graph.remove_and_replace(fake, original).unwrap();
|
||||||
|
}
|
||||||
|
sysroot
|
||||||
|
.crates()
|
||||||
|
.filter_map(|krate| {
|
||||||
|
let file_id = load(&sysroot[krate].root)?;
|
||||||
|
let crate_id = crate_graph.crate_id_for_crate_root(file_id)?;
|
||||||
|
Some((krate, crate_id))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
|
fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
|
||||||
add_dep_inner(graph, from, Dependency::new(name, to))
|
add_dep_inner(graph, from, Dependency::new(name, to))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue