1 //! Contains basic data about various HIR declarations.
6 name::{name, AsName, Name},
9 use ra_syntax::ast::{self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner};
14 type_ref::{Mutability, TypeRef},
15 AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule,
16 ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
19 #[derive(Debug, Clone, PartialEq, Eq)]
20 pub struct FunctionData {
22 pub params: Vec<TypeRef>,
23 pub ret_type: TypeRef,
24 /// True if the first param is `self`. This is relevant to decide whether this
25 /// can be called as a method.
26 pub has_self_param: bool,
30 pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> {
31 let src = func.lookup(db).source(db);
32 let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing);
33 let mut params = Vec::new();
34 let mut has_self_param = false;
35 if let Some(param_list) = src.value.param_list() {
36 if let Some(self_param) = param_list.self_param() {
37 let self_type = if let Some(type_ref) = self_param.ascribed_type() {
38 TypeRef::from_ast(type_ref)
40 let self_type = TypeRef::Path(name![Self].into());
41 match self_param.kind() {
42 ast::SelfParamKind::Owned => self_type,
43 ast::SelfParamKind::Ref => {
44 TypeRef::Reference(Box::new(self_type), Mutability::Shared)
46 ast::SelfParamKind::MutRef => {
47 TypeRef::Reference(Box::new(self_type), Mutability::Mut)
51 params.push(self_type);
52 has_self_param = true;
54 for param in param_list.params() {
55 let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
56 params.push(type_ref);
59 let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) {
60 TypeRef::from_ast(type_ref)
65 let sig = FunctionData { name, params, ret_type, has_self_param };
70 #[derive(Debug, Clone, PartialEq, Eq)]
71 pub struct TypeAliasData {
73 pub type_ref: Option<TypeRef>,
77 pub(crate) fn type_alias_data_query(
78 db: &impl DefDatabase,
80 ) -> Arc<TypeAliasData> {
81 let node = typ.lookup(db).source(db).value;
82 let name = node.name().map_or_else(Name::missing, |n| n.as_name());
83 let type_ref = node.type_ref().map(TypeRef::from_ast);
84 Arc::new(TypeAliasData { name, type_ref })
88 #[derive(Debug, Clone, PartialEq, Eq)]
89 pub struct TraitData {
91 pub items: Vec<(Name, AssocItemId)>,
96 pub(crate) fn trait_data_query(db: &impl DefDatabase, tr: TraitId) -> Arc<TraitData> {
97 let src = tr.lookup(db).source(db);
98 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
99 let auto = src.value.is_auto();
100 let ast_id_map = db.ast_id_map(src.file_id);
102 let container = AssocContainerId::TraitId(tr);
103 let items = if let Some(item_list) = src.value.item_list() {
106 .map(|item_node| match item_node {
107 ast::ImplItem::FnDef(it) => {
108 let name = it.name().map_or_else(Name::missing, |it| it.as_name());
109 let def = FunctionLoc {
111 ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
117 ast::ImplItem::ConstDef(it) => {
118 let name = it.name().map_or_else(Name::missing, |it| it.as_name());
121 ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
127 ast::ImplItem::TypeAliasDef(it) => {
128 let name = it.name().map_or_else(Name::missing, |it| it.as_name());
129 let def = TypeAliasLoc {
131 ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
142 Arc::new(TraitData { name, items, auto })
145 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
146 self.items.iter().filter_map(|(_name, item)| match item {
147 AssocItemId::TypeAliasId(t) => Some(*t),
152 pub fn associated_type_by_name(&self, name: &Name) -> Option<TypeAliasId> {
153 self.items.iter().find_map(|(item_name, item)| match item {
154 AssocItemId::TypeAliasId(t) if item_name == name => Some(*t),
160 #[derive(Debug, Clone, PartialEq, Eq)]
161 pub struct ImplData {
162 pub target_trait: Option<TypeRef>,
163 pub target_type: TypeRef,
164 pub items: Vec<AssocItemId>,
165 pub is_negative: bool,
169 pub(crate) fn impl_data_query(db: &impl DefDatabase, id: ImplId) -> Arc<ImplData> {
170 let impl_loc = id.lookup(db);
171 let src = impl_loc.source(db);
173 let target_trait = src.value.target_trait().map(TypeRef::from_ast);
174 let target_type = TypeRef::from_ast_opt(src.value.target_type());
175 let is_negative = src.value.is_negative();
176 let module_id = impl_loc.container.module(db);
178 let mut items = Vec::new();
179 if let Some(item_list) = src.value.item_list() {
180 items.extend(collect_impl_items(db, item_list.impl_items(), src.file_id, id));
181 items.extend(collect_impl_items_in_macros(
184 &src.with_value(item_list),
189 let res = ImplData { target_trait, target_type, items, is_negative };
194 #[derive(Debug, Clone, PartialEq, Eq)]
195 pub struct ConstData {
196 /// const _: () = ();
197 pub name: Option<Name>,
198 pub type_ref: TypeRef,
202 pub(crate) fn const_data_query(db: &impl DefDatabase, konst: ConstId) -> Arc<ConstData> {
203 let node = konst.lookup(db).source(db).value;
204 Arc::new(ConstData::new(&node))
207 pub(crate) fn static_data_query(db: &impl DefDatabase, konst: StaticId) -> Arc<ConstData> {
208 let node = konst.lookup(db).source(db).value;
209 Arc::new(ConstData::new(&node))
212 fn new<N: NameOwner + TypeAscriptionOwner>(node: &N) -> ConstData {
213 let name = node.name().map(|n| n.as_name());
214 let type_ref = TypeRef::from_ast_opt(node.ascribed_type());
215 ConstData { name, type_ref }
219 fn collect_impl_items_in_macros(
220 db: &impl DefDatabase,
222 impl_block: &InFile<ast::ItemList>,
224 ) -> Vec<AssocItemId> {
225 let mut expander = Expander::new(db, impl_block.file_id, module_id);
226 let mut res = Vec::new();
228 for m in impl_block.value.syntax().children().filter_map(ast::MacroCall::cast) {
229 res.extend(collect_impl_items_in_macro(db, &mut expander, m, id))
235 fn collect_impl_items_in_macro(
236 db: &impl DefDatabase,
237 expander: &mut Expander,
240 ) -> Vec<AssocItemId> {
241 if let Some((mark, items)) = expander.enter_expand(db, m) {
242 let items: InFile<ast::MacroItems> = expander.to_source(items);
243 let mut res = collect_impl_items(
245 items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())),
249 // Recursive collect macros
250 // Note that ast::ModuleItem do not include ast::MacroCall
251 // We cannot use ModuleItemOwner::items here
252 for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) {
253 res.extend(collect_impl_items_in_macro(db, expander, it, id))
255 expander.exit(db, mark);
262 fn collect_impl_items(
263 db: &impl DefDatabase,
264 impl_items: impl Iterator<Item = ImplItem>,
265 file_id: crate::HirFileId,
267 ) -> Vec<AssocItemId> {
268 let items = db.ast_id_map(file_id);
271 .map(|item_node| match item_node {
272 ast::ImplItem::FnDef(it) => {
273 let def = FunctionLoc {
274 container: AssocContainerId::ImplId(id),
275 ast_id: AstId::new(file_id, items.ast_id(&it)),
280 ast::ImplItem::ConstDef(it) => {
282 container: AssocContainerId::ImplId(id),
283 ast_id: AstId::new(file_id, items.ast_id(&it)),
288 ast::ImplItem::TypeAliasDef(it) => {
289 let def = TypeAliasLoc {
290 container: AssocContainerId::ImplId(id),
291 ast_id: AstId::new(file_id, items.ast_id(&it)),