diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-11-27 12:03:14 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-11-27 12:03:14 +0000 |
commit | 0bc6f5802f3b80b76aeeb1668a1e1f5db7494309 (patch) | |
tree | ec9c94fa1bf857032b3914175d03fd179f74c660 /crates/ra_analysis/src/descriptors/module | |
parent | 8e37208040a456d4e481472f69b3b584655ee90f (diff) | |
parent | 10f4d4b74cd7e072bf5e8d3fb57c76f35ea03e1d (diff) |
Merge #245
245: File items r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_analysis/src/descriptors/module')
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/nameres.rs | 187 |
1 files changed, 133 insertions, 54 deletions
diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index 648ec5e43..d347a69b0 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs | |||
@@ -17,27 +17,83 @@ | |||
17 | use std::{ | 17 | use std::{ |
18 | sync::Arc, | 18 | sync::Arc, |
19 | time::Instant, | 19 | time::Instant, |
20 | ops::Index, | ||
20 | }; | 21 | }; |
21 | 22 | ||
22 | use rustc_hash::FxHashMap; | 23 | use rustc_hash::FxHashMap; |
23 | 24 | ||
24 | use ra_syntax::{ | 25 | use ra_syntax::{ |
26 | SyntaxNode, SyntaxNodeRef, TextRange, | ||
25 | SmolStr, SyntaxKind::{self, *}, | 27 | SmolStr, SyntaxKind::{self, *}, |
26 | ast::{self, ModuleItemOwner} | 28 | ast::{self, ModuleItemOwner, AstNode} |
27 | }; | 29 | }; |
28 | 30 | ||
29 | use crate::{ | 31 | use crate::{ |
30 | Cancelable, | 32 | Cancelable, FileId, |
31 | loc2id::{DefId, DefLoc}, | 33 | loc2id::{DefId, DefLoc}, |
32 | descriptors::{ | 34 | descriptors::{ |
33 | Path, PathKind, | 35 | Path, PathKind, |
34 | DescriptorDatabase, | 36 | DescriptorDatabase, |
35 | module::{ModuleId, ModuleTree, ModuleSourceNode}, | 37 | module::{ModuleId, ModuleTree, ModuleSourceNode}, |
36 | }, | 38 | }, |
37 | syntax_ptr::{LocalSyntaxPtr}, | ||
38 | input::SourceRootId, | 39 | input::SourceRootId, |
40 | arena::{Arena, Id} | ||
39 | }; | 41 | }; |
40 | 42 | ||
43 | /// Identifier of item within a specific file. This is stable over reparses, so | ||
44 | /// it's OK to use it as a salsa key/value. | ||
45 | pub(crate) type FileItemId = Id<SyntaxNode>; | ||
46 | |||
47 | /// Maps item's `SyntaxNode`s to `FileItemId` and back. | ||
48 | #[derive(Debug, PartialEq, Eq, Default)] | ||
49 | pub(crate) struct FileItems { | ||
50 | arena: Arena<SyntaxNode>, | ||
51 | } | ||
52 | |||
53 | impl FileItems { | ||
54 | fn alloc(&mut self, item: SyntaxNode) -> FileItemId { | ||
55 | self.arena.alloc(item) | ||
56 | } | ||
57 | fn id_of(&self, item: SyntaxNodeRef) -> FileItemId { | ||
58 | let (id, _item) = self | ||
59 | .arena | ||
60 | .iter() | ||
61 | .find(|(_id, i)| i.borrowed() == item) | ||
62 | .unwrap(); | ||
63 | id | ||
64 | } | ||
65 | } | ||
66 | |||
67 | impl Index<FileItemId> for FileItems { | ||
68 | type Output = SyntaxNode; | ||
69 | fn index(&self, idx: FileItemId) -> &SyntaxNode { | ||
70 | &self.arena[idx] | ||
71 | } | ||
72 | } | ||
73 | |||
74 | pub(crate) fn file_items(db: &impl DescriptorDatabase, file_id: FileId) -> Arc<FileItems> { | ||
75 | let source_file = db.file_syntax(file_id); | ||
76 | let source_file = source_file.borrowed(); | ||
77 | let mut res = FileItems::default(); | ||
78 | source_file | ||
79 | .syntax() | ||
80 | .descendants() | ||
81 | .filter_map(ast::ModuleItem::cast) | ||
82 | .map(|it| it.syntax().owned()) | ||
83 | .for_each(|it| { | ||
84 | res.alloc(it); | ||
85 | }); | ||
86 | Arc::new(res) | ||
87 | } | ||
88 | |||
89 | pub(crate) fn file_item( | ||
90 | db: &impl DescriptorDatabase, | ||
91 | file_id: FileId, | ||
92 | file_item_id: FileItemId, | ||
93 | ) -> SyntaxNode { | ||
94 | db._file_items(file_id)[file_item_id].clone() | ||
95 | } | ||
96 | |||
41 | /// Item map is the result of the name resolution. Item map contains, for each | 97 | /// Item map is the result of the name resolution. Item map contains, for each |
42 | /// module, the set of visible items. | 98 | /// module, the set of visible items. |
43 | #[derive(Default, Debug, PartialEq, Eq)] | 99 | #[derive(Default, Debug, PartialEq, Eq)] |
@@ -62,17 +118,44 @@ pub(crate) struct InputModuleItems { | |||
62 | imports: Vec<Import>, | 118 | imports: Vec<Import>, |
63 | } | 119 | } |
64 | 120 | ||
121 | #[derive(Debug, PartialEq, Eq)] | ||
122 | struct ModuleItem { | ||
123 | id: FileItemId, | ||
124 | name: SmolStr, | ||
125 | kind: SyntaxKind, | ||
126 | vis: Vis, | ||
127 | } | ||
128 | |||
129 | #[derive(Debug, PartialEq, Eq)] | ||
130 | enum Vis { | ||
131 | // Priv, | ||
132 | Other, | ||
133 | } | ||
134 | |||
65 | #[derive(Debug, Clone, PartialEq, Eq)] | 135 | #[derive(Debug, Clone, PartialEq, Eq)] |
66 | struct Import { | 136 | struct Import { |
67 | path: Path, | 137 | path: Path, |
68 | kind: ImportKind, | 138 | kind: ImportKind, |
69 | } | 139 | } |
70 | 140 | ||
141 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
142 | pub(crate) struct NamedImport { | ||
143 | file_item_id: FileItemId, | ||
144 | relative_range: TextRange, | ||
145 | } | ||
146 | |||
147 | impl NamedImport { | ||
148 | pub(crate) fn range(&self, db: &impl DescriptorDatabase, file_id: FileId) -> TextRange { | ||
149 | let syntax = db._file_item(file_id, self.file_item_id); | ||
150 | let offset = syntax.borrowed().range().start(); | ||
151 | self.relative_range + offset | ||
152 | } | ||
153 | } | ||
154 | |||
71 | #[derive(Debug, Clone, PartialEq, Eq)] | 155 | #[derive(Debug, Clone, PartialEq, Eq)] |
72 | enum ImportKind { | 156 | enum ImportKind { |
73 | Glob, | 157 | Glob, |
74 | // TODO: make offset independent | 158 | Named(NamedImport), |
75 | Named(LocalSyntaxPtr), | ||
76 | } | 159 | } |
77 | 160 | ||
78 | pub(crate) fn input_module_items( | 161 | pub(crate) fn input_module_items( |
@@ -82,10 +165,11 @@ pub(crate) fn input_module_items( | |||
82 | ) -> Cancelable<Arc<InputModuleItems>> { | 165 | ) -> Cancelable<Arc<InputModuleItems>> { |
83 | let module_tree = db._module_tree(source_root)?; | 166 | let module_tree = db._module_tree(source_root)?; |
84 | let source = module_id.source(&module_tree); | 167 | let source = module_id.source(&module_tree); |
168 | let file_items = db._file_items(source.file_id()); | ||
85 | let res = match source.resolve(db) { | 169 | let res = match source.resolve(db) { |
86 | ModuleSourceNode::SourceFile(it) => { | 170 | ModuleSourceNode::SourceFile(it) => { |
87 | let items = it.borrowed().items(); | 171 | let items = it.borrowed().items(); |
88 | InputModuleItems::new(items) | 172 | InputModuleItems::new(&file_items, items) |
89 | } | 173 | } |
90 | ModuleSourceNode::Module(it) => { | 174 | ModuleSourceNode::Module(it) => { |
91 | let items = it | 175 | let items = it |
@@ -93,7 +177,7 @@ pub(crate) fn input_module_items( | |||
93 | .item_list() | 177 | .item_list() |
94 | .into_iter() | 178 | .into_iter() |
95 | .flat_map(|it| it.items()); | 179 | .flat_map(|it| it.items()); |
96 | InputModuleItems::new(items) | 180 | InputModuleItems::new(&file_items, items) |
97 | } | 181 | } |
98 | }; | 182 | }; |
99 | Ok(Arc::new(res)) | 183 | Ok(Arc::new(res)) |
@@ -112,7 +196,6 @@ pub(crate) fn item_map( | |||
112 | Ok((id, items)) | 196 | Ok((id, items)) |
113 | }) | 197 | }) |
114 | .collect::<Cancelable<FxHashMap<_, _>>>()?; | 198 | .collect::<Cancelable<FxHashMap<_, _>>>()?; |
115 | |||
116 | let mut resolver = Resolver { | 199 | let mut resolver = Resolver { |
117 | db: db, | 200 | db: db, |
118 | input: &input, | 201 | input: &input, |
@@ -134,8 +217,7 @@ pub(crate) struct Resolution { | |||
134 | /// None for unresolved | 217 | /// None for unresolved |
135 | pub(crate) def_id: Option<DefId>, | 218 | pub(crate) def_id: Option<DefId>, |
136 | /// ident by whitch this is imported into local scope. | 219 | /// ident by whitch this is imported into local scope. |
137 | /// TODO: make this offset-independent. | 220 | pub(crate) import: Option<NamedImport>, |
138 | pub(crate) import_name: Option<LocalSyntaxPtr>, | ||
139 | } | 221 | } |
140 | 222 | ||
141 | // #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | 223 | // #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
@@ -150,55 +232,49 @@ pub(crate) struct Resolution { | |||
150 | // values: Option<T>, | 232 | // values: Option<T>, |
151 | // } | 233 | // } |
152 | 234 | ||
153 | #[derive(Debug, PartialEq, Eq)] | ||
154 | struct ModuleItem { | ||
155 | ptr: LocalSyntaxPtr, | ||
156 | name: SmolStr, | ||
157 | kind: SyntaxKind, | ||
158 | vis: Vis, | ||
159 | } | ||
160 | |||
161 | #[derive(Debug, PartialEq, Eq)] | ||
162 | enum Vis { | ||
163 | // Priv, | ||
164 | Other, | ||
165 | } | ||
166 | |||
167 | impl InputModuleItems { | 235 | impl InputModuleItems { |
168 | fn new<'a>(items: impl Iterator<Item = ast::ModuleItem<'a>>) -> InputModuleItems { | 236 | fn new<'a>( |
237 | file_items: &FileItems, | ||
238 | items: impl Iterator<Item = ast::ModuleItem<'a>>, | ||
239 | ) -> InputModuleItems { | ||
169 | let mut res = InputModuleItems::default(); | 240 | let mut res = InputModuleItems::default(); |
170 | for item in items { | 241 | for item in items { |
171 | res.add_item(item); | 242 | res.add_item(file_items, item); |
172 | } | 243 | } |
173 | res | 244 | res |
174 | } | 245 | } |
175 | 246 | ||
176 | fn add_item(&mut self, item: ast::ModuleItem) -> Option<()> { | 247 | fn add_item(&mut self, file_items: &FileItems, item: ast::ModuleItem) -> Option<()> { |
177 | match item { | 248 | match item { |
178 | ast::ModuleItem::StructDef(it) => self.items.push(ModuleItem::new(it)?), | 249 | ast::ModuleItem::StructDef(it) => self.items.push(ModuleItem::new(file_items, it)?), |
179 | ast::ModuleItem::EnumDef(it) => self.items.push(ModuleItem::new(it)?), | 250 | ast::ModuleItem::EnumDef(it) => self.items.push(ModuleItem::new(file_items, it)?), |
180 | ast::ModuleItem::FnDef(it) => self.items.push(ModuleItem::new(it)?), | 251 | ast::ModuleItem::FnDef(it) => self.items.push(ModuleItem::new(file_items, it)?), |
181 | ast::ModuleItem::TraitDef(it) => self.items.push(ModuleItem::new(it)?), | 252 | ast::ModuleItem::TraitDef(it) => self.items.push(ModuleItem::new(file_items, it)?), |
182 | ast::ModuleItem::TypeDef(it) => self.items.push(ModuleItem::new(it)?), | 253 | ast::ModuleItem::TypeDef(it) => self.items.push(ModuleItem::new(file_items, it)?), |
183 | ast::ModuleItem::ImplItem(_) => { | 254 | ast::ModuleItem::ImplItem(_) => { |
184 | // impls don't define items | 255 | // impls don't define items |
185 | } | 256 | } |
186 | ast::ModuleItem::UseItem(it) => self.add_use_item(it), | 257 | ast::ModuleItem::UseItem(it) => self.add_use_item(file_items, it), |
187 | ast::ModuleItem::ExternCrateItem(_) => { | 258 | ast::ModuleItem::ExternCrateItem(_) => { |
188 | // TODO | 259 | // TODO |
189 | } | 260 | } |
190 | ast::ModuleItem::ConstDef(it) => self.items.push(ModuleItem::new(it)?), | 261 | ast::ModuleItem::ConstDef(it) => self.items.push(ModuleItem::new(file_items, it)?), |
191 | ast::ModuleItem::StaticDef(it) => self.items.push(ModuleItem::new(it)?), | 262 | ast::ModuleItem::StaticDef(it) => self.items.push(ModuleItem::new(file_items, it)?), |
192 | ast::ModuleItem::Module(it) => self.items.push(ModuleItem::new(it)?), | 263 | ast::ModuleItem::Module(it) => self.items.push(ModuleItem::new(file_items, it)?), |
193 | } | 264 | } |
194 | Some(()) | 265 | Some(()) |
195 | } | 266 | } |
196 | 267 | ||
197 | fn add_use_item(&mut self, item: ast::UseItem) { | 268 | fn add_use_item(&mut self, file_items: &FileItems, item: ast::UseItem) { |
198 | Path::expand_use_item(item, |path, ptr| { | 269 | let file_item_id = file_items.id_of(item.syntax()); |
199 | let kind = match ptr { | 270 | let start_offset = item.syntax().range().start(); |
271 | Path::expand_use_item(item, |path, range| { | ||
272 | let kind = match range { | ||
200 | None => ImportKind::Glob, | 273 | None => ImportKind::Glob, |
201 | Some(ptr) => ImportKind::Named(ptr), | 274 | Some(range) => ImportKind::Named(NamedImport { |
275 | file_item_id, | ||
276 | relative_range: range - start_offset, | ||
277 | }), | ||
202 | }; | 278 | }; |
203 | self.imports.push(Import { kind, path }) | 279 | self.imports.push(Import { kind, path }) |
204 | }) | 280 | }) |
@@ -206,13 +282,13 @@ impl InputModuleItems { | |||
206 | } | 282 | } |
207 | 283 | ||
208 | impl ModuleItem { | 284 | impl ModuleItem { |
209 | fn new<'a>(item: impl ast::NameOwner<'a>) -> Option<ModuleItem> { | 285 | fn new<'a>(file_items: &FileItems, item: impl ast::NameOwner<'a>) -> Option<ModuleItem> { |
210 | let name = item.name()?.text(); | 286 | let name = item.name()?.text(); |
211 | let ptr = LocalSyntaxPtr::new(item.syntax()); | ||
212 | let kind = item.syntax().kind(); | 287 | let kind = item.syntax().kind(); |
213 | let vis = Vis::Other; | 288 | let vis = Vis::Other; |
289 | let id = file_items.id_of(item.syntax()); | ||
214 | let res = ModuleItem { | 290 | let res = ModuleItem { |
215 | ptr, | 291 | id, |
216 | name, | 292 | name, |
217 | kind, | 293 | kind, |
218 | vis, | 294 | vis, |
@@ -252,12 +328,12 @@ where | |||
252 | 328 | ||
253 | for import in input.imports.iter() { | 329 | for import in input.imports.iter() { |
254 | if let Some(name) = import.path.segments.iter().last() { | 330 | if let Some(name) = import.path.segments.iter().last() { |
255 | if let ImportKind::Named(ptr) = import.kind { | 331 | if let ImportKind::Named(import) = import.kind { |
256 | module_items.items.insert( | 332 | module_items.items.insert( |
257 | name.clone(), | 333 | name.clone(), |
258 | Resolution { | 334 | Resolution { |
259 | def_id: None, | 335 | def_id: None, |
260 | import_name: Some(ptr), | 336 | import: Some(import), |
261 | }, | 337 | }, |
262 | ); | 338 | ); |
263 | } | 339 | } |
@@ -269,12 +345,14 @@ where | |||
269 | // handle submodules separatelly | 345 | // handle submodules separatelly |
270 | continue; | 346 | continue; |
271 | } | 347 | } |
272 | let ptr = item.ptr.into_global(file_id); | 348 | let def_loc = DefLoc::Item { |
273 | let def_loc = DefLoc::Item { ptr }; | 349 | file_id, |
350 | id: item.id, | ||
351 | }; | ||
274 | let def_id = self.db.id_maps().def_id(def_loc); | 352 | let def_id = self.db.id_maps().def_id(def_loc); |
275 | let resolution = Resolution { | 353 | let resolution = Resolution { |
276 | def_id: Some(def_id), | 354 | def_id: Some(def_id), |
277 | import_name: None, | 355 | import: None, |
278 | }; | 356 | }; |
279 | module_items.items.insert(item.name.clone(), resolution); | 357 | module_items.items.insert(item.name.clone(), resolution); |
280 | } | 358 | } |
@@ -287,7 +365,7 @@ where | |||
287 | let def_id = self.db.id_maps().def_id(def_loc); | 365 | let def_id = self.db.id_maps().def_id(def_loc); |
288 | let resolution = Resolution { | 366 | let resolution = Resolution { |
289 | def_id: Some(def_id), | 367 | def_id: Some(def_id), |
290 | import_name: None, | 368 | import: None, |
291 | }; | 369 | }; |
292 | module_items.items.insert(name, resolution); | 370 | module_items.items.insert(name, resolution); |
293 | } | 371 | } |
@@ -341,7 +419,7 @@ where | |||
341 | self.update(module_id, |items| { | 419 | self.update(module_id, |items| { |
342 | let res = Resolution { | 420 | let res = Resolution { |
343 | def_id: Some(def_id), | 421 | def_id: Some(def_id), |
344 | import_name: Some(ptr), | 422 | import: Some(ptr), |
345 | }; | 423 | }; |
346 | items.items.insert(name.clone(), res); | 424 | items.items.insert(name.clone(), res); |
347 | }) | 425 | }) |
@@ -452,10 +530,11 @@ mod tests { | |||
452 | let events = db.log_executed(|| { | 530 | let events = db.log_executed(|| { |
453 | db._item_map(source_root).unwrap(); | 531 | db._item_map(source_root).unwrap(); |
454 | }); | 532 | }); |
455 | // assert!( | 533 | assert!( |
456 | // !format!("{:?}", events).contains("_item_map"), | 534 | !format!("{:?}", events).contains("_item_map"), |
457 | // "{:#?}", events | 535 | "{:#?}", |
458 | // ) | 536 | events |
537 | ) | ||
459 | } | 538 | } |
460 | } | 539 | } |
461 | } | 540 | } |