From fd4456d0ec88e3433a7a8be6f27d8af9afedefe5 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 6 Jan 2019 17:33:27 +0300 Subject: flatten module structure --- crates/ra_hir/src/module/imp.rs | 190 ----------- crates/ra_hir/src/module/nameres.rs | 509 ------------------------------ crates/ra_hir/src/module/nameres/tests.rs | 273 ---------------- 3 files changed, 972 deletions(-) delete mode 100644 crates/ra_hir/src/module/imp.rs delete mode 100644 crates/ra_hir/src/module/nameres.rs delete mode 100644 crates/ra_hir/src/module/nameres/tests.rs (limited to 'crates/ra_hir/src/module') diff --git a/crates/ra_hir/src/module/imp.rs b/crates/ra_hir/src/module/imp.rs deleted file mode 100644 index 3849026db..000000000 --- a/crates/ra_hir/src/module/imp.rs +++ /dev/null @@ -1,190 +0,0 @@ -use std::sync::Arc; - -use ra_syntax::ast::{self, NameOwner}; -use relative_path::RelativePathBuf; -use rustc_hash::{FxHashMap, FxHashSet}; -use arrayvec::ArrayVec; -use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId}; - -use crate::{ - HirDatabase, Name, AsName, -}; - -use super::{ - LinkData, LinkId, ModuleData, ModuleId, ModuleSource, - ModuleTree, Problem, -}; - -#[derive(Clone, Hash, PartialEq, Eq, Debug)] -pub enum Submodule { - Declaration(Name), - Definition(Name, ModuleSource), -} - -impl Submodule { - fn name(&self) -> &Name { - match self { - Submodule::Declaration(name) => name, - Submodule::Definition(name, _) => name, - } - } -} - -pub(crate) fn modules<'a>( - root: impl ast::ModuleItemOwner<'a>, -) -> impl Iterator)> { - root.items() - .filter_map(|item| match item { - ast::ModuleItem::Module(m) => Some(m), - _ => None, - }) - .filter_map(|module| { - let name = module.name()?.as_name(); - Some((name, module)) - }) -} - -pub(crate) fn module_tree( - db: &impl HirDatabase, - source_root: SourceRootId, -) -> Cancelable> { - db.check_canceled()?; - let res = create_module_tree(db, source_root)?; - Ok(Arc::new(res)) -} - -fn create_module_tree<'a>( - db: &impl HirDatabase, - source_root: SourceRootId, -) -> Cancelable { - let mut tree = ModuleTree::default(); - - let mut roots = FxHashMap::default(); - let mut visited = FxHashSet::default(); - - let source_root = db.source_root(source_root); - for &file_id in source_root.files.values() { - let source = ModuleSource::new_file(file_id.into()); - if visited.contains(&source) { - continue; // TODO: use explicit crate_roots here - } - assert!(!roots.contains_key(&file_id)); - let module_id = build_subtree( - db, - &source_root, - &mut tree, - &mut visited, - &mut roots, - None, - source, - )?; - roots.insert(file_id, module_id); - } - Ok(tree) -} - -fn build_subtree( - db: &impl HirDatabase, - source_root: &SourceRoot, - tree: &mut ModuleTree, - visited: &mut FxHashSet, - roots: &mut FxHashMap, - parent: Option, - source: ModuleSource, -) -> Cancelable { - visited.insert(source); - let id = tree.push_mod(ModuleData { - source, - parent, - children: Vec::new(), - }); - for sub in db.submodules(source)?.iter() { - let link = tree.push_link(LinkData { - name: sub.name().clone(), - owner: id, - points_to: Vec::new(), - problem: None, - }); - - let (points_to, problem) = match sub { - Submodule::Declaration(name) => { - let (points_to, problem) = resolve_submodule(db, source, &name); - let points_to = points_to - .into_iter() - .map(|file_id| match roots.remove(&file_id) { - Some(module_id) => { - tree.mods[module_id].parent = Some(link); - Ok(module_id) - } - None => build_subtree( - db, - source_root, - tree, - visited, - roots, - Some(link), - ModuleSource::new_file(file_id.into()), - ), - }) - .collect::>>()?; - (points_to, problem) - } - Submodule::Definition(_name, submodule_source) => { - let points_to = build_subtree( - db, - source_root, - tree, - visited, - roots, - Some(link), - *submodule_source, - )?; - (vec![points_to], None) - } - }; - - tree.links[link].points_to = points_to; - tree.links[link].problem = problem; - } - Ok(id) -} - -fn resolve_submodule( - db: &impl HirDatabase, - source: ModuleSource, - name: &Name, -) -> (Vec, Option) { - // FIXME: handle submodules of inline modules properly - let file_id = source.file_id().original_file(db); - let source_root_id = db.file_source_root(file_id); - let path = db.file_relative_path(file_id); - let root = RelativePathBuf::default(); - let dir_path = path.parent().unwrap_or(&root); - let mod_name = path.file_stem().unwrap_or("unknown"); - let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main"; - - let file_mod = dir_path.join(format!("{}.rs", name)); - let dir_mod = dir_path.join(format!("{}/mod.rs", name)); - let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name)); - let mut candidates = ArrayVec::<[_; 2]>::new(); - if is_dir_owner { - candidates.push(file_mod.clone()); - candidates.push(dir_mod); - } else { - candidates.push(file_dir_mod.clone()); - }; - let sr = db.source_root(source_root_id); - let points_to = candidates - .into_iter() - .filter_map(|path| sr.files.get(&path)) - .map(|&it| it) - .collect::>(); - let problem = if points_to.is_empty() { - Some(Problem::UnresolvedModule { - candidate: if is_dir_owner { file_mod } else { file_dir_mod }, - }) - } else { - None - }; - (points_to, problem) -} diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs deleted file mode 100644 index 7d5e86c89..000000000 --- a/crates/ra_hir/src/module/nameres.rs +++ /dev/null @@ -1,509 +0,0 @@ -//! Name resolution algorithm. The end result of the algorithm is `ItemMap`: a -//! map with maps each module to it's scope: the set of items, visible in the -//! module. That is, we only resolve imports here, name resolution of item -//! bodies will be done in a separate step. -//! -//! Like Rustc, we use an interative per-crate algorithm: we start with scopes -//! containing only directly defined items, and then iteratively resolve -//! imports. -//! -//! To make this work nicely in the IDE scenarios, we place `InputModuleItems` -//! in between raw syntax and name resolution. `InputModuleItems` are computed -//! using only the module's syntax, and it is all directly defined items plus -//! imports. The plain is to make `InputModuleItems` independent of local -//! modifications (that is, typing inside a function shold not change IMIs), -//! such that the results of name resolution can be preserved unless the module -//! structure itself is modified. -use std::sync::Arc; - -use rustc_hash::FxHashMap; -use ra_syntax::{ - TextRange, - SyntaxKind::{self, *}, - ast::{self, AstNode} -}; -use ra_db::{SourceRootId, Cancelable, FileId}; - -use crate::{ - HirFileId, - DefId, DefLoc, DefKind, - SourceItemId, SourceFileItemId, SourceFileItems, - Path, PathKind, - HirDatabase, Crate, - Name, AsName, - module::{ModuleId, ModuleTree}, -}; - -/// Item map is the result of the name resolution. Item map contains, for each -/// module, the set of visible items. -// FIXME: currenty we compute item map per source-root. We should do it per crate instead. -#[derive(Default, Debug, PartialEq, Eq)] -pub struct ItemMap { - pub per_module: FxHashMap, -} - -#[derive(Debug, Default, PartialEq, Eq, Clone)] -pub struct ModuleScope { - items: FxHashMap, -} - -impl ModuleScope { - pub fn entries<'a>(&'a self) -> impl Iterator + 'a { - self.items.iter() - } - pub fn get(&self, name: &Name) -> Option<&Resolution> { - self.items.get(name) - } -} - -/// A set of items and imports declared inside a module, without relation to -/// other modules. -/// -/// This stands in-between raw syntax and name resolution and alow us to avoid -/// recomputing name res: if `InputModuleItems` are the same, we can avoid -/// running name resolution. -#[derive(Debug, Default, PartialEq, Eq)] -pub struct InputModuleItems { - pub(crate) items: Vec, - imports: Vec, -} - -#[derive(Debug, PartialEq, Eq)] -pub(crate) struct ModuleItem { - pub(crate) id: SourceItemId, - pub(crate) name: Name, - kind: SyntaxKind, - vis: Vis, -} - -#[derive(Debug, PartialEq, Eq)] -enum Vis { - // Priv, - Other, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct Import { - path: Path, - kind: ImportKind, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct NamedImport { - pub file_item_id: SourceFileItemId, - pub relative_range: TextRange, -} - -impl NamedImport { - // FIXME: this is only here for one use-case in completion. Seems like a - // pretty gross special case. - pub fn range(&self, db: &impl HirDatabase, file_id: FileId) -> TextRange { - let source_item_id = SourceItemId { - file_id: file_id.into(), - item_id: Some(self.file_item_id), - }; - let syntax = db.file_item(source_item_id); - let offset = syntax.borrowed().range().start(); - self.relative_range + offset - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -enum ImportKind { - Glob, - Named(NamedImport), -} - -/// Resolution is basically `DefId` atm, but it should account for stuff like -/// multiple namespaces, ambiguity and errors. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Resolution { - /// None for unresolved - pub def_id: PerNs, - /// ident by whitch this is imported into local scope. - pub import: Option, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Namespace { - Types, - Values, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct PerNs { - pub types: Option, - pub values: Option, -} - -impl PerNs { - pub fn none() -> PerNs { - PerNs { - types: None, - values: None, - } - } - - pub fn values(t: T) -> PerNs { - PerNs { - types: None, - values: Some(t), - } - } - - pub fn types(t: T) -> PerNs { - PerNs { - types: Some(t), - values: None, - } - } - - pub fn both(types: T, values: T) -> PerNs { - PerNs { - types: Some(types), - values: Some(values), - } - } - - pub fn is_none(&self) -> bool { - self.types.is_none() && self.values.is_none() - } - - pub fn take(self, namespace: Namespace) -> Option { - match namespace { - Namespace::Types => self.types, - Namespace::Values => self.values, - } - } - - pub fn take_types(self) -> Option { - self.take(Namespace::Types) - } - - pub fn take_values(self) -> Option { - self.take(Namespace::Values) - } - - pub fn get(&self, namespace: Namespace) -> Option<&T> { - self.as_ref().take(namespace) - } - - pub fn as_ref(&self) -> PerNs<&T> { - PerNs { - types: self.types.as_ref(), - values: self.values.as_ref(), - } - } - - pub fn and_then(self, f: impl Fn(T) -> Option) -> PerNs { - PerNs { - types: self.types.and_then(&f), - values: self.values.and_then(&f), - } - } - - pub fn map(self, f: impl Fn(T) -> U) -> PerNs { - PerNs { - types: self.types.map(&f), - values: self.values.map(&f), - } - } -} - -impl InputModuleItems { - pub(crate) fn add_item( - &mut self, - file_id: HirFileId, - file_items: &SourceFileItems, - item: ast::ModuleItem, - ) -> Option<()> { - match item { - ast::ModuleItem::StructDef(it) => { - self.items.push(ModuleItem::new(file_id, file_items, it)?) - } - ast::ModuleItem::EnumDef(it) => { - self.items.push(ModuleItem::new(file_id, file_items, it)?) - } - ast::ModuleItem::FnDef(it) => { - self.items.push(ModuleItem::new(file_id, file_items, it)?) - } - ast::ModuleItem::TraitDef(it) => { - self.items.push(ModuleItem::new(file_id, file_items, it)?) - } - ast::ModuleItem::TypeDef(it) => { - self.items.push(ModuleItem::new(file_id, file_items, it)?) - } - ast::ModuleItem::ImplBlock(_) => { - // impls don't define items - } - ast::ModuleItem::UseItem(it) => self.add_use_item(file_items, it), - ast::ModuleItem::ExternCrateItem(_) => { - // TODO - } - ast::ModuleItem::ConstDef(it) => { - self.items.push(ModuleItem::new(file_id, file_items, it)?) - } - ast::ModuleItem::StaticDef(it) => { - self.items.push(ModuleItem::new(file_id, file_items, it)?) - } - ast::ModuleItem::Module(it) => { - self.items.push(ModuleItem::new(file_id, file_items, it)?) - } - } - Some(()) - } - - fn add_use_item(&mut self, file_items: &SourceFileItems, item: ast::UseItem) { - let file_item_id = file_items.id_of_unchecked(item.syntax()); - let start_offset = item.syntax().range().start(); - Path::expand_use_item(item, |path, range| { - let kind = match range { - None => ImportKind::Glob, - Some(range) => ImportKind::Named(NamedImport { - file_item_id, - relative_range: range - start_offset, - }), - }; - self.imports.push(Import { kind, path }) - }) - } -} - -impl ModuleItem { - fn new<'a>( - file_id: HirFileId, - file_items: &SourceFileItems, - item: impl ast::NameOwner<'a>, - ) -> Option { - let name = item.name()?.as_name(); - let kind = item.syntax().kind(); - let vis = Vis::Other; - let item_id = Some(file_items.id_of_unchecked(item.syntax())); - let id = SourceItemId { file_id, item_id }; - let res = ModuleItem { - id, - name, - kind, - vis, - }; - Some(res) - } -} - -pub(crate) struct Resolver<'a, DB> { - db: &'a DB, - input: &'a FxHashMap>, - source_root: SourceRootId, - module_tree: Arc, - result: ItemMap, -} - -impl<'a, DB> Resolver<'a, DB> -where - DB: HirDatabase, -{ - pub(crate) fn new( - db: &'a DB, - input: &'a FxHashMap>, - source_root: SourceRootId, - module_tree: Arc, - ) -> Resolver<'a, DB> { - Resolver { - db, - input, - source_root, - module_tree, - result: ItemMap::default(), - } - } - - pub(crate) fn resolve(mut self) -> Cancelable { - for (&module_id, items) in self.input.iter() { - self.populate_module(module_id, Arc::clone(items))?; - } - - for &module_id in self.input.keys() { - self.db.check_canceled()?; - self.resolve_imports(module_id)?; - } - Ok(self.result) - } - - fn populate_module( - &mut self, - module_id: ModuleId, - input: Arc, - ) -> Cancelable<()> { - let mut module_items = ModuleScope::default(); - - // Populate extern crates prelude - { - let root_id = module_id.crate_root(&self.module_tree); - let file_id = root_id.source(&self.module_tree).file_id(); - let crate_graph = self.db.crate_graph(); - if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file()) - { - let krate = Crate::new(crate_id); - for dep in krate.dependencies(self.db)? { - if let Some(module) = dep.krate.root_module(self.db)? { - let def_id = module.def_id; - self.add_module_item( - &mut module_items, - dep.name.clone(), - PerNs::types(def_id), - ); - } - } - }; - } - for import in input.imports.iter() { - if let Some(name) = import.path.segments.iter().last() { - if let ImportKind::Named(import) = import.kind { - module_items.items.insert( - name.clone(), - Resolution { - def_id: PerNs::none(), - import: Some(import), - }, - ); - } - } - } - // Populate explicitly declared items, except modules - for item in input.items.iter() { - if item.kind == MODULE { - continue; - } - // depending on the item kind, the location can define something in - // the values namespace, the types namespace, or both - let kind = DefKind::for_syntax_kind(item.kind); - let def_id = kind.map(|k| { - let def_loc = DefLoc { - kind: k, - source_root_id: self.source_root, - module_id, - source_item_id: item.id, - }; - def_loc.id(self.db) - }); - let resolution = Resolution { - def_id, - import: None, - }; - module_items.items.insert(item.name.clone(), resolution); - } - - // Populate modules - for (name, module_id) in module_id.children(&self.module_tree) { - let def_loc = DefLoc { - kind: DefKind::Module, - source_root_id: self.source_root, - module_id, - source_item_id: module_id.source(&self.module_tree).0, - }; - let def_id = def_loc.id(self.db); - self.add_module_item(&mut module_items, name, PerNs::types(def_id)); - } - - self.result.per_module.insert(module_id, module_items); - Ok(()) - } - - fn add_module_item(&self, module_items: &mut ModuleScope, name: Name, def_id: PerNs) { - let resolution = Resolution { - def_id, - import: None, - }; - module_items.items.insert(name, resolution); - } - - fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> { - for import in self.input[&module_id].imports.iter() { - self.resolve_import(module_id, import)?; - } - Ok(()) - } - - fn resolve_import(&mut self, module_id: ModuleId, import: &Import) -> Cancelable<()> { - let ptr = match import.kind { - ImportKind::Glob => return Ok(()), - ImportKind::Named(ptr) => ptr, - }; - - let mut curr: ModuleId = match import.path.kind { - PathKind::Plain | PathKind::Self_ => module_id, - PathKind::Super => { - match module_id.parent(&self.module_tree) { - Some(it) => it, - // TODO: error - None => return Ok(()), - } - } - PathKind::Crate => module_id.crate_root(&self.module_tree), - }; - - for (i, name) in import.path.segments.iter().enumerate() { - let is_last = i == import.path.segments.len() - 1; - - let def_id = match self.result.per_module[&curr].items.get(name) { - Some(res) if !res.def_id.is_none() => res.def_id, - _ => return Ok(()), - }; - - if !is_last { - let type_def_id = if let Some(d) = def_id.take(Namespace::Types) { - d - } else { - return Ok(()); - }; - curr = match type_def_id.loc(self.db) { - DefLoc { - kind: DefKind::Module, - module_id: target_module_id, - source_root_id, - .. - } => { - if source_root_id == self.source_root { - target_module_id - } else { - let module = crate::code_model_api::Module::new(type_def_id); - let path = Path { - segments: import.path.segments[i + 1..].iter().cloned().collect(), - kind: PathKind::Crate, - }; - let def_id = module.resolve_path(self.db, &path)?; - if !def_id.is_none() { - self.update(module_id, |items| { - let res = Resolution { - def_id: def_id, - import: Some(ptr), - }; - items.items.insert(name.clone(), res); - }) - } - return Ok(()); - } - } - _ => return Ok(()), - } - } else { - self.update(module_id, |items| { - let res = Resolution { - def_id: def_id, - import: Some(ptr), - }; - items.items.insert(name.clone(), res); - }) - } - } - Ok(()) - } - - fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) { - let module_items = self.result.per_module.get_mut(&module_id).unwrap(); - f(module_items) - } -} - -#[cfg(test)] -mod tests; diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs deleted file mode 100644 index dcbe65aec..000000000 --- a/crates/ra_hir/src/module/nameres/tests.rs +++ /dev/null @@ -1,273 +0,0 @@ -use std::sync::Arc; - -use salsa::Database; -use ra_db::{FilesDatabase, CrateGraph}; -use relative_path::RelativePath; -use test_utils::assert_eq_text; - -use crate::{ - self as hir, - db::HirDatabase, - mock::MockDatabase, -}; - -fn item_map(fixture: &str) -> (Arc, hir::ModuleId) { - let (db, pos) = MockDatabase::with_position(fixture); - let source_root = db.file_source_root(pos.file_id); - let module = hir::source_binder::module_from_position(&db, pos) - .unwrap() - .unwrap(); - let module_id = module.def_id.loc(&db).module_id; - (db.item_map(source_root).unwrap(), module_id) -} - -fn check_module_item_map(map: &hir::ItemMap, module_id: hir::ModuleId, expected: &str) { - let mut lines = map.per_module[&module_id] - .items - .iter() - .map(|(name, res)| format!("{}: {}", name, dump_resolution(res))) - .collect::>(); - lines.sort(); - let actual = lines.join("\n"); - let expected = expected - .trim() - .lines() - .map(|it| it.trim()) - .collect::>() - .join("\n"); - assert_eq_text!(&actual, &expected); - - fn dump_resolution(resolution: &hir::Resolution) -> &'static str { - match ( - resolution.def_id.types.is_some(), - resolution.def_id.values.is_some(), - ) { - (true, true) => "t v", - (true, false) => "t", - (false, true) => "v", - (false, false) => "_", - } - } -} - -#[test] -fn item_map_smoke_test() { - let (item_map, module_id) = item_map( - " - //- /lib.rs - mod foo; - - use crate::foo::bar::Baz; - <|> - - //- /foo/mod.rs - pub mod bar; - - //- /foo/bar.rs - pub struct Baz; - ", - ); - check_module_item_map( - &item_map, - module_id, - " - Baz: t v - foo: t - ", - ); -} - -#[test] -fn item_map_contains_items_from_expansions() { - let (item_map, module_id) = item_map( - " - //- /lib.rs - mod foo; - - use crate::foo::bar::Baz; - <|> - - //- /foo/mod.rs - pub mod bar; - - //- /foo/bar.rs - salsa::query_group! { - trait Baz {} - } - ", - ); - check_module_item_map( - &item_map, - module_id, - " - Baz: t - foo: t - ", - ); -} - -#[test] -fn item_map_using_self() { - let (item_map, module_id) = item_map( - " - //- /lib.rs - mod foo; - use crate::foo::bar::Baz::{self}; - <|> - //- /foo/mod.rs - pub mod bar; - //- /foo/bar.rs - pub struct Baz; - ", - ); - check_module_item_map( - &item_map, - module_id, - " - Baz: t v - foo: t - ", - ); -} - -#[test] -fn item_map_across_crates() { - let (mut db, sr) = MockDatabase::with_files( - " - //- /main.rs - use test_crate::Baz; - - //- /lib.rs - pub struct Baz; - ", - ); - let main_id = sr.files[RelativePath::new("/main.rs")]; - let lib_id = sr.files[RelativePath::new("/lib.rs")]; - - let mut crate_graph = CrateGraph::default(); - let main_crate = crate_graph.add_crate_root(main_id); - let lib_crate = crate_graph.add_crate_root(lib_id); - crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate); - - db.set_crate_graph(crate_graph); - - let source_root = db.file_source_root(main_id); - let module = hir::source_binder::module_from_file_id(&db, main_id) - .unwrap() - .unwrap(); - let module_id = module.def_id.loc(&db).module_id; - let item_map = db.item_map(source_root).unwrap(); - - check_module_item_map( - &item_map, - module_id, - " - Baz: t v - test_crate: t - ", - ); -} - -#[test] -fn typing_inside_a_function_should_not_invalidate_item_map() { - let (mut db, pos) = MockDatabase::with_position( - " - //- /lib.rs - mod foo; - - use crate::foo::bar::Baz; - - //- /foo/mod.rs - pub mod bar; - - //- /foo/bar.rs - <|> - salsa::query_group! { - trait Baz { - fn foo() -> i32 { 1 + 1 } - } - } - ", - ); - let source_root = db.file_source_root(pos.file_id); - { - let events = db.log_executed(|| { - db.item_map(source_root).unwrap(); - }); - assert!(format!("{:?}", events).contains("item_map")) - } - - let new_text = " - salsa::query_group! { - trait Baz { - fn foo() -> i32 { 92 } - } - } - " - .to_string(); - - db.query_mut(ra_db::FileTextQuery) - .set(pos.file_id, Arc::new(new_text)); - - { - let events = db.log_executed(|| { - db.item_map(source_root).unwrap(); - }); - assert!( - !format!("{:?}", events).contains("item_map"), - "{:#?}", - events - ) - } -} - -#[test] -fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() { - let (mut db, pos) = MockDatabase::with_position( - " - //- /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; - ", - ); - let source_root = db.file_source_root(pos.file_id); - { - let events = db.log_executed(|| { - db.item_map(source_root).unwrap(); - }); - assert!(format!("{:?}", events).contains("item_map")) - } - - let new_text = " - mod foo; - - use crate::foo::bar::Baz; - - fn foo() -> i32 { 92 } - " - .to_string(); - - db.query_mut(ra_db::FileTextQuery) - .set(pos.file_id, Arc::new(new_text)); - - { - let events = db.log_executed(|| { - db.item_map(source_root).unwrap(); - }); - assert!( - !format!("{:?}", events).contains("item_map"), - "{:#?}", - events - ) - } -} -- cgit v1.2.3