aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-01-08 22:57:40 +0000
committerAleksey Kladov <[email protected]>2019-01-08 22:57:40 +0000
commit5609989368e5cd5137e8860b7a78859b98e89085 (patch)
tree55b931a5fdd3f65734bbc7a46bc23b92161adf66 /crates
parent2dc85619beaa3cd9fc47bb8ac1791820691e1205 (diff)
more stable DefIds via bfs tree walking
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/ids.rs21
-rw-r--r--crates/ra_hir/src/nameres/tests.rs17
2 files changed, 31 insertions, 7 deletions
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 3db757778..8ac49eba3 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -253,13 +253,17 @@ impl SourceFileItems {
253 } 253 }
254 254
255 fn init(&mut self, source_file: &SourceFile) { 255 fn init(&mut self, source_file: &SourceFile) {
256 source_file.syntax().descendants().for_each(|it| { 256 // By walking the tree in bread-first order we make sure that parents
257 // get lower ids then children. That is, addding a new child does not
258 // change parent's id. This means that, say, adding a new function to a
259 // trait does not chage ids of top-level items, which helps caching.
260 bfs(source_file.syntax(), |it| {
257 if let Some(module_item) = ast::ModuleItem::cast(it) { 261 if let Some(module_item) = ast::ModuleItem::cast(it) {
258 self.alloc(module_item.syntax().to_owned()); 262 self.alloc(module_item.syntax().to_owned());
259 } else if let Some(macro_call) = ast::MacroCall::cast(it) { 263 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
260 self.alloc(macro_call.syntax().to_owned()); 264 self.alloc(macro_call.syntax().to_owned());
261 } 265 }
262 }); 266 })
263 } 267 }
264 268
265 fn alloc(&mut self, item: TreePtr<SyntaxNode>) -> SourceFileItemId { 269 fn alloc(&mut self, item: TreePtr<SyntaxNode>) -> SourceFileItemId {
@@ -305,3 +309,16 @@ impl std::ops::Index<SourceFileItemId> for SourceFileItems {
305 &self.arena[idx] 309 &self.arena[idx]
306 } 310 }
307} 311}
312
313/// Walks the subtree in bfs order, calling `f` for each node.
314fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) {
315 let mut curr_layer = vec![node];
316 let mut next_layer = vec![];
317 while !curr_layer.is_empty() {
318 curr_layer.drain(..).for_each(|node| {
319 next_layer.extend(node.children());
320 f(node);
321 });
322 std::mem::swap(&mut curr_layer, &mut next_layer);
323 }
324}
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index a19a6fe51..17de54b44 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -368,7 +368,7 @@ fn typing_inside_a_function_should_not_invalidate_item_map() {
368 mod foo; 368 mod foo;
369 369
370 use crate::foo::bar::Baz; 370 use crate::foo::bar::Baz;
371{ 371
372 fn foo() -> i32 { 92 } 372 fn foo() -> i32 { 92 }
373 ", 373 ",
374 ); 374 );
@@ -380,12 +380,15 @@ fn adding_inner_items_should_not_invalidate_item_map() {
380 " 380 "
381 //- /lib.rs 381 //- /lib.rs
382 struct S { a: i32} 382 struct S { a: i32}
383 mod foo;<|>
384 enum E { A } 383 enum E { A }
385 use crate::foo::bar::Baz;
386 trait T { 384 trait T {
387 fn a() {} 385 fn a() {}
388 } 386 }
387 mod foo;<|>
388 impl S {
389 fn a() {}
390 }
391 use crate::foo::bar::Baz;
389 //- /foo/mod.rs 392 //- /foo/mod.rs
390 pub mod bar; 393 pub mod bar;
391 394
@@ -394,13 +397,17 @@ fn adding_inner_items_should_not_invalidate_item_map() {
394 ", 397 ",
395 " 398 "
396 struct S { a: i32, b: () } 399 struct S { a: i32, b: () }
397 mod foo;<|>
398 enum E { A, B } 400 enum E { A, B }
399 use crate::foo::bar::Baz;
400 trait T { 401 trait T {
401 fn a() {} 402 fn a() {}
402 fn b() {} 403 fn b() {}
403 } 404 }
405 mod foo;<|>
406 impl S {
407 fn a() {}
408 fn b() {}
409 }
410 use crate::foo::bar::Baz;
404 ", 411 ",
405 ); 412 );
406} 413}