From 6fba51c5fc05264abcbf971dcf28142746588d74 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 3 Nov 2019 23:35:48 +0300 Subject: move crate_def_map tests to hir_def --- Cargo.lock | 1 + crates/ra_db/src/fixture.rs | 148 +++- crates/ra_db/src/input.rs | 1 + crates/ra_hir/src/nameres.rs | 3 - crates/ra_hir/src/nameres/tests.rs | 573 --------------- crates/ra_hir/src/nameres/tests/globs.rs | 118 ---- crates/ra_hir/src/nameres/tests/incremental.rs | 140 ---- crates/ra_hir/src/nameres/tests/macros.rs | 635 ----------------- crates/ra_hir/src/nameres/tests/mod_resolution.rs | 759 -------------------- crates/ra_hir/src/nameres/tests/primitives.rs | 24 - crates/ra_hir_def/Cargo.toml | 4 + crates/ra_hir_def/src/nameres.rs | 3 + crates/ra_hir_def/src/nameres/tests.rs | 522 ++++++++++++++ crates/ra_hir_def/src/nameres/tests/globs.rs | 114 +++ crates/ra_hir_def/src/nameres/tests/incremental.rs | 133 ++++ crates/ra_hir_def/src/nameres/tests/macros.rs | 602 ++++++++++++++++ .../ra_hir_def/src/nameres/tests/mod_resolution.rs | 782 +++++++++++++++++++++ crates/ra_hir_def/src/nameres/tests/primitives.rs | 24 + crates/ra_hir_def/src/test_db.rs | 36 +- 19 files changed, 2368 insertions(+), 2254 deletions(-) delete mode 100644 crates/ra_hir/src/nameres/tests.rs delete mode 100644 crates/ra_hir/src/nameres/tests/globs.rs delete mode 100644 crates/ra_hir/src/nameres/tests/incremental.rs delete mode 100644 crates/ra_hir/src/nameres/tests/macros.rs delete mode 100644 crates/ra_hir/src/nameres/tests/mod_resolution.rs delete mode 100644 crates/ra_hir/src/nameres/tests/primitives.rs create mode 100644 crates/ra_hir_def/src/nameres/tests.rs create mode 100644 crates/ra_hir_def/src/nameres/tests/globs.rs create mode 100644 crates/ra_hir_def/src/nameres/tests/incremental.rs create mode 100644 crates/ra_hir_def/src/nameres/tests/macros.rs create mode 100644 crates/ra_hir_def/src/nameres/tests/mod_resolution.rs create mode 100644 crates/ra_hir_def/src/nameres/tests/primitives.rs diff --git a/Cargo.lock b/Cargo.lock index c96e0869c..889820c99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1028,6 +1028,7 @@ dependencies = [ name = "ra_hir_def" version = "0.1.0" dependencies = [ + "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ra_arena 0.1.0", diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs index 469251fe9..f5dd59f84 100644 --- a/crates/ra_db/src/fixture.rs +++ b/crates/ra_db/src/fixture.rs @@ -3,9 +3,12 @@ use std::sync::Arc; use ra_cfg::CfgOptions; +use rustc_hash::FxHashMap; +use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; use crate::{ - CrateGraph, Edition, FileId, RelativePathBuf, SourceDatabaseExt, SourceRoot, SourceRootId, + CrateGraph, Edition, FileId, FilePosition, RelativePathBuf, SourceDatabaseExt, SourceRoot, + SourceRootId, }; pub const WORKSPACE: SourceRootId = SourceRootId(0); @@ -16,6 +19,19 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { let file_id = with_single_file(&mut db, text); (db, file_id) } + + fn with_files(fixture: &str) -> Self { + let mut db = Self::default(); + let pos = with_files(&mut db, fixture); + assert!(pos.is_none()); + db + } + + fn with_position(fixture: &str) -> (Self, FilePosition) { + let mut db = Self::default(); + let pos = with_files(&mut db, fixture); + (db, pos.unwrap()) + } } impl WithFixture for DB {} @@ -38,3 +54,133 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, text: &str) -> FileId { file_id } + +fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option { + let fixture = parse_fixture(fixture); + + let mut crate_graph = CrateGraph::default(); + let mut crates = FxHashMap::default(); + let mut crate_deps = Vec::new(); + let mut default_crate_root: Option = None; + + let mut source_root = SourceRoot::default(); + let mut source_root_id = WORKSPACE; + let mut source_root_prefix: RelativePathBuf = "/".into(); + let mut file_id = FileId(0); + + let mut file_position = None; + + for entry in fixture.iter() { + let meta = match parse_meta(&entry.meta) { + ParsedMeta::Root { path } => { + let source_root = std::mem::replace(&mut source_root, SourceRoot::default()); + db.set_source_root(source_root_id, Arc::new(source_root)); + source_root_id.0 += 1; + source_root_prefix = path; + continue; + } + ParsedMeta::File(it) => it, + }; + assert!(meta.path.starts_with(&source_root_prefix)); + + if let Some(krate) = meta.krate { + let crate_id = crate_graph.add_crate_root(file_id, meta.edition, meta.cfg); + let prev = crates.insert(krate.clone(), crate_id); + assert!(prev.is_none()); + for dep in meta.deps { + crate_deps.push((krate.clone(), dep)) + } + } else if meta.path == "/main.rs" || meta.path == "/lib.rs" { + assert!(default_crate_root.is_none()); + default_crate_root = Some(file_id); + } + + let text = if entry.text.contains(CURSOR_MARKER) { + let (offset, text) = extract_offset(&entry.text); + assert!(file_position.is_none()); + file_position = Some(FilePosition { file_id, offset }); + text.to_string() + } else { + entry.text.to_string() + }; + + db.set_file_text(file_id, Arc::new(text)); + db.set_file_relative_path(file_id, meta.path.clone()); + db.set_file_source_root(file_id, source_root_id); + source_root.insert_file(meta.path, file_id); + + file_id.0 += 1; + } + + if crates.is_empty() { + let crate_root = default_crate_root.unwrap(); + crate_graph.add_crate_root(crate_root, Edition::Edition2018, CfgOptions::default()); + } else { + for (from, to) in crate_deps { + let from_id = crates[&from]; + let to_id = crates[&to]; + crate_graph.add_dep(from_id, to.into(), to_id).unwrap(); + } + } + + db.set_source_root(source_root_id, Arc::new(source_root)); + db.set_crate_graph(Arc::new(crate_graph)); + + file_position +} + +enum ParsedMeta { + Root { path: RelativePathBuf }, + File(FileMeta), +} + +struct FileMeta { + path: RelativePathBuf, + krate: Option, + deps: Vec, + cfg: CfgOptions, + edition: Edition, +} + +//- /lib.rs crate:foo deps:bar,baz +fn parse_meta(meta: &str) -> ParsedMeta { + let components = meta.split_ascii_whitespace().collect::>(); + + if components[0] == "root" { + let path: RelativePathBuf = components[1].into(); + assert!(path.starts_with("/") && path.ends_with("/")); + return ParsedMeta::Root { path }; + } + + let path: RelativePathBuf = components[0].into(); + assert!(path.starts_with("/")); + + let mut krate = None; + let mut deps = Vec::new(); + let mut edition = Edition::Edition2018; + let mut cfg = CfgOptions::default(); + for component in components[1..].iter() { + let (key, value) = split1(component, ':').unwrap(); + match key { + "crate" => krate = Some(value.to_string()), + "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), + "edition" => edition = Edition::from_string(&value), + "cfg" => { + for key in value.split(',') { + match split1(key, '=') { + None => cfg.insert_atom(key.into()), + Some((k, v)) => cfg.insert_key_value(k.into(), v.into()), + } + } + } + _ => panic!("bad component: {:?}", component), + } + } + + ParsedMeta::File(FileMeta { path, krate, deps, edition, cfg }) +} + +fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { + let idx = haystack.find(delim)?; + Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) +} diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index eafa95921..7c8dac1d3 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -97,6 +97,7 @@ pub enum Edition { } impl Edition { + //FIXME: replace with FromStr with proper error handling pub fn from_string(s: &str) -> Edition { match s { "2015" => Edition::Edition2015, diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index bb775cfc9..875addc84 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -47,9 +47,6 @@ //! path and, upon success, we run macro expansion and "collect module" phase //! on the result -#[cfg(test)] -mod tests; - pub use hir_def::nameres::{ per_ns::{Namespace, PerNs}, raw::ImportId, diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs deleted file mode 100644 index 02db91a86..000000000 --- a/crates/ra_hir/src/nameres/tests.rs +++ /dev/null @@ -1,573 +0,0 @@ -mod macros; -mod globs; -mod incremental; -mod primitives; -mod mod_resolution; - -use std::sync::Arc; - -use hir_def::{db::DefDatabase2, nameres::*, CrateModuleId}; -use insta::assert_snapshot; -use ra_db::SourceDatabase; -// use test_utils::covers; - -use crate::mock::{CrateGraphFixture, MockDatabase}; - -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 krate = db.crate_graph().iter().next().unwrap(); - 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() - .map(|(name, res)| (name, res.def)) - .collect::>(); - entries.sort_by_key(|(name, _)| *name); - - for (name, res) in entries { - *buf += &format!("{}:", name); - - if res.types.is_some() { - *buf += " t"; - } - if res.values.is_some() { - *buf += " v"; - } - if res.macros.is_some() { - *buf += " m"; - } - if res.is_none() { - *buf += " _"; - } - - *buf += "\n"; - } - - for (name, child) in map.modules[module].children.iter() { - let path = path.to_string() + &format!("::{}", name); - go(buf, map, &path, *child); - } - } -} - -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(fixture: &str, graph: CrateGraphFixture) -> String { - let dm = compute_crate_def_map(fixture, 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!(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!(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!(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!(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!(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!(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!(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!(map, @r###" - ⋮crate - ⋮bar: t - ⋮foo: t - ⋮ - ⋮crate::bar - ⋮Bar: t v - ⋮ - ⋮crate::foo - ⋮Bar: t v - ⋮FromLib: t v - "###); -} - -#[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!(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!(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!(map, @r###" - ⋮crate - ⋮alloc_crate: t - ⋮sync: t - ⋮ - ⋮crate::sync - ⋮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!(map, - @r###" - ⋮crate - ⋮alloc_crate: t - ⋮sync: t - ⋮ - ⋮crate::sync - ⋮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!(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!(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!(map, @r###" - ⋮crate - ⋮Bar: t v - ⋮foo: v - "###); -} - -#[test] -fn cfg_not_test() { - let map = def_map_with_crate_graph( - r#" - //- /main.rs - use {Foo, Bar, Baz}; - //- /lib.rs - #[prelude_import] - pub use self::prelude::*; - mod prelude { - #[cfg(test)] - pub struct Foo; - #[cfg(not(test))] - pub struct Bar; - #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] - pub struct Baz; - } - "#, - crate_graph! { - "main": ("/main.rs", ["std"]), - "std": ("/lib.rs", []), - }, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮Bar: t v - ⋮Baz: _ - ⋮Foo: _ - "###); -} - -#[test] -fn cfg_test() { - let map = def_map_with_crate_graph( - r#" - //- /main.rs - use {Foo, Bar, Baz}; - //- /lib.rs - #[prelude_import] - pub use self::prelude::*; - mod prelude { - #[cfg(test)] - pub struct Foo; - #[cfg(not(test))] - pub struct Bar; - #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] - pub struct Baz; - } - "#, - crate_graph! { - "main": ("/main.rs", ["std"]), - "std": ("/lib.rs", [], cfg = { - "test", - "feature" = "foo", - "feature" = "bar", - "opt" = "42", - }), - }, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮Bar: _ - ⋮Baz: t v - ⋮Foo: t v - "###); -} diff --git a/crates/ra_hir/src/nameres/tests/globs.rs b/crates/ra_hir/src/nameres/tests/globs.rs deleted file mode 100644 index b3e4d8d94..000000000 --- a/crates/ra_hir/src/nameres/tests/globs.rs +++ /dev/null @@ -1,118 +0,0 @@ -use super::*; - -#[test] -fn glob_1() { - let map = def_map( - " - //- /lib.rs - mod foo; - use foo::*; - - //- /foo/mod.rs - pub mod bar; - pub use self::bar::Baz; - pub struct Foo; - - //- /foo/bar.rs - pub struct Baz; - ", - ); - assert_snapshot!(map, @r###" - ⋮crate - ⋮Baz: t v - ⋮Foo: t v - ⋮bar: t - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮Baz: t v - ⋮Foo: t v - ⋮bar: t - ⋮ - ⋮crate::foo::bar - ⋮Baz: t v - "### - ); -} - -#[test] -fn glob_2() { - let map = def_map( - " - //- /lib.rs - mod foo; - use foo::*; - - //- /foo/mod.rs - pub mod bar; - pub use self::bar::*; - pub struct Foo; - - //- /foo/bar.rs - pub struct Baz; - pub use super::*; - ", - ); - assert_snapshot!(map, @r###" - ⋮crate - ⋮Baz: t v - ⋮Foo: t v - ⋮bar: t - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮Baz: t v - ⋮Foo: t v - ⋮bar: t - ⋮ - ⋮crate::foo::bar - ⋮Baz: t v - ⋮Foo: t v - ⋮bar: t - "### - ); -} - -#[test] -fn glob_across_crates() { - // covers!(glob_across_crates); - let map = def_map_with_crate_graph( - " - //- /main.rs - use test_crate::*; - - //- /lib.rs - pub struct Baz; - ", - crate_graph! { - "main": ("/main.rs", ["test_crate"]), - "test_crate": ("/lib.rs", []), - }, - ); - assert_snapshot!(map, @r###" - ⋮crate - ⋮Baz: t v - "### - ); -} - -#[test] -fn glob_enum() { - // covers!(glob_enum); - let map = def_map( - " - //- /lib.rs - enum Foo { - Bar, Baz - } - use self::Foo::*; - ", - ); - assert_snapshot!(map, @r###" - ⋮crate - ⋮Bar: t v - ⋮Baz: t v - ⋮Foo: t - "### - ); -} diff --git a/crates/ra_hir/src/nameres/tests/incremental.rs b/crates/ra_hir/src/nameres/tests/incremental.rs deleted file mode 100644 index 723ece7b0..000000000 --- a/crates/ra_hir/src/nameres/tests/incremental.rs +++ /dev/null @@ -1,140 +0,0 @@ -use std::sync::Arc; - -use ra_db::{SourceDatabase, SourceDatabaseExt}; - -use super::*; - -fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) { - let (mut db, pos) = MockDatabase::with_position(initial); - let krate = db.crate_graph().iter().next().unwrap(); - { - let events = db.log_executed(|| { - db.crate_def_map(krate); - }); - assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) - } - db.set_file_text(pos.file_id, Arc::new(file_change.to_string())); - - { - let events = db.log_executed(|| { - db.crate_def_map(krate); - }); - assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) - } -} - -#[test] -fn typing_inside_a_function_should_not_invalidate_def_map() { - check_def_map_is_not_recomputed( - " - //- /lib.rs - mod foo;<|> - - use crate::foo::bar::Baz; - - fn foo() -> i32 { - 1 + 1 - } - //- /foo/mod.rs - pub mod bar; - - //- /foo/bar.rs - pub struct Baz; - ", - " - mod foo; - - use crate::foo::bar::Baz; - - fn foo() -> i32 { 92 } - ", - ); -} - -#[test] -fn adding_inner_items_should_not_invalidate_def_map() { - check_def_map_is_not_recomputed( - " - //- /lib.rs - struct S { a: i32} - enum E { A } - trait T { - fn a() {} - } - mod foo;<|> - impl S { - fn a() {} - } - use crate::foo::bar::Baz; - //- /foo/mod.rs - pub mod bar; - - //- /foo/bar.rs - pub struct Baz; - ", - " - struct S { a: i32, b: () } - enum E { A, B } - trait T { - fn a() {} - fn b() {} - } - mod foo;<|> - impl S { - fn a() {} - fn b() {} - } - use crate::foo::bar::Baz; - ", - ); -} - -#[test] -fn typing_inside_a_macro_should_not_invalidate_def_map() { - let (mut db, pos) = MockDatabase::with_position( - " - //- /lib.rs - macro_rules! m { - ($ident:ident) => { - fn f() { - $ident + $ident; - }; - } - } - mod foo; - - //- /foo/mod.rs - pub mod bar; - - //- /foo/bar.rs - <|> - m!(X); - ", - ); - { - let events = db.log_executed(|| { - let src = crate::Source { - file_id: pos.file_id.into(), - ast: crate::ModuleSource::new(&db, Some(pos.file_id), None), - }; - let module = crate::Module::from_definition(&db, src).unwrap(); - let decls = module.declarations(&db); - assert_eq!(decls.len(), 18); - }); - assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) - } - db.set_file_text(pos.file_id, Arc::new("m!(Y);".to_string())); - - { - let events = db.log_executed(|| { - let src = crate::Source { - file_id: pos.file_id.into(), - ast: crate::ModuleSource::new(&db, Some(pos.file_id), None), - }; - let module = crate::Module::from_definition(&db, src).unwrap(); - let decls = module.declarations(&db); - assert_eq!(decls.len(), 18); - }); - assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) - } -} diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs deleted file mode 100644 index 78bb0eb0d..000000000 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ /dev/null @@ -1,635 +0,0 @@ -use super::*; - -#[test] -fn macro_rules_are_globally_visible() { - let map = def_map( - " - //- /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 v - ⋮nested: t - ⋮ - ⋮crate::nested - ⋮Bar: t v - ⋮Baz: t v - "###); -} - -#[test] -fn macro_rules_can_define_modules() { - let map = def_map( - " - //- /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_with_crate_graph( - " - //- /main.rs - foo::structs!(Foo, Bar) - mod bar; - - //- /bar.rs - use crate::*; - - //- /lib.rs - #[macro_export] - macro_rules! structs { - ($($i:ident),*) => { - $(struct $i { field: u32 } )* - } - } - ", - crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/lib.rs", []), - }, - ); - assert_snapshot!(map, @r###" - ⋮crate - ⋮Bar: t v - ⋮Foo: t v - ⋮bar: t - ⋮ - ⋮crate::bar - ⋮Bar: t v - ⋮Foo: t v - ⋮bar: t - "###); -} - -#[test] -fn macro_rules_export_with_local_inner_macros_are_visible() { - let map = def_map_with_crate_graph( - " - //- /main.rs - foo::structs!(Foo, Bar) - mod bar; - - //- /bar.rs - use crate::*; - - //- /lib.rs - #[macro_export(local_inner_macros)] - macro_rules! structs { - ($($i:ident),*) => { - $(struct $i { field: u32 } )* - } - } - ", - crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/lib.rs", []), - }, - ); - assert_snapshot!(map, @r###" - ⋮crate - ⋮Bar: t v - ⋮Foo: t v - ⋮bar: t - ⋮ - ⋮crate::bar - ⋮Bar: t v - ⋮Foo: t v - ⋮bar: t - "###); -} - -#[test] -fn unexpanded_macro_should_expand_by_fixedpoint_loop() { - let map = def_map_with_crate_graph( - " - //- /main.rs - macro_rules! baz { - () => { - use foo::bar; - } - } - - foo!(); - bar!(); - baz!(); - - //- /lib.rs - #[macro_export] - macro_rules! foo { - () => { - struct Foo { field: u32 } - } - } - #[macro_export] - macro_rules! bar { - () => { - use foo::foo; - } - } - ", - crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/lib.rs", []), - }, - ); - assert_snapshot!(map, @r###" - ⋮crate - ⋮Foo: t v - ⋮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_with_crate_graph( - " - //- /main.rs - 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 - #[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; } - } - } - ", - crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/lib.rs", []), - }, - ); - 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_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 - "###); -} - -#[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_with_crate_graph( - " - //- /main.rs - #[macro_use] - extern crate foo; - - foo!(Direct); - bar!(Alias); - - //- /lib.rs - use crate::foo as bar; - - mod m { - #[macro_export] - macro_rules! foo { - ($x:ident) => { struct $x; } - } - } - ", - crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/lib.rs", []), - }, - ); - 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_with_crate_graph( - " - //- /main.rs - #[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 - mod m { - #[macro_export] - macro_rules! not_current1 { - () => { - use $crate::Bar; - } - } - } - - #[macro_export] - macro_rules! not_current2 { - () => { - use $crate::Baz; - } - } - - struct Bar; - struct Baz; - ", - crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/lib.rs", []), - }, - ); - 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_with_crate_graph( - r#" - //- /main.rs - foo!(); - - //- /std.rs - #[prelude_import] - use self::prelude::*; - - pub use core::foo; - - mod prelude {} - - #[macro_use] - mod std_macros; - - //- /core.rs - #[macro_export] - macro_rules! foo { - () => { - use $crate::bar; - } - } - - pub struct bar; - "#, - crate_graph! { - "main": ("/main.rs", ["std"]), - "std": ("/std.rs", ["core"]), - "core": ("/core.rs", []), - }, - ); - assert_snapshot!(map, @r###" - ⋮crate - ⋮bar: t v - "###); -} diff --git a/crates/ra_hir/src/nameres/tests/mod_resolution.rs b/crates/ra_hir/src/nameres/tests/mod_resolution.rs deleted file mode 100644 index abfe8b1c3..000000000 --- a/crates/ra_hir/src/nameres/tests/mod_resolution.rs +++ /dev/null @@ -1,759 +0,0 @@ -use super::*; - -#[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!(map, @r###" - ⋮crate - ⋮Baz: _ - "###); -} - -#[test] -fn nested_module_resolution() { - let map = def_map( - " - //- /lib.rs - mod n1; - - //- /n1.rs - mod n2; - - //- /n1/n2.rs - struct X; - ", - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮n1: t - ⋮ - ⋮crate::n1 - ⋮n2: t - ⋮ - ⋮crate::n1::n2 - ⋮X: 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!(map, @r###" - ⋮crate - ⋮Bar: t v - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮Bar: t v - "###); -} - -#[test] -fn module_resolution_works_for_raw_modules() { - let map = def_map( - " - //- /lib.rs - mod r#async; - use self::r#async::Bar; - - //- /async.rs - pub struct Bar; - ", - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮Bar: t v - ⋮async: t - ⋮ - ⋮crate::async - ⋮Bar: t v - "###); -} - -#[test] -fn module_resolution_decl_path() { - let map = def_map( - r###" - //- /lib.rs - #[path = "bar/baz/foo.rs"] - mod foo; - use self::foo::Bar; - - //- /bar/baz/foo.rs - pub struct Bar; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮Bar: t v - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮Bar: t v - "###); -} - -#[test] -fn module_resolution_module_with_path_in_mod_rs() { - let map = def_map( - r###" - //- /main.rs - mod foo; - - //- /foo/mod.rs - #[path = "baz.rs"] - pub mod bar; - - use self::bar::Baz; - - //- /foo/baz.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮Baz: t v - ⋮bar: t - ⋮ - ⋮crate::foo::bar - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_module_with_path_non_crate_root() { - let map = def_map( - r###" - //- /main.rs - mod foo; - - //- /foo.rs - #[path = "baz.rs"] - pub mod bar; - - use self::bar::Baz; - - //- /baz.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮Baz: t v - ⋮bar: t - ⋮ - ⋮crate::foo::bar - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_module_decl_path_super() { - let map = def_map( - r###" - //- /main.rs - #[path = "bar/baz/module.rs"] - mod foo; - pub struct Baz; - - //- /bar/baz/module.rs - use super::Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮Baz: t v - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_explicit_path_mod_rs() { - let map = def_map( - r###" - //- /main.rs - #[path = "module/mod.rs"] - mod foo; - - //- /module/mod.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_relative_path() { - let map = def_map( - r###" - //- /main.rs - mod foo; - - //- /foo.rs - #[path = "./sub.rs"] - pub mod foo_bar; - - //- /sub.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮foo_bar: t - ⋮ - ⋮crate::foo::foo_bar - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_relative_path_2() { - let map = def_map( - r###" - //- /main.rs - mod foo; - - //- /foo/mod.rs - #[path="../sub.rs"] - pub mod foo_bar; - - //- /sub.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮foo_bar: t - ⋮ - ⋮crate::foo::foo_bar - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_explicit_path_mod_rs_2() { - let map = def_map( - r###" - //- /main.rs - #[path = "module/bar/mod.rs"] - mod foo; - - //- /module/bar/mod.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_explicit_path_mod_rs_with_win_separator() { - let map = def_map( - r###" - //- /main.rs - #[path = "module\bar\mod.rs"] - mod foo; - - //- /module/bar/mod.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_decl_inside_inline_module_with_path_attribute() { - let map = def_map( - r###" - //- /main.rs - #[path = "models"] - mod foo { - mod bar; - } - - //- /models/bar.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮bar: t - ⋮ - ⋮crate::foo::bar - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_decl_inside_inline_module() { - let map = def_map( - r###" - //- /main.rs - mod foo { - mod bar; - } - - //- /foo/bar.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮bar: t - ⋮ - ⋮crate::foo::bar - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_decl_inside_inline_module_2_with_path_attribute() { - let map = def_map( - r###" - //- /main.rs - #[path = "models/db"] - mod foo { - mod bar; - } - - //- /models/db/bar.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮bar: t - ⋮ - ⋮crate::foo::bar - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_decl_inside_inline_module_3() { - let map = def_map( - r###" - //- /main.rs - #[path = "models/db"] - mod foo { - #[path = "users.rs"] - mod bar; - } - - //- /models/db/users.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮bar: t - ⋮ - ⋮crate::foo::bar - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_decl_inside_inline_module_empty_path() { - let map = def_map( - r###" - //- /main.rs - #[path = ""] - mod foo { - #[path = "users.rs"] - mod bar; - } - - //- /users.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮bar: t - ⋮ - ⋮crate::foo::bar - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_decl_empty_path() { - let map = def_map( - r###" - //- /main.rs - #[path = ""] // Should try to read `/` (a directory) - mod foo; - - //- /foo.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - "###); -} - -#[test] -fn module_resolution_decl_inside_inline_module_relative_path() { - let map = def_map( - r###" - //- /main.rs - #[path = "./models"] - mod foo { - mod bar; - } - - //- /models/bar.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮bar: t - ⋮ - ⋮crate::foo::bar - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_decl_inside_inline_module_in_crate_root() { - let map = def_map( - r###" - //- /main.rs - mod foo { - #[path = "baz.rs"] - mod bar; - } - use self::foo::bar::Baz; - - //- /foo/baz.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮Baz: t v - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮bar: t - ⋮ - ⋮crate::foo::bar - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_decl_inside_inline_module_in_mod_rs() { - let map = def_map( - r###" - //- /main.rs - mod foo; - - //- /foo/mod.rs - mod bar { - #[path = "qwe.rs"] - pub mod baz; - } - use self::bar::baz::Baz; - - //- /foo/bar/qwe.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮Baz: t v - ⋮bar: t - ⋮ - ⋮crate::foo::bar - ⋮baz: t - ⋮ - ⋮crate::foo::bar::baz - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_decl_inside_inline_module_in_non_crate_root() { - let map = def_map( - r###" - //- /main.rs - mod foo; - - //- /foo.rs - mod bar { - #[path = "qwe.rs"] - pub mod baz; - } - use self::bar::baz::Baz; - - //- /foo/bar/qwe.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮Baz: t v - ⋮bar: t - ⋮ - ⋮crate::foo::bar - ⋮baz: t - ⋮ - ⋮crate::foo::bar::baz - ⋮Baz: t v - "###); -} - -#[test] -fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { - let map = def_map( - r###" - //- /main.rs - mod foo; - - //- /foo.rs - #[path = "bar"] - mod bar { - pub mod baz; - } - use self::bar::baz::Baz; - - //- /bar/baz.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮ - ⋮crate::foo - ⋮Baz: t v - ⋮bar: t - ⋮ - ⋮crate::foo::bar - ⋮baz: t - ⋮ - ⋮crate::foo::bar::baz - ⋮Baz: t 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!(diagnostics, @r###" - "mod bar;": unresolved module - "### - ); -} - -#[test] -fn module_resolution_decl_inside_module_in_non_crate_root_2() { - let map = def_map( - r###" - //- /main.rs - #[path="module/m2.rs"] - mod module; - - //- /module/m2.rs - pub mod submod; - - //- /module/submod.rs - pub struct Baz; - "###, - ); - - assert_snapshot!(map, @r###" - ⋮crate - ⋮module: t - ⋮ - ⋮crate::module - ⋮submod: t - ⋮ - ⋮crate::module::submod - ⋮Baz: t v - "###); -} - -#[test] -fn nested_out_of_line_module() { - let map = def_map( - r###" - //- /lib.rs - mod a { - mod b { - mod c; - } - } - - //- /a/b/c.rs - struct X; - "###, - ); - - assert_snapshot!(map, @r###" - crate - a: t - - crate::a - b: t - - crate::a::b - c: t - - crate::a::b::c - X: t v - "###); -} - -#[test] -fn nested_out_of_line_module_with_path() { - let map = def_map( - r###" - //- /lib.rs - mod a { - #[path = "d/e"] - mod b { - mod c; - } - } - - //- /a/d/e/c.rs - struct X; - "###, - ); - - assert_snapshot!(map, @r###" - crate - a: t - - crate::a - b: t - - crate::a::b - c: t - - crate::a::b::c - X: t v - "###); -} diff --git a/crates/ra_hir/src/nameres/tests/primitives.rs b/crates/ra_hir/src/nameres/tests/primitives.rs deleted file mode 100644 index 0e2708658..000000000 --- a/crates/ra_hir/src/nameres/tests/primitives.rs +++ /dev/null @@ -1,24 +0,0 @@ -use super::*; - -#[test] -fn primitive_reexport() { - let map = def_map( - " - //- /lib.rs - mod foo; - use foo::int; - - //- /foo.rs - pub use i32 as int; - ", - ); - assert_snapshot!(map, @r###" - ⋮crate - ⋮foo: t - ⋮int: t - ⋮ - ⋮crate::foo - ⋮int: t - "### - ); -} diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index 746c907e8..15055db64 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml @@ -19,3 +19,7 @@ test_utils = { path = "../test_utils" } mbe = { path = "../ra_mbe", package = "ra_mbe" } ra_cfg = { path = "../ra_cfg" } tt = { path = "../ra_tt", package = "ra_tt" } + +[dev-dependencies] +insta = "0.12.0" + diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index db59344aa..b3640da3d 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs @@ -6,6 +6,9 @@ pub mod per_ns; pub mod collector; pub mod mod_resolution; +#[cfg(test)] +mod tests; + use std::sync::Arc; use hir_expand::{diagnostics::DiagnosticSink, name::Name, MacroDefId}; diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs new file mode 100644 index 000000000..f9a8edd43 --- /dev/null +++ b/crates/ra_hir_def/src/nameres/tests.rs @@ -0,0 +1,522 @@ +mod globs; +mod incremental; +mod macros; +mod mod_resolution; +mod primitives; + +use std::sync::Arc; + +use insta::assert_snapshot; +use ra_db::{fixture::WithFixture, SourceDatabase}; +// use test_utils::covers; + +use crate::{db::DefDatabase2, nameres::*, test_db::TestDB, CrateModuleId}; + +fn def_map(fixtute: &str) -> String { + let dm = compute_crate_def_map(fixtute); + render_crate_def_map(&dm) +} + +fn compute_crate_def_map(fixture: &str) -> Arc { + let db = TestDB::with_files(fixture); + let krate = db.crate_graph().iter().next().unwrap(); + 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() + .map(|(name, res)| (name, res.def)) + .collect::>(); + entries.sort_by_key(|(name, _)| *name); + + for (name, res) in entries { + *buf += &format!("{}:", name); + + if res.types.is_some() { + *buf += " t"; + } + if res.values.is_some() { + *buf += " v"; + } + if res.macros.is_some() { + *buf += " m"; + } + if res.is_none() { + *buf += " _"; + } + + *buf += "\n"; + } + + for (name, child) in map.modules[module].children.iter() { + let path = path.to_string() + &format!("::{}", name); + go(buf, map, &path, *child); + } + } +} + +#[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!(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!(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!(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!(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!(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( + " + //- /main.rs crate:main deps:test_crate + use Foo::*; + + //- /lib.rs crate:test_crate + mod prelude; + #[prelude_import] + use prelude::*; + + //- /prelude.rs + pub enum Foo { Bar, Baz }; + ", + ); + assert_snapshot!(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!(map, @r###" + ⋮crate + ⋮E: t + ⋮V: t v + "### + ); +} + +#[test] +fn edition_2015_imports() { + let map = def_map( + " + //- /main.rs crate:main deps:other_crate edition:2015 + mod foo; + mod bar; + + //- /bar.rs + struct Bar; + + //- /foo.rs + use bar::Bar; + use other_crate::FromLib; + + //- /lib.rs crate:other_crate edition:2018 + struct FromLib; + ", + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮bar: t + ⋮foo: t + ⋮ + ⋮crate::bar + ⋮Bar: t v + ⋮ + ⋮crate::foo + ⋮Bar: t v + ⋮FromLib: t v + "###); +} + +#[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!(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( + " + //- /main.rs crate:main deps:test_crate + use test_crate::Baz; + + //- /lib.rs crate:test_crate + pub struct Baz; + ", + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮Baz: t v + "###); +} + +#[test] +fn extern_crate_rename() { + let map = def_map( + " + //- /main.rs crate:main deps:alloc + extern crate alloc as alloc_crate; + + mod alloc; + mod sync; + + //- /sync.rs + use alloc_crate::Arc; + + //- /lib.rs crate:alloc + struct Arc; + ", + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮alloc_crate: t + ⋮sync: t + ⋮ + ⋮crate::sync + ⋮Arc: t v + "###); +} + +#[test] +fn extern_crate_rename_2015_edition() { + let map = def_map( + " + //- /main.rs crate:main deps:alloc edition:2015 + extern crate alloc as alloc_crate; + + mod alloc; + mod sync; + + //- /sync.rs + use alloc_crate::Arc; + + //- /lib.rs crate:alloc + struct Arc; + ", + ); + + assert_snapshot!(map, + @r###" + ⋮crate + ⋮alloc_crate: t + ⋮sync: t + ⋮ + ⋮crate::sync + ⋮Arc: t v + "### + ); +} + +#[test] +fn import_across_source_roots() { + let map = def_map( + " + //- /main.rs crate:main deps:test_crate + use test_crate::a::b::C; + + //- root /test_crate/ + + //- /test_crate/lib.rs crate:test_crate + pub mod a { + pub mod b { + pub struct C; + } + } + + ", + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮C: t v + "###); +} + +#[test] +fn reexport_across_crates() { + let map = def_map( + " + //- /main.rs crate:main deps:test_crate + use test_crate::Baz; + + //- /lib.rs crate:test_crate + pub use foo::Baz; + + mod foo; + + //- /foo.rs + pub struct Baz; + ", + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮Baz: t v + "###); +} + +#[test] +fn values_dont_shadow_extern_crates() { + let map = def_map( + " + //- /main.rs crate:main deps:foo + fn foo() {} + use foo::Bar; + + //- /foo/lib.rs crate:foo + pub struct Bar; + ", + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮Bar: t v + ⋮foo: v + "###); +} + +#[test] +fn cfg_not_test() { + let map = def_map( + r#" + //- /main.rs crate:main deps:std + use {Foo, Bar, Baz}; + + //- /lib.rs crate:std + #[prelude_import] + pub use self::prelude::*; + mod prelude { + #[cfg(test)] + pub struct Foo; + #[cfg(not(test))] + pub struct Bar; + #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] + pub struct Baz; + } + "#, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮Bar: t v + ⋮Baz: _ + ⋮Foo: _ + "###); +} + +#[test] +fn cfg_test() { + let map = def_map( + r#" + //- /main.rs crate:main deps:std + use {Foo, Bar, Baz}; + + //- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42 + #[prelude_import] + pub use self::prelude::*; + mod prelude { + #[cfg(test)] + pub struct Foo; + #[cfg(not(test))] + pub struct Bar; + #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] + pub struct Baz; + } + "#, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮Bar: _ + ⋮Baz: t v + ⋮Foo: t v + "###); +} diff --git a/crates/ra_hir_def/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs new file mode 100644 index 000000000..cf4a2a851 --- /dev/null +++ b/crates/ra_hir_def/src/nameres/tests/globs.rs @@ -0,0 +1,114 @@ +use super::*; + +#[test] +fn glob_1() { + let map = def_map( + " + //- /lib.rs + mod foo; + use foo::*; + + //- /foo/mod.rs + pub mod bar; + pub use self::bar::Baz; + pub struct Foo; + + //- /foo/bar.rs + pub struct Baz; + ", + ); + assert_snapshot!(map, @r###" + ⋮crate + ⋮Baz: t v + ⋮Foo: t v + ⋮bar: t + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + ⋮Foo: t v + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "### + ); +} + +#[test] +fn glob_2() { + let map = def_map( + " + //- /lib.rs + mod foo; + use foo::*; + + //- /foo/mod.rs + pub mod bar; + pub use self::bar::*; + pub struct Foo; + + //- /foo/bar.rs + pub struct Baz; + pub use super::*; + ", + ); + assert_snapshot!(map, @r###" + ⋮crate + ⋮Baz: t v + ⋮Foo: t v + ⋮bar: t + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + ⋮Foo: t v + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + ⋮Foo: t v + ⋮bar: t + "### + ); +} + +#[test] +fn glob_across_crates() { + // covers!(glob_across_crates); + let map = def_map( + " + //- /main.rs crate:main deps:test_crate + use test_crate::*; + + //- /lib.rs crate:test_crate + pub struct Baz; + ", + ); + assert_snapshot!(map, @r###" + ⋮crate + ⋮Baz: t v + "### + ); +} + +#[test] +fn glob_enum() { + // covers!(glob_enum); + let map = def_map( + " + //- /lib.rs + enum Foo { + Bar, Baz + } + use self::Foo::*; + ", + ); + assert_snapshot!(map, @r###" + ⋮crate + ⋮Bar: t v + ⋮Baz: t v + ⋮Foo: t + "### + ); +} diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs new file mode 100644 index 000000000..80dcec62f --- /dev/null +++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs @@ -0,0 +1,133 @@ +use std::sync::Arc; + +use ra_db::{SourceDatabase, SourceDatabaseExt}; + +use super::*; + +fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) { + let (mut db, pos) = TestDB::with_position(initial); + let krate = db.crate_graph().iter().next().unwrap(); + { + let events = db.log_executed(|| { + db.crate_def_map(krate); + }); + assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) + } + db.set_file_text(pos.file_id, Arc::new(file_change.to_string())); + + { + let events = db.log_executed(|| { + db.crate_def_map(krate); + }); + assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) + } +} + +#[test] +fn typing_inside_a_function_should_not_invalidate_def_map() { + check_def_map_is_not_recomputed( + " + //- /lib.rs + mod foo;<|> + + use crate::foo::bar::Baz; + + fn foo() -> i32 { + 1 + 1 + } + //- /foo/mod.rs + pub mod bar; + + //- /foo/bar.rs + pub struct Baz; + ", + " + mod foo; + + use crate::foo::bar::Baz; + + fn foo() -> i32 { 92 } + ", + ); +} + +#[test] +fn adding_inner_items_should_not_invalidate_def_map() { + check_def_map_is_not_recomputed( + " + //- /lib.rs + struct S { a: i32} + enum E { A } + trait T { + fn a() {} + } + mod foo;<|> + impl S { + fn a() {} + } + use crate::foo::bar::Baz; + //- /foo/mod.rs + pub mod bar; + + //- /foo/bar.rs + pub struct Baz; + ", + " + struct S { a: i32, b: () } + enum E { A, B } + trait T { + fn a() {} + fn b() {} + } + mod foo;<|> + impl S { + fn a() {} + fn b() {} + } + use crate::foo::bar::Baz; + ", + ); +} + +#[test] +fn typing_inside_a_macro_should_not_invalidate_def_map() { + let (mut db, pos) = TestDB::with_position( + " + //- /lib.rs + macro_rules! m { + ($ident:ident) => { + fn f() { + $ident + $ident; + }; + } + } + mod foo; + + //- /foo/mod.rs + pub mod bar; + + //- /foo/bar.rs + <|> + m!(X); + ", + ); + let krate = db.crate_graph().iter().next().unwrap(); + { + let events = db.log_executed(|| { + let crate_def_map = db.crate_def_map(krate); + let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); + assert_eq!(module_data.scope.items.len(), 1); + }); + assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) + } + db.set_file_text(pos.file_id, Arc::new("m!(Y);".to_string())); + + { + let events = db.log_executed(|| { + let crate_def_map = db.crate_def_map(krate); + let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); + assert_eq!(module_data.scope.items.len(), 1); + }); + assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) + } +} diff --git a/crates/ra_hir_def/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs new file mode 100644 index 000000000..9bb3895ad --- /dev/null +++ b/crates/ra_hir_def/src/nameres/tests/macros.rs @@ -0,0 +1,602 @@ +use super::*; + +#[test] +fn macro_rules_are_globally_visible() { + let map = def_map( + " + //- /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 v + ⋮nested: t + ⋮ + ⋮crate::nested + ⋮Bar: t v + ⋮Baz: t v + "###); +} + +#[test] +fn macro_rules_can_define_modules() { + let map = def_map( + " + //- /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 v + ⋮Foo: t v + ⋮bar: t + ⋮ + ⋮crate::bar + ⋮Bar: t v + ⋮Foo: t v + ⋮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 v + ⋮Foo: t v + ⋮bar: t + ⋮ + ⋮crate::bar + ⋮Bar: t v + ⋮Foo: t v + ⋮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 v + ⋮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 + "###); +} diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs new file mode 100644 index 000000000..8d804a63e --- /dev/null +++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs @@ -0,0 +1,782 @@ +use super::*; + +#[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!(map, @r###" + ⋮crate + ⋮Baz: _ + "###); +} + +#[test] +fn nested_module_resolution() { + let map = def_map( + " + //- /lib.rs + mod n1; + + //- /n1.rs + mod n2; + + //- /n1/n2.rs + struct X; + ", + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮n1: t + ⋮ + ⋮crate::n1 + ⋮n2: t + ⋮ + ⋮crate::n1::n2 + ⋮X: t v + "###); +} + +#[test] +fn module_resolution_works_for_non_standard_filenames() { + let map = def_map( + " + //- /my_library.rs crate:my_library + mod foo; + use self::foo::Bar; + + //- /foo/mod.rs + pub struct Bar; + ", + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮Bar: t v + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Bar: t v + "###); +} + +#[test] +fn module_resolution_works_for_raw_modules() { + let map = def_map( + " + //- /lib.rs + mod r#async; + use self::r#async::Bar; + + //- /async.rs + pub struct Bar; + ", + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮Bar: t v + ⋮async: t + ⋮ + ⋮crate::async + ⋮Bar: t v + "###); +} + +#[test] +fn module_resolution_decl_path() { + let map = def_map( + r###" + //- /lib.rs + #[path = "bar/baz/foo.rs"] + mod foo; + use self::foo::Bar; + + //- /bar/baz/foo.rs + pub struct Bar; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮Bar: t v + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Bar: t v + "###); +} + +#[test] +fn module_resolution_module_with_path_in_mod_rs() { + let map = def_map( + r###" + //- /main.rs + mod foo; + + //- /foo/mod.rs + #[path = "baz.rs"] + pub mod bar; + + use self::bar::Baz; + + //- /foo/baz.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_module_with_path_non_crate_root() { + let map = def_map( + r###" + //- /main.rs + mod foo; + + //- /foo.rs + #[path = "baz.rs"] + pub mod bar; + + use self::bar::Baz; + + //- /baz.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_module_decl_path_super() { + let map = def_map( + r###" + //- /main.rs + #[path = "bar/baz/module.rs"] + mod foo; + pub struct Baz; + + //- /bar/baz/module.rs + use super::Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮Baz: t v + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_explicit_path_mod_rs() { + let map = def_map( + r###" + //- /main.rs + #[path = "module/mod.rs"] + mod foo; + + //- /module/mod.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_relative_path() { + let map = def_map( + r###" + //- /main.rs + mod foo; + + //- /foo.rs + #[path = "./sub.rs"] + pub mod foo_bar; + + //- /sub.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮foo_bar: t + ⋮ + ⋮crate::foo::foo_bar + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_relative_path_2() { + let map = def_map( + r###" + //- /main.rs + mod foo; + + //- /foo/mod.rs + #[path="../sub.rs"] + pub mod foo_bar; + + //- /sub.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮foo_bar: t + ⋮ + ⋮crate::foo::foo_bar + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_explicit_path_mod_rs_2() { + let map = def_map( + r###" + //- /main.rs + #[path = "module/bar/mod.rs"] + mod foo; + + //- /module/bar/mod.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_explicit_path_mod_rs_with_win_separator() { + let map = def_map( + r###" + //- /main.rs + #[path = "module\bar\mod.rs"] + mod foo; + + //- /module/bar/mod.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_decl_inside_inline_module_with_path_attribute() { + let map = def_map( + r###" + //- /main.rs + #[path = "models"] + mod foo { + mod bar; + } + + //- /models/bar.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_decl_inside_inline_module() { + let map = def_map( + r###" + //- /main.rs + mod foo { + mod bar; + } + + //- /foo/bar.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_decl_inside_inline_module_2_with_path_attribute() { + let map = def_map( + r###" + //- /main.rs + #[path = "models/db"] + mod foo { + mod bar; + } + + //- /models/db/bar.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_decl_inside_inline_module_3() { + let map = def_map( + r###" + //- /main.rs + #[path = "models/db"] + mod foo { + #[path = "users.rs"] + mod bar; + } + + //- /models/db/users.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_decl_inside_inline_module_empty_path() { + let map = def_map( + r###" + //- /main.rs + #[path = ""] + mod foo { + #[path = "users.rs"] + mod bar; + } + + //- /users.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_decl_empty_path() { + let map = def_map( + r###" + //- /main.rs + #[path = ""] // Should try to read `/` (a directory) + mod foo; + + //- /foo.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + "###); +} + +#[test] +fn module_resolution_decl_inside_inline_module_relative_path() { + let map = def_map( + r###" + //- /main.rs + #[path = "./models"] + mod foo { + mod bar; + } + + //- /models/bar.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_decl_inside_inline_module_in_crate_root() { + let map = def_map( + r###" + //- /main.rs + mod foo { + #[path = "baz.rs"] + mod bar; + } + use self::foo::bar::Baz; + + //- /foo/baz.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮Baz: t v + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_decl_inside_inline_module_in_mod_rs() { + let map = def_map( + r###" + //- /main.rs + mod foo; + + //- /foo/mod.rs + mod bar { + #[path = "qwe.rs"] + pub mod baz; + } + use self::bar::baz::Baz; + + //- /foo/bar/qwe.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮baz: t + ⋮ + ⋮crate::foo::bar::baz + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_decl_inside_inline_module_in_non_crate_root() { + let map = def_map( + r###" + //- /main.rs + mod foo; + + //- /foo.rs + mod bar { + #[path = "qwe.rs"] + pub mod baz; + } + use self::bar::baz::Baz; + + //- /foo/bar/qwe.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮baz: t + ⋮ + ⋮crate::foo::bar::baz + ⋮Baz: t v + "###); +} + +#[test] +fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { + let map = def_map( + r###" + //- /main.rs + mod foo; + + //- /foo.rs + #[path = "bar"] + mod bar { + pub mod baz; + } + use self::bar::baz::Baz; + + //- /bar/baz.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮ + ⋮crate::foo + ⋮Baz: t v + ⋮bar: t + ⋮ + ⋮crate::foo::bar + ⋮baz: t + ⋮ + ⋮crate::foo::bar::baz + ⋮Baz: t v + "###); +} + +#[test] +fn unresolved_module_diagnostics() { + let db = TestDB::with_files( + r" + //- /lib.rs + mod foo; + mod bar; + mod baz {} + //- /foo.rs + ", + ); + let krate = db.crate_graph().iter().next().unwrap(); + + let crate_def_map = db.crate_def_map(krate); + + insta::assert_debug_snapshot!( + crate_def_map.diagnostics, + @r###" + [ + UnresolvedModule { + module: CrateModuleId( + 0, + ), + declaration: AstId { + file_id: HirFileId( + FileId( + FileId( + 0, + ), + ), + ), + file_ast_id: FileAstId { + raw: ErasedFileAstId( + 1, + ), + _ty: PhantomData, + }, + }, + candidate: "bar.rs", + }, + ] + "### + ); +} + +#[test] +fn module_resolution_decl_inside_module_in_non_crate_root_2() { + let map = def_map( + r###" + //- /main.rs + #[path="module/m2.rs"] + mod module; + + //- /module/m2.rs + pub mod submod; + + //- /module/submod.rs + pub struct Baz; + "###, + ); + + assert_snapshot!(map, @r###" + ⋮crate + ⋮module: t + ⋮ + ⋮crate::module + ⋮submod: t + ⋮ + ⋮crate::module::submod + ⋮Baz: t v + "###); +} + +#[test] +fn nested_out_of_line_module() { + let map = def_map( + r###" + //- /lib.rs + mod a { + mod b { + mod c; + } + } + + //- /a/b/c.rs + struct X; + "###, + ); + + assert_snapshot!(map, @r###" + crate + a: t + + crate::a + b: t + + crate::a::b + c: t + + crate::a::b::c + X: t v + "###); +} + +#[test] +fn nested_out_of_line_module_with_path() { + let map = def_map( + r###" + //- /lib.rs + mod a { + #[path = "d/e"] + mod b { + mod c; + } + } + + //- /a/d/e/c.rs + struct X; + "###, + ); + + assert_snapshot!(map, @r###" + crate + a: t + + crate::a + b: t + + crate::a::b + c: t + + crate::a::b::c + X: t v + "###); +} diff --git a/crates/ra_hir_def/src/nameres/tests/primitives.rs b/crates/ra_hir_def/src/nameres/tests/primitives.rs new file mode 100644 index 000000000..0e2708658 --- /dev/null +++ b/crates/ra_hir_def/src/nameres/tests/primitives.rs @@ -0,0 +1,24 @@ +use super::*; + +#[test] +fn primitive_reexport() { + let map = def_map( + " + //- /lib.rs + mod foo; + use foo::int; + + //- /foo.rs + pub use i32 as int; + ", + ); + assert_snapshot!(map, @r###" + ⋮crate + ⋮foo: t + ⋮int: t + ⋮ + ⋮crate::foo + ⋮int: t + "### + ); +} diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs index 67714c68e..05018f8e4 100644 --- a/crates/ra_hir_def/src/test_db.rs +++ b/crates/ra_hir_def/src/test_db.rs @@ -1,4 +1,7 @@ -use std::{panic, sync::Arc}; +use std::{ + panic, + sync::{Arc, Mutex}, +}; use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate}; use relative_path::RelativePath; @@ -13,12 +16,20 @@ use relative_path::RelativePath; #[derive(Debug, Default)] pub struct TestDB { runtime: salsa::Runtime, + events: Mutex>>>, } impl salsa::Database for TestDB { fn salsa_runtime(&self) -> &salsa::Runtime { &self.runtime } + + fn salsa_event(&self, event: impl Fn() -> salsa::Event) { + let mut events = self.events.lock().unwrap(); + if let Some(events) = &mut *events { + events.push(event()); + } + } } impl panic::RefUnwindSafe for TestDB {} @@ -38,3 +49,26 @@ impl FileLoader for TestDB { FileLoaderDelegate(self).relevant_crates(file_id) } } + +impl TestDB { + pub fn log(&self, f: impl FnOnce()) -> Vec> { + *self.events.lock().unwrap() = Some(Vec::new()); + f(); + self.events.lock().unwrap().take().unwrap() + } + + pub fn log_executed(&self, f: impl FnOnce()) -> Vec { + let events = self.log(f); + events + .into_iter() + .filter_map(|e| match e.kind { + // This pretty horrible, but `Debug` is the only way to inspect + // QueryDescriptor at the moment. + salsa::EventKind::WillExecute { database_key } => { + Some(format!("{:?}", database_key)) + } + _ => None, + }) + .collect() + } +} -- cgit v1.2.3