aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-05-21 17:29:31 +0100
committerGitHub <[email protected]>2021-05-21 17:29:31 +0100
commitde403b10448e23f232804596538de92fc57203d6 (patch)
treedcf8ccdfd09d282f14e5e5c24057496caaa3a4ff
parenteb08a27f1bd31cc15db4893dded60663effaf3f9 (diff)
parentd00bc9c2fc211650bf3d16b0e77fc7dac20f34c5 (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.rs13
-rw-r--r--crates/hir_def/src/item_tree/lower.rs49
-rw-r--r--crates/hir_def/src/nameres/collector.rs1
-rw-r--r--crates/hir_def/src/nameres/tests/macros.rs36
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
239struct ItemTreeData { 241struct 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 {
432mod_items! { 435mod_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)]
515pub 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)]
511pub struct Function { 522pub 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
878fn 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]
739fn unresolved_attrs_extern_block_hang() {
740 check(
741 r#"
742#[unresolved]
743extern "C" {
744 #[unresolved]
745 fn f();
746}
747 "#,
748 expect![[r#"
749 crate
750 f: v
751 "#]],
752 );
753}
754
755#[test]
756fn macros_in_extern_block() {
757 check(
758 r#"
759macro_rules! m {
760 () => { static S: u8; };
761}
762
763extern {
764 m!();
765}
766 "#,
767 expect![[r#"
768 crate
769 S: v
770 "#]],
771 );
772}
773
774#[test]
739fn resolves_derive_helper() { 775fn resolves_derive_helper() {
740 cov_mark::check!(resolved_derive_helper); 776 cov_mark::check!(resolved_derive_helper);
741 check( 777 check(