mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-16 17:58:16 +00:00
Merge #2201
2201: Resolve core types r=matklad a=Matthias247 This adds support for completion and goto definition of types defined within the "core" crate. The core crate is added as a dependency to each crate in the project. The core crate exported it's own prelude. This caused now all crates to inherit the core crates prelude instead of the std crates. In order to avoid the problem the prelude resolution has been changed to overwrite an already resolved prelude if this was set to a crate named core - in order to pick a better prelude like std. Fixes #2199 Co-authored-by: Matthias Einwag <matthias.einwag@live.com>
This commit is contained in:
commit
7973fd66e9
5 changed files with 112 additions and 6 deletions
|
@ -36,11 +36,12 @@ pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) ->
|
|||
);
|
||||
|
||||
// look for the prelude
|
||||
if def_map.prelude.is_none() {
|
||||
let map = db.crate_def_map(dep.crate_id);
|
||||
if map.prelude.is_some() {
|
||||
def_map.prelude = map.prelude;
|
||||
}
|
||||
// If the dependency defines a prelude, we overwrite an already defined
|
||||
// prelude. This is necessary to import the "std" prelude if a crate
|
||||
// depends on both "core" and "std".
|
||||
let dep_def_map = db.crate_def_map(dep.crate_id);
|
||||
if dep_def_map.prelude.is_some() {
|
||||
def_map.prelude = dep_def_map.prelude;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -463,6 +463,37 @@ fn values_dont_shadow_extern_crates() {
|
|||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn std_prelude_takes_precedence_above_core_prelude() {
|
||||
let map = def_map(
|
||||
r#"
|
||||
//- /main.rs crate:main deps:core,std
|
||||
use {Foo, Bar};
|
||||
|
||||
//- /std.rs crate:std deps:core
|
||||
#[prelude_import]
|
||||
pub use self::prelude::*;
|
||||
mod prelude {
|
||||
pub struct Foo;
|
||||
pub use core::prelude::Bar;
|
||||
}
|
||||
|
||||
//- /core.rs crate:core
|
||||
#[prelude_import]
|
||||
pub use self::prelude::*;
|
||||
mod prelude {
|
||||
pub struct Bar;
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
assert_snapshot!(map, @r###"
|
||||
⋮crate
|
||||
⋮Bar: t v
|
||||
⋮Foo: t v
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cfg_not_test() {
|
||||
let map = def_map(
|
||||
|
|
|
@ -597,6 +597,68 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_std_prelude_if_core_is_defined() {
|
||||
assert_debug_snapshot!(
|
||||
do_reference_completion(
|
||||
"
|
||||
//- /main.rs
|
||||
fn foo() { let x: <|> }
|
||||
|
||||
//- /core/lib.rs
|
||||
#[prelude_import]
|
||||
use prelude::*;
|
||||
|
||||
mod prelude {
|
||||
struct Option;
|
||||
}
|
||||
|
||||
//- /std/lib.rs
|
||||
#[prelude_import]
|
||||
use prelude::*;
|
||||
|
||||
mod prelude {
|
||||
struct String;
|
||||
}
|
||||
"
|
||||
),
|
||||
@r###"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "String",
|
||||
source_range: [18; 18),
|
||||
delete: [18; 18),
|
||||
insert: "String",
|
||||
kind: Struct,
|
||||
},
|
||||
CompletionItem {
|
||||
label: "core",
|
||||
source_range: [18; 18),
|
||||
delete: [18; 18),
|
||||
insert: "core",
|
||||
kind: Module,
|
||||
},
|
||||
CompletionItem {
|
||||
label: "foo()",
|
||||
source_range: [18; 18),
|
||||
delete: [18; 18),
|
||||
insert: "foo()$0",
|
||||
kind: Function,
|
||||
lookup: "foo",
|
||||
detail: "fn foo()",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "std",
|
||||
source_range: [18; 18),
|
||||
delete: [18; 18),
|
||||
insert: "std",
|
||||
kind: Module,
|
||||
},
|
||||
]
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_macros_as_value() {
|
||||
assert_debug_snapshot!(
|
||||
|
|
|
@ -199,6 +199,7 @@ impl ProjectWorkspace {
|
|||
}
|
||||
}
|
||||
|
||||
let libcore = sysroot.core().and_then(|it| sysroot_crates.get(&it).copied());
|
||||
let libstd = sysroot.std().and_then(|it| sysroot_crates.get(&it).copied());
|
||||
|
||||
let mut pkg_to_lib_crate = FxHashMap::default();
|
||||
|
@ -226,7 +227,7 @@ impl ProjectWorkspace {
|
|||
}
|
||||
}
|
||||
|
||||
// Set deps to the std and to the lib target of the current package
|
||||
// Set deps to the core, std and to the lib target of the current package
|
||||
for &from in pkg_crates.get(&pkg).into_iter().flatten() {
|
||||
if let Some(to) = lib_tgt {
|
||||
if to != from {
|
||||
|
@ -240,6 +241,13 @@ impl ProjectWorkspace {
|
|||
}
|
||||
}
|
||||
}
|
||||
// core is added as a dependency before std in order to
|
||||
// mimic rustcs dependency order
|
||||
if let Some(core) = libcore {
|
||||
if let Err(_) = crate_graph.add_dep(from, "core".into(), core) {
|
||||
log::error!("cyclic dependency on core for {}", pkg.name(&cargo))
|
||||
}
|
||||
}
|
||||
if let Some(std) = libstd {
|
||||
if let Err(_) = crate_graph.add_dep(from, "std".into(), std) {
|
||||
log::error!("cyclic dependency on std for {}", pkg.name(&cargo))
|
||||
|
|
|
@ -27,6 +27,10 @@ struct SysrootCrateData {
|
|||
}
|
||||
|
||||
impl Sysroot {
|
||||
pub fn core(&self) -> Option<SysrootCrate> {
|
||||
self.by_name("core")
|
||||
}
|
||||
|
||||
pub fn std(&self) -> Option<SysrootCrate> {
|
||||
self.by_name("std")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue