mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-26 11:59:49 +00:00
Merge commit 'aa9bc86125
' into sync-from-ra
This commit is contained in:
parent
1570299af4
commit
c48062fe2a
598 changed files with 57696 additions and 17615 deletions
|
@ -14,9 +14,10 @@ use std::{
|
|||
};
|
||||
|
||||
use cargo_metadata::{camino::Utf8Path, Message};
|
||||
use itertools::Itertools;
|
||||
use la_arena::ArenaMap;
|
||||
use paths::{AbsPath, AbsPathBuf};
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use semver::Version;
|
||||
use serde::Deserialize;
|
||||
|
||||
|
@ -56,7 +57,10 @@ impl BuildScriptOutput {
|
|||
}
|
||||
|
||||
impl WorkspaceBuildScripts {
|
||||
fn build_command(config: &CargoConfig) -> io::Result<Command> {
|
||||
fn build_command(
|
||||
config: &CargoConfig,
|
||||
allowed_features: &FxHashSet<String>,
|
||||
) -> io::Result<Command> {
|
||||
let mut cmd = match config.run_build_script_command.as_deref() {
|
||||
Some([program, args @ ..]) => {
|
||||
let mut cmd = Command::new(program);
|
||||
|
@ -88,7 +92,12 @@ impl WorkspaceBuildScripts {
|
|||
}
|
||||
if !features.is_empty() {
|
||||
cmd.arg("--features");
|
||||
cmd.arg(features.join(" "));
|
||||
cmd.arg(
|
||||
features
|
||||
.iter()
|
||||
.filter(|&feat| allowed_features.contains(feat))
|
||||
.join(","),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,13 +136,20 @@ impl WorkspaceBuildScripts {
|
|||
}
|
||||
.as_ref();
|
||||
|
||||
match Self::run_per_ws(Self::build_command(config)?, workspace, current_dir, progress) {
|
||||
let allowed_features = workspace.workspace_features();
|
||||
|
||||
match Self::run_per_ws(
|
||||
Self::build_command(config, &allowed_features)?,
|
||||
workspace,
|
||||
current_dir,
|
||||
progress,
|
||||
) {
|
||||
Ok(WorkspaceBuildScripts { error: Some(error), .. })
|
||||
if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) =>
|
||||
{
|
||||
// building build scripts failed, attempt to build with --keep-going so
|
||||
// that we potentially get more build data
|
||||
let mut cmd = Self::build_command(config)?;
|
||||
let mut cmd = Self::build_command(config, &allowed_features)?;
|
||||
cmd.args(["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
|
||||
let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?;
|
||||
res.error = Some(error);
|
||||
|
@ -161,7 +177,7 @@ impl WorkspaceBuildScripts {
|
|||
))
|
||||
}
|
||||
};
|
||||
let cmd = Self::build_command(config)?;
|
||||
let cmd = Self::build_command(config, &Default::default())?;
|
||||
// NB: Cargo.toml could have been modified between `cargo metadata` and
|
||||
// `cargo check`. We shouldn't assume that package ids we see here are
|
||||
// exactly those from `config`.
|
||||
|
@ -415,7 +431,6 @@ impl WorkspaceBuildScripts {
|
|||
let dir_entry = entry.ok()?;
|
||||
if dir_entry.file_type().ok()?.is_file() {
|
||||
let path = dir_entry.path();
|
||||
tracing::info!("p{:?}", path);
|
||||
let extension = path.extension()?;
|
||||
if extension == std::env::consts::DLL_EXTENSION {
|
||||
let name = path.file_stem()?.to_str()?.split_once('-')?.0.to_owned();
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
//! See [`CargoWorkspace`].
|
||||
|
||||
use std::iter;
|
||||
use std::path::PathBuf;
|
||||
use std::str::from_utf8;
|
||||
use std::{ops, process::Command};
|
||||
|
@ -10,7 +9,7 @@ use base_db::Edition;
|
|||
use cargo_metadata::{CargoOpt, MetadataCommand};
|
||||
use la_arena::{Arena, Idx};
|
||||
use paths::{AbsPath, AbsPathBuf};
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use serde::Deserialize;
|
||||
use serde_json::from_value;
|
||||
|
||||
|
@ -32,6 +31,7 @@ pub struct CargoWorkspace {
|
|||
packages: Arena<PackageData>,
|
||||
targets: Arena<TargetData>,
|
||||
workspace_root: AbsPathBuf,
|
||||
target_directory: AbsPathBuf,
|
||||
}
|
||||
|
||||
impl ops::Index<Package> for CargoWorkspace {
|
||||
|
@ -57,20 +57,6 @@ pub enum RustLibSource {
|
|||
Discover,
|
||||
}
|
||||
|
||||
/// Crates to disable `#[cfg(test)]` on.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum UnsetTestCrates {
|
||||
None,
|
||||
Only(Vec<String>),
|
||||
All,
|
||||
}
|
||||
|
||||
impl Default for UnsetTestCrates {
|
||||
fn default() -> Self {
|
||||
Self::None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum CargoFeatures {
|
||||
All,
|
||||
|
@ -99,8 +85,7 @@ pub struct CargoConfig {
|
|||
pub sysroot_src: Option<AbsPathBuf>,
|
||||
/// rustc private crate source
|
||||
pub rustc_source: Option<RustLibSource>,
|
||||
/// crates to disable `#[cfg(test)]` on
|
||||
pub unset_test_crates: UnsetTestCrates,
|
||||
pub cfg_overrides: CfgOverrides,
|
||||
/// 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.
|
||||
|
@ -113,27 +98,6 @@ pub struct CargoConfig {
|
|||
pub invocation_location: InvocationLocation,
|
||||
}
|
||||
|
||||
impl CargoConfig {
|
||||
pub fn cfg_overrides(&self) -> CfgOverrides {
|
||||
match &self.unset_test_crates {
|
||||
UnsetTestCrates::None => CfgOverrides::Selective(iter::empty().collect()),
|
||||
UnsetTestCrates::Only(unset_test_crates) => CfgOverrides::Selective(
|
||||
unset_test_crates
|
||||
.iter()
|
||||
.cloned()
|
||||
.zip(iter::repeat_with(|| {
|
||||
cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())])
|
||||
.unwrap()
|
||||
}))
|
||||
.collect(),
|
||||
),
|
||||
UnsetTestCrates::All => CfgOverrides::Wildcard(
|
||||
cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]).unwrap(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Package = Idx<PackageData>;
|
||||
|
||||
pub type Target = Idx<TargetData>;
|
||||
|
@ -293,14 +257,30 @@ impl CargoWorkspace {
|
|||
}
|
||||
meta.current_dir(current_dir.as_os_str());
|
||||
|
||||
if !targets.is_empty() {
|
||||
let other_options: Vec<_> = targets
|
||||
.into_iter()
|
||||
.flat_map(|target| ["--filter-platform".to_string(), target])
|
||||
.collect();
|
||||
meta.other_options(other_options);
|
||||
let mut other_options = vec![];
|
||||
// cargo metadata only supports a subset of flags of what cargo usually accepts, and usually
|
||||
// the only relevant flags for metadata here are unstable ones, so we pass those along
|
||||
// but nothing else
|
||||
let mut extra_args = config.extra_args.iter();
|
||||
while let Some(arg) = extra_args.next() {
|
||||
if arg == "-Z" {
|
||||
if let Some(arg) = extra_args.next() {
|
||||
other_options.push("-Z".to_owned());
|
||||
other_options.push(arg.to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !targets.is_empty() {
|
||||
other_options.append(
|
||||
&mut targets
|
||||
.into_iter()
|
||||
.flat_map(|target| ["--filter-platform".to_owned().to_string(), target])
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
meta.other_options(other_options);
|
||||
|
||||
// FIXME: Fetching metadata is a slow process, as it might require
|
||||
// calling crates.io. We should be reporting progress here, but it's
|
||||
// unclear whether cargo itself supports it.
|
||||
|
@ -411,7 +391,10 @@ impl CargoWorkspace {
|
|||
let workspace_root =
|
||||
AbsPathBuf::assert(PathBuf::from(meta.workspace_root.into_os_string()));
|
||||
|
||||
CargoWorkspace { packages, targets, workspace_root }
|
||||
let target_directory =
|
||||
AbsPathBuf::assert(PathBuf::from(meta.target_directory.into_os_string()));
|
||||
|
||||
CargoWorkspace { packages, targets, workspace_root, target_directory }
|
||||
}
|
||||
|
||||
pub fn packages(&self) -> impl Iterator<Item = Package> + ExactSizeIterator + '_ {
|
||||
|
@ -429,6 +412,10 @@ impl CargoWorkspace {
|
|||
&self.workspace_root
|
||||
}
|
||||
|
||||
pub fn target_directory(&self) -> &AbsPath {
|
||||
&self.target_directory
|
||||
}
|
||||
|
||||
pub fn package_flag(&self, package: &PackageData) -> String {
|
||||
if self.is_unique(&package.name) {
|
||||
package.name.clone()
|
||||
|
@ -467,6 +454,21 @@ impl CargoWorkspace {
|
|||
None
|
||||
}
|
||||
|
||||
/// Returns the union of the features of all member crates in this workspace.
|
||||
pub fn workspace_features(&self) -> FxHashSet<String> {
|
||||
self.packages()
|
||||
.filter_map(|package| {
|
||||
let package = &self[package];
|
||||
if package.is_member {
|
||||
Some(package.features.keys().cloned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn is_unique(&self, name: &str) -> bool {
|
||||
self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
|
||||
}
|
||||
|
|
|
@ -49,6 +49,14 @@ impl Extend<CfgFlag> for CfgOptions {
|
|||
}
|
||||
}
|
||||
|
||||
impl FromIterator<CfgFlag> for CfgOptions {
|
||||
fn from_iter<T: IntoIterator<Item = CfgFlag>>(iter: T) -> Self {
|
||||
let mut this = CfgOptions::default();
|
||||
this.extend(iter);
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CfgFlag {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
|
|
|
@ -44,7 +44,7 @@ pub use crate::{
|
|||
build_scripts::WorkspaceBuildScripts,
|
||||
cargo_workspace::{
|
||||
CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency,
|
||||
RustLibSource, Target, TargetData, TargetKind, UnsetTestCrates,
|
||||
RustLibSource, Target, TargetData, TargetKind,
|
||||
},
|
||||
manifest_path::ManifestPath,
|
||||
project_json::{ProjectJson, ProjectJsonData},
|
||||
|
|
|
@ -34,6 +34,10 @@ impl ManifestPath {
|
|||
pub fn parent(&self) -> &AbsPath {
|
||||
self.file.parent().unwrap()
|
||||
}
|
||||
|
||||
pub fn canonicalize(&self) -> ! {
|
||||
(&**self).canonicalize()
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Deref for ManifestPath {
|
||||
|
|
|
@ -49,12 +49,12 @@
|
|||
//! user explores them belongs to that extension (it's totally valid to change
|
||||
//! rust-project.json over time via configuration request!)
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, Edition};
|
||||
use la_arena::RawIdx;
|
||||
use paths::{AbsPath, AbsPathBuf};
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::{de, Deserialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::cfg_flag::CfgFlag;
|
||||
|
||||
|
@ -98,26 +98,23 @@ impl ProjectJson {
|
|||
/// * `data` - The parsed contents of `rust-project.json`, or project json that's passed via
|
||||
/// configuration.
|
||||
pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson {
|
||||
let absolutize_on_base = |p| base.absolutize(p);
|
||||
ProjectJson {
|
||||
sysroot: data.sysroot.map(|it| base.join(it)),
|
||||
sysroot_src: data.sysroot_src.map(|it| base.join(it)),
|
||||
sysroot: data.sysroot.map(absolutize_on_base),
|
||||
sysroot_src: data.sysroot_src.map(absolutize_on_base),
|
||||
project_root: base.to_path_buf(),
|
||||
crates: data
|
||||
.crates
|
||||
.into_iter()
|
||||
.map(|crate_data| {
|
||||
let is_workspace_member = crate_data.is_workspace_member.unwrap_or_else(|| {
|
||||
crate_data.root_module.is_relative()
|
||||
&& !crate_data.root_module.starts_with("..")
|
||||
|| crate_data.root_module.starts_with(base)
|
||||
});
|
||||
let root_module = base.join(crate_data.root_module).normalize();
|
||||
let root_module = absolutize_on_base(crate_data.root_module);
|
||||
let is_workspace_member = crate_data
|
||||
.is_workspace_member
|
||||
.unwrap_or_else(|| root_module.starts_with(base));
|
||||
let (include, exclude) = match crate_data.source {
|
||||
Some(src) => {
|
||||
let absolutize = |dirs: Vec<PathBuf>| {
|
||||
dirs.into_iter()
|
||||
.map(|it| base.join(it).normalize())
|
||||
.collect::<Vec<_>>()
|
||||
dirs.into_iter().map(absolutize_on_base).collect::<Vec<_>>()
|
||||
};
|
||||
(absolutize(src.include_dirs), absolutize(src.exclude_dirs))
|
||||
}
|
||||
|
@ -135,7 +132,10 @@ impl ProjectJson {
|
|||
.deps
|
||||
.into_iter()
|
||||
.map(|dep_data| {
|
||||
Dependency::new(dep_data.name, CrateId(dep_data.krate as u32))
|
||||
Dependency::new(
|
||||
dep_data.name,
|
||||
CrateId::from_raw(RawIdx::from(dep_data.krate as u32)),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
cfg: crate_data.cfg,
|
||||
|
@ -143,7 +143,7 @@ impl ProjectJson {
|
|||
env: crate_data.env,
|
||||
proc_macro_dylib_path: crate_data
|
||||
.proc_macro_dylib_path
|
||||
.map(|it| base.join(it)),
|
||||
.map(absolutize_on_base),
|
||||
is_workspace_member,
|
||||
include,
|
||||
exclude,
|
||||
|
@ -151,7 +151,7 @@ impl ProjectJson {
|
|||
repository: crate_data.repository,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,7 +162,10 @@ impl ProjectJson {
|
|||
|
||||
/// 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))
|
||||
self.crates
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, krate)| (CrateId::from_raw(RawIdx::from(idx as u32)), krate))
|
||||
}
|
||||
|
||||
/// Returns the path to the project's root folder.
|
||||
|
@ -236,7 +239,7 @@ struct CrateSource {
|
|||
exclude_dirs: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
fn deserialize_crate_name<'de, D>(de: D) -> Result<CrateName, D::Error>
|
||||
fn deserialize_crate_name<'de, D>(de: D) -> std::result::Result<CrateName, D::Error>
|
||||
where
|
||||
D: de::Deserializer<'de>,
|
||||
{
|
||||
|
|
|
@ -12,13 +12,15 @@ 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>,
|
||||
/// 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>;
|
||||
|
@ -74,6 +76,23 @@ impl Sysroot {
|
|||
pub fn is_empty(&self) -> bool {
|
||||
self.crates.is_empty()
|
||||
}
|
||||
|
||||
pub fn loading_warning(&self) -> Option<String> {
|
||||
if self.by_name("core").is_none() {
|
||||
let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
|
||||
" (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
|
||||
} else {
|
||||
" try running `rustup component add rust-src` to possible fix this"
|
||||
};
|
||||
Some(format!(
|
||||
"could not find libcore in loaded sysroot at `{}`{}",
|
||||
self.src_root.as_path().display(),
|
||||
var_note,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Expose a builder api as loading the sysroot got way too modular and complicated.
|
||||
|
@ -103,14 +122,36 @@ impl Sysroot {
|
|||
|
||||
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())
|
||||
format_err!("can't load standard library from sysroot path {}", sysroot_dir.display())
|
||||
})?;
|
||||
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: Remove this `hack_cargo_workspace` field completely once we support sysroot dependencies
|
||||
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() {
|
||||
let name = path.split('/').last().unwrap();
|
||||
|
@ -153,19 +194,6 @@ impl Sysroot {
|
|||
}
|
||||
}
|
||||
|
||||
if sysroot.by_name("core").is_none() {
|
||||
let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
|
||||
" (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
tracing::error!(
|
||||
"could not find libcore in sysroot path `{}`{}",
|
||||
sysroot.src_root.as_path().display(),
|
||||
var_note,
|
||||
);
|
||||
}
|
||||
|
||||
sysroot
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ pub fn get(
|
|||
let mut cmd = Command::new(toolchain::rustc());
|
||||
cmd.envs(extra_env);
|
||||
cmd.current_dir(cargo_toml.parent())
|
||||
.args(["-Z", "unstable-options", "rustc", "--print", "target-spec-json"])
|
||||
.args(["-Z", "unstable-options", "--print", "target-spec-json"])
|
||||
.env("RUSTC_BOOTSTRAP", "1");
|
||||
if let Some(target) = target {
|
||||
cmd.args(["--target", target]);
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue