diff options
Diffstat (limited to 'crates/ra_analysis/src/completion/reference_completion.rs')
-rw-r--r-- | crates/ra_analysis/src/completion/reference_completion.rs | 106 |
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 | }; |
9 | use hir::{ | ||
10 | self, | ||
11 | FnScopes, | ||
12 | Def, | ||
13 | Path, | ||
14 | }; | ||
9 | 15 | ||
10 | use crate::{ | 16 | use 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 | ||
20 | pub(super) fn completions( | 22 | pub(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 | ||
123 | fn 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 | |||
149 | fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { | 128 | fn 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 | |||
171 | fn complete_path( | 150 | fn 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 | ||
193 | fn 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 | |||
206 | fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) { | 178 | fn 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(), |