From d963042ca9da93be8d5922ce46ea26dc6a79c929 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 27 Dec 2018 20:07:21 +0300 Subject: introduce hir::Name --- crates/ra_hir/src/krate.rs | 7 ++-- crates/ra_hir/src/lib.rs | 3 ++ crates/ra_hir/src/module.rs | 19 ++++++----- crates/ra_hir/src/module/imp.rs | 19 +++++------ crates/ra_hir/src/module/nameres.rs | 25 ++++++++------ crates/ra_hir/src/module/nameres/tests.rs | 7 ++-- crates/ra_hir/src/name.rs | 56 +++++++++++++++++++++++++++++++ crates/ra_hir/src/path.rs | 18 +++++++--- crates/ra_hir/src/query_definitions.rs | 6 ++-- crates/ra_hir/src/ty.rs | 10 +++--- 10 files changed, 120 insertions(+), 50 deletions(-) create mode 100644 crates/ra_hir/src/name.rs (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs index 1196dcef1..89b1e639e 100644 --- a/crates/ra_hir/src/krate.rs +++ b/crates/ra_hir/src/krate.rs @@ -1,7 +1,6 @@ -use ra_syntax::SmolStr; pub use ra_db::CrateId; -use crate::{HirDatabase, Module, Cancelable}; +use crate::{HirDatabase, Module, Cancelable, Name, AsName}; /// 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 @@ -14,7 +13,7 @@ pub struct Crate { #[derive(Debug)] pub struct CrateDependency { pub krate: Crate, - pub name: SmolStr, + pub name: Name, } impl Crate { @@ -27,7 +26,7 @@ impl Crate { .dependencies(self.crate_id) .map(|dep| { let krate = Crate::new(dep.crate_id()); - let name = dep.name.clone(); + let name = dep.as_name(); CrateDependency { krate, name } }) .collect() diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index f1cc0ccd0..bf43cd0ae 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -22,6 +22,7 @@ mod path; mod arena; pub mod source_binder; +mod name; mod krate; mod module; mod function; @@ -37,10 +38,12 @@ use ra_db::{LocationIntener, SourceRootId, FileId, Cancelable}; use crate::{ db::HirDatabase, arena::{Arena, Id}, + name::AsName, }; pub use self::{ path::{Path, PathKind}, + name::Name, krate::Crate, module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution}, function::{Function, FnScopes}, diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs index b9d36f01f..43413acb8 100644 --- a/crates/ra_hir/src/module.rs +++ b/crates/ra_hir/src/module.rs @@ -7,13 +7,14 @@ use log; use ra_syntax::{ algo::generate, ast::{self, AstNode, NameOwner}, - SmolStr, SyntaxNode, + SyntaxNode, }; use ra_db::{SourceRootId, FileId, Cancelable}; use relative_path::RelativePathBuf; use crate::{ DefKind, DefLoc, DefId, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId, Crate, + Name, arena::{Arena, Id}, }; @@ -84,7 +85,7 @@ impl Module { } /// `name` is `None` for the crate's root module - pub fn name(&self) -> Option { + pub fn name(&self) -> Option<&Name> { let link = self.module_id.parent_link(&self.tree)?; Some(link.name(&self.tree)) } @@ -100,7 +101,7 @@ impl Module { } /// Finds a child module with the specified name. - pub fn child(&self, name: &str) -> Option { + pub fn child(&self, name: &Name) -> Option { let child_id = self.module_id.child(&self.tree, name)?; Some(Module { module_id: child_id, @@ -230,15 +231,15 @@ impl ModuleId { .last() .unwrap() } - fn child(self, tree: &ModuleTree, name: &str) -> Option { + fn child(self, tree: &ModuleTree, name: &Name) -> Option { let link = tree.mods[self] .children .iter() .map(|&it| &tree.links[it]) - .find(|it| it.name == name)?; + .find(|it| it.name == *name)?; Some(*link.points_to.first()?) } - fn children<'a>(self, tree: &'a ModuleTree) -> impl Iterator + 'a { + fn children<'a>(self, tree: &'a ModuleTree) -> impl Iterator + 'a { tree.mods[self].children.iter().filter_map(move |&it| { let link = &tree.links[it]; let module = *link.points_to.first()?; @@ -263,8 +264,8 @@ impl LinkId { fn owner(self, tree: &ModuleTree) -> ModuleId { tree.links[self].owner } - fn name(self, tree: &ModuleTree) -> SmolStr { - tree.links[self].name.clone() + fn name(self, tree: &ModuleTree) -> &Name { + &tree.links[self].name } fn bind_source<'a>(self, tree: &ModuleTree, db: &impl HirDatabase) -> ast::ModuleNode { let owner = self.owner(tree); @@ -328,7 +329,7 @@ impl ModuleSource { #[derive(Hash, Debug, PartialEq, Eq)] struct LinkData { owner: ModuleId, - name: SmolStr, + name: Name, points_to: Vec, problem: Option, } diff --git a/crates/ra_hir/src/module/imp.rs b/crates/ra_hir/src/module/imp.rs index 748fdb64e..eded85a63 100644 --- a/crates/ra_hir/src/module/imp.rs +++ b/crates/ra_hir/src/module/imp.rs @@ -1,16 +1,13 @@ use std::sync::Arc; -use ra_syntax::{ - ast::{self, NameOwner}, - SmolStr, -}; +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, + HirDatabase, Name, AsName, }; use super::{ @@ -20,12 +17,12 @@ use super::{ #[derive(Clone, Hash, PartialEq, Eq, Debug)] pub enum Submodule { - Declaration(SmolStr), - Definition(SmolStr, ModuleSource), + Declaration(Name), + Definition(Name, ModuleSource), } impl Submodule { - fn name(&self) -> &SmolStr { + fn name(&self) -> &Name { match self { Submodule::Declaration(name) => name, Submodule::Definition(name, _) => name, @@ -35,14 +32,14 @@ impl Submodule { pub(crate) fn modules<'a>( root: impl ast::ModuleItemOwner<'a>, -) -> impl Iterator)> { +) -> impl Iterator)> { root.items() .filter_map(|item| match item { ast::ModuleItem::Module(m) => Some(m), _ => None, }) .filter_map(|module| { - let name = module.name()?.text(); + let name = module.name()?.as_name(); Some((name, module)) }) } @@ -155,7 +152,7 @@ fn build_subtree( fn resolve_submodule( db: &impl HirDatabase, source: ModuleSource, - name: &SmolStr, + name: &Name, ) -> (Vec, Option) { // FIXME: handle submodules of inline modules properly let file_id = source.file_id(); diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index 98cd225dd..68eb02a98 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs @@ -14,14 +14,12 @@ //! 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 std::sync::Arc; use rustc_hash::FxHashMap; use ra_syntax::{ TextRange, - SmolStr, SyntaxKind::{self, *}, + SyntaxKind::{self, *}, ast::{self, AstNode} }; use ra_db::SourceRootId; @@ -32,6 +30,7 @@ use crate::{ SourceItemId, SourceFileItemId, SourceFileItems, Path, PathKind, HirDatabase, Crate, + Name, AsName, module::{Module, ModuleId, ModuleTree}, }; @@ -45,14 +44,14 @@ pub struct ItemMap { #[derive(Debug, Default, PartialEq, Eq, Clone)] pub struct ModuleScope { - items: FxHashMap, + items: FxHashMap, } impl ModuleScope { - pub fn entries<'a>(&'a self) -> impl Iterator + 'a { + pub fn entries<'a>(&'a self) -> impl Iterator + 'a { self.items.iter() } - pub fn get(&self, name: &SmolStr) -> Option<&Resolution> { + pub fn get(&self, name: &Name) -> Option<&Resolution> { self.items.get(name) } } @@ -72,7 +71,7 @@ pub struct InputModuleItems { #[derive(Debug, PartialEq, Eq)] struct ModuleItem { id: SourceFileItemId, - name: SmolStr, + name: Name, kind: SyntaxKind, vis: Vis, } @@ -260,7 +259,7 @@ impl InputModuleItems { impl ModuleItem { fn new<'a>(file_items: &SourceFileItems, item: impl ast::NameOwner<'a>) -> Option { - let name = item.name()?.text(); + let name = item.name()?.as_name(); let kind = item.syntax().kind(); let vis = Vis::Other; let id = file_items.id_of_unchecked(item.syntax()); @@ -328,7 +327,11 @@ where for dep in krate.dependencies(self.db) { if let Some(module) = dep.krate.root_module(self.db)? { let def_id = module.def_id(self.db); - self.add_module_item(&mut module_items, dep.name, PerNs::types(def_id)); + self.add_module_item( + &mut module_items, + dep.name.clone(), + PerNs::types(def_id), + ); } } }; @@ -389,7 +392,7 @@ where Ok(()) } - fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, def_id: PerNs) { + fn add_module_item(&self, module_items: &mut ModuleScope, name: Name, def_id: PerNs) { let resolution = Resolution { def_id, import: None, diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs index 03ea5c1d6..165ac81c8 100644 --- a/crates/ra_hir/src/module/nameres/tests.rs +++ b/crates/ra_hir/src/module/nameres/tests.rs @@ -9,6 +9,7 @@ use crate::{ self as hir, db::HirDatabase, mock::MockDatabase, + Name, }; fn item_map(fixture: &str) -> (Arc, hir::ModuleId) { @@ -38,7 +39,7 @@ fn item_map_smoke_test() { pub struct Baz; ", ); - let name = SmolStr::from("Baz"); + let name = Name::new(SmolStr::from("Baz")); let resolution = &item_map.per_module[&module_id].items[&name]; assert!(resolution.def_id.take_types().is_some()); } @@ -57,7 +58,7 @@ fn test_self() { pub struct Baz; ", ); - let name = SmolStr::from("Baz"); + let name = Name::new(SmolStr::from("Baz")); let resolution = &item_map.per_module[&module_id].items[&name]; assert!(resolution.def_id.take_types().is_some()); } @@ -90,7 +91,7 @@ fn item_map_across_crates() { let module_id = module.module_id; let item_map = db.item_map(source_root).unwrap(); - let name = SmolStr::from("Baz"); + let name = Name::new(SmolStr::from("Baz")); let resolution = &item_map.per_module[&module_id].items[&name]; assert!(resolution.def_id.take_types().is_some()); } diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs new file mode 100644 index 000000000..7f42c9f04 --- /dev/null +++ b/crates/ra_hir/src/name.rs @@ -0,0 +1,56 @@ +use std::fmt; + +use ra_syntax::{ast, SmolStr}; + +/// `Name` is a wrapper around string, which is used in hir for both references +/// and declarations. In theory, names should also carry hygene info, but we are +/// not there yet! +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Name { + text: SmolStr, +} + +impl fmt::Display for Name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.text, f) + } +} + +impl Name { + // TODO: get rid of this? + pub(crate) fn as_str(&self) -> &str { + self.text.as_str() + } + + #[cfg(not(test))] + fn new(text: SmolStr) -> Name { + Name { text } + } + + #[cfg(test)] + pub(crate) fn new(text: SmolStr) -> Name { + Name { text } + } +} + +pub(crate) trait AsName { + fn as_name(&self) -> Name; +} + +impl AsName for ast::NameRef<'_> { + fn as_name(&self) -> Name { + Name::new(self.text()) + } +} + +impl AsName for ast::Name<'_> { + fn as_name(&self) -> Name { + Name::new(self.text()) + } +} + +impl AsName for ra_db::Dependency { + fn as_name(&self) -> Name { + Name::new(self.name.clone()) + } +} diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 0b260072c..93f7203fe 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs @@ -1,9 +1,11 @@ -use ra_syntax::{SmolStr, ast, AstNode, TextRange}; +use ra_syntax::{ast, AstNode, TextRange}; + +use crate::{Name, AsName}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Path { pub kind: PathKind, - pub segments: Vec, + pub segments: Vec, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -29,7 +31,7 @@ impl Path { loop { let segment = path.segment()?; match segment.kind()? { - ast::PathSegmentKind::Name(name) => segments.push(name.text()), + ast::PathSegmentKind::Name(name) => segments.push(name.as_name()), ast::PathSegmentKind::CrateKw => { kind = PathKind::Crate; break; @@ -67,6 +69,14 @@ impl Path { pub fn is_ident(&self) -> bool { self.kind == PathKind::Plain && self.segments.len() == 1 } + + /// If this path is a single identifier, like `foo`, return its name. + pub fn as_ident(&self) -> Option<&Name> { + if self.kind != PathKind::Plain || self.segments.len() > 1 { + return None; + } + self.segments.first() + } } fn expand_use_tree( @@ -130,7 +140,7 @@ fn convert_path(prefix: Option, path: ast::Path) -> Option { kind: PathKind::Plain, segments: Vec::with_capacity(1), }); - res.segments.push(name.text()); + res.segments.push(name.as_name()); res } ast::PathSegmentKind::CrateKw => { diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs index 4a7958a12..e6241342a 100644 --- a/crates/ra_hir/src/query_definitions.rs +++ b/crates/ra_hir/src/query_definitions.rs @@ -11,7 +11,7 @@ use ra_syntax::{ use ra_db::{SourceRootId, FileId, Cancelable,}; use crate::{ - SourceFileItems, SourceItemId, DefKind, Function, DefId, + SourceFileItems, SourceItemId, DefKind, Function, DefId, Name, AsName, db::HirDatabase, function::{FnScopes, FnId}, module::{ @@ -130,14 +130,14 @@ pub(crate) fn submodules( pub(crate) fn modules<'a>( root: impl ast::ModuleItemOwner<'a>, -) -> impl Iterator)> { +) -> impl Iterator)> { root.items() .filter_map(|item| match item { ast::ModuleItem::Module(m) => Some(m), _ => None, }) .filter_map(|module| { - let name = module.name()?.text(); + let name = module.name()?.as_name(); Some((name, module)) }) } diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 67b523c2c..dc3323b1a 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -179,13 +179,13 @@ impl Ty { module: &Module, path: &Path, ) -> Cancelable { - if path.is_ident() { - let name = &path.segments[0]; - if let Some(int_ty) = primitive::IntTy::from_string(&name) { + if let Some(name) = path.as_ident() { + let name = name.as_str(); // :-( + if let Some(int_ty) = primitive::IntTy::from_string(name) { return Ok(Ty::Int(int_ty)); - } else if let Some(uint_ty) = primitive::UintTy::from_string(&name) { + } else if let Some(uint_ty) = primitive::UintTy::from_string(name) { return Ok(Ty::Uint(uint_ty)); - } else if let Some(float_ty) = primitive::FloatTy::from_string(&name) { + } else if let Some(float_ty) = primitive::FloatTy::from_string(name) { return Ok(Ty::Float(float_ty)); } } -- cgit v1.2.3