mod macros; mod globs; mod incremental; use std::sync::Arc; use ra_db::SourceDatabase; use test_utils::covers; use insta::assert_snapshot_matches; use crate::{ Crate, mock::{MockDatabase, CrateGraphFixture}, nameres::Resolution, }; use super::*; fn compute_crate_def_map(fixture: &str, graph: Option) -> Arc { let mut db = MockDatabase::with_files(fixture); if let Some(graph) = graph { db.set_crate_graph_from_fixture(graph); } let crate_id = db.crate_graph().iter().next().unwrap(); let krate = Crate { crate_id }; db.crate_def_map(krate) } fn render_crate_def_map(map: &CrateDefMap) -> String { let mut buf = String::new(); go(&mut buf, map, "\ncrate", map.root); return buf.trim().to_string(); fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: CrateModuleId) { *buf += path; *buf += "\n"; let mut entries = map.modules[module].scope.items.iter().collect::>(); entries.sort_by_key(|(name, _)| *name); for (name, res) in entries { *buf += &format!("{}: {}\n", name, dump_resolution(res)) } for (name, child) in map.modules[module].children.iter() { let path = path.to_string() + &format!("::{}", name); go(buf, map, &path, *child); } } fn dump_resolution(resolution: &Resolution) -> &'static str { match (resolution.def.types.is_some(), resolution.def.values.is_some()) { (true, true) => "t v", (true, false) => "t", (false, true) => "v", (false, false) => "_", } } } fn def_map(fixtute: &str) -> String { let dm = compute_crate_def_map(fixtute, None); render_crate_def_map(&dm) } fn def_map_with_crate_graph(fixtute: &str, graph: CrateGraphFixture) -> String { let dm = compute_crate_def_map(fixtute, Some(graph)); render_crate_def_map(&dm) } #[test] fn crate_def_map_smoke_test() { let map = def_map( " //- /lib.rs mod foo; struct S; use crate::foo::bar::E; use self::E::V; //- /foo/mod.rs pub mod bar; fn f() {} //- /foo/bar.rs pub struct Baz; enum E { V } ", ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮E: t ⋮S: t v ⋮V: t v ⋮foo: t ⋮ ⋮crate::foo ⋮bar: t ⋮f: v ⋮ ⋮crate::foo::bar ⋮Baz: t v ⋮E: t "###) } #[test] fn bogus_paths() { covers!(bogus_paths); let map = def_map( " //- /lib.rs mod foo; struct S; use self; //- /foo/mod.rs use super; use crate; ", ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮S: t v ⋮foo: t ⋮ ⋮crate::foo "### ) } #[test] fn use_as() { let map = def_map( " //- /lib.rs mod foo; use crate::foo::Baz as Foo; //- /foo/mod.rs pub struct Baz; ", ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮Foo: t v ⋮foo: t ⋮ ⋮crate::foo ⋮Baz: t v "### ); } #[test] fn use_trees() { let map = def_map( " //- /lib.rs mod foo; use crate::foo::bar::{Baz, Quux}; //- /foo/mod.rs pub mod bar; //- /foo/bar.rs pub struct Baz; pub enum Quux {}; ", ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮Baz: t v ⋮Quux: t ⋮foo: t ⋮ ⋮crate::foo ⋮bar: t ⋮ ⋮crate::foo::bar ⋮Baz: t v ⋮Quux: t "###); } #[test] fn re_exports() { let map = def_map( " //- /lib.rs mod foo; use self::foo::Baz; //- /foo/mod.rs pub mod bar; pub use self::bar::Baz; //- /foo/bar.rs pub struct Baz; ", ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮Baz: t v ⋮foo: t ⋮ ⋮crate::foo ⋮Baz: t v ⋮bar: t ⋮ ⋮crate::foo::bar ⋮Baz: t v "###); } #[test] fn std_prelude() { covers!(std_prelude); let map = def_map_with_crate_graph( " //- /main.rs use Foo::*; //- /lib.rs mod prelude; #[prelude_import] use prelude::*; //- /prelude.rs pub enum Foo { Bar, Baz }; ", crate_graph! { "main": ("/main.rs", ["test_crate"]), "test_crate": ("/lib.rs", []), }, ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮Bar: t v ⋮Baz: t v "###); } #[test] fn can_import_enum_variant() { covers!(can_import_enum_variant); let map = def_map( " //- /lib.rs enum E { V } use self::E::V; ", ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮E: t ⋮V: t v "### ); } #[test] fn edition_2015_imports() { let map = def_map_with_crate_graph( " //- /main.rs mod foo; mod bar; //- /bar.rs struct Bar; //- /foo.rs use bar::Bar; use other_crate::FromLib; //- /lib.rs struct FromLib; ", crate_graph! { "main": ("/main.rs", "2015", ["other_crate"]), "other_crate": ("/lib.rs", "2018", []), }, ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮bar: t ⋮foo: t ⋮ ⋮crate::bar ⋮Bar: t v ⋮ ⋮crate::foo ⋮Bar: t v ⋮FromLib: t v "###); } #[test] fn module_resolution_works_for_non_standard_filenames() { let map = def_map_with_crate_graph( " //- /my_library.rs mod foo; use self::foo::Bar; //- /foo/mod.rs pub struct Bar; ", crate_graph! { "my_library": ("/my_library.rs", []), }, ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮Bar: t v ⋮foo: t ⋮ ⋮crate::foo ⋮Bar: t v "###); } #[test] fn name_res_works_for_broken_modules() { covers!(name_res_works_for_broken_modules); let map = def_map( " //- /lib.rs mod foo // no `;`, no body use self::foo::Baz; //- /foo/mod.rs pub mod bar; pub use self::bar::Baz; //- /foo/bar.rs pub struct Baz; ", ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮Baz: _ "###); } #[test] fn item_map_using_self() { let map = def_map( " //- /lib.rs mod foo; use crate::foo::bar::Baz::{self}; //- /foo/mod.rs pub mod bar; //- /foo/bar.rs pub struct Baz; ", ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮Baz: t v ⋮foo: t ⋮ ⋮crate::foo ⋮bar: t ⋮ ⋮crate::foo::bar ⋮Baz: t v "###); } #[test] fn item_map_across_crates() { let map = def_map_with_crate_graph( " //- /main.rs use test_crate::Baz; //- /lib.rs pub struct Baz; ", crate_graph! { "main": ("/main.rs", ["test_crate"]), "test_crate": ("/lib.rs", []), }, ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮Baz: t v "###); } #[test] fn extern_crate_rename() { let map = def_map_with_crate_graph( " //- /main.rs extern crate alloc as alloc_crate; mod alloc; mod sync; //- /sync.rs use alloc_crate::Arc; //- /lib.rs struct Arc; ", crate_graph! { "main": ("/main.rs", ["alloc"]), "alloc": ("/lib.rs", []), }, ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮Arc: t v "###); } #[test] fn extern_crate_rename_2015_edition() { let map = def_map_with_crate_graph( " //- /main.rs extern crate alloc as alloc_crate; mod alloc; mod sync; //- /sync.rs use alloc_crate::Arc; //- /lib.rs struct Arc; ", crate_graph! { "main": ("/main.rs", "2015", ["alloc"]), "alloc": ("/lib.rs", []), }, ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮Arc: t v "### ); } #[test] fn import_across_source_roots() { let map = def_map_with_crate_graph( " //- /lib.rs pub mod a { pub mod b { pub struct C; } } //- root /main/ //- /main/main.rs use test_crate::a::b::C; ", crate_graph! { "main": ("/main/main.rs", ["test_crate"]), "test_crate": ("/lib.rs", []), }, ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮C: t v "###); } #[test] fn reexport_across_crates() { let map = def_map_with_crate_graph( " //- /main.rs use test_crate::Baz; //- /lib.rs pub use foo::Baz; mod foo; //- /foo.rs pub struct Baz; ", crate_graph! { "main": ("/main.rs", ["test_crate"]), "test_crate": ("/lib.rs", []), }, ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮Baz: t v "###); } #[test] fn values_dont_shadow_extern_crates() { let map = def_map_with_crate_graph( " //- /main.rs fn foo() {} use foo::Bar; //- /foo/lib.rs pub struct Bar; ", crate_graph! { "main": ("/main.rs", ["foo"]), "foo": ("/foo/lib.rs", []), }, ); assert_snapshot_matches!(map, @r###" ⋮crate ⋮Bar: t v ⋮foo: v "###); } #[test] fn unresolved_module_diagnostics() { let diagnostics = MockDatabase::with_files( r" //- /lib.rs mod foo; mod bar; mod baz {} //- /foo.rs ", ) .diagnostics(); assert_snapshot_matches!(diagnostics, @r###" "mod bar;": unresolved module "### ); }