From 11f19b784923ac701bc6fc39a6aea712f0091bf7 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 21 Nov 2018 17:51:02 +0300 Subject: name res uses paths --- .../src/completion/reference_completion.rs | 64 ++++++++-------------- crates/ra_analysis/src/descriptors/mod.rs | 2 +- .../ra_analysis/src/descriptors/module/nameres.rs | 4 +- crates/ra_analysis/src/descriptors/path.rs | 51 ++++++++++++++++- 4 files changed, 74 insertions(+), 47 deletions(-) diff --git a/crates/ra_analysis/src/completion/reference_completion.rs b/crates/ra_analysis/src/completion/reference_completion.rs index 84383b547..a96570415 100644 --- a/crates/ra_analysis/src/completion/reference_completion.rs +++ b/crates/ra_analysis/src/completion/reference_completion.rs @@ -10,8 +10,11 @@ use ra_syntax::{ use crate::{ db::RootDatabase, completion::CompletionItem, - descriptors::module::{ModuleDescriptor}, - descriptors::function::FnScopes, + descriptors::{ + module::{ModuleDescriptor}, + function::FnScopes, + Path, PathKind, + }, Cancelable }; @@ -55,7 +58,7 @@ pub(super) fn completions( }), ); } - NameRefKind::CratePath(path) => complete_path(acc, db, module, path)?, + NameRefKind::Path(path) => complete_path(acc, db, module, path)?, NameRefKind::BareIdentInMod => { let name_range = name_ref.syntax().range(); let top_node = name_ref @@ -79,8 +82,8 @@ enum NameRefKind<'a> { LocalRef { enclosing_fn: Option>, }, - /// NameRef is the last segment in crate:: path - CratePath(Vec>), + /// NameRef is the last segment in some path + Path(Path), /// NameRef is bare identifier at the module's root. /// Used for keyword completion BareIdentInMod, @@ -102,8 +105,10 @@ fn classify_name_ref(name_ref: ast::NameRef) -> Option { let parent = name_ref.syntax().parent()?; if let Some(segment) = ast::PathSegment::cast(parent) { let path = segment.parent_path(); - if let Some(crate_path) = crate_path(path) { - return Some(NameRefKind::CratePath(crate_path)); + if let Some(path) = Path::from_ast(path) { + if !path.is_ident() { + return Some(NameRefKind::Path(path)); + } } if path.qualifier().is_none() { let enclosing_fn = name_ref @@ -117,32 +122,6 @@ fn classify_name_ref(name_ref: ast::NameRef) -> Option { None } -fn crate_path(mut path: ast::Path) -> Option> { - let mut res = Vec::new(); - loop { - let segment = path.segment()?; - match segment.kind()? { - ast::PathSegmentKind::Name(name) => res.push(name), - ast::PathSegmentKind::CrateKw => break, - ast::PathSegmentKind::SelfKw | ast::PathSegmentKind::SuperKw => return None, - } - path = qualifier(path)?; - } - res.reverse(); - return Some(res); - - fn qualifier(path: ast::Path) -> Option { - if let Some(q) = path.qualifier() { - return Some(q); - } - // TODO: this bottom up traversal is not too precise. - // Should we handle do a top-down analysiss, recording results? - let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; - let use_tree = use_tree_list.parent_use_tree(); - use_tree.path() - } -} - fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec) { let mut shadowed = FxHashSet::default(); acc.extend( @@ -169,9 +148,9 @@ fn complete_path( acc: &mut Vec, db: &RootDatabase, module: &ModuleDescriptor, - crate_path: Vec, + path: Path, ) -> Cancelable<()> { - let target_module = match find_target_module(module, crate_path) { + let target_module = match find_target_module(module, path) { None => return Ok(()), Some(it) => it, }; @@ -188,14 +167,15 @@ fn complete_path( Ok(()) } -fn find_target_module( - module: &ModuleDescriptor, - mut crate_path: Vec, -) -> Option { - crate_path.pop(); +fn find_target_module(module: &ModuleDescriptor, path: Path) -> Option { + if path.kind != PathKind::Crate { + return None; + } + let mut segments = path.segments; + segments.pop(); let mut target_module = module.crate_root(); - for name in crate_path { - target_module = target_module.child(name.text().as_str())?; + for name in segments { + target_module = target_module.child(&name)?; } Some(target_module) } diff --git a/crates/ra_analysis/src/descriptors/mod.rs b/crates/ra_analysis/src/descriptors/mod.rs index e6225479d..97750ea64 100644 --- a/crates/ra_analysis/src/descriptors/mod.rs +++ b/crates/ra_analysis/src/descriptors/mod.rs @@ -5,7 +5,7 @@ mod path; use std::sync::Arc; use ra_syntax::{ - ast::{self, FnDefNode}, + ast::{self, FnDefNode, AstNode}, TextRange, }; diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index bf671470c..4c555421d 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs @@ -23,7 +23,7 @@ use rustc_hash::FxHashMap; use ra_syntax::{ SmolStr, SyntaxKind::{self, *}, - ast::{self, AstNode, ModuleItemOwner} + ast::{self, ModuleItemOwner} }; use crate::{ @@ -309,7 +309,7 @@ where let mut curr = match import.path.kind { // TODO: handle extern crates - PathKind::Abs => return, + PathKind::Plain => return, PathKind::Self_ => module_id, PathKind::Super => { match module_id.parent(&self.module_tree) { diff --git a/crates/ra_analysis/src/descriptors/path.rs b/crates/ra_analysis/src/descriptors/path.rs index 4ed561b51..99fca18b1 100644 --- a/crates/ra_analysis/src/descriptors/path.rs +++ b/crates/ra_analysis/src/descriptors/path.rs @@ -10,13 +10,14 @@ pub(crate) struct Path { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum PathKind { - Abs, + Plain, Self_, Super, Crate, } impl Path { + /// Calls `cb` with all paths, represented by this use item. pub(crate) fn expand_use_item( item: ast::UseItem, mut cb: impl FnMut(Path, Option), @@ -25,6 +26,52 @@ impl Path { expand_use_tree(None, tree, &mut cb); } } + + /// Converts an `ast::Path` to `Path`. Works with use trees. + pub(crate) fn from_ast(mut path: ast::Path) -> Option { + let mut kind = PathKind::Plain; + let mut segments = Vec::new(); + loop { + let segment = path.segment()?; + match segment.kind()? { + ast::PathSegmentKind::Name(name) => segments.push(name.text()), + ast::PathSegmentKind::CrateKw => { + kind = PathKind::Crate; + break; + } + ast::PathSegmentKind::SelfKw => { + kind = PathKind::Self_; + break; + } + ast::PathSegmentKind::SuperKw => { + kind = PathKind::Super; + break; + } + } + path = match qualifier(path) { + Some(it) => it, + None => break, + }; + } + segments.reverse(); + return Some(Path { kind, segments }); + + fn qualifier(path: ast::Path) -> Option { + if let Some(q) = path.qualifier() { + return Some(q); + } + // TODO: this bottom up traversal is not too precise. + // Should we handle do a top-down analysiss, recording results? + let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; + let use_tree = use_tree_list.parent_use_tree(); + use_tree.path() + } + } + + /// `true` is this path is a single identifier, like `foo` + pub(crate) fn is_ident(&self) -> bool { + self.kind == PathKind::Plain && self.segments.len() == 1 + } } fn expand_use_tree( @@ -68,7 +115,7 @@ fn convert_path(prefix: Option, path: ast::Path) -> Option { let res = match segment.kind()? { ast::PathSegmentKind::Name(name) => { let mut res = prefix.unwrap_or_else(|| Path { - kind: PathKind::Abs, + kind: PathKind::Plain, segments: Vec::with_capacity(1), }); res.segments.push(name.text()); -- cgit v1.2.3