From 6d253b58da955cee73b0715b91d728df5009937d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 7 Nov 2018 21:38:41 +0300 Subject: Complete paths in use trees --- .../src/completion/reference_completion.rs | 21 ++++++++--- crates/ra_analysis/tests/tests.rs | 41 ++++++++++++++++++++++ crates/ra_syntax/src/ast/mod.rs | 9 +++++ 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/crates/ra_analysis/src/completion/reference_completion.rs b/crates/ra_analysis/src/completion/reference_completion.rs index f708f07a0..6c5fd0be6 100644 --- a/crates/ra_analysis/src/completion/reference_completion.rs +++ b/crates/ra_analysis/src/completion/reference_completion.rs @@ -105,6 +105,9 @@ 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 path.qualifier().is_none() { let enclosing_fn = name_ref .syntax() @@ -113,9 +116,6 @@ fn classify_name_ref(name_ref: ast::NameRef) -> Option { .find_map(ast::FnDef::cast); return Some(NameRefKind::LocalRef { enclosing_fn }); } - if let Some(crate_path) = crate_path(path) { - return Some(NameRefKind::CratePath(crate_path)); - } } None } @@ -129,10 +129,21 @@ fn crate_path(mut path: ast::Path) -> Option> { ast::PathSegmentKind::CrateKw => break, ast::PathSegmentKind::SelfKw | ast::PathSegmentKind::SuperKw => return None, } - path = path.qualifier()?; + path = qualifier(path)?; } res.reverse(); - Some(res) + 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) { diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs index c605d34f0..719c166b5 100644 --- a/crates/ra_analysis/tests/tests.rs +++ b/crates/ra_analysis/tests/tests.rs @@ -452,3 +452,44 @@ fn test_complete_crate_path() { &completions, ); } + +#[test] +fn test_complete_crate_path_with_braces() { + let (analysis, position) = analysis_and_position( + " + //- /lib.rs + mod foo; + struct Spam; + //- /foo.rs + use crate::{Sp<|>}; + ", + ); + let completions = analysis.completions(position).unwrap().unwrap(); + assert_eq_dbg( + r#"[CompletionItem { label: "foo", lookup: None, snippet: None }, + CompletionItem { label: "Spam", lookup: None, snippet: None }]"#, + &completions, + ); +} + +#[test] +fn test_complete_crate_path_in_nested_tree() { + let (analysis, position) = analysis_and_position( + " + //- /lib.rs + mod foo; + pub mod bar { + pub mod baz { + pub struct Spam; + } + } + //- /foo.rs + use crate::{bar::{baz::Sp<|>}}; + ", + ); + let completions = analysis.completions(position).unwrap().unwrap(); + assert_eq_dbg( + r#"[CompletionItem { label: "Spam", lookup: None, snippet: None }]"#, + &completions, + ); +} diff --git a/crates/ra_syntax/src/ast/mod.rs b/crates/ra_syntax/src/ast/mod.rs index d93f92672..6b0d62610 100644 --- a/crates/ra_syntax/src/ast/mod.rs +++ b/crates/ra_syntax/src/ast/mod.rs @@ -296,6 +296,15 @@ impl<'a> PathSegment<'a> { } } +impl<'a> UseTreeList<'a> { + pub fn parent_use_tree(self) -> UseTree<'a> { + self.syntax() + .parent() + .and_then(UseTree::cast) + .expect("UseTreeLists are always nested in UseTrees") + } +} + fn child_opt<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> Option { children(parent).next() } -- cgit v1.2.3