aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-11-07 18:38:41 +0000
committerAleksey Kladov <[email protected]>2018-11-07 18:38:41 +0000
commit6d253b58da955cee73b0715b91d728df5009937d (patch)
tree8951f181a563fbb08199ab99f383f2d01a756f05 /crates
parent06fbc6e3edca1e53f1034bf779f2677d87076c1c (diff)
Complete paths in use trees
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_analysis/src/completion/reference_completion.rs21
-rw-r--r--crates/ra_analysis/tests/tests.rs41
-rw-r--r--crates/ra_syntax/src/ast/mod.rs9
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<NameRefKind> {
105 let parent = name_ref.syntax().parent()?; 105 let parent = name_ref.syntax().parent()?;
106 if let Some(segment) = ast::PathSegment::cast(parent) { 106 if let Some(segment) = ast::PathSegment::cast(parent) {
107 let path = segment.parent_path(); 107 let path = segment.parent_path();
108 if let Some(crate_path) = crate_path(path) {
109 return Some(NameRefKind::CratePath(crate_path));
110 }
108 if path.qualifier().is_none() { 111 if path.qualifier().is_none() {
109 let enclosing_fn = name_ref 112 let enclosing_fn = name_ref
110 .syntax() 113 .syntax()
@@ -113,9 +116,6 @@ fn classify_name_ref(name_ref: ast::NameRef) -> Option<NameRefKind> {
113 .find_map(ast::FnDef::cast); 116 .find_map(ast::FnDef::cast);
114 return Some(NameRefKind::LocalRef { enclosing_fn }); 117 return Some(NameRefKind::LocalRef { enclosing_fn });
115 } 118 }
116 if let Some(crate_path) = crate_path(path) {
117 return Some(NameRefKind::CratePath(crate_path));
118 }
119 } 119 }
120 None 120 None
121} 121}
@@ -129,10 +129,21 @@ fn crate_path(mut path: ast::Path) -> Option<Vec<ast::NameRef>> {
129 ast::PathSegmentKind::CrateKw => break, 129 ast::PathSegmentKind::CrateKw => break,
130 ast::PathSegmentKind::SelfKw | ast::PathSegmentKind::SuperKw => return None, 130 ast::PathSegmentKind::SelfKw | ast::PathSegmentKind::SuperKw => return None,
131 } 131 }
132 path = path.qualifier()?; 132 path = qualifier(path)?;
133 } 133 }
134 res.reverse(); 134 res.reverse();
135 Some(res) 135 return Some(res);
136
137 fn qualifier(path: ast::Path) -> Option<ast::Path> {
138 if let Some(q) = path.qualifier() {
139 return Some(q);
140 }
141 // TODO: this bottom up traversal is not too precise.
142 // Should we handle do a top-down analysiss, recording results?
143 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
144 let use_tree = use_tree_list.parent_use_tree();
145 use_tree.path()
146 }
136} 147}
137 148
138fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { 149fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) {
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() {
452 &completions, 452 &completions,
453 ); 453 );
454} 454}
455
456#[test]
457fn test_complete_crate_path_with_braces() {
458 let (analysis, position) = analysis_and_position(
459 "
460 //- /lib.rs
461 mod foo;
462 struct Spam;
463 //- /foo.rs
464 use crate::{Sp<|>};
465 ",
466 );
467 let completions = analysis.completions(position).unwrap().unwrap();
468 assert_eq_dbg(
469 r#"[CompletionItem { label: "foo", lookup: None, snippet: None },
470 CompletionItem { label: "Spam", lookup: None, snippet: None }]"#,
471 &completions,
472 );
473}
474
475#[test]
476fn test_complete_crate_path_in_nested_tree() {
477 let (analysis, position) = analysis_and_position(
478 "
479 //- /lib.rs
480 mod foo;
481 pub mod bar {
482 pub mod baz {
483 pub struct Spam;
484 }
485 }
486 //- /foo.rs
487 use crate::{bar::{baz::Sp<|>}};
488 ",
489 );
490 let completions = analysis.completions(position).unwrap().unwrap();
491 assert_eq_dbg(
492 r#"[CompletionItem { label: "Spam", lookup: None, snippet: None }]"#,
493 &completions,
494 );
495}
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> {
296 } 296 }
297} 297}
298 298
299impl<'a> UseTreeList<'a> {
300 pub fn parent_use_tree(self) -> UseTree<'a> {
301 self.syntax()
302 .parent()
303 .and_then(UseTree::cast)
304 .expect("UseTreeLists are always nested in UseTrees")
305 }
306}
307
299fn child_opt<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> Option<C> { 308fn child_opt<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> Option<C> {
300 children(parent).next() 309 children(parent).next()
301} 310}