diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-05-21 17:29:31 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-05-21 17:29:31 +0100 |
commit | de403b10448e23f232804596538de92fc57203d6 (patch) | |
tree | dcf8ccdfd09d282f14e5e5c24057496caaa3a4ff | |
parent | eb08a27f1bd31cc15db4893dded60663effaf3f9 (diff) | |
parent | d00bc9c2fc211650bf3d16b0e77fc7dac20f34c5 (diff) |
Merge #8910
8910: Don't lower extern block in the ItemTree r=jonas-schievink a=jonas-schievink
The ItemTree lowering code used to attach attributes on an `extern {}` block to all the children. This is wrong and causes problems with attribute resolution that manifested as a hang.
This PR treats extern blocks as first-class items in the ItemTree and lowers its contents in the `ModCollector` instead.
Fixes https://github.com/rust-analyzer/rust-analyzer/issues/8414#issuecomment-845607923
Fixes https://github.com/rust-analyzer/rust-analyzer/issues/8905
Fixes https://github.com/rust-analyzer/rust-analyzer/issues/8909
bors r+
Co-authored-by: Jonas Schievink <[email protected]>
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 13 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree/lower.rs | 49 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 1 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/macros.rs | 36 |
4 files changed, 79 insertions, 20 deletions
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index cad8a7479..797b905d1 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -132,6 +132,7 @@ impl ItemTree { | |||
132 | let ItemTreeData { | 132 | let ItemTreeData { |
133 | imports, | 133 | imports, |
134 | extern_crates, | 134 | extern_crates, |
135 | extern_blocks, | ||
135 | functions, | 136 | functions, |
136 | params, | 137 | params, |
137 | structs, | 138 | structs, |
@@ -154,6 +155,7 @@ impl ItemTree { | |||
154 | 155 | ||
155 | imports.shrink_to_fit(); | 156 | imports.shrink_to_fit(); |
156 | extern_crates.shrink_to_fit(); | 157 | extern_crates.shrink_to_fit(); |
158 | extern_blocks.shrink_to_fit(); | ||
157 | functions.shrink_to_fit(); | 159 | functions.shrink_to_fit(); |
158 | params.shrink_to_fit(); | 160 | params.shrink_to_fit(); |
159 | structs.shrink_to_fit(); | 161 | structs.shrink_to_fit(); |
@@ -239,6 +241,7 @@ static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(P | |||
239 | struct ItemTreeData { | 241 | struct ItemTreeData { |
240 | imports: Arena<Import>, | 242 | imports: Arena<Import>, |
241 | extern_crates: Arena<ExternCrate>, | 243 | extern_crates: Arena<ExternCrate>, |
244 | extern_blocks: Arena<ExternBlock>, | ||
242 | functions: Arena<Function>, | 245 | functions: Arena<Function>, |
243 | params: Arena<Param>, | 246 | params: Arena<Param>, |
244 | structs: Arena<Struct>, | 247 | structs: Arena<Struct>, |
@@ -432,6 +435,7 @@ macro_rules! mod_items { | |||
432 | mod_items! { | 435 | mod_items! { |
433 | Import in imports -> ast::Use, | 436 | Import in imports -> ast::Use, |
434 | ExternCrate in extern_crates -> ast::ExternCrate, | 437 | ExternCrate in extern_crates -> ast::ExternCrate, |
438 | ExternBlock in extern_blocks -> ast::ExternBlock, | ||
435 | Function in functions -> ast::Fn, | 439 | Function in functions -> ast::Fn, |
436 | Struct in structs -> ast::Struct, | 440 | Struct in structs -> ast::Struct, |
437 | Union in unions -> ast::Union, | 441 | Union in unions -> ast::Union, |
@@ -508,6 +512,13 @@ pub struct ExternCrate { | |||
508 | } | 512 | } |
509 | 513 | ||
510 | #[derive(Debug, Clone, Eq, PartialEq)] | 514 | #[derive(Debug, Clone, Eq, PartialEq)] |
515 | pub struct ExternBlock { | ||
516 | pub abi: Option<Interned<str>>, | ||
517 | pub ast_id: FileAstId<ast::ExternBlock>, | ||
518 | pub children: Box<[ModItem]>, | ||
519 | } | ||
520 | |||
521 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
511 | pub struct Function { | 522 | pub struct Function { |
512 | pub name: Name, | 523 | pub name: Name, |
513 | pub visibility: RawVisibilityId, | 524 | pub visibility: RawVisibilityId, |
@@ -691,6 +702,7 @@ impl ModItem { | |||
691 | match self { | 702 | match self { |
692 | ModItem::Import(_) | 703 | ModItem::Import(_) |
693 | | ModItem::ExternCrate(_) | 704 | | ModItem::ExternCrate(_) |
705 | | ModItem::ExternBlock(_) | ||
694 | | ModItem::Struct(_) | 706 | | ModItem::Struct(_) |
695 | | ModItem::Union(_) | 707 | | ModItem::Union(_) |
696 | | ModItem::Enum(_) | 708 | | ModItem::Enum(_) |
@@ -715,6 +727,7 @@ impl ModItem { | |||
715 | match self { | 727 | match self { |
716 | ModItem::Import(it) => tree[it.index].ast_id().upcast(), | 728 | ModItem::Import(it) => tree[it.index].ast_id().upcast(), |
717 | ModItem::ExternCrate(it) => tree[it.index].ast_id().upcast(), | 729 | ModItem::ExternCrate(it) => tree[it.index].ast_id().upcast(), |
730 | ModItem::ExternBlock(it) => tree[it.index].ast_id().upcast(), | ||
718 | ModItem::Function(it) => tree[it.index].ast_id().upcast(), | 731 | ModItem::Function(it) => tree[it.index].ast_id().upcast(), |
719 | ModItem::Struct(it) => tree[it.index].ast_id().upcast(), | 732 | ModItem::Struct(it) => tree[it.index].ast_id().upcast(), |
720 | ModItem::Union(it) => tree[it.index].ast_id().upcast(), | 733 | ModItem::Union(it) => tree[it.index].ast_id().upcast(), |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index fe348091d..a7ffc6364 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -147,9 +147,7 @@ impl<'a> Ctx<'a> { | |||
147 | ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), | 147 | ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), |
148 | ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into), | 148 | ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into), |
149 | ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into), | 149 | ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into), |
150 | ast::Item::ExternBlock(ast) => { | 150 | ast::Item::ExternBlock(ast) => Some(self.lower_extern_block(ast).into()), |
151 | Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>())) | ||
152 | } | ||
153 | }; | 151 | }; |
154 | 152 | ||
155 | if !attrs.is_empty() { | 153 | if !attrs.is_empty() { |
@@ -397,19 +395,7 @@ impl<'a> Ctx<'a> { | |||
397 | ret_type | 395 | ret_type |
398 | }; | 396 | }; |
399 | 397 | ||
400 | let abi = func.abi().map(|abi| { | 398 | let abi = func.abi().map(lower_abi); |
401 | // FIXME: Abi::abi() -> Option<SyntaxToken>? | ||
402 | match abi.syntax().last_token() { | ||
403 | Some(tok) if tok.kind() == SyntaxKind::STRING => { | ||
404 | // FIXME: Better way to unescape? | ||
405 | Interned::new_str(tok.text().trim_matches('"')) | ||
406 | } | ||
407 | _ => { | ||
408 | // `extern` default to be `extern "C"`. | ||
409 | Interned::new_str("C") | ||
410 | } | ||
411 | } | ||
412 | }); | ||
413 | 399 | ||
414 | let ast_id = self.source_ast_id_map.ast_id(func); | 400 | let ast_id = self.source_ast_id_map.ast_id(func); |
415 | 401 | ||
@@ -647,8 +633,10 @@ impl<'a> Ctx<'a> { | |||
647 | Some(id(self.data().macro_defs.alloc(res))) | 633 | Some(id(self.data().macro_defs.alloc(res))) |
648 | } | 634 | } |
649 | 635 | ||
650 | fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> { | 636 | fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> FileItemTreeId<ExternBlock> { |
651 | block.extern_item_list().map_or(Vec::new(), |list| { | 637 | let ast_id = self.source_ast_id_map.ast_id(block); |
638 | let abi = block.abi().map(lower_abi); | ||
639 | let children: Box<[_]> = block.extern_item_list().map_or(Box::new([]), |list| { | ||
652 | list.extern_items() | 640 | list.extern_items() |
653 | .filter_map(|item| { | 641 | .filter_map(|item| { |
654 | self.collect_inner_items(item.syntax()); | 642 | self.collect_inner_items(item.syntax()); |
@@ -673,13 +661,20 @@ impl<'a> Ctx<'a> { | |||
673 | self.data().type_aliases[foreign_ty.index].is_extern = true; | 661 | self.data().type_aliases[foreign_ty.index].is_extern = true; |
674 | foreign_ty.into() | 662 | foreign_ty.into() |
675 | } | 663 | } |
676 | ast::ExternItem::MacroCall(_) => return None, | 664 | ast::ExternItem::MacroCall(call) => { |
665 | // FIXME: we need some way of tracking that the macro call is in an | ||
666 | // extern block | ||
667 | self.lower_macro_call(&call)?.into() | ||
668 | } | ||
677 | }; | 669 | }; |
678 | self.add_attrs(id.into(), attrs); | 670 | self.add_attrs(id.into(), attrs); |
679 | Some(id) | 671 | Some(id) |
680 | }) | 672 | }) |
681 | .collect() | 673 | .collect() |
682 | }) | 674 | }); |
675 | |||
676 | let res = ExternBlock { abi, ast_id, children }; | ||
677 | id(self.data().extern_blocks.alloc(res)) | ||
683 | } | 678 | } |
684 | 679 | ||
685 | /// Lowers generics defined on `node` and collects inner items defined within. | 680 | /// Lowers generics defined on `node` and collects inner items defined within. |
@@ -879,3 +874,17 @@ fn is_intrinsic_fn_unsafe(name: &Name) -> bool { | |||
879 | ] | 874 | ] |
880 | .contains(&name) | 875 | .contains(&name) |
881 | } | 876 | } |
877 | |||
878 | fn lower_abi(abi: ast::Abi) -> Interned<str> { | ||
879 | // FIXME: Abi::abi() -> Option<SyntaxToken>? | ||
880 | match abi.syntax().last_token() { | ||
881 | Some(tok) if tok.kind() == SyntaxKind::STRING => { | ||
882 | // FIXME: Better way to unescape? | ||
883 | Interned::new_str(tok.text().trim_matches('"')) | ||
884 | } | ||
885 | _ => { | ||
886 | // `extern` default to be `extern "C"`. | ||
887 | Interned::new_str("C") | ||
888 | } | ||
889 | } | ||
890 | } | ||
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index e76d039b8..fa4b135fd 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -1243,6 +1243,7 @@ impl ModCollector<'_, '_> { | |||
1243 | status: PartialResolvedImport::Unresolved, | 1243 | status: PartialResolvedImport::Unresolved, |
1244 | }) | 1244 | }) |
1245 | } | 1245 | } |
1246 | ModItem::ExternBlock(block) => self.collect(&self.item_tree[block].children), | ||
1246 | ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]), | 1247 | ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]), |
1247 | ModItem::MacroRules(id) => self.collect_macro_rules(id), | 1248 | ModItem::MacroRules(id) => self.collect_macro_rules(id), |
1248 | ModItem::MacroDef(id) => self.collect_macro_def(id), | 1249 | ModItem::MacroDef(id) => self.collect_macro_def(id), |
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs index 04de107f5..133b2d818 100644 --- a/crates/hir_def/src/nameres/tests/macros.rs +++ b/crates/hir_def/src/nameres/tests/macros.rs | |||
@@ -736,6 +736,42 @@ fn unresolved_attributes_fall_back_track_per_file_moditems() { | |||
736 | } | 736 | } |
737 | 737 | ||
738 | #[test] | 738 | #[test] |
739 | fn unresolved_attrs_extern_block_hang() { | ||
740 | check( | ||
741 | r#" | ||
742 | #[unresolved] | ||
743 | extern "C" { | ||
744 | #[unresolved] | ||
745 | fn f(); | ||
746 | } | ||
747 | "#, | ||
748 | expect![[r#" | ||
749 | crate | ||
750 | f: v | ||
751 | "#]], | ||
752 | ); | ||
753 | } | ||
754 | |||
755 | #[test] | ||
756 | fn macros_in_extern_block() { | ||
757 | check( | ||
758 | r#" | ||
759 | macro_rules! m { | ||
760 | () => { static S: u8; }; | ||
761 | } | ||
762 | |||
763 | extern { | ||
764 | m!(); | ||
765 | } | ||
766 | "#, | ||
767 | expect![[r#" | ||
768 | crate | ||
769 | S: v | ||
770 | "#]], | ||
771 | ); | ||
772 | } | ||
773 | |||
774 | #[test] | ||
739 | fn resolves_derive_helper() { | 775 | fn resolves_derive_helper() { |
740 | cov_mark::check!(resolved_derive_helper); | 776 | cov_mark::check!(resolved_derive_helper); |
741 | check( | 777 | check( |