aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-12-21 20:04:56 +0000
committerAleksey Kladov <[email protected]>2018-12-21 20:04:56 +0000
commit2136e75c0bce090d104bb5b5006e48e42fb22a0a (patch)
treed17fa5832a8e04f925f9d3b62c3c2bf23a2de714 /crates/ra_analysis
parentcbe67339df2bbcb17e12ad74e8b8cd53baffb9f7 (diff)
move path completion to a separate component
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r--crates/ra_analysis/src/completion.rs43
-rw-r--r--crates/ra_analysis/src/completion/complete_path.rs95
-rw-r--r--crates/ra_analysis/src/completion/reference_completion.rs33
3 files changed, 127 insertions, 44 deletions
diff --git a/crates/ra_analysis/src/completion.rs b/crates/ra_analysis/src/completion.rs
index 883b3e851..d91304bc2 100644
--- a/crates/ra_analysis/src/completion.rs
+++ b/crates/ra_analysis/src/completion.rs
@@ -4,13 +4,12 @@ mod reference_completion;
4mod complete_fn_param; 4mod complete_fn_param;
5mod complete_keyword; 5mod complete_keyword;
6mod complete_snippet; 6mod complete_snippet;
7mod complete_path;
7 8
8use ra_editor::find_node_at_offset; 9use ra_editor::find_node_at_offset;
9use ra_text_edit::AtomTextEdit; 10use ra_text_edit::AtomTextEdit;
10use ra_syntax::{ 11use ra_syntax::{
11 algo::{ 12 algo::find_leaf_at_offset,
12 find_leaf_at_offset,
13 },
14 ast, 13 ast,
15 AstNode, 14 AstNode,
16 SyntaxNodeRef, 15 SyntaxNodeRef,
@@ -48,11 +47,12 @@ pub(crate) fn completions(
48 reference_completion::completions(&mut acc, db, &module, &file, name_ref)?; 47 reference_completion::completions(&mut acc, db, &module, &file, name_ref)?;
49 } 48 }
50 49
51 let ctx = ctry!(SyntaxContext::new(&original_file, position.offset)); 50 let ctx = ctry!(SyntaxContext::new(db, &original_file, position)?);
52 complete_fn_param::complete_fn_param(&mut acc, &ctx); 51 complete_fn_param::complete_fn_param(&mut acc, &ctx);
53 complete_keyword::complete_expr_keyword(&mut acc, &ctx); 52 complete_keyword::complete_expr_keyword(&mut acc, &ctx);
54 complete_snippet::complete_expr_snippet(&mut acc, &ctx); 53 complete_snippet::complete_expr_snippet(&mut acc, &ctx);
55 complete_snippet::complete_item_snippet(&mut acc, &ctx); 54 complete_snippet::complete_item_snippet(&mut acc, &ctx);
55 complete_path::complete_path(&mut acc, &ctx)?;
56 56
57 Ok(Some(acc)) 57 Ok(Some(acc))
58} 58}
@@ -61,31 +61,44 @@ pub(crate) fn completions(
61/// exactly is the cursor, syntax-wise. 61/// exactly is the cursor, syntax-wise.
62#[derive(Debug)] 62#[derive(Debug)]
63pub(super) struct SyntaxContext<'a> { 63pub(super) struct SyntaxContext<'a> {
64 db: &'a db::RootDatabase,
64 leaf: SyntaxNodeRef<'a>, 65 leaf: SyntaxNodeRef<'a>,
66 module: Option<hir::Module>,
65 enclosing_fn: Option<ast::FnDef<'a>>, 67 enclosing_fn: Option<ast::FnDef<'a>>,
66 is_param: bool, 68 is_param: bool,
67 /// A single-indent path, like `foo`. 69 /// A single-indent path, like `foo`.
68 is_trivial_path: bool, 70 is_trivial_path: bool,
71 /// If not a trivial, path, the prefix (qualifier).
72 path_prefix: Option<hir::Path>,
69 after_if: bool, 73 after_if: bool,
70 is_stmt: bool, 74 is_stmt: bool,
71 /// Something is typed at the "top" level, in module or impl/trait. 75 /// Something is typed at the "top" level, in module or impl/trait.
72 is_new_item: bool, 76 is_new_item: bool,
73} 77}
74 78
75impl SyntaxContext<'_> { 79impl<'a> SyntaxContext<'a> {
76 pub(super) fn new(original_file: &SourceFileNode, offset: TextUnit) -> Option<SyntaxContext> { 80 pub(super) fn new(
77 let leaf = find_leaf_at_offset(original_file.syntax(), offset).left_biased()?; 81 db: &'a db::RootDatabase,
82 original_file: &'a SourceFileNode,
83 position: FilePosition,
84 ) -> Cancelable<Option<SyntaxContext<'a>>> {
85 let module = source_binder::module_from_position(db, position)?;
86 let leaf =
87 ctry!(find_leaf_at_offset(original_file.syntax(), position.offset).left_biased());
78 let mut ctx = SyntaxContext { 88 let mut ctx = SyntaxContext {
89 db,
79 leaf, 90 leaf,
91 module,
80 enclosing_fn: None, 92 enclosing_fn: None,
81 is_param: false, 93 is_param: false,
82 is_trivial_path: false, 94 is_trivial_path: false,
95 path_prefix: None,
83 after_if: false, 96 after_if: false,
84 is_stmt: false, 97 is_stmt: false,
85 is_new_item: false, 98 is_new_item: false,
86 }; 99 };
87 ctx.fill(original_file, offset); 100 ctx.fill(original_file, position.offset);
88 Some(ctx) 101 Ok(Some(ctx))
89 } 102 }
90 103
91 fn fill(&mut self, original_file: &SourceFileNode, offset: TextUnit) { 104 fn fill(&mut self, original_file: &SourceFileNode, offset: TextUnit) {
@@ -140,11 +153,13 @@ impl SyntaxContext<'_> {
140 }; 153 };
141 if let Some(segment) = ast::PathSegment::cast(parent) { 154 if let Some(segment) = ast::PathSegment::cast(parent) {
142 let path = segment.parent_path(); 155 let path = segment.parent_path();
143 // if let Some(path) = Path::from_ast(path) { 156 if let Some(mut path) = hir::Path::from_ast(path) {
144 // if !path.is_ident() { 157 if !path.is_ident() {
145 // return Some(NameRefKind::Path(path)); 158 path.segments.pop().unwrap();
146 // } 159 self.path_prefix = Some(path);
147 // } 160 return;
161 }
162 }
148 if path.qualifier().is_none() { 163 if path.qualifier().is_none() {
149 self.is_trivial_path = true; 164 self.is_trivial_path = true;
150 self.enclosing_fn = self 165 self.enclosing_fn = self
diff --git a/crates/ra_analysis/src/completion/complete_path.rs b/crates/ra_analysis/src/completion/complete_path.rs
new file mode 100644
index 000000000..d04503e46
--- /dev/null
+++ b/crates/ra_analysis/src/completion/complete_path.rs
@@ -0,0 +1,95 @@
1use crate::{
2 completion::{CompletionItem, Completions, CompletionKind::*, SyntaxContext},
3 Cancelable,
4};
5
6pub(super) fn complete_path(acc: &mut Completions, ctx: &SyntaxContext) -> Cancelable<()> {
7 let (path, module) = match (&ctx.path_prefix, &ctx.module) {
8 (Some(path), Some(module)) => (path.clone(), module),
9 _ => return Ok(()),
10 };
11 let def_id = match module.resolve_path(ctx.db, path)? {
12 None => return Ok(()),
13 Some(it) => it,
14 };
15 let target_module = match def_id.resolve(ctx.db)? {
16 hir::Def::Module(it) => it,
17 _ => return Ok(()),
18 };
19 let module_scope = target_module.scope(ctx.db)?;
20 module_scope.entries().for_each(|(name, _res)| {
21 CompletionItem::new(name.to_string())
22 .kind(Reference)
23 .add_to(acc)
24 });
25 Ok(())
26}
27
28#[cfg(test)]
29mod tests {
30 use crate::completion::{CompletionKind, check_completion};
31
32 fn check_reference_completion(code: &str, expected_completions: &str) {
33 check_completion(code, expected_completions, CompletionKind::Reference);
34 }
35
36 #[test]
37 fn completes_use_item_starting_with_self() {
38 check_reference_completion(
39 r"
40 use self::m::<|>;
41
42 mod m {
43 struct Bar;
44 }
45 ",
46 "Bar",
47 );
48 }
49
50 #[test]
51 fn completes_use_item_starting_with_crate() {
52 check_reference_completion(
53 "
54 //- /lib.rs
55 mod foo;
56 struct Spam;
57 //- /foo.rs
58 use crate::Sp<|>
59 ",
60 "Spam;foo",
61 );
62 }
63
64 #[test]
65 fn completes_nested_use_tree() {
66 check_reference_completion(
67 "
68 //- /lib.rs
69 mod foo;
70 struct Spam;
71 //- /foo.rs
72 use crate::{Sp<|>};
73 ",
74 "Spam;foo",
75 );
76 }
77
78 #[test]
79 fn completes_deeply_nested_use_tree() {
80 check_reference_completion(
81 "
82 //- /lib.rs
83 mod foo;
84 pub mod bar {
85 pub mod baz {
86 pub struct Spam;
87 }
88 }
89 //- /foo.rs
90 use crate::{bar::{baz::Sp<|>}};
91 ",
92 "Spam",
93 );
94 }
95}
diff --git a/crates/ra_analysis/src/completion/reference_completion.rs b/crates/ra_analysis/src/completion/reference_completion.rs
index 46d381927..459ed8f6f 100644
--- a/crates/ra_analysis/src/completion/reference_completion.rs
+++ b/crates/ra_analysis/src/completion/reference_completion.rs
@@ -1,4 +1,4 @@
1use rustc_hash::{FxHashSet}; 1use rustc_hash::FxHashSet;
2use ra_syntax::{ 2use ra_syntax::{
3 SourceFileNode, AstNode, 3 SourceFileNode, AstNode,
4 ast, 4 ast,
@@ -6,7 +6,7 @@ use ra_syntax::{
6}; 6};
7use hir::{ 7use hir::{
8 self, 8 self,
9 FnScopes, Def, Path 9 FnScopes, Path
10}; 10};
11 11
12use crate::{ 12use crate::{
@@ -53,7 +53,7 @@ pub(super) fn completions(
53 .add_to(acc) 53 .add_to(acc)
54 }); 54 });
55 } 55 }
56 NameRefKind::Path(path) => complete_path(acc, db, module, path)?, 56 NameRefKind::Path(_) => (),
57 NameRefKind::BareIdentInMod => (), 57 NameRefKind::BareIdentInMod => (),
58 } 58 }
59 Ok(()) 59 Ok(())
@@ -121,33 +121,6 @@ fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Completions)
121 } 121 }
122} 122}
123 123
124fn complete_path(
125 acc: &mut Completions,
126 db: &RootDatabase,
127 module: &hir::Module,
128 mut path: Path,
129) -> Cancelable<()> {
130 if path.segments.is_empty() {
131 return Ok(());
132 }
133 path.segments.pop();
134 let def_id = match module.resolve_path(db, path)? {
135 None => return Ok(()),
136 Some(it) => it,
137 };
138 let target_module = match def_id.resolve(db)? {
139 Def::Module(it) => it,
140 _ => return Ok(()),
141 };
142 let module_scope = target_module.scope(db)?;
143 module_scope.entries().for_each(|(name, _res)| {
144 CompletionItem::new(name.to_string())
145 .kind(Reference)
146 .add_to(acc)
147 });
148 Ok(())
149}
150
151#[cfg(test)] 124#[cfg(test)]
152mod tests { 125mod tests {
153 use crate::completion::{CompletionKind, check_completion}; 126 use crate::completion::{CompletionKind, check_completion};