diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 469ed5b5e6b..0d0e757fca7 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -844,7 +844,7 @@ pub fn method_params(self, db: &dyn HirDatabase) -> Option> { } pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).is_unsafe + db.function_data(self.id).qualifier.is_unsafe } pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs index aea53d527e1..b09da06979d 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs @@ -9,7 +9,7 @@ attr::Attrs, body::Expander, db::DefDatabase, - item_tree::{AssocItem, ItemTreeId, ModItem}, + item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem}, type_ref::{TypeBound, TypeRef}, visibility::RawVisibility, AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, @@ -26,9 +26,9 @@ pub struct FunctionData { /// can be called as a method. pub has_self_param: bool, pub has_body: bool, - pub is_unsafe: bool, + pub qualifier: FunctionQualifier, + pub is_in_extern_block: bool, pub is_varargs: bool, - pub is_extern: bool, pub visibility: RawVisibility, } @@ -46,9 +46,9 @@ pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc]>, pub is_varargs: bool, pub ret_type: Idx, pub ast_id: FileAstId, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FunctionQualifier { + pub is_default: bool, + pub is_const: bool, + pub is_async: bool, + pub is_unsafe: bool, + pub abi: Option, +} + #[derive(Debug, Clone, Eq, PartialEq)] pub struct Struct { pub name: Name, diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 240fdacf94c..6b5438dc93d 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs @@ -391,14 +391,33 @@ fn lower_function(&mut self, func: &ast::Fn) -> Option> let has_body = func.body().is_some(); let ast_id = self.source_ast_id_map.ast_id(func); + let qualifier = FunctionQualifier { + is_default: func.default_token().is_some(), + is_const: func.const_token().is_some(), + is_async: func.async_token().is_some(), + is_unsafe: func.unsafe_token().is_some(), + abi: func.abi().map(|abi| { + // FIXME: Abi::abi() -> Option? + match abi.syntax().last_token() { + Some(tok) if tok.kind() == SyntaxKind::STRING => { + // FIXME: Better way to unescape? + tok.text().trim_matches('"').into() + } + _ => { + // `extern` default to be `extern "C"`. + "C".into() + } + } + }), + }; let mut res = Function { name, visibility, generic_params: GenericParamsId::EMPTY, has_self_param, has_body, - is_unsafe: func.unsafe_token().is_some(), - is_extern: false, + qualifier, + is_in_extern_block: false, params, is_varargs, ret_type, @@ -608,8 +627,8 @@ fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec { ast::ExternItem::Fn(ast) => { let func_id = self.lower_function(&ast)?; let func = &mut self.data().functions[func_id.index]; - func.is_unsafe = is_intrinsic_fn_unsafe(&func.name); - func.is_extern = true; + func.qualifier.is_unsafe = is_intrinsic_fn_unsafe(&func.name); + func.is_in_extern_block = true; func_id.into() } ast::ExternItem::Static(ast) => { diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs index 3605ca5816c..982ad5b9e00 100644 --- a/crates/hir_ty/src/diagnostics/decl_check.rs +++ b/crates/hir_ty/src/diagnostics/decl_check.rs @@ -91,7 +91,7 @@ fn allowed(&self, id: AttrDefId, allow_name: &str) -> bool { fn validate_func(&mut self, func: FunctionId) { let data = self.db.function_data(func); - if data.is_extern { + if data.is_in_extern_block { cov_mark::hit!(extern_func_incorrect_case_ignored); return; } diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs index 20bb6482796..44a7e550647 100644 --- a/crates/hir_ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs @@ -32,7 +32,7 @@ pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) { let def = self.owner.into(); let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); let is_unsafe = match self.owner { - DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe, + DefWithBodyId::FunctionId(it) => db.function_data(it).qualifier.is_unsafe, DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false, }; if is_unsafe @@ -86,7 +86,7 @@ fn walk_unsafe( match expr { &Expr::Call { callee, .. } => { if let Some(func) = infer[callee].as_fn_def(db) { - if db.function_data(func).is_unsafe { + if db.function_data(func).qualifier.is_unsafe { unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); } } @@ -103,7 +103,7 @@ fn walk_unsafe( Expr::MethodCall { .. } => { if infer .method_resolution(current) - .map(|func| db.function_data(func).is_unsafe) + .map(|func| db.function_data(func).qualifier.is_unsafe) .unwrap_or(false) { unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });