1 //! Handles lowering of build-system specific workspace information (`cargo
2 //! metadata` or `rust-project.json`) into representation stored in the salsa
3 //! database -- `CrateGraph`.
5 use std::{collections::VecDeque, fmt, fs, path::Path, process::Command};
7 use anyhow::{format_err, Context, Result};
8 use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro};
9 use cargo_workspace::DepKind;
10 use cfg::{CfgDiff, CfgOptions};
11 use paths::{AbsPath, AbsPathBuf};
12 use proc_macro_api::ProcMacroClient;
13 use rustc_hash::{FxHashMap, FxHashSet};
16 build_data::{BuildDataResult, PackageBuildData, WorkspaceBuildData},
20 sysroot::SysrootCrate,
21 utf8_stdout, BuildDataCollector, CargoConfig, CargoWorkspace, ProjectJson, ProjectManifest,
25 pub type CfgOverrides = FxHashMap<String, CfgDiff>;
27 /// `PackageRoot` describes a package root folder.
28 /// Which may be an external dependency, or a member of
29 /// the current workspace.
30 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
31 pub struct PackageRoot {
32 /// Is a member of the current workspace
34 pub include: Vec<AbsPathBuf>,
35 pub exclude: Vec<AbsPathBuf>,
38 #[derive(Clone, Eq, PartialEq)]
39 pub enum ProjectWorkspace {
40 /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
42 cargo: CargoWorkspace,
44 rustc: Option<CargoWorkspace>,
45 /// Holds cfg flags for the current target. We get those by running
46 /// `rustc --print cfg`.
48 /// FIXME: make this a per-crate map, as, eg, build.rs might have a
50 rustc_cfg: Vec<CfgFlag>,
51 cfg_overrides: CfgOverrides,
53 /// Project workspace was manually specified using a `rust-project.json` file.
54 Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
56 // FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
57 // That's not the end user experience we should strive for.
58 // Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working.
59 // That needs some changes on the salsa-level though.
60 // In particular, we should split the unified CrateGraph (which currently has maximal durability) into proper crate graph, and a set of ad hoc roots (with minimal durability).
61 // Then, we need to hide the graph behind the queries such that most queries look only at the proper crate graph, and fall back to ad hoc roots only if there's no results.
62 // After this, we should be able to tweak the logic in reload.rs to add newly opened files, which don't belong to any existing crates, to the set of the detached files.
64 /// Project with a set of disjoint files, not belonging to any particular workspace.
65 /// Backed by basic sysroot crates for basic completion and highlighting.
66 DetachedFiles { files: Vec<AbsPathBuf>, sysroot: Sysroot, rustc_cfg: Vec<CfgFlag> },
69 impl fmt::Debug for ProjectWorkspace {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 // Make sure this isn't too verbose.
73 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => f
74 .debug_struct("Cargo")
75 .field("root", &cargo.workspace_root().file_name())
76 .field("n_packages", &cargo.packages().len())
77 .field("n_sysroot_crates", &sysroot.crates().len())
79 "n_rustc_compiler_crates",
80 &rustc.as_ref().map_or(0, |rc| rc.packages().len()),
82 .field("n_rustc_cfg", &rustc_cfg.len())
83 .field("n_cfg_overrides", &cfg_overrides.len())
85 ProjectWorkspace::Json { project, sysroot, rustc_cfg } => {
86 let mut debug_struct = f.debug_struct("Json");
87 debug_struct.field("n_crates", &project.n_crates());
88 if let Some(sysroot) = sysroot {
89 debug_struct.field("n_sysroot_crates", &sysroot.crates().len());
91 debug_struct.field("n_rustc_cfg", &rustc_cfg.len());
94 ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => f
95 .debug_struct("DetachedFiles")
96 .field("n_files", &files.len())
97 .field("n_sysroot_crates", &sysroot.crates().len())
98 .field("n_rustc_cfg", &rustc_cfg.len())
104 impl ProjectWorkspace {
106 manifest: ProjectManifest,
107 config: &CargoConfig,
108 progress: &dyn Fn(String),
109 ) -> Result<ProjectWorkspace> {
110 let res = match manifest {
111 ProjectManifest::ProjectJson(project_json) => {
112 let file = fs::read_to_string(&project_json).with_context(|| {
113 format!("Failed to read json file {}", project_json.display())
115 let data = serde_json::from_str(&file).with_context(|| {
116 format!("Failed to deserialize json file {}", project_json.display())
118 let project_location = project_json.parent().unwrap().to_path_buf();
119 let project_json = ProjectJson::new(&project_location, data);
120 ProjectWorkspace::load_inline(project_json, config.target.as_deref())?
122 ProjectManifest::CargoToml(cargo_toml) => {
123 let cargo_version = utf8_stdout({
124 let mut cmd = Command::new(toolchain::cargo());
125 cmd.arg("--version");
129 let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, config, progress)
132 "Failed to read Cargo metadata from Cargo.toml file {}, {}",
133 cargo_toml.display(),
138 let sysroot = if config.no_sysroot {
141 Sysroot::discover(&cargo_toml).with_context(|| {
143 "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
149 let rustc_dir = if let Some(rustc_source) = &config.rustc_source {
150 use cargo_workspace::RustcSource;
152 RustcSource::Path(path) => Some(path.clone()),
153 RustcSource::Discover => Sysroot::discover_rustc(&cargo_toml),
159 let rustc = if let Some(rustc_dir) = rustc_dir {
161 CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress)
163 format!("Failed to read Cargo metadata for Rust sources")
170 let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref());
172 let cfg_overrides = config.cfg_overrides();
173 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides }
181 project_json: ProjectJson,
182 target: Option<&str>,
183 ) -> Result<ProjectWorkspace> {
184 let sysroot = match &project_json.sysroot_src {
185 Some(path) => Some(Sysroot::load(path)?),
188 let rustc_cfg = rustc_cfg::get(None, target);
189 Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
192 pub fn load_detached_files(detached_files: Vec<AbsPathBuf>) -> Result<ProjectWorkspace> {
193 let sysroot = Sysroot::discover(
194 detached_files.first().ok_or_else(|| format_err!("No detached files to load"))?,
196 let rustc_cfg = rustc_cfg::get(None, None);
197 Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
200 /// Returns the roots for the current `ProjectWorkspace`
201 /// The return type contains the path and whether or not
202 /// the root is a member of the current workspace
203 pub fn to_roots(&self, build_data: Option<&BuildDataResult>) -> Vec<PackageRoot> {
205 ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project
207 .map(|(_, krate)| PackageRoot {
208 is_member: krate.is_workspace_member,
209 include: krate.include.clone(),
210 exclude: krate.exclude.clone(),
212 .collect::<FxHashSet<_>>()
214 .chain(sysroot.as_ref().into_iter().flat_map(|sysroot| {
215 sysroot.crates().map(move |krate| PackageRoot {
217 include: vec![sysroot[krate].root_dir().to_path_buf()],
221 .collect::<Vec<_>>(),
222 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg: _, cfg_overrides: _ } => {
226 let is_member = cargo[pkg].is_member;
227 let pkg_root = cargo[pkg].root().to_path_buf();
229 let mut include = vec![pkg_root.clone()];
232 .and_then(|it| it.get(cargo.workspace_root()))
233 .and_then(|map| map.get(&cargo[pkg].id))
234 .and_then(|it| it.out_dir.clone()),
237 // In case target's path is manually set in Cargo.toml to be
238 // outside the package root, add its parent as an extra include.
239 // An example of this situation would look like this:
243 // path = "../../src/lib.rs"
245 let extra_targets = cargo[pkg]
248 .filter(|&&tgt| cargo[tgt].kind == TargetKind::Lib)
249 .filter_map(|&tgt| cargo[tgt].root.parent())
250 .map(|tgt| tgt.normalize().to_path_buf())
251 .filter(|path| !path.starts_with(pkg_root.clone()));
252 include.extend(extra_targets);
254 let mut exclude = vec![pkg_root.join(".git")];
256 exclude.push(pkg_root.join("target"));
258 exclude.push(pkg_root.join("tests"));
259 exclude.push(pkg_root.join("examples"));
260 exclude.push(pkg_root.join("benches"));
262 PackageRoot { is_member, include, exclude }
264 .chain(sysroot.crates().map(|krate| PackageRoot {
266 include: vec![sysroot[krate].root_dir().to_path_buf()],
269 .chain(rustc.into_iter().flat_map(|rustc| {
270 rustc.packages().map(move |krate| PackageRoot {
272 include: vec![rustc[krate].root().to_path_buf()],
278 ProjectWorkspace::DetachedFiles { files, sysroot, .. } => files
280 .map(|detached_file| PackageRoot {
282 include: vec![detached_file.clone()],
285 .chain(sysroot.crates().map(|krate| PackageRoot {
287 include: vec![sysroot[krate].root_dir().to_path_buf()],
294 pub fn n_packages(&self) -> usize {
296 ProjectWorkspace::Json { project, .. } => project.n_crates(),
297 ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => {
298 let rustc_package_len = rustc.as_ref().map_or(0, |rc| rc.packages().len());
299 cargo.packages().len() + sysroot.crates().len() + rustc_package_len
301 ProjectWorkspace::DetachedFiles { sysroot, files, .. } => {
302 sysroot.crates().len() + files.len()
307 pub fn to_crate_graph(
309 build_data: Option<&BuildDataResult>,
310 proc_macro_client: Option<&ProcMacroClient>,
311 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
313 let _p = profile::span("ProjectWorkspace::to_crate_graph");
314 let proc_macro_loader = |path: &Path| match proc_macro_client {
315 Some(client) => client.by_dylib_path(path),
319 let mut crate_graph = match self {
320 ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph(
327 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg, cfg_overrides } => {
328 cargo_to_crate_graph(
334 build_data.and_then(|it| it.get(cargo.workspace_root())),
340 .and_then(|(it, map)| map.get(it.workspace_root())),
343 ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => {
344 detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot)
347 if crate_graph.patch_cfg_if() {
348 log::debug!("Patched std to depend on cfg-if")
350 log::debug!("Did not patch std to depend on cfg-if")
355 pub fn collect_build_data_configs(&self, collector: &mut BuildDataCollector) {
357 ProjectWorkspace::Cargo { cargo, .. } => {
358 collector.add_config(cargo.workspace_root(), cargo.build_data_config().clone());
365 fn project_json_to_crate_graph(
366 rustc_cfg: Vec<CfgFlag>,
367 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
368 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
369 project: &ProjectJson,
370 sysroot: &Option<Sysroot>,
372 let mut crate_graph = CrateGraph::default();
373 let sysroot_deps = sysroot
375 .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load));
377 let mut cfg_cache: FxHashMap<&str, Vec<CfgFlag>> = FxHashMap::default();
378 let crates: FxHashMap<CrateId, CrateId> = project
380 .filter_map(|(crate_id, krate)| {
381 let file_path = &krate.root_module;
382 let file_id = load(file_path)?;
383 Some((crate_id, krate, file_id))
385 .map(|(crate_id, krate, file_id)| {
386 let env = krate.env.clone().into_iter().collect();
387 let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| proc_macro_loader(&it));
389 let target_cfgs = match krate.target.as_deref() {
391 cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(None, Some(target)))
396 let mut cfg_options = CfgOptions::default();
397 cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned());
400 crate_graph.add_crate_root(
403 krate.display_name.clone(),
407 proc_macro.unwrap_or_default(),
413 for (from, krate) in project.crates() {
414 if let Some(&from) = crates.get(&from) {
415 if let Some((public_deps, _proc_macro)) = &sysroot_deps {
416 for (name, to) in public_deps.iter() {
417 add_dep(&mut crate_graph, from, name.clone(), *to)
421 for dep in &krate.deps {
422 if let Some(&to) = crates.get(&dep.crate_id) {
423 add_dep(&mut crate_graph, from, dep.name.clone(), to)
431 fn cargo_to_crate_graph(
432 rustc_cfg: Vec<CfgFlag>,
433 override_cfg: &CfgOverrides,
434 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
435 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
436 cargo: &CargoWorkspace,
437 build_data_map: Option<&WorkspaceBuildData>,
439 rustc: &Option<CargoWorkspace>,
440 rustc_build_data_map: Option<&WorkspaceBuildData>,
442 let _p = profile::span("cargo_to_crate_graph");
443 let mut crate_graph = CrateGraph::default();
444 let (public_deps, libproc_macro) =
445 sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load);
447 let mut cfg_options = CfgOptions::default();
448 cfg_options.extend(rustc_cfg);
450 let mut pkg_to_lib_crate = FxHashMap::default();
452 // Add test cfg for non-sysroot crates
453 cfg_options.insert_atom("test".into());
454 cfg_options.insert_atom("debug_assertions".into());
456 let mut pkg_crates = FxHashMap::default();
457 // Does any crate signal to rust-analyzer that they need the rustc_private crates?
458 let mut has_private = false;
459 // Next, create crates for each package, target pair
460 for pkg in cargo.packages() {
461 let mut cfg_options = &cfg_options;
462 let mut replaced_cfg_options;
463 if let Some(overrides) = override_cfg.get(&cargo[pkg].name) {
464 // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
465 // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
466 // working on rust-lang/rust as that's the only time it appears outside sysroot).
468 // A more ideal solution might be to reanalyze crates based on where the cursor is and
469 // figure out the set of cfgs that would have to apply to make it active.
471 replaced_cfg_options = cfg_options.clone();
472 replaced_cfg_options.apply_diff(overrides.clone());
473 cfg_options = &replaced_cfg_options;
476 has_private |= cargo[pkg].metadata.rustc_private;
477 let mut lib_tgt = None;
478 for &tgt in cargo[pkg].targets.iter() {
479 if let Some(file_id) = load(&cargo[tgt].root) {
480 let crate_id = add_target_crate_root(
483 build_data_map.and_then(|it| it.get(&cargo[pkg].id)),
489 if cargo[tgt].kind == TargetKind::Lib {
490 lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
491 pkg_to_lib_crate.insert(pkg, crate_id);
493 if cargo[tgt].is_proc_macro {
494 if let Some(proc_macro) = libproc_macro {
498 CrateName::new("proc_macro").unwrap(),
504 pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, cargo[tgt].kind));
508 // Set deps to the core, std and to the lib target of the current package
509 for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
510 if let Some((to, name)) = lib_tgt.clone() {
511 if to != *from && *kind != TargetKind::BuildScript {
512 // (build script can not depend on its library target)
514 // For root projects with dashes in their name,
515 // cargo metadata does not do any normalization,
516 // so we do it ourselves currently
517 let name = CrateName::normalize_dashes(&name);
518 add_dep(&mut crate_graph, *from, name, to);
521 for (name, krate) in public_deps.iter() {
522 add_dep(&mut crate_graph, *from, name.clone(), *krate);
527 // Now add a dep edge from all targets of upstream to the lib
528 // target of downstream.
529 for pkg in cargo.packages() {
530 for dep in cargo[pkg].dependencies.iter() {
531 let name = CrateName::new(&dep.name).unwrap();
532 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
533 for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
534 if dep.kind == DepKind::Build && *kind != TargetKind::BuildScript {
535 // Only build scripts may depend on build dependencies.
538 if dep.kind != DepKind::Build && *kind == TargetKind::BuildScript {
539 // Build scripts may only depend on build dependencies.
543 add_dep(&mut crate_graph, *from, name.clone(), to)
550 // If the user provided a path to rustc sources, we add all the rustc_private crates
551 // and create dependencies on them for the crates which opt-in to that
552 if let Some(rustc_workspace) = rustc {
557 rustc_build_data_map,
560 &mut pkg_to_lib_crate,
570 fn detached_files_to_crate_graph(
571 rustc_cfg: Vec<CfgFlag>,
572 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
573 detached_files: &[AbsPathBuf],
576 let _p = profile::span("detached_files_to_crate_graph");
577 let mut crate_graph = CrateGraph::default();
578 let (public_deps, _libproc_macro) =
579 sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load);
581 let mut cfg_options = CfgOptions::default();
582 cfg_options.extend(rustc_cfg);
584 for detached_file in detached_files {
585 let file_id = match load(detached_file) {
586 Some(file_id) => file_id,
588 log::error!("Failed to load detached file {:?}", detached_file);
592 let display_name = detached_file
594 .and_then(|os_str| os_str.to_str())
595 .map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_string()));
596 let detached_file_crate = crate_graph.add_crate_root(
598 Edition::Edition2018,
606 for (name, krate) in public_deps.iter() {
607 add_dep(&mut crate_graph, detached_file_crate, name.clone(), *krate);
613 fn handle_rustc_crates(
614 rustc_workspace: &CargoWorkspace,
615 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
616 crate_graph: &mut CrateGraph,
617 rustc_build_data_map: Option<&WorkspaceBuildData>,
618 cfg_options: &CfgOptions,
619 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
620 pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
621 public_deps: &[(CrateName, CrateId)],
622 cargo: &CargoWorkspace,
623 pkg_crates: &FxHashMap<la_arena::Idx<crate::PackageData>, Vec<(CrateId, TargetKind)>>,
625 let mut rustc_pkg_crates = FxHashMap::default();
626 // The root package of the rustc-dev component is rustc_driver, so we match that
628 rustc_workspace.packages().find(|package| rustc_workspace[*package].name == "rustc_driver");
629 // The rustc workspace might be incomplete (such as if rustc-dev is not
630 // installed for the current toolchain) and `rustcSource` is set to discover.
631 if let Some(root_pkg) = root_pkg {
632 // Iterate through every crate in the dependency subtree of rustc_driver using BFS
633 let mut queue = VecDeque::new();
634 queue.push_back(root_pkg);
635 while let Some(pkg) = queue.pop_front() {
636 // Don't duplicate packages if they are dependended on a diamond pattern
637 // N.B. if this line is ommitted, we try to analyse over 4_800_000 crates
638 // which is not ideal
639 if rustc_pkg_crates.contains_key(&pkg) {
642 for dep in &rustc_workspace[pkg].dependencies {
643 queue.push_back(dep.pkg);
645 for &tgt in rustc_workspace[pkg].targets.iter() {
646 if rustc_workspace[tgt].kind != TargetKind::Lib {
649 if let Some(file_id) = load(&rustc_workspace[tgt].root) {
650 let crate_id = add_target_crate_root(
652 &rustc_workspace[pkg],
653 rustc_build_data_map.and_then(|it| it.get(&rustc_workspace[pkg].id)),
657 &rustc_workspace[tgt].name,
659 pkg_to_lib_crate.insert(pkg, crate_id);
660 // Add dependencies on core / std / alloc for this crate
661 for (name, krate) in public_deps.iter() {
662 add_dep(crate_graph, crate_id, name.clone(), *krate);
664 rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
669 // Now add a dep edge from all targets of upstream to the lib
670 // target of downstream.
671 for pkg in rustc_pkg_crates.keys().copied() {
672 for dep in rustc_workspace[pkg].dependencies.iter() {
673 let name = CrateName::new(&dep.name).unwrap();
674 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
675 for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() {
676 add_dep(crate_graph, from, name.clone(), to);
681 // Add a dependency on the rustc_private crates for all targets of each package
683 for dep in rustc_workspace.packages() {
684 let name = CrateName::normalize_dashes(&rustc_workspace[dep].name);
686 if let Some(&to) = pkg_to_lib_crate.get(&dep) {
687 for pkg in cargo.packages() {
688 let package = &cargo[pkg];
689 if !package.metadata.rustc_private {
692 for (from, _) in pkg_crates.get(&pkg).into_iter().flatten() {
693 // Avoid creating duplicate dependencies
694 // This avoids the situation where `from` depends on e.g. `arrayvec`, but
695 // `rust_analyzer` thinks that it should use the one from the `rustcSource`
696 // instead of the one from `crates.io`
697 if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) {
698 add_dep(crate_graph, *from, name.clone(), to);
706 fn add_target_crate_root(
707 crate_graph: &mut CrateGraph,
708 pkg: &cargo_workspace::PackageData,
709 build_data: Option<&PackageBuildData>,
710 cfg_options: &CfgOptions,
711 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
715 let edition = pkg.edition;
717 let mut opts = cfg_options.clone();
718 for feature in pkg.active_features.iter() {
719 opts.insert_key_value("feature".into(), feature.into());
721 if let Some(cfgs) = build_data.as_ref().map(|it| &it.cfgs) {
722 opts.extend(cfgs.iter().cloned());
727 let mut env = Env::default();
728 if let Some(envs) = build_data.map(|it| &it.envs) {
730 env.set(k, v.clone());
734 let proc_macro = build_data
736 .and_then(|it| it.proc_macro_dylib_path.as_ref())
737 .map(|it| proc_macro_loader(it))
738 .unwrap_or_default();
740 let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string());
741 let mut potential_cfg_options = cfg_options.clone();
742 potential_cfg_options.extend(
745 .map(|feat| CfgFlag::KeyValue { key: "feature".into(), value: feat.0.into() }),
748 let crate_id = crate_graph.add_crate_root(
753 potential_cfg_options,
761 fn sysroot_to_crate_graph(
762 crate_graph: &mut CrateGraph,
764 rustc_cfg: Vec<CfgFlag>,
765 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
766 ) -> (Vec<(CrateName, CrateId)>, Option<CrateId>) {
767 let _p = profile::span("sysroot_to_crate_graph");
768 let mut cfg_options = CfgOptions::default();
769 cfg_options.extend(rustc_cfg);
770 let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot
772 .filter_map(|krate| {
773 let file_id = load(&sysroot[krate].root)?;
775 let env = Env::default();
776 let proc_macro = vec![];
777 let display_name = CrateDisplayName::from_canonical_name(sysroot[krate].name.clone());
778 let crate_id = crate_graph.add_crate_root(
780 Edition::Edition2018,
787 Some((krate, crate_id))
791 for from in sysroot.crates() {
792 for &to in sysroot[from].deps.iter() {
793 let name = CrateName::new(&sysroot[to].name).unwrap();
794 if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) {
795 add_dep(crate_graph, from, name, to);
800 let public_deps = sysroot
802 .map(|(name, idx)| (CrateName::new(name).unwrap(), sysroot_crates[&idx]))
803 .collect::<Vec<_>>();
805 let libproc_macro = sysroot.proc_macro().and_then(|it| sysroot_crates.get(&it).copied());
806 (public_deps, libproc_macro)
809 fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
810 if let Err(err) = graph.add_dep(from, name, to) {
811 log::error!("{}", err)