Introduce FunctionQualifier for hir::FunctionData

This commit is contained in:
oxalica 2021-03-14 18:00:11 +08:00
parent b9c172a977
commit 2bb8956a10
No known key found for this signature in database
GPG Key ID: CED392DE0C483D00
6 changed files with 45 additions and 17 deletions

View File

@ -844,7 +844,7 @@ impl Function {
} }
pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { 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) { pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {

View File

@ -9,7 +9,7 @@ use crate::{
attr::Attrs, attr::Attrs,
body::Expander, body::Expander,
db::DefDatabase, db::DefDatabase,
item_tree::{AssocItem, ItemTreeId, ModItem}, item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem},
type_ref::{TypeBound, TypeRef}, type_ref::{TypeBound, TypeRef},
visibility::RawVisibility, visibility::RawVisibility,
AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
@ -26,9 +26,9 @@ pub struct FunctionData {
/// can be called as a method. /// can be called as a method.
pub has_self_param: bool, pub has_self_param: bool,
pub has_body: bool, pub has_body: bool,
pub is_unsafe: bool, pub qualifier: FunctionQualifier,
pub is_in_extern_block: bool,
pub is_varargs: bool, pub is_varargs: bool,
pub is_extern: bool,
pub visibility: RawVisibility, pub visibility: RawVisibility,
} }
@ -46,9 +46,9 @@ impl FunctionData {
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
has_self_param: func.has_self_param, has_self_param: func.has_self_param,
has_body: func.has_body, has_body: func.has_body,
is_unsafe: func.is_unsafe, qualifier: func.qualifier.clone(),
is_in_extern_block: func.is_in_extern_block,
is_varargs: func.is_varargs, is_varargs: func.is_varargs,
is_extern: func.is_extern,
visibility: item_tree[func.visibility].clone(), visibility: item_tree[func.visibility].clone(),
}) })
} }

View File

@ -24,7 +24,7 @@ use la_arena::{Arena, Idx, RawIdx};
use profile::Count; use profile::Count;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use smallvec::SmallVec; use smallvec::SmallVec;
use syntax::{ast, match_ast, SyntaxKind}; use syntax::{ast, match_ast, SmolStr, SyntaxKind};
use crate::{ use crate::{
attr::{Attrs, RawAttrs}, attr::{Attrs, RawAttrs},
@ -551,16 +551,25 @@ pub struct Function {
pub generic_params: GenericParamsId, pub generic_params: GenericParamsId,
pub has_self_param: bool, pub has_self_param: bool,
pub has_body: bool, pub has_body: bool,
pub is_unsafe: bool, pub qualifier: FunctionQualifier,
/// Whether the function is located in an `extern` block (*not* whether it is an /// Whether the function is located in an `extern` block (*not* whether it is an
/// `extern "abi" fn`). /// `extern "abi" fn`).
pub is_extern: bool, pub is_in_extern_block: bool,
pub params: Box<[Idx<TypeRef>]>, pub params: Box<[Idx<TypeRef>]>,
pub is_varargs: bool, pub is_varargs: bool,
pub ret_type: Idx<TypeRef>, pub ret_type: Idx<TypeRef>,
pub ast_id: FileAstId<ast::Fn>, pub ast_id: FileAstId<ast::Fn>,
} }
#[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<SmolStr>,
}
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct Struct { pub struct Struct {
pub name: Name, pub name: Name,

View File

@ -391,14 +391,33 @@ impl Ctx {
let has_body = func.body().is_some(); let has_body = func.body().is_some();
let ast_id = self.source_ast_id_map.ast_id(func); 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<SyntaxToken>?
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 { let mut res = Function {
name, name,
visibility, visibility,
generic_params: GenericParamsId::EMPTY, generic_params: GenericParamsId::EMPTY,
has_self_param, has_self_param,
has_body, has_body,
is_unsafe: func.unsafe_token().is_some(), qualifier,
is_extern: false, is_in_extern_block: false,
params, params,
is_varargs, is_varargs,
ret_type, ret_type,
@ -608,8 +627,8 @@ impl Ctx {
ast::ExternItem::Fn(ast) => { ast::ExternItem::Fn(ast) => {
let func_id = self.lower_function(&ast)?; let func_id = self.lower_function(&ast)?;
let func = &mut self.data().functions[func_id.index]; let func = &mut self.data().functions[func_id.index];
func.is_unsafe = is_intrinsic_fn_unsafe(&func.name); func.qualifier.is_unsafe = is_intrinsic_fn_unsafe(&func.name);
func.is_extern = true; func.is_in_extern_block = true;
func_id.into() func_id.into()
} }
ast::ExternItem::Static(ast) => { ast::ExternItem::Static(ast) => {

View File

@ -91,7 +91,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
fn validate_func(&mut self, func: FunctionId) { fn validate_func(&mut self, func: FunctionId) {
let data = self.db.function_data(func); 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); cov_mark::hit!(extern_func_incorrect_case_ignored);
return; return;
} }

View File

@ -32,7 +32,7 @@ impl<'a, 'b> UnsafeValidator<'a, 'b> {
let def = self.owner.into(); let def = self.owner.into();
let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def);
let is_unsafe = match self.owner { 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, DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
}; };
if is_unsafe if is_unsafe
@ -86,7 +86,7 @@ fn walk_unsafe(
match expr { match expr {
&Expr::Call { callee, .. } => { &Expr::Call { callee, .. } => {
if let Some(func) = infer[callee].as_fn_def(db) { 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 }); unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
} }
} }
@ -103,7 +103,7 @@ fn walk_unsafe(
Expr::MethodCall { .. } => { Expr::MethodCall { .. } => {
if infer if infer
.method_resolution(current) .method_resolution(current)
.map(|func| db.function_data(func).is_unsafe) .map(|func| db.function_data(func).qualifier.is_unsafe)
.unwrap_or(false) .unwrap_or(false)
{ {
unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });