diff options
-rw-r--r-- | crates/ra_analysis/src/completion/reference_completion.rs | 64 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/mod.rs | 2 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/nameres.rs | 4 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/path.rs | 51 |
4 files changed, 74 insertions, 47 deletions
diff --git a/crates/ra_analysis/src/completion/reference_completion.rs b/crates/ra_analysis/src/completion/reference_completion.rs index 84383b547..a96570415 100644 --- a/crates/ra_analysis/src/completion/reference_completion.rs +++ b/crates/ra_analysis/src/completion/reference_completion.rs | |||
@@ -10,8 +10,11 @@ use ra_syntax::{ | |||
10 | use crate::{ | 10 | use crate::{ |
11 | db::RootDatabase, | 11 | db::RootDatabase, |
12 | completion::CompletionItem, | 12 | completion::CompletionItem, |
13 | descriptors::module::{ModuleDescriptor}, | 13 | descriptors::{ |
14 | descriptors::function::FnScopes, | 14 | module::{ModuleDescriptor}, |
15 | function::FnScopes, | ||
16 | Path, PathKind, | ||
17 | }, | ||
15 | Cancelable | 18 | Cancelable |
16 | }; | 19 | }; |
17 | 20 | ||
@@ -55,7 +58,7 @@ pub(super) fn completions( | |||
55 | }), | 58 | }), |
56 | ); | 59 | ); |
57 | } | 60 | } |
58 | NameRefKind::CratePath(path) => complete_path(acc, db, module, path)?, | 61 | NameRefKind::Path(path) => complete_path(acc, db, module, path)?, |
59 | NameRefKind::BareIdentInMod => { | 62 | NameRefKind::BareIdentInMod => { |
60 | let name_range = name_ref.syntax().range(); | 63 | let name_range = name_ref.syntax().range(); |
61 | let top_node = name_ref | 64 | let top_node = name_ref |
@@ -79,8 +82,8 @@ enum NameRefKind<'a> { | |||
79 | LocalRef { | 82 | LocalRef { |
80 | enclosing_fn: Option<ast::FnDef<'a>>, | 83 | enclosing_fn: Option<ast::FnDef<'a>>, |
81 | }, | 84 | }, |
82 | /// NameRef is the last segment in crate:: path | 85 | /// NameRef is the last segment in some path |
83 | CratePath(Vec<ast::NameRef<'a>>), | 86 | Path(Path), |
84 | /// NameRef is bare identifier at the module's root. | 87 | /// NameRef is bare identifier at the module's root. |
85 | /// Used for keyword completion | 88 | /// Used for keyword completion |
86 | BareIdentInMod, | 89 | BareIdentInMod, |
@@ -102,8 +105,10 @@ fn classify_name_ref(name_ref: ast::NameRef) -> Option<NameRefKind> { | |||
102 | let parent = name_ref.syntax().parent()?; | 105 | let parent = name_ref.syntax().parent()?; |
103 | if let Some(segment) = ast::PathSegment::cast(parent) { | 106 | if let Some(segment) = ast::PathSegment::cast(parent) { |
104 | let path = segment.parent_path(); | 107 | let path = segment.parent_path(); |
105 | if let Some(crate_path) = crate_path(path) { | 108 | if let Some(path) = Path::from_ast(path) { |
106 | return Some(NameRefKind::CratePath(crate_path)); | 109 | if !path.is_ident() { |
110 | return Some(NameRefKind::Path(path)); | ||
111 | } | ||
107 | } | 112 | } |
108 | if path.qualifier().is_none() { | 113 | if path.qualifier().is_none() { |
109 | let enclosing_fn = name_ref | 114 | let enclosing_fn = name_ref |
@@ -117,32 +122,6 @@ fn classify_name_ref(name_ref: ast::NameRef) -> Option<NameRefKind> { | |||
117 | None | 122 | None |
118 | } | 123 | } |
119 | 124 | ||
120 | fn crate_path(mut path: ast::Path) -> Option<Vec<ast::NameRef>> { | ||
121 | let mut res = Vec::new(); | ||
122 | loop { | ||
123 | let segment = path.segment()?; | ||
124 | match segment.kind()? { | ||
125 | ast::PathSegmentKind::Name(name) => res.push(name), | ||
126 | ast::PathSegmentKind::CrateKw => break, | ||
127 | ast::PathSegmentKind::SelfKw | ast::PathSegmentKind::SuperKw => return None, | ||
128 | } | ||
129 | path = qualifier(path)?; | ||
130 | } | ||
131 | res.reverse(); | ||
132 | return Some(res); | ||
133 | |||
134 | fn qualifier(path: ast::Path) -> Option<ast::Path> { | ||
135 | if let Some(q) = path.qualifier() { | ||
136 | return Some(q); | ||
137 | } | ||
138 | // TODO: this bottom up traversal is not too precise. | ||
139 | // Should we handle do a top-down analysiss, recording results? | ||
140 | let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; | ||
141 | let use_tree = use_tree_list.parent_use_tree(); | ||
142 | use_tree.path() | ||
143 | } | ||
144 | } | ||
145 | |||
146 | fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { | 125 | fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { |
147 | let mut shadowed = FxHashSet::default(); | 126 | let mut shadowed = FxHashSet::default(); |
148 | acc.extend( | 127 | acc.extend( |
@@ -169,9 +148,9 @@ fn complete_path( | |||
169 | acc: &mut Vec<CompletionItem>, | 148 | acc: &mut Vec<CompletionItem>, |
170 | db: &RootDatabase, | 149 | db: &RootDatabase, |
171 | module: &ModuleDescriptor, | 150 | module: &ModuleDescriptor, |
172 | crate_path: Vec<ast::NameRef>, | 151 | path: Path, |
173 | ) -> Cancelable<()> { | 152 | ) -> Cancelable<()> { |
174 | let target_module = match find_target_module(module, crate_path) { | 153 | let target_module = match find_target_module(module, path) { |
175 | None => return Ok(()), | 154 | None => return Ok(()), |
176 | Some(it) => it, | 155 | Some(it) => it, |
177 | }; | 156 | }; |
@@ -188,14 +167,15 @@ fn complete_path( | |||
188 | Ok(()) | 167 | Ok(()) |
189 | } | 168 | } |
190 | 169 | ||
191 | fn find_target_module( | 170 | fn find_target_module(module: &ModuleDescriptor, path: Path) -> Option<ModuleDescriptor> { |
192 | module: &ModuleDescriptor, | 171 | if path.kind != PathKind::Crate { |
193 | mut crate_path: Vec<ast::NameRef>, | 172 | return None; |
194 | ) -> Option<ModuleDescriptor> { | 173 | } |
195 | crate_path.pop(); | 174 | let mut segments = path.segments; |
175 | segments.pop(); | ||
196 | let mut target_module = module.crate_root(); | 176 | let mut target_module = module.crate_root(); |
197 | for name in crate_path { | 177 | for name in segments { |
198 | target_module = target_module.child(name.text().as_str())?; | 178 | target_module = target_module.child(&name)?; |
199 | } | 179 | } |
200 | Some(target_module) | 180 | Some(target_module) |
201 | } | 181 | } |
diff --git a/crates/ra_analysis/src/descriptors/mod.rs b/crates/ra_analysis/src/descriptors/mod.rs index e6225479d..97750ea64 100644 --- a/crates/ra_analysis/src/descriptors/mod.rs +++ b/crates/ra_analysis/src/descriptors/mod.rs | |||
@@ -5,7 +5,7 @@ mod path; | |||
5 | use std::sync::Arc; | 5 | use std::sync::Arc; |
6 | 6 | ||
7 | use ra_syntax::{ | 7 | use ra_syntax::{ |
8 | ast::{self, FnDefNode}, | 8 | ast::{self, FnDefNode, AstNode}, |
9 | TextRange, | 9 | TextRange, |
10 | }; | 10 | }; |
11 | 11 | ||
diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index bf671470c..4c555421d 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs | |||
@@ -23,7 +23,7 @@ use rustc_hash::FxHashMap; | |||
23 | 23 | ||
24 | use ra_syntax::{ | 24 | use ra_syntax::{ |
25 | SmolStr, SyntaxKind::{self, *}, | 25 | SmolStr, SyntaxKind::{self, *}, |
26 | ast::{self, AstNode, ModuleItemOwner} | 26 | ast::{self, ModuleItemOwner} |
27 | }; | 27 | }; |
28 | 28 | ||
29 | use crate::{ | 29 | use crate::{ |
@@ -309,7 +309,7 @@ where | |||
309 | 309 | ||
310 | let mut curr = match import.path.kind { | 310 | let mut curr = match import.path.kind { |
311 | // TODO: handle extern crates | 311 | // TODO: handle extern crates |
312 | PathKind::Abs => return, | 312 | PathKind::Plain => return, |
313 | PathKind::Self_ => module_id, | 313 | PathKind::Self_ => module_id, |
314 | PathKind::Super => { | 314 | PathKind::Super => { |
315 | match module_id.parent(&self.module_tree) { | 315 | match module_id.parent(&self.module_tree) { |
diff --git a/crates/ra_analysis/src/descriptors/path.rs b/crates/ra_analysis/src/descriptors/path.rs index 4ed561b51..99fca18b1 100644 --- a/crates/ra_analysis/src/descriptors/path.rs +++ b/crates/ra_analysis/src/descriptors/path.rs | |||
@@ -10,13 +10,14 @@ pub(crate) struct Path { | |||
10 | 10 | ||
11 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 11 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
12 | pub(crate) enum PathKind { | 12 | pub(crate) enum PathKind { |
13 | Abs, | 13 | Plain, |
14 | Self_, | 14 | Self_, |
15 | Super, | 15 | Super, |
16 | Crate, | 16 | Crate, |
17 | } | 17 | } |
18 | 18 | ||
19 | impl Path { | 19 | impl Path { |
20 | /// Calls `cb` with all paths, represented by this use item. | ||
20 | pub(crate) fn expand_use_item( | 21 | pub(crate) fn expand_use_item( |
21 | item: ast::UseItem, | 22 | item: ast::UseItem, |
22 | mut cb: impl FnMut(Path, Option<LocalSyntaxPtr>), | 23 | mut cb: impl FnMut(Path, Option<LocalSyntaxPtr>), |
@@ -25,6 +26,52 @@ impl Path { | |||
25 | expand_use_tree(None, tree, &mut cb); | 26 | expand_use_tree(None, tree, &mut cb); |
26 | } | 27 | } |
27 | } | 28 | } |
29 | |||
30 | /// Converts an `ast::Path` to `Path`. Works with use trees. | ||
31 | pub(crate) fn from_ast(mut path: ast::Path) -> Option<Path> { | ||
32 | let mut kind = PathKind::Plain; | ||
33 | let mut segments = Vec::new(); | ||
34 | loop { | ||
35 | let segment = path.segment()?; | ||
36 | match segment.kind()? { | ||
37 | ast::PathSegmentKind::Name(name) => segments.push(name.text()), | ||
38 | ast::PathSegmentKind::CrateKw => { | ||
39 | kind = PathKind::Crate; | ||
40 | break; | ||
41 | } | ||
42 | ast::PathSegmentKind::SelfKw => { | ||
43 | kind = PathKind::Self_; | ||
44 | break; | ||
45 | } | ||
46 | ast::PathSegmentKind::SuperKw => { | ||
47 | kind = PathKind::Super; | ||
48 | break; | ||
49 | } | ||
50 | } | ||
51 | path = match qualifier(path) { | ||
52 | Some(it) => it, | ||
53 | None => break, | ||
54 | }; | ||
55 | } | ||
56 | segments.reverse(); | ||
57 | return Some(Path { kind, segments }); | ||
58 | |||
59 | fn qualifier(path: ast::Path) -> Option<ast::Path> { | ||
60 | if let Some(q) = path.qualifier() { | ||
61 | return Some(q); | ||
62 | } | ||
63 | // TODO: this bottom up traversal is not too precise. | ||
64 | // Should we handle do a top-down analysiss, recording results? | ||
65 | let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; | ||
66 | let use_tree = use_tree_list.parent_use_tree(); | ||
67 | use_tree.path() | ||
68 | } | ||
69 | } | ||
70 | |||
71 | /// `true` is this path is a single identifier, like `foo` | ||
72 | pub(crate) fn is_ident(&self) -> bool { | ||
73 | self.kind == PathKind::Plain && self.segments.len() == 1 | ||
74 | } | ||
28 | } | 75 | } |
29 | 76 | ||
30 | fn expand_use_tree( | 77 | fn expand_use_tree( |
@@ -68,7 +115,7 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { | |||
68 | let res = match segment.kind()? { | 115 | let res = match segment.kind()? { |
69 | ast::PathSegmentKind::Name(name) => { | 116 | ast::PathSegmentKind::Name(name) => { |
70 | let mut res = prefix.unwrap_or_else(|| Path { | 117 | let mut res = prefix.unwrap_or_else(|| Path { |
71 | kind: PathKind::Abs, | 118 | kind: PathKind::Plain, |
72 | segments: Vec::with_capacity(1), | 119 | segments: Vec::with_capacity(1), |
73 | }); | 120 | }); |
74 | res.segments.push(name.text()); | 121 | res.segments.push(name.text()); |