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() { covers!(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() { covers!(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() { covers!(macro_dollar_crate_self); covers!(macro_dollar_crate_other); 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() { covers!(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); }