mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 14:03:35 +00:00
Merge #1771
1771: Further tweak for macro_use on extern crate r=matklad a=uHOOCCOOHu Some more tweaks to #1743 to behave more like `rustc` 1. Hoist macros from `#[macro_use] extern crate`, so that they can be used before `extern crate`. 2. Implicit `#[macro_use]` for `prelude` if exists Co-authored-by: uHOOCCOOHu <hooccooh1896@gmail.com>
This commit is contained in:
commit
419eec3d2f
3 changed files with 91 additions and 18 deletions
|
@ -12,4 +12,5 @@ test_utils::marks!(
|
|||
trait_resolution_on_fn_type
|
||||
infer_while_let
|
||||
macro_rules_from_other_crates_are_visible_with_macro_use
|
||||
prelude_is_macro_use
|
||||
);
|
||||
|
|
|
@ -183,11 +183,14 @@ where
|
|||
|
||||
if let Some(ModuleDef::Module(m)) = res.take_types() {
|
||||
tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
|
||||
self.import_all_macros_exported(m);
|
||||
}
|
||||
}
|
||||
|
||||
let item_map = self.db.crate_def_map(m.krate);
|
||||
for (name, ¯o_id) in &item_map.exported_macros {
|
||||
self.global_macro_scope.insert(name.clone(), macro_id);
|
||||
}
|
||||
fn import_all_macros_exported(&mut self, module: Module) {
|
||||
let item_map = self.db.crate_def_map(module.krate);
|
||||
for (name, ¯o_id) in &item_map.exported_macros {
|
||||
self.global_macro_scope.insert(name.clone(), macro_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -520,20 +523,32 @@ where
|
|||
DB: DefDatabase,
|
||||
{
|
||||
fn collect(&mut self, items: &[raw::RawItem]) {
|
||||
// Prelude module is always considered to be `#[macro_use]`.
|
||||
if let Some(prelude_module) = self.def_collector.def_map.prelude {
|
||||
tested_by!(prelude_is_macro_use);
|
||||
self.def_collector.import_all_macros_exported(prelude_module);
|
||||
}
|
||||
|
||||
// This should be processed eagerly instead of deferred to resolving.
|
||||
// `#[macro_use] extern crate` is hoisted to imports macros before collecting
|
||||
// any other items.
|
||||
for item in items {
|
||||
if let raw::RawItem::Import(import_id) = *item {
|
||||
let import = self.raw_items[import_id].clone();
|
||||
if import.is_extern_crate && import.is_macro_use {
|
||||
self.def_collector.import_macros_from_extern_crate(&import);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for item in items {
|
||||
match *item {
|
||||
raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]),
|
||||
raw::RawItem::Import(import_id) => {
|
||||
let import = self.raw_items[import_id].clone();
|
||||
// This should be processed eagerly instead of deferred to resolving.
|
||||
// Otherwise, since it will only mutate `global_macro_scope`
|
||||
// without `update` names in `mod`s, unresolved macros cannot be expanded.
|
||||
if import.is_extern_crate && import.is_macro_use {
|
||||
self.def_collector.import_macros_from_extern_crate(&import);
|
||||
}
|
||||
|
||||
self.def_collector.unresolved_imports.push((self.module_id, import_id, import));
|
||||
}
|
||||
raw::RawItem::Import(import_id) => self.def_collector.unresolved_imports.push((
|
||||
self.module_id,
|
||||
import_id,
|
||||
self.raw_items[import_id].clone(),
|
||||
)),
|
||||
raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]),
|
||||
raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
|
||||
}
|
||||
|
|
|
@ -144,9 +144,6 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() {
|
|||
let map = def_map_with_crate_graph(
|
||||
"
|
||||
//- /main.rs
|
||||
#[macro_use]
|
||||
extern crate foo;
|
||||
|
||||
structs!(Foo);
|
||||
structs_priv!(Bar);
|
||||
structs_not_exported!(MacroNotResolved1);
|
||||
|
@ -154,6 +151,9 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() {
|
|||
|
||||
mod bar;
|
||||
|
||||
#[macro_use]
|
||||
extern crate foo;
|
||||
|
||||
//- /bar.rs
|
||||
structs!(Baz);
|
||||
crate::structs!(MacroNotResolved3);
|
||||
|
@ -191,3 +191,60 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() {
|
|||
⋮Baz: t v
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prelude_is_macro_use() {
|
||||
covers!(prelude_is_macro_use);
|
||||
let map = def_map_with_crate_graph(
|
||||
"
|
||||
//- /main.rs
|
||||
structs!(Foo);
|
||||
structs_priv!(Bar);
|
||||
structs_outside!(Out);
|
||||
crate::structs!(MacroNotResolved2);
|
||||
|
||||
mod bar;
|
||||
|
||||
//- /bar.rs
|
||||
structs!(Baz);
|
||||
crate::structs!(MacroNotResolved3);
|
||||
|
||||
//- /lib.rs
|
||||
#[prelude_import]
|
||||
use self::prelude::*;
|
||||
|
||||
mod prelude {
|
||||
#[macro_export]
|
||||
macro_rules! structs {
|
||||
($i:ident) => { struct $i; }
|
||||
}
|
||||
|
||||
mod priv_mod {
|
||||
#[macro_export]
|
||||
macro_rules! structs_priv {
|
||||
($i:ident) => { struct $i; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! structs_outside {
|
||||
($i:ident) => { struct $i; }
|
||||
}
|
||||
",
|
||||
crate_graph! {
|
||||
"main": ("/main.rs", ["foo"]),
|
||||
"foo": ("/lib.rs", []),
|
||||
},
|
||||
);
|
||||
assert_snapshot!(map, @r###"
|
||||
⋮crate
|
||||
⋮Bar: t v
|
||||
⋮Foo: t v
|
||||
⋮Out: t v
|
||||
⋮bar: t
|
||||
⋮
|
||||
⋮crate::bar
|
||||
⋮Baz: t v
|
||||
"###);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue