mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
name res uses paths
This commit is contained in:
parent
5a87a24f82
commit
11f19b7849
4 changed files with 74 additions and 47 deletions
|
@ -10,8 +10,11 @@ use ra_syntax::{
|
||||||
use crate::{
|
use crate::{
|
||||||
db::RootDatabase,
|
db::RootDatabase,
|
||||||
completion::CompletionItem,
|
completion::CompletionItem,
|
||||||
descriptors::module::{ModuleDescriptor},
|
descriptors::{
|
||||||
descriptors::function::FnScopes,
|
module::{ModuleDescriptor},
|
||||||
|
function::FnScopes,
|
||||||
|
Path, PathKind,
|
||||||
|
},
|
||||||
Cancelable
|
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 => {
|
NameRefKind::BareIdentInMod => {
|
||||||
let name_range = name_ref.syntax().range();
|
let name_range = name_ref.syntax().range();
|
||||||
let top_node = name_ref
|
let top_node = name_ref
|
||||||
|
@ -79,8 +82,8 @@ enum NameRefKind<'a> {
|
||||||
LocalRef {
|
LocalRef {
|
||||||
enclosing_fn: Option<ast::FnDef<'a>>,
|
enclosing_fn: Option<ast::FnDef<'a>>,
|
||||||
},
|
},
|
||||||
/// NameRef is the last segment in crate:: path
|
/// NameRef is the last segment in some path
|
||||||
CratePath(Vec<ast::NameRef<'a>>),
|
Path(Path),
|
||||||
/// NameRef is bare identifier at the module's root.
|
/// NameRef is bare identifier at the module's root.
|
||||||
/// Used for keyword completion
|
/// Used for keyword completion
|
||||||
BareIdentInMod,
|
BareIdentInMod,
|
||||||
|
@ -102,8 +105,10 @@ fn classify_name_ref(name_ref: ast::NameRef) -> Option<NameRefKind> {
|
||||||
let parent = name_ref.syntax().parent()?;
|
let parent = name_ref.syntax().parent()?;
|
||||||
if let Some(segment) = ast::PathSegment::cast(parent) {
|
if let Some(segment) = ast::PathSegment::cast(parent) {
|
||||||
let path = segment.parent_path();
|
let path = segment.parent_path();
|
||||||
if let Some(crate_path) = crate_path(path) {
|
if let Some(path) = Path::from_ast(path) {
|
||||||
return Some(NameRefKind::CratePath(crate_path));
|
if !path.is_ident() {
|
||||||
|
return Some(NameRefKind::Path(path));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if path.qualifier().is_none() {
|
if path.qualifier().is_none() {
|
||||||
let enclosing_fn = name_ref
|
let enclosing_fn = name_ref
|
||||||
|
@ -117,32 +122,6 @@ fn classify_name_ref(name_ref: ast::NameRef) -> Option<NameRefKind> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn crate_path(mut path: ast::Path) -> Option<Vec<ast::NameRef>> {
|
|
||||||
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<ast::Path> {
|
|
||||||
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<CompletionItem>) {
|
fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) {
|
||||||
let mut shadowed = FxHashSet::default();
|
let mut shadowed = FxHashSet::default();
|
||||||
acc.extend(
|
acc.extend(
|
||||||
|
@ -169,9 +148,9 @@ fn complete_path(
|
||||||
acc: &mut Vec<CompletionItem>,
|
acc: &mut Vec<CompletionItem>,
|
||||||
db: &RootDatabase,
|
db: &RootDatabase,
|
||||||
module: &ModuleDescriptor,
|
module: &ModuleDescriptor,
|
||||||
crate_path: Vec<ast::NameRef>,
|
path: Path,
|
||||||
) -> Cancelable<()> {
|
) -> Cancelable<()> {
|
||||||
let target_module = match find_target_module(module, crate_path) {
|
let target_module = match find_target_module(module, path) {
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
};
|
};
|
||||||
|
@ -188,14 +167,15 @@ fn complete_path(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_target_module(
|
fn find_target_module(module: &ModuleDescriptor, path: Path) -> Option<ModuleDescriptor> {
|
||||||
module: &ModuleDescriptor,
|
if path.kind != PathKind::Crate {
|
||||||
mut crate_path: Vec<ast::NameRef>,
|
return None;
|
||||||
) -> Option<ModuleDescriptor> {
|
}
|
||||||
crate_path.pop();
|
let mut segments = path.segments;
|
||||||
|
segments.pop();
|
||||||
let mut target_module = module.crate_root();
|
let mut target_module = module.crate_root();
|
||||||
for name in crate_path {
|
for name in segments {
|
||||||
target_module = target_module.child(name.text().as_str())?;
|
target_module = target_module.child(&name)?;
|
||||||
}
|
}
|
||||||
Some(target_module)
|
Some(target_module)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ mod path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
ast::{self, FnDefNode},
|
ast::{self, FnDefNode, AstNode},
|
||||||
TextRange,
|
TextRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
SmolStr, SyntaxKind::{self, *},
|
SmolStr, SyntaxKind::{self, *},
|
||||||
ast::{self, AstNode, ModuleItemOwner}
|
ast::{self, ModuleItemOwner}
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -309,7 +309,7 @@ where
|
||||||
|
|
||||||
let mut curr = match import.path.kind {
|
let mut curr = match import.path.kind {
|
||||||
// TODO: handle extern crates
|
// TODO: handle extern crates
|
||||||
PathKind::Abs => return,
|
PathKind::Plain => return,
|
||||||
PathKind::Self_ => module_id,
|
PathKind::Self_ => module_id,
|
||||||
PathKind::Super => {
|
PathKind::Super => {
|
||||||
match module_id.parent(&self.module_tree) {
|
match module_id.parent(&self.module_tree) {
|
||||||
|
|
|
@ -10,13 +10,14 @@ pub(crate) struct Path {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub(crate) enum PathKind {
|
pub(crate) enum PathKind {
|
||||||
Abs,
|
Plain,
|
||||||
Self_,
|
Self_,
|
||||||
Super,
|
Super,
|
||||||
Crate,
|
Crate,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Path {
|
impl Path {
|
||||||
|
/// Calls `cb` with all paths, represented by this use item.
|
||||||
pub(crate) fn expand_use_item(
|
pub(crate) fn expand_use_item(
|
||||||
item: ast::UseItem,
|
item: ast::UseItem,
|
||||||
mut cb: impl FnMut(Path, Option<LocalSyntaxPtr>),
|
mut cb: impl FnMut(Path, Option<LocalSyntaxPtr>),
|
||||||
|
@ -25,6 +26,52 @@ impl Path {
|
||||||
expand_use_tree(None, tree, &mut cb);
|
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<Path> {
|
||||||
|
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<ast::Path> {
|
||||||
|
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(
|
fn expand_use_tree(
|
||||||
|
@ -68,7 +115,7 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> {
|
||||||
let res = match segment.kind()? {
|
let res = match segment.kind()? {
|
||||||
ast::PathSegmentKind::Name(name) => {
|
ast::PathSegmentKind::Name(name) => {
|
||||||
let mut res = prefix.unwrap_or_else(|| Path {
|
let mut res = prefix.unwrap_or_else(|| Path {
|
||||||
kind: PathKind::Abs,
|
kind: PathKind::Plain,
|
||||||
segments: Vec::with_capacity(1),
|
segments: Vec::with_capacity(1),
|
||||||
});
|
});
|
||||||
res.segments.push(name.text());
|
res.segments.push(name.text());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue