Skip to content

Commit

Permalink
Detect sysroot dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
HKalbasi committed Apr 19, 2023
1 parent 9b54e39 commit ab3f01b
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 52 deletions.
54 changes: 47 additions & 7 deletions crates/base-db/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,24 +386,64 @@ impl CrateGraph {
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(
&mut self,
from: CrateId,
dep: Dependency,
) -> Result<(), CyclicDependenciesError> {
let _p = profile::span("add_dep");

// 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`.
if let Some(path) = self.find_path(&mut FxHashSet::default(), dep.crate_id, from) {
self.check_cycle_after_dependency(from, dep.crate_id)?;

self.arena[from].add_dep(dep);
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 == dep.crate_id);
assert!(err.from().0 == from && err.to().0 == to);
return Err(err);
}

self.arena[from].add_dep(dep);
Ok(())
}

Expand Down
31 changes: 27 additions & 4 deletions crates/project-model/src/sysroot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ use la_arena::{Arena, Idx};
use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap;

use crate::{utf8_stdout, ManifestPath};
use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath};

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Sysroot {
root: AbsPathBuf,
src_root: AbsPathBuf,
crates: Arena<SysrootCrateData>,
pub cargo_workspace: Option<CargoWorkspace>,
}

pub(crate) type SysrootCrate = Idx<SysrootCrateData>;
Expand Down Expand Up @@ -125,9 +126,31 @@ impl Sysroot {
Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
}

pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Sysroot {
let mut sysroot =
Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() };
pub fn load(sysroot_dir: AbsPathBuf, mut sysroot_src_dir: AbsPathBuf) -> Sysroot {
// FIXME: generate /tmp/ra-sysroot-hack from sysroot_src_dir
let 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("/home/hamid/oss/rust-analyzer").unwrap(),
&CargoConfig::default(),
&|_| (),
)
.map(CargoWorkspace::new)
.ok()
} else {
None
};
let mut sysroot = Sysroot {
root: sysroot_dir,
src_root: sysroot_src_dir,
crates: Arena::default(),
cargo_workspace,
};

for path in SYSROOT_CRATES.trim().lines() {
let name = path.split('/').last().unwrap();
Expand Down
139 changes: 98 additions & 41 deletions crates/project-model/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,20 +615,27 @@ impl ProjectWorkspace {
build_scripts,
toolchain,
target_layout,
} => cargo_to_crate_graph(
load,
rustc.as_ref().ok(),
cargo,
sysroot.as_ref().ok(),
rustc_cfg.clone(),
cfg_overrides,
build_scripts,
match target_layout.as_ref() {
Ok(it) => Ok(Arc::from(it.as_str())),
Err(it) => Err(Arc::from(it.as_str())),
},
toolchain.as_ref().and_then(|it| ReleaseChannel::from_str(it.pre.as_str())),
),
} => {
let mut res = (CrateGraph::default(), ProcMacroPaths::default());
cargo_to_crate_graph(
&mut res.0,
&mut res.1,
load,
rustc.as_ref().ok(),
cargo,
sysroot.as_ref().ok(),
rustc_cfg.clone(),
cfg_overrides,
None,
build_scripts,
match target_layout.as_ref() {
Ok(it) => Ok(Arc::from(it.as_str())),
Err(it) => Err(Arc::from(it.as_str())),
},
toolchain.as_ref().and_then(|it| ReleaseChannel::from_str(it.pre.as_str())),
);
res
}
ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => {
detached_files_to_crate_graph(
rustc_cfg.clone(),
Expand Down Expand Up @@ -815,20 +822,21 @@ fn project_json_to_crate_graph(
}

fn cargo_to_crate_graph(
crate_graph: &mut CrateGraph,
proc_macros: &mut ProcMacroPaths,
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
rustc: Option<&(CargoWorkspace, WorkspaceBuildScripts)>,
cargo: &CargoWorkspace,
sysroot: Option<&Sysroot>,
rustc_cfg: Vec<CfgFlag>,
override_cfg: &CfgOverrides,
// Don't compute cfg and use this if present
forced_cfg: Option<CfgOptions>,
build_scripts: &WorkspaceBuildScripts,
target_layout: TargetLayoutLoadResult,
channel: Option<ReleaseChannel>,
) -> (CrateGraph, ProcMacroPaths) {
) {
let _p = profile::span("cargo_to_crate_graph");
let mut res = (CrateGraph::default(), ProcMacroPaths::default());
let crate_graph = &mut res.0;
let proc_macros = &mut res.1;
let (public_deps, libproc_macro) = match sysroot {
Some(sysroot) => sysroot_to_crate_graph(
crate_graph,
Expand Down Expand Up @@ -858,7 +866,7 @@ fn cargo_to_crate_graph(
for pkg in cargo.packages() {
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();

// Add test cfg for local crates
Expand All @@ -882,7 +890,7 @@ fn cargo_to_crate_graph(
cfg_options.apply_diff(overrides.clone());
};
cfg_options
};
});

let mut lib_tgt = None;
for &tgt in cargo[pkg].targets.iter() {
Expand Down Expand Up @@ -989,7 +997,6 @@ fn cargo_to_crate_graph(
);
}
}
res
}

fn detached_files_to_crate_graph(
Expand Down Expand Up @@ -1280,31 +1287,81 @@ fn sysroot_to_crate_graph(
) -> (SysrootPublicDeps, Option<CrateId>) {
let _p = profile::span("sysroot_to_crate_graph");
let mut cfg_options = CfgOptions::default();
cfg_options.extend(rustc_cfg);
let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot
.crates()
.filter_map(|krate| {
let file_id = load(&sysroot[krate].root)?;

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),
cfg_options.extend(rustc_cfg.clone());
let sysroot_crates: FxHashMap<SysrootCrate, CrateId> =
if let Some(cargo) = &sysroot.cargo_workspace {
cargo_to_crate_graph(
crate_graph,
&mut Default::default(),
load,
None,
cfg_options.clone(),
cargo,
None,
env,
false,
CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)),
target_layout.clone(),
rustc_cfg,
&CfgOverrides::default(),
Some(cfg_options),
&WorkspaceBuildScripts::default(),
target_layout,
channel,
);
Some((krate, crate_id))
})
.collect();
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()
} else {
sysroot
.crates()
.filter_map(|krate| {
let file_id = load(&sysroot[krate].root)?;

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 &to in sysroot[from].deps.iter() {
let name = CrateName::new(&sysroot[to].name).unwrap();
Expand Down

0 comments on commit ab3f01b

Please sign in to comment.