aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src/completion/reference_completion.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis/src/completion/reference_completion.rs')
-rw-r--r--crates/ra_analysis/src/completion/reference_completion.rs106
1 files changed, 39 insertions, 67 deletions
diff --git a/crates/ra_analysis/src/completion/reference_completion.rs b/crates/ra_analysis/src/completion/reference_completion.rs
index 6c5fd0be6..e1a2d5241 100644
--- a/crates/ra_analysis/src/completion/reference_completion.rs
+++ b/crates/ra_analysis/src/completion/reference_completion.rs
@@ -6,23 +6,23 @@ use ra_syntax::{
6 ast::{self, LoopBodyOwner}, 6 ast::{self, LoopBodyOwner},
7 SyntaxKind::*, 7 SyntaxKind::*,
8}; 8};
9use hir::{
10 self,
11 FnScopes,
12 Def,
13 Path,
14};
9 15
10use crate::{ 16use crate::{
11 db::RootDatabase, 17 db::RootDatabase,
12 input::{SourceRootId},
13 completion::CompletionItem, 18 completion::CompletionItem,
14 descriptors::module::{ModuleId, ModuleTree},
15 descriptors::function::FnScopes,
16 descriptors::DescriptorDatabase,
17 Cancelable 19 Cancelable
18}; 20};
19 21
20pub(super) fn completions( 22pub(super) fn completions(
21 acc: &mut Vec<CompletionItem>, 23 acc: &mut Vec<CompletionItem>,
22 db: &RootDatabase, 24 db: &RootDatabase,
23 source_root_id: SourceRootId, 25 module: &hir::Module,
24 module_tree: &ModuleTree,
25 module_id: ModuleId,
26 file: &SourceFileNode, 26 file: &SourceFileNode,
27 name_ref: ast::NameRef, 27 name_ref: ast::NameRef,
28) -> Cancelable<()> { 28) -> Cancelable<()> {
@@ -40,25 +40,28 @@ pub(super) fn completions(
40 complete_expr_snippets(acc); 40 complete_expr_snippets(acc);
41 } 41 }
42 42
43 let module_scope = db.module_scope(source_root_id, module_id)?; 43 let module_scope = module.scope(db)?;
44 acc.extend( 44 acc.extend(
45 module_scope 45 module_scope
46 .entries() 46 .entries()
47 .iter() 47 .filter(|(_name, res)| {
48 .filter(|entry| {
49 // Don't expose this item 48 // Don't expose this item
50 !entry.ptr().range().is_subrange(&name_ref.syntax().range()) 49 match res.import {
50 None => true,
51 Some(import) => {
52 let range = import.range(db, module.source().file_id());
53 !range.is_subrange(&name_ref.syntax().range())
54 }
55 }
51 }) 56 })
52 .map(|entry| CompletionItem { 57 .map(|(name, _res)| CompletionItem {
53 label: entry.name().to_string(), 58 label: name.to_string(),
54 lookup: None, 59 lookup: None,
55 snippet: None, 60 snippet: None,
56 }), 61 }),
57 ); 62 );
58 } 63 }
59 NameRefKind::CratePath(path) => { 64 NameRefKind::Path(path) => complete_path(acc, db, module, path)?,
60 complete_path(acc, db, source_root_id, module_tree, module_id, path)?
61 }
62 NameRefKind::BareIdentInMod => { 65 NameRefKind::BareIdentInMod => {
63 let name_range = name_ref.syntax().range(); 66 let name_range = name_ref.syntax().range();
64 let top_node = name_ref 67 let top_node = name_ref
@@ -82,8 +85,8 @@ enum NameRefKind<'a> {
82 LocalRef { 85 LocalRef {
83 enclosing_fn: Option<ast::FnDef<'a>>, 86 enclosing_fn: Option<ast::FnDef<'a>>,
84 }, 87 },
85 /// NameRef is the last segment in crate:: path 88 /// NameRef is the last segment in some path
86 CratePath(Vec<ast::NameRef<'a>>), 89 Path(Path),
87 /// NameRef is bare identifier at the module's root. 90 /// NameRef is bare identifier at the module's root.
88 /// Used for keyword completion 91 /// Used for keyword completion
89 BareIdentInMod, 92 BareIdentInMod,
@@ -105,8 +108,10 @@ fn classify_name_ref(name_ref: ast::NameRef) -> Option<NameRefKind> {
105 let parent = name_ref.syntax().parent()?; 108 let parent = name_ref.syntax().parent()?;
106 if let Some(segment) = ast::PathSegment::cast(parent) { 109 if let Some(segment) = ast::PathSegment::cast(parent) {
107 let path = segment.parent_path(); 110 let path = segment.parent_path();
108 if let Some(crate_path) = crate_path(path) { 111 if let Some(path) = Path::from_ast(path) {
109 return Some(NameRefKind::CratePath(crate_path)); 112 if !path.is_ident() {
113 return Some(NameRefKind::Path(path));
114 }
110 } 115 }
111 if path.qualifier().is_none() { 116 if path.qualifier().is_none() {
112 let enclosing_fn = name_ref 117 let enclosing_fn = name_ref
@@ -120,32 +125,6 @@ fn classify_name_ref(name_ref: ast::NameRef) -> Option<NameRefKind> {
120 None 125 None
121} 126}
122 127
123fn crate_path(mut path: ast::Path) -> Option<Vec<ast::NameRef>> {
124 let mut res = Vec::new();
125 loop {
126 let segment = path.segment()?;
127 match segment.kind()? {
128 ast::PathSegmentKind::Name(name) => res.push(name),
129 ast::PathSegmentKind::CrateKw => break,
130 ast::PathSegmentKind::SelfKw | ast::PathSegmentKind::SuperKw => return None,
131 }
132 path = qualifier(path)?;
133 }
134 res.reverse();
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 }
147}
148
149fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { 128fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) {
150 let mut shadowed = FxHashSet::default(); 129 let mut shadowed = FxHashSet::default();
151 acc.extend( 130 acc.extend(
@@ -171,18 +150,24 @@ fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<Completi
171fn complete_path( 150fn complete_path(
172 acc: &mut Vec<CompletionItem>, 151 acc: &mut Vec<CompletionItem>,
173 db: &RootDatabase, 152 db: &RootDatabase,
174 source_root_id: SourceRootId, 153 module: &hir::Module,
175 module_tree: &ModuleTree, 154 mut path: Path,
176 module_id: ModuleId,
177 crate_path: Vec<ast::NameRef>,
178) -> Cancelable<()> { 155) -> Cancelable<()> {
179 let target_module_id = match find_target_module(module_tree, module_id, crate_path) { 156 if path.segments.is_empty() {
157 return Ok(());
158 }
159 path.segments.pop();
160 let def_id = match module.resolve_path(db, path)? {
180 None => return Ok(()), 161 None => return Ok(()),
181 Some(it) => it, 162 Some(it) => it,
182 }; 163 };
183 let module_scope = db.module_scope(source_root_id, target_module_id)?; 164 let target_module = match def_id.resolve(db)? {
184 let completions = module_scope.entries().iter().map(|entry| CompletionItem { 165 Def::Module(it) => it,
185 label: entry.name().to_string(), 166 Def::Item => return Ok(()),
167 };
168 let module_scope = target_module.scope(db)?;
169 let completions = module_scope.entries().map(|(name, _res)| CompletionItem {
170 label: name.to_string(),
186 lookup: None, 171 lookup: None,
187 snippet: None, 172 snippet: None,
188 }); 173 });
@@ -190,19 +175,6 @@ fn complete_path(
190 Ok(()) 175 Ok(())
191} 176}
192 177
193fn find_target_module(
194 module_tree: &ModuleTree,
195 module_id: ModuleId,
196 mut crate_path: Vec<ast::NameRef>,
197) -> Option<ModuleId> {
198 crate_path.pop();
199 let mut target_module = module_id.root(&module_tree);
200 for name in crate_path {
201 target_module = target_module.child(module_tree, name.text().as_str())?;
202 }
203 Some(target_module)
204}
205
206fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) { 178fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) {
207 acc.push(CompletionItem { 179 acc.push(CompletionItem {
208 label: "tfn".to_string(), 180 label: "tfn".to_string(),