Don't lower extern block in the ItemTree

This commit is contained in:
Jonas Schievink 2021-05-21 18:27:25 +02:00
parent eb08a27f1b
commit d00bc9c2fc
4 changed files with 79 additions and 20 deletions

View File

@ -132,6 +132,7 @@ fn shrink_to_fit(&mut self) {
let ItemTreeData { let ItemTreeData {
imports, imports,
extern_crates, extern_crates,
extern_blocks,
functions, functions,
params, params,
structs, structs,
@ -154,6 +155,7 @@ fn shrink_to_fit(&mut self) {
imports.shrink_to_fit(); imports.shrink_to_fit();
extern_crates.shrink_to_fit(); extern_crates.shrink_to_fit();
extern_blocks.shrink_to_fit();
functions.shrink_to_fit(); functions.shrink_to_fit();
params.shrink_to_fit(); params.shrink_to_fit();
structs.shrink_to_fit(); structs.shrink_to_fit();
@ -239,6 +241,7 @@ fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId {
struct ItemTreeData { struct ItemTreeData {
imports: Arena<Import>, imports: Arena<Import>,
extern_crates: Arena<ExternCrate>, extern_crates: Arena<ExternCrate>,
extern_blocks: Arena<ExternBlock>,
functions: Arena<Function>, functions: Arena<Function>,
params: Arena<Param>, params: Arena<Param>,
structs: Arena<Struct>, structs: Arena<Struct>,
@ -432,6 +435,7 @@ fn index(&self, index: Idx<$typ>) -> &Self::Output {
mod_items! { mod_items! {
Import in imports -> ast::Use, Import in imports -> ast::Use,
ExternCrate in extern_crates -> ast::ExternCrate, ExternCrate in extern_crates -> ast::ExternCrate,
ExternBlock in extern_blocks -> ast::ExternBlock,
Function in functions -> ast::Fn, Function in functions -> ast::Fn,
Struct in structs -> ast::Struct, Struct in structs -> ast::Struct,
Union in unions -> ast::Union, Union in unions -> ast::Union,
@ -507,6 +511,13 @@ pub struct ExternCrate {
pub ast_id: FileAstId<ast::ExternCrate>, pub ast_id: FileAstId<ast::ExternCrate>,
} }
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ExternBlock {
pub abi: Option<Interned<str>>,
pub ast_id: FileAstId<ast::ExternBlock>,
pub children: Box<[ModItem]>,
}
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct Function { pub struct Function {
pub name: Name, pub name: Name,
@ -691,6 +702,7 @@ pub fn as_assoc_item(&self) -> Option<AssocItem> {
match self { match self {
ModItem::Import(_) ModItem::Import(_)
| ModItem::ExternCrate(_) | ModItem::ExternCrate(_)
| ModItem::ExternBlock(_)
| ModItem::Struct(_) | ModItem::Struct(_)
| ModItem::Union(_) | ModItem::Union(_)
| ModItem::Enum(_) | ModItem::Enum(_)
@ -715,6 +727,7 @@ pub fn ast_id(&self, tree: &ItemTree) -> FileAstId<ast::Item> {
match self { match self {
ModItem::Import(it) => tree[it.index].ast_id().upcast(), ModItem::Import(it) => tree[it.index].ast_id().upcast(),
ModItem::ExternCrate(it) => tree[it.index].ast_id().upcast(), ModItem::ExternCrate(it) => tree[it.index].ast_id().upcast(),
ModItem::ExternBlock(it) => tree[it.index].ast_id().upcast(),
ModItem::Function(it) => tree[it.index].ast_id().upcast(), ModItem::Function(it) => tree[it.index].ast_id().upcast(),
ModItem::Struct(it) => tree[it.index].ast_id().upcast(), ModItem::Struct(it) => tree[it.index].ast_id().upcast(),
ModItem::Union(it) => tree[it.index].ast_id().upcast(), ModItem::Union(it) => tree[it.index].ast_id().upcast(),

View File

@ -147,9 +147,7 @@ fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItems>
ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into), ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into),
ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into), ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into),
ast::Item::ExternBlock(ast) => { ast::Item::ExternBlock(ast) => Some(self.lower_extern_block(ast).into()),
Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
}
}; };
if !attrs.is_empty() { if !attrs.is_empty() {
@ -397,19 +395,7 @@ fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>>
ret_type ret_type
}; };
let abi = func.abi().map(|abi| { let abi = func.abi().map(lower_abi);
// FIXME: Abi::abi() -> Option<SyntaxToken>?
match abi.syntax().last_token() {
Some(tok) if tok.kind() == SyntaxKind::STRING => {
// FIXME: Better way to unescape?
Interned::new_str(tok.text().trim_matches('"'))
}
_ => {
// `extern` default to be `extern "C"`.
Interned::new_str("C")
}
}
});
let ast_id = self.source_ast_id_map.ast_id(func); let ast_id = self.source_ast_id_map.ast_id(func);
@ -647,8 +633,10 @@ fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option<FileItemTreeId<MacroD
Some(id(self.data().macro_defs.alloc(res))) Some(id(self.data().macro_defs.alloc(res)))
} }
fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> { fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> FileItemTreeId<ExternBlock> {
block.extern_item_list().map_or(Vec::new(), |list| { let ast_id = self.source_ast_id_map.ast_id(block);
let abi = block.abi().map(lower_abi);
let children: Box<[_]> = block.extern_item_list().map_or(Box::new([]), |list| {
list.extern_items() list.extern_items()
.filter_map(|item| { .filter_map(|item| {
self.collect_inner_items(item.syntax()); self.collect_inner_items(item.syntax());
@ -673,13 +661,20 @@ fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> {
self.data().type_aliases[foreign_ty.index].is_extern = true; self.data().type_aliases[foreign_ty.index].is_extern = true;
foreign_ty.into() foreign_ty.into()
} }
ast::ExternItem::MacroCall(_) => return None, ast::ExternItem::MacroCall(call) => {
// FIXME: we need some way of tracking that the macro call is in an
// extern block
self.lower_macro_call(&call)?.into()
}
}; };
self.add_attrs(id.into(), attrs); self.add_attrs(id.into(), attrs);
Some(id) Some(id)
}) })
.collect() .collect()
}) });
let res = ExternBlock { abi, ast_id, children };
id(self.data().extern_blocks.alloc(res))
} }
/// Lowers generics defined on `node` and collects inner items defined within. /// Lowers generics defined on `node` and collects inner items defined within.
@ -879,3 +874,17 @@ fn is_intrinsic_fn_unsafe(name: &Name) -> bool {
] ]
.contains(&name) .contains(&name)
} }
fn lower_abi(abi: ast::Abi) -> Interned<str> {
// FIXME: Abi::abi() -> Option<SyntaxToken>?
match abi.syntax().last_token() {
Some(tok) if tok.kind() == SyntaxKind::STRING => {
// FIXME: Better way to unescape?
Interned::new_str(tok.text().trim_matches('"'))
}
_ => {
// `extern` default to be `extern "C"`.
Interned::new_str("C")
}
}
}

View File

@ -1243,6 +1243,7 @@ fn collect(&mut self, items: &[ModItem]) {
status: PartialResolvedImport::Unresolved, status: PartialResolvedImport::Unresolved,
}) })
} }
ModItem::ExternBlock(block) => self.collect(&self.item_tree[block].children),
ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]), ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]),
ModItem::MacroRules(id) => self.collect_macro_rules(id), ModItem::MacroRules(id) => self.collect_macro_rules(id),
ModItem::MacroDef(id) => self.collect_macro_def(id), ModItem::MacroDef(id) => self.collect_macro_def(id),

View File

@ -735,6 +735,42 @@ fn unresolved_attributes_fall_back_track_per_file_moditems() {
); );
} }
#[test]
fn unresolved_attrs_extern_block_hang() {
check(
r#"
#[unresolved]
extern "C" {
#[unresolved]
fn f();
}
"#,
expect![[r#"
crate
f: v
"#]],
);
}
#[test]
fn macros_in_extern_block() {
check(
r#"
macro_rules! m {
() => { static S: u8; };
}
extern {
m!();
}
"#,
expect![[r#"
crate
S: v
"#]],
);
}
#[test] #[test]
fn resolves_derive_helper() { fn resolves_derive_helper() {
cov_mark::check!(resolved_derive_helper); cov_mark::check!(resolved_derive_helper);