From 32c067f8c9aec56bb502c5a569884679bae27af3 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 8 Dec 2018 21:54:00 +0300 Subject: track deps in project model --- crates/ra_lsp_server/src/project_model.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs index 3305d468a..22495f49c 100644 --- a/crates/ra_lsp_server/src/project_model.rs +++ b/crates/ra_lsp_server/src/project_model.rs @@ -28,6 +28,7 @@ struct PackageData { manifest: PathBuf, targets: Vec, is_member: bool, + dependencies: Vec, } #[derive(Debug, Clone)] @@ -106,6 +107,7 @@ impl CargoWorkspace { manifest: PathBuf::from(meta_pkg.manifest_path), targets: Vec::new(), is_member, + dependencies: Vec::new(), }; for meta_tgt in meta_pkg.targets { let tgt = Target(targets.len()); @@ -119,6 +121,14 @@ impl CargoWorkspace { } packages.push(pkg_data) } + let resolve = meta.resolve.expect("metadata executed with deps"); + for node in resolve.nodes { + let source = pkg_by_id[&node.id]; + for id in node.dependencies { + let target = pkg_by_id[&id]; + packages[source.0].dependencies.push(target); + } + } Ok(CargoWorkspace { packages, targets }) } -- cgit v1.2.3 From 9b1356464a834e0b9a88dd3eeabc50bf1d734f35 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 8 Dec 2018 23:16:11 +0300 Subject: propagate deps to CrateGraph --- crates/ra_db/src/input.rs | 3 +++ crates/ra_lsp_server/src/project_model.rs | 15 +++++++++--- crates/ra_lsp_server/src/server_world.rs | 39 ++++++++++++++++++++++--------- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index 7d9faa43c..a48d05b98 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -48,6 +48,9 @@ impl CrateGraph { assert!(prev.is_none()); crate_id } + //FIXME: check that we don't have cycles here. + // Just a simple depth first search from `to` should work, + // the graph is small. pub fn add_dep(&mut self, from: CrateId, to: CrateId) { self.arena.get_mut(&from).unwrap().add_dep(to) } diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs index 22495f49c..5da71b9f5 100644 --- a/crates/ra_lsp_server/src/project_model.rs +++ b/crates/ra_lsp_server/src/project_model.rs @@ -1,6 +1,5 @@ use std::path::{Path, PathBuf}; -use serde_derive::Serialize; use cargo_metadata::{metadata_run, CargoOpt}; use ra_syntax::SmolStr; use rustc_hash::{FxHashMap, FxHashSet}; @@ -11,15 +10,22 @@ use crate::{ thread_watcher::{ThreadWatcher, Worker}, }; +/// `CargoWorksapce` represents the logical structure of, well, a Cargo +/// workspace. It pretty closely mirrors `cargo metadata` output. +/// +/// Note that internally, rust analyzer uses a differnet structure: +/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, +/// while this knows about `Pacakges` & `Targets`: purely cargo-related +/// concepts. #[derive(Debug, Clone)] pub struct CargoWorkspace { packages: Vec, targets: Vec, } -#[derive(Clone, Copy, Debug, Serialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Package(usize); -#[derive(Clone, Copy, Debug, Serialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Target(usize); #[derive(Debug, Clone)] @@ -62,6 +68,9 @@ impl Package { pub fn is_member(self, ws: &CargoWorkspace) -> bool { ws.pkg(self).is_member } + pub fn dependencies<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator + 'a { + ws.pkg(self).dependencies.iter().cloned() + } } impl Target { diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index c3f89ad5f..f2d602dc7 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -13,7 +13,7 @@ use failure::{bail, format_err}; use crate::{ path_map::{PathMap, Root}, - project_model::CargoWorkspace, + project_model::{CargoWorkspace, TargetKind}, vfs::{FileEvent, FileEventKind}, Result, }; @@ -142,17 +142,34 @@ impl ServerWorldState { } pub fn set_workspaces(&mut self, ws: Vec) { let mut crate_graph = CrateGraph::default(); - ws.iter() - .flat_map(|ws| { - ws.packages() - .flat_map(move |pkg| pkg.targets(ws)) - .map(move |tgt| tgt.root(ws)) - }) - .for_each(|root| { - if let Some(file_id) = self.path_map.get_id(root) { - crate_graph.add_crate_root(file_id); + let mut pkg_to_lib_crate = FxHashMap::default(); + let mut pkg_crates = FxHashMap::default(); + for ws in ws.iter() { + for pkg in ws.packages() { + for tgt in pkg.targets(ws) { + let root = tgt.root(ws); + if let Some(file_id) = self.path_map.get_id(root) { + let crate_id = crate_graph.add_crate_root(file_id); + if tgt.kind(ws) == TargetKind::Lib { + pkg_to_lib_crate.insert(pkg, crate_id); + } + pkg_crates + .entry(pkg) + .or_insert_with(Vec::new) + .push(crate_id); + } + } + } + for pkg in ws.packages() { + for dep in pkg.dependencies(ws) { + if let Some(&to) = pkg_to_lib_crate.get(&dep) { + for &from in pkg_crates.get(&pkg).into_iter().flatten() { + crate_graph.add_dep(from, to); + } + } } - }); + } + } self.workspaces = Arc::new(ws); let mut change = AnalysisChange::new(); change.set_crate_graph(crate_graph); -- cgit v1.2.3 From 9c6c7ec2daacdbcaae8fe697b30d4c99aae69090 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 8 Dec 2018 23:40:55 +0300 Subject: hir::Crate boilerplate --- crates/ra_hir/src/krate.rs | 15 +++++++++++++++ crates/ra_hir/src/lib.rs | 8 ++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 crates/ra_hir/src/krate.rs diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs new file mode 100644 index 000000000..367ddbd21 --- /dev/null +++ b/crates/ra_hir/src/krate.rs @@ -0,0 +1,15 @@ +use crate::FileId; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct CrateId(u32); + +#[derive(Debug)] +pub struct Crate { + root: FileId, +} + +impl Crate { + pub fn dependencies(&self) -> Vec { + Vec::new() + } +} diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index f50b922af..0fa2ec50f 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -18,12 +18,15 @@ pub mod db; #[cfg(test)] mod mock; mod query_definitions; -mod function; -mod module; mod path; mod arena; pub mod source_binder; +mod krate; +mod module; +mod function; + + use std::ops::Index; use ra_syntax::{SyntaxNodeRef, SyntaxNode}; @@ -36,6 +39,7 @@ use crate::{ pub use self::{ path::{Path, PathKind}, + krate::Crate, module::{Module, ModuleId, Problem, nameres::ItemMap}, function::{Function, FnScopes}, }; -- cgit v1.2.3 From ca7e5905c1daffbed6a08fe674ae821f99bd274d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 9 Dec 2018 00:51:06 +0300 Subject: more crate boilerplate --- Cargo.toml | 1 - crates/ra_db/src/input.rs | 20 ++++++++++++++++---- crates/ra_hir/src/krate.rs | 34 ++++++++++++++++++++++++++++------ crates/ra_hir/src/lib.rs | 1 - crates/ra_hir/src/module.rs | 11 ++++++++++- 5 files changed, 54 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8e4e84729..5cfc064b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,5 @@ [workspace] members = [ "crates/*" ] -exclude = [ "crates/rowan"] [profile.release] debug = true diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index a48d05b98..37da8c549 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -20,25 +20,31 @@ pub struct CrateGraph { #[derive(Debug, Clone, PartialEq, Eq)] struct CrateData { file_id: FileId, - deps: Vec, + dependencies: Vec, } impl CrateData { fn new(file_id: FileId) -> CrateData { CrateData { file_id, - deps: Vec::new(), + dependencies: Vec::new(), } } fn add_dep(&mut self, dep: CrateId) { - self.deps.push(Dependency { crate_: dep }) + self.dependencies.push(Dependency { crate_id: dep }) } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct Dependency { - crate_: CrateId, + crate_id: CrateId, +} + +impl Dependency { + pub fn crate_id(&self) -> CrateId { + self.crate_id + } } impl CrateGraph { @@ -64,6 +70,12 @@ impl CrateGraph { .find(|(_crate_id, data)| data.file_id == file_id)?; Some(crate_id) } + pub fn dependencies<'a>( + &'a self, + crate_id: CrateId, + ) -> impl Iterator + 'a { + self.arena[&crate_id].dependencies.iter() + } } salsa::query_group! { diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs index 367ddbd21..61007cc29 100644 --- a/crates/ra_hir/src/krate.rs +++ b/crates/ra_hir/src/krate.rs @@ -1,15 +1,37 @@ -use crate::FileId; +use crate::{HirDatabase, Module, Cancelable}; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct CrateId(u32); +pub use ra_db::CrateId; +/// hir::Crate describes a single crate. It's the main inteface with which +/// crate's dependencies interact. Mostly, it should be just a proxy for the +/// root module. #[derive(Debug)] pub struct Crate { - root: FileId, + crate_id: CrateId, } impl Crate { - pub fn dependencies(&self) -> Vec { - Vec::new() + pub(crate) fn new(crate_id: CrateId) -> Crate { + Crate { crate_id } + } + pub fn dependencies(&self, db: &impl HirDatabase) -> Vec { + let crate_graph = db.crate_graph(); + crate_graph + .dependencies(self.crate_id) + .map(|dep| Crate::new(dep.crate_id())) + .collect() + } + pub fn root_module(&self, db: &impl HirDatabase) -> Cancelable> { + let crate_graph = db.crate_graph(); + let file_id = crate_graph.crate_root(self.crate_id); + let source_root_id = db.file_source_root(file_id); + let module_tree = db.module_tree(source_root_id)?; + // FIXME: teach module tree about crate roots instead of guessing + let (module_id, _) = ctry!(module_tree + .modules_with_sources() + .find(|(_, src)| src.file_id() == file_id)); + + let module = Module::new(db, source_root_id, module_id)?; + Ok(Some(module)) } } diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 0fa2ec50f..578fde259 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -26,7 +26,6 @@ mod krate; mod module; mod function; - use std::ops::Index; use ra_syntax::{SyntaxNodeRef, SyntaxNode}; diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs index e7a49f83a..c6bb76d56 100644 --- a/crates/ra_hir/src/module.rs +++ b/crates/ra_hir/src/module.rs @@ -12,7 +12,7 @@ use ra_db::{SourceRootId, FileId, Cancelable}; use relative_path::RelativePathBuf; use crate::{ - DefKind, DefLoc, DefId, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId, + DefKind, DefLoc, DefId, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId, Crate, arena::{Arena, Id}, }; @@ -64,6 +64,15 @@ impl Module { }) } + /// Returns the crate this module is part of. + pub fn krate(&self, db: &impl HirDatabase) -> Option { + let root_id = self.module_id.crate_root(&self.tree); + let file_id = root_id.source(&self.tree).file_id(); + let crate_graph = db.crate_graph(); + let crate_id = crate_graph.crate_id_for_crate_root(file_id)?; + Some(Crate::new(crate_id)) + } + /// The root of the tree this module is part of pub fn crate_root(&self) -> Module { let root_id = self.module_id.crate_root(&self.tree); -- cgit v1.2.3 From 961cae7e53a05625f3e010076673ca083479b481 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 9 Dec 2018 01:02:53 +0300 Subject: thread info about dep names --- crates/ra_db/src/input.rs | 13 +++++++------ crates/ra_lsp_server/src/project_model.rs | 19 +++++++++++++++---- crates/ra_lsp_server/src/server_world.rs | 4 ++-- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index 37da8c549..44c5bac93 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -1,7 +1,7 @@ use std::sync::Arc; -use rustc_hash::FxHashMap; -use rustc_hash::FxHashSet; +use rustc_hash::{FxHashSet, FxHashMap}; +use ra_syntax::SmolStr; use salsa; use crate::file_resolver::FileResolverImp; @@ -31,14 +31,15 @@ impl CrateData { } } - fn add_dep(&mut self, dep: CrateId) { - self.dependencies.push(Dependency { crate_id: dep }) + fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) { + self.dependencies.push(Dependency { name, crate_id }) } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct Dependency { crate_id: CrateId, + name: SmolStr, } impl Dependency { @@ -57,8 +58,8 @@ impl CrateGraph { //FIXME: check that we don't have cycles here. // Just a simple depth first search from `to` should work, // the graph is small. - pub fn add_dep(&mut self, from: CrateId, to: CrateId) { - self.arena.get_mut(&from).unwrap().add_dep(to) + pub fn add_dep(&mut self, from: CrateId, name: SmolStr, to: CrateId) { + self.arena.get_mut(&from).unwrap().add_dep(name, to) } pub fn crate_root(&self, crate_id: CrateId) -> FileId { self.arena[&crate_id].file_id diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs index 5da71b9f5..cb91ada90 100644 --- a/crates/ra_lsp_server/src/project_model.rs +++ b/crates/ra_lsp_server/src/project_model.rs @@ -34,7 +34,13 @@ struct PackageData { manifest: PathBuf, targets: Vec, is_member: bool, - dependencies: Vec, + dependencies: Vec, +} + +#[derive(Debug, Clone)] +pub struct PackageDependency { + pub pkg: Package, + pub name: SmolStr, } #[derive(Debug, Clone)] @@ -68,8 +74,11 @@ impl Package { pub fn is_member(self, ws: &CargoWorkspace) -> bool { ws.pkg(self).is_member } - pub fn dependencies<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator + 'a { - ws.pkg(self).dependencies.iter().cloned() + pub fn dependencies<'a>( + self, + ws: &'a CargoWorkspace, + ) -> impl Iterator + 'a { + ws.pkg(self).dependencies.iter() } } @@ -135,7 +144,9 @@ impl CargoWorkspace { let source = pkg_by_id[&node.id]; for id in node.dependencies { let target = pkg_by_id[&id]; - packages[source.0].dependencies.push(target); + let name: SmolStr = packages[target.0].name.replace('-', "_").into(); + let dep = PackageDependency { name, pkg: target }; + packages[source.0].dependencies.push(dep); } } diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index f2d602dc7..ab4c2c8aa 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -162,9 +162,9 @@ impl ServerWorldState { } for pkg in ws.packages() { for dep in pkg.dependencies(ws) { - if let Some(&to) = pkg_to_lib_crate.get(&dep) { + if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { for &from in pkg_crates.get(&pkg).into_iter().flatten() { - crate_graph.add_dep(from, to); + crate_graph.add_dep(from, dep.name.clone(), to); } } } -- cgit v1.2.3 From 74fe581061be5175835efda69ee1fa3817716a59 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 9 Dec 2018 01:05:49 +0300 Subject: return dependencies with names --- crates/ra_db/src/input.rs | 4 ++-- crates/ra_hir/src/krate.rs | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index 44c5bac93..ac144b991 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -38,8 +38,8 @@ impl CrateData { #[derive(Debug, Clone, PartialEq, Eq)] pub struct Dependency { - crate_id: CrateId, - name: SmolStr, + pub crate_id: CrateId, + pub name: SmolStr, } impl Dependency { diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs index 61007cc29..1196dcef1 100644 --- a/crates/ra_hir/src/krate.rs +++ b/crates/ra_hir/src/krate.rs @@ -1,7 +1,8 @@ -use crate::{HirDatabase, Module, Cancelable}; - +use ra_syntax::SmolStr; pub use ra_db::CrateId; +use crate::{HirDatabase, Module, Cancelable}; + /// hir::Crate describes a single crate. It's the main inteface with which /// crate's dependencies interact. Mostly, it should be just a proxy for the /// root module. @@ -10,15 +11,25 @@ pub struct Crate { crate_id: CrateId, } +#[derive(Debug)] +pub struct CrateDependency { + pub krate: Crate, + pub name: SmolStr, +} + impl Crate { pub(crate) fn new(crate_id: CrateId) -> Crate { Crate { crate_id } } - pub fn dependencies(&self, db: &impl HirDatabase) -> Vec { + pub fn dependencies(&self, db: &impl HirDatabase) -> Vec { let crate_graph = db.crate_graph(); crate_graph .dependencies(self.crate_id) - .map(|dep| Crate::new(dep.crate_id())) + .map(|dep| { + let krate = Crate::new(dep.crate_id()); + let name = dep.name.clone(); + CrateDependency { krate, name } + }) .collect() } pub fn root_module(&self, db: &impl HirDatabase) -> Cancelable> { -- cgit v1.2.3 From 8b9ff46b378e37b256f6b93f1f6f3bb5bc122064 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 9 Dec 2018 12:24:52 +0300 Subject: make resolver fields private --- crates/ra_hir/src/module/nameres.rs | 25 ++++++++++++++++++++----- crates/ra_hir/src/query_definitions.rs | 9 ++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index 6511359d0..c75c1bbea 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs @@ -200,17 +200,32 @@ impl ModuleItem { } pub(crate) struct Resolver<'a, DB> { - pub(crate) db: &'a DB, - pub(crate) input: &'a FxHashMap>, - pub(crate) source_root: SourceRootId, - pub(crate) module_tree: Arc, - pub(crate) result: ItemMap, + 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: db, + input: &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, items) diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs index bb4457d07..37c4f9e4f 100644 --- a/crates/ra_hir/src/query_definitions.rs +++ b/crates/ra_hir/src/query_definitions.rs @@ -141,13 +141,8 @@ pub(super) fn item_map( Ok((id, items)) }) .collect::>>()?; - let resolver = Resolver { - db: db, - input: &input, - source_root, - module_tree, - result: ItemMap::default(), - }; + + let resolver = Resolver::new(db, &input, source_root, module_tree); let res = resolver.resolve()?; let elapsed = start.elapsed(); log::info!("item_map: {:?}", elapsed); -- cgit v1.2.3 From 6a16d3fb0b2165e19098f3298916f78a14535388 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 9 Dec 2018 12:45:47 +0300 Subject: WIP: resolve across crates --- crates/ra_hir/src/module/nameres.rs | 55 +++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index c75c1bbea..768836b65 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs @@ -31,7 +31,7 @@ use crate::{ DefId, DefLoc, DefKind, SourceItemId, SourceFileItemId, SourceFileItems, Path, PathKind, - HirDatabase, + HirDatabase, Crate, module::{ModuleId, ModuleTree}, }; @@ -218,8 +218,8 @@ where module_tree: Arc, ) -> Resolver<'a, DB> { Resolver { - db: db, - input: &input, + db, + input, source_root, module_tree, result: ItemMap::default(), @@ -233,7 +233,7 @@ where for &module_id in self.input.keys() { self.db.check_canceled()?; - self.resolve_imports(module_id); + self.resolve_imports(module_id)?; } Ok(self.result) } @@ -297,40 +297,66 @@ where self.result.per_module.insert(module_id, module_items); } - fn resolve_imports(&mut self, module_id: ModuleId) { + fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> { for import in self.input[&module_id].imports.iter() { - self.resolve_import(module_id, import); + self.resolve_import(module_id, import)?; } + Ok(()) } - fn resolve_import(&mut self, module_id: ModuleId, import: &Import) { + fn resolve_import(&mut self, module_id: ModuleId, import: &Import) -> Cancelable<()> { let ptr = match import.kind { - ImportKind::Glob => return, + ImportKind::Glob => return Ok(()), ImportKind::Named(ptr) => ptr, }; + let mut segments = import.path.segments.iter().enumerate(); let mut curr = match import.path.kind { // TODO: handle extern crates - PathKind::Plain => return, + PathKind::Plain => { + 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(); + let crate_id = match crate_graph.crate_id_for_crate_root(file_id) { + None => return Ok(()), + Some(it) => it, + }; + let krate = Crate::new(crate_id); + let crate_name = match segments.next() { + None => return Ok(()), + Some((_, it)) => it, + }; + match krate + .dependencies(self.db) + .into_iter() + .find(|it| &it.name == crate_name) + { + None => return Ok(()), + Some(dep) => match dep.krate.root_module(self.db)? { + None => return Ok(()), + Some(it) => it.module_id, + }, + } + } PathKind::Self_ => module_id, PathKind::Super => { match module_id.parent(&self.module_tree) { Some(it) => it, // TODO: error - None => return, + None => return Ok(()), } } PathKind::Crate => module_id.crate_root(&self.module_tree), }; - for (i, name) in import.path.segments.iter().enumerate() { + for (i, name) in segments { let is_last = i == import.path.segments.len() - 1; let def_id = match self.result.per_module[&curr].items.get(name) { - None => return, + None => return Ok(()), Some(res) => match res.def_id { Some(it) => it, - None => return, + None => return Ok(()), }, }; @@ -341,7 +367,7 @@ where module_id, .. } => module_id, - _ => return, + _ => return Ok(()), } } else { self.update(module_id, |items| { @@ -353,6 +379,7 @@ where }) } } + Ok(()) } fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) { -- cgit v1.2.3 From e89da32bb7cf7388946964e1e34df722527d0838 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 9 Dec 2018 12:48:55 +0300 Subject: move tests to separate file --- crates/ra_hir/src/module/nameres.rs | 98 +------------------------------ crates/ra_hir/src/module/nameres/tests.rs | 94 +++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 97 deletions(-) create mode 100644 crates/ra_hir/src/module/nameres/tests.rs diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index 768836b65..5e4bb7669 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs @@ -312,7 +312,6 @@ where let mut segments = import.path.segments.iter().enumerate(); let mut curr = match import.path.kind { - // TODO: handle extern crates PathKind::Plain => { let root_id = module_id.crate_root(&self.module_tree); let file_id = root_id.source(&self.module_tree).file_id(); @@ -389,99 +388,4 @@ where } #[cfg(test)] -mod tests { - use std::sync::Arc; - - use salsa::Database; - use ra_db::FilesDatabase; - use ra_syntax::SmolStr; - - 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.module_id; - (db.item_map(source_root).unwrap(), module_id) - } - - #[test] - fn test_item_map() { - 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; - ", - ); - let name = SmolStr::from("Baz"); - let resolution = &item_map.per_module[&module_id].items[&name]; - assert!(resolution.def_id.is_some()); - } - - #[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; - - 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 - ) - } - } -} +mod tests; diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs new file mode 100644 index 000000000..060683e27 --- /dev/null +++ b/crates/ra_hir/src/module/nameres/tests.rs @@ -0,0 +1,94 @@ +use std::sync::Arc; + +use salsa::Database; +use ra_db::FilesDatabase; +use ra_syntax::SmolStr; + +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.module_id; + (db.item_map(source_root).unwrap(), module_id) +} + +#[test] +fn test_item_map() { + 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; + ", + ); + let name = SmolStr::from("Baz"); + let resolution = &item_map.per_module[&module_id].items[&name]; + assert!(resolution.def_id.is_some()); +} + +#[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; + + 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 From 7784c7a701ba944decf671f80dea581d68667663 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 9 Dec 2018 13:49:54 +0300 Subject: resolve extern crates propertly --- crates/ra_db/src/mock.rs | 7 ++- crates/ra_hir/src/mock.rs | 24 +++++++-- crates/ra_hir/src/module/nameres.rs | 81 ++++++++++++++----------------- crates/ra_hir/src/module/nameres/tests.rs | 37 +++++++++++++- 4 files changed, 98 insertions(+), 51 deletions(-) diff --git a/crates/ra_db/src/mock.rs b/crates/ra_db/src/mock.rs index 2840f9655..2f7551597 100644 --- a/crates/ra_db/src/mock.rs +++ b/crates/ra_db/src/mock.rs @@ -5,7 +5,7 @@ use relative_path::{RelativePath, RelativePathBuf}; use crate::{FileId, FileResolver, SourceRoot, FileResolverImp}; -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct FileMap(Vec<(FileId, RelativePathBuf)>); impl FileMap { @@ -28,6 +28,11 @@ impl FileMap { self.iter().map(|(id, _)| id).collect() } + pub fn file_id(&self, path: &str) -> FileId { + assert!(path.starts_with('/')); + self.iter().find(|(_, p)| p == &path[1..]).unwrap().0 + } + fn iter<'a>(&'a self) -> impl Iterator + 'a { self.0 .iter() diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index e855df11d..b7193c4f3 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use parking_lot::Mutex; use salsa::{self, Database}; -use ra_db::{LocationIntener, BaseDatabase, FilePosition, mock::FileMap, FileId, WORKSPACE}; +use ra_db::{LocationIntener, BaseDatabase, FilePosition, mock::FileMap, FileId, WORKSPACE, CrateGraph}; use relative_path::RelativePathBuf; use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; @@ -16,7 +16,24 @@ pub(crate) struct MockDatabase { } impl MockDatabase { + pub(crate) fn with_files(fixture: &str) -> (MockDatabase, FileMap) { + let (db, file_map, position) = MockDatabase::from_fixture(fixture); + assert!(position.is_none()); + (db, file_map) + } + pub(crate) fn with_position(fixture: &str) -> (MockDatabase, FilePosition) { + let (db, _, position) = MockDatabase::from_fixture(fixture); + let position = position.expect("expected a marker ( <|> )"); + (db, position) + } + + pub(crate) fn set_crate_graph(&mut self, crate_graph: CrateGraph) { + self.query_mut(ra_db::CrateGraphQuery) + .set((), Arc::new(crate_graph)); + } + + fn from_fixture(fixture: &str) -> (MockDatabase, FileMap, Option) { let mut db = MockDatabase::default(); let mut position = None; @@ -32,11 +49,10 @@ impl MockDatabase { db.add_file(&mut file_map, &entry.meta, &entry.text); } } - let position = position.expect("expected a marker (<|>)"); - let source_root = file_map.into_source_root(); + let source_root = file_map.clone().into_source_root(); db.query_mut(ra_db::SourceRootQuery) .set(WORKSPACE, Arc::new(source_root)); - (db, position) + (db, file_map, position) } fn add_file(&mut self, file_map: &mut FileMap, path: &str, text: &str) -> FileId { diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index 5e4bb7669..9afeade9e 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs @@ -228,7 +228,7 @@ where pub(crate) fn resolve(mut self) -> Cancelable { for (&module_id, items) in self.input.iter() { - self.populate_module(module_id, items) + self.populate_module(module_id, items)?; } for &module_id in self.input.keys() { @@ -238,11 +238,25 @@ where Ok(self.result) } - fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) { + fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) -> Cancelable<()> { let file_id = module_id.source(&self.module_tree).file_id(); 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) { + let krate = Crate::new(crate_id); + for dep in krate.dependencies(self.db) { + if let Some(module) = dep.krate.root_module(self.db)? { + self.add_module_item(&mut module_items, dep.name, module.module_id); + } + } + }; + } for import in input.imports.iter() { if let Some(name) = import.path.segments.iter().last() { if let ImportKind::Named(import) = import.kind { @@ -256,10 +270,9 @@ where } } } - + // Populate explicitelly declared items, except modules for item in input.items.iter() { if item.kind == MODULE { - // handle submodules separatelly continue; } let def_loc = DefLoc { @@ -279,22 +292,28 @@ where 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); - let resolution = Resolution { - def_id: Some(def_id), - import: None, - }; - module_items.items.insert(name, resolution); + self.add_module_item(&mut module_items, name, module_id); } self.result.per_module.insert(module_id, module_items); + Ok(()) + } + + fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, module_id: ModuleId) { + 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); + let resolution = Resolution { + def_id: Some(def_id), + import: None, + }; + module_items.items.insert(name, resolution); } fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> { @@ -309,35 +328,9 @@ where ImportKind::Glob => return Ok(()), ImportKind::Named(ptr) => ptr, }; - let mut segments = import.path.segments.iter().enumerate(); let mut curr = match import.path.kind { - PathKind::Plain => { - 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(); - let crate_id = match crate_graph.crate_id_for_crate_root(file_id) { - None => return Ok(()), - Some(it) => it, - }; - let krate = Crate::new(crate_id); - let crate_name = match segments.next() { - None => return Ok(()), - Some((_, it)) => it, - }; - match krate - .dependencies(self.db) - .into_iter() - .find(|it| &it.name == crate_name) - { - None => return Ok(()), - Some(dep) => match dep.krate.root_module(self.db)? { - None => return Ok(()), - Some(it) => it.module_id, - }, - } - } - PathKind::Self_ => module_id, + PathKind::Plain | PathKind::Self_ => module_id, PathKind::Super => { match module_id.parent(&self.module_tree) { Some(it) => it, @@ -348,7 +341,7 @@ where PathKind::Crate => module_id.crate_root(&self.module_tree), }; - for (i, name) in segments { + 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) { diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs index 060683e27..9ddc32dcd 100644 --- a/crates/ra_hir/src/module/nameres/tests.rs +++ b/crates/ra_hir/src/module/nameres/tests.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use salsa::Database; -use ra_db::FilesDatabase; +use ra_db::{FilesDatabase, CrateGraph}; use ra_syntax::SmolStr; use crate::{ @@ -21,7 +21,7 @@ fn item_map(fixture: &str) -> (Arc, hir::ModuleId) { } #[test] -fn test_item_map() { +fn item_map_smoke_test() { let (item_map, module_id) = item_map( " //- /lib.rs @@ -42,6 +42,39 @@ fn test_item_map() { assert!(resolution.def_id.is_some()); } +#[test] +fn item_map_across_crates() { + let (mut db, files) = MockDatabase::with_files( + " + //- /main.rs + use test_crate::Baz; + + //- /lib.rs + pub struct Baz; + ", + ); + let main_id = files.file_id("/main.rs"); + let lib_id = files.file_id("/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.module_id; + let item_map = db.item_map(source_root).unwrap(); + + let name = SmolStr::from("Baz"); + let resolution = &item_map.per_module[&module_id].items[&name]; + assert!(resolution.def_id.is_some()); +} + #[test] fn typing_inside_a_function_should_not_invalidate_item_map() { let (mut db, pos) = MockDatabase::with_position( -- cgit v1.2.3