| use super::*; |
| |
| #[test] |
| fn macro_rules_are_globally_visible() { |
| let map = def_map( |
| r" |
| //- /lib.rs |
| macro_rules! structs { |
| ($($i:ident),*) => { |
| $(struct $i { field: u32 } )* |
| } |
| } |
| structs!(Foo); |
| mod nested; |
| |
| //- /nested.rs |
| structs!(Bar, Baz); |
| ", |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮Foo: t |
| ⋮nested: t |
| ⋮ |
| ⋮crate::nested |
| ⋮Bar: t |
| ⋮Baz: t |
| "###); |
| } |
| |
| #[test] |
| fn macro_rules_can_define_modules() { |
| let map = def_map( |
| r" |
| //- /lib.rs |
| macro_rules! m { |
| ($name:ident) => { mod $name; } |
| } |
| m!(n1); |
| |
| mod m { |
| m!(n3) |
| } |
| |
| //- /n1.rs |
| m!(n2) |
| //- /n1/n2.rs |
| struct X; |
| //- /m/n3.rs |
| struct Y; |
| ", |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮m: t |
| ⋮n1: t |
| ⋮ |
| ⋮crate::m |
| ⋮n3: t |
| ⋮ |
| ⋮crate::m::n3 |
| ⋮Y: t v |
| ⋮ |
| ⋮crate::n1 |
| ⋮n2: t |
| ⋮ |
| ⋮crate::n1::n2 |
| ⋮X: t v |
| "###); |
| } |
| |
| #[test] |
| fn macro_rules_from_other_crates_are_visible() { |
| let map = def_map( |
| " |
| //- /main.rs crate:main deps:foo |
| foo::structs!(Foo, Bar) |
| mod bar; |
| |
| //- /bar.rs |
| use crate::*; |
| |
| //- /lib.rs crate:foo |
| #[macro_export] |
| macro_rules! structs { |
| ($($i:ident),*) => { |
| $(struct $i { field: u32 } )* |
| } |
| } |
| ", |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮Bar: t |
| ⋮Foo: t |
| ⋮bar: t |
| ⋮ |
| ⋮crate::bar |
| ⋮Bar: t |
| ⋮Foo: t |
| ⋮bar: t |
| "###); |
| } |
| |
| #[test] |
| fn macro_rules_export_with_local_inner_macros_are_visible() { |
| let map = def_map( |
| " |
| //- /main.rs crate:main deps:foo |
| foo::structs!(Foo, Bar) |
| mod bar; |
| |
| //- /bar.rs |
| use crate::*; |
| |
| //- /lib.rs crate:foo |
| #[macro_export(local_inner_macros)] |
| macro_rules! structs { |
| ($($i:ident),*) => { |
| $(struct $i { field: u32 } )* |
| } |
| } |
| ", |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮Bar: t |
| ⋮Foo: t |
| ⋮bar: t |
| ⋮ |
| ⋮crate::bar |
| ⋮Bar: t |
| ⋮Foo: t |
| ⋮bar: t |
| "###); |
| } |
| |
| #[test] |
| fn local_inner_macros_makes_local_macros_usable() { |
| let map = def_map( |
| " |
| //- /main.rs crate:main deps:foo |
| foo::structs!(Foo, Bar); |
| mod bar; |
| //- /bar.rs |
| use crate::*; |
| //- /lib.rs crate:foo |
| #[macro_export(local_inner_macros)] |
| macro_rules! structs { |
| ($($i:ident),*) => { |
| inner!($($i),*); |
| } |
| } |
| #[macro_export] |
| macro_rules! inner { |
| ($($i:ident),*) => { |
| $(struct $i { field: u32 } )* |
| } |
| } |
| ", |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮Bar: t |
| ⋮Foo: t |
| ⋮bar: t |
| ⋮ |
| ⋮crate::bar |
| ⋮Bar: t |
| ⋮Foo: t |
| ⋮bar: t |
| "###); |
| } |
| |
| #[test] |
| fn unexpanded_macro_should_expand_by_fixedpoint_loop() { |
| let map = def_map( |
| " |
| //- /main.rs crate:main deps:foo |
| macro_rules! baz { |
| () => { |
| use foo::bar; |
| } |
| } |
| |
| foo!(); |
| bar!(); |
| baz!(); |
| |
| //- /lib.rs crate:foo |
| #[macro_export] |
| macro_rules! foo { |
| () => { |
| struct Foo { field: u32 } |
| } |
| } |
| #[macro_export] |
| macro_rules! bar { |
| () => { |
| use foo::foo; |
| } |
| } |
| ", |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮Foo: t |
| ⋮bar: m |
| ⋮foo: m |
| "###); |
| } |
| |
| #[test] |
| fn macro_rules_from_other_crates_are_visible_with_macro_use() { |
| mark::check!(macro_rules_from_other_crates_are_visible_with_macro_use); |
| let map = def_map( |
| " |
| //- /main.rs crate:main deps:foo |
| structs!(Foo); |
| structs_priv!(Bar); |
| structs_not_exported!(MacroNotResolved1); |
| crate::structs!(MacroNotResolved2); |
| |
| mod bar; |
| |
| #[macro_use] |
| extern crate foo; |
| |
| //- /bar.rs |
| structs!(Baz); |
| crate::structs!(MacroNotResolved3); |
| |
| //- /lib.rs crate:foo |
| #[macro_export] |
| macro_rules! structs { |
| ($i:ident) => { struct $i; } |
| } |
| |
| macro_rules! structs_not_exported { |
| ($i:ident) => { struct $i; } |
| } |
| |
| mod priv_mod { |
| #[macro_export] |
| macro_rules! structs_priv { |
| ($i:ident) => { struct $i; } |
| } |
| } |
| ", |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮Bar: t v |
| ⋮Foo: t v |
| ⋮bar: t |
| ⋮foo: t |
| ⋮ |
| ⋮crate::bar |
| ⋮Baz: t v |
| "###); |
| } |
| |
| #[test] |
| fn prelude_is_macro_use() { |
| mark::check!(prelude_is_macro_use); |
| let map = def_map( |
| " |
| //- /main.rs crate:main deps:foo |
| structs!(Foo); |
| structs_priv!(Bar); |
| structs_outside!(Out); |
| crate::structs!(MacroNotResolved2); |
| |
| mod bar; |
| |
| //- /bar.rs |
| structs!(Baz); |
| crate::structs!(MacroNotResolved3); |
| |
| //- /lib.rs crate:foo |
| #[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; } |
| } |
| ", |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮Bar: t v |
| ⋮Foo: t v |
| ⋮Out: t v |
| ⋮bar: t |
| ⋮ |
| ⋮crate::bar |
| ⋮Baz: t v |
| "###); |
| } |
| |
| #[test] |
| fn prelude_cycle() { |
| let map = def_map( |
| " |
| //- /lib.rs |
| #[prelude_import] |
| use self::prelude::*; |
| |
| declare_mod!(); |
| |
| mod prelude { |
| macro_rules! declare_mod { |
| () => (mod foo {}) |
| } |
| } |
| ", |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮prelude: t |
| ⋮ |
| ⋮crate::prelude |
| "###); |
| } |
| |
| #[test] |
| fn plain_macros_are_legacy_textual_scoped() { |
| let map = def_map( |
| r#" |
| //- /main.rs |
| mod m1; |
| bar!(NotFoundNotMacroUse); |
| |
| mod m2 { |
| foo!(NotFoundBeforeInside2); |
| } |
| |
| macro_rules! foo { |
| ($x:ident) => { struct $x; } |
| } |
| foo!(Ok); |
| |
| mod m3; |
| foo!(OkShadowStop); |
| bar!(NotFoundMacroUseStop); |
| |
| #[macro_use] |
| mod m5 { |
| #[macro_use] |
| mod m6 { |
| macro_rules! foo { |
| ($x:ident) => { fn $x() {} } |
| } |
| } |
| } |
| foo!(ok_double_macro_use_shadow); |
| |
| baz!(NotFoundBefore); |
| #[macro_use] |
| mod m7 { |
| macro_rules! baz { |
| ($x:ident) => { struct $x; } |
| } |
| } |
| baz!(OkAfter); |
| |
| //- /m1.rs |
| foo!(NotFoundBeforeInside1); |
| macro_rules! bar { |
| ($x:ident) => { struct $x; } |
| } |
| |
| //- /m3/mod.rs |
| foo!(OkAfterInside); |
| macro_rules! foo { |
| ($x:ident) => { fn $x() {} } |
| } |
| foo!(ok_shadow); |
| |
| #[macro_use] |
| mod m4; |
| bar!(OkMacroUse); |
| |
| //- /m3/m4.rs |
| foo!(ok_shadow_deep); |
| macro_rules! bar { |
| ($x:ident) => { struct $x; } |
| } |
| "#, |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮Ok: t v |
| ⋮OkAfter: t v |
| ⋮OkShadowStop: t v |
| ⋮m1: t |
| ⋮m2: t |
| ⋮m3: t |
| ⋮m5: t |
| ⋮m7: t |
| ⋮ok_double_macro_use_shadow: v |
| ⋮ |
| ⋮crate::m7 |
| ⋮ |
| ⋮crate::m1 |
| ⋮ |
| ⋮crate::m5 |
| ⋮m6: t |
| ⋮ |
| ⋮crate::m5::m6 |
| ⋮ |
| ⋮crate::m2 |
| ⋮ |
| ⋮crate::m3 |
| ⋮OkAfterInside: t v |
| ⋮OkMacroUse: t v |
| ⋮m4: t |
| ⋮ok_shadow: v |
| ⋮ |
| ⋮crate::m3::m4 |
| ⋮ok_shadow_deep: v |
| "###); |
| } |
| |
| #[test] |
| fn type_value_macro_live_in_different_scopes() { |
| let map = def_map( |
| " |
| //- /main.rs |
| #[macro_export] |
| macro_rules! foo { |
| ($x:ident) => { type $x = (); } |
| } |
| |
| foo!(foo); |
| use foo as bar; |
| |
| use self::foo as baz; |
| fn baz() {} |
| ", |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮bar: t m |
| ⋮baz: t v m |
| ⋮foo: t m |
| "###); |
| } |
| |
| #[test] |
| fn macro_use_can_be_aliased() { |
| let map = def_map( |
| " |
| //- /main.rs crate:main deps:foo |
| #[macro_use] |
| extern crate foo; |
| |
| foo!(Direct); |
| bar!(Alias); |
| |
| //- /lib.rs crate:foo |
| use crate::foo as bar; |
| |
| mod m { |
| #[macro_export] |
| macro_rules! foo { |
| ($x:ident) => { struct $x; } |
| } |
| } |
| ", |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮Alias: t v |
| ⋮Direct: t v |
| ⋮foo: t |
| "###); |
| } |
| |
| #[test] |
| fn path_qualified_macros() { |
| let map = def_map( |
| " |
| //- /main.rs |
| macro_rules! foo { |
| ($x:ident) => { struct $x; } |
| } |
| |
| crate::foo!(NotResolved); |
| |
| crate::bar!(OkCrate); |
| bar!(OkPlain); |
| alias1!(NotHere); |
| m::alias1!(OkAliasPlain); |
| m::alias2!(OkAliasSuper); |
| m::alias3!(OkAliasCrate); |
| not_found!(NotFound); |
| |
| mod m { |
| #[macro_export] |
| macro_rules! bar { |
| ($x:ident) => { struct $x; } |
| } |
| |
| pub use bar as alias1; |
| pub use super::bar as alias2; |
| pub use crate::bar as alias3; |
| pub use self::bar as not_found; |
| } |
| ", |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮OkAliasCrate: t v |
| ⋮OkAliasPlain: t v |
| ⋮OkAliasSuper: t v |
| ⋮OkCrate: t v |
| ⋮OkPlain: t v |
| ⋮bar: m |
| ⋮m: t |
| ⋮ |
| ⋮crate::m |
| ⋮alias1: m |
| ⋮alias2: m |
| ⋮alias3: m |
| ⋮not_found: _ |
| "###); |
| } |
| |
| #[test] |
| fn macro_dollar_crate_is_correct_in_item() { |
| mark::check!(macro_dollar_crate_self); |
| let map = def_map( |
| " |
| //- /main.rs crate:main deps:foo |
| #[macro_use] |
| extern crate foo; |
| |
| #[macro_use] |
| mod m { |
| macro_rules! current { |
| () => { |
| use $crate::Foo as FooSelf; |
| } |
| } |
| } |
| |
| struct Foo; |
| |
| current!(); |
| not_current1!(); |
| foo::not_current2!(); |
| |
| //- /lib.rs crate:foo |
| mod m { |
| #[macro_export] |
| macro_rules! not_current1 { |
| () => { |
| use $crate::Bar; |
| } |
| } |
| } |
| |
| #[macro_export] |
| macro_rules! not_current2 { |
| () => { |
| use $crate::Baz; |
| } |
| } |
| |
| struct Bar; |
| struct Baz; |
| ", |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮Bar: t v |
| ⋮Baz: t v |
| ⋮Foo: t v |
| ⋮FooSelf: t v |
| ⋮foo: t |
| ⋮m: t |
| ⋮ |
| ⋮crate::m |
| "###); |
| } |
| |
| #[test] |
| fn macro_dollar_crate_is_correct_in_indirect_deps() { |
| mark::check!(macro_dollar_crate_other); |
| // From std |
| let map = def_map( |
| r#" |
| //- /main.rs crate:main deps:std |
| foo!(); |
| |
| //- /std.rs crate:std deps:core |
| #[prelude_import] |
| use self::prelude::*; |
| |
| pub use core::foo; |
| |
| mod prelude {} |
| |
| #[macro_use] |
| mod std_macros; |
| |
| //- /core.rs crate:core |
| #[macro_export] |
| macro_rules! foo { |
| () => { |
| use $crate::bar; |
| } |
| } |
| |
| pub struct bar; |
| "#, |
| ); |
| assert_snapshot!(map, @r###" |
| ⋮crate |
| ⋮bar: t v |
| "###); |
| } |
| |
| #[test] |
| fn expand_derive() { |
| let map = compute_crate_def_map( |
| " |
| //- /main.rs |
| #[derive(Clone)] |
| struct Foo; |
| ", |
| ); |
| assert_eq!(map.modules[map.root].scope.impls().len(), 1); |
| } |
| |
| #[test] |
| fn expand_multiple_derive() { |
| let map = compute_crate_def_map( |
| " |
| //- /main.rs |
| #[derive(Copy, Clone)] |
| struct Foo; |
| ", |
| ); |
| assert_eq!(map.modules[map.root].scope.impls().len(), 2); |
| } |