aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/Cargo.toml1
-rw-r--r--crates/hir_def/src/data.rs57
-rw-r--r--crates/hir_def/src/item_tree.rs31
-rw-r--r--crates/hir_def/src/item_tree/lower.rs66
4 files changed, 102 insertions, 53 deletions
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml
index 43324d8d9..60adb655c 100644
--- a/crates/hir_def/Cargo.toml
+++ b/crates/hir_def/Cargo.toml
@@ -10,6 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13bitflags = "1.2.1"
13cov-mark = { version = "1.1", features = ["thread-local"] } 14cov-mark = { version = "1.1", features = ["thread-local"] }
14dashmap = { version = "4.0.2", features = ["raw-api"] } 15dashmap = { version = "4.0.2", features = ["raw-api"] }
15log = "0.4.8" 16log = "0.4.8"
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index 31f994681..b409fb45c 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -10,7 +10,7 @@ use crate::{
10 body::Expander, 10 body::Expander,
11 db::DefDatabase, 11 db::DefDatabase,
12 intern::Interned, 12 intern::Interned,
13 item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param}, 13 item_tree::{AssocItem, FnFlags, ItemTreeId, ModItem, Param},
14 type_ref::{TraitRef, TypeBound, TypeRef}, 14 type_ref::{TraitRef, TypeBound, TypeRef},
15 visibility::RawVisibility, 15 visibility::RawVisibility,
16 AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, 16 AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
@@ -23,14 +23,9 @@ pub struct FunctionData {
23 pub params: Vec<Interned<TypeRef>>, 23 pub params: Vec<Interned<TypeRef>>,
24 pub ret_type: Interned<TypeRef>, 24 pub ret_type: Interned<TypeRef>,
25 pub attrs: Attrs, 25 pub attrs: Attrs,
26 /// True if the first param is `self`. This is relevant to decide whether this
27 /// can be called as a method.
28 pub has_self_param: bool,
29 pub has_body: bool,
30 pub qualifier: FunctionQualifier,
31 pub is_in_extern_block: bool,
32 pub is_varargs: bool,
33 pub visibility: RawVisibility, 26 pub visibility: RawVisibility,
27 pub abi: Option<Interned<str>>,
28 flags: FnFlags,
34} 29}
35 30
36impl FunctionData { 31impl FunctionData {
@@ -53,6 +48,11 @@ impl FunctionData {
53 .next_back() 48 .next_back()
54 .map_or(false, |param| matches!(item_tree[param], Param::Varargs)); 49 .map_or(false, |param| matches!(item_tree[param], Param::Varargs));
55 50
51 let mut flags = func.flags;
52 if is_varargs {
53 flags |= FnFlags::IS_VARARGS;
54 }
55
56 Arc::new(FunctionData { 56 Arc::new(FunctionData {
57 name: func.name.clone(), 57 name: func.name.clone(),
58 params: enabled_params 58 params: enabled_params
@@ -64,14 +64,45 @@ impl FunctionData {
64 .collect(), 64 .collect(),
65 ret_type: func.ret_type.clone(), 65 ret_type: func.ret_type.clone(),
66 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), 66 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
67 has_self_param: func.has_self_param,
68 has_body: func.has_body,
69 qualifier: func.qualifier.clone(),
70 is_in_extern_block: func.is_in_extern_block,
71 is_varargs,
72 visibility: item_tree[func.visibility].clone(), 67 visibility: item_tree[func.visibility].clone(),
68 abi: func.abi.clone(),
69 flags,
73 }) 70 })
74 } 71 }
72
73 pub fn has_body(&self) -> bool {
74 self.flags.contains(FnFlags::HAS_BODY)
75 }
76
77 /// True if the first param is `self`. This is relevant to decide whether this
78 /// can be called as a method.
79 pub fn has_self_param(&self) -> bool {
80 self.flags.contains(FnFlags::HAS_SELF_PARAM)
81 }
82
83 pub fn is_default(&self) -> bool {
84 self.flags.contains(FnFlags::IS_DEFAULT)
85 }
86
87 pub fn is_const(&self) -> bool {
88 self.flags.contains(FnFlags::IS_CONST)
89 }
90
91 pub fn is_async(&self) -> bool {
92 self.flags.contains(FnFlags::IS_ASYNC)
93 }
94
95 pub fn is_unsafe(&self) -> bool {
96 self.flags.contains(FnFlags::IS_UNSAFE)
97 }
98
99 pub fn is_in_extern_block(&self) -> bool {
100 self.flags.contains(FnFlags::IS_IN_EXTERN_BLOCK)
101 }
102
103 pub fn is_varargs(&self) -> bool {
104 self.flags.contains(FnFlags::IS_VARARGS)
105 }
75} 106}
76 107
77#[derive(Debug, Clone, PartialEq, Eq)] 108#[derive(Debug, Clone, PartialEq, Eq)]
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index dd80cef23..c6d700977 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -24,7 +24,7 @@ use la_arena::{Arena, Idx, RawIdx};
24use profile::Count; 24use profile::Count;
25use rustc_hash::FxHashMap; 25use rustc_hash::FxHashMap;
26use smallvec::SmallVec; 26use smallvec::SmallVec;
27use syntax::{ast, match_ast, SmolStr, SyntaxKind}; 27use syntax::{ast, match_ast, SyntaxKind};
28 28
29use crate::{ 29use crate::{
30 attr::{Attrs, RawAttrs}, 30 attr::{Attrs, RawAttrs},
@@ -556,15 +556,11 @@ pub struct Function {
556 pub name: Name, 556 pub name: Name,
557 pub visibility: RawVisibilityId, 557 pub visibility: RawVisibilityId,
558 pub generic_params: GenericParamsId, 558 pub generic_params: GenericParamsId,
559 pub has_self_param: bool, 559 pub abi: Option<Interned<str>>,
560 pub has_body: bool,
561 pub qualifier: FunctionQualifier,
562 /// Whether the function is located in an `extern` block (*not* whether it is an
563 /// `extern "abi" fn`).
564 pub is_in_extern_block: bool,
565 pub params: IdRange<Param>, 560 pub params: IdRange<Param>,
566 pub ret_type: Interned<TypeRef>, 561 pub ret_type: Interned<TypeRef>,
567 pub ast_id: FileAstId<ast::Fn>, 562 pub ast_id: FileAstId<ast::Fn>,
563 pub(crate) flags: FnFlags,
568} 564}
569 565
570#[derive(Debug, Clone, Eq, PartialEq)] 566#[derive(Debug, Clone, Eq, PartialEq)]
@@ -573,13 +569,20 @@ pub enum Param {
573 Varargs, 569 Varargs,
574} 570}
575 571
576#[derive(Debug, Clone, PartialEq, Eq)] 572bitflags::bitflags! {
577pub struct FunctionQualifier { 573 /// NOTE: Shared with `FunctionData`
578 pub is_default: bool, 574 pub(crate) struct FnFlags: u8 {
579 pub is_const: bool, 575 const HAS_SELF_PARAM = 1 << 0;
580 pub is_async: bool, 576 const HAS_BODY = 1 << 1;
581 pub is_unsafe: bool, 577 const IS_DEFAULT = 1 << 2;
582 pub abi: Option<SmolStr>, 578 const IS_CONST = 1 << 3;
579 const IS_ASYNC = 1 << 4;
580 const IS_UNSAFE = 1 << 5;
581 /// Whether the function is located in an `extern` block (*not* whether it is an
582 /// `extern "abi" fn`).
583 const IS_IN_EXTERN_BLOCK = 1 << 6;
584 const IS_VARARGS = 1 << 7;
585 }
583} 586}
584 587
585#[derive(Debug, Clone, Eq, PartialEq)] 588#[derive(Debug, Clone, Eq, PartialEq)]
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index ead7cd7a4..39e8403b0 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -395,39 +395,51 @@ impl Ctx {
395 ret_type 395 ret_type
396 }; 396 };
397 397
398 let has_body = func.body().is_some(); 398 let abi = func.abi().map(|abi| {
399 // FIXME: Abi::abi() -> Option<SyntaxToken>?
400 match abi.syntax().last_token() {
401 Some(tok) if tok.kind() == SyntaxKind::STRING => {
402 // FIXME: Better way to unescape?
403 Interned::new_str(tok.text().trim_matches('"'))
404 }
405 _ => {
406 // `extern` default to be `extern "C"`.
407 Interned::new_str("C")
408 }
409 }
410 });
399 411
400 let ast_id = self.source_ast_id_map.ast_id(func); 412 let ast_id = self.source_ast_id_map.ast_id(func);
401 let qualifier = FunctionQualifier { 413
402 is_default: func.default_token().is_some(), 414 let mut flags = FnFlags::empty();
403 is_const: func.const_token().is_some(), 415 if func.body().is_some() {
404 is_async: func.async_token().is_some(), 416 flags |= FnFlags::HAS_BODY;
405 is_unsafe: func.unsafe_token().is_some(), 417 }
406 abi: func.abi().map(|abi| { 418 if has_self_param {
407 // FIXME: Abi::abi() -> Option<SyntaxToken>? 419 flags |= FnFlags::HAS_SELF_PARAM;
408 match abi.syntax().last_token() { 420 }
409 Some(tok) if tok.kind() == SyntaxKind::STRING => { 421 if func.default_token().is_some() {
410 // FIXME: Better way to unescape? 422 flags |= FnFlags::IS_DEFAULT;
411 tok.text().trim_matches('"').into() 423 }
412 } 424 if func.const_token().is_some() {
413 _ => { 425 flags |= FnFlags::IS_CONST;
414 // `extern` default to be `extern "C"`. 426 }
415 "C".into() 427 if func.async_token().is_some() {
416 } 428 flags |= FnFlags::IS_ASYNC;
417 } 429 }
418 }), 430 if func.unsafe_token().is_some() {
419 }; 431 flags |= FnFlags::IS_UNSAFE;
432 }
433
420 let mut res = Function { 434 let mut res = Function {
421 name, 435 name,
422 visibility, 436 visibility,
423 generic_params: GenericParamsId::EMPTY, 437 generic_params: GenericParamsId::EMPTY,
424 has_self_param, 438 abi,
425 has_body,
426 qualifier,
427 is_in_extern_block: false,
428 params, 439 params,
429 ret_type: Interned::new(ret_type), 440 ret_type: Interned::new(ret_type),
430 ast_id, 441 ast_id,
442 flags,
431 }; 443 };
432 res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); 444 res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func);
433 445
@@ -640,8 +652,10 @@ impl Ctx {
640 ast::ExternItem::Fn(ast) => { 652 ast::ExternItem::Fn(ast) => {
641 let func_id = self.lower_function(&ast)?; 653 let func_id = self.lower_function(&ast)?;
642 let func = &mut self.data().functions[func_id.index]; 654 let func = &mut self.data().functions[func_id.index];
643 func.qualifier.is_unsafe = is_intrinsic_fn_unsafe(&func.name); 655 if is_intrinsic_fn_unsafe(&func.name) {
644 func.is_in_extern_block = true; 656 func.flags |= FnFlags::IS_UNSAFE;
657 }
658 func.flags |= FnFlags::IS_IN_EXTERN_BLOCK;
645 func_id.into() 659 func_id.into()
646 } 660 }
647 ast::ExternItem::Static(ast) => { 661 ast::ExternItem::Static(ast) => {