mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-26 11:59:49 +00:00
⬆️ rust-analyzer
This commit is contained in:
parent
3a57388d13
commit
4f55ebbd4f
122 changed files with 2885 additions and 1093 deletions
|
@ -15,7 +15,7 @@ use rustc_hash::FxHashMap;
|
|||
use semver::Version;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{cfg_flag::CfgFlag, CargoConfig, CargoWorkspace, Package};
|
||||
use crate::{cfg_flag::CfgFlag, CargoConfig, CargoFeatures, CargoWorkspace, Package};
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct WorkspaceBuildScripts {
|
||||
|
@ -49,7 +49,6 @@ impl WorkspaceBuildScripts {
|
|||
|
||||
let mut cmd = Command::new(toolchain::cargo());
|
||||
cmd.envs(&config.extra_env);
|
||||
|
||||
cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]);
|
||||
|
||||
// --all-targets includes tests, benches and examples in addition to the
|
||||
|
@ -61,15 +60,18 @@ impl WorkspaceBuildScripts {
|
|||
cmd.args(&["--target", target]);
|
||||
}
|
||||
|
||||
if config.all_features {
|
||||
cmd.arg("--all-features");
|
||||
} else {
|
||||
if config.no_default_features {
|
||||
cmd.arg("--no-default-features");
|
||||
match &config.features {
|
||||
CargoFeatures::All => {
|
||||
cmd.arg("--all-features");
|
||||
}
|
||||
if !config.features.is_empty() {
|
||||
cmd.arg("--features");
|
||||
cmd.arg(config.features.join(" "));
|
||||
CargoFeatures::Selected { features, no_default_features } => {
|
||||
if *no_default_features {
|
||||
cmd.arg("--no-default-features");
|
||||
}
|
||||
if !features.is_empty() {
|
||||
cmd.arg("--features");
|
||||
cmd.arg(features.join(" "));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,35 +71,40 @@ impl Default for UnsetTestCrates {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum CargoFeatures {
|
||||
All,
|
||||
Selected {
|
||||
/// List of features to activate.
|
||||
features: Vec<String>,
|
||||
/// Do not activate the `default` feature.
|
||||
no_default_features: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl Default for CargoFeatures {
|
||||
fn default() -> Self {
|
||||
CargoFeatures::Selected { features: vec![], no_default_features: false }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct CargoConfig {
|
||||
/// Do not activate the `default` feature.
|
||||
pub no_default_features: bool,
|
||||
|
||||
/// Activate all available features
|
||||
pub all_features: bool,
|
||||
|
||||
/// List of features to activate.
|
||||
/// This will be ignored if `cargo_all_features` is true.
|
||||
pub features: Vec<String>,
|
||||
|
||||
pub features: CargoFeatures,
|
||||
/// rustc target
|
||||
pub target: Option<String>,
|
||||
|
||||
/// Don't load sysroot crates (`std`, `core` & friends). Might be useful
|
||||
/// when debugging isolated issues.
|
||||
pub no_sysroot: bool,
|
||||
|
||||
/// Sysroot loading behavior
|
||||
pub sysroot: Option<RustcSource>,
|
||||
/// rustc private crate source
|
||||
pub rustc_source: Option<RustcSource>,
|
||||
|
||||
/// crates to disable `#[cfg(test)]` on
|
||||
pub unset_test_crates: UnsetTestCrates,
|
||||
|
||||
/// Invoke `cargo check` through the RUSTC_WRAPPER.
|
||||
pub wrap_rustc_in_build_scripts: bool,
|
||||
|
||||
/// The command to run instead of `cargo check` for building build scripts.
|
||||
pub run_build_script_command: Option<Vec<String>>,
|
||||
|
||||
/// Extra env vars to set when invoking the cargo command
|
||||
pub extra_env: FxHashMap<String, String>,
|
||||
}
|
||||
|
||||
|
@ -143,7 +148,7 @@ pub struct PackageData {
|
|||
pub targets: Vec<Target>,
|
||||
/// Does this package come from the local filesystem (and is editable)?
|
||||
pub is_local: bool,
|
||||
// Whether this package is a member of the workspace
|
||||
/// Whether this package is a member of the workspace
|
||||
pub is_member: bool,
|
||||
/// List of packages this package depends on
|
||||
pub dependencies: Vec<PackageDependency>,
|
||||
|
@ -249,8 +254,8 @@ impl TargetKind {
|
|||
}
|
||||
}
|
||||
|
||||
// Deserialize helper for the cargo metadata
|
||||
#[derive(Deserialize, Default)]
|
||||
// Deserialise helper for the cargo metadata
|
||||
struct PackageMetadata {
|
||||
#[serde(rename = "rust-analyzer")]
|
||||
rust_analyzer: Option<RustAnalyzerPackageMetaData>,
|
||||
|
@ -266,22 +271,25 @@ impl CargoWorkspace {
|
|||
let target = config
|
||||
.target
|
||||
.clone()
|
||||
.or_else(|| cargo_config_build_target(cargo_toml, config))
|
||||
.or_else(|| rustc_discover_host_triple(cargo_toml, config));
|
||||
.or_else(|| cargo_config_build_target(cargo_toml, &config.extra_env))
|
||||
.or_else(|| rustc_discover_host_triple(cargo_toml, &config.extra_env));
|
||||
|
||||
let mut meta = MetadataCommand::new();
|
||||
meta.cargo_path(toolchain::cargo());
|
||||
meta.manifest_path(cargo_toml.to_path_buf());
|
||||
if config.all_features {
|
||||
meta.features(CargoOpt::AllFeatures);
|
||||
} else {
|
||||
if config.no_default_features {
|
||||
// FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
|
||||
// https://github.com/oli-obk/cargo_metadata/issues/79
|
||||
meta.features(CargoOpt::NoDefaultFeatures);
|
||||
match &config.features {
|
||||
CargoFeatures::All => {
|
||||
meta.features(CargoOpt::AllFeatures);
|
||||
}
|
||||
if !config.features.is_empty() {
|
||||
meta.features(CargoOpt::SomeFeatures(config.features.clone()));
|
||||
CargoFeatures::Selected { features, no_default_features } => {
|
||||
if *no_default_features {
|
||||
// FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
|
||||
// https://github.com/oli-obk/cargo_metadata/issues/79
|
||||
meta.features(CargoOpt::NoDefaultFeatures);
|
||||
}
|
||||
if !features.is_empty() {
|
||||
meta.features(CargoOpt::SomeFeatures(features.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
meta.current_dir(current_dir.as_os_str());
|
||||
|
@ -295,12 +303,9 @@ impl CargoWorkspace {
|
|||
// unclear whether cargo itself supports it.
|
||||
progress("metadata".to_string());
|
||||
|
||||
fn exec_with_env(
|
||||
command: &cargo_metadata::MetadataCommand,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
) -> Result<cargo_metadata::Metadata, cargo_metadata::Error> {
|
||||
let mut command = command.cargo_command();
|
||||
command.envs(extra_env);
|
||||
(|| -> Result<cargo_metadata::Metadata, cargo_metadata::Error> {
|
||||
let mut command = meta.cargo_command();
|
||||
command.envs(&config.extra_env);
|
||||
let output = command.output()?;
|
||||
if !output.status.success() {
|
||||
return Err(cargo_metadata::Error::CargoMetadata {
|
||||
|
@ -312,12 +317,8 @@ impl CargoWorkspace {
|
|||
.find(|line| line.starts_with('{'))
|
||||
.ok_or(cargo_metadata::Error::NoJson)?;
|
||||
cargo_metadata::MetadataCommand::parse(stdout)
|
||||
}
|
||||
|
||||
let meta = exec_with_env(&meta, &config.extra_env)
|
||||
.with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))?;
|
||||
|
||||
Ok(meta)
|
||||
})()
|
||||
.with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))
|
||||
}
|
||||
|
||||
pub fn new(mut meta: cargo_metadata::Metadata) -> CargoWorkspace {
|
||||
|
@ -386,32 +387,14 @@ impl CargoWorkspace {
|
|||
}
|
||||
let resolve = meta.resolve.expect("metadata executed with deps");
|
||||
for mut node in resolve.nodes {
|
||||
let source = match pkg_by_id.get(&node.id) {
|
||||
Some(&src) => src,
|
||||
// FIXME: replace this and a similar branch below with `.unwrap`, once
|
||||
// https://github.com/rust-lang/cargo/issues/7841
|
||||
// is fixed and hits stable (around 1.43-is probably?).
|
||||
None => {
|
||||
tracing::error!("Node id do not match in cargo metadata, ignoring {}", node.id);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let &source = pkg_by_id.get(&node.id).unwrap();
|
||||
node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg));
|
||||
for (dep_node, kind) in node
|
||||
let dependencies = node
|
||||
.deps
|
||||
.iter()
|
||||
.flat_map(|dep| DepKind::iter(&dep.dep_kinds).map(move |kind| (dep, kind)))
|
||||
{
|
||||
let pkg = match pkg_by_id.get(&dep_node.pkg) {
|
||||
Some(&pkg) => pkg,
|
||||
None => {
|
||||
tracing::error!(
|
||||
"Dep node id do not match in cargo metadata, ignoring {}",
|
||||
dep_node.pkg
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
.flat_map(|dep| DepKind::iter(&dep.dep_kinds).map(move |kind| (dep, kind)));
|
||||
for (dep_node, kind) in dependencies {
|
||||
let &pkg = pkg_by_id.get(&dep_node.pkg).unwrap();
|
||||
let dep = PackageDependency { name: dep_node.name.clone(), pkg, kind };
|
||||
packages[source].dependencies.push(dep);
|
||||
}
|
||||
|
@ -456,10 +439,7 @@ impl CargoWorkspace {
|
|||
found = true
|
||||
}
|
||||
self[pkg].dependencies.iter().find_map(|dep| {
|
||||
if &self[dep.pkg].manifest == manifest_path {
|
||||
return Some(self[pkg].manifest.clone());
|
||||
}
|
||||
None
|
||||
(&self[dep.pkg].manifest == manifest_path).then(|| self[pkg].manifest.clone())
|
||||
})
|
||||
})
|
||||
.collect::<Vec<ManifestPath>>();
|
||||
|
@ -485,9 +465,12 @@ impl CargoWorkspace {
|
|||
}
|
||||
}
|
||||
|
||||
fn rustc_discover_host_triple(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option<String> {
|
||||
fn rustc_discover_host_triple(
|
||||
cargo_toml: &ManifestPath,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
) -> Option<String> {
|
||||
let mut rustc = Command::new(toolchain::rustc());
|
||||
rustc.envs(&config.extra_env);
|
||||
rustc.envs(extra_env);
|
||||
rustc.current_dir(cargo_toml.parent()).arg("-vV");
|
||||
tracing::debug!("Discovering host platform by {:?}", rustc);
|
||||
match utf8_stdout(rustc) {
|
||||
|
@ -509,9 +492,12 @@ fn rustc_discover_host_triple(cargo_toml: &ManifestPath, config: &CargoConfig) -
|
|||
}
|
||||
}
|
||||
|
||||
fn cargo_config_build_target(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option<String> {
|
||||
fn cargo_config_build_target(
|
||||
cargo_toml: &ManifestPath,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
) -> Option<String> {
|
||||
let mut cargo_config = Command::new(toolchain::cargo());
|
||||
cargo_config.envs(&config.extra_env);
|
||||
cargo_config.envs(extra_env);
|
||||
cargo_config
|
||||
.current_dir(cargo_toml.parent())
|
||||
.args(&["-Z", "unstable-options", "config", "get", "build.target"])
|
||||
|
|
|
@ -42,8 +42,8 @@ use rustc_hash::FxHashSet;
|
|||
pub use crate::{
|
||||
build_scripts::WorkspaceBuildScripts,
|
||||
cargo_workspace::{
|
||||
CargoConfig, CargoWorkspace, Package, PackageData, PackageDependency, RustcSource, Target,
|
||||
TargetData, TargetKind, UnsetTestCrates,
|
||||
CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency,
|
||||
RustcSource, Target, TargetData, TargetKind, UnsetTestCrates,
|
||||
},
|
||||
manifest_path::ManifestPath,
|
||||
project_json::{ProjectJson, ProjectJsonData},
|
||||
|
|
|
@ -110,14 +110,17 @@ impl ProjectJson {
|
|||
.collect::<Vec<_>>(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of crates in the project.
|
||||
pub fn n_crates(&self) -> usize {
|
||||
self.crates.len()
|
||||
}
|
||||
|
||||
/// Returns an iterator over the crates in the project.
|
||||
pub fn crates(&self) -> impl Iterator<Item = (CrateId, &Crate)> + '_ {
|
||||
self.crates.iter().enumerate().map(|(idx, krate)| (CrateId(idx as u32), krate))
|
||||
}
|
||||
|
||||
/// Returns the path to the project's root folder.
|
||||
pub fn path(&self) -> &AbsPath {
|
||||
&self.project_root
|
||||
|
|
|
@ -3,13 +3,14 @@
|
|||
use std::process::Command;
|
||||
|
||||
use anyhow::Result;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{cfg_flag::CfgFlag, utf8_stdout, CargoConfig, ManifestPath};
|
||||
use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath};
|
||||
|
||||
pub(crate) fn get(
|
||||
cargo_toml: Option<&ManifestPath>,
|
||||
target: Option<&str>,
|
||||
config: &CargoConfig,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
) -> Vec<CfgFlag> {
|
||||
let _p = profile::span("rustc_cfg::get");
|
||||
let mut res = Vec::with_capacity(6 * 2 + 1);
|
||||
|
@ -22,7 +23,7 @@ pub(crate) fn get(
|
|||
}
|
||||
}
|
||||
|
||||
match get_rust_cfgs(cargo_toml, target, config) {
|
||||
match get_rust_cfgs(cargo_toml, target, extra_env) {
|
||||
Ok(rustc_cfgs) => {
|
||||
tracing::debug!(
|
||||
"rustc cfgs found: {:?}",
|
||||
|
@ -42,11 +43,11 @@ pub(crate) fn get(
|
|||
fn get_rust_cfgs(
|
||||
cargo_toml: Option<&ManifestPath>,
|
||||
target: Option<&str>,
|
||||
config: &CargoConfig,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
) -> Result<String> {
|
||||
if let Some(cargo_toml) = cargo_toml {
|
||||
let mut cargo_config = Command::new(toolchain::cargo());
|
||||
cargo_config.envs(&config.extra_env);
|
||||
cargo_config.envs(extra_env);
|
||||
cargo_config
|
||||
.current_dir(cargo_toml.parent())
|
||||
.args(&["-Z", "unstable-options", "rustc", "--print", "cfg"])
|
||||
|
@ -61,7 +62,7 @@ fn get_rust_cfgs(
|
|||
}
|
||||
// using unstable cargo features failed, fall back to using plain rustc
|
||||
let mut cmd = Command::new(toolchain::rustc());
|
||||
cmd.envs(&config.extra_env);
|
||||
cmd.envs(extra_env);
|
||||
cmd.args(&["--print", "cfg", "-O"]);
|
||||
if let Some(target) = target {
|
||||
cmd.args(&["--target", target]);
|
||||
|
|
|
@ -9,8 +9,9 @@ use std::{env, fs, iter, ops, path::PathBuf, process::Command};
|
|||
use anyhow::{format_err, Result};
|
||||
use la_arena::{Arena, Idx};
|
||||
use paths::{AbsPath, AbsPathBuf};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{utf8_stdout, CargoConfig, ManifestPath};
|
||||
use crate::{utf8_stdout, ManifestPath};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Sysroot {
|
||||
|
@ -66,23 +67,37 @@ impl Sysroot {
|
|||
pub fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + 'a {
|
||||
self.crates.iter().map(|(id, _data)| id)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn discover(dir: &AbsPath, config: &CargoConfig) -> Result<Sysroot> {
|
||||
impl Sysroot {
|
||||
pub fn discover(dir: &AbsPath, extra_env: &FxHashMap<String, String>) -> Result<Sysroot> {
|
||||
tracing::debug!("Discovering sysroot for {}", dir.display());
|
||||
let sysroot_dir = discover_sysroot_dir(dir, config)?;
|
||||
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, dir, config)?;
|
||||
let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
|
||||
let sysroot_src_dir =
|
||||
discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env)?;
|
||||
let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn discover_rustc(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option<ManifestPath> {
|
||||
pub fn discover_rustc(
|
||||
cargo_toml: &ManifestPath,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
) -> Option<ManifestPath> {
|
||||
tracing::debug!("Discovering rustc source for {}", cargo_toml.display());
|
||||
let current_dir = cargo_toml.parent();
|
||||
discover_sysroot_dir(current_dir, config)
|
||||
discover_sysroot_dir(current_dir, extra_env)
|
||||
.ok()
|
||||
.and_then(|sysroot_dir| get_rustc_src(&sysroot_dir))
|
||||
}
|
||||
|
||||
pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf) -> Result<Sysroot> {
|
||||
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| {
|
||||
format_err!("can't load standard library from sysroot {}", sysroot_dir.display())
|
||||
})?;
|
||||
let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Result<Sysroot> {
|
||||
let mut sysroot =
|
||||
Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() };
|
||||
|
@ -146,35 +161,43 @@ impl Sysroot {
|
|||
}
|
||||
}
|
||||
|
||||
fn discover_sysroot_dir(current_dir: &AbsPath, config: &CargoConfig) -> Result<AbsPathBuf> {
|
||||
fn discover_sysroot_dir(
|
||||
current_dir: &AbsPath,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
) -> Result<AbsPathBuf> {
|
||||
let mut rustc = Command::new(toolchain::rustc());
|
||||
rustc.envs(&config.extra_env);
|
||||
rustc.envs(extra_env);
|
||||
rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
|
||||
tracing::debug!("Discovering sysroot by {:?}", rustc);
|
||||
let stdout = utf8_stdout(rustc)?;
|
||||
Ok(AbsPathBuf::assert(PathBuf::from(stdout)))
|
||||
}
|
||||
|
||||
fn discover_sysroot_src_dir(
|
||||
sysroot_path: &AbsPathBuf,
|
||||
current_dir: &AbsPath,
|
||||
config: &CargoConfig,
|
||||
) -> Result<AbsPathBuf> {
|
||||
fn discover_sysroot_src_dir(sysroot_path: &AbsPathBuf) -> Option<AbsPathBuf> {
|
||||
if let Ok(path) = env::var("RUST_SRC_PATH") {
|
||||
let path = AbsPathBuf::try_from(path.as_str())
|
||||
.map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?;
|
||||
let core = path.join("core");
|
||||
if fs::metadata(&core).is_ok() {
|
||||
tracing::debug!("Discovered sysroot by RUST_SRC_PATH: {}", path.display());
|
||||
return Ok(path);
|
||||
if let Ok(path) = AbsPathBuf::try_from(path.as_str()) {
|
||||
let core = path.join("core");
|
||||
if fs::metadata(&core).is_ok() {
|
||||
tracing::debug!("Discovered sysroot by RUST_SRC_PATH: {}", path.display());
|
||||
return Some(path);
|
||||
}
|
||||
tracing::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core);
|
||||
} else {
|
||||
tracing::debug!("RUST_SRC_PATH is set, but is invalid, ignoring");
|
||||
}
|
||||
tracing::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core);
|
||||
}
|
||||
|
||||
get_rust_src(sysroot_path)
|
||||
}
|
||||
fn discover_sysroot_src_dir_or_add_component(
|
||||
sysroot_path: &AbsPathBuf,
|
||||
current_dir: &AbsPath,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
) -> Result<AbsPathBuf> {
|
||||
discover_sysroot_src_dir(sysroot_path)
|
||||
.or_else(|| {
|
||||
let mut rustup = Command::new(toolchain::rustup());
|
||||
rustup.envs(&config.extra_env);
|
||||
rustup.envs(extra_env);
|
||||
rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]);
|
||||
utf8_stdout(rustup).ok()?;
|
||||
get_rust_src(sysroot_path)
|
||||
|
|
|
@ -10,8 +10,8 @@ use paths::{AbsPath, AbsPathBuf};
|
|||
use serde::de::DeserializeOwned;
|
||||
|
||||
use crate::{
|
||||
CargoConfig, CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace,
|
||||
Sysroot, WorkspaceBuildScripts,
|
||||
CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot,
|
||||
WorkspaceBuildScripts,
|
||||
};
|
||||
|
||||
fn load_cargo(file: &str) -> CrateGraph {
|
||||
|
@ -101,7 +101,7 @@ fn to_crate_graph(project_workspace: ProjectWorkspace) -> CrateGraph {
|
|||
Some(FileId(counter))
|
||||
}
|
||||
},
|
||||
&CargoConfig::default(),
|
||||
&Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -185,6 +185,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
|
|||
),
|
||||
origin: CratesIo {
|
||||
repo: None,
|
||||
name: Some(
|
||||
"hello-world",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -260,6 +263,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
|
|||
),
|
||||
origin: CratesIo {
|
||||
repo: None,
|
||||
name: Some(
|
||||
"hello-world",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -335,6 +341,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
|
|||
),
|
||||
origin: CratesIo {
|
||||
repo: None,
|
||||
name: Some(
|
||||
"hello-world",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -410,6 +419,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
|
|||
),
|
||||
origin: CratesIo {
|
||||
repo: None,
|
||||
name: Some(
|
||||
"hello-world",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -477,6 +489,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
|
|||
repo: Some(
|
||||
"https://github.com/rust-lang/libc",
|
||||
),
|
||||
name: Some(
|
||||
"libc",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -567,6 +582,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
|
|||
),
|
||||
origin: CratesIo {
|
||||
repo: None,
|
||||
name: Some(
|
||||
"hello-world",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -644,6 +662,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
|
|||
),
|
||||
origin: CratesIo {
|
||||
repo: None,
|
||||
name: Some(
|
||||
"hello-world",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -721,6 +742,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
|
|||
),
|
||||
origin: CratesIo {
|
||||
repo: None,
|
||||
name: Some(
|
||||
"hello-world",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -798,6 +822,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
|
|||
),
|
||||
origin: CratesIo {
|
||||
repo: None,
|
||||
name: Some(
|
||||
"hello-world",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -865,6 +892,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
|
|||
repo: Some(
|
||||
"https://github.com/rust-lang/libc",
|
||||
),
|
||||
name: Some(
|
||||
"libc",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -946,6 +976,9 @@ fn cargo_hello_world_project_model() {
|
|||
),
|
||||
origin: CratesIo {
|
||||
repo: None,
|
||||
name: Some(
|
||||
"hello-world",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -1023,6 +1056,9 @@ fn cargo_hello_world_project_model() {
|
|||
),
|
||||
origin: CratesIo {
|
||||
repo: None,
|
||||
name: Some(
|
||||
"hello-world",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -1100,6 +1136,9 @@ fn cargo_hello_world_project_model() {
|
|||
),
|
||||
origin: CratesIo {
|
||||
repo: None,
|
||||
name: Some(
|
||||
"hello-world",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -1177,6 +1216,9 @@ fn cargo_hello_world_project_model() {
|
|||
),
|
||||
origin: CratesIo {
|
||||
repo: None,
|
||||
name: Some(
|
||||
"hello-world",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -1244,6 +1286,9 @@ fn cargo_hello_world_project_model() {
|
|||
repo: Some(
|
||||
"https://github.com/rust-lang/libc",
|
||||
),
|
||||
name: Some(
|
||||
"libc",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
@ -1804,6 +1849,9 @@ fn rust_project_hello_world_project_model() {
|
|||
),
|
||||
origin: CratesIo {
|
||||
repo: None,
|
||||
name: Some(
|
||||
"hello_world",
|
||||
),
|
||||
},
|
||||
is_proc_macro: false,
|
||||
},
|
||||
|
|
|
@ -21,8 +21,8 @@ use crate::{
|
|||
cfg_flag::CfgFlag,
|
||||
rustc_cfg,
|
||||
sysroot::SysrootCrate,
|
||||
utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath, ProjectJson, ProjectManifest, Sysroot,
|
||||
TargetKind, WorkspaceBuildScripts,
|
||||
utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath, Package, ProjectJson, ProjectManifest,
|
||||
Sysroot, TargetKind, WorkspaceBuildScripts,
|
||||
};
|
||||
|
||||
/// A set of cfg-overrides per crate.
|
||||
|
@ -156,7 +156,11 @@ impl ProjectWorkspace {
|
|||
})?;
|
||||
let project_location = project_json.parent().to_path_buf();
|
||||
let project_json = ProjectJson::new(&project_location, data);
|
||||
ProjectWorkspace::load_inline(project_json, config.target.as_deref(), config)?
|
||||
ProjectWorkspace::load_inline(
|
||||
project_json,
|
||||
config.target.as_deref(),
|
||||
&config.extra_env,
|
||||
)?
|
||||
}
|
||||
ProjectManifest::CargoToml(cargo_toml) => {
|
||||
let cargo_version = utf8_stdout({
|
||||
|
@ -184,20 +188,33 @@ impl ProjectWorkspace {
|
|||
})?;
|
||||
let cargo = CargoWorkspace::new(meta);
|
||||
|
||||
let sysroot = if config.no_sysroot {
|
||||
None
|
||||
} else {
|
||||
Some(Sysroot::discover(cargo_toml.parent(), config).with_context(|| {
|
||||
format!(
|
||||
let sysroot = match &config.sysroot {
|
||||
Some(RustcSource::Path(path)) => {
|
||||
Some(Sysroot::with_sysroot_dir(path.clone()).with_context(|| {
|
||||
format!(
|
||||
"Failed to find sysroot for Cargo.toml file {}.",
|
||||
cargo_toml.display()
|
||||
)
|
||||
})?)
|
||||
}
|
||||
Some(RustcSource::Discover) => Some(
|
||||
Sysroot::discover(cargo_toml.parent(), &config.extra_env).with_context(
|
||||
|| {
|
||||
format!(
|
||||
"Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
|
||||
cargo_toml.display()
|
||||
)
|
||||
})?)
|
||||
},
|
||||
)?,
|
||||
),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let rustc_dir = match &config.rustc_source {
|
||||
Some(RustcSource::Path(path)) => ManifestPath::try_from(path.clone()).ok(),
|
||||
Some(RustcSource::Discover) => Sysroot::discover_rustc(&cargo_toml, config),
|
||||
Some(RustcSource::Discover) => {
|
||||
Sysroot::discover_rustc(&cargo_toml, &config.extra_env)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
|
@ -217,7 +234,8 @@ impl ProjectWorkspace {
|
|||
None => None,
|
||||
};
|
||||
|
||||
let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), config);
|
||||
let rustc_cfg =
|
||||
rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), &config.extra_env);
|
||||
|
||||
let cfg_overrides = config.cfg_overrides();
|
||||
ProjectWorkspace::Cargo {
|
||||
|
@ -238,7 +256,7 @@ impl ProjectWorkspace {
|
|||
pub fn load_inline(
|
||||
project_json: ProjectJson,
|
||||
target: Option<&str>,
|
||||
config: &CargoConfig,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
) -> Result<ProjectWorkspace> {
|
||||
let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
|
||||
(Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)?),
|
||||
|
@ -260,7 +278,7 @@ impl ProjectWorkspace {
|
|||
(None, None) => None,
|
||||
};
|
||||
|
||||
let rustc_cfg = rustc_cfg::get(None, target, config);
|
||||
let rustc_cfg = rustc_cfg::get(None, target, extra_env);
|
||||
Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
|
||||
}
|
||||
|
||||
|
@ -270,9 +288,9 @@ impl ProjectWorkspace {
|
|||
.first()
|
||||
.and_then(|it| it.parent())
|
||||
.ok_or_else(|| format_err!("No detached files to load"))?,
|
||||
&CargoConfig::default(),
|
||||
&Default::default(),
|
||||
)?;
|
||||
let rustc_cfg = rustc_cfg::get(None, None, &CargoConfig::default());
|
||||
let rustc_cfg = rustc_cfg::get(None, None, &Default::default());
|
||||
Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
|
||||
}
|
||||
|
||||
|
@ -306,6 +324,13 @@ impl ProjectWorkspace {
|
|||
/// The return type contains the path and whether or not
|
||||
/// the root is a member of the current workspace
|
||||
pub fn to_roots(&self) -> Vec<PackageRoot> {
|
||||
let mk_sysroot = |sysroot: Option<&Sysroot>| {
|
||||
sysroot.map(|sysroot| PackageRoot {
|
||||
is_local: false,
|
||||
include: vec![sysroot.src_root().to_path_buf()],
|
||||
exclude: Vec::new(),
|
||||
})
|
||||
};
|
||||
match self {
|
||||
ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project
|
||||
.crates()
|
||||
|
@ -316,13 +341,7 @@ impl ProjectWorkspace {
|
|||
})
|
||||
.collect::<FxHashSet<_>>()
|
||||
.into_iter()
|
||||
.chain(sysroot.as_ref().into_iter().flat_map(|sysroot| {
|
||||
sysroot.crates().map(move |krate| PackageRoot {
|
||||
is_local: false,
|
||||
include: vec![sysroot[krate].root.parent().to_path_buf()],
|
||||
exclude: Vec::new(),
|
||||
})
|
||||
}))
|
||||
.chain(mk_sysroot(sysroot.as_ref()))
|
||||
.collect::<Vec<_>>(),
|
||||
ProjectWorkspace::Cargo {
|
||||
cargo,
|
||||
|
@ -371,11 +390,7 @@ impl ProjectWorkspace {
|
|||
}
|
||||
PackageRoot { is_local, include, exclude }
|
||||
})
|
||||
.chain(sysroot.iter().map(|sysroot| PackageRoot {
|
||||
is_local: false,
|
||||
include: vec![sysroot.src_root().to_path_buf()],
|
||||
exclude: Vec::new(),
|
||||
}))
|
||||
.chain(mk_sysroot(sysroot.as_ref()))
|
||||
.chain(rustc.iter().flat_map(|rustc| {
|
||||
rustc.packages().map(move |krate| PackageRoot {
|
||||
is_local: false,
|
||||
|
@ -392,11 +407,7 @@ impl ProjectWorkspace {
|
|||
include: vec![detached_file.clone()],
|
||||
exclude: Vec::new(),
|
||||
})
|
||||
.chain(sysroot.crates().map(|krate| PackageRoot {
|
||||
is_local: false,
|
||||
include: vec![sysroot[krate].root.parent().to_path_buf()],
|
||||
exclude: Vec::new(),
|
||||
}))
|
||||
.chain(mk_sysroot(Some(sysroot)))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
@ -419,7 +430,7 @@ impl ProjectWorkspace {
|
|||
&self,
|
||||
load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
|
||||
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
|
||||
config: &CargoConfig,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
) -> CrateGraph {
|
||||
let _p = profile::span("ProjectWorkspace::to_crate_graph");
|
||||
|
||||
|
@ -430,7 +441,7 @@ impl ProjectWorkspace {
|
|||
load,
|
||||
project,
|
||||
sysroot,
|
||||
config,
|
||||
extra_env,
|
||||
),
|
||||
ProjectWorkspace::Cargo {
|
||||
cargo,
|
||||
|
@ -469,7 +480,7 @@ fn project_json_to_crate_graph(
|
|||
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
|
||||
project: &ProjectJson,
|
||||
sysroot: &Option<Sysroot>,
|
||||
config: &CargoConfig,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
) -> CrateGraph {
|
||||
let mut crate_graph = CrateGraph::default();
|
||||
let sysroot_deps = sysroot
|
||||
|
@ -497,7 +508,7 @@ fn project_json_to_crate_graph(
|
|||
let target_cfgs = match krate.target.as_deref() {
|
||||
Some(target) => cfg_cache
|
||||
.entry(target)
|
||||
.or_insert_with(|| rustc_cfg::get(None, Some(target), config)),
|
||||
.or_insert_with(|| rustc_cfg::get(None, Some(target), extra_env)),
|
||||
None => &rustc_cfg,
|
||||
};
|
||||
|
||||
|
@ -516,9 +527,15 @@ fn project_json_to_crate_graph(
|
|||
proc_macro,
|
||||
krate.is_proc_macro,
|
||||
if krate.display_name.is_some() {
|
||||
CrateOrigin::CratesIo { repo: krate.repository.clone() }
|
||||
CrateOrigin::CratesIo {
|
||||
repo: krate.repository.clone(),
|
||||
name: krate
|
||||
.display_name
|
||||
.clone()
|
||||
.map(|n| n.canonical_name().to_string()),
|
||||
}
|
||||
} else {
|
||||
CrateOrigin::CratesIo { repo: None }
|
||||
CrateOrigin::CratesIo { repo: None, name: None }
|
||||
},
|
||||
),
|
||||
)
|
||||
|
@ -630,6 +647,8 @@ fn cargo_to_crate_graph(
|
|||
lib_tgt = Some((crate_id, cargo[tgt].name.clone()));
|
||||
pkg_to_lib_crate.insert(pkg, crate_id);
|
||||
}
|
||||
// Even crates that don't set proc-macro = true are allowed to depend on proc_macro
|
||||
// (just none of the APIs work when called outside of a proc macro).
|
||||
if let Some(proc_macro) = libproc_macro {
|
||||
add_dep_with_prelude(
|
||||
&mut crate_graph,
|
||||
|
@ -645,19 +664,19 @@ fn cargo_to_crate_graph(
|
|||
}
|
||||
|
||||
// Set deps to the core, std and to the lib target of the current package
|
||||
for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
|
||||
for &(from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
|
||||
// Add sysroot deps first so that a lib target named `core` etc. can overwrite them.
|
||||
public_deps.add(*from, &mut crate_graph);
|
||||
public_deps.add(from, &mut crate_graph);
|
||||
|
||||
if let Some((to, name)) = lib_tgt.clone() {
|
||||
if to != *from && *kind != TargetKind::BuildScript {
|
||||
if to != from && kind != TargetKind::BuildScript {
|
||||
// (build script can not depend on its library target)
|
||||
|
||||
// For root projects with dashes in their name,
|
||||
// cargo metadata does not do any normalization,
|
||||
// so we do it ourselves currently
|
||||
let name = CrateName::normalize_dashes(&name);
|
||||
add_dep(&mut crate_graph, *from, name, to);
|
||||
add_dep(&mut crate_graph, from, name, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -669,17 +688,17 @@ fn cargo_to_crate_graph(
|
|||
for dep in cargo[pkg].dependencies.iter() {
|
||||
let name = CrateName::new(&dep.name).unwrap();
|
||||
if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
|
||||
for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
|
||||
if dep.kind == DepKind::Build && *kind != TargetKind::BuildScript {
|
||||
for &(from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
|
||||
if dep.kind == DepKind::Build && kind != TargetKind::BuildScript {
|
||||
// Only build scripts may depend on build dependencies.
|
||||
continue;
|
||||
}
|
||||
if dep.kind != DepKind::Build && *kind == TargetKind::BuildScript {
|
||||
if dep.kind != DepKind::Build && kind == TargetKind::BuildScript {
|
||||
// Build scripts may only depend on build dependencies.
|
||||
continue;
|
||||
}
|
||||
|
||||
add_dep(&mut crate_graph, *from, name.clone(), to)
|
||||
add_dep(&mut crate_graph, from, name.clone(), to)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -690,9 +709,9 @@ fn cargo_to_crate_graph(
|
|||
// and create dependencies on them for the crates which opt-in to that
|
||||
if let Some(rustc_workspace) = rustc {
|
||||
handle_rustc_crates(
|
||||
&mut crate_graph,
|
||||
rustc_workspace,
|
||||
load,
|
||||
&mut crate_graph,
|
||||
&cfg_options,
|
||||
override_cfg,
|
||||
load_proc_macro,
|
||||
|
@ -736,14 +755,17 @@ fn detached_files_to_crate_graph(
|
|||
let detached_file_crate = crate_graph.add_crate_root(
|
||||
file_id,
|
||||
Edition::CURRENT,
|
||||
display_name,
|
||||
display_name.clone(),
|
||||
None,
|
||||
cfg_options.clone(),
|
||||
cfg_options.clone(),
|
||||
Env::default(),
|
||||
Ok(Vec::new()),
|
||||
false,
|
||||
CrateOrigin::CratesIo { repo: None },
|
||||
CrateOrigin::CratesIo {
|
||||
repo: None,
|
||||
name: display_name.map(|n| n.canonical_name().to_string()),
|
||||
},
|
||||
);
|
||||
|
||||
public_deps.add(detached_file_crate, &mut crate_graph);
|
||||
|
@ -752,16 +774,16 @@ fn detached_files_to_crate_graph(
|
|||
}
|
||||
|
||||
fn handle_rustc_crates(
|
||||
crate_graph: &mut CrateGraph,
|
||||
rustc_workspace: &CargoWorkspace,
|
||||
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
|
||||
crate_graph: &mut CrateGraph,
|
||||
cfg_options: &CfgOptions,
|
||||
override_cfg: &CfgOverrides,
|
||||
load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
|
||||
pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
|
||||
pkg_to_lib_crate: &mut FxHashMap<Package, CrateId>,
|
||||
public_deps: &SysrootPublicDeps,
|
||||
cargo: &CargoWorkspace,
|
||||
pkg_crates: &FxHashMap<la_arena::Idx<crate::PackageData>, Vec<(CrateId, TargetKind)>>,
|
||||
pkg_crates: &FxHashMap<Package, Vec<(CrateId, TargetKind)>>,
|
||||
build_scripts: &WorkspaceBuildScripts,
|
||||
) {
|
||||
let mut rustc_pkg_crates = FxHashMap::default();
|
||||
|
@ -775,8 +797,8 @@ fn handle_rustc_crates(
|
|||
let mut queue = VecDeque::new();
|
||||
queue.push_back(root_pkg);
|
||||
while let Some(pkg) = queue.pop_front() {
|
||||
// Don't duplicate packages if they are dependended on a diamond pattern
|
||||
// N.B. if this line is omitted, we try to analyse over 4_800_000 crates
|
||||
// Don't duplicate packages if they are dependent on a diamond pattern
|
||||
// N.B. if this line is omitted, we try to analyze over 4_800_000 crates
|
||||
// which is not ideal
|
||||
if rustc_pkg_crates.contains_key(&pkg) {
|
||||
continue;
|
||||
|
@ -919,7 +941,7 @@ fn add_target_crate_root(
|
|||
env,
|
||||
proc_macro,
|
||||
is_proc_macro,
|
||||
CrateOrigin::CratesIo { repo: pkg.repository.clone() },
|
||||
CrateOrigin::CratesIo { repo: pkg.repository.clone(), name: Some(pkg.name.clone()) },
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue