aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/data.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/data.rs')
-rw-r--r--crates/ra_hir_def/src/data.rs192
1 files changed, 192 insertions, 0 deletions
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
new file mode 100644
index 000000000..ba47629db
--- /dev/null
+++ b/crates/ra_hir_def/src/data.rs
@@ -0,0 +1,192 @@
1//! Contains basic data about various HIR declarations.
2
3use std::sync::Arc;
4
5use hir_expand::{
6 name::{self, AsName, Name},
7 AstId,
8};
9use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
10
11use crate::{
12 db::DefDatabase2,
13 type_ref::{Mutability, TypeRef},
14 AssocItemId, AstItemDef, ConstLoc, ContainerId, FunctionId, FunctionLoc, HasSource, ImplId,
15 Intern, Lookup, TraitId, TypeAliasId, TypeAliasLoc,
16};
17
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct FunctionData {
20 pub name: Name,
21 pub params: Vec<TypeRef>,
22 pub ret_type: TypeRef,
23 /// True if the first param is `self`. This is relevant to decide whether this
24 /// can be called as a method.
25 pub has_self_param: bool,
26}
27
28impl FunctionData {
29 pub(crate) fn fn_data_query(db: &impl DefDatabase2, func: FunctionId) -> Arc<FunctionData> {
30 let src = func.lookup(db).source(db);
31 let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing);
32 let mut params = Vec::new();
33 let mut has_self_param = false;
34 if let Some(param_list) = src.value.param_list() {
35 if let Some(self_param) = param_list.self_param() {
36 let self_type = if let Some(type_ref) = self_param.ascribed_type() {
37 TypeRef::from_ast(type_ref)
38 } else {
39 let self_type = TypeRef::Path(name::SELF_TYPE.into());
40 match self_param.kind() {
41 ast::SelfParamKind::Owned => self_type,
42 ast::SelfParamKind::Ref => {
43 TypeRef::Reference(Box::new(self_type), Mutability::Shared)
44 }
45 ast::SelfParamKind::MutRef => {
46 TypeRef::Reference(Box::new(self_type), Mutability::Mut)
47 }
48 }
49 };
50 params.push(self_type);
51 has_self_param = true;
52 }
53 for param in param_list.params() {
54 let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
55 params.push(type_ref);
56 }
57 }
58 let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) {
59 TypeRef::from_ast(type_ref)
60 } else {
61 TypeRef::unit()
62 };
63
64 let sig = FunctionData { name, params, ret_type, has_self_param };
65 Arc::new(sig)
66 }
67}
68
69#[derive(Debug, Clone, PartialEq, Eq)]
70pub struct TypeAliasData {
71 pub name: Name,
72 pub type_ref: Option<TypeRef>,
73}
74
75impl TypeAliasData {
76 pub(crate) fn type_alias_data_query(
77 db: &impl DefDatabase2,
78 typ: TypeAliasId,
79 ) -> Arc<TypeAliasData> {
80 let node = typ.lookup(db).source(db).value;
81 let name = node.name().map_or_else(Name::missing, |n| n.as_name());
82 let type_ref = node.type_ref().map(TypeRef::from_ast);
83 Arc::new(TypeAliasData { name, type_ref })
84 }
85}
86
87#[derive(Debug, Clone, PartialEq, Eq)]
88pub struct TraitData {
89 pub name: Option<Name>,
90 pub items: Vec<AssocItemId>,
91 pub auto: bool,
92}
93
94impl TraitData {
95 pub(crate) fn trait_data_query(db: &impl DefDatabase2, tr: TraitId) -> Arc<TraitData> {
96 let src = tr.source(db);
97 let name = src.value.name().map(|n| n.as_name());
98 let auto = src.value.is_auto();
99 let ast_id_map = db.ast_id_map(src.file_id);
100 let items = if let Some(item_list) = src.value.item_list() {
101 item_list
102 .impl_items()
103 .map(|item_node| match item_node {
104 ast::ImplItem::FnDef(it) => FunctionLoc {
105 container: ContainerId::TraitId(tr),
106 ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
107 }
108 .intern(db)
109 .into(),
110 ast::ImplItem::ConstDef(it) => ConstLoc {
111 container: ContainerId::TraitId(tr),
112 ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
113 }
114 .intern(db)
115 .into(),
116 ast::ImplItem::TypeAliasDef(it) => TypeAliasLoc {
117 container: ContainerId::TraitId(tr),
118 ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
119 }
120 .intern(db)
121 .into(),
122 })
123 .collect()
124 } else {
125 Vec::new()
126 };
127 Arc::new(TraitData { name, items, auto })
128 }
129
130 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
131 self.items.iter().filter_map(|item| match item {
132 AssocItemId::TypeAliasId(t) => Some(*t),
133 _ => None,
134 })
135 }
136}
137
138#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct ImplData {
140 pub target_trait: Option<TypeRef>,
141 pub target_type: TypeRef,
142 pub items: Vec<AssocItemId>,
143 pub is_negative: bool,
144}
145
146impl ImplData {
147 pub(crate) fn impl_data_query(db: &impl DefDatabase2, id: ImplId) -> Arc<ImplData> {
148 let src = id.source(db);
149 let items = db.ast_id_map(src.file_id);
150
151 let target_trait = src.value.target_trait().map(TypeRef::from_ast);
152 let target_type = TypeRef::from_ast_opt(src.value.target_type());
153 let is_negative = src.value.is_negative();
154
155 let items = if let Some(item_list) = src.value.item_list() {
156 item_list
157 .impl_items()
158 .map(|item_node| match item_node {
159 ast::ImplItem::FnDef(it) => {
160 let def = FunctionLoc {
161 container: ContainerId::ImplId(id),
162 ast_id: AstId::new(src.file_id, items.ast_id(&it)),
163 }
164 .intern(db);
165 def.into()
166 }
167 ast::ImplItem::ConstDef(it) => {
168 let def = ConstLoc {
169 container: ContainerId::ImplId(id),
170 ast_id: AstId::new(src.file_id, items.ast_id(&it)),
171 }
172 .intern(db);
173 def.into()
174 }
175 ast::ImplItem::TypeAliasDef(it) => {
176 let def = TypeAliasLoc {
177 container: ContainerId::ImplId(id),
178 ast_id: AstId::new(src.file_id, items.ast_id(&it)),
179 }
180 .intern(db);
181 def.into()
182 }
183 })
184 .collect()
185 } else {
186 Vec::new()
187 };
188
189 let res = ImplData { target_trait, target_type, items, is_negative };
190 Arc::new(res)
191 }
192}