diff options
Diffstat (limited to 'crates/ra_hir_def/src')
43 files changed, 0 insertions, 15260 deletions
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs deleted file mode 100644 index 6cb56a1cd..000000000 --- a/crates/ra_hir_def/src/adt.rs +++ /dev/null | |||
@@ -1,295 +0,0 @@ | |||
1 | //! Defines hir-level representation of structs, enums and unions | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use either::Either; | ||
6 | use hir_expand::{ | ||
7 | name::{AsName, Name}, | ||
8 | InFile, | ||
9 | }; | ||
10 | use ra_arena::{map::ArenaMap, Arena}; | ||
11 | use ra_syntax::ast::{self, NameOwner, VisibilityOwner}; | ||
12 | |||
13 | use crate::{ | ||
14 | body::{CfgExpander, LowerCtx}, | ||
15 | db::DefDatabase, | ||
16 | item_tree::{Field, Fields, ItemTree}, | ||
17 | src::HasChildSource, | ||
18 | src::HasSource, | ||
19 | trace::Trace, | ||
20 | type_ref::TypeRef, | ||
21 | visibility::RawVisibility, | ||
22 | EnumId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, | ||
23 | VariantId, | ||
24 | }; | ||
25 | use ra_cfg::CfgOptions; | ||
26 | |||
27 | /// Note that we use `StructData` for unions as well! | ||
28 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
29 | pub struct StructData { | ||
30 | pub name: Name, | ||
31 | pub variant_data: Arc<VariantData>, | ||
32 | } | ||
33 | |||
34 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
35 | pub struct EnumData { | ||
36 | pub name: Name, | ||
37 | pub variants: Arena<EnumVariantData>, | ||
38 | } | ||
39 | |||
40 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
41 | pub struct EnumVariantData { | ||
42 | pub name: Name, | ||
43 | pub variant_data: Arc<VariantData>, | ||
44 | } | ||
45 | |||
46 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
47 | pub enum VariantData { | ||
48 | Record(Arena<FieldData>), | ||
49 | Tuple(Arena<FieldData>), | ||
50 | Unit, | ||
51 | } | ||
52 | |||
53 | /// A single field of an enum variant or struct | ||
54 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
55 | pub struct FieldData { | ||
56 | pub name: Name, | ||
57 | pub type_ref: TypeRef, | ||
58 | pub visibility: RawVisibility, | ||
59 | } | ||
60 | |||
61 | impl StructData { | ||
62 | pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> { | ||
63 | let loc = id.lookup(db); | ||
64 | let item_tree = db.item_tree(loc.id.file_id); | ||
65 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); | ||
66 | |||
67 | let strukt = &item_tree[loc.id.value]; | ||
68 | let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields); | ||
69 | |||
70 | Arc::new(StructData { name: strukt.name.clone(), variant_data: Arc::new(variant_data) }) | ||
71 | } | ||
72 | pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> { | ||
73 | let loc = id.lookup(db); | ||
74 | let item_tree = db.item_tree(loc.id.file_id); | ||
75 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); | ||
76 | |||
77 | let union = &item_tree[loc.id.value]; | ||
78 | let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields); | ||
79 | |||
80 | Arc::new(StructData { name: union.name.clone(), variant_data: Arc::new(variant_data) }) | ||
81 | } | ||
82 | } | ||
83 | |||
84 | impl EnumData { | ||
85 | pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> { | ||
86 | let loc = e.lookup(db); | ||
87 | let item_tree = db.item_tree(loc.id.file_id); | ||
88 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); | ||
89 | |||
90 | let enum_ = &item_tree[loc.id.value]; | ||
91 | let mut variants = Arena::new(); | ||
92 | for var_id in enum_.variants.clone() { | ||
93 | if item_tree.attrs(var_id.into()).is_cfg_enabled(&cfg_options) { | ||
94 | let var = &item_tree[var_id]; | ||
95 | let var_data = lower_fields(&item_tree, &cfg_options, &var.fields); | ||
96 | |||
97 | variants.alloc(EnumVariantData { | ||
98 | name: var.name.clone(), | ||
99 | variant_data: Arc::new(var_data), | ||
100 | }); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | Arc::new(EnumData { name: enum_.name.clone(), variants }) | ||
105 | } | ||
106 | |||
107 | pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> { | ||
108 | let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?; | ||
109 | Some(id) | ||
110 | } | ||
111 | } | ||
112 | |||
113 | impl HasChildSource for EnumId { | ||
114 | type ChildId = LocalEnumVariantId; | ||
115 | type Value = ast::Variant; | ||
116 | fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> { | ||
117 | let src = self.lookup(db).source(db); | ||
118 | let mut trace = Trace::new_for_map(); | ||
119 | lower_enum(db, &mut trace, &src, self.lookup(db).container.module(db)); | ||
120 | src.with_value(trace.into_map()) | ||
121 | } | ||
122 | } | ||
123 | |||
124 | fn lower_enum( | ||
125 | db: &dyn DefDatabase, | ||
126 | trace: &mut Trace<EnumVariantData, ast::Variant>, | ||
127 | ast: &InFile<ast::Enum>, | ||
128 | module_id: ModuleId, | ||
129 | ) { | ||
130 | let expander = CfgExpander::new(db, ast.file_id, module_id.krate); | ||
131 | let variants = ast | ||
132 | .value | ||
133 | .variant_list() | ||
134 | .into_iter() | ||
135 | .flat_map(|it| it.variants()) | ||
136 | .filter(|var| expander.is_cfg_enabled(var)); | ||
137 | for var in variants { | ||
138 | trace.alloc( | ||
139 | || var.clone(), | ||
140 | || EnumVariantData { | ||
141 | name: var.name().map_or_else(Name::missing, |it| it.as_name()), | ||
142 | variant_data: Arc::new(VariantData::new(db, ast.with_value(var.kind()), module_id)), | ||
143 | }, | ||
144 | ); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | impl VariantData { | ||
149 | fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>, module_id: ModuleId) -> Self { | ||
150 | let mut expander = CfgExpander::new(db, flavor.file_id, module_id.krate); | ||
151 | let mut trace = Trace::new_for_arena(); | ||
152 | match lower_struct(db, &mut expander, &mut trace, &flavor) { | ||
153 | StructKind::Tuple => VariantData::Tuple(trace.into_arena()), | ||
154 | StructKind::Record => VariantData::Record(trace.into_arena()), | ||
155 | StructKind::Unit => VariantData::Unit, | ||
156 | } | ||
157 | } | ||
158 | |||
159 | pub fn fields(&self) -> &Arena<FieldData> { | ||
160 | const EMPTY: &Arena<FieldData> = &Arena::new(); | ||
161 | match &self { | ||
162 | VariantData::Record(fields) | VariantData::Tuple(fields) => fields, | ||
163 | _ => EMPTY, | ||
164 | } | ||
165 | } | ||
166 | |||
167 | pub fn field(&self, name: &Name) -> Option<LocalFieldId> { | ||
168 | self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None }) | ||
169 | } | ||
170 | |||
171 | pub fn kind(&self) -> StructKind { | ||
172 | match self { | ||
173 | VariantData::Record(_) => StructKind::Record, | ||
174 | VariantData::Tuple(_) => StructKind::Tuple, | ||
175 | VariantData::Unit => StructKind::Unit, | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | impl HasChildSource for VariantId { | ||
181 | type ChildId = LocalFieldId; | ||
182 | type Value = Either<ast::TupleField, ast::RecordField>; | ||
183 | |||
184 | fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> { | ||
185 | let (src, module_id) = match self { | ||
186 | VariantId::EnumVariantId(it) => { | ||
187 | // I don't really like the fact that we call into parent source | ||
188 | // here, this might add to more queries then necessary. | ||
189 | let src = it.parent.child_source(db); | ||
190 | (src.map(|map| map[it.local_id].kind()), it.parent.lookup(db).container.module(db)) | ||
191 | } | ||
192 | VariantId::StructId(it) => { | ||
193 | (it.lookup(db).source(db).map(|it| it.kind()), it.lookup(db).container.module(db)) | ||
194 | } | ||
195 | VariantId::UnionId(it) => ( | ||
196 | it.lookup(db).source(db).map(|it| { | ||
197 | it.record_field_list() | ||
198 | .map(ast::StructKind::Record) | ||
199 | .unwrap_or(ast::StructKind::Unit) | ||
200 | }), | ||
201 | it.lookup(db).container.module(db), | ||
202 | ), | ||
203 | }; | ||
204 | let mut expander = CfgExpander::new(db, src.file_id, module_id.krate); | ||
205 | let mut trace = Trace::new_for_map(); | ||
206 | lower_struct(db, &mut expander, &mut trace, &src); | ||
207 | src.with_value(trace.into_map()) | ||
208 | } | ||
209 | } | ||
210 | |||
211 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
212 | pub enum StructKind { | ||
213 | Tuple, | ||
214 | Record, | ||
215 | Unit, | ||
216 | } | ||
217 | |||
218 | fn lower_struct( | ||
219 | db: &dyn DefDatabase, | ||
220 | expander: &mut CfgExpander, | ||
221 | trace: &mut Trace<FieldData, Either<ast::TupleField, ast::RecordField>>, | ||
222 | ast: &InFile<ast::StructKind>, | ||
223 | ) -> StructKind { | ||
224 | let ctx = LowerCtx::new(db, ast.file_id); | ||
225 | |||
226 | match &ast.value { | ||
227 | ast::StructKind::Tuple(fl) => { | ||
228 | for (i, fd) in fl.fields().enumerate() { | ||
229 | if !expander.is_cfg_enabled(&fd) { | ||
230 | continue; | ||
231 | } | ||
232 | |||
233 | trace.alloc( | ||
234 | || Either::Left(fd.clone()), | ||
235 | || FieldData { | ||
236 | name: Name::new_tuple_field(i), | ||
237 | type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()), | ||
238 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), | ||
239 | }, | ||
240 | ); | ||
241 | } | ||
242 | StructKind::Tuple | ||
243 | } | ||
244 | ast::StructKind::Record(fl) => { | ||
245 | for fd in fl.fields() { | ||
246 | if !expander.is_cfg_enabled(&fd) { | ||
247 | continue; | ||
248 | } | ||
249 | |||
250 | trace.alloc( | ||
251 | || Either::Right(fd.clone()), | ||
252 | || FieldData { | ||
253 | name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), | ||
254 | type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()), | ||
255 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), | ||
256 | }, | ||
257 | ); | ||
258 | } | ||
259 | StructKind::Record | ||
260 | } | ||
261 | ast::StructKind::Unit => StructKind::Unit, | ||
262 | } | ||
263 | } | ||
264 | |||
265 | fn lower_fields(item_tree: &ItemTree, cfg_options: &CfgOptions, fields: &Fields) -> VariantData { | ||
266 | match fields { | ||
267 | Fields::Record(flds) => { | ||
268 | let mut arena = Arena::new(); | ||
269 | for field_id in flds.clone() { | ||
270 | if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) { | ||
271 | arena.alloc(lower_field(item_tree, &item_tree[field_id])); | ||
272 | } | ||
273 | } | ||
274 | VariantData::Record(arena) | ||
275 | } | ||
276 | Fields::Tuple(flds) => { | ||
277 | let mut arena = Arena::new(); | ||
278 | for field_id in flds.clone() { | ||
279 | if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) { | ||
280 | arena.alloc(lower_field(item_tree, &item_tree[field_id])); | ||
281 | } | ||
282 | } | ||
283 | VariantData::Tuple(arena) | ||
284 | } | ||
285 | Fields::Unit => VariantData::Unit, | ||
286 | } | ||
287 | } | ||
288 | |||
289 | fn lower_field(item_tree: &ItemTree, field: &Field) -> FieldData { | ||
290 | FieldData { | ||
291 | name: field.name.clone(), | ||
292 | type_ref: field.type_ref.clone(), | ||
293 | visibility: item_tree[field.visibility].clone(), | ||
294 | } | ||
295 | } | ||
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs deleted file mode 100644 index 050832ce0..000000000 --- a/crates/ra_hir_def/src/attr.rs +++ /dev/null | |||
@@ -1,212 +0,0 @@ | |||
1 | //! A higher level attributes based on TokenTree, with also some shortcuts. | ||
2 | |||
3 | use std::{ops, sync::Arc}; | ||
4 | |||
5 | use either::Either; | ||
6 | use hir_expand::{hygiene::Hygiene, AstId, InFile}; | ||
7 | use mbe::ast_to_token_tree; | ||
8 | use ra_cfg::{CfgExpr, CfgOptions}; | ||
9 | use ra_syntax::{ | ||
10 | ast::{self, AstNode, AttrsOwner}, | ||
11 | SmolStr, | ||
12 | }; | ||
13 | use tt::Subtree; | ||
14 | |||
15 | use crate::{ | ||
16 | db::DefDatabase, | ||
17 | item_tree::{ItemTreeId, ItemTreeNode}, | ||
18 | nameres::ModuleSource, | ||
19 | path::ModPath, | ||
20 | src::HasChildSource, | ||
21 | AdtId, AttrDefId, Lookup, | ||
22 | }; | ||
23 | |||
24 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | ||
25 | pub struct Attrs { | ||
26 | entries: Option<Arc<[Attr]>>, | ||
27 | } | ||
28 | |||
29 | impl ops::Deref for Attrs { | ||
30 | type Target = [Attr]; | ||
31 | |||
32 | fn deref(&self) -> &[Attr] { | ||
33 | match &self.entries { | ||
34 | Some(it) => &*it, | ||
35 | None => &[], | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | |||
40 | impl Attrs { | ||
41 | pub const EMPTY: Attrs = Attrs { entries: None }; | ||
42 | |||
43 | pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { | ||
44 | match def { | ||
45 | AttrDefId::ModuleId(module) => { | ||
46 | let def_map = db.crate_def_map(module.krate); | ||
47 | let mod_data = &def_map[module.local_id]; | ||
48 | match mod_data.declaration_source(db) { | ||
49 | Some(it) => { | ||
50 | Attrs::from_attrs_owner(db, it.as_ref().map(|it| it as &dyn AttrsOwner)) | ||
51 | } | ||
52 | None => Attrs::from_attrs_owner( | ||
53 | db, | ||
54 | mod_data.definition_source(db).as_ref().map(|src| match src { | ||
55 | ModuleSource::SourceFile(file) => file as &dyn AttrsOwner, | ||
56 | ModuleSource::Module(module) => module as &dyn AttrsOwner, | ||
57 | }), | ||
58 | ), | ||
59 | } | ||
60 | } | ||
61 | AttrDefId::FieldId(it) => { | ||
62 | let src = it.parent.child_source(db); | ||
63 | match &src.value[it.local_id] { | ||
64 | Either::Left(_tuple) => Attrs::default(), | ||
65 | Either::Right(record) => Attrs::from_attrs_owner(db, src.with_value(record)), | ||
66 | } | ||
67 | } | ||
68 | AttrDefId::EnumVariantId(var_id) => { | ||
69 | let src = var_id.parent.child_source(db); | ||
70 | let src = src.as_ref().map(|it| &it[var_id.local_id]); | ||
71 | Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) | ||
72 | } | ||
73 | AttrDefId::AdtId(it) => match it { | ||
74 | AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
75 | AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
76 | AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
77 | }, | ||
78 | AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
79 | AttrDefId::MacroDefId(it) => { | ||
80 | it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) | ||
81 | } | ||
82 | AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
83 | AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
84 | AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
85 | AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
86 | AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), | ||
87 | } | ||
88 | } | ||
89 | |||
90 | pub fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs { | ||
91 | let hygiene = Hygiene::new(db.upcast(), owner.file_id); | ||
92 | Attrs::new(owner.value, &hygiene) | ||
93 | } | ||
94 | |||
95 | pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs { | ||
96 | let docs = ast::CommentIter::from_syntax_node(owner.syntax()).doc_comment_text().map( | ||
97 | |docs_text| Attr { | ||
98 | input: Some(AttrInput::Literal(SmolStr::new(docs_text))), | ||
99 | path: ModPath::from(hir_expand::name!(doc)), | ||
100 | }, | ||
101 | ); | ||
102 | let mut attrs = owner.attrs().peekable(); | ||
103 | let entries = if attrs.peek().is_none() { | ||
104 | // Avoid heap allocation | ||
105 | None | ||
106 | } else { | ||
107 | Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).chain(docs).collect()) | ||
108 | }; | ||
109 | Attrs { entries } | ||
110 | } | ||
111 | |||
112 | pub fn merge(&self, other: Attrs) -> Attrs { | ||
113 | match (&self.entries, &other.entries) { | ||
114 | (None, None) => Attrs { entries: None }, | ||
115 | (Some(entries), None) | (None, Some(entries)) => { | ||
116 | Attrs { entries: Some(entries.clone()) } | ||
117 | } | ||
118 | (Some(a), Some(b)) => { | ||
119 | Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) } | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | |||
124 | pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { | ||
125 | AttrQuery { attrs: self, key } | ||
126 | } | ||
127 | |||
128 | pub fn cfg(&self) -> impl Iterator<Item = CfgExpr> + '_ { | ||
129 | // FIXME: handle cfg_attr :-) | ||
130 | self.by_key("cfg").tt_values().map(CfgExpr::parse) | ||
131 | } | ||
132 | pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { | ||
133 | self.cfg().all(|cfg| cfg_options.check(&cfg) != Some(false)) | ||
134 | } | ||
135 | } | ||
136 | |||
137 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
138 | pub struct Attr { | ||
139 | pub(crate) path: ModPath, | ||
140 | pub(crate) input: Option<AttrInput>, | ||
141 | } | ||
142 | |||
143 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
144 | pub enum AttrInput { | ||
145 | /// `#[attr = "string"]` | ||
146 | Literal(SmolStr), | ||
147 | /// `#[attr(subtree)]` | ||
148 | TokenTree(Subtree), | ||
149 | } | ||
150 | |||
151 | impl Attr { | ||
152 | fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> { | ||
153 | let path = ModPath::from_src(ast.path()?, hygiene)?; | ||
154 | let input = if let Some(lit) = ast.literal() { | ||
155 | // FIXME: escape? raw string? | ||
156 | let value = lit.syntax().first_token()?.text().trim_matches('"').into(); | ||
157 | Some(AttrInput::Literal(value)) | ||
158 | } else if let Some(tt) = ast.token_tree() { | ||
159 | Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0)) | ||
160 | } else { | ||
161 | None | ||
162 | }; | ||
163 | Some(Attr { path, input }) | ||
164 | } | ||
165 | } | ||
166 | |||
167 | #[derive(Debug, Clone, Copy)] | ||
168 | pub struct AttrQuery<'a> { | ||
169 | attrs: &'a Attrs, | ||
170 | key: &'static str, | ||
171 | } | ||
172 | |||
173 | impl<'a> AttrQuery<'a> { | ||
174 | pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> { | ||
175 | self.attrs().filter_map(|attr| match attr.input.as_ref()? { | ||
176 | AttrInput::TokenTree(it) => Some(it), | ||
177 | _ => None, | ||
178 | }) | ||
179 | } | ||
180 | |||
181 | pub fn string_value(self) -> Option<&'a SmolStr> { | ||
182 | self.attrs().find_map(|attr| match attr.input.as_ref()? { | ||
183 | AttrInput::Literal(it) => Some(it), | ||
184 | _ => None, | ||
185 | }) | ||
186 | } | ||
187 | |||
188 | pub fn exists(self) -> bool { | ||
189 | self.attrs().next().is_some() | ||
190 | } | ||
191 | |||
192 | fn attrs(self) -> impl Iterator<Item = &'a Attr> { | ||
193 | let key = self.key; | ||
194 | self.attrs | ||
195 | .iter() | ||
196 | .filter(move |attr| attr.path.as_ident().map_or(false, |s| s.to_string() == key)) | ||
197 | } | ||
198 | } | ||
199 | |||
200 | fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> Attrs | ||
201 | where | ||
202 | N: ast::AttrsOwner, | ||
203 | { | ||
204 | let src = InFile::new(src.file_id, src.to_node(db.upcast())); | ||
205 | Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) | ||
206 | } | ||
207 | |||
208 | fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs { | ||
209 | let tree = db.item_tree(id.file_id); | ||
210 | let mod_item = N::id_to_mod_item(id.value); | ||
211 | tree.attrs(mod_item.into()).clone() | ||
212 | } | ||
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs deleted file mode 100644 index d5f18b920..000000000 --- a/crates/ra_hir_def/src/body.rs +++ /dev/null | |||
@@ -1,361 +0,0 @@ | |||
1 | //! Defines `Body`: a lowered representation of bodies of functions, statics and | ||
2 | //! consts. | ||
3 | mod lower; | ||
4 | pub mod scope; | ||
5 | |||
6 | use std::{mem, ops::Index, sync::Arc}; | ||
7 | |||
8 | use drop_bomb::DropBomb; | ||
9 | use either::Either; | ||
10 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId}; | ||
11 | use ra_arena::{map::ArenaMap, Arena}; | ||
12 | use ra_cfg::CfgOptions; | ||
13 | use ra_db::CrateId; | ||
14 | use ra_prof::profile; | ||
15 | use ra_syntax::{ast, AstNode, AstPtr}; | ||
16 | use rustc_hash::FxHashMap; | ||
17 | use test_utils::mark; | ||
18 | |||
19 | pub(crate) use lower::LowerCtx; | ||
20 | |||
21 | use crate::{ | ||
22 | attr::Attrs, | ||
23 | db::DefDatabase, | ||
24 | expr::{Expr, ExprId, Pat, PatId}, | ||
25 | item_scope::BuiltinShadowMode, | ||
26 | item_scope::ItemScope, | ||
27 | nameres::CrateDefMap, | ||
28 | path::{ModPath, Path}, | ||
29 | src::HasSource, | ||
30 | AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, | ||
31 | }; | ||
32 | |||
33 | /// A subset of Expander that only deals with cfg attributes. We only need it to | ||
34 | /// avoid cyclic queries in crate def map during enum processing. | ||
35 | pub(crate) struct CfgExpander { | ||
36 | cfg_options: CfgOptions, | ||
37 | hygiene: Hygiene, | ||
38 | } | ||
39 | |||
40 | pub(crate) struct Expander { | ||
41 | cfg_expander: CfgExpander, | ||
42 | crate_def_map: Arc<CrateDefMap>, | ||
43 | current_file_id: HirFileId, | ||
44 | ast_id_map: Arc<AstIdMap>, | ||
45 | module: ModuleId, | ||
46 | recursion_limit: usize, | ||
47 | } | ||
48 | |||
49 | #[cfg(test)] | ||
50 | const EXPANSION_RECURSION_LIMIT: usize = 32; | ||
51 | |||
52 | #[cfg(not(test))] | ||
53 | const EXPANSION_RECURSION_LIMIT: usize = 128; | ||
54 | |||
55 | impl CfgExpander { | ||
56 | pub(crate) fn new( | ||
57 | db: &dyn DefDatabase, | ||
58 | current_file_id: HirFileId, | ||
59 | krate: CrateId, | ||
60 | ) -> CfgExpander { | ||
61 | let hygiene = Hygiene::new(db.upcast(), current_file_id); | ||
62 | let cfg_options = db.crate_graph()[krate].cfg_options.clone(); | ||
63 | CfgExpander { cfg_options, hygiene } | ||
64 | } | ||
65 | |||
66 | pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs { | ||
67 | Attrs::new(owner, &self.hygiene) | ||
68 | } | ||
69 | |||
70 | pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool { | ||
71 | let attrs = self.parse_attrs(owner); | ||
72 | attrs.is_cfg_enabled(&self.cfg_options) | ||
73 | } | ||
74 | } | ||
75 | |||
76 | impl Expander { | ||
77 | pub(crate) fn new( | ||
78 | db: &dyn DefDatabase, | ||
79 | current_file_id: HirFileId, | ||
80 | module: ModuleId, | ||
81 | ) -> Expander { | ||
82 | let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); | ||
83 | let crate_def_map = db.crate_def_map(module.krate); | ||
84 | let ast_id_map = db.ast_id_map(current_file_id); | ||
85 | Expander { | ||
86 | cfg_expander, | ||
87 | crate_def_map, | ||
88 | current_file_id, | ||
89 | ast_id_map, | ||
90 | module, | ||
91 | recursion_limit: 0, | ||
92 | } | ||
93 | } | ||
94 | |||
95 | pub(crate) fn enter_expand<T: ast::AstNode>( | ||
96 | &mut self, | ||
97 | db: &dyn DefDatabase, | ||
98 | local_scope: Option<&ItemScope>, | ||
99 | macro_call: ast::MacroCall, | ||
100 | ) -> Option<(Mark, T)> { | ||
101 | self.recursion_limit += 1; | ||
102 | if self.recursion_limit > EXPANSION_RECURSION_LIMIT { | ||
103 | mark::hit!(your_stack_belongs_to_me); | ||
104 | return None; | ||
105 | } | ||
106 | |||
107 | let macro_call = InFile::new(self.current_file_id, ¯o_call); | ||
108 | |||
109 | if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, |path| { | ||
110 | if let Some(local_scope) = local_scope { | ||
111 | if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) { | ||
112 | return Some(def); | ||
113 | } | ||
114 | } | ||
115 | self.resolve_path_as_macro(db, &path) | ||
116 | }) { | ||
117 | let file_id = call_id.as_file(); | ||
118 | if let Some(node) = db.parse_or_expand(file_id) { | ||
119 | if let Some(expr) = T::cast(node) { | ||
120 | log::debug!("macro expansion {:#?}", expr.syntax()); | ||
121 | |||
122 | let mark = Mark { | ||
123 | file_id: self.current_file_id, | ||
124 | ast_id_map: mem::take(&mut self.ast_id_map), | ||
125 | bomb: DropBomb::new("expansion mark dropped"), | ||
126 | }; | ||
127 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); | ||
128 | self.current_file_id = file_id; | ||
129 | self.ast_id_map = db.ast_id_map(file_id); | ||
130 | return Some((mark, expr)); | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | // FIXME: Instead of just dropping the error from expansion | ||
136 | // report it | ||
137 | None | ||
138 | } | ||
139 | |||
140 | pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { | ||
141 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); | ||
142 | self.current_file_id = mark.file_id; | ||
143 | self.ast_id_map = mem::take(&mut mark.ast_id_map); | ||
144 | self.recursion_limit -= 1; | ||
145 | mark.bomb.defuse(); | ||
146 | } | ||
147 | |||
148 | pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> { | ||
149 | InFile { file_id: self.current_file_id, value } | ||
150 | } | ||
151 | |||
152 | pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool { | ||
153 | self.cfg_expander.is_cfg_enabled(owner) | ||
154 | } | ||
155 | |||
156 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { | ||
157 | Path::from_src(path, &self.cfg_expander.hygiene) | ||
158 | } | ||
159 | |||
160 | fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> { | ||
161 | self.crate_def_map | ||
162 | .resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other) | ||
163 | .0 | ||
164 | .take_macros() | ||
165 | } | ||
166 | |||
167 | fn ast_id<N: AstNode>(&self, item: &N) -> AstId<N> { | ||
168 | let file_local_id = self.ast_id_map.ast_id(item); | ||
169 | AstId::new(self.current_file_id, file_local_id) | ||
170 | } | ||
171 | } | ||
172 | |||
173 | pub(crate) struct Mark { | ||
174 | file_id: HirFileId, | ||
175 | ast_id_map: Arc<AstIdMap>, | ||
176 | bomb: DropBomb, | ||
177 | } | ||
178 | |||
179 | /// The body of an item (function, const etc.). | ||
180 | #[derive(Debug, Eq, PartialEq)] | ||
181 | pub struct Body { | ||
182 | pub exprs: Arena<Expr>, | ||
183 | pub pats: Arena<Pat>, | ||
184 | /// The patterns for the function's parameters. While the parameter types are | ||
185 | /// part of the function signature, the patterns are not (they don't change | ||
186 | /// the external type of the function). | ||
187 | /// | ||
188 | /// If this `Body` is for the body of a constant, this will just be | ||
189 | /// empty. | ||
190 | pub params: Vec<PatId>, | ||
191 | /// The `ExprId` of the actual body expression. | ||
192 | pub body_expr: ExprId, | ||
193 | pub item_scope: ItemScope, | ||
194 | } | ||
195 | |||
196 | pub type ExprPtr = AstPtr<ast::Expr>; | ||
197 | pub type ExprSource = InFile<ExprPtr>; | ||
198 | |||
199 | pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | ||
200 | pub type PatSource = InFile<PatPtr>; | ||
201 | |||
202 | /// An item body together with the mapping from syntax nodes to HIR expression | ||
203 | /// IDs. This is needed to go from e.g. a position in a file to the HIR | ||
204 | /// expression containing it; but for type inference etc., we want to operate on | ||
205 | /// a structure that is agnostic to the actual positions of expressions in the | ||
206 | /// file, so that we don't recompute types whenever some whitespace is typed. | ||
207 | /// | ||
208 | /// One complication here is that, due to macro expansion, a single `Body` might | ||
209 | /// be spread across several files. So, for each ExprId and PatId, we record | ||
210 | /// both the HirFileId and the position inside the file. However, we only store | ||
211 | /// AST -> ExprId mapping for non-macro files, as it is not clear how to handle | ||
212 | /// this properly for macros. | ||
213 | #[derive(Default, Debug, Eq, PartialEq)] | ||
214 | pub struct BodySourceMap { | ||
215 | expr_map: FxHashMap<ExprSource, ExprId>, | ||
216 | expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>, | ||
217 | pat_map: FxHashMap<PatSource, PatId>, | ||
218 | pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>, | ||
219 | field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordExprField>>>, | ||
220 | expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>, | ||
221 | } | ||
222 | |||
223 | #[derive(Default, Debug, Eq, PartialEq, Clone, Copy)] | ||
224 | pub struct SyntheticSyntax; | ||
225 | |||
226 | impl Body { | ||
227 | pub(crate) fn body_with_source_map_query( | ||
228 | db: &dyn DefDatabase, | ||
229 | def: DefWithBodyId, | ||
230 | ) -> (Arc<Body>, Arc<BodySourceMap>) { | ||
231 | let _p = profile("body_with_source_map_query"); | ||
232 | let mut params = None; | ||
233 | |||
234 | let (file_id, module, body) = match def { | ||
235 | DefWithBodyId::FunctionId(f) => { | ||
236 | let f = f.lookup(db); | ||
237 | let src = f.source(db); | ||
238 | params = src.value.param_list(); | ||
239 | (src.file_id, f.module(db), src.value.body().map(ast::Expr::from)) | ||
240 | } | ||
241 | DefWithBodyId::ConstId(c) => { | ||
242 | let c = c.lookup(db); | ||
243 | let src = c.source(db); | ||
244 | (src.file_id, c.module(db), src.value.body()) | ||
245 | } | ||
246 | DefWithBodyId::StaticId(s) => { | ||
247 | let s = s.lookup(db); | ||
248 | let src = s.source(db); | ||
249 | (src.file_id, s.module(db), src.value.body()) | ||
250 | } | ||
251 | }; | ||
252 | let expander = Expander::new(db, file_id, module); | ||
253 | let (body, source_map) = Body::new(db, def, expander, params, body); | ||
254 | (Arc::new(body), Arc::new(source_map)) | ||
255 | } | ||
256 | |||
257 | pub(crate) fn body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<Body> { | ||
258 | db.body_with_source_map(def).0 | ||
259 | } | ||
260 | |||
261 | fn new( | ||
262 | db: &dyn DefDatabase, | ||
263 | def: DefWithBodyId, | ||
264 | expander: Expander, | ||
265 | params: Option<ast::ParamList>, | ||
266 | body: Option<ast::Expr>, | ||
267 | ) -> (Body, BodySourceMap) { | ||
268 | lower::lower(db, def, expander, params, body) | ||
269 | } | ||
270 | } | ||
271 | |||
272 | impl Index<ExprId> for Body { | ||
273 | type Output = Expr; | ||
274 | |||
275 | fn index(&self, expr: ExprId) -> &Expr { | ||
276 | &self.exprs[expr] | ||
277 | } | ||
278 | } | ||
279 | |||
280 | impl Index<PatId> for Body { | ||
281 | type Output = Pat; | ||
282 | |||
283 | fn index(&self, pat: PatId) -> &Pat { | ||
284 | &self.pats[pat] | ||
285 | } | ||
286 | } | ||
287 | |||
288 | impl BodySourceMap { | ||
289 | pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> { | ||
290 | self.expr_map_back[expr].clone() | ||
291 | } | ||
292 | |||
293 | pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> { | ||
294 | let src = node.map(|it| AstPtr::new(it)); | ||
295 | self.expr_map.get(&src).cloned() | ||
296 | } | ||
297 | |||
298 | pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<HirFileId> { | ||
299 | let src = node.map(|it| AstPtr::new(it)); | ||
300 | self.expansions.get(&src).cloned() | ||
301 | } | ||
302 | |||
303 | pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> { | ||
304 | self.pat_map_back[pat].clone() | ||
305 | } | ||
306 | |||
307 | pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> { | ||
308 | let src = node.map(|it| Either::Left(AstPtr::new(it))); | ||
309 | self.pat_map.get(&src).cloned() | ||
310 | } | ||
311 | |||
312 | pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> { | ||
313 | let src = node.map(|it| Either::Right(AstPtr::new(it))); | ||
314 | self.pat_map.get(&src).cloned() | ||
315 | } | ||
316 | |||
317 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordExprField>> { | ||
318 | self.field_map[&(expr, field)].clone() | ||
319 | } | ||
320 | } | ||
321 | |||
322 | #[cfg(test)] | ||
323 | mod tests { | ||
324 | use ra_db::{fixture::WithFixture, SourceDatabase}; | ||
325 | use test_utils::mark; | ||
326 | |||
327 | use crate::ModuleDefId; | ||
328 | |||
329 | use super::*; | ||
330 | |||
331 | fn lower(ra_fixture: &str) -> Arc<Body> { | ||
332 | let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture); | ||
333 | |||
334 | let krate = db.crate_graph().iter().next().unwrap(); | ||
335 | let def_map = db.crate_def_map(krate); | ||
336 | let module = def_map.modules_for_file(file_id).next().unwrap(); | ||
337 | let module = &def_map[module]; | ||
338 | let fn_def = match module.scope.declarations().next().unwrap() { | ||
339 | ModuleDefId::FunctionId(it) => it, | ||
340 | _ => panic!(), | ||
341 | }; | ||
342 | |||
343 | db.body(fn_def.into()) | ||
344 | } | ||
345 | |||
346 | #[test] | ||
347 | fn your_stack_belongs_to_me() { | ||
348 | mark::check!(your_stack_belongs_to_me); | ||
349 | lower( | ||
350 | " | ||
351 | macro_rules! n_nuple { | ||
352 | ($e:tt) => (); | ||
353 | ($($rest:tt)*) => {{ | ||
354 | (n_nuple!($($rest)*)None,) | ||
355 | }}; | ||
356 | } | ||
357 | fn main() { n_nuple!(1,2,3); } | ||
358 | ", | ||
359 | ); | ||
360 | } | ||
361 | } | ||
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs deleted file mode 100644 index f5c37edb3..000000000 --- a/crates/ra_hir_def/src/body/lower.rs +++ /dev/null | |||
@@ -1,931 +0,0 @@ | |||
1 | //! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` | ||
2 | //! representation. | ||
3 | |||
4 | use std::{any::type_name, sync::Arc}; | ||
5 | |||
6 | use either::Either; | ||
7 | use hir_expand::{ | ||
8 | hygiene::Hygiene, | ||
9 | name::{name, AsName, Name}, | ||
10 | HirFileId, MacroDefId, MacroDefKind, | ||
11 | }; | ||
12 | use ra_arena::Arena; | ||
13 | use ra_syntax::{ | ||
14 | ast::{ | ||
15 | self, ArgListOwner, ArrayExprKind, AstChildren, LiteralKind, LoopBodyOwner, NameOwner, | ||
16 | SlicePatComponents, | ||
17 | }, | ||
18 | AstNode, AstPtr, | ||
19 | }; | ||
20 | use rustc_hash::FxHashMap; | ||
21 | use test_utils::mark; | ||
22 | |||
23 | use crate::{ | ||
24 | adt::StructKind, | ||
25 | body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax}, | ||
26 | builtin_type::{BuiltinFloat, BuiltinInt}, | ||
27 | db::DefDatabase, | ||
28 | expr::{ | ||
29 | dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, | ||
30 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, | ||
31 | }, | ||
32 | item_scope::BuiltinShadowMode, | ||
33 | item_tree::{ItemTree, ItemTreeId, ItemTreeNode}, | ||
34 | path::{GenericArgs, Path}, | ||
35 | type_ref::{Mutability, Rawness, TypeRef}, | ||
36 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, | ||
37 | StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, | ||
38 | }; | ||
39 | |||
40 | use super::{ExprSource, PatSource}; | ||
41 | |||
42 | pub(crate) struct LowerCtx { | ||
43 | hygiene: Hygiene, | ||
44 | } | ||
45 | |||
46 | impl LowerCtx { | ||
47 | pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { | ||
48 | LowerCtx { hygiene: Hygiene::new(db.upcast(), file_id) } | ||
49 | } | ||
50 | pub fn with_hygiene(hygiene: &Hygiene) -> Self { | ||
51 | LowerCtx { hygiene: hygiene.clone() } | ||
52 | } | ||
53 | |||
54 | pub fn lower_path(&self, ast: ast::Path) -> Option<Path> { | ||
55 | Path::from_src(ast, &self.hygiene) | ||
56 | } | ||
57 | } | ||
58 | |||
59 | pub(super) fn lower( | ||
60 | db: &dyn DefDatabase, | ||
61 | def: DefWithBodyId, | ||
62 | expander: Expander, | ||
63 | params: Option<ast::ParamList>, | ||
64 | body: Option<ast::Expr>, | ||
65 | ) -> (Body, BodySourceMap) { | ||
66 | let item_tree = db.item_tree(expander.current_file_id); | ||
67 | ExprCollector { | ||
68 | db, | ||
69 | def, | ||
70 | source_map: BodySourceMap::default(), | ||
71 | body: Body { | ||
72 | exprs: Arena::default(), | ||
73 | pats: Arena::default(), | ||
74 | params: Vec::new(), | ||
75 | body_expr: dummy_expr_id(), | ||
76 | item_scope: Default::default(), | ||
77 | }, | ||
78 | item_trees: { | ||
79 | let mut map = FxHashMap::default(); | ||
80 | map.insert(expander.current_file_id, item_tree); | ||
81 | map | ||
82 | }, | ||
83 | expander, | ||
84 | } | ||
85 | .collect(params, body) | ||
86 | } | ||
87 | |||
88 | struct ExprCollector<'a> { | ||
89 | db: &'a dyn DefDatabase, | ||
90 | def: DefWithBodyId, | ||
91 | expander: Expander, | ||
92 | body: Body, | ||
93 | source_map: BodySourceMap, | ||
94 | |||
95 | item_trees: FxHashMap<HirFileId, Arc<ItemTree>>, | ||
96 | } | ||
97 | |||
98 | impl ExprCollector<'_> { | ||
99 | fn collect( | ||
100 | mut self, | ||
101 | param_list: Option<ast::ParamList>, | ||
102 | body: Option<ast::Expr>, | ||
103 | ) -> (Body, BodySourceMap) { | ||
104 | if let Some(param_list) = param_list { | ||
105 | if let Some(self_param) = param_list.self_param() { | ||
106 | let ptr = AstPtr::new(&self_param); | ||
107 | let param_pat = self.alloc_pat( | ||
108 | Pat::Bind { | ||
109 | name: name![self], | ||
110 | mode: BindingAnnotation::Unannotated, | ||
111 | subpat: None, | ||
112 | }, | ||
113 | Either::Right(ptr), | ||
114 | ); | ||
115 | self.body.params.push(param_pat); | ||
116 | } | ||
117 | |||
118 | for param in param_list.params() { | ||
119 | let pat = match param.pat() { | ||
120 | None => continue, | ||
121 | Some(pat) => pat, | ||
122 | }; | ||
123 | let param_pat = self.collect_pat(pat); | ||
124 | self.body.params.push(param_pat); | ||
125 | } | ||
126 | }; | ||
127 | |||
128 | self.body.body_expr = self.collect_expr_opt(body); | ||
129 | (self.body, self.source_map) | ||
130 | } | ||
131 | |||
132 | fn ctx(&self) -> LowerCtx { | ||
133 | LowerCtx::new(self.db, self.expander.current_file_id) | ||
134 | } | ||
135 | |||
136 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { | ||
137 | let src = self.expander.to_source(ptr); | ||
138 | let id = self.make_expr(expr, Ok(src.clone())); | ||
139 | self.source_map.expr_map.insert(src, id); | ||
140 | id | ||
141 | } | ||
142 | // desugared exprs don't have ptr, that's wrong and should be fixed | ||
143 | // somehow. | ||
144 | fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { | ||
145 | self.make_expr(expr, Err(SyntheticSyntax)) | ||
146 | } | ||
147 | fn empty_block(&mut self) -> ExprId { | ||
148 | self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None, label: None }) | ||
149 | } | ||
150 | fn missing_expr(&mut self) -> ExprId { | ||
151 | self.alloc_expr_desugared(Expr::Missing) | ||
152 | } | ||
153 | fn make_expr(&mut self, expr: Expr, src: Result<ExprSource, SyntheticSyntax>) -> ExprId { | ||
154 | let id = self.body.exprs.alloc(expr); | ||
155 | self.source_map.expr_map_back.insert(id, src); | ||
156 | id | ||
157 | } | ||
158 | |||
159 | fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { | ||
160 | let src = self.expander.to_source(ptr); | ||
161 | let id = self.make_pat(pat, Ok(src.clone())); | ||
162 | self.source_map.pat_map.insert(src, id); | ||
163 | id | ||
164 | } | ||
165 | fn missing_pat(&mut self) -> PatId { | ||
166 | self.make_pat(Pat::Missing, Err(SyntheticSyntax)) | ||
167 | } | ||
168 | fn make_pat(&mut self, pat: Pat, src: Result<PatSource, SyntheticSyntax>) -> PatId { | ||
169 | let id = self.body.pats.alloc(pat); | ||
170 | self.source_map.pat_map_back.insert(id, src); | ||
171 | id | ||
172 | } | ||
173 | |||
174 | fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { | ||
175 | let syntax_ptr = AstPtr::new(&expr); | ||
176 | if !self.expander.is_cfg_enabled(&expr) { | ||
177 | return self.missing_expr(); | ||
178 | } | ||
179 | |||
180 | match expr { | ||
181 | ast::Expr::IfExpr(e) => { | ||
182 | let then_branch = self.collect_block_opt(e.then_branch()); | ||
183 | |||
184 | let else_branch = e.else_branch().map(|b| match b { | ||
185 | ast::ElseBranch::Block(it) => self.collect_block(it), | ||
186 | ast::ElseBranch::IfExpr(elif) => { | ||
187 | let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap(); | ||
188 | self.collect_expr(expr) | ||
189 | } | ||
190 | }); | ||
191 | |||
192 | let condition = match e.condition() { | ||
193 | None => self.missing_expr(), | ||
194 | Some(condition) => match condition.pat() { | ||
195 | None => self.collect_expr_opt(condition.expr()), | ||
196 | // if let -- desugar to match | ||
197 | Some(pat) => { | ||
198 | let pat = self.collect_pat(pat); | ||
199 | let match_expr = self.collect_expr_opt(condition.expr()); | ||
200 | let placeholder_pat = self.missing_pat(); | ||
201 | let arms = vec![ | ||
202 | MatchArm { pat, expr: then_branch, guard: None }, | ||
203 | MatchArm { | ||
204 | pat: placeholder_pat, | ||
205 | expr: else_branch.unwrap_or_else(|| self.empty_block()), | ||
206 | guard: None, | ||
207 | }, | ||
208 | ]; | ||
209 | return self | ||
210 | .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr); | ||
211 | } | ||
212 | }, | ||
213 | }; | ||
214 | |||
215 | self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) | ||
216 | } | ||
217 | ast::Expr::EffectExpr(e) => match e.effect() { | ||
218 | ast::Effect::Try(_) => { | ||
219 | let body = self.collect_block_opt(e.block_expr()); | ||
220 | self.alloc_expr(Expr::TryBlock { body }, syntax_ptr) | ||
221 | } | ||
222 | ast::Effect::Unsafe(_) => { | ||
223 | let body = self.collect_block_opt(e.block_expr()); | ||
224 | self.alloc_expr(Expr::Unsafe { body }, syntax_ptr) | ||
225 | } | ||
226 | // FIXME: we need to record these effects somewhere... | ||
227 | ast::Effect::Label(label) => match e.block_expr() { | ||
228 | Some(block) => { | ||
229 | let res = self.collect_block(block); | ||
230 | match &mut self.body.exprs[res] { | ||
231 | Expr::Block { label: block_label, .. } => { | ||
232 | *block_label = | ||
233 | label.lifetime_token().map(|t| Name::new_lifetime(&t)) | ||
234 | } | ||
235 | _ => unreachable!(), | ||
236 | } | ||
237 | res | ||
238 | } | ||
239 | None => self.missing_expr(), | ||
240 | }, | ||
241 | // FIXME: we need to record these effects somewhere... | ||
242 | ast::Effect::Async(_) => self.collect_block_opt(e.block_expr()), | ||
243 | }, | ||
244 | ast::Expr::BlockExpr(e) => self.collect_block(e), | ||
245 | ast::Expr::LoopExpr(e) => { | ||
246 | let body = self.collect_block_opt(e.loop_body()); | ||
247 | self.alloc_expr( | ||
248 | Expr::Loop { | ||
249 | body, | ||
250 | label: e | ||
251 | .label() | ||
252 | .and_then(|l| l.lifetime_token()) | ||
253 | .map(|l| Name::new_lifetime(&l)), | ||
254 | }, | ||
255 | syntax_ptr, | ||
256 | ) | ||
257 | } | ||
258 | ast::Expr::WhileExpr(e) => { | ||
259 | let body = self.collect_block_opt(e.loop_body()); | ||
260 | |||
261 | let condition = match e.condition() { | ||
262 | None => self.missing_expr(), | ||
263 | Some(condition) => match condition.pat() { | ||
264 | None => self.collect_expr_opt(condition.expr()), | ||
265 | // if let -- desugar to match | ||
266 | Some(pat) => { | ||
267 | mark::hit!(infer_resolve_while_let); | ||
268 | let pat = self.collect_pat(pat); | ||
269 | let match_expr = self.collect_expr_opt(condition.expr()); | ||
270 | let placeholder_pat = self.missing_pat(); | ||
271 | let break_ = | ||
272 | self.alloc_expr_desugared(Expr::Break { expr: None, label: None }); | ||
273 | let arms = vec![ | ||
274 | MatchArm { pat, expr: body, guard: None }, | ||
275 | MatchArm { pat: placeholder_pat, expr: break_, guard: None }, | ||
276 | ]; | ||
277 | let match_expr = | ||
278 | self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms }); | ||
279 | return self.alloc_expr( | ||
280 | Expr::Loop { | ||
281 | body: match_expr, | ||
282 | label: e | ||
283 | .label() | ||
284 | .and_then(|l| l.lifetime_token()) | ||
285 | .map(|l| Name::new_lifetime(&l)), | ||
286 | }, | ||
287 | syntax_ptr, | ||
288 | ); | ||
289 | } | ||
290 | }, | ||
291 | }; | ||
292 | |||
293 | self.alloc_expr( | ||
294 | Expr::While { | ||
295 | condition, | ||
296 | body, | ||
297 | label: e | ||
298 | .label() | ||
299 | .and_then(|l| l.lifetime_token()) | ||
300 | .map(|l| Name::new_lifetime(&l)), | ||
301 | }, | ||
302 | syntax_ptr, | ||
303 | ) | ||
304 | } | ||
305 | ast::Expr::ForExpr(e) => { | ||
306 | let iterable = self.collect_expr_opt(e.iterable()); | ||
307 | let pat = self.collect_pat_opt(e.pat()); | ||
308 | let body = self.collect_block_opt(e.loop_body()); | ||
309 | self.alloc_expr( | ||
310 | Expr::For { | ||
311 | iterable, | ||
312 | pat, | ||
313 | body, | ||
314 | label: e | ||
315 | .label() | ||
316 | .and_then(|l| l.lifetime_token()) | ||
317 | .map(|l| Name::new_lifetime(&l)), | ||
318 | }, | ||
319 | syntax_ptr, | ||
320 | ) | ||
321 | } | ||
322 | ast::Expr::CallExpr(e) => { | ||
323 | let callee = self.collect_expr_opt(e.expr()); | ||
324 | let args = if let Some(arg_list) = e.arg_list() { | ||
325 | arg_list.args().map(|e| self.collect_expr(e)).collect() | ||
326 | } else { | ||
327 | Vec::new() | ||
328 | }; | ||
329 | self.alloc_expr(Expr::Call { callee, args }, syntax_ptr) | ||
330 | } | ||
331 | ast::Expr::MethodCallExpr(e) => { | ||
332 | let receiver = self.collect_expr_opt(e.expr()); | ||
333 | let args = if let Some(arg_list) = e.arg_list() { | ||
334 | arg_list.args().map(|e| self.collect_expr(e)).collect() | ||
335 | } else { | ||
336 | Vec::new() | ||
337 | }; | ||
338 | let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); | ||
339 | let generic_args = | ||
340 | e.generic_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it)); | ||
341 | self.alloc_expr( | ||
342 | Expr::MethodCall { receiver, method_name, args, generic_args }, | ||
343 | syntax_ptr, | ||
344 | ) | ||
345 | } | ||
346 | ast::Expr::MatchExpr(e) => { | ||
347 | let expr = self.collect_expr_opt(e.expr()); | ||
348 | let arms = if let Some(match_arm_list) = e.match_arm_list() { | ||
349 | match_arm_list | ||
350 | .arms() | ||
351 | .map(|arm| MatchArm { | ||
352 | pat: self.collect_pat_opt(arm.pat()), | ||
353 | expr: self.collect_expr_opt(arm.expr()), | ||
354 | guard: arm | ||
355 | .guard() | ||
356 | .and_then(|guard| guard.expr()) | ||
357 | .map(|e| self.collect_expr(e)), | ||
358 | }) | ||
359 | .collect() | ||
360 | } else { | ||
361 | Vec::new() | ||
362 | }; | ||
363 | self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr) | ||
364 | } | ||
365 | ast::Expr::PathExpr(e) => { | ||
366 | let path = e | ||
367 | .path() | ||
368 | .and_then(|path| self.expander.parse_path(path)) | ||
369 | .map(Expr::Path) | ||
370 | .unwrap_or(Expr::Missing); | ||
371 | self.alloc_expr(path, syntax_ptr) | ||
372 | } | ||
373 | ast::Expr::ContinueExpr(e) => self.alloc_expr( | ||
374 | Expr::Continue { label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) }, | ||
375 | syntax_ptr, | ||
376 | ), | ||
377 | ast::Expr::BreakExpr(e) => { | ||
378 | let expr = e.expr().map(|e| self.collect_expr(e)); | ||
379 | self.alloc_expr( | ||
380 | Expr::Break { expr, label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) }, | ||
381 | syntax_ptr, | ||
382 | ) | ||
383 | } | ||
384 | ast::Expr::ParenExpr(e) => { | ||
385 | let inner = self.collect_expr_opt(e.expr()); | ||
386 | // make the paren expr point to the inner expression as well | ||
387 | let src = self.expander.to_source(syntax_ptr); | ||
388 | self.source_map.expr_map.insert(src, inner); | ||
389 | inner | ||
390 | } | ||
391 | ast::Expr::ReturnExpr(e) => { | ||
392 | let expr = e.expr().map(|e| self.collect_expr(e)); | ||
393 | self.alloc_expr(Expr::Return { expr }, syntax_ptr) | ||
394 | } | ||
395 | ast::Expr::RecordExpr(e) => { | ||
396 | let path = e.path().and_then(|path| self.expander.parse_path(path)); | ||
397 | let mut field_ptrs = Vec::new(); | ||
398 | let record_lit = if let Some(nfl) = e.record_expr_field_list() { | ||
399 | let fields = nfl | ||
400 | .fields() | ||
401 | .inspect(|field| field_ptrs.push(AstPtr::new(field))) | ||
402 | .filter_map(|field| { | ||
403 | if !self.expander.is_cfg_enabled(&field) { | ||
404 | return None; | ||
405 | } | ||
406 | let name = field.field_name()?.as_name(); | ||
407 | |||
408 | Some(RecordLitField { | ||
409 | name, | ||
410 | expr: match field.expr() { | ||
411 | Some(e) => self.collect_expr(e), | ||
412 | None => self.missing_expr(), | ||
413 | }, | ||
414 | }) | ||
415 | }) | ||
416 | .collect(); | ||
417 | let spread = nfl.spread().map(|s| self.collect_expr(s)); | ||
418 | Expr::RecordLit { path, fields, spread } | ||
419 | } else { | ||
420 | Expr::RecordLit { path, fields: Vec::new(), spread: None } | ||
421 | }; | ||
422 | |||
423 | let res = self.alloc_expr(record_lit, syntax_ptr); | ||
424 | for (i, ptr) in field_ptrs.into_iter().enumerate() { | ||
425 | let src = self.expander.to_source(ptr); | ||
426 | self.source_map.field_map.insert((res, i), src); | ||
427 | } | ||
428 | res | ||
429 | } | ||
430 | ast::Expr::FieldExpr(e) => { | ||
431 | let expr = self.collect_expr_opt(e.expr()); | ||
432 | let name = match e.field_access() { | ||
433 | Some(kind) => kind.as_name(), | ||
434 | _ => Name::missing(), | ||
435 | }; | ||
436 | self.alloc_expr(Expr::Field { expr, name }, syntax_ptr) | ||
437 | } | ||
438 | ast::Expr::AwaitExpr(e) => { | ||
439 | let expr = self.collect_expr_opt(e.expr()); | ||
440 | self.alloc_expr(Expr::Await { expr }, syntax_ptr) | ||
441 | } | ||
442 | ast::Expr::TryExpr(e) => { | ||
443 | let expr = self.collect_expr_opt(e.expr()); | ||
444 | self.alloc_expr(Expr::Try { expr }, syntax_ptr) | ||
445 | } | ||
446 | ast::Expr::CastExpr(e) => { | ||
447 | let expr = self.collect_expr_opt(e.expr()); | ||
448 | let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty()); | ||
449 | self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) | ||
450 | } | ||
451 | ast::Expr::RefExpr(e) => { | ||
452 | let expr = self.collect_expr_opt(e.expr()); | ||
453 | let raw_tok = e.raw_token().is_some(); | ||
454 | let mutability = if raw_tok { | ||
455 | if e.mut_token().is_some() { | ||
456 | Mutability::Mut | ||
457 | } else if e.const_token().is_some() { | ||
458 | Mutability::Shared | ||
459 | } else { | ||
460 | unreachable!("parser only remaps to raw_token() if matching mutability token follows") | ||
461 | } | ||
462 | } else { | ||
463 | Mutability::from_mutable(e.mut_token().is_some()) | ||
464 | }; | ||
465 | let rawness = Rawness::from_raw(raw_tok); | ||
466 | self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr) | ||
467 | } | ||
468 | ast::Expr::PrefixExpr(e) => { | ||
469 | let expr = self.collect_expr_opt(e.expr()); | ||
470 | if let Some(op) = e.op_kind() { | ||
471 | self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr) | ||
472 | } else { | ||
473 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
474 | } | ||
475 | } | ||
476 | ast::Expr::ClosureExpr(e) => { | ||
477 | let mut args = Vec::new(); | ||
478 | let mut arg_types = Vec::new(); | ||
479 | if let Some(pl) = e.param_list() { | ||
480 | for param in pl.params() { | ||
481 | let pat = self.collect_pat_opt(param.pat()); | ||
482 | let type_ref = param.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); | ||
483 | args.push(pat); | ||
484 | arg_types.push(type_ref); | ||
485 | } | ||
486 | } | ||
487 | let ret_type = | ||
488 | e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it)); | ||
489 | let body = self.collect_expr_opt(e.body()); | ||
490 | self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) | ||
491 | } | ||
492 | ast::Expr::BinExpr(e) => { | ||
493 | let lhs = self.collect_expr_opt(e.lhs()); | ||
494 | let rhs = self.collect_expr_opt(e.rhs()); | ||
495 | let op = e.op_kind().map(BinaryOp::from); | ||
496 | self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr) | ||
497 | } | ||
498 | ast::Expr::TupleExpr(e) => { | ||
499 | let exprs = e.fields().map(|expr| self.collect_expr(expr)).collect(); | ||
500 | self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr) | ||
501 | } | ||
502 | ast::Expr::BoxExpr(e) => { | ||
503 | let expr = self.collect_expr_opt(e.expr()); | ||
504 | self.alloc_expr(Expr::Box { expr }, syntax_ptr) | ||
505 | } | ||
506 | |||
507 | ast::Expr::ArrayExpr(e) => { | ||
508 | let kind = e.kind(); | ||
509 | |||
510 | match kind { | ||
511 | ArrayExprKind::ElementList(e) => { | ||
512 | let exprs = e.map(|expr| self.collect_expr(expr)).collect(); | ||
513 | self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr) | ||
514 | } | ||
515 | ArrayExprKind::Repeat { initializer, repeat } => { | ||
516 | let initializer = self.collect_expr_opt(initializer); | ||
517 | let repeat = self.collect_expr_opt(repeat); | ||
518 | self.alloc_expr( | ||
519 | Expr::Array(Array::Repeat { initializer, repeat }), | ||
520 | syntax_ptr, | ||
521 | ) | ||
522 | } | ||
523 | } | ||
524 | } | ||
525 | |||
526 | ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr), | ||
527 | ast::Expr::IndexExpr(e) => { | ||
528 | let base = self.collect_expr_opt(e.base()); | ||
529 | let index = self.collect_expr_opt(e.index()); | ||
530 | self.alloc_expr(Expr::Index { base, index }, syntax_ptr) | ||
531 | } | ||
532 | ast::Expr::RangeExpr(e) => { | ||
533 | let lhs = e.start().map(|lhs| self.collect_expr(lhs)); | ||
534 | let rhs = e.end().map(|rhs| self.collect_expr(rhs)); | ||
535 | match e.op_kind() { | ||
536 | Some(range_type) => { | ||
537 | self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr) | ||
538 | } | ||
539 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
540 | } | ||
541 | } | ||
542 | ast::Expr::MacroCall(e) => { | ||
543 | if let Some(name) = e.is_macro_rules().map(|it| it.as_name()) { | ||
544 | let mac = MacroDefId { | ||
545 | krate: Some(self.expander.module.krate), | ||
546 | ast_id: Some(self.expander.ast_id(&e)), | ||
547 | kind: MacroDefKind::Declarative, | ||
548 | local_inner: false, | ||
549 | }; | ||
550 | self.body.item_scope.define_legacy_macro(name, mac); | ||
551 | |||
552 | // FIXME: do we still need to allocate this as missing ? | ||
553 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
554 | } else { | ||
555 | let macro_call = self.expander.to_source(AstPtr::new(&e)); | ||
556 | match self.expander.enter_expand(self.db, Some(&self.body.item_scope), e) { | ||
557 | Some((mark, expansion)) => { | ||
558 | self.source_map | ||
559 | .expansions | ||
560 | .insert(macro_call, self.expander.current_file_id); | ||
561 | |||
562 | let item_tree = self.db.item_tree(self.expander.current_file_id); | ||
563 | self.item_trees.insert(self.expander.current_file_id, item_tree); | ||
564 | let id = self.collect_expr(expansion); | ||
565 | self.expander.exit(self.db, mark); | ||
566 | id | ||
567 | } | ||
568 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
569 | } | ||
570 | } | ||
571 | } | ||
572 | } | ||
573 | } | ||
574 | |||
575 | fn find_inner_item<N: ItemTreeNode>(&self, ast: &N::Source) -> Option<ItemTreeId<N>> { | ||
576 | let id = self.expander.ast_id(ast); | ||
577 | let tree = &self.item_trees[&id.file_id]; | ||
578 | |||
579 | // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes | ||
580 | |||
581 | // Root file (non-macro). | ||
582 | let item_tree_id = tree | ||
583 | .all_inner_items() | ||
584 | .chain(tree.top_level_items().iter().copied()) | ||
585 | .filter_map(|mod_item| mod_item.downcast::<N>()) | ||
586 | .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value.upcast()) | ||
587 | .or_else(|| { | ||
588 | log::debug!( | ||
589 | "couldn't find inner {} item for {:?} (AST: `{}` - {:?})", | ||
590 | type_name::<N>(), | ||
591 | id, | ||
592 | ast.syntax(), | ||
593 | ast.syntax(), | ||
594 | ); | ||
595 | None | ||
596 | })?; | ||
597 | |||
598 | Some(ItemTreeId::new(id.file_id, item_tree_id)) | ||
599 | } | ||
600 | |||
601 | fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { | ||
602 | if let Some(expr) = expr { | ||
603 | self.collect_expr(expr) | ||
604 | } else { | ||
605 | self.missing_expr() | ||
606 | } | ||
607 | } | ||
608 | |||
609 | fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { | ||
610 | let syntax_node_ptr = AstPtr::new(&block.clone().into()); | ||
611 | self.collect_block_items(&block); | ||
612 | let statements = block | ||
613 | .statements() | ||
614 | .filter_map(|s| { | ||
615 | let stmt = match s { | ||
616 | ast::Stmt::LetStmt(stmt) => { | ||
617 | let pat = self.collect_pat_opt(stmt.pat()); | ||
618 | let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); | ||
619 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); | ||
620 | Statement::Let { pat, type_ref, initializer } | ||
621 | } | ||
622 | ast::Stmt::ExprStmt(stmt) => { | ||
623 | Statement::Expr(self.collect_expr_opt(stmt.expr())) | ||
624 | } | ||
625 | ast::Stmt::Item(_) => return None, | ||
626 | }; | ||
627 | Some(stmt) | ||
628 | }) | ||
629 | .collect(); | ||
630 | let tail = block.expr().map(|e| self.collect_expr(e)); | ||
631 | self.alloc_expr(Expr::Block { statements, tail, label: None }, syntax_node_ptr) | ||
632 | } | ||
633 | |||
634 | fn collect_block_items(&mut self, block: &ast::BlockExpr) { | ||
635 | let container = ContainerId::DefWithBodyId(self.def); | ||
636 | |||
637 | let items = block | ||
638 | .statements() | ||
639 | .filter_map(|stmt| match stmt { | ||
640 | ast::Stmt::Item(it) => Some(it), | ||
641 | ast::Stmt::LetStmt(_) | ast::Stmt::ExprStmt(_) => None, | ||
642 | }) | ||
643 | .filter_map(|item| { | ||
644 | let (def, name): (ModuleDefId, Option<ast::Name>) = match item { | ||
645 | ast::Item::Fn(def) => { | ||
646 | let id = self.find_inner_item(&def)?; | ||
647 | ( | ||
648 | FunctionLoc { container: container.into(), id }.intern(self.db).into(), | ||
649 | def.name(), | ||
650 | ) | ||
651 | } | ||
652 | ast::Item::TypeAlias(def) => { | ||
653 | let id = self.find_inner_item(&def)?; | ||
654 | ( | ||
655 | TypeAliasLoc { container: container.into(), id }.intern(self.db).into(), | ||
656 | def.name(), | ||
657 | ) | ||
658 | } | ||
659 | ast::Item::Const(def) => { | ||
660 | let id = self.find_inner_item(&def)?; | ||
661 | ( | ||
662 | ConstLoc { container: container.into(), id }.intern(self.db).into(), | ||
663 | def.name(), | ||
664 | ) | ||
665 | } | ||
666 | ast::Item::Static(def) => { | ||
667 | let id = self.find_inner_item(&def)?; | ||
668 | (StaticLoc { container, id }.intern(self.db).into(), def.name()) | ||
669 | } | ||
670 | ast::Item::Struct(def) => { | ||
671 | let id = self.find_inner_item(&def)?; | ||
672 | (StructLoc { container, id }.intern(self.db).into(), def.name()) | ||
673 | } | ||
674 | ast::Item::Enum(def) => { | ||
675 | let id = self.find_inner_item(&def)?; | ||
676 | (EnumLoc { container, id }.intern(self.db).into(), def.name()) | ||
677 | } | ||
678 | ast::Item::Union(def) => { | ||
679 | let id = self.find_inner_item(&def)?; | ||
680 | (UnionLoc { container, id }.intern(self.db).into(), def.name()) | ||
681 | } | ||
682 | ast::Item::Trait(def) => { | ||
683 | let id = self.find_inner_item(&def)?; | ||
684 | (TraitLoc { container, id }.intern(self.db).into(), def.name()) | ||
685 | } | ||
686 | ast::Item::ExternBlock(_) => return None, // FIXME: collect from extern blocks | ||
687 | ast::Item::Impl(_) | ||
688 | | ast::Item::Use(_) | ||
689 | | ast::Item::ExternCrate(_) | ||
690 | | ast::Item::Module(_) | ||
691 | | ast::Item::MacroCall(_) => return None, | ||
692 | }; | ||
693 | |||
694 | Some((def, name)) | ||
695 | }) | ||
696 | .collect::<Vec<_>>(); | ||
697 | |||
698 | for (def, name) in items { | ||
699 | self.body.item_scope.define_def(def); | ||
700 | if let Some(name) = name { | ||
701 | let vis = crate::visibility::Visibility::Public; // FIXME determine correctly | ||
702 | let has_constructor = match def { | ||
703 | ModuleDefId::AdtId(AdtId::StructId(s)) => { | ||
704 | self.db.struct_data(s).variant_data.kind() != StructKind::Record | ||
705 | } | ||
706 | _ => true, | ||
707 | }; | ||
708 | self.body.item_scope.push_res( | ||
709 | name.as_name(), | ||
710 | crate::per_ns::PerNs::from_def(def, vis, has_constructor), | ||
711 | ); | ||
712 | } | ||
713 | } | ||
714 | } | ||
715 | |||
716 | fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId { | ||
717 | if let Some(block) = expr { | ||
718 | self.collect_block(block) | ||
719 | } else { | ||
720 | self.missing_expr() | ||
721 | } | ||
722 | } | ||
723 | |||
724 | fn collect_pat(&mut self, pat: ast::Pat) -> PatId { | ||
725 | let pattern = match &pat { | ||
726 | ast::Pat::IdentPat(bp) => { | ||
727 | let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); | ||
728 | let annotation = | ||
729 | BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some()); | ||
730 | let subpat = bp.pat().map(|subpat| self.collect_pat(subpat)); | ||
731 | if annotation == BindingAnnotation::Unannotated && subpat.is_none() { | ||
732 | // This could also be a single-segment path pattern. To | ||
733 | // decide that, we need to try resolving the name. | ||
734 | let (resolved, _) = self.expander.crate_def_map.resolve_path( | ||
735 | self.db, | ||
736 | self.expander.module.local_id, | ||
737 | &name.clone().into(), | ||
738 | BuiltinShadowMode::Other, | ||
739 | ); | ||
740 | match resolved.take_values() { | ||
741 | Some(ModuleDefId::ConstId(_)) => Pat::Path(name.into()), | ||
742 | Some(ModuleDefId::EnumVariantId(_)) => { | ||
743 | // this is only really valid for unit variants, but | ||
744 | // shadowing other enum variants with a pattern is | ||
745 | // an error anyway | ||
746 | Pat::Path(name.into()) | ||
747 | } | ||
748 | Some(ModuleDefId::AdtId(AdtId::StructId(s))) | ||
749 | if self.db.struct_data(s).variant_data.kind() != StructKind::Record => | ||
750 | { | ||
751 | // Funnily enough, record structs *can* be shadowed | ||
752 | // by pattern bindings (but unit or tuple structs | ||
753 | // can't). | ||
754 | Pat::Path(name.into()) | ||
755 | } | ||
756 | // shadowing statics is an error as well, so we just ignore that case here | ||
757 | _ => Pat::Bind { name, mode: annotation, subpat }, | ||
758 | } | ||
759 | } else { | ||
760 | Pat::Bind { name, mode: annotation, subpat } | ||
761 | } | ||
762 | } | ||
763 | ast::Pat::TupleStructPat(p) => { | ||
764 | let path = p.path().and_then(|path| self.expander.parse_path(path)); | ||
765 | let (args, ellipsis) = self.collect_tuple_pat(p.fields()); | ||
766 | Pat::TupleStruct { path, args, ellipsis } | ||
767 | } | ||
768 | ast::Pat::RefPat(p) => { | ||
769 | let pat = self.collect_pat_opt(p.pat()); | ||
770 | let mutability = Mutability::from_mutable(p.mut_token().is_some()); | ||
771 | Pat::Ref { pat, mutability } | ||
772 | } | ||
773 | ast::Pat::PathPat(p) => { | ||
774 | let path = p.path().and_then(|path| self.expander.parse_path(path)); | ||
775 | path.map(Pat::Path).unwrap_or(Pat::Missing) | ||
776 | } | ||
777 | ast::Pat::OrPat(p) => { | ||
778 | let pats = p.pats().map(|p| self.collect_pat(p)).collect(); | ||
779 | Pat::Or(pats) | ||
780 | } | ||
781 | ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()), | ||
782 | ast::Pat::TuplePat(p) => { | ||
783 | let (args, ellipsis) = self.collect_tuple_pat(p.fields()); | ||
784 | Pat::Tuple { args, ellipsis } | ||
785 | } | ||
786 | ast::Pat::WildcardPat(_) => Pat::Wild, | ||
787 | ast::Pat::RecordPat(p) => { | ||
788 | let path = p.path().and_then(|path| self.expander.parse_path(path)); | ||
789 | let args: Vec<_> = p | ||
790 | .record_pat_field_list() | ||
791 | .expect("every struct should have a field list") | ||
792 | .fields() | ||
793 | .filter_map(|f| { | ||
794 | let ast_pat = f.pat()?; | ||
795 | let pat = self.collect_pat(ast_pat); | ||
796 | let name = f.field_name()?.as_name(); | ||
797 | Some(RecordFieldPat { name, pat }) | ||
798 | }) | ||
799 | .collect(); | ||
800 | |||
801 | let ellipsis = p | ||
802 | .record_pat_field_list() | ||
803 | .expect("every struct should have a field list") | ||
804 | .dotdot_token() | ||
805 | .is_some(); | ||
806 | |||
807 | Pat::Record { path, args, ellipsis } | ||
808 | } | ||
809 | ast::Pat::SlicePat(p) => { | ||
810 | let SlicePatComponents { prefix, slice, suffix } = p.components(); | ||
811 | |||
812 | // FIXME properly handle `RestPat` | ||
813 | Pat::Slice { | ||
814 | prefix: prefix.into_iter().map(|p| self.collect_pat(p)).collect(), | ||
815 | slice: slice.map(|p| self.collect_pat(p)), | ||
816 | suffix: suffix.into_iter().map(|p| self.collect_pat(p)).collect(), | ||
817 | } | ||
818 | } | ||
819 | ast::Pat::LiteralPat(lit) => { | ||
820 | if let Some(ast_lit) = lit.literal() { | ||
821 | let expr = Expr::Literal(ast_lit.kind().into()); | ||
822 | let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit)); | ||
823 | let expr_id = self.alloc_expr(expr, expr_ptr); | ||
824 | Pat::Lit(expr_id) | ||
825 | } else { | ||
826 | Pat::Missing | ||
827 | } | ||
828 | } | ||
829 | ast::Pat::RestPat(_) => { | ||
830 | // `RestPat` requires special handling and should not be mapped | ||
831 | // to a Pat. Here we are using `Pat::Missing` as a fallback for | ||
832 | // when `RestPat` is mapped to `Pat`, which can easily happen | ||
833 | // when the source code being analyzed has a malformed pattern | ||
834 | // which includes `..` in a place where it isn't valid. | ||
835 | |||
836 | Pat::Missing | ||
837 | } | ||
838 | // FIXME: implement | ||
839 | ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, | ||
840 | }; | ||
841 | let ptr = AstPtr::new(&pat); | ||
842 | self.alloc_pat(pattern, Either::Left(ptr)) | ||
843 | } | ||
844 | |||
845 | fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId { | ||
846 | if let Some(pat) = pat { | ||
847 | self.collect_pat(pat) | ||
848 | } else { | ||
849 | self.missing_pat() | ||
850 | } | ||
851 | } | ||
852 | |||
853 | fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Vec<PatId>, Option<usize>) { | ||
854 | // Find the location of the `..`, if there is one. Note that we do not | ||
855 | // consider the possiblity of there being multiple `..` here. | ||
856 | let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_))); | ||
857 | // We want to skip the `..` pattern here, since we account for it above. | ||
858 | let args = args | ||
859 | .filter(|p| !matches!(p, ast::Pat::RestPat(_))) | ||
860 | .map(|p| self.collect_pat(p)) | ||
861 | .collect(); | ||
862 | |||
863 | (args, ellipsis) | ||
864 | } | ||
865 | } | ||
866 | |||
867 | impl From<ast::BinOp> for BinaryOp { | ||
868 | fn from(ast_op: ast::BinOp) -> Self { | ||
869 | match ast_op { | ||
870 | ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or), | ||
871 | ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And), | ||
872 | ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }), | ||
873 | ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }), | ||
874 | ast::BinOp::LesserEqualTest => { | ||
875 | BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false }) | ||
876 | } | ||
877 | ast::BinOp::GreaterEqualTest => { | ||
878 | BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false }) | ||
879 | } | ||
880 | ast::BinOp::LesserTest => { | ||
881 | BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true }) | ||
882 | } | ||
883 | ast::BinOp::GreaterTest => { | ||
884 | BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true }) | ||
885 | } | ||
886 | ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add), | ||
887 | ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul), | ||
888 | ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub), | ||
889 | ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div), | ||
890 | ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem), | ||
891 | ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl), | ||
892 | ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr), | ||
893 | ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor), | ||
894 | ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr), | ||
895 | ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd), | ||
896 | ast::BinOp::Assignment => BinaryOp::Assignment { op: None }, | ||
897 | ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) }, | ||
898 | ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) }, | ||
899 | ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) }, | ||
900 | ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) }, | ||
901 | ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) }, | ||
902 | ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) }, | ||
903 | ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) }, | ||
904 | ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) }, | ||
905 | ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) }, | ||
906 | ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) }, | ||
907 | } | ||
908 | } | ||
909 | } | ||
910 | |||
911 | impl From<ast::LiteralKind> for Literal { | ||
912 | fn from(ast_lit_kind: ast::LiteralKind) -> Self { | ||
913 | match ast_lit_kind { | ||
914 | LiteralKind::IntNumber { suffix } => { | ||
915 | let known_name = suffix.and_then(|it| BuiltinInt::from_suffix(&it)); | ||
916 | |||
917 | Literal::Int(Default::default(), known_name) | ||
918 | } | ||
919 | LiteralKind::FloatNumber { suffix } => { | ||
920 | let known_name = suffix.and_then(|it| BuiltinFloat::from_suffix(&it)); | ||
921 | |||
922 | Literal::Float(Default::default(), known_name) | ||
923 | } | ||
924 | LiteralKind::ByteString => Literal::ByteString(Default::default()), | ||
925 | LiteralKind::String => Literal::String(Default::default()), | ||
926 | LiteralKind::Byte => Literal::Int(Default::default(), Some(BuiltinInt::U8)), | ||
927 | LiteralKind::Bool(val) => Literal::Bool(val), | ||
928 | LiteralKind::Char => Literal::Char(Default::default()), | ||
929 | } | ||
930 | } | ||
931 | } | ||
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs deleted file mode 100644 index 99e876683..000000000 --- a/crates/ra_hir_def/src/body/scope.rs +++ /dev/null | |||
@@ -1,456 +0,0 @@ | |||
1 | //! Name resolution for expressions. | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use hir_expand::name::Name; | ||
5 | use ra_arena::{Arena, Idx}; | ||
6 | use rustc_hash::FxHashMap; | ||
7 | |||
8 | use crate::{ | ||
9 | body::Body, | ||
10 | db::DefDatabase, | ||
11 | expr::{Expr, ExprId, Pat, PatId, Statement}, | ||
12 | DefWithBodyId, | ||
13 | }; | ||
14 | |||
15 | pub type ScopeId = Idx<ScopeData>; | ||
16 | |||
17 | #[derive(Debug, PartialEq, Eq)] | ||
18 | pub struct ExprScopes { | ||
19 | scopes: Arena<ScopeData>, | ||
20 | scope_by_expr: FxHashMap<ExprId, ScopeId>, | ||
21 | } | ||
22 | |||
23 | #[derive(Debug, PartialEq, Eq)] | ||
24 | pub struct ScopeEntry { | ||
25 | name: Name, | ||
26 | pat: PatId, | ||
27 | } | ||
28 | |||
29 | impl ScopeEntry { | ||
30 | pub fn name(&self) -> &Name { | ||
31 | &self.name | ||
32 | } | ||
33 | |||
34 | pub fn pat(&self) -> PatId { | ||
35 | self.pat | ||
36 | } | ||
37 | } | ||
38 | |||
39 | #[derive(Debug, PartialEq, Eq)] | ||
40 | pub struct ScopeData { | ||
41 | parent: Option<ScopeId>, | ||
42 | entries: Vec<ScopeEntry>, | ||
43 | } | ||
44 | |||
45 | impl ExprScopes { | ||
46 | pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> { | ||
47 | let body = db.body(def); | ||
48 | Arc::new(ExprScopes::new(&*body)) | ||
49 | } | ||
50 | |||
51 | fn new(body: &Body) -> ExprScopes { | ||
52 | let mut scopes = | ||
53 | ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() }; | ||
54 | let root = scopes.root_scope(); | ||
55 | scopes.add_params_bindings(body, root, &body.params); | ||
56 | compute_expr_scopes(body.body_expr, body, &mut scopes, root); | ||
57 | scopes | ||
58 | } | ||
59 | |||
60 | pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { | ||
61 | &self.scopes[scope].entries | ||
62 | } | ||
63 | |||
64 | pub fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ { | ||
65 | std::iter::successors(scope, move |&scope| self.scopes[scope].parent) | ||
66 | } | ||
67 | |||
68 | pub fn resolve_name_in_scope(&self, scope: ScopeId, name: &Name) -> Option<&ScopeEntry> { | ||
69 | self.scope_chain(Some(scope)) | ||
70 | .find_map(|scope| self.entries(scope).iter().find(|it| it.name == *name)) | ||
71 | } | ||
72 | |||
73 | pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { | ||
74 | self.scope_by_expr.get(&expr).copied() | ||
75 | } | ||
76 | |||
77 | pub fn scope_by_expr(&self) -> &FxHashMap<ExprId, ScopeId> { | ||
78 | &self.scope_by_expr | ||
79 | } | ||
80 | |||
81 | fn root_scope(&mut self) -> ScopeId { | ||
82 | self.scopes.alloc(ScopeData { parent: None, entries: vec![] }) | ||
83 | } | ||
84 | |||
85 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { | ||
86 | self.scopes.alloc(ScopeData { parent: Some(parent), entries: vec![] }) | ||
87 | } | ||
88 | |||
89 | fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { | ||
90 | let pattern = &body[pat]; | ||
91 | if let Pat::Bind { name, .. } = pattern { | ||
92 | let entry = ScopeEntry { name: name.clone(), pat }; | ||
93 | self.scopes[scope].entries.push(entry); | ||
94 | } | ||
95 | |||
96 | pattern.walk_child_pats(|pat| self.add_bindings(body, scope, pat)); | ||
97 | } | ||
98 | |||
99 | fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) { | ||
100 | params.iter().for_each(|pat| self.add_bindings(body, scope, *pat)); | ||
101 | } | ||
102 | |||
103 | fn set_scope(&mut self, node: ExprId, scope: ScopeId) { | ||
104 | self.scope_by_expr.insert(node, scope); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | fn compute_block_scopes( | ||
109 | statements: &[Statement], | ||
110 | tail: Option<ExprId>, | ||
111 | body: &Body, | ||
112 | scopes: &mut ExprScopes, | ||
113 | mut scope: ScopeId, | ||
114 | ) { | ||
115 | for stmt in statements { | ||
116 | match stmt { | ||
117 | Statement::Let { pat, initializer, .. } => { | ||
118 | if let Some(expr) = initializer { | ||
119 | scopes.set_scope(*expr, scope); | ||
120 | compute_expr_scopes(*expr, body, scopes, scope); | ||
121 | } | ||
122 | scope = scopes.new_scope(scope); | ||
123 | scopes.add_bindings(body, scope, *pat); | ||
124 | } | ||
125 | Statement::Expr(expr) => { | ||
126 | scopes.set_scope(*expr, scope); | ||
127 | compute_expr_scopes(*expr, body, scopes, scope); | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | if let Some(expr) = tail { | ||
132 | compute_expr_scopes(expr, body, scopes, scope); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { | ||
137 | scopes.set_scope(expr, scope); | ||
138 | match &body[expr] { | ||
139 | Expr::Block { statements, tail, .. } => { | ||
140 | compute_block_scopes(&statements, *tail, body, scopes, scope); | ||
141 | } | ||
142 | Expr::For { iterable, pat, body: body_expr, .. } => { | ||
143 | compute_expr_scopes(*iterable, body, scopes, scope); | ||
144 | let scope = scopes.new_scope(scope); | ||
145 | scopes.add_bindings(body, scope, *pat); | ||
146 | compute_expr_scopes(*body_expr, body, scopes, scope); | ||
147 | } | ||
148 | Expr::Lambda { args, body: body_expr, .. } => { | ||
149 | let scope = scopes.new_scope(scope); | ||
150 | scopes.add_params_bindings(body, scope, &args); | ||
151 | compute_expr_scopes(*body_expr, body, scopes, scope); | ||
152 | } | ||
153 | Expr::Match { expr, arms } => { | ||
154 | compute_expr_scopes(*expr, body, scopes, scope); | ||
155 | for arm in arms { | ||
156 | let scope = scopes.new_scope(scope); | ||
157 | scopes.add_bindings(body, scope, arm.pat); | ||
158 | if let Some(guard) = arm.guard { | ||
159 | scopes.set_scope(guard, scope); | ||
160 | compute_expr_scopes(guard, body, scopes, scope); | ||
161 | } | ||
162 | scopes.set_scope(arm.expr, scope); | ||
163 | compute_expr_scopes(arm.expr, body, scopes, scope); | ||
164 | } | ||
165 | } | ||
166 | e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)), | ||
167 | }; | ||
168 | } | ||
169 | |||
170 | #[cfg(test)] | ||
171 | mod tests { | ||
172 | use hir_expand::{name::AsName, InFile}; | ||
173 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase}; | ||
174 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; | ||
175 | use test_utils::{assert_eq_text, extract_offset, mark}; | ||
176 | |||
177 | use crate::{db::DefDatabase, test_db::TestDB, FunctionId, ModuleDefId}; | ||
178 | |||
179 | fn find_function(db: &TestDB, file_id: FileId) -> FunctionId { | ||
180 | let krate = db.test_crate(); | ||
181 | let crate_def_map = db.crate_def_map(krate); | ||
182 | |||
183 | let module = crate_def_map.modules_for_file(file_id).next().unwrap(); | ||
184 | let (_, def) = crate_def_map[module].scope.entries().next().unwrap(); | ||
185 | match def.take_values().unwrap() { | ||
186 | ModuleDefId::FunctionId(it) => it, | ||
187 | _ => panic!(), | ||
188 | } | ||
189 | } | ||
190 | |||
191 | fn do_check(ra_fixture: &str, expected: &[&str]) { | ||
192 | let (offset, code) = extract_offset(ra_fixture); | ||
193 | let code = { | ||
194 | let mut buf = String::new(); | ||
195 | let off: usize = offset.into(); | ||
196 | buf.push_str(&code[..off]); | ||
197 | buf.push_str("<|>marker"); | ||
198 | buf.push_str(&code[off..]); | ||
199 | buf | ||
200 | }; | ||
201 | |||
202 | let (db, position) = TestDB::with_position(&code); | ||
203 | let file_id = position.file_id; | ||
204 | let offset = position.offset; | ||
205 | |||
206 | let file_syntax = db.parse(file_id).syntax_node(); | ||
207 | let marker: ast::PathExpr = find_node_at_offset(&file_syntax, offset).unwrap(); | ||
208 | let function = find_function(&db, file_id); | ||
209 | |||
210 | let scopes = db.expr_scopes(function.into()); | ||
211 | let (_body, source_map) = db.body_with_source_map(function.into()); | ||
212 | |||
213 | let expr_id = source_map | ||
214 | .node_expr(InFile { file_id: file_id.into(), value: &marker.into() }) | ||
215 | .unwrap(); | ||
216 | let scope = scopes.scope_for(expr_id); | ||
217 | |||
218 | let actual = scopes | ||
219 | .scope_chain(scope) | ||
220 | .flat_map(|scope| scopes.entries(scope)) | ||
221 | .map(|it| it.name().to_string()) | ||
222 | .collect::<Vec<_>>() | ||
223 | .join("\n"); | ||
224 | let expected = expected.join("\n"); | ||
225 | assert_eq_text!(&expected, &actual); | ||
226 | } | ||
227 | |||
228 | #[test] | ||
229 | fn test_lambda_scope() { | ||
230 | do_check( | ||
231 | r" | ||
232 | fn quux(foo: i32) { | ||
233 | let f = |bar, baz: i32| { | ||
234 | <|> | ||
235 | }; | ||
236 | }", | ||
237 | &["bar", "baz", "foo"], | ||
238 | ); | ||
239 | } | ||
240 | |||
241 | #[test] | ||
242 | fn test_call_scope() { | ||
243 | do_check( | ||
244 | r" | ||
245 | fn quux() { | ||
246 | f(|x| <|> ); | ||
247 | }", | ||
248 | &["x"], | ||
249 | ); | ||
250 | } | ||
251 | |||
252 | #[test] | ||
253 | fn test_method_call_scope() { | ||
254 | do_check( | ||
255 | r" | ||
256 | fn quux() { | ||
257 | z.f(|x| <|> ); | ||
258 | }", | ||
259 | &["x"], | ||
260 | ); | ||
261 | } | ||
262 | |||
263 | #[test] | ||
264 | fn test_loop_scope() { | ||
265 | do_check( | ||
266 | r" | ||
267 | fn quux() { | ||
268 | loop { | ||
269 | let x = (); | ||
270 | <|> | ||
271 | }; | ||
272 | }", | ||
273 | &["x"], | ||
274 | ); | ||
275 | } | ||
276 | |||
277 | #[test] | ||
278 | fn test_match() { | ||
279 | do_check( | ||
280 | r" | ||
281 | fn quux() { | ||
282 | match () { | ||
283 | Some(x) => { | ||
284 | <|> | ||
285 | } | ||
286 | }; | ||
287 | }", | ||
288 | &["x"], | ||
289 | ); | ||
290 | } | ||
291 | |||
292 | #[test] | ||
293 | fn test_shadow_variable() { | ||
294 | do_check( | ||
295 | r" | ||
296 | fn foo(x: String) { | ||
297 | let x : &str = &x<|>; | ||
298 | }", | ||
299 | &["x"], | ||
300 | ); | ||
301 | } | ||
302 | |||
303 | #[test] | ||
304 | fn test_bindings_after_at() { | ||
305 | do_check( | ||
306 | r" | ||
307 | fn foo() { | ||
308 | match Some(()) { | ||
309 | opt @ Some(unit) => { | ||
310 | <|> | ||
311 | } | ||
312 | _ => {} | ||
313 | } | ||
314 | } | ||
315 | ", | ||
316 | &["opt", "unit"], | ||
317 | ); | ||
318 | } | ||
319 | |||
320 | #[test] | ||
321 | fn macro_inner_item() { | ||
322 | do_check( | ||
323 | r" | ||
324 | macro_rules! mac { | ||
325 | () => {{ | ||
326 | fn inner() {} | ||
327 | inner(); | ||
328 | }}; | ||
329 | } | ||
330 | |||
331 | fn foo() { | ||
332 | mac!(); | ||
333 | <|> | ||
334 | } | ||
335 | ", | ||
336 | &[], | ||
337 | ); | ||
338 | } | ||
339 | |||
340 | #[test] | ||
341 | fn broken_inner_item() { | ||
342 | do_check( | ||
343 | r" | ||
344 | fn foo() { | ||
345 | trait {} | ||
346 | <|> | ||
347 | } | ||
348 | ", | ||
349 | &[], | ||
350 | ); | ||
351 | } | ||
352 | |||
353 | fn do_check_local_name(ra_fixture: &str, expected_offset: u32) { | ||
354 | let (db, position) = TestDB::with_position(ra_fixture); | ||
355 | let file_id = position.file_id; | ||
356 | let offset = position.offset; | ||
357 | |||
358 | let file = db.parse(file_id).ok().unwrap(); | ||
359 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) | ||
360 | .expect("failed to find a name at the target offset"); | ||
361 | let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), offset).unwrap(); | ||
362 | |||
363 | let function = find_function(&db, file_id); | ||
364 | |||
365 | let scopes = db.expr_scopes(function.into()); | ||
366 | let (_body, source_map) = db.body_with_source_map(function.into()); | ||
367 | |||
368 | let expr_scope = { | ||
369 | let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap(); | ||
370 | let expr_id = | ||
371 | source_map.node_expr(InFile { file_id: file_id.into(), value: &expr_ast }).unwrap(); | ||
372 | scopes.scope_for(expr_id).unwrap() | ||
373 | }; | ||
374 | |||
375 | let resolved = scopes.resolve_name_in_scope(expr_scope, &name_ref.as_name()).unwrap(); | ||
376 | let pat_src = source_map.pat_syntax(resolved.pat()).unwrap(); | ||
377 | |||
378 | let local_name = pat_src.value.either( | ||
379 | |it| it.syntax_node_ptr().to_node(file.syntax()), | ||
380 | |it| it.syntax_node_ptr().to_node(file.syntax()), | ||
381 | ); | ||
382 | assert_eq!(local_name.text_range(), expected_name.syntax().text_range()); | ||
383 | } | ||
384 | |||
385 | #[test] | ||
386 | fn test_resolve_local_name() { | ||
387 | do_check_local_name( | ||
388 | r#" | ||
389 | fn foo(x: i32, y: u32) { | ||
390 | { | ||
391 | let z = x * 2; | ||
392 | } | ||
393 | { | ||
394 | let t = x<|> * 3; | ||
395 | } | ||
396 | } | ||
397 | "#, | ||
398 | 7, | ||
399 | ); | ||
400 | } | ||
401 | |||
402 | #[test] | ||
403 | fn test_resolve_local_name_declaration() { | ||
404 | do_check_local_name( | ||
405 | r#" | ||
406 | fn foo(x: String) { | ||
407 | let x : &str = &x<|>; | ||
408 | } | ||
409 | "#, | ||
410 | 7, | ||
411 | ); | ||
412 | } | ||
413 | |||
414 | #[test] | ||
415 | fn test_resolve_local_name_shadow() { | ||
416 | do_check_local_name( | ||
417 | r" | ||
418 | fn foo(x: String) { | ||
419 | let x : &str = &x; | ||
420 | x<|> | ||
421 | } | ||
422 | ", | ||
423 | 28, | ||
424 | ); | ||
425 | } | ||
426 | |||
427 | #[test] | ||
428 | fn ref_patterns_contribute_bindings() { | ||
429 | do_check_local_name( | ||
430 | r" | ||
431 | fn foo() { | ||
432 | if let Some(&from) = bar() { | ||
433 | from<|>; | ||
434 | } | ||
435 | } | ||
436 | ", | ||
437 | 28, | ||
438 | ); | ||
439 | } | ||
440 | |||
441 | #[test] | ||
442 | fn while_let_desugaring() { | ||
443 | mark::check!(infer_resolve_while_let); | ||
444 | do_check_local_name( | ||
445 | r#" | ||
446 | fn test() { | ||
447 | let foo: Option<f32> = None; | ||
448 | while let Option::Some(spam) = foo { | ||
449 | spam<|> | ||
450 | } | ||
451 | } | ||
452 | "#, | ||
453 | 75, | ||
454 | ); | ||
455 | } | ||
456 | } | ||
diff --git a/crates/ra_hir_def/src/builtin_type.rs b/crates/ra_hir_def/src/builtin_type.rs deleted file mode 100644 index 0f872b5c0..000000000 --- a/crates/ra_hir_def/src/builtin_type.rs +++ /dev/null | |||
@@ -1,166 +0,0 @@ | |||
1 | //! This module defines built-in types. | ||
2 | //! | ||
3 | //! A peculiarity of built-in types is that they are always available and are | ||
4 | //! not associated with any particular crate. | ||
5 | |||
6 | use std::fmt; | ||
7 | |||
8 | use hir_expand::name::{name, AsName, Name}; | ||
9 | |||
10 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
11 | pub enum Signedness { | ||
12 | Signed, | ||
13 | Unsigned, | ||
14 | } | ||
15 | |||
16 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
17 | pub enum IntBitness { | ||
18 | Xsize, | ||
19 | X8, | ||
20 | X16, | ||
21 | X32, | ||
22 | X64, | ||
23 | X128, | ||
24 | } | ||
25 | |||
26 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
27 | pub enum FloatBitness { | ||
28 | X32, | ||
29 | X64, | ||
30 | } | ||
31 | |||
32 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
33 | pub struct BuiltinInt { | ||
34 | pub signedness: Signedness, | ||
35 | pub bitness: IntBitness, | ||
36 | } | ||
37 | |||
38 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
39 | pub struct BuiltinFloat { | ||
40 | pub bitness: FloatBitness, | ||
41 | } | ||
42 | |||
43 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
44 | pub enum BuiltinType { | ||
45 | Char, | ||
46 | Bool, | ||
47 | Str, | ||
48 | Int(BuiltinInt), | ||
49 | Float(BuiltinFloat), | ||
50 | } | ||
51 | |||
52 | impl BuiltinType { | ||
53 | #[rustfmt::skip] | ||
54 | pub const ALL: &'static [(Name, BuiltinType)] = &[ | ||
55 | (name![char], BuiltinType::Char), | ||
56 | (name![bool], BuiltinType::Bool), | ||
57 | (name![str], BuiltinType::Str), | ||
58 | |||
59 | (name![isize], BuiltinType::Int(BuiltinInt::ISIZE)), | ||
60 | (name![i8], BuiltinType::Int(BuiltinInt::I8)), | ||
61 | (name![i16], BuiltinType::Int(BuiltinInt::I16)), | ||
62 | (name![i32], BuiltinType::Int(BuiltinInt::I32)), | ||
63 | (name![i64], BuiltinType::Int(BuiltinInt::I64)), | ||
64 | (name![i128], BuiltinType::Int(BuiltinInt::I128)), | ||
65 | |||
66 | (name![usize], BuiltinType::Int(BuiltinInt::USIZE)), | ||
67 | (name![u8], BuiltinType::Int(BuiltinInt::U8)), | ||
68 | (name![u16], BuiltinType::Int(BuiltinInt::U16)), | ||
69 | (name![u32], BuiltinType::Int(BuiltinInt::U32)), | ||
70 | (name![u64], BuiltinType::Int(BuiltinInt::U64)), | ||
71 | (name![u128], BuiltinType::Int(BuiltinInt::U128)), | ||
72 | |||
73 | (name![f32], BuiltinType::Float(BuiltinFloat::F32)), | ||
74 | (name![f64], BuiltinType::Float(BuiltinFloat::F64)), | ||
75 | ]; | ||
76 | } | ||
77 | |||
78 | impl AsName for BuiltinType { | ||
79 | fn as_name(&self) -> Name { | ||
80 | match self { | ||
81 | BuiltinType::Char => name![char], | ||
82 | BuiltinType::Bool => name![bool], | ||
83 | BuiltinType::Str => name![str], | ||
84 | BuiltinType::Int(BuiltinInt { signedness, bitness }) => match (signedness, bitness) { | ||
85 | (Signedness::Signed, IntBitness::Xsize) => name![isize], | ||
86 | (Signedness::Signed, IntBitness::X8) => name![i8], | ||
87 | (Signedness::Signed, IntBitness::X16) => name![i16], | ||
88 | (Signedness::Signed, IntBitness::X32) => name![i32], | ||
89 | (Signedness::Signed, IntBitness::X64) => name![i64], | ||
90 | (Signedness::Signed, IntBitness::X128) => name![i128], | ||
91 | |||
92 | (Signedness::Unsigned, IntBitness::Xsize) => name![usize], | ||
93 | (Signedness::Unsigned, IntBitness::X8) => name![u8], | ||
94 | (Signedness::Unsigned, IntBitness::X16) => name![u16], | ||
95 | (Signedness::Unsigned, IntBitness::X32) => name![u32], | ||
96 | (Signedness::Unsigned, IntBitness::X64) => name![u64], | ||
97 | (Signedness::Unsigned, IntBitness::X128) => name![u128], | ||
98 | }, | ||
99 | BuiltinType::Float(BuiltinFloat { bitness }) => match bitness { | ||
100 | FloatBitness::X32 => name![f32], | ||
101 | FloatBitness::X64 => name![f64], | ||
102 | }, | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | |||
107 | impl fmt::Display for BuiltinType { | ||
108 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
109 | let type_name = self.as_name(); | ||
110 | type_name.fmt(f) | ||
111 | } | ||
112 | } | ||
113 | |||
114 | #[rustfmt::skip] | ||
115 | impl BuiltinInt { | ||
116 | pub const ISIZE: BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::Xsize }; | ||
117 | pub const I8 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X8 }; | ||
118 | pub const I16 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X16 }; | ||
119 | pub const I32 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X32 }; | ||
120 | pub const I64 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X64 }; | ||
121 | pub const I128 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X128 }; | ||
122 | |||
123 | pub const USIZE: BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::Xsize }; | ||
124 | pub const U8 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X8 }; | ||
125 | pub const U16 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X16 }; | ||
126 | pub const U32 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X32 }; | ||
127 | pub const U64 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X64 }; | ||
128 | pub const U128 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X128 }; | ||
129 | |||
130 | |||
131 | pub fn from_suffix(suffix: &str) -> Option<BuiltinInt> { | ||
132 | let res = match suffix { | ||
133 | "isize" => Self::ISIZE, | ||
134 | "i8" => Self::I8, | ||
135 | "i16" => Self::I16, | ||
136 | "i32" => Self::I32, | ||
137 | "i64" => Self::I64, | ||
138 | "i128" => Self::I128, | ||
139 | |||
140 | "usize" => Self::USIZE, | ||
141 | "u8" => Self::U8, | ||
142 | "u16" => Self::U16, | ||
143 | "u32" => Self::U32, | ||
144 | "u64" => Self::U64, | ||
145 | "u128" => Self::U128, | ||
146 | |||
147 | _ => return None, | ||
148 | }; | ||
149 | Some(res) | ||
150 | } | ||
151 | } | ||
152 | |||
153 | #[rustfmt::skip] | ||
154 | impl BuiltinFloat { | ||
155 | pub const F32: BuiltinFloat = BuiltinFloat { bitness: FloatBitness::X32 }; | ||
156 | pub const F64: BuiltinFloat = BuiltinFloat { bitness: FloatBitness::X64 }; | ||
157 | |||
158 | pub fn from_suffix(suffix: &str) -> Option<BuiltinFloat> { | ||
159 | let res = match suffix { | ||
160 | "f32" => BuiltinFloat::F32, | ||
161 | "f64" => BuiltinFloat::F64, | ||
162 | _ => return None, | ||
163 | }; | ||
164 | Some(res) | ||
165 | } | ||
166 | } | ||
diff --git a/crates/ra_hir_def/src/child_by_source.rs b/crates/ra_hir_def/src/child_by_source.rs deleted file mode 100644 index dcb00a1d9..000000000 --- a/crates/ra_hir_def/src/child_by_source.rs +++ /dev/null | |||
@@ -1,177 +0,0 @@ | |||
1 | //! When *constructing* `hir`, we start at some parent syntax node and recursively | ||
2 | //! lower the children. | ||
3 | //! | ||
4 | //! This modules allows one to go in the opposite direction: start with a syntax | ||
5 | //! node for a *child*, and get its hir. | ||
6 | |||
7 | use either::Either; | ||
8 | |||
9 | use crate::{ | ||
10 | db::DefDatabase, | ||
11 | dyn_map::DynMap, | ||
12 | item_scope::ItemScope, | ||
13 | keys, | ||
14 | src::{HasChildSource, HasSource}, | ||
15 | AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, FieldId, ImplId, Lookup, ModuleDefId, | ||
16 | ModuleId, TraitId, VariantId, | ||
17 | }; | ||
18 | |||
19 | pub trait ChildBySource { | ||
20 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap; | ||
21 | } | ||
22 | |||
23 | impl ChildBySource for TraitId { | ||
24 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { | ||
25 | let mut res = DynMap::default(); | ||
26 | |||
27 | let data = db.trait_data(*self); | ||
28 | for (_name, item) in data.items.iter() { | ||
29 | match *item { | ||
30 | AssocItemId::FunctionId(func) => { | ||
31 | let src = func.lookup(db).source(db); | ||
32 | res[keys::FUNCTION].insert(src, func) | ||
33 | } | ||
34 | AssocItemId::ConstId(konst) => { | ||
35 | let src = konst.lookup(db).source(db); | ||
36 | res[keys::CONST].insert(src, konst) | ||
37 | } | ||
38 | AssocItemId::TypeAliasId(ty) => { | ||
39 | let src = ty.lookup(db).source(db); | ||
40 | res[keys::TYPE_ALIAS].insert(src, ty) | ||
41 | } | ||
42 | } | ||
43 | } | ||
44 | |||
45 | res | ||
46 | } | ||
47 | } | ||
48 | |||
49 | impl ChildBySource for ImplId { | ||
50 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { | ||
51 | let mut res = DynMap::default(); | ||
52 | |||
53 | let data = db.impl_data(*self); | ||
54 | for &item in data.items.iter() { | ||
55 | match item { | ||
56 | AssocItemId::FunctionId(func) => { | ||
57 | let src = func.lookup(db).source(db); | ||
58 | res[keys::FUNCTION].insert(src, func) | ||
59 | } | ||
60 | AssocItemId::ConstId(konst) => { | ||
61 | let src = konst.lookup(db).source(db); | ||
62 | res[keys::CONST].insert(src, konst) | ||
63 | } | ||
64 | AssocItemId::TypeAliasId(ty) => { | ||
65 | let src = ty.lookup(db).source(db); | ||
66 | res[keys::TYPE_ALIAS].insert(src, ty) | ||
67 | } | ||
68 | } | ||
69 | } | ||
70 | |||
71 | res | ||
72 | } | ||
73 | } | ||
74 | |||
75 | impl ChildBySource for ModuleId { | ||
76 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { | ||
77 | let crate_def_map = db.crate_def_map(self.krate); | ||
78 | let module_data = &crate_def_map[self.local_id]; | ||
79 | module_data.scope.child_by_source(db) | ||
80 | } | ||
81 | } | ||
82 | |||
83 | impl ChildBySource for ItemScope { | ||
84 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { | ||
85 | let mut res = DynMap::default(); | ||
86 | self.declarations().for_each(|item| add_module_def(db, &mut res, item)); | ||
87 | self.impls().for_each(|imp| add_impl(db, &mut res, imp)); | ||
88 | return res; | ||
89 | |||
90 | fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) { | ||
91 | match item { | ||
92 | ModuleDefId::FunctionId(func) => { | ||
93 | let src = func.lookup(db).source(db); | ||
94 | map[keys::FUNCTION].insert(src, func) | ||
95 | } | ||
96 | ModuleDefId::ConstId(konst) => { | ||
97 | let src = konst.lookup(db).source(db); | ||
98 | map[keys::CONST].insert(src, konst) | ||
99 | } | ||
100 | ModuleDefId::StaticId(statik) => { | ||
101 | let src = statik.lookup(db).source(db); | ||
102 | map[keys::STATIC].insert(src, statik) | ||
103 | } | ||
104 | ModuleDefId::TypeAliasId(ty) => { | ||
105 | let src = ty.lookup(db).source(db); | ||
106 | map[keys::TYPE_ALIAS].insert(src, ty) | ||
107 | } | ||
108 | ModuleDefId::TraitId(trait_) => { | ||
109 | let src = trait_.lookup(db).source(db); | ||
110 | map[keys::TRAIT].insert(src, trait_) | ||
111 | } | ||
112 | ModuleDefId::AdtId(adt) => match adt { | ||
113 | AdtId::StructId(strukt) => { | ||
114 | let src = strukt.lookup(db).source(db); | ||
115 | map[keys::STRUCT].insert(src, strukt) | ||
116 | } | ||
117 | AdtId::UnionId(union_) => { | ||
118 | let src = union_.lookup(db).source(db); | ||
119 | map[keys::UNION].insert(src, union_) | ||
120 | } | ||
121 | AdtId::EnumId(enum_) => { | ||
122 | let src = enum_.lookup(db).source(db); | ||
123 | map[keys::ENUM].insert(src, enum_) | ||
124 | } | ||
125 | }, | ||
126 | _ => (), | ||
127 | } | ||
128 | } | ||
129 | fn add_impl(db: &dyn DefDatabase, map: &mut DynMap, imp: ImplId) { | ||
130 | let src = imp.lookup(db).source(db); | ||
131 | map[keys::IMPL].insert(src, imp) | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | impl ChildBySource for VariantId { | ||
137 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { | ||
138 | let mut res = DynMap::default(); | ||
139 | |||
140 | let arena_map = self.child_source(db); | ||
141 | let arena_map = arena_map.as_ref(); | ||
142 | for (local_id, source) in arena_map.value.iter() { | ||
143 | let id = FieldId { parent: *self, local_id }; | ||
144 | match source { | ||
145 | Either::Left(source) => { | ||
146 | res[keys::TUPLE_FIELD].insert(arena_map.with_value(source.clone()), id) | ||
147 | } | ||
148 | Either::Right(source) => { | ||
149 | res[keys::RECORD_FIELD].insert(arena_map.with_value(source.clone()), id) | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | res | ||
154 | } | ||
155 | } | ||
156 | |||
157 | impl ChildBySource for EnumId { | ||
158 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { | ||
159 | let mut res = DynMap::default(); | ||
160 | |||
161 | let arena_map = self.child_source(db); | ||
162 | let arena_map = arena_map.as_ref(); | ||
163 | for (local_id, source) in arena_map.value.iter() { | ||
164 | let id = EnumVariantId { parent: *self, local_id }; | ||
165 | res[keys::VARIANT].insert(arena_map.with_value(source.clone()), id) | ||
166 | } | ||
167 | |||
168 | res | ||
169 | } | ||
170 | } | ||
171 | |||
172 | impl ChildBySource for DefWithBodyId { | ||
173 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { | ||
174 | let body = db.body(*self); | ||
175 | body.item_scope.child_by_source(db) | ||
176 | } | ||
177 | } | ||
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs deleted file mode 100644 index 88a8ef9bf..000000000 --- a/crates/ra_hir_def/src/data.rs +++ /dev/null | |||
@@ -1,279 +0,0 @@ | |||
1 | //! Contains basic data about various HIR declarations. | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use hir_expand::{name::Name, InFile}; | ||
6 | use ra_prof::profile; | ||
7 | use ra_syntax::ast; | ||
8 | |||
9 | use crate::{ | ||
10 | attr::Attrs, | ||
11 | body::Expander, | ||
12 | db::DefDatabase, | ||
13 | item_tree::{AssocItem, ItemTreeId, ModItem}, | ||
14 | type_ref::{TypeBound, TypeRef}, | ||
15 | visibility::RawVisibility, | ||
16 | AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, | ||
17 | Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | ||
18 | }; | ||
19 | |||
20 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
21 | pub struct FunctionData { | ||
22 | pub name: Name, | ||
23 | pub params: Vec<TypeRef>, | ||
24 | pub ret_type: TypeRef, | ||
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 is_unsafe: bool, | ||
30 | pub is_varargs: bool, | ||
31 | pub visibility: RawVisibility, | ||
32 | } | ||
33 | |||
34 | impl FunctionData { | ||
35 | pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> { | ||
36 | let loc = func.lookup(db); | ||
37 | let item_tree = db.item_tree(loc.id.file_id); | ||
38 | let func = &item_tree[loc.id.value]; | ||
39 | |||
40 | Arc::new(FunctionData { | ||
41 | name: func.name.clone(), | ||
42 | params: func.params.to_vec(), | ||
43 | ret_type: func.ret_type.clone(), | ||
44 | attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(), | ||
45 | has_self_param: func.has_self_param, | ||
46 | is_unsafe: func.is_unsafe, | ||
47 | is_varargs: func.is_varargs, | ||
48 | visibility: item_tree[func.visibility].clone(), | ||
49 | }) | ||
50 | } | ||
51 | } | ||
52 | |||
53 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
54 | pub struct TypeAliasData { | ||
55 | pub name: Name, | ||
56 | pub type_ref: Option<TypeRef>, | ||
57 | pub visibility: RawVisibility, | ||
58 | /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). | ||
59 | pub bounds: Vec<TypeBound>, | ||
60 | } | ||
61 | |||
62 | impl TypeAliasData { | ||
63 | pub(crate) fn type_alias_data_query( | ||
64 | db: &dyn DefDatabase, | ||
65 | typ: TypeAliasId, | ||
66 | ) -> Arc<TypeAliasData> { | ||
67 | let loc = typ.lookup(db); | ||
68 | let item_tree = db.item_tree(loc.id.file_id); | ||
69 | let typ = &item_tree[loc.id.value]; | ||
70 | |||
71 | Arc::new(TypeAliasData { | ||
72 | name: typ.name.clone(), | ||
73 | type_ref: typ.type_ref.clone(), | ||
74 | visibility: item_tree[typ.visibility].clone(), | ||
75 | bounds: typ.bounds.to_vec(), | ||
76 | }) | ||
77 | } | ||
78 | } | ||
79 | |||
80 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
81 | pub struct TraitData { | ||
82 | pub name: Name, | ||
83 | pub items: Vec<(Name, AssocItemId)>, | ||
84 | pub auto: bool, | ||
85 | } | ||
86 | |||
87 | impl TraitData { | ||
88 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { | ||
89 | let tr_loc = tr.lookup(db); | ||
90 | let item_tree = db.item_tree(tr_loc.id.file_id); | ||
91 | let tr_def = &item_tree[tr_loc.id.value]; | ||
92 | let name = tr_def.name.clone(); | ||
93 | let auto = tr_def.auto; | ||
94 | let module_id = tr_loc.container.module(db); | ||
95 | let container = AssocContainerId::TraitId(tr); | ||
96 | let mut expander = Expander::new(db, tr_loc.id.file_id, module_id); | ||
97 | |||
98 | let items = collect_items( | ||
99 | db, | ||
100 | module_id, | ||
101 | &mut expander, | ||
102 | tr_def.items.iter().copied(), | ||
103 | tr_loc.id.file_id, | ||
104 | container, | ||
105 | 100, | ||
106 | ); | ||
107 | |||
108 | Arc::new(TraitData { name, items, auto }) | ||
109 | } | ||
110 | |||
111 | pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { | ||
112 | self.items.iter().filter_map(|(_name, item)| match item { | ||
113 | AssocItemId::TypeAliasId(t) => Some(*t), | ||
114 | _ => None, | ||
115 | }) | ||
116 | } | ||
117 | |||
118 | pub fn associated_type_by_name(&self, name: &Name) -> Option<TypeAliasId> { | ||
119 | self.items.iter().find_map(|(item_name, item)| match item { | ||
120 | AssocItemId::TypeAliasId(t) if item_name == name => Some(*t), | ||
121 | _ => None, | ||
122 | }) | ||
123 | } | ||
124 | } | ||
125 | |||
126 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
127 | pub struct ImplData { | ||
128 | pub target_trait: Option<TypeRef>, | ||
129 | pub target_type: TypeRef, | ||
130 | pub items: Vec<AssocItemId>, | ||
131 | pub is_negative: bool, | ||
132 | } | ||
133 | |||
134 | impl ImplData { | ||
135 | pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> { | ||
136 | let _p = profile("impl_data_query"); | ||
137 | let impl_loc = id.lookup(db); | ||
138 | |||
139 | let item_tree = db.item_tree(impl_loc.id.file_id); | ||
140 | let impl_def = &item_tree[impl_loc.id.value]; | ||
141 | let target_trait = impl_def.target_trait.clone(); | ||
142 | let target_type = impl_def.target_type.clone(); | ||
143 | let is_negative = impl_def.is_negative; | ||
144 | let module_id = impl_loc.container.module(db); | ||
145 | let container = AssocContainerId::ImplId(id); | ||
146 | let mut expander = Expander::new(db, impl_loc.id.file_id, module_id); | ||
147 | |||
148 | let items = collect_items( | ||
149 | db, | ||
150 | module_id, | ||
151 | &mut expander, | ||
152 | impl_def.items.iter().copied(), | ||
153 | impl_loc.id.file_id, | ||
154 | container, | ||
155 | 100, | ||
156 | ); | ||
157 | let items = items.into_iter().map(|(_, item)| item).collect(); | ||
158 | |||
159 | Arc::new(ImplData { target_trait, target_type, items, is_negative }) | ||
160 | } | ||
161 | } | ||
162 | |||
163 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
164 | pub struct ConstData { | ||
165 | /// const _: () = (); | ||
166 | pub name: Option<Name>, | ||
167 | pub type_ref: TypeRef, | ||
168 | pub visibility: RawVisibility, | ||
169 | } | ||
170 | |||
171 | impl ConstData { | ||
172 | pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> { | ||
173 | let loc = konst.lookup(db); | ||
174 | let item_tree = db.item_tree(loc.id.file_id); | ||
175 | let konst = &item_tree[loc.id.value]; | ||
176 | |||
177 | Arc::new(ConstData { | ||
178 | name: konst.name.clone(), | ||
179 | type_ref: konst.type_ref.clone(), | ||
180 | visibility: item_tree[konst.visibility].clone(), | ||
181 | }) | ||
182 | } | ||
183 | } | ||
184 | |||
185 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
186 | pub struct StaticData { | ||
187 | pub name: Option<Name>, | ||
188 | pub type_ref: TypeRef, | ||
189 | pub visibility: RawVisibility, | ||
190 | pub mutable: bool, | ||
191 | } | ||
192 | |||
193 | impl StaticData { | ||
194 | pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> { | ||
195 | let node = konst.lookup(db); | ||
196 | let item_tree = db.item_tree(node.id.file_id); | ||
197 | let statik = &item_tree[node.id.value]; | ||
198 | |||
199 | Arc::new(StaticData { | ||
200 | name: Some(statik.name.clone()), | ||
201 | type_ref: statik.type_ref.clone(), | ||
202 | visibility: item_tree[statik.visibility].clone(), | ||
203 | mutable: statik.mutable, | ||
204 | }) | ||
205 | } | ||
206 | } | ||
207 | |||
208 | fn collect_items( | ||
209 | db: &dyn DefDatabase, | ||
210 | module: ModuleId, | ||
211 | expander: &mut Expander, | ||
212 | assoc_items: impl Iterator<Item = AssocItem>, | ||
213 | file_id: crate::HirFileId, | ||
214 | container: AssocContainerId, | ||
215 | limit: usize, | ||
216 | ) -> Vec<(Name, AssocItemId)> { | ||
217 | if limit == 0 { | ||
218 | return Vec::new(); | ||
219 | } | ||
220 | |||
221 | let item_tree = db.item_tree(file_id); | ||
222 | let cfg_options = db.crate_graph()[module.krate].cfg_options.clone(); | ||
223 | |||
224 | let mut items = Vec::new(); | ||
225 | for item in assoc_items { | ||
226 | match item { | ||
227 | AssocItem::Function(id) => { | ||
228 | let item = &item_tree[id]; | ||
229 | let attrs = item_tree.attrs(ModItem::from(id).into()); | ||
230 | if !attrs.is_cfg_enabled(&cfg_options) { | ||
231 | continue; | ||
232 | } | ||
233 | let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); | ||
234 | items.push((item.name.clone(), def.into())); | ||
235 | } | ||
236 | // FIXME: cfg? | ||
237 | AssocItem::Const(id) => { | ||
238 | let item = &item_tree[id]; | ||
239 | let name = match item.name.clone() { | ||
240 | Some(name) => name, | ||
241 | None => continue, | ||
242 | }; | ||
243 | let def = ConstLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); | ||
244 | items.push((name, def.into())); | ||
245 | } | ||
246 | AssocItem::TypeAlias(id) => { | ||
247 | let item = &item_tree[id]; | ||
248 | let def = TypeAliasLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); | ||
249 | items.push((item.name.clone(), def.into())); | ||
250 | } | ||
251 | AssocItem::MacroCall(call) => { | ||
252 | let call = &item_tree[call]; | ||
253 | let ast_id_map = db.ast_id_map(file_id); | ||
254 | let root = db.parse_or_expand(file_id).unwrap(); | ||
255 | let call = ast_id_map.get(call.ast_id).to_node(&root); | ||
256 | |||
257 | if let Some((mark, mac)) = expander.enter_expand(db, None, call) { | ||
258 | let src: InFile<ast::MacroItems> = expander.to_source(mac); | ||
259 | let item_tree = db.item_tree(src.file_id); | ||
260 | let iter = | ||
261 | item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item); | ||
262 | items.extend(collect_items( | ||
263 | db, | ||
264 | module, | ||
265 | expander, | ||
266 | iter, | ||
267 | src.file_id, | ||
268 | container, | ||
269 | limit - 1, | ||
270 | )); | ||
271 | |||
272 | expander.exit(db, mark); | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | |||
278 | items | ||
279 | } | ||
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs deleted file mode 100644 index 9c3ede2d7..000000000 --- a/crates/ra_hir_def/src/db.rs +++ /dev/null | |||
@@ -1,121 +0,0 @@ | |||
1 | //! Defines database & queries for name resolution. | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use hir_expand::{db::AstDatabase, HirFileId}; | ||
5 | use ra_db::{salsa, CrateId, SourceDatabase, Upcast}; | ||
6 | use ra_prof::profile; | ||
7 | use ra_syntax::SmolStr; | ||
8 | |||
9 | use crate::{ | ||
10 | adt::{EnumData, StructData}, | ||
11 | attr::Attrs, | ||
12 | body::{scope::ExprScopes, Body, BodySourceMap}, | ||
13 | data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData}, | ||
14 | docs::Documentation, | ||
15 | generics::GenericParams, | ||
16 | import_map::ImportMap, | ||
17 | item_tree::ItemTree, | ||
18 | lang_item::{LangItemTarget, LangItems}, | ||
19 | nameres::CrateDefMap, | ||
20 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, | ||
21 | GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, | ||
22 | TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, | ||
23 | }; | ||
24 | |||
25 | #[salsa::query_group(InternDatabaseStorage)] | ||
26 | pub trait InternDatabase: SourceDatabase { | ||
27 | #[salsa::interned] | ||
28 | fn intern_function(&self, loc: FunctionLoc) -> FunctionId; | ||
29 | #[salsa::interned] | ||
30 | fn intern_struct(&self, loc: StructLoc) -> StructId; | ||
31 | #[salsa::interned] | ||
32 | fn intern_union(&self, loc: UnionLoc) -> UnionId; | ||
33 | #[salsa::interned] | ||
34 | fn intern_enum(&self, loc: EnumLoc) -> EnumId; | ||
35 | #[salsa::interned] | ||
36 | fn intern_const(&self, loc: ConstLoc) -> ConstId; | ||
37 | #[salsa::interned] | ||
38 | fn intern_static(&self, loc: StaticLoc) -> StaticId; | ||
39 | #[salsa::interned] | ||
40 | fn intern_trait(&self, loc: TraitLoc) -> TraitId; | ||
41 | #[salsa::interned] | ||
42 | fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId; | ||
43 | #[salsa::interned] | ||
44 | fn intern_impl(&self, loc: ImplLoc) -> ImplId; | ||
45 | } | ||
46 | |||
47 | #[salsa::query_group(DefDatabaseStorage)] | ||
48 | pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | ||
49 | #[salsa::invoke(ItemTree::item_tree_query)] | ||
50 | fn item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>; | ||
51 | |||
52 | #[salsa::invoke(crate_def_map_wait)] | ||
53 | #[salsa::transparent] | ||
54 | fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>; | ||
55 | |||
56 | #[salsa::invoke(CrateDefMap::crate_def_map_query)] | ||
57 | fn crate_def_map_query(&self, krate: CrateId) -> Arc<CrateDefMap>; | ||
58 | |||
59 | #[salsa::invoke(StructData::struct_data_query)] | ||
60 | fn struct_data(&self, id: StructId) -> Arc<StructData>; | ||
61 | #[salsa::invoke(StructData::union_data_query)] | ||
62 | fn union_data(&self, id: UnionId) -> Arc<StructData>; | ||
63 | |||
64 | #[salsa::invoke(EnumData::enum_data_query)] | ||
65 | fn enum_data(&self, e: EnumId) -> Arc<EnumData>; | ||
66 | |||
67 | #[salsa::invoke(ImplData::impl_data_query)] | ||
68 | fn impl_data(&self, e: ImplId) -> Arc<ImplData>; | ||
69 | |||
70 | #[salsa::invoke(TraitData::trait_data_query)] | ||
71 | fn trait_data(&self, e: TraitId) -> Arc<TraitData>; | ||
72 | |||
73 | #[salsa::invoke(TypeAliasData::type_alias_data_query)] | ||
74 | fn type_alias_data(&self, e: TypeAliasId) -> Arc<TypeAliasData>; | ||
75 | |||
76 | #[salsa::invoke(FunctionData::fn_data_query)] | ||
77 | fn function_data(&self, func: FunctionId) -> Arc<FunctionData>; | ||
78 | |||
79 | #[salsa::invoke(ConstData::const_data_query)] | ||
80 | fn const_data(&self, konst: ConstId) -> Arc<ConstData>; | ||
81 | |||
82 | #[salsa::invoke(StaticData::static_data_query)] | ||
83 | fn static_data(&self, konst: StaticId) -> Arc<StaticData>; | ||
84 | |||
85 | #[salsa::invoke(Body::body_with_source_map_query)] | ||
86 | fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>); | ||
87 | |||
88 | #[salsa::invoke(Body::body_query)] | ||
89 | fn body(&self, def: DefWithBodyId) -> Arc<Body>; | ||
90 | |||
91 | #[salsa::invoke(ExprScopes::expr_scopes_query)] | ||
92 | fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>; | ||
93 | |||
94 | #[salsa::invoke(GenericParams::generic_params_query)] | ||
95 | fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>; | ||
96 | |||
97 | #[salsa::invoke(Attrs::attrs_query)] | ||
98 | fn attrs(&self, def: AttrDefId) -> Attrs; | ||
99 | |||
100 | #[salsa::invoke(LangItems::module_lang_items_query)] | ||
101 | fn module_lang_items(&self, module: ModuleId) -> Option<Arc<LangItems>>; | ||
102 | |||
103 | #[salsa::invoke(LangItems::crate_lang_items_query)] | ||
104 | fn crate_lang_items(&self, krate: CrateId) -> Arc<LangItems>; | ||
105 | |||
106 | #[salsa::invoke(LangItems::lang_item_query)] | ||
107 | fn lang_item(&self, start_crate: CrateId, item: SmolStr) -> Option<LangItemTarget>; | ||
108 | |||
109 | // FIXME(https://github.com/rust-analyzer/rust-analyzer/issues/2148#issuecomment-550519102) | ||
110 | // Remove this query completely, in favor of `Attrs::docs` method | ||
111 | #[salsa::invoke(Documentation::documentation_query)] | ||
112 | fn documentation(&self, def: AttrDefId) -> Option<Documentation>; | ||
113 | |||
114 | #[salsa::invoke(ImportMap::import_map_query)] | ||
115 | fn import_map(&self, krate: CrateId) -> Arc<ImportMap>; | ||
116 | } | ||
117 | |||
118 | fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { | ||
119 | let _p = profile("crate_def_map:wait"); | ||
120 | db.crate_def_map_query(krate) | ||
121 | } | ||
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs deleted file mode 100644 index 30db48f86..000000000 --- a/crates/ra_hir_def/src/diagnostics.rs +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
1 | //! Diagnostics produced by `hir_def`. | ||
2 | |||
3 | use std::any::Any; | ||
4 | |||
5 | use hir_expand::diagnostics::Diagnostic; | ||
6 | use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; | ||
7 | |||
8 | use hir_expand::{HirFileId, InFile}; | ||
9 | |||
10 | #[derive(Debug)] | ||
11 | pub struct UnresolvedModule { | ||
12 | pub file: HirFileId, | ||
13 | pub decl: AstPtr<ast::Module>, | ||
14 | pub candidate: String, | ||
15 | } | ||
16 | |||
17 | impl Diagnostic for UnresolvedModule { | ||
18 | fn message(&self) -> String { | ||
19 | "unresolved module".to_string() | ||
20 | } | ||
21 | fn source(&self) -> InFile<SyntaxNodePtr> { | ||
22 | InFile::new(self.file, self.decl.clone().into()) | ||
23 | } | ||
24 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
25 | self | ||
26 | } | ||
27 | } | ||
diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs deleted file mode 100644 index 2630b3d89..000000000 --- a/crates/ra_hir_def/src/docs.rs +++ /dev/null | |||
@@ -1,121 +0,0 @@ | |||
1 | //! Defines hir documentation. | ||
2 | //! | ||
3 | //! This really shouldn't exist, instead, we should deshugar doc comments into attributes, see | ||
4 | //! https://github.com/rust-analyzer/rust-analyzer/issues/2148#issuecomment-550519102 | ||
5 | |||
6 | use std::sync::Arc; | ||
7 | |||
8 | use either::Either; | ||
9 | use ra_syntax::ast; | ||
10 | |||
11 | use crate::{ | ||
12 | db::DefDatabase, | ||
13 | src::{HasChildSource, HasSource}, | ||
14 | AdtId, AttrDefId, Lookup, | ||
15 | }; | ||
16 | |||
17 | /// Holds documentation | ||
18 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
19 | pub struct Documentation(Arc<str>); | ||
20 | |||
21 | impl Into<String> for Documentation { | ||
22 | fn into(self) -> String { | ||
23 | self.as_str().to_owned() | ||
24 | } | ||
25 | } | ||
26 | |||
27 | impl Documentation { | ||
28 | fn new(s: &str) -> Documentation { | ||
29 | Documentation(s.into()) | ||
30 | } | ||
31 | |||
32 | pub fn from_ast<N>(node: &N) -> Option<Documentation> | ||
33 | where | ||
34 | N: ast::DocCommentsOwner + ast::AttrsOwner, | ||
35 | { | ||
36 | docs_from_ast(node) | ||
37 | } | ||
38 | |||
39 | pub fn as_str(&self) -> &str { | ||
40 | &*self.0 | ||
41 | } | ||
42 | |||
43 | pub(crate) fn documentation_query( | ||
44 | db: &dyn DefDatabase, | ||
45 | def: AttrDefId, | ||
46 | ) -> Option<Documentation> { | ||
47 | match def { | ||
48 | AttrDefId::ModuleId(module) => { | ||
49 | let def_map = db.crate_def_map(module.krate); | ||
50 | let src = def_map[module.local_id].declaration_source(db)?; | ||
51 | docs_from_ast(&src.value) | ||
52 | } | ||
53 | AttrDefId::FieldId(it) => { | ||
54 | let src = it.parent.child_source(db); | ||
55 | match &src.value[it.local_id] { | ||
56 | Either::Left(_tuple) => None, | ||
57 | Either::Right(record) => docs_from_ast(record), | ||
58 | } | ||
59 | } | ||
60 | AttrDefId::AdtId(it) => match it { | ||
61 | AdtId::StructId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
62 | AdtId::EnumId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
63 | AdtId::UnionId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
64 | }, | ||
65 | AttrDefId::EnumVariantId(it) => { | ||
66 | let src = it.parent.child_source(db); | ||
67 | docs_from_ast(&src.value[it.local_id]) | ||
68 | } | ||
69 | AttrDefId::TraitId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
70 | AttrDefId::MacroDefId(it) => docs_from_ast(&it.ast_id?.to_node(db.upcast())), | ||
71 | AttrDefId::ConstId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
72 | AttrDefId::StaticId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
73 | AttrDefId::FunctionId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
74 | AttrDefId::TypeAliasId(it) => docs_from_ast(&it.lookup(db).source(db).value), | ||
75 | AttrDefId::ImplId(_) => None, | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | |||
80 | pub(crate) fn docs_from_ast<N>(node: &N) -> Option<Documentation> | ||
81 | where | ||
82 | N: ast::DocCommentsOwner + ast::AttrsOwner, | ||
83 | { | ||
84 | let doc_comment_text = node.doc_comment_text(); | ||
85 | let doc_attr_text = expand_doc_attrs(node); | ||
86 | let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text); | ||
87 | docs.map(|it| Documentation::new(&it)) | ||
88 | } | ||
89 | |||
90 | fn merge_doc_comments_and_attrs( | ||
91 | doc_comment_text: Option<String>, | ||
92 | doc_attr_text: Option<String>, | ||
93 | ) -> Option<String> { | ||
94 | match (doc_comment_text, doc_attr_text) { | ||
95 | (Some(mut comment_text), Some(attr_text)) => { | ||
96 | comment_text.push_str("\n\n"); | ||
97 | comment_text.push_str(&attr_text); | ||
98 | Some(comment_text) | ||
99 | } | ||
100 | (Some(comment_text), None) => Some(comment_text), | ||
101 | (None, Some(attr_text)) => Some(attr_text), | ||
102 | (None, None) => None, | ||
103 | } | ||
104 | } | ||
105 | |||
106 | fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option<String> { | ||
107 | let mut docs = String::new(); | ||
108 | for attr in owner.attrs() { | ||
109 | if let Some(("doc", value)) = | ||
110 | attr.as_simple_key_value().as_ref().map(|(k, v)| (k.as_str(), v.as_str())) | ||
111 | { | ||
112 | docs.push_str(value); | ||
113 | docs.push_str("\n\n"); | ||
114 | } | ||
115 | } | ||
116 | if docs.is_empty() { | ||
117 | None | ||
118 | } else { | ||
119 | Some(docs.trim_end_matches("\n\n").to_owned()) | ||
120 | } | ||
121 | } | ||
diff --git a/crates/ra_hir_def/src/dyn_map.rs b/crates/ra_hir_def/src/dyn_map.rs deleted file mode 100644 index 6f269d7b0..000000000 --- a/crates/ra_hir_def/src/dyn_map.rs +++ /dev/null | |||
@@ -1,108 +0,0 @@ | |||
1 | //! This module defines a `DynMap` -- a container for heterogeneous maps. | ||
2 | //! | ||
3 | //! This means that `DynMap` stores a bunch of hash maps inside, and those maps | ||
4 | //! can be of different types. | ||
5 | //! | ||
6 | //! It is used like this: | ||
7 | //! | ||
8 | //! ``` | ||
9 | //! // keys define submaps of a `DynMap` | ||
10 | //! const STRING_TO_U32: Key<String, u32> = Key::new(); | ||
11 | //! const U32_TO_VEC: Key<u32, Vec<bool>> = Key::new(); | ||
12 | //! | ||
13 | //! // Note: concrete type, no type params! | ||
14 | //! let mut map = DynMap::new(); | ||
15 | //! | ||
16 | //! // To access a specific map, index the `DynMap` by `Key`: | ||
17 | //! map[STRING_TO_U32].insert("hello".to_string(), 92); | ||
18 | //! let value = map[U32_TO_VEC].get(92); | ||
19 | //! assert!(value.is_none()); | ||
20 | //! ``` | ||
21 | //! | ||
22 | //! This is a work of fiction. Any similarities to Kotlin's `BindingContext` are | ||
23 | //! a coincidence. | ||
24 | use std::{ | ||
25 | hash::Hash, | ||
26 | marker::PhantomData, | ||
27 | ops::{Index, IndexMut}, | ||
28 | }; | ||
29 | |||
30 | use anymap::Map; | ||
31 | use rustc_hash::FxHashMap; | ||
32 | |||
33 | pub struct Key<K, V, P = (K, V)> { | ||
34 | _phantom: PhantomData<(K, V, P)>, | ||
35 | } | ||
36 | |||
37 | impl<K, V, P> Key<K, V, P> { | ||
38 | pub(crate) const fn new() -> Key<K, V, P> { | ||
39 | Key { _phantom: PhantomData } | ||
40 | } | ||
41 | } | ||
42 | |||
43 | impl<K, V, P> Copy for Key<K, V, P> {} | ||
44 | |||
45 | impl<K, V, P> Clone for Key<K, V, P> { | ||
46 | fn clone(&self) -> Key<K, V, P> { | ||
47 | *self | ||
48 | } | ||
49 | } | ||
50 | |||
51 | pub trait Policy { | ||
52 | type K; | ||
53 | type V; | ||
54 | |||
55 | fn insert(map: &mut DynMap, key: Self::K, value: Self::V); | ||
56 | fn get<'a>(map: &'a DynMap, key: &Self::K) -> Option<&'a Self::V>; | ||
57 | } | ||
58 | |||
59 | impl<K: Hash + Eq + 'static, V: 'static> Policy for (K, V) { | ||
60 | type K = K; | ||
61 | type V = V; | ||
62 | fn insert(map: &mut DynMap, key: K, value: V) { | ||
63 | map.map.entry::<FxHashMap<K, V>>().or_insert_with(Default::default).insert(key, value); | ||
64 | } | ||
65 | fn get<'a>(map: &'a DynMap, key: &K) -> Option<&'a V> { | ||
66 | map.map.get::<FxHashMap<K, V>>()?.get(key) | ||
67 | } | ||
68 | } | ||
69 | |||
70 | pub struct DynMap { | ||
71 | pub(crate) map: Map, | ||
72 | } | ||
73 | |||
74 | impl Default for DynMap { | ||
75 | fn default() -> Self { | ||
76 | DynMap { map: Map::new() } | ||
77 | } | ||
78 | } | ||
79 | |||
80 | #[repr(transparent)] | ||
81 | pub struct KeyMap<KEY> { | ||
82 | map: DynMap, | ||
83 | _phantom: PhantomData<KEY>, | ||
84 | } | ||
85 | |||
86 | impl<P: Policy> KeyMap<Key<P::K, P::V, P>> { | ||
87 | pub fn insert(&mut self, key: P::K, value: P::V) { | ||
88 | P::insert(&mut self.map, key, value) | ||
89 | } | ||
90 | pub fn get(&self, key: &P::K) -> Option<&P::V> { | ||
91 | P::get(&self.map, key) | ||
92 | } | ||
93 | } | ||
94 | |||
95 | impl<P: Policy> Index<Key<P::K, P::V, P>> for DynMap { | ||
96 | type Output = KeyMap<Key<P::K, P::V, P>>; | ||
97 | fn index(&self, _key: Key<P::K, P::V, P>) -> &Self::Output { | ||
98 | // Safe due to `#[repr(transparent)]`. | ||
99 | unsafe { std::mem::transmute::<&DynMap, &KeyMap<Key<P::K, P::V, P>>>(self) } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | impl<P: Policy> IndexMut<Key<P::K, P::V, P>> for DynMap { | ||
104 | fn index_mut(&mut self, _key: Key<P::K, P::V, P>) -> &mut Self::Output { | ||
105 | // Safe due to `#[repr(transparent)]`. | ||
106 | unsafe { std::mem::transmute::<&mut DynMap, &mut KeyMap<Key<P::K, P::V, P>>>(self) } | ||
107 | } | ||
108 | } | ||
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs deleted file mode 100644 index e41cfc16b..000000000 --- a/crates/ra_hir_def/src/expr.rs +++ /dev/null | |||
@@ -1,420 +0,0 @@ | |||
1 | //! This module describes hir-level representation of expressions. | ||
2 | //! | ||
3 | //! This representaion is: | ||
4 | //! | ||
5 | //! 1. Identity-based. Each expression has an `id`, so we can distinguish | ||
6 | //! between different `1` in `1 + 1`. | ||
7 | //! 2. Independent of syntax. Though syntactic provenance information can be | ||
8 | //! attached separately via id-based side map. | ||
9 | //! 3. Unresolved. Paths are stored as sequences of names, and not as defs the | ||
10 | //! names refer to. | ||
11 | //! 4. Desugared. There's no `if let`. | ||
12 | //! | ||
13 | //! See also a neighboring `body` module. | ||
14 | |||
15 | use hir_expand::name::Name; | ||
16 | use ra_arena::{Idx, RawId}; | ||
17 | use ra_syntax::ast::RangeOp; | ||
18 | |||
19 | use crate::{ | ||
20 | builtin_type::{BuiltinFloat, BuiltinInt}, | ||
21 | path::{GenericArgs, Path}, | ||
22 | type_ref::{Mutability, Rawness, TypeRef}, | ||
23 | }; | ||
24 | |||
25 | pub type ExprId = Idx<Expr>; | ||
26 | pub(crate) fn dummy_expr_id() -> ExprId { | ||
27 | ExprId::from_raw(RawId::from(!0)) | ||
28 | } | ||
29 | |||
30 | pub type PatId = Idx<Pat>; | ||
31 | |||
32 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
33 | pub enum Literal { | ||
34 | String(String), | ||
35 | ByteString(Vec<u8>), | ||
36 | Char(char), | ||
37 | Bool(bool), | ||
38 | Int(u64, Option<BuiltinInt>), | ||
39 | Float(u64, Option<BuiltinFloat>), // FIXME: f64 is not Eq | ||
40 | } | ||
41 | |||
42 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
43 | pub enum Expr { | ||
44 | /// This is produced if the syntax tree does not have a required expression piece. | ||
45 | Missing, | ||
46 | Path(Path), | ||
47 | If { | ||
48 | condition: ExprId, | ||
49 | then_branch: ExprId, | ||
50 | else_branch: Option<ExprId>, | ||
51 | }, | ||
52 | Block { | ||
53 | statements: Vec<Statement>, | ||
54 | tail: Option<ExprId>, | ||
55 | label: Option<Name>, | ||
56 | }, | ||
57 | Loop { | ||
58 | body: ExprId, | ||
59 | label: Option<Name>, | ||
60 | }, | ||
61 | While { | ||
62 | condition: ExprId, | ||
63 | body: ExprId, | ||
64 | label: Option<Name>, | ||
65 | }, | ||
66 | For { | ||
67 | iterable: ExprId, | ||
68 | pat: PatId, | ||
69 | body: ExprId, | ||
70 | label: Option<Name>, | ||
71 | }, | ||
72 | Call { | ||
73 | callee: ExprId, | ||
74 | args: Vec<ExprId>, | ||
75 | }, | ||
76 | MethodCall { | ||
77 | receiver: ExprId, | ||
78 | method_name: Name, | ||
79 | args: Vec<ExprId>, | ||
80 | generic_args: Option<GenericArgs>, | ||
81 | }, | ||
82 | Match { | ||
83 | expr: ExprId, | ||
84 | arms: Vec<MatchArm>, | ||
85 | }, | ||
86 | Continue { | ||
87 | label: Option<Name>, | ||
88 | }, | ||
89 | Break { | ||
90 | expr: Option<ExprId>, | ||
91 | label: Option<Name>, | ||
92 | }, | ||
93 | Return { | ||
94 | expr: Option<ExprId>, | ||
95 | }, | ||
96 | RecordLit { | ||
97 | path: Option<Path>, | ||
98 | fields: Vec<RecordLitField>, | ||
99 | spread: Option<ExprId>, | ||
100 | }, | ||
101 | Field { | ||
102 | expr: ExprId, | ||
103 | name: Name, | ||
104 | }, | ||
105 | Await { | ||
106 | expr: ExprId, | ||
107 | }, | ||
108 | Try { | ||
109 | expr: ExprId, | ||
110 | }, | ||
111 | TryBlock { | ||
112 | body: ExprId, | ||
113 | }, | ||
114 | Cast { | ||
115 | expr: ExprId, | ||
116 | type_ref: TypeRef, | ||
117 | }, | ||
118 | Ref { | ||
119 | expr: ExprId, | ||
120 | rawness: Rawness, | ||
121 | mutability: Mutability, | ||
122 | }, | ||
123 | Box { | ||
124 | expr: ExprId, | ||
125 | }, | ||
126 | UnaryOp { | ||
127 | expr: ExprId, | ||
128 | op: UnaryOp, | ||
129 | }, | ||
130 | BinaryOp { | ||
131 | lhs: ExprId, | ||
132 | rhs: ExprId, | ||
133 | op: Option<BinaryOp>, | ||
134 | }, | ||
135 | Range { | ||
136 | lhs: Option<ExprId>, | ||
137 | rhs: Option<ExprId>, | ||
138 | range_type: RangeOp, | ||
139 | }, | ||
140 | Index { | ||
141 | base: ExprId, | ||
142 | index: ExprId, | ||
143 | }, | ||
144 | Lambda { | ||
145 | args: Vec<PatId>, | ||
146 | arg_types: Vec<Option<TypeRef>>, | ||
147 | ret_type: Option<TypeRef>, | ||
148 | body: ExprId, | ||
149 | }, | ||
150 | Tuple { | ||
151 | exprs: Vec<ExprId>, | ||
152 | }, | ||
153 | Unsafe { | ||
154 | body: ExprId, | ||
155 | }, | ||
156 | Array(Array), | ||
157 | Literal(Literal), | ||
158 | } | ||
159 | |||
160 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
161 | pub enum BinaryOp { | ||
162 | LogicOp(LogicOp), | ||
163 | ArithOp(ArithOp), | ||
164 | CmpOp(CmpOp), | ||
165 | Assignment { op: Option<ArithOp> }, | ||
166 | } | ||
167 | |||
168 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
169 | pub enum LogicOp { | ||
170 | And, | ||
171 | Or, | ||
172 | } | ||
173 | |||
174 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
175 | pub enum CmpOp { | ||
176 | Eq { negated: bool }, | ||
177 | Ord { ordering: Ordering, strict: bool }, | ||
178 | } | ||
179 | |||
180 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
181 | pub enum Ordering { | ||
182 | Less, | ||
183 | Greater, | ||
184 | } | ||
185 | |||
186 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
187 | pub enum ArithOp { | ||
188 | Add, | ||
189 | Mul, | ||
190 | Sub, | ||
191 | Div, | ||
192 | Rem, | ||
193 | Shl, | ||
194 | Shr, | ||
195 | BitXor, | ||
196 | BitOr, | ||
197 | BitAnd, | ||
198 | } | ||
199 | |||
200 | pub use ra_syntax::ast::PrefixOp as UnaryOp; | ||
201 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
202 | pub enum Array { | ||
203 | ElementList(Vec<ExprId>), | ||
204 | Repeat { initializer: ExprId, repeat: ExprId }, | ||
205 | } | ||
206 | |||
207 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
208 | pub struct MatchArm { | ||
209 | pub pat: PatId, | ||
210 | pub guard: Option<ExprId>, | ||
211 | pub expr: ExprId, | ||
212 | } | ||
213 | |||
214 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
215 | pub struct RecordLitField { | ||
216 | pub name: Name, | ||
217 | pub expr: ExprId, | ||
218 | } | ||
219 | |||
220 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
221 | pub enum Statement { | ||
222 | Let { pat: PatId, type_ref: Option<TypeRef>, initializer: Option<ExprId> }, | ||
223 | Expr(ExprId), | ||
224 | } | ||
225 | |||
226 | impl Expr { | ||
227 | pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) { | ||
228 | match self { | ||
229 | Expr::Missing => {} | ||
230 | Expr::Path(_) => {} | ||
231 | Expr::If { condition, then_branch, else_branch } => { | ||
232 | f(*condition); | ||
233 | f(*then_branch); | ||
234 | if let Some(else_branch) = else_branch { | ||
235 | f(*else_branch); | ||
236 | } | ||
237 | } | ||
238 | Expr::Block { statements, tail, .. } => { | ||
239 | for stmt in statements { | ||
240 | match stmt { | ||
241 | Statement::Let { initializer, .. } => { | ||
242 | if let Some(expr) = initializer { | ||
243 | f(*expr); | ||
244 | } | ||
245 | } | ||
246 | Statement::Expr(e) => f(*e), | ||
247 | } | ||
248 | } | ||
249 | if let Some(expr) = tail { | ||
250 | f(*expr); | ||
251 | } | ||
252 | } | ||
253 | Expr::TryBlock { body } | Expr::Unsafe { body } => f(*body), | ||
254 | Expr::Loop { body, .. } => f(*body), | ||
255 | Expr::While { condition, body, .. } => { | ||
256 | f(*condition); | ||
257 | f(*body); | ||
258 | } | ||
259 | Expr::For { iterable, body, .. } => { | ||
260 | f(*iterable); | ||
261 | f(*body); | ||
262 | } | ||
263 | Expr::Call { callee, args } => { | ||
264 | f(*callee); | ||
265 | for arg in args { | ||
266 | f(*arg); | ||
267 | } | ||
268 | } | ||
269 | Expr::MethodCall { receiver, args, .. } => { | ||
270 | f(*receiver); | ||
271 | for arg in args { | ||
272 | f(*arg); | ||
273 | } | ||
274 | } | ||
275 | Expr::Match { expr, arms } => { | ||
276 | f(*expr); | ||
277 | for arm in arms { | ||
278 | f(arm.expr); | ||
279 | } | ||
280 | } | ||
281 | Expr::Continue { .. } => {} | ||
282 | Expr::Break { expr, .. } | Expr::Return { expr } => { | ||
283 | if let Some(expr) = expr { | ||
284 | f(*expr); | ||
285 | } | ||
286 | } | ||
287 | Expr::RecordLit { fields, spread, .. } => { | ||
288 | for field in fields { | ||
289 | f(field.expr); | ||
290 | } | ||
291 | if let Some(expr) = spread { | ||
292 | f(*expr); | ||
293 | } | ||
294 | } | ||
295 | Expr::Lambda { body, .. } => { | ||
296 | f(*body); | ||
297 | } | ||
298 | Expr::BinaryOp { lhs, rhs, .. } => { | ||
299 | f(*lhs); | ||
300 | f(*rhs); | ||
301 | } | ||
302 | Expr::Range { lhs, rhs, .. } => { | ||
303 | if let Some(lhs) = rhs { | ||
304 | f(*lhs); | ||
305 | } | ||
306 | if let Some(rhs) = lhs { | ||
307 | f(*rhs); | ||
308 | } | ||
309 | } | ||
310 | Expr::Index { base, index } => { | ||
311 | f(*base); | ||
312 | f(*index); | ||
313 | } | ||
314 | Expr::Field { expr, .. } | ||
315 | | Expr::Await { expr } | ||
316 | | Expr::Try { expr } | ||
317 | | Expr::Cast { expr, .. } | ||
318 | | Expr::Ref { expr, .. } | ||
319 | | Expr::UnaryOp { expr, .. } | ||
320 | | Expr::Box { expr } => { | ||
321 | f(*expr); | ||
322 | } | ||
323 | Expr::Tuple { exprs } => { | ||
324 | for expr in exprs { | ||
325 | f(*expr); | ||
326 | } | ||
327 | } | ||
328 | Expr::Array(a) => match a { | ||
329 | Array::ElementList(exprs) => { | ||
330 | for expr in exprs { | ||
331 | f(*expr); | ||
332 | } | ||
333 | } | ||
334 | Array::Repeat { initializer, repeat } => { | ||
335 | f(*initializer); | ||
336 | f(*repeat) | ||
337 | } | ||
338 | }, | ||
339 | Expr::Literal(_) => {} | ||
340 | } | ||
341 | } | ||
342 | } | ||
343 | |||
344 | /// Explicit binding annotations given in the HIR for a binding. Note | ||
345 | /// that this is not the final binding *mode* that we infer after type | ||
346 | /// inference. | ||
347 | #[derive(Clone, PartialEq, Eq, Debug, Copy)] | ||
348 | pub enum BindingAnnotation { | ||
349 | /// No binding annotation given: this means that the final binding mode | ||
350 | /// will depend on whether we have skipped through a `&` reference | ||
351 | /// when matching. For example, the `x` in `Some(x)` will have binding | ||
352 | /// mode `None`; if you do `let Some(x) = &Some(22)`, it will | ||
353 | /// ultimately be inferred to be by-reference. | ||
354 | Unannotated, | ||
355 | |||
356 | /// Annotated with `mut x` -- could be either ref or not, similar to `None`. | ||
357 | Mutable, | ||
358 | |||
359 | /// Annotated as `ref`, like `ref x` | ||
360 | Ref, | ||
361 | |||
362 | /// Annotated as `ref mut x`. | ||
363 | RefMut, | ||
364 | } | ||
365 | |||
366 | impl BindingAnnotation { | ||
367 | pub fn new(is_mutable: bool, is_ref: bool) -> Self { | ||
368 | match (is_mutable, is_ref) { | ||
369 | (true, true) => BindingAnnotation::RefMut, | ||
370 | (false, true) => BindingAnnotation::Ref, | ||
371 | (true, false) => BindingAnnotation::Mutable, | ||
372 | (false, false) => BindingAnnotation::Unannotated, | ||
373 | } | ||
374 | } | ||
375 | } | ||
376 | |||
377 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
378 | pub struct RecordFieldPat { | ||
379 | pub name: Name, | ||
380 | pub pat: PatId, | ||
381 | } | ||
382 | |||
383 | /// Close relative to rustc's hir::PatKind | ||
384 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
385 | pub enum Pat { | ||
386 | Missing, | ||
387 | Wild, | ||
388 | Tuple { args: Vec<PatId>, ellipsis: Option<usize> }, | ||
389 | Or(Vec<PatId>), | ||
390 | Record { path: Option<Path>, args: Vec<RecordFieldPat>, ellipsis: bool }, | ||
391 | Range { start: ExprId, end: ExprId }, | ||
392 | Slice { prefix: Vec<PatId>, slice: Option<PatId>, suffix: Vec<PatId> }, | ||
393 | Path(Path), | ||
394 | Lit(ExprId), | ||
395 | Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, | ||
396 | TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, | ||
397 | Ref { pat: PatId, mutability: Mutability }, | ||
398 | } | ||
399 | |||
400 | impl Pat { | ||
401 | pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { | ||
402 | match self { | ||
403 | Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) | Pat::Wild | Pat::Missing => {} | ||
404 | Pat::Bind { subpat, .. } => { | ||
405 | subpat.iter().copied().for_each(f); | ||
406 | } | ||
407 | Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => { | ||
408 | args.iter().copied().for_each(f); | ||
409 | } | ||
410 | Pat::Ref { pat, .. } => f(*pat), | ||
411 | Pat::Slice { prefix, slice, suffix } => { | ||
412 | let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter()); | ||
413 | total_iter.copied().for_each(f); | ||
414 | } | ||
415 | Pat::Record { args, .. } => { | ||
416 | args.iter().map(|f| f.pat).for_each(f); | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | } | ||
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs deleted file mode 100644 index 06701a830..000000000 --- a/crates/ra_hir_def/src/find_path.rs +++ /dev/null | |||
@@ -1,691 +0,0 @@ | |||
1 | //! An algorithm to find a path to refer to a certain item. | ||
2 | |||
3 | use hir_expand::name::{known, AsName, Name}; | ||
4 | use ra_prof::profile; | ||
5 | use rustc_hash::FxHashSet; | ||
6 | use test_utils::mark; | ||
7 | |||
8 | use crate::{ | ||
9 | db::DefDatabase, | ||
10 | item_scope::ItemInNs, | ||
11 | path::{ModPath, PathKind}, | ||
12 | visibility::Visibility, | ||
13 | ModuleDefId, ModuleId, | ||
14 | }; | ||
15 | |||
16 | // FIXME: handle local items | ||
17 | |||
18 | /// Find a path that can be used to refer to a certain item. This can depend on | ||
19 | /// *from where* you're referring to the item, hence the `from` parameter. | ||
20 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { | ||
21 | let _p = profile("find_path"); | ||
22 | find_path_inner(db, item, from, MAX_PATH_LEN) | ||
23 | } | ||
24 | |||
25 | const MAX_PATH_LEN: usize = 15; | ||
26 | |||
27 | impl ModPath { | ||
28 | fn starts_with_std(&self) -> bool { | ||
29 | self.segments.first() == Some(&known::std) | ||
30 | } | ||
31 | |||
32 | // When std library is present, paths starting with `std::` | ||
33 | // should be preferred over paths starting with `core::` and `alloc::` | ||
34 | fn can_start_with_std(&self) -> bool { | ||
35 | let first_segment = self.segments.first(); | ||
36 | first_segment == Some(&known::alloc) || first_segment == Some(&known::core) | ||
37 | } | ||
38 | } | ||
39 | |||
40 | fn find_path_inner( | ||
41 | db: &dyn DefDatabase, | ||
42 | item: ItemInNs, | ||
43 | from: ModuleId, | ||
44 | max_len: usize, | ||
45 | ) -> Option<ModPath> { | ||
46 | if max_len == 0 { | ||
47 | return None; | ||
48 | } | ||
49 | |||
50 | // Base cases: | ||
51 | |||
52 | // - if the item is already in scope, return the name under which it is | ||
53 | let def_map = db.crate_def_map(from.krate); | ||
54 | let from_scope: &crate::item_scope::ItemScope = &def_map.modules[from.local_id].scope; | ||
55 | if let Some((name, _)) = from_scope.name_of(item) { | ||
56 | return Some(ModPath::from_segments(PathKind::Plain, vec![name.clone()])); | ||
57 | } | ||
58 | |||
59 | // - if the item is the crate root, return `crate` | ||
60 | if item | ||
61 | == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { | ||
62 | krate: from.krate, | ||
63 | local_id: def_map.root, | ||
64 | })) | ||
65 | { | ||
66 | return Some(ModPath::from_segments(PathKind::Crate, Vec::new())); | ||
67 | } | ||
68 | |||
69 | // - if the item is the module we're in, use `self` | ||
70 | if item == ItemInNs::Types(from.into()) { | ||
71 | return Some(ModPath::from_segments(PathKind::Super(0), Vec::new())); | ||
72 | } | ||
73 | |||
74 | // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) | ||
75 | if let Some(parent_id) = def_map.modules[from.local_id].parent { | ||
76 | if item | ||
77 | == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { | ||
78 | krate: from.krate, | ||
79 | local_id: parent_id, | ||
80 | })) | ||
81 | { | ||
82 | return Some(ModPath::from_segments(PathKind::Super(1), Vec::new())); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | // - if the item is the crate root of a dependency crate, return the name from the extern prelude | ||
87 | for (name, def_id) in &def_map.extern_prelude { | ||
88 | if item == ItemInNs::Types(*def_id) { | ||
89 | return Some(ModPath::from_segments(PathKind::Plain, vec![name.clone()])); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | // - if the item is in the prelude, return the name from there | ||
94 | if let Some(prelude_module) = def_map.prelude { | ||
95 | let prelude_def_map = db.crate_def_map(prelude_module.krate); | ||
96 | let prelude_scope: &crate::item_scope::ItemScope = | ||
97 | &prelude_def_map.modules[prelude_module.local_id].scope; | ||
98 | if let Some((name, vis)) = prelude_scope.name_of(item) { | ||
99 | if vis.is_visible_from(db, from) { | ||
100 | return Some(ModPath::from_segments(PathKind::Plain, vec![name.clone()])); | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | |||
105 | // - if the item is a builtin, it's in scope | ||
106 | if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item { | ||
107 | return Some(ModPath::from_segments(PathKind::Plain, vec![builtin.as_name()])); | ||
108 | } | ||
109 | |||
110 | // Recursive case: | ||
111 | // - if the item is an enum variant, refer to it via the enum | ||
112 | if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() { | ||
113 | if let Some(mut path) = find_path(db, ItemInNs::Types(variant.parent.into()), from) { | ||
114 | let data = db.enum_data(variant.parent); | ||
115 | path.segments.push(data.variants[variant.local_id].name.clone()); | ||
116 | return Some(path); | ||
117 | } | ||
118 | // If this doesn't work, it seems we have no way of referring to the | ||
119 | // enum; that's very weird, but there might still be a reexport of the | ||
120 | // variant somewhere | ||
121 | } | ||
122 | |||
123 | // - otherwise, look for modules containing (reexporting) it and import it from one of those | ||
124 | |||
125 | let crate_root = ModuleId { local_id: def_map.root, krate: from.krate }; | ||
126 | let crate_attrs = db.attrs(crate_root.into()); | ||
127 | let prefer_no_std = crate_attrs.by_key("no_std").exists(); | ||
128 | let mut best_path = None; | ||
129 | let mut best_path_len = max_len; | ||
130 | |||
131 | if item.krate(db) == Some(from.krate) { | ||
132 | // Item was defined in the same crate that wants to import it. It cannot be found in any | ||
133 | // dependency in this case. | ||
134 | |||
135 | let local_imports = find_local_import_locations(db, item, from); | ||
136 | for (module_id, name) in local_imports { | ||
137 | if let Some(mut path) = find_path_inner( | ||
138 | db, | ||
139 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), | ||
140 | from, | ||
141 | best_path_len - 1, | ||
142 | ) { | ||
143 | path.segments.push(name); | ||
144 | |||
145 | let new_path = if let Some(best_path) = best_path { | ||
146 | select_best_path(best_path, path, prefer_no_std) | ||
147 | } else { | ||
148 | path | ||
149 | }; | ||
150 | best_path_len = new_path.len(); | ||
151 | best_path = Some(new_path); | ||
152 | } | ||
153 | } | ||
154 | } else { | ||
155 | // Item was defined in some upstream crate. This means that it must be exported from one, | ||
156 | // too (unless we can't name it at all). It could *also* be (re)exported by the same crate | ||
157 | // that wants to import it here, but we always prefer to use the external path here. | ||
158 | |||
159 | let crate_graph = db.crate_graph(); | ||
160 | let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| { | ||
161 | let import_map = db.import_map(dep.crate_id); | ||
162 | import_map.import_info_for(item).and_then(|info| { | ||
163 | // Determine best path for containing module and append last segment from `info`. | ||
164 | let mut path = find_path_inner( | ||
165 | db, | ||
166 | ItemInNs::Types(ModuleDefId::ModuleId(info.container)), | ||
167 | from, | ||
168 | best_path_len - 1, | ||
169 | )?; | ||
170 | path.segments.push(info.path.segments.last().unwrap().clone()); | ||
171 | Some(path) | ||
172 | }) | ||
173 | }); | ||
174 | |||
175 | for path in extern_paths { | ||
176 | let new_path = if let Some(best_path) = best_path { | ||
177 | select_best_path(best_path, path, prefer_no_std) | ||
178 | } else { | ||
179 | path | ||
180 | }; | ||
181 | best_path = Some(new_path); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | best_path | ||
186 | } | ||
187 | |||
188 | fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath { | ||
189 | if old_path.starts_with_std() && new_path.can_start_with_std() { | ||
190 | if prefer_no_std { | ||
191 | mark::hit!(prefer_no_std_paths); | ||
192 | new_path | ||
193 | } else { | ||
194 | mark::hit!(prefer_std_paths); | ||
195 | old_path | ||
196 | } | ||
197 | } else if new_path.starts_with_std() && old_path.can_start_with_std() { | ||
198 | if prefer_no_std { | ||
199 | mark::hit!(prefer_no_std_paths); | ||
200 | old_path | ||
201 | } else { | ||
202 | mark::hit!(prefer_std_paths); | ||
203 | new_path | ||
204 | } | ||
205 | } else if new_path.len() < old_path.len() { | ||
206 | new_path | ||
207 | } else { | ||
208 | old_path | ||
209 | } | ||
210 | } | ||
211 | |||
212 | /// Finds locations in `from.krate` from which `item` can be imported by `from`. | ||
213 | fn find_local_import_locations( | ||
214 | db: &dyn DefDatabase, | ||
215 | item: ItemInNs, | ||
216 | from: ModuleId, | ||
217 | ) -> Vec<(ModuleId, Name)> { | ||
218 | let _p = profile("find_local_import_locations"); | ||
219 | |||
220 | // `from` can import anything below `from` with visibility of at least `from`, and anything | ||
221 | // above `from` with any visibility. That means we do not need to descend into private siblings | ||
222 | // of `from` (and similar). | ||
223 | |||
224 | let def_map = db.crate_def_map(from.krate); | ||
225 | |||
226 | // Compute the initial worklist. We start with all direct child modules of `from` as well as all | ||
227 | // of its (recursive) parent modules. | ||
228 | let data = &def_map.modules[from.local_id]; | ||
229 | let mut worklist = data | ||
230 | .children | ||
231 | .values() | ||
232 | .map(|child| ModuleId { krate: from.krate, local_id: *child }) | ||
233 | .collect::<Vec<_>>(); | ||
234 | let mut parent = data.parent; | ||
235 | while let Some(p) = parent { | ||
236 | worklist.push(ModuleId { krate: from.krate, local_id: p }); | ||
237 | parent = def_map.modules[p].parent; | ||
238 | } | ||
239 | |||
240 | let mut seen: FxHashSet<_> = FxHashSet::default(); | ||
241 | |||
242 | let mut locations = Vec::new(); | ||
243 | while let Some(module) = worklist.pop() { | ||
244 | if !seen.insert(module) { | ||
245 | continue; // already processed this module | ||
246 | } | ||
247 | |||
248 | let ext_def_map; | ||
249 | let data = if module.krate == from.krate { | ||
250 | &def_map[module.local_id] | ||
251 | } else { | ||
252 | // The crate might reexport a module defined in another crate. | ||
253 | ext_def_map = db.crate_def_map(module.krate); | ||
254 | &ext_def_map[module.local_id] | ||
255 | }; | ||
256 | |||
257 | if let Some((name, vis)) = data.scope.name_of(item) { | ||
258 | if vis.is_visible_from(db, from) { | ||
259 | let is_private = if let Visibility::Module(private_to) = vis { | ||
260 | private_to.local_id == module.local_id | ||
261 | } else { | ||
262 | false | ||
263 | }; | ||
264 | let is_original_def = if let Some(module_def_id) = item.as_module_def_id() { | ||
265 | data.scope.declarations().any(|it| it == module_def_id) | ||
266 | } else { | ||
267 | false | ||
268 | }; | ||
269 | |||
270 | // Ignore private imports. these could be used if we are | ||
271 | // in a submodule of this module, but that's usually not | ||
272 | // what the user wants; and if this module can import | ||
273 | // the item and we're a submodule of it, so can we. | ||
274 | // Also this keeps the cached data smaller. | ||
275 | if !is_private || is_original_def { | ||
276 | locations.push((module, name.clone())); | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | |||
281 | // Descend into all modules visible from `from`. | ||
282 | for (_, per_ns) in data.scope.entries() { | ||
283 | if let Some((ModuleDefId::ModuleId(module), vis)) = per_ns.take_types_vis() { | ||
284 | if vis.is_visible_from(db, from) { | ||
285 | worklist.push(module); | ||
286 | } | ||
287 | } | ||
288 | } | ||
289 | } | ||
290 | |||
291 | locations | ||
292 | } | ||
293 | |||
294 | #[cfg(test)] | ||
295 | mod tests { | ||
296 | use hir_expand::hygiene::Hygiene; | ||
297 | use ra_db::fixture::WithFixture; | ||
298 | use ra_syntax::ast::AstNode; | ||
299 | use test_utils::mark; | ||
300 | |||
301 | use crate::test_db::TestDB; | ||
302 | |||
303 | use super::*; | ||
304 | |||
305 | /// `code` needs to contain a cursor marker; checks that `find_path` for the | ||
306 | /// item the `path` refers to returns that same path when called from the | ||
307 | /// module the cursor is in. | ||
308 | fn check_found_path(ra_fixture: &str, path: &str) { | ||
309 | let (db, pos) = TestDB::with_position(ra_fixture); | ||
310 | let module = db.module_for_file(pos.file_id); | ||
311 | let parsed_path_file = ra_syntax::SourceFile::parse(&format!("use {};", path)); | ||
312 | let ast_path = parsed_path_file | ||
313 | .syntax_node() | ||
314 | .descendants() | ||
315 | .find_map(ra_syntax::ast::Path::cast) | ||
316 | .unwrap(); | ||
317 | let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap(); | ||
318 | |||
319 | let crate_def_map = db.crate_def_map(module.krate); | ||
320 | let resolved = crate_def_map | ||
321 | .resolve_path( | ||
322 | &db, | ||
323 | module.local_id, | ||
324 | &mod_path, | ||
325 | crate::item_scope::BuiltinShadowMode::Module, | ||
326 | ) | ||
327 | .0 | ||
328 | .take_types() | ||
329 | .unwrap(); | ||
330 | |||
331 | let found_path = find_path(&db, ItemInNs::Types(resolved), module); | ||
332 | |||
333 | assert_eq!(found_path, Some(mod_path)); | ||
334 | } | ||
335 | |||
336 | #[test] | ||
337 | fn same_module() { | ||
338 | let code = r#" | ||
339 | //- /main.rs | ||
340 | struct S; | ||
341 | <|> | ||
342 | "#; | ||
343 | check_found_path(code, "S"); | ||
344 | } | ||
345 | |||
346 | #[test] | ||
347 | fn enum_variant() { | ||
348 | let code = r#" | ||
349 | //- /main.rs | ||
350 | enum E { A } | ||
351 | <|> | ||
352 | "#; | ||
353 | check_found_path(code, "E::A"); | ||
354 | } | ||
355 | |||
356 | #[test] | ||
357 | fn sub_module() { | ||
358 | let code = r#" | ||
359 | //- /main.rs | ||
360 | mod foo { | ||
361 | pub struct S; | ||
362 | } | ||
363 | <|> | ||
364 | "#; | ||
365 | check_found_path(code, "foo::S"); | ||
366 | } | ||
367 | |||
368 | #[test] | ||
369 | fn super_module() { | ||
370 | let code = r#" | ||
371 | //- /main.rs | ||
372 | mod foo; | ||
373 | //- /foo.rs | ||
374 | mod bar; | ||
375 | struct S; | ||
376 | //- /foo/bar.rs | ||
377 | <|> | ||
378 | "#; | ||
379 | check_found_path(code, "super::S"); | ||
380 | } | ||
381 | |||
382 | #[test] | ||
383 | fn self_module() { | ||
384 | let code = r#" | ||
385 | //- /main.rs | ||
386 | mod foo; | ||
387 | //- /foo.rs | ||
388 | <|> | ||
389 | "#; | ||
390 | check_found_path(code, "self"); | ||
391 | } | ||
392 | |||
393 | #[test] | ||
394 | fn crate_root() { | ||
395 | let code = r#" | ||
396 | //- /main.rs | ||
397 | mod foo; | ||
398 | //- /foo.rs | ||
399 | <|> | ||
400 | "#; | ||
401 | check_found_path(code, "crate"); | ||
402 | } | ||
403 | |||
404 | #[test] | ||
405 | fn same_crate() { | ||
406 | let code = r#" | ||
407 | //- /main.rs | ||
408 | mod foo; | ||
409 | struct S; | ||
410 | //- /foo.rs | ||
411 | <|> | ||
412 | "#; | ||
413 | check_found_path(code, "crate::S"); | ||
414 | } | ||
415 | |||
416 | #[test] | ||
417 | fn different_crate() { | ||
418 | let code = r#" | ||
419 | //- /main.rs crate:main deps:std | ||
420 | <|> | ||
421 | //- /std.rs crate:std | ||
422 | pub struct S; | ||
423 | "#; | ||
424 | check_found_path(code, "std::S"); | ||
425 | } | ||
426 | |||
427 | #[test] | ||
428 | fn different_crate_renamed() { | ||
429 | let code = r#" | ||
430 | //- /main.rs crate:main deps:std | ||
431 | extern crate std as std_renamed; | ||
432 | <|> | ||
433 | //- /std.rs crate:std | ||
434 | pub struct S; | ||
435 | "#; | ||
436 | check_found_path(code, "std_renamed::S"); | ||
437 | } | ||
438 | |||
439 | #[test] | ||
440 | fn partially_imported() { | ||
441 | // Tests that short paths are used even for external items, when parts of the path are | ||
442 | // already in scope. | ||
443 | check_found_path( | ||
444 | r#" | ||
445 | //- /main.rs crate:main deps:ra_syntax | ||
446 | |||
447 | use ra_syntax::ast; | ||
448 | <|> | ||
449 | |||
450 | //- /lib.rs crate:ra_syntax | ||
451 | pub mod ast { | ||
452 | pub enum ModuleItem { | ||
453 | A, B, C, | ||
454 | } | ||
455 | } | ||
456 | "#, | ||
457 | "ast::ModuleItem", | ||
458 | ); | ||
459 | |||
460 | check_found_path( | ||
461 | r#" | ||
462 | //- /main.rs crate:main deps:ra_syntax | ||
463 | |||
464 | <|> | ||
465 | |||
466 | //- /lib.rs crate:ra_syntax | ||
467 | pub mod ast { | ||
468 | pub enum ModuleItem { | ||
469 | A, B, C, | ||
470 | } | ||
471 | } | ||
472 | "#, | ||
473 | "ra_syntax::ast::ModuleItem", | ||
474 | ); | ||
475 | } | ||
476 | |||
477 | #[test] | ||
478 | fn same_crate_reexport() { | ||
479 | let code = r#" | ||
480 | //- /main.rs | ||
481 | mod bar { | ||
482 | mod foo { pub(super) struct S; } | ||
483 | pub(crate) use foo::*; | ||
484 | } | ||
485 | <|> | ||
486 | "#; | ||
487 | check_found_path(code, "bar::S"); | ||
488 | } | ||
489 | |||
490 | #[test] | ||
491 | fn same_crate_reexport_rename() { | ||
492 | let code = r#" | ||
493 | //- /main.rs | ||
494 | mod bar { | ||
495 | mod foo { pub(super) struct S; } | ||
496 | pub(crate) use foo::S as U; | ||
497 | } | ||
498 | <|> | ||
499 | "#; | ||
500 | check_found_path(code, "bar::U"); | ||
501 | } | ||
502 | |||
503 | #[test] | ||
504 | fn different_crate_reexport() { | ||
505 | let code = r#" | ||
506 | //- /main.rs crate:main deps:std | ||
507 | <|> | ||
508 | //- /std.rs crate:std deps:core | ||
509 | pub use core::S; | ||
510 | //- /core.rs crate:core | ||
511 | pub struct S; | ||
512 | "#; | ||
513 | check_found_path(code, "std::S"); | ||
514 | } | ||
515 | |||
516 | #[test] | ||
517 | fn prelude() { | ||
518 | let code = r#" | ||
519 | //- /main.rs crate:main deps:std | ||
520 | <|> | ||
521 | //- /std.rs crate:std | ||
522 | pub mod prelude { pub struct S; } | ||
523 | #[prelude_import] | ||
524 | pub use prelude::*; | ||
525 | "#; | ||
526 | check_found_path(code, "S"); | ||
527 | } | ||
528 | |||
529 | #[test] | ||
530 | fn enum_variant_from_prelude() { | ||
531 | let code = r#" | ||
532 | //- /main.rs crate:main deps:std | ||
533 | <|> | ||
534 | //- /std.rs crate:std | ||
535 | pub mod prelude { | ||
536 | pub enum Option<T> { Some(T), None } | ||
537 | pub use Option::*; | ||
538 | } | ||
539 | #[prelude_import] | ||
540 | pub use prelude::*; | ||
541 | "#; | ||
542 | check_found_path(code, "None"); | ||
543 | check_found_path(code, "Some"); | ||
544 | } | ||
545 | |||
546 | #[test] | ||
547 | fn shortest_path() { | ||
548 | let code = r#" | ||
549 | //- /main.rs | ||
550 | pub mod foo; | ||
551 | pub mod baz; | ||
552 | struct S; | ||
553 | <|> | ||
554 | //- /foo.rs | ||
555 | pub mod bar { pub struct S; } | ||
556 | //- /baz.rs | ||
557 | pub use crate::foo::bar::S; | ||
558 | "#; | ||
559 | check_found_path(code, "baz::S"); | ||
560 | } | ||
561 | |||
562 | #[test] | ||
563 | fn discount_private_imports() { | ||
564 | let code = r#" | ||
565 | //- /main.rs | ||
566 | mod foo; | ||
567 | pub mod bar { pub struct S; } | ||
568 | use bar::S; | ||
569 | //- /foo.rs | ||
570 | <|> | ||
571 | "#; | ||
572 | // crate::S would be shorter, but using private imports seems wrong | ||
573 | check_found_path(code, "crate::bar::S"); | ||
574 | } | ||
575 | |||
576 | #[test] | ||
577 | fn import_cycle() { | ||
578 | let code = r#" | ||
579 | //- /main.rs | ||
580 | pub mod foo; | ||
581 | pub mod bar; | ||
582 | pub mod baz; | ||
583 | //- /bar.rs | ||
584 | <|> | ||
585 | //- /foo.rs | ||
586 | pub use super::baz; | ||
587 | pub struct S; | ||
588 | //- /baz.rs | ||
589 | pub use super::foo; | ||
590 | "#; | ||
591 | check_found_path(code, "crate::foo::S"); | ||
592 | } | ||
593 | |||
594 | #[test] | ||
595 | fn prefer_std_paths_over_alloc() { | ||
596 | mark::check!(prefer_std_paths); | ||
597 | let code = r#" | ||
598 | //- /main.rs crate:main deps:alloc,std | ||
599 | <|> | ||
600 | |||
601 | //- /std.rs crate:std deps:alloc | ||
602 | pub mod sync { | ||
603 | pub use alloc::sync::Arc; | ||
604 | } | ||
605 | |||
606 | //- /zzz.rs crate:alloc | ||
607 | pub mod sync { | ||
608 | pub struct Arc; | ||
609 | } | ||
610 | "#; | ||
611 | check_found_path(code, "std::sync::Arc"); | ||
612 | } | ||
613 | |||
614 | #[test] | ||
615 | fn prefer_core_paths_over_std() { | ||
616 | mark::check!(prefer_no_std_paths); | ||
617 | let code = r#" | ||
618 | //- /main.rs crate:main deps:core,std | ||
619 | #![no_std] | ||
620 | |||
621 | <|> | ||
622 | |||
623 | //- /std.rs crate:std deps:core | ||
624 | |||
625 | pub mod fmt { | ||
626 | pub use core::fmt::Error; | ||
627 | } | ||
628 | |||
629 | //- /zzz.rs crate:core | ||
630 | |||
631 | pub mod fmt { | ||
632 | pub struct Error; | ||
633 | } | ||
634 | "#; | ||
635 | check_found_path(code, "core::fmt::Error"); | ||
636 | } | ||
637 | |||
638 | #[test] | ||
639 | fn prefer_alloc_paths_over_std() { | ||
640 | let code = r#" | ||
641 | //- /main.rs crate:main deps:alloc,std | ||
642 | #![no_std] | ||
643 | |||
644 | <|> | ||
645 | |||
646 | //- /std.rs crate:std deps:alloc | ||
647 | |||
648 | pub mod sync { | ||
649 | pub use alloc::sync::Arc; | ||
650 | } | ||
651 | |||
652 | //- /zzz.rs crate:alloc | ||
653 | |||
654 | pub mod sync { | ||
655 | pub struct Arc; | ||
656 | } | ||
657 | "#; | ||
658 | check_found_path(code, "alloc::sync::Arc"); | ||
659 | } | ||
660 | |||
661 | #[test] | ||
662 | fn prefer_shorter_paths_if_not_alloc() { | ||
663 | let code = r#" | ||
664 | //- /main.rs crate:main deps:megaalloc,std | ||
665 | <|> | ||
666 | |||
667 | //- /std.rs crate:std deps:megaalloc | ||
668 | pub mod sync { | ||
669 | pub use megaalloc::sync::Arc; | ||
670 | } | ||
671 | |||
672 | //- /zzz.rs crate:megaalloc | ||
673 | pub struct Arc; | ||
674 | "#; | ||
675 | check_found_path(code, "megaalloc::Arc"); | ||
676 | } | ||
677 | |||
678 | #[test] | ||
679 | fn builtins_are_in_scope() { | ||
680 | let code = r#" | ||
681 | //- /main.rs | ||
682 | <|> | ||
683 | |||
684 | pub mod primitive { | ||
685 | pub use u8; | ||
686 | } | ||
687 | "#; | ||
688 | check_found_path(code, "u8"); | ||
689 | check_found_path(code, "u16"); | ||
690 | } | ||
691 | } | ||
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs deleted file mode 100644 index 699ba9c92..000000000 --- a/crates/ra_hir_def/src/generics.rs +++ /dev/null | |||
@@ -1,340 +0,0 @@ | |||
1 | //! Many kinds of items or constructs can have generic parameters: functions, | ||
2 | //! structs, impls, traits, etc. This module provides a common HIR for these | ||
3 | //! generic parameters. See also the `Generics` type and the `generics_of` query | ||
4 | //! in rustc. | ||
5 | use std::sync::Arc; | ||
6 | |||
7 | use either::Either; | ||
8 | use hir_expand::{ | ||
9 | name::{name, AsName, Name}, | ||
10 | InFile, | ||
11 | }; | ||
12 | use ra_arena::{map::ArenaMap, Arena}; | ||
13 | use ra_db::FileId; | ||
14 | use ra_prof::profile; | ||
15 | use ra_syntax::ast::{self, GenericParamsOwner, NameOwner, TypeBoundsOwner}; | ||
16 | |||
17 | use crate::{ | ||
18 | body::LowerCtx, | ||
19 | child_by_source::ChildBySource, | ||
20 | db::DefDatabase, | ||
21 | dyn_map::DynMap, | ||
22 | keys, | ||
23 | src::HasChildSource, | ||
24 | src::HasSource, | ||
25 | type_ref::{TypeBound, TypeRef}, | ||
26 | AdtId, GenericDefId, LocalTypeParamId, Lookup, TypeParamId, | ||
27 | }; | ||
28 | |||
29 | /// Data about a generic parameter (to a function, struct, impl, ...). | ||
30 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
31 | pub struct TypeParamData { | ||
32 | pub name: Option<Name>, | ||
33 | pub default: Option<TypeRef>, | ||
34 | pub provenance: TypeParamProvenance, | ||
35 | } | ||
36 | |||
37 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | ||
38 | pub enum TypeParamProvenance { | ||
39 | TypeParamList, | ||
40 | TraitSelf, | ||
41 | ArgumentImplTrait, | ||
42 | } | ||
43 | |||
44 | /// Data about the generic parameters of a function, struct, impl, etc. | ||
45 | #[derive(Clone, PartialEq, Eq, Debug, Default)] | ||
46 | pub struct GenericParams { | ||
47 | pub types: Arena<TypeParamData>, | ||
48 | // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>, | ||
49 | pub where_predicates: Vec<WherePredicate>, | ||
50 | } | ||
51 | |||
52 | /// A single predicate from a where clause, i.e. `where Type: Trait`. Combined | ||
53 | /// where clauses like `where T: Foo + Bar` are turned into multiple of these. | ||
54 | /// It might still result in multiple actual predicates though, because of | ||
55 | /// associated type bindings like `Iterator<Item = u32>`. | ||
56 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
57 | pub struct WherePredicate { | ||
58 | pub target: WherePredicateTarget, | ||
59 | pub bound: TypeBound, | ||
60 | } | ||
61 | |||
62 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
63 | pub enum WherePredicateTarget { | ||
64 | TypeRef(TypeRef), | ||
65 | /// For desugared where predicates that can directly refer to a type param. | ||
66 | TypeParam(LocalTypeParamId), | ||
67 | } | ||
68 | |||
69 | type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>; | ||
70 | |||
71 | impl GenericParams { | ||
72 | pub(crate) fn generic_params_query( | ||
73 | db: &dyn DefDatabase, | ||
74 | def: GenericDefId, | ||
75 | ) -> Arc<GenericParams> { | ||
76 | let _p = profile("generic_params_query"); | ||
77 | |||
78 | let generics = match def { | ||
79 | GenericDefId::FunctionId(id) => { | ||
80 | let id = id.lookup(db).id; | ||
81 | let tree = db.item_tree(id.file_id); | ||
82 | let item = &tree[id.value]; | ||
83 | tree[item.generic_params].clone() | ||
84 | } | ||
85 | GenericDefId::AdtId(AdtId::StructId(id)) => { | ||
86 | let id = id.lookup(db).id; | ||
87 | let tree = db.item_tree(id.file_id); | ||
88 | let item = &tree[id.value]; | ||
89 | tree[item.generic_params].clone() | ||
90 | } | ||
91 | GenericDefId::AdtId(AdtId::EnumId(id)) => { | ||
92 | let id = id.lookup(db).id; | ||
93 | let tree = db.item_tree(id.file_id); | ||
94 | let item = &tree[id.value]; | ||
95 | tree[item.generic_params].clone() | ||
96 | } | ||
97 | GenericDefId::AdtId(AdtId::UnionId(id)) => { | ||
98 | let id = id.lookup(db).id; | ||
99 | let tree = db.item_tree(id.file_id); | ||
100 | let item = &tree[id.value]; | ||
101 | tree[item.generic_params].clone() | ||
102 | } | ||
103 | GenericDefId::TraitId(id) => { | ||
104 | let id = id.lookup(db).id; | ||
105 | let tree = db.item_tree(id.file_id); | ||
106 | let item = &tree[id.value]; | ||
107 | tree[item.generic_params].clone() | ||
108 | } | ||
109 | GenericDefId::TypeAliasId(id) => { | ||
110 | let id = id.lookup(db).id; | ||
111 | let tree = db.item_tree(id.file_id); | ||
112 | let item = &tree[id.value]; | ||
113 | tree[item.generic_params].clone() | ||
114 | } | ||
115 | GenericDefId::ImplId(id) => { | ||
116 | let id = id.lookup(db).id; | ||
117 | let tree = db.item_tree(id.file_id); | ||
118 | let item = &tree[id.value]; | ||
119 | tree[item.generic_params].clone() | ||
120 | } | ||
121 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(), | ||
122 | }; | ||
123 | Arc::new(generics) | ||
124 | } | ||
125 | |||
126 | fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { | ||
127 | let mut generics = GenericParams { types: Arena::default(), where_predicates: Vec::new() }; | ||
128 | let mut sm = ArenaMap::default(); | ||
129 | |||
130 | // FIXME: add `: Sized` bound for everything except for `Self` in traits | ||
131 | let file_id = match def { | ||
132 | GenericDefId::FunctionId(it) => { | ||
133 | let src = it.lookup(db).source(db); | ||
134 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
135 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
136 | // lower `impl Trait` in arguments | ||
137 | let data = db.function_data(it); | ||
138 | for param in &data.params { | ||
139 | generics.fill_implicit_impl_trait_args(param); | ||
140 | } | ||
141 | src.file_id | ||
142 | } | ||
143 | GenericDefId::AdtId(AdtId::StructId(it)) => { | ||
144 | let src = it.lookup(db).source(db); | ||
145 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
146 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
147 | src.file_id | ||
148 | } | ||
149 | GenericDefId::AdtId(AdtId::UnionId(it)) => { | ||
150 | let src = it.lookup(db).source(db); | ||
151 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
152 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
153 | src.file_id | ||
154 | } | ||
155 | GenericDefId::AdtId(AdtId::EnumId(it)) => { | ||
156 | let src = it.lookup(db).source(db); | ||
157 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
158 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
159 | src.file_id | ||
160 | } | ||
161 | GenericDefId::TraitId(it) => { | ||
162 | let src = it.lookup(db).source(db); | ||
163 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
164 | |||
165 | // traits get the Self type as an implicit first type parameter | ||
166 | let self_param_id = generics.types.alloc(TypeParamData { | ||
167 | name: Some(name![Self]), | ||
168 | default: None, | ||
169 | provenance: TypeParamProvenance::TraitSelf, | ||
170 | }); | ||
171 | sm.insert(self_param_id, Either::Left(src.value.clone())); | ||
172 | // add super traits as bounds on Self | ||
173 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar | ||
174 | let self_param = TypeRef::Path(name![Self].into()); | ||
175 | generics.fill_bounds(&lower_ctx, &src.value, self_param); | ||
176 | |||
177 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
178 | src.file_id | ||
179 | } | ||
180 | GenericDefId::TypeAliasId(it) => { | ||
181 | let src = it.lookup(db).source(db); | ||
182 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
183 | |||
184 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
185 | src.file_id | ||
186 | } | ||
187 | // Note that we don't add `Self` here: in `impl`s, `Self` is not a | ||
188 | // type-parameter, but rather is a type-alias for impl's target | ||
189 | // type, so this is handled by the resolver. | ||
190 | GenericDefId::ImplId(it) => { | ||
191 | let src = it.lookup(db).source(db); | ||
192 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
193 | |||
194 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
195 | src.file_id | ||
196 | } | ||
197 | // We won't be using this ID anyway | ||
198 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(), | ||
199 | }; | ||
200 | |||
201 | (generics, InFile::new(file_id, sm)) | ||
202 | } | ||
203 | |||
204 | pub(crate) fn fill( | ||
205 | &mut self, | ||
206 | lower_ctx: &LowerCtx, | ||
207 | sm: &mut SourceMap, | ||
208 | node: &dyn GenericParamsOwner, | ||
209 | ) { | ||
210 | if let Some(params) = node.generic_param_list() { | ||
211 | self.fill_params(lower_ctx, sm, params) | ||
212 | } | ||
213 | if let Some(where_clause) = node.where_clause() { | ||
214 | self.fill_where_predicates(lower_ctx, where_clause); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | pub(crate) fn fill_bounds( | ||
219 | &mut self, | ||
220 | lower_ctx: &LowerCtx, | ||
221 | node: &dyn ast::TypeBoundsOwner, | ||
222 | type_ref: TypeRef, | ||
223 | ) { | ||
224 | for bound in | ||
225 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) | ||
226 | { | ||
227 | self.add_where_predicate_from_bound(lower_ctx, bound, type_ref.clone()); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | fn fill_params( | ||
232 | &mut self, | ||
233 | lower_ctx: &LowerCtx, | ||
234 | sm: &mut SourceMap, | ||
235 | params: ast::GenericParamList, | ||
236 | ) { | ||
237 | for type_param in params.type_params() { | ||
238 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); | ||
239 | // FIXME: Use `Path::from_src` | ||
240 | let default = type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it)); | ||
241 | let param = TypeParamData { | ||
242 | name: Some(name.clone()), | ||
243 | default, | ||
244 | provenance: TypeParamProvenance::TypeParamList, | ||
245 | }; | ||
246 | let param_id = self.types.alloc(param); | ||
247 | sm.insert(param_id, Either::Right(type_param.clone())); | ||
248 | |||
249 | let type_ref = TypeRef::Path(name.into()); | ||
250 | self.fill_bounds(&lower_ctx, &type_param, type_ref); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { | ||
255 | for pred in where_clause.predicates() { | ||
256 | let type_ref = match pred.ty() { | ||
257 | Some(type_ref) => type_ref, | ||
258 | None => continue, | ||
259 | }; | ||
260 | let type_ref = TypeRef::from_ast(lower_ctx, type_ref); | ||
261 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { | ||
262 | self.add_where_predicate_from_bound(lower_ctx, bound, type_ref.clone()); | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | |||
267 | fn add_where_predicate_from_bound( | ||
268 | &mut self, | ||
269 | lower_ctx: &LowerCtx, | ||
270 | bound: ast::TypeBound, | ||
271 | type_ref: TypeRef, | ||
272 | ) { | ||
273 | if bound.question_mark_token().is_some() { | ||
274 | // FIXME: remove this bound | ||
275 | return; | ||
276 | } | ||
277 | let bound = TypeBound::from_ast(lower_ctx, bound); | ||
278 | self.where_predicates | ||
279 | .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); | ||
280 | } | ||
281 | |||
282 | pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { | ||
283 | type_ref.walk(&mut |type_ref| { | ||
284 | if let TypeRef::ImplTrait(bounds) = type_ref { | ||
285 | let param = TypeParamData { | ||
286 | name: None, | ||
287 | default: None, | ||
288 | provenance: TypeParamProvenance::ArgumentImplTrait, | ||
289 | }; | ||
290 | let param_id = self.types.alloc(param); | ||
291 | for bound in bounds { | ||
292 | self.where_predicates.push(WherePredicate { | ||
293 | target: WherePredicateTarget::TypeParam(param_id), | ||
294 | bound: bound.clone(), | ||
295 | }); | ||
296 | } | ||
297 | } | ||
298 | }); | ||
299 | } | ||
300 | |||
301 | pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { | ||
302 | self.types | ||
303 | .iter() | ||
304 | .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) | ||
305 | } | ||
306 | |||
307 | pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> { | ||
308 | self.types.iter().find_map(|(id, p)| { | ||
309 | if p.provenance == TypeParamProvenance::TraitSelf { | ||
310 | Some(id) | ||
311 | } else { | ||
312 | None | ||
313 | } | ||
314 | }) | ||
315 | } | ||
316 | } | ||
317 | |||
318 | impl HasChildSource for GenericDefId { | ||
319 | type ChildId = LocalTypeParamId; | ||
320 | type Value = Either<ast::Trait, ast::TypeParam>; | ||
321 | fn child_source(&self, db: &dyn DefDatabase) -> InFile<SourceMap> { | ||
322 | let (_, sm) = GenericParams::new(db, *self); | ||
323 | sm | ||
324 | } | ||
325 | } | ||
326 | |||
327 | impl ChildBySource for GenericDefId { | ||
328 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { | ||
329 | let mut res = DynMap::default(); | ||
330 | let arena_map = self.child_source(db); | ||
331 | let arena_map = arena_map.as_ref(); | ||
332 | for (local_id, src) in arena_map.value.iter() { | ||
333 | let id = TypeParamId { parent: *self, local_id }; | ||
334 | if let Either::Right(type_param) = src { | ||
335 | res[keys::TYPE_PARAM].insert(arena_map.with_value(type_param.clone()), id) | ||
336 | } | ||
337 | } | ||
338 | res | ||
339 | } | ||
340 | } | ||
diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs deleted file mode 100644 index 9e4c30b1a..000000000 --- a/crates/ra_hir_def/src/import_map.rs +++ /dev/null | |||
@@ -1,745 +0,0 @@ | |||
1 | //! A map of all publicly exported items in a crate. | ||
2 | |||
3 | use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc}; | ||
4 | |||
5 | use fst::{self, Streamer}; | ||
6 | use indexmap::{map::Entry, IndexMap}; | ||
7 | use ra_db::CrateId; | ||
8 | use ra_syntax::SmolStr; | ||
9 | use rustc_hash::{FxHashMap, FxHasher}; | ||
10 | use smallvec::SmallVec; | ||
11 | |||
12 | use crate::{ | ||
13 | db::DefDatabase, | ||
14 | item_scope::ItemInNs, | ||
15 | path::{ModPath, PathKind}, | ||
16 | visibility::Visibility, | ||
17 | AssocItemId, ModuleDefId, ModuleId, TraitId, | ||
18 | }; | ||
19 | |||
20 | type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>; | ||
21 | |||
22 | /// Item import details stored in the `ImportMap`. | ||
23 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
24 | pub struct ImportInfo { | ||
25 | /// A path that can be used to import the item, relative to the crate's root. | ||
26 | pub path: ModPath, | ||
27 | /// The module containing this item. | ||
28 | pub container: ModuleId, | ||
29 | } | ||
30 | |||
31 | /// A map from publicly exported items to the path needed to import/name them from a downstream | ||
32 | /// crate. | ||
33 | /// | ||
34 | /// Reexports of items are taken into account, ie. if something is exported under multiple | ||
35 | /// names, the one with the shortest import path will be used. | ||
36 | /// | ||
37 | /// Note that all paths are relative to the containing crate's root, so the crate name still needs | ||
38 | /// to be prepended to the `ModPath` before the path is valid. | ||
39 | #[derive(Default)] | ||
40 | pub struct ImportMap { | ||
41 | map: FxIndexMap<ItemInNs, ImportInfo>, | ||
42 | |||
43 | /// List of keys stored in `map`, sorted lexicographically by their `ModPath`. Indexed by the | ||
44 | /// values returned by running `fst`. | ||
45 | /// | ||
46 | /// Since a path can refer to multiple items due to namespacing, we store all items with the | ||
47 | /// same path right after each other. This allows us to find all items after the FST gives us | ||
48 | /// the index of the first one. | ||
49 | importables: Vec<ItemInNs>, | ||
50 | fst: fst::Map<Vec<u8>>, | ||
51 | |||
52 | /// Maps names of associated items to the item's ID. Only includes items whose defining trait is | ||
53 | /// exported. | ||
54 | assoc_map: FxHashMap<SmolStr, SmallVec<[AssocItemId; 1]>>, | ||
55 | } | ||
56 | |||
57 | impl ImportMap { | ||
58 | pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { | ||
59 | let _p = ra_prof::profile("import_map_query"); | ||
60 | let def_map = db.crate_def_map(krate); | ||
61 | let mut import_map = Self::default(); | ||
62 | |||
63 | // We look only into modules that are public(ly reexported), starting with the crate root. | ||
64 | let empty = ModPath { kind: PathKind::Plain, segments: vec![] }; | ||
65 | let root = ModuleId { krate, local_id: def_map.root }; | ||
66 | let mut worklist = vec![(root, empty)]; | ||
67 | while let Some((module, mod_path)) = worklist.pop() { | ||
68 | let ext_def_map; | ||
69 | let mod_data = if module.krate == krate { | ||
70 | &def_map[module.local_id] | ||
71 | } else { | ||
72 | // The crate might reexport a module defined in another crate. | ||
73 | ext_def_map = db.crate_def_map(module.krate); | ||
74 | &ext_def_map[module.local_id] | ||
75 | }; | ||
76 | |||
77 | let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| { | ||
78 | let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public); | ||
79 | if per_ns.is_none() { | ||
80 | None | ||
81 | } else { | ||
82 | Some((name, per_ns)) | ||
83 | } | ||
84 | }); | ||
85 | |||
86 | for (name, per_ns) in visible_items { | ||
87 | let mk_path = || { | ||
88 | let mut path = mod_path.clone(); | ||
89 | path.segments.push(name.clone()); | ||
90 | path | ||
91 | }; | ||
92 | |||
93 | for item in per_ns.iter_items() { | ||
94 | let path = mk_path(); | ||
95 | match import_map.map.entry(item) { | ||
96 | Entry::Vacant(entry) => { | ||
97 | entry.insert(ImportInfo { path, container: module }); | ||
98 | } | ||
99 | Entry::Occupied(mut entry) => { | ||
100 | // If the new path is shorter, prefer that one. | ||
101 | if path.len() < entry.get().path.len() { | ||
102 | *entry.get_mut() = ImportInfo { path, container: module }; | ||
103 | } else { | ||
104 | continue; | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | |||
109 | // If we've just added a path to a module, descend into it. We might traverse | ||
110 | // modules multiple times, but only if the new path to it is shorter than the | ||
111 | // first (else we `continue` above). | ||
112 | if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { | ||
113 | worklist.push((mod_id, mk_path())); | ||
114 | } | ||
115 | |||
116 | // If we've added a path to a trait, add the trait's methods to the method map. | ||
117 | if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() { | ||
118 | import_map.collect_trait_methods(db, tr); | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | |||
124 | let mut importables = import_map.map.iter().collect::<Vec<_>>(); | ||
125 | |||
126 | importables.sort_by(cmp); | ||
127 | |||
128 | // Build the FST, taking care not to insert duplicate values. | ||
129 | |||
130 | let mut builder = fst::MapBuilder::memory(); | ||
131 | let mut last_batch_start = 0; | ||
132 | |||
133 | for idx in 0..importables.len() { | ||
134 | if let Some(next_item) = importables.get(idx + 1) { | ||
135 | if cmp(&importables[last_batch_start], next_item) == Ordering::Equal { | ||
136 | continue; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | let start = last_batch_start; | ||
141 | last_batch_start = idx + 1; | ||
142 | |||
143 | let key = fst_path(&importables[start].1.path); | ||
144 | |||
145 | builder.insert(key, start as u64).unwrap(); | ||
146 | } | ||
147 | |||
148 | import_map.fst = fst::Map::new(builder.into_inner().unwrap()).unwrap(); | ||
149 | import_map.importables = importables.iter().map(|(item, _)| **item).collect(); | ||
150 | |||
151 | Arc::new(import_map) | ||
152 | } | ||
153 | |||
154 | /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root. | ||
155 | pub fn path_of(&self, item: ItemInNs) -> Option<&ModPath> { | ||
156 | Some(&self.map.get(&item)?.path) | ||
157 | } | ||
158 | |||
159 | pub fn import_info_for(&self, item: ItemInNs) -> Option<&ImportInfo> { | ||
160 | self.map.get(&item) | ||
161 | } | ||
162 | |||
163 | fn collect_trait_methods(&mut self, db: &dyn DefDatabase, tr: TraitId) { | ||
164 | let data = db.trait_data(tr); | ||
165 | for (name, item) in data.items.iter() { | ||
166 | self.assoc_map.entry(name.to_string().into()).or_default().push(*item); | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | |||
171 | impl PartialEq for ImportMap { | ||
172 | fn eq(&self, other: &Self) -> bool { | ||
173 | // `fst` and `importables` are built from `map`, so we don't need to compare them. | ||
174 | self.map == other.map | ||
175 | } | ||
176 | } | ||
177 | |||
178 | impl Eq for ImportMap {} | ||
179 | |||
180 | impl fmt::Debug for ImportMap { | ||
181 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
182 | let mut importable_paths: Vec<_> = self | ||
183 | .map | ||
184 | .iter() | ||
185 | .map(|(item, info)| { | ||
186 | let ns = match item { | ||
187 | ItemInNs::Types(_) => "t", | ||
188 | ItemInNs::Values(_) => "v", | ||
189 | ItemInNs::Macros(_) => "m", | ||
190 | }; | ||
191 | format!("- {} ({})", info.path, ns) | ||
192 | }) | ||
193 | .collect(); | ||
194 | |||
195 | importable_paths.sort(); | ||
196 | f.write_str(&importable_paths.join("\n")) | ||
197 | } | ||
198 | } | ||
199 | |||
200 | fn fst_path(path: &ModPath) -> String { | ||
201 | let mut s = path.to_string(); | ||
202 | s.make_ascii_lowercase(); | ||
203 | s | ||
204 | } | ||
205 | |||
206 | fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering { | ||
207 | let lhs_str = fst_path(&lhs.path); | ||
208 | let rhs_str = fst_path(&rhs.path); | ||
209 | lhs_str.cmp(&rhs_str) | ||
210 | } | ||
211 | |||
212 | #[derive(Debug)] | ||
213 | pub struct Query { | ||
214 | query: String, | ||
215 | lowercased: String, | ||
216 | anchor_end: bool, | ||
217 | case_sensitive: bool, | ||
218 | limit: usize, | ||
219 | } | ||
220 | |||
221 | impl Query { | ||
222 | pub fn new(query: &str) -> Self { | ||
223 | Self { | ||
224 | lowercased: query.to_lowercase(), | ||
225 | query: query.to_string(), | ||
226 | anchor_end: false, | ||
227 | case_sensitive: false, | ||
228 | limit: usize::max_value(), | ||
229 | } | ||
230 | } | ||
231 | |||
232 | /// Only returns items whose paths end with the (case-insensitive) query string as their last | ||
233 | /// segment. | ||
234 | pub fn anchor_end(self) -> Self { | ||
235 | Self { anchor_end: true, ..self } | ||
236 | } | ||
237 | |||
238 | /// Limits the returned number of items to `limit`. | ||
239 | pub fn limit(self, limit: usize) -> Self { | ||
240 | Self { limit, ..self } | ||
241 | } | ||
242 | |||
243 | /// Respect casing of the query string when matching. | ||
244 | pub fn case_sensitive(self) -> Self { | ||
245 | Self { case_sensitive: true, ..self } | ||
246 | } | ||
247 | } | ||
248 | |||
249 | /// Searches dependencies of `krate` for an importable path matching `query`. | ||
250 | /// | ||
251 | /// This returns a list of items that could be imported from dependencies of `krate`. | ||
252 | pub fn search_dependencies<'a>( | ||
253 | db: &'a dyn DefDatabase, | ||
254 | krate: CrateId, | ||
255 | query: Query, | ||
256 | ) -> Vec<ItemInNs> { | ||
257 | let _p = ra_prof::profile("search_dependencies").detail(|| format!("{:?}", query)); | ||
258 | |||
259 | let graph = db.crate_graph(); | ||
260 | let import_maps: Vec<_> = | ||
261 | graph[krate].dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect(); | ||
262 | |||
263 | let automaton = fst::automaton::Subsequence::new(&query.lowercased); | ||
264 | |||
265 | let mut op = fst::map::OpBuilder::new(); | ||
266 | for map in &import_maps { | ||
267 | op = op.add(map.fst.search(&automaton)); | ||
268 | } | ||
269 | |||
270 | let mut stream = op.union(); | ||
271 | let mut res = Vec::new(); | ||
272 | while let Some((_, indexed_values)) = stream.next() { | ||
273 | for indexed_value in indexed_values { | ||
274 | let import_map = &import_maps[indexed_value.index]; | ||
275 | let importables = &import_map.importables[indexed_value.value as usize..]; | ||
276 | |||
277 | // Path shared by the importable items in this group. | ||
278 | let path = &import_map.map[&importables[0]].path; | ||
279 | |||
280 | if query.anchor_end { | ||
281 | // Last segment must match query. | ||
282 | let last = path.segments.last().unwrap().to_string(); | ||
283 | if last.to_lowercase() != query.lowercased { | ||
284 | continue; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | // Add the items from this `ModPath` group. Those are all subsequent items in | ||
289 | // `importables` whose paths match `path`. | ||
290 | let iter = importables.iter().copied().take_while(|item| { | ||
291 | let item_path = &import_map.map[item].path; | ||
292 | fst_path(item_path) == fst_path(path) | ||
293 | }); | ||
294 | |||
295 | if query.case_sensitive { | ||
296 | // FIXME: This does not do a subsequence match. | ||
297 | res.extend(iter.filter(|item| { | ||
298 | let item_path = &import_map.map[item].path; | ||
299 | item_path.to_string().contains(&query.query) | ||
300 | })); | ||
301 | } else { | ||
302 | res.extend(iter); | ||
303 | } | ||
304 | |||
305 | if res.len() >= query.limit { | ||
306 | res.truncate(query.limit); | ||
307 | return res; | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | |||
312 | // Add all exported associated items whose names match the query (exactly). | ||
313 | for map in &import_maps { | ||
314 | if let Some(v) = map.assoc_map.get(&*query.query) { | ||
315 | res.extend(v.iter().map(|&assoc| { | ||
316 | ItemInNs::Types(match assoc { | ||
317 | AssocItemId::FunctionId(it) => it.into(), | ||
318 | AssocItemId::ConstId(it) => it.into(), | ||
319 | AssocItemId::TypeAliasId(it) => it.into(), | ||
320 | }) | ||
321 | })); | ||
322 | } | ||
323 | } | ||
324 | |||
325 | res | ||
326 | } | ||
327 | |||
328 | #[cfg(test)] | ||
329 | mod tests { | ||
330 | use expect::{expect, Expect}; | ||
331 | use ra_db::{fixture::WithFixture, SourceDatabase, Upcast}; | ||
332 | |||
333 | use crate::{test_db::TestDB, AssocContainerId, Lookup}; | ||
334 | |||
335 | use super::*; | ||
336 | |||
337 | fn check_search(ra_fixture: &str, krate_name: &str, query: Query, expect: Expect) { | ||
338 | let db = TestDB::with_files(ra_fixture); | ||
339 | let crate_graph = db.crate_graph(); | ||
340 | let krate = crate_graph | ||
341 | .iter() | ||
342 | .find(|krate| { | ||
343 | crate_graph[*krate].display_name.as_ref().map(|n| n.to_string()) | ||
344 | == Some(krate_name.to_string()) | ||
345 | }) | ||
346 | .unwrap(); | ||
347 | |||
348 | let actual = search_dependencies(db.upcast(), krate, query) | ||
349 | .into_iter() | ||
350 | .filter_map(|item| { | ||
351 | let mark = match item { | ||
352 | ItemInNs::Types(_) => "t", | ||
353 | ItemInNs::Values(_) => "v", | ||
354 | ItemInNs::Macros(_) => "m", | ||
355 | }; | ||
356 | let item = assoc_to_trait(&db, item); | ||
357 | item.krate(db.upcast()).map(|krate| { | ||
358 | let map = db.import_map(krate); | ||
359 | let path = map.path_of(item).unwrap(); | ||
360 | format!( | ||
361 | "{}::{} ({})\n", | ||
362 | crate_graph[krate].display_name.as_ref().unwrap(), | ||
363 | path, | ||
364 | mark | ||
365 | ) | ||
366 | }) | ||
367 | }) | ||
368 | .collect::<String>(); | ||
369 | expect.assert_eq(&actual) | ||
370 | } | ||
371 | |||
372 | fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> ItemInNs { | ||
373 | let assoc: AssocItemId = match item { | ||
374 | ItemInNs::Types(it) | ItemInNs::Values(it) => match it { | ||
375 | ModuleDefId::TypeAliasId(it) => it.into(), | ||
376 | ModuleDefId::FunctionId(it) => it.into(), | ||
377 | ModuleDefId::ConstId(it) => it.into(), | ||
378 | _ => return item, | ||
379 | }, | ||
380 | _ => return item, | ||
381 | }; | ||
382 | |||
383 | let container = match assoc { | ||
384 | AssocItemId::FunctionId(it) => it.lookup(db).container, | ||
385 | AssocItemId::ConstId(it) => it.lookup(db).container, | ||
386 | AssocItemId::TypeAliasId(it) => it.lookup(db).container, | ||
387 | }; | ||
388 | |||
389 | match container { | ||
390 | AssocContainerId::TraitId(it) => ItemInNs::Types(it.into()), | ||
391 | _ => item, | ||
392 | } | ||
393 | } | ||
394 | |||
395 | fn check(ra_fixture: &str, expect: Expect) { | ||
396 | let db = TestDB::with_files(ra_fixture); | ||
397 | let crate_graph = db.crate_graph(); | ||
398 | |||
399 | let actual = crate_graph | ||
400 | .iter() | ||
401 | .filter_map(|krate| { | ||
402 | let cdata = &crate_graph[krate]; | ||
403 | let name = cdata.display_name.as_ref()?; | ||
404 | |||
405 | let map = db.import_map(krate); | ||
406 | |||
407 | Some(format!("{}:\n{:?}\n", name, map)) | ||
408 | }) | ||
409 | .collect::<String>(); | ||
410 | |||
411 | expect.assert_eq(&actual) | ||
412 | } | ||
413 | |||
414 | #[test] | ||
415 | fn smoke() { | ||
416 | check( | ||
417 | r" | ||
418 | //- /main.rs crate:main deps:lib | ||
419 | |||
420 | mod private { | ||
421 | pub use lib::Pub; | ||
422 | pub struct InPrivateModule; | ||
423 | } | ||
424 | |||
425 | pub mod publ1 { | ||
426 | use lib::Pub; | ||
427 | } | ||
428 | |||
429 | pub mod real_pub { | ||
430 | pub use lib::Pub; | ||
431 | } | ||
432 | pub mod real_pu2 { // same path length as above | ||
433 | pub use lib::Pub; | ||
434 | } | ||
435 | |||
436 | //- /lib.rs crate:lib | ||
437 | pub struct Pub {} | ||
438 | pub struct Pub2; // t + v | ||
439 | struct Priv; | ||
440 | ", | ||
441 | expect![[r#" | ||
442 | main: | ||
443 | - publ1 (t) | ||
444 | - real_pu2 (t) | ||
445 | - real_pub (t) | ||
446 | - real_pub::Pub (t) | ||
447 | lib: | ||
448 | - Pub (t) | ||
449 | - Pub2 (t) | ||
450 | - Pub2 (v) | ||
451 | "#]], | ||
452 | ); | ||
453 | } | ||
454 | |||
455 | #[test] | ||
456 | fn prefers_shortest_path() { | ||
457 | check( | ||
458 | r" | ||
459 | //- /main.rs crate:main | ||
460 | |||
461 | pub mod sub { | ||
462 | pub mod subsub { | ||
463 | pub struct Def {} | ||
464 | } | ||
465 | |||
466 | pub use super::sub::subsub::Def; | ||
467 | } | ||
468 | ", | ||
469 | expect![[r#" | ||
470 | main: | ||
471 | - sub (t) | ||
472 | - sub::Def (t) | ||
473 | - sub::subsub (t) | ||
474 | "#]], | ||
475 | ); | ||
476 | } | ||
477 | |||
478 | #[test] | ||
479 | fn type_reexport_cross_crate() { | ||
480 | // Reexports need to be visible from a crate, even if the original crate exports the item | ||
481 | // at a shorter path. | ||
482 | check( | ||
483 | r" | ||
484 | //- /main.rs crate:main deps:lib | ||
485 | pub mod m { | ||
486 | pub use lib::S; | ||
487 | } | ||
488 | //- /lib.rs crate:lib | ||
489 | pub struct S; | ||
490 | ", | ||
491 | expect![[r#" | ||
492 | main: | ||
493 | - m (t) | ||
494 | - m::S (t) | ||
495 | - m::S (v) | ||
496 | lib: | ||
497 | - S (t) | ||
498 | - S (v) | ||
499 | "#]], | ||
500 | ); | ||
501 | } | ||
502 | |||
503 | #[test] | ||
504 | fn macro_reexport() { | ||
505 | check( | ||
506 | r" | ||
507 | //- /main.rs crate:main deps:lib | ||
508 | pub mod m { | ||
509 | pub use lib::pub_macro; | ||
510 | } | ||
511 | //- /lib.rs crate:lib | ||
512 | #[macro_export] | ||
513 | macro_rules! pub_macro { | ||
514 | () => {}; | ||
515 | } | ||
516 | ", | ||
517 | expect![[r#" | ||
518 | main: | ||
519 | - m (t) | ||
520 | - m::pub_macro (m) | ||
521 | lib: | ||
522 | - pub_macro (m) | ||
523 | "#]], | ||
524 | ); | ||
525 | } | ||
526 | |||
527 | #[test] | ||
528 | fn module_reexport() { | ||
529 | // Reexporting modules from a dependency adds all contents to the import map. | ||
530 | check( | ||
531 | r" | ||
532 | //- /main.rs crate:main deps:lib | ||
533 | pub use lib::module as reexported_module; | ||
534 | //- /lib.rs crate:lib | ||
535 | pub mod module { | ||
536 | pub struct S; | ||
537 | } | ||
538 | ", | ||
539 | expect![[r#" | ||
540 | main: | ||
541 | - reexported_module (t) | ||
542 | - reexported_module::S (t) | ||
543 | - reexported_module::S (v) | ||
544 | lib: | ||
545 | - module (t) | ||
546 | - module::S (t) | ||
547 | - module::S (v) | ||
548 | "#]], | ||
549 | ); | ||
550 | } | ||
551 | |||
552 | #[test] | ||
553 | fn cyclic_module_reexport() { | ||
554 | // A cyclic reexport does not hang. | ||
555 | check( | ||
556 | r" | ||
557 | //- /lib.rs crate:lib | ||
558 | pub mod module { | ||
559 | pub struct S; | ||
560 | pub use super::sub::*; | ||
561 | } | ||
562 | |||
563 | pub mod sub { | ||
564 | pub use super::module; | ||
565 | } | ||
566 | ", | ||
567 | expect![[r#" | ||
568 | lib: | ||
569 | - module (t) | ||
570 | - module::S (t) | ||
571 | - module::S (v) | ||
572 | - sub (t) | ||
573 | "#]], | ||
574 | ); | ||
575 | } | ||
576 | |||
577 | #[test] | ||
578 | fn private_macro() { | ||
579 | check( | ||
580 | r" | ||
581 | //- /lib.rs crate:lib | ||
582 | macro_rules! private_macro { | ||
583 | () => {}; | ||
584 | } | ||
585 | ", | ||
586 | expect![[r#" | ||
587 | lib: | ||
588 | |||
589 | "#]], | ||
590 | ); | ||
591 | } | ||
592 | |||
593 | #[test] | ||
594 | fn namespacing() { | ||
595 | check( | ||
596 | r" | ||
597 | //- /lib.rs crate:lib | ||
598 | pub struct Thing; // t + v | ||
599 | #[macro_export] | ||
600 | macro_rules! Thing { // m | ||
601 | () => {}; | ||
602 | } | ||
603 | ", | ||
604 | expect![[r#" | ||
605 | lib: | ||
606 | - Thing (m) | ||
607 | - Thing (t) | ||
608 | - Thing (v) | ||
609 | "#]], | ||
610 | ); | ||
611 | |||
612 | check( | ||
613 | r" | ||
614 | //- /lib.rs crate:lib | ||
615 | pub mod Thing {} // t | ||
616 | #[macro_export] | ||
617 | macro_rules! Thing { // m | ||
618 | () => {}; | ||
619 | } | ||
620 | ", | ||
621 | expect![[r#" | ||
622 | lib: | ||
623 | - Thing (m) | ||
624 | - Thing (t) | ||
625 | "#]], | ||
626 | ); | ||
627 | } | ||
628 | |||
629 | #[test] | ||
630 | fn search() { | ||
631 | let ra_fixture = r#" | ||
632 | //- /main.rs crate:main deps:dep | ||
633 | //- /dep.rs crate:dep deps:tdep | ||
634 | use tdep::fmt as fmt_dep; | ||
635 | pub mod fmt { | ||
636 | pub trait Display { | ||
637 | fn fmt(); | ||
638 | } | ||
639 | } | ||
640 | #[macro_export] | ||
641 | macro_rules! Fmt { | ||
642 | () => {}; | ||
643 | } | ||
644 | pub struct Fmt; | ||
645 | |||
646 | pub fn format() {} | ||
647 | pub fn no() {} | ||
648 | |||
649 | //- /tdep.rs crate:tdep | ||
650 | pub mod fmt { | ||
651 | pub struct NotImportableFromMain; | ||
652 | } | ||
653 | "#; | ||
654 | |||
655 | check_search( | ||
656 | ra_fixture, | ||
657 | "main", | ||
658 | Query::new("fmt"), | ||
659 | expect![[r#" | ||
660 | dep::fmt (t) | ||
661 | dep::Fmt (t) | ||
662 | dep::Fmt (v) | ||
663 | dep::Fmt (m) | ||
664 | dep::fmt::Display (t) | ||
665 | dep::format (v) | ||
666 | dep::fmt::Display (t) | ||
667 | "#]], | ||
668 | ); | ||
669 | |||
670 | check_search( | ||
671 | ra_fixture, | ||
672 | "main", | ||
673 | Query::new("fmt").anchor_end(), | ||
674 | expect![[r#" | ||
675 | dep::fmt (t) | ||
676 | dep::Fmt (t) | ||
677 | dep::Fmt (v) | ||
678 | dep::Fmt (m) | ||
679 | dep::fmt::Display (t) | ||
680 | "#]], | ||
681 | ); | ||
682 | } | ||
683 | |||
684 | #[test] | ||
685 | fn search_casing() { | ||
686 | let ra_fixture = r#" | ||
687 | //- /main.rs crate:main deps:dep | ||
688 | //- /dep.rs crate:dep | ||
689 | |||
690 | pub struct fmt; | ||
691 | pub struct FMT; | ||
692 | "#; | ||
693 | |||
694 | check_search( | ||
695 | ra_fixture, | ||
696 | "main", | ||
697 | Query::new("FMT"), | ||
698 | expect![[r#" | ||
699 | dep::fmt (t) | ||
700 | dep::fmt (v) | ||
701 | dep::FMT (t) | ||
702 | dep::FMT (v) | ||
703 | "#]], | ||
704 | ); | ||
705 | |||
706 | check_search( | ||
707 | ra_fixture, | ||
708 | "main", | ||
709 | Query::new("FMT").case_sensitive(), | ||
710 | expect![[r#" | ||
711 | dep::FMT (t) | ||
712 | dep::FMT (v) | ||
713 | "#]], | ||
714 | ); | ||
715 | } | ||
716 | |||
717 | #[test] | ||
718 | fn search_limit() { | ||
719 | check_search( | ||
720 | r#" | ||
721 | //- /main.rs crate:main deps:dep | ||
722 | //- /dep.rs crate:dep | ||
723 | pub mod fmt { | ||
724 | pub trait Display { | ||
725 | fn fmt(); | ||
726 | } | ||
727 | } | ||
728 | #[macro_export] | ||
729 | macro_rules! Fmt { | ||
730 | () => {}; | ||
731 | } | ||
732 | pub struct Fmt; | ||
733 | |||
734 | pub fn format() {} | ||
735 | pub fn no() {} | ||
736 | "#, | ||
737 | "main", | ||
738 | Query::new("").limit(2), | ||
739 | expect![[r#" | ||
740 | dep::fmt (t) | ||
741 | dep::Fmt (t) | ||
742 | "#]], | ||
743 | ); | ||
744 | } | ||
745 | } | ||
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs deleted file mode 100644 index 8fee4b15e..000000000 --- a/crates/ra_hir_def/src/item_scope.rs +++ /dev/null | |||
@@ -1,341 +0,0 @@ | |||
1 | //! Describes items defined or visible (ie, imported) in a certain scope. | ||
2 | //! This is shared between modules and blocks. | ||
3 | |||
4 | use std::collections::hash_map::Entry; | ||
5 | |||
6 | use hir_expand::name::Name; | ||
7 | use once_cell::sync::Lazy; | ||
8 | use ra_db::CrateId; | ||
9 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
10 | use test_utils::mark; | ||
11 | |||
12 | use crate::{ | ||
13 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, | ||
14 | LocalModuleId, Lookup, MacroDefId, ModuleDefId, TraitId, | ||
15 | }; | ||
16 | |||
17 | #[derive(Copy, Clone)] | ||
18 | pub(crate) enum ImportType { | ||
19 | Glob, | ||
20 | Named, | ||
21 | } | ||
22 | |||
23 | #[derive(Debug, Default)] | ||
24 | pub struct PerNsGlobImports { | ||
25 | types: FxHashSet<(LocalModuleId, Name)>, | ||
26 | values: FxHashSet<(LocalModuleId, Name)>, | ||
27 | macros: FxHashSet<(LocalModuleId, Name)>, | ||
28 | } | ||
29 | |||
30 | #[derive(Debug, Default, PartialEq, Eq)] | ||
31 | pub struct ItemScope { | ||
32 | types: FxHashMap<Name, (ModuleDefId, Visibility)>, | ||
33 | values: FxHashMap<Name, (ModuleDefId, Visibility)>, | ||
34 | macros: FxHashMap<Name, (MacroDefId, Visibility)>, | ||
35 | unresolved: FxHashSet<Name>, | ||
36 | |||
37 | defs: Vec<ModuleDefId>, | ||
38 | impls: Vec<ImplId>, | ||
39 | /// Traits imported via `use Trait as _;`. | ||
40 | unnamed_trait_imports: FxHashMap<TraitId, Visibility>, | ||
41 | /// Macros visible in current module in legacy textual scope | ||
42 | /// | ||
43 | /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first. | ||
44 | /// If it yields no result, then it turns to module scoped `macros`. | ||
45 | /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped, | ||
46 | /// and only normal scoped `macros` will be searched in. | ||
47 | /// | ||
48 | /// Note that this automatically inherit macros defined textually before the definition of module itself. | ||
49 | /// | ||
50 | /// Module scoped macros will be inserted into `items` instead of here. | ||
51 | // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will | ||
52 | // be all resolved to the last one defined if shadowing happens. | ||
53 | legacy_macros: FxHashMap<Name, MacroDefId>, | ||
54 | } | ||
55 | |||
56 | pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { | ||
57 | BuiltinType::ALL | ||
58 | .iter() | ||
59 | .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public))) | ||
60 | .collect() | ||
61 | }); | ||
62 | |||
63 | /// Shadow mode for builtin type which can be shadowed by module. | ||
64 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
65 | pub(crate) enum BuiltinShadowMode { | ||
66 | /// Prefer user-defined modules (or other types) over builtins. | ||
67 | Module, | ||
68 | /// Prefer builtins over user-defined modules (but not other types). | ||
69 | Other, | ||
70 | } | ||
71 | |||
72 | /// Legacy macros can only be accessed through special methods like `get_legacy_macros`. | ||
73 | /// Other methods will only resolve values, types and module scoped macros only. | ||
74 | impl ItemScope { | ||
75 | pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { | ||
76 | // FIXME: shadowing | ||
77 | let keys: FxHashSet<_> = self | ||
78 | .types | ||
79 | .keys() | ||
80 | .chain(self.values.keys()) | ||
81 | .chain(self.macros.keys()) | ||
82 | .chain(self.unresolved.iter()) | ||
83 | .collect(); | ||
84 | |||
85 | keys.into_iter().map(move |name| (name, self.get(name))) | ||
86 | } | ||
87 | |||
88 | pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ { | ||
89 | self.defs.iter().copied() | ||
90 | } | ||
91 | |||
92 | pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ { | ||
93 | self.impls.iter().copied() | ||
94 | } | ||
95 | |||
96 | pub fn visibility_of(&self, def: ModuleDefId) -> Option<Visibility> { | ||
97 | self.name_of(ItemInNs::Types(def)) | ||
98 | .or_else(|| self.name_of(ItemInNs::Values(def))) | ||
99 | .map(|(_, v)| v) | ||
100 | } | ||
101 | |||
102 | /// Iterate over all module scoped macros | ||
103 | pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { | ||
104 | self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) | ||
105 | } | ||
106 | |||
107 | /// Iterate over all legacy textual scoped macros visible at the end of the module | ||
108 | pub(crate) fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { | ||
109 | self.legacy_macros.iter().map(|(name, def)| (name, *def)) | ||
110 | } | ||
111 | |||
112 | /// Get a name from current module scope, legacy macros are not included | ||
113 | pub(crate) fn get(&self, name: &Name) -> PerNs { | ||
114 | PerNs { | ||
115 | types: self.types.get(name).copied(), | ||
116 | values: self.values.get(name).copied(), | ||
117 | macros: self.macros.get(name).copied(), | ||
118 | } | ||
119 | } | ||
120 | |||
121 | pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { | ||
122 | for (name, per_ns) in self.entries() { | ||
123 | if let Some(vis) = item.match_with(per_ns) { | ||
124 | return Some((name, vis)); | ||
125 | } | ||
126 | } | ||
127 | None | ||
128 | } | ||
129 | |||
130 | pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { | ||
131 | self.types | ||
132 | .values() | ||
133 | .filter_map(|(def, _)| match def { | ||
134 | ModuleDefId::TraitId(t) => Some(*t), | ||
135 | _ => None, | ||
136 | }) | ||
137 | .chain(self.unnamed_trait_imports.keys().copied()) | ||
138 | } | ||
139 | |||
140 | pub(crate) fn define_def(&mut self, def: ModuleDefId) { | ||
141 | self.defs.push(def) | ||
142 | } | ||
143 | |||
144 | pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> { | ||
145 | self.legacy_macros.get(name).copied() | ||
146 | } | ||
147 | |||
148 | pub(crate) fn define_impl(&mut self, imp: ImplId) { | ||
149 | self.impls.push(imp) | ||
150 | } | ||
151 | |||
152 | pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) { | ||
153 | self.legacy_macros.insert(name, mac); | ||
154 | } | ||
155 | |||
156 | pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> { | ||
157 | self.unnamed_trait_imports.get(&tr).copied() | ||
158 | } | ||
159 | |||
160 | pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) { | ||
161 | self.unnamed_trait_imports.insert(tr, vis); | ||
162 | } | ||
163 | |||
164 | pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { | ||
165 | let mut changed = false; | ||
166 | |||
167 | if let Some(types) = def.types { | ||
168 | self.types.entry(name.clone()).or_insert_with(|| { | ||
169 | changed = true; | ||
170 | types | ||
171 | }); | ||
172 | } | ||
173 | if let Some(values) = def.values { | ||
174 | self.values.entry(name.clone()).or_insert_with(|| { | ||
175 | changed = true; | ||
176 | values | ||
177 | }); | ||
178 | } | ||
179 | if let Some(macros) = def.macros { | ||
180 | self.macros.entry(name.clone()).or_insert_with(|| { | ||
181 | changed = true; | ||
182 | macros | ||
183 | }); | ||
184 | } | ||
185 | |||
186 | if def.is_none() { | ||
187 | if self.unresolved.insert(name) { | ||
188 | changed = true; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | changed | ||
193 | } | ||
194 | |||
195 | pub(crate) fn push_res_with_import( | ||
196 | &mut self, | ||
197 | glob_imports: &mut PerNsGlobImports, | ||
198 | lookup: (LocalModuleId, Name), | ||
199 | def: PerNs, | ||
200 | def_import_type: ImportType, | ||
201 | ) -> bool { | ||
202 | let mut changed = false; | ||
203 | |||
204 | macro_rules! check_changed { | ||
205 | ( | ||
206 | $changed:ident, | ||
207 | ( $this:ident / $def:ident ) . $field:ident, | ||
208 | $glob_imports:ident [ $lookup:ident ], | ||
209 | $def_import_type:ident | ||
210 | ) => {{ | ||
211 | let existing = $this.$field.entry($lookup.1.clone()); | ||
212 | match (existing, $def.$field) { | ||
213 | (Entry::Vacant(entry), Some(_)) => { | ||
214 | match $def_import_type { | ||
215 | ImportType::Glob => { | ||
216 | $glob_imports.$field.insert($lookup.clone()); | ||
217 | } | ||
218 | ImportType::Named => { | ||
219 | $glob_imports.$field.remove(&$lookup); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | if let Some(fld) = $def.$field { | ||
224 | entry.insert(fld); | ||
225 | } | ||
226 | $changed = true; | ||
227 | } | ||
228 | (Entry::Occupied(mut entry), Some(_)) | ||
229 | if $glob_imports.$field.contains(&$lookup) | ||
230 | && matches!($def_import_type, ImportType::Named) => | ||
231 | { | ||
232 | mark::hit!(import_shadowed); | ||
233 | $glob_imports.$field.remove(&$lookup); | ||
234 | if let Some(fld) = $def.$field { | ||
235 | entry.insert(fld); | ||
236 | } | ||
237 | $changed = true; | ||
238 | } | ||
239 | _ => {} | ||
240 | } | ||
241 | }}; | ||
242 | } | ||
243 | |||
244 | check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type); | ||
245 | check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type); | ||
246 | check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type); | ||
247 | |||
248 | if def.is_none() { | ||
249 | if self.unresolved.insert(lookup.1) { | ||
250 | changed = true; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | changed | ||
255 | } | ||
256 | |||
257 | pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Option<Name>, PerNs)> + 'a { | ||
258 | self.entries().map(|(name, res)| (Some(name.clone()), res)).chain( | ||
259 | self.unnamed_trait_imports | ||
260 | .iter() | ||
261 | .map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))), | ||
262 | ) | ||
263 | } | ||
264 | |||
265 | pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { | ||
266 | self.legacy_macros.clone() | ||
267 | } | ||
268 | } | ||
269 | |||
270 | impl PerNs { | ||
271 | pub(crate) fn from_def(def: ModuleDefId, v: Visibility, has_constructor: bool) -> PerNs { | ||
272 | match def { | ||
273 | ModuleDefId::ModuleId(_) => PerNs::types(def, v), | ||
274 | ModuleDefId::FunctionId(_) => PerNs::values(def, v), | ||
275 | ModuleDefId::AdtId(adt) => match adt { | ||
276 | AdtId::UnionId(_) => PerNs::types(def, v), | ||
277 | AdtId::EnumId(_) => PerNs::types(def, v), | ||
278 | AdtId::StructId(_) => { | ||
279 | if has_constructor { | ||
280 | PerNs::both(def, def, v) | ||
281 | } else { | ||
282 | PerNs::types(def, v) | ||
283 | } | ||
284 | } | ||
285 | }, | ||
286 | ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v), | ||
287 | ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v), | ||
288 | ModuleDefId::TraitId(_) => PerNs::types(def, v), | ||
289 | ModuleDefId::TypeAliasId(_) => PerNs::types(def, v), | ||
290 | ModuleDefId::BuiltinType(_) => PerNs::types(def, v), | ||
291 | } | ||
292 | } | ||
293 | } | ||
294 | |||
295 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] | ||
296 | pub enum ItemInNs { | ||
297 | Types(ModuleDefId), | ||
298 | Values(ModuleDefId), | ||
299 | Macros(MacroDefId), | ||
300 | } | ||
301 | |||
302 | impl ItemInNs { | ||
303 | fn match_with(self, per_ns: PerNs) -> Option<Visibility> { | ||
304 | match self { | ||
305 | ItemInNs::Types(def) => { | ||
306 | per_ns.types.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis) | ||
307 | } | ||
308 | ItemInNs::Values(def) => { | ||
309 | per_ns.values.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis) | ||
310 | } | ||
311 | ItemInNs::Macros(def) => { | ||
312 | per_ns.macros.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis) | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | |||
317 | pub fn as_module_def_id(self) -> Option<ModuleDefId> { | ||
318 | match self { | ||
319 | ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id), | ||
320 | ItemInNs::Macros(_) => None, | ||
321 | } | ||
322 | } | ||
323 | |||
324 | /// Returns the crate defining this item (or `None` if `self` is built-in). | ||
325 | pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> { | ||
326 | Some(match self { | ||
327 | ItemInNs::Types(did) | ItemInNs::Values(did) => match did { | ||
328 | ModuleDefId::ModuleId(id) => id.krate, | ||
329 | ModuleDefId::FunctionId(id) => id.lookup(db).module(db).krate, | ||
330 | ModuleDefId::AdtId(id) => id.module(db).krate, | ||
331 | ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db).krate, | ||
332 | ModuleDefId::ConstId(id) => id.lookup(db).container.module(db).krate, | ||
333 | ModuleDefId::StaticId(id) => id.lookup(db).container.module(db).krate, | ||
334 | ModuleDefId::TraitId(id) => id.lookup(db).container.module(db).krate, | ||
335 | ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate, | ||
336 | ModuleDefId::BuiltinType(_) => return None, | ||
337 | }, | ||
338 | ItemInNs::Macros(id) => return id.krate, | ||
339 | }) | ||
340 | } | ||
341 | } | ||
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs deleted file mode 100644 index a67e75dac..000000000 --- a/crates/ra_hir_def/src/item_tree.rs +++ /dev/null | |||
@@ -1,754 +0,0 @@ | |||
1 | //! A simplified AST that only contains items. | ||
2 | |||
3 | mod lower; | ||
4 | #[cfg(test)] | ||
5 | mod tests; | ||
6 | |||
7 | use std::{ | ||
8 | any::type_name, | ||
9 | fmt::{self, Debug}, | ||
10 | hash::{Hash, Hasher}, | ||
11 | marker::PhantomData, | ||
12 | ops::{Index, Range}, | ||
13 | sync::Arc, | ||
14 | }; | ||
15 | |||
16 | use ast::{AstNode, AttrsOwner, NameOwner, StructKind}; | ||
17 | use either::Either; | ||
18 | use hir_expand::{ | ||
19 | ast_id_map::FileAstId, | ||
20 | hygiene::Hygiene, | ||
21 | name::{name, AsName, Name}, | ||
22 | HirFileId, InFile, | ||
23 | }; | ||
24 | use ra_arena::{Arena, Idx, RawId}; | ||
25 | use ra_syntax::{ast, match_ast}; | ||
26 | use rustc_hash::FxHashMap; | ||
27 | use smallvec::SmallVec; | ||
28 | use test_utils::mark; | ||
29 | |||
30 | use crate::{ | ||
31 | attr::Attrs, | ||
32 | db::DefDatabase, | ||
33 | generics::GenericParams, | ||
34 | path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, | ||
35 | type_ref::{Mutability, TypeBound, TypeRef}, | ||
36 | visibility::RawVisibility, | ||
37 | }; | ||
38 | |||
39 | #[derive(Copy, Clone, Eq, PartialEq)] | ||
40 | pub struct RawVisibilityId(u32); | ||
41 | |||
42 | impl RawVisibilityId { | ||
43 | pub const PUB: Self = RawVisibilityId(u32::max_value()); | ||
44 | pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1); | ||
45 | pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2); | ||
46 | } | ||
47 | |||
48 | impl fmt::Debug for RawVisibilityId { | ||
49 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
50 | let mut f = f.debug_tuple("RawVisibilityId"); | ||
51 | match *self { | ||
52 | Self::PUB => f.field(&"pub"), | ||
53 | Self::PRIV => f.field(&"pub(self)"), | ||
54 | Self::PUB_CRATE => f.field(&"pub(crate)"), | ||
55 | _ => f.field(&self.0), | ||
56 | }; | ||
57 | f.finish() | ||
58 | } | ||
59 | } | ||
60 | |||
61 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
62 | pub struct GenericParamsId(u32); | ||
63 | |||
64 | impl GenericParamsId { | ||
65 | pub const EMPTY: Self = GenericParamsId(u32::max_value()); | ||
66 | } | ||
67 | |||
68 | /// The item tree of a source file. | ||
69 | #[derive(Debug, Eq, PartialEq)] | ||
70 | pub struct ItemTree { | ||
71 | top_level: SmallVec<[ModItem; 1]>, | ||
72 | attrs: FxHashMap<AttrOwner, Attrs>, | ||
73 | inner_items: FxHashMap<FileAstId<ast::Item>, SmallVec<[ModItem; 1]>>, | ||
74 | |||
75 | data: Option<Box<ItemTreeData>>, | ||
76 | } | ||
77 | |||
78 | impl ItemTree { | ||
79 | pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> { | ||
80 | let _p = ra_prof::profile("item_tree_query").detail(|| format!("{:?}", file_id)); | ||
81 | let syntax = if let Some(node) = db.parse_or_expand(file_id) { | ||
82 | node | ||
83 | } else { | ||
84 | return Arc::new(Self::empty()); | ||
85 | }; | ||
86 | |||
87 | let hygiene = Hygiene::new(db.upcast(), file_id); | ||
88 | let ctx = lower::Ctx::new(db, hygiene.clone(), file_id); | ||
89 | let mut top_attrs = None; | ||
90 | let mut item_tree = match_ast! { | ||
91 | match syntax { | ||
92 | ast::SourceFile(file) => { | ||
93 | top_attrs = Some(Attrs::new(&file, &hygiene)); | ||
94 | ctx.lower_module_items(&file) | ||
95 | }, | ||
96 | ast::MacroItems(items) => { | ||
97 | ctx.lower_module_items(&items) | ||
98 | }, | ||
99 | // Macros can expand to expressions. We return an empty item tree in this case, but | ||
100 | // still need to collect inner items. | ||
101 | ast::Expr(e) => { | ||
102 | ctx.lower_inner_items(e.syntax()) | ||
103 | }, | ||
104 | _ => { | ||
105 | panic!("cannot create item tree from {:?}", syntax); | ||
106 | }, | ||
107 | } | ||
108 | }; | ||
109 | |||
110 | if let Some(attrs) = top_attrs { | ||
111 | item_tree.attrs.insert(AttrOwner::TopLevel, attrs); | ||
112 | } | ||
113 | item_tree.shrink_to_fit(); | ||
114 | Arc::new(item_tree) | ||
115 | } | ||
116 | |||
117 | fn empty() -> Self { | ||
118 | Self { | ||
119 | top_level: Default::default(), | ||
120 | attrs: Default::default(), | ||
121 | inner_items: Default::default(), | ||
122 | data: Default::default(), | ||
123 | } | ||
124 | } | ||
125 | |||
126 | fn shrink_to_fit(&mut self) { | ||
127 | if let Some(data) = &mut self.data { | ||
128 | let ItemTreeData { | ||
129 | imports, | ||
130 | extern_crates, | ||
131 | functions, | ||
132 | structs, | ||
133 | fields, | ||
134 | unions, | ||
135 | enums, | ||
136 | variants, | ||
137 | consts, | ||
138 | statics, | ||
139 | traits, | ||
140 | impls, | ||
141 | type_aliases, | ||
142 | mods, | ||
143 | macro_calls, | ||
144 | exprs, | ||
145 | vis, | ||
146 | generics, | ||
147 | } = &mut **data; | ||
148 | |||
149 | imports.shrink_to_fit(); | ||
150 | extern_crates.shrink_to_fit(); | ||
151 | functions.shrink_to_fit(); | ||
152 | structs.shrink_to_fit(); | ||
153 | fields.shrink_to_fit(); | ||
154 | unions.shrink_to_fit(); | ||
155 | enums.shrink_to_fit(); | ||
156 | variants.shrink_to_fit(); | ||
157 | consts.shrink_to_fit(); | ||
158 | statics.shrink_to_fit(); | ||
159 | traits.shrink_to_fit(); | ||
160 | impls.shrink_to_fit(); | ||
161 | type_aliases.shrink_to_fit(); | ||
162 | mods.shrink_to_fit(); | ||
163 | macro_calls.shrink_to_fit(); | ||
164 | exprs.shrink_to_fit(); | ||
165 | |||
166 | vis.arena.shrink_to_fit(); | ||
167 | generics.arena.shrink_to_fit(); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | /// Returns an iterator over all items located at the top level of the `HirFileId` this | ||
172 | /// `ItemTree` was created from. | ||
173 | pub fn top_level_items(&self) -> &[ModItem] { | ||
174 | &self.top_level | ||
175 | } | ||
176 | |||
177 | /// Returns the inner attributes of the source file. | ||
178 | pub fn top_level_attrs(&self) -> &Attrs { | ||
179 | self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&Attrs::EMPTY) | ||
180 | } | ||
181 | |||
182 | pub fn attrs(&self, of: AttrOwner) -> &Attrs { | ||
183 | self.attrs.get(&of).unwrap_or(&Attrs::EMPTY) | ||
184 | } | ||
185 | |||
186 | /// Returns the lowered inner items that `ast` corresponds to. | ||
187 | /// | ||
188 | /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered | ||
189 | /// to multiple items in the `ItemTree`. | ||
190 | pub fn inner_items(&self, ast: FileAstId<ast::Item>) -> &[ModItem] { | ||
191 | &self.inner_items[&ast] | ||
192 | } | ||
193 | |||
194 | pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ { | ||
195 | self.inner_items.values().flatten().copied() | ||
196 | } | ||
197 | |||
198 | pub fn source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source { | ||
199 | // This unwrap cannot fail, since it has either succeeded above, or resulted in an empty | ||
200 | // ItemTree (in which case there is no valid `FileItemTreeId` to call this method with). | ||
201 | let root = | ||
202 | db.parse_or_expand(of.file_id).expect("parse_or_expand failed on constructed ItemTree"); | ||
203 | |||
204 | let id = self[of.value].ast_id(); | ||
205 | let map = db.ast_id_map(of.file_id); | ||
206 | let ptr = map.get(id); | ||
207 | ptr.to_node(&root) | ||
208 | } | ||
209 | |||
210 | fn data(&self) -> &ItemTreeData { | ||
211 | self.data.as_ref().expect("attempted to access data of empty ItemTree") | ||
212 | } | ||
213 | |||
214 | fn data_mut(&mut self) -> &mut ItemTreeData { | ||
215 | self.data.get_or_insert_with(Box::default) | ||
216 | } | ||
217 | } | ||
218 | |||
219 | #[derive(Default, Debug, Eq, PartialEq)] | ||
220 | struct ItemVisibilities { | ||
221 | arena: Arena<RawVisibility>, | ||
222 | } | ||
223 | |||
224 | impl ItemVisibilities { | ||
225 | fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId { | ||
226 | match &vis { | ||
227 | RawVisibility::Public => RawVisibilityId::PUB, | ||
228 | RawVisibility::Module(path) if path.segments.is_empty() => match &path.kind { | ||
229 | PathKind::Super(0) => RawVisibilityId::PRIV, | ||
230 | PathKind::Crate => RawVisibilityId::PUB_CRATE, | ||
231 | _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), | ||
232 | }, | ||
233 | _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()), | ||
234 | } | ||
235 | } | ||
236 | } | ||
237 | |||
238 | static VIS_PUB: RawVisibility = RawVisibility::Public; | ||
239 | static VIS_PRIV: RawVisibility = | ||
240 | RawVisibility::Module(ModPath { kind: PathKind::Super(0), segments: Vec::new() }); | ||
241 | static VIS_PUB_CRATE: RawVisibility = | ||
242 | RawVisibility::Module(ModPath { kind: PathKind::Crate, segments: Vec::new() }); | ||
243 | |||
244 | #[derive(Default, Debug, Eq, PartialEq)] | ||
245 | struct GenericParamsStorage { | ||
246 | arena: Arena<GenericParams>, | ||
247 | } | ||
248 | |||
249 | impl GenericParamsStorage { | ||
250 | fn alloc(&mut self, params: GenericParams) -> GenericParamsId { | ||
251 | if params.types.is_empty() && params.where_predicates.is_empty() { | ||
252 | return GenericParamsId::EMPTY; | ||
253 | } | ||
254 | |||
255 | GenericParamsId(self.arena.alloc(params).into_raw().into()) | ||
256 | } | ||
257 | } | ||
258 | |||
259 | static EMPTY_GENERICS: GenericParams = | ||
260 | GenericParams { types: Arena::new(), where_predicates: Vec::new() }; | ||
261 | |||
262 | #[derive(Default, Debug, Eq, PartialEq)] | ||
263 | struct ItemTreeData { | ||
264 | imports: Arena<Import>, | ||
265 | extern_crates: Arena<ExternCrate>, | ||
266 | functions: Arena<Function>, | ||
267 | structs: Arena<Struct>, | ||
268 | fields: Arena<Field>, | ||
269 | unions: Arena<Union>, | ||
270 | enums: Arena<Enum>, | ||
271 | variants: Arena<Variant>, | ||
272 | consts: Arena<Const>, | ||
273 | statics: Arena<Static>, | ||
274 | traits: Arena<Trait>, | ||
275 | impls: Arena<Impl>, | ||
276 | type_aliases: Arena<TypeAlias>, | ||
277 | mods: Arena<Mod>, | ||
278 | macro_calls: Arena<MacroCall>, | ||
279 | exprs: Arena<Expr>, | ||
280 | |||
281 | vis: ItemVisibilities, | ||
282 | generics: GenericParamsStorage, | ||
283 | } | ||
284 | |||
285 | #[derive(Debug, Eq, PartialEq, Hash)] | ||
286 | pub enum AttrOwner { | ||
287 | /// Attributes on an item. | ||
288 | ModItem(ModItem), | ||
289 | /// Inner attributes of the source file. | ||
290 | TopLevel, | ||
291 | |||
292 | Variant(Idx<Variant>), | ||
293 | Field(Idx<Field>), | ||
294 | // FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`. | ||
295 | } | ||
296 | |||
297 | macro_rules! from_attrs { | ||
298 | ( $( $var:ident($t:ty) ),+ ) => { | ||
299 | $( | ||
300 | impl From<$t> for AttrOwner { | ||
301 | fn from(t: $t) -> AttrOwner { | ||
302 | AttrOwner::$var(t) | ||
303 | } | ||
304 | } | ||
305 | )+ | ||
306 | }; | ||
307 | } | ||
308 | |||
309 | from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>)); | ||
310 | |||
311 | /// Trait implemented by all item nodes in the item tree. | ||
312 | pub trait ItemTreeNode: Clone { | ||
313 | type Source: AstNode + Into<ast::Item>; | ||
314 | |||
315 | fn ast_id(&self) -> FileAstId<Self::Source>; | ||
316 | |||
317 | /// Looks up an instance of `Self` in an item tree. | ||
318 | fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self; | ||
319 | |||
320 | /// Downcasts a `ModItem` to a `FileItemTreeId` specific to this type. | ||
321 | fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>>; | ||
322 | |||
323 | /// Upcasts a `FileItemTreeId` to a generic `ModItem`. | ||
324 | fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem; | ||
325 | } | ||
326 | |||
327 | pub struct FileItemTreeId<N: ItemTreeNode> { | ||
328 | index: Idx<N>, | ||
329 | _p: PhantomData<N>, | ||
330 | } | ||
331 | |||
332 | impl<N: ItemTreeNode> Clone for FileItemTreeId<N> { | ||
333 | fn clone(&self) -> Self { | ||
334 | Self { index: self.index, _p: PhantomData } | ||
335 | } | ||
336 | } | ||
337 | impl<N: ItemTreeNode> Copy for FileItemTreeId<N> {} | ||
338 | |||
339 | impl<N: ItemTreeNode> PartialEq for FileItemTreeId<N> { | ||
340 | fn eq(&self, other: &FileItemTreeId<N>) -> bool { | ||
341 | self.index == other.index | ||
342 | } | ||
343 | } | ||
344 | impl<N: ItemTreeNode> Eq for FileItemTreeId<N> {} | ||
345 | |||
346 | impl<N: ItemTreeNode> Hash for FileItemTreeId<N> { | ||
347 | fn hash<H: Hasher>(&self, state: &mut H) { | ||
348 | self.index.hash(state) | ||
349 | } | ||
350 | } | ||
351 | |||
352 | impl<N: ItemTreeNode> fmt::Debug for FileItemTreeId<N> { | ||
353 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
354 | self.index.fmt(f) | ||
355 | } | ||
356 | } | ||
357 | |||
358 | pub type ItemTreeId<N> = InFile<FileItemTreeId<N>>; | ||
359 | |||
360 | macro_rules! mod_items { | ||
361 | ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => { | ||
362 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
363 | pub enum ModItem { | ||
364 | $( | ||
365 | $typ(FileItemTreeId<$typ>), | ||
366 | )+ | ||
367 | } | ||
368 | |||
369 | $( | ||
370 | impl From<FileItemTreeId<$typ>> for ModItem { | ||
371 | fn from(id: FileItemTreeId<$typ>) -> ModItem { | ||
372 | ModItem::$typ(id) | ||
373 | } | ||
374 | } | ||
375 | )+ | ||
376 | |||
377 | $( | ||
378 | impl ItemTreeNode for $typ { | ||
379 | type Source = $ast; | ||
380 | |||
381 | fn ast_id(&self) -> FileAstId<Self::Source> { | ||
382 | self.ast_id | ||
383 | } | ||
384 | |||
385 | fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self { | ||
386 | &tree.data().$fld[index] | ||
387 | } | ||
388 | |||
389 | fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> { | ||
390 | if let ModItem::$typ(id) = mod_item { | ||
391 | Some(id) | ||
392 | } else { | ||
393 | None | ||
394 | } | ||
395 | } | ||
396 | |||
397 | fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem { | ||
398 | ModItem::$typ(id) | ||
399 | } | ||
400 | } | ||
401 | |||
402 | impl Index<Idx<$typ>> for ItemTree { | ||
403 | type Output = $typ; | ||
404 | |||
405 | fn index(&self, index: Idx<$typ>) -> &Self::Output { | ||
406 | &self.data().$fld[index] | ||
407 | } | ||
408 | } | ||
409 | )+ | ||
410 | }; | ||
411 | } | ||
412 | |||
413 | mod_items! { | ||
414 | Import in imports -> ast::Use, | ||
415 | ExternCrate in extern_crates -> ast::ExternCrate, | ||
416 | Function in functions -> ast::Fn, | ||
417 | Struct in structs -> ast::Struct, | ||
418 | Union in unions -> ast::Union, | ||
419 | Enum in enums -> ast::Enum, | ||
420 | Const in consts -> ast::Const, | ||
421 | Static in statics -> ast::Static, | ||
422 | Trait in traits -> ast::Trait, | ||
423 | Impl in impls -> ast::Impl, | ||
424 | TypeAlias in type_aliases -> ast::TypeAlias, | ||
425 | Mod in mods -> ast::Module, | ||
426 | MacroCall in macro_calls -> ast::MacroCall, | ||
427 | } | ||
428 | |||
429 | macro_rules! impl_index { | ||
430 | ( $($fld:ident: $t:ty),+ $(,)? ) => { | ||
431 | $( | ||
432 | impl Index<Idx<$t>> for ItemTree { | ||
433 | type Output = $t; | ||
434 | |||
435 | fn index(&self, index: Idx<$t>) -> &Self::Output { | ||
436 | &self.data().$fld[index] | ||
437 | } | ||
438 | } | ||
439 | )+ | ||
440 | }; | ||
441 | } | ||
442 | |||
443 | impl_index!(fields: Field, variants: Variant, exprs: Expr); | ||
444 | |||
445 | impl Index<RawVisibilityId> for ItemTree { | ||
446 | type Output = RawVisibility; | ||
447 | fn index(&self, index: RawVisibilityId) -> &Self::Output { | ||
448 | match index { | ||
449 | RawVisibilityId::PRIV => &VIS_PRIV, | ||
450 | RawVisibilityId::PUB => &VIS_PUB, | ||
451 | RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE, | ||
452 | _ => &self.data().vis.arena[Idx::from_raw(index.0.into())], | ||
453 | } | ||
454 | } | ||
455 | } | ||
456 | |||
457 | impl Index<GenericParamsId> for ItemTree { | ||
458 | type Output = GenericParams; | ||
459 | |||
460 | fn index(&self, index: GenericParamsId) -> &Self::Output { | ||
461 | match index { | ||
462 | GenericParamsId::EMPTY => &EMPTY_GENERICS, | ||
463 | _ => &self.data().generics.arena[Idx::from_raw(index.0.into())], | ||
464 | } | ||
465 | } | ||
466 | } | ||
467 | |||
468 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | ||
469 | type Output = N; | ||
470 | fn index(&self, id: FileItemTreeId<N>) -> &N { | ||
471 | N::lookup(self, id.index) | ||
472 | } | ||
473 | } | ||
474 | |||
475 | /// A desugared `use` import. | ||
476 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
477 | pub struct Import { | ||
478 | pub path: ModPath, | ||
479 | pub alias: Option<ImportAlias>, | ||
480 | pub visibility: RawVisibilityId, | ||
481 | pub is_glob: bool, | ||
482 | pub is_prelude: bool, | ||
483 | /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many | ||
484 | /// `Import`s can map to the same `use` item. | ||
485 | pub ast_id: FileAstId<ast::Use>, | ||
486 | } | ||
487 | |||
488 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
489 | pub struct ExternCrate { | ||
490 | pub path: ModPath, | ||
491 | pub alias: Option<ImportAlias>, | ||
492 | pub visibility: RawVisibilityId, | ||
493 | /// Whether this is a `#[macro_use] extern crate ...`. | ||
494 | pub is_macro_use: bool, | ||
495 | pub ast_id: FileAstId<ast::ExternCrate>, | ||
496 | } | ||
497 | |||
498 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
499 | pub struct Function { | ||
500 | pub name: Name, | ||
501 | pub visibility: RawVisibilityId, | ||
502 | pub generic_params: GenericParamsId, | ||
503 | pub has_self_param: bool, | ||
504 | pub is_unsafe: bool, | ||
505 | pub params: Box<[TypeRef]>, | ||
506 | pub is_varargs: bool, | ||
507 | pub ret_type: TypeRef, | ||
508 | pub ast_id: FileAstId<ast::Fn>, | ||
509 | } | ||
510 | |||
511 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
512 | pub struct Struct { | ||
513 | pub name: Name, | ||
514 | pub visibility: RawVisibilityId, | ||
515 | pub generic_params: GenericParamsId, | ||
516 | pub fields: Fields, | ||
517 | pub ast_id: FileAstId<ast::Struct>, | ||
518 | pub kind: StructDefKind, | ||
519 | } | ||
520 | |||
521 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
522 | pub enum StructDefKind { | ||
523 | /// `struct S { ... }` - type namespace only. | ||
524 | Record, | ||
525 | /// `struct S(...);` | ||
526 | Tuple, | ||
527 | /// `struct S;` | ||
528 | Unit, | ||
529 | } | ||
530 | |||
531 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
532 | pub struct Union { | ||
533 | pub name: Name, | ||
534 | pub visibility: RawVisibilityId, | ||
535 | pub generic_params: GenericParamsId, | ||
536 | pub fields: Fields, | ||
537 | pub ast_id: FileAstId<ast::Union>, | ||
538 | } | ||
539 | |||
540 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
541 | pub struct Enum { | ||
542 | pub name: Name, | ||
543 | pub visibility: RawVisibilityId, | ||
544 | pub generic_params: GenericParamsId, | ||
545 | pub variants: IdRange<Variant>, | ||
546 | pub ast_id: FileAstId<ast::Enum>, | ||
547 | } | ||
548 | |||
549 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
550 | pub struct Const { | ||
551 | /// const _: () = (); | ||
552 | pub name: Option<Name>, | ||
553 | pub visibility: RawVisibilityId, | ||
554 | pub type_ref: TypeRef, | ||
555 | pub ast_id: FileAstId<ast::Const>, | ||
556 | } | ||
557 | |||
558 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
559 | pub struct Static { | ||
560 | pub name: Name, | ||
561 | pub visibility: RawVisibilityId, | ||
562 | pub mutable: bool, | ||
563 | pub type_ref: TypeRef, | ||
564 | pub ast_id: FileAstId<ast::Static>, | ||
565 | } | ||
566 | |||
567 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
568 | pub struct Trait { | ||
569 | pub name: Name, | ||
570 | pub visibility: RawVisibilityId, | ||
571 | pub generic_params: GenericParamsId, | ||
572 | pub auto: bool, | ||
573 | pub items: Box<[AssocItem]>, | ||
574 | pub ast_id: FileAstId<ast::Trait>, | ||
575 | } | ||
576 | |||
577 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
578 | pub struct Impl { | ||
579 | pub generic_params: GenericParamsId, | ||
580 | pub target_trait: Option<TypeRef>, | ||
581 | pub target_type: TypeRef, | ||
582 | pub is_negative: bool, | ||
583 | pub items: Box<[AssocItem]>, | ||
584 | pub ast_id: FileAstId<ast::Impl>, | ||
585 | } | ||
586 | |||
587 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
588 | pub struct TypeAlias { | ||
589 | pub name: Name, | ||
590 | pub visibility: RawVisibilityId, | ||
591 | /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. | ||
592 | pub bounds: Box<[TypeBound]>, | ||
593 | pub generic_params: GenericParamsId, | ||
594 | pub type_ref: Option<TypeRef>, | ||
595 | pub ast_id: FileAstId<ast::TypeAlias>, | ||
596 | } | ||
597 | |||
598 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
599 | pub struct Mod { | ||
600 | pub name: Name, | ||
601 | pub visibility: RawVisibilityId, | ||
602 | pub kind: ModKind, | ||
603 | pub ast_id: FileAstId<ast::Module>, | ||
604 | } | ||
605 | |||
606 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
607 | pub enum ModKind { | ||
608 | /// `mod m { ... }` | ||
609 | Inline { items: Box<[ModItem]> }, | ||
610 | |||
611 | /// `mod m;` | ||
612 | Outline {}, | ||
613 | } | ||
614 | |||
615 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
616 | pub struct MacroCall { | ||
617 | /// For `macro_rules!` declarations, this is the name of the declared macro. | ||
618 | pub name: Option<Name>, | ||
619 | /// Path to the called macro. | ||
620 | pub path: ModPath, | ||
621 | /// Has `#[macro_export]`. | ||
622 | pub is_export: bool, | ||
623 | /// Has `#[macro_export(local_inner_macros)]`. | ||
624 | pub is_local_inner: bool, | ||
625 | /// Has `#[rustc_builtin_macro]`. | ||
626 | pub is_builtin: bool, | ||
627 | pub ast_id: FileAstId<ast::MacroCall>, | ||
628 | } | ||
629 | |||
630 | // NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array | ||
631 | // lengths, but we don't do much with them yet. | ||
632 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
633 | pub struct Expr; | ||
634 | |||
635 | macro_rules! impl_froms { | ||
636 | ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { | ||
637 | $( | ||
638 | impl From<$t> for $e { | ||
639 | fn from(it: $t) -> $e { | ||
640 | $e::$v(it) | ||
641 | } | ||
642 | } | ||
643 | )* | ||
644 | } | ||
645 | } | ||
646 | |||
647 | impl ModItem { | ||
648 | pub fn as_assoc_item(&self) -> Option<AssocItem> { | ||
649 | match self { | ||
650 | ModItem::Import(_) | ||
651 | | ModItem::ExternCrate(_) | ||
652 | | ModItem::Struct(_) | ||
653 | | ModItem::Union(_) | ||
654 | | ModItem::Enum(_) | ||
655 | | ModItem::Static(_) | ||
656 | | ModItem::Trait(_) | ||
657 | | ModItem::Impl(_) | ||
658 | | ModItem::Mod(_) => None, | ||
659 | ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)), | ||
660 | ModItem::Const(konst) => Some(AssocItem::Const(*konst)), | ||
661 | ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)), | ||
662 | ModItem::Function(func) => Some(AssocItem::Function(*func)), | ||
663 | } | ||
664 | } | ||
665 | |||
666 | pub fn downcast<N: ItemTreeNode>(self) -> Option<FileItemTreeId<N>> { | ||
667 | N::id_from_mod_item(self) | ||
668 | } | ||
669 | } | ||
670 | |||
671 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
672 | pub enum AssocItem { | ||
673 | Function(FileItemTreeId<Function>), | ||
674 | TypeAlias(FileItemTreeId<TypeAlias>), | ||
675 | Const(FileItemTreeId<Const>), | ||
676 | MacroCall(FileItemTreeId<MacroCall>), | ||
677 | } | ||
678 | |||
679 | impl_froms!(AssocItem { | ||
680 | Function(FileItemTreeId<Function>), | ||
681 | TypeAlias(FileItemTreeId<TypeAlias>), | ||
682 | Const(FileItemTreeId<Const>), | ||
683 | MacroCall(FileItemTreeId<MacroCall>), | ||
684 | }); | ||
685 | |||
686 | impl From<AssocItem> for ModItem { | ||
687 | fn from(item: AssocItem) -> Self { | ||
688 | match item { | ||
689 | AssocItem::Function(it) => it.into(), | ||
690 | AssocItem::TypeAlias(it) => it.into(), | ||
691 | AssocItem::Const(it) => it.into(), | ||
692 | AssocItem::MacroCall(it) => it.into(), | ||
693 | } | ||
694 | } | ||
695 | } | ||
696 | |||
697 | #[derive(Debug, Eq, PartialEq)] | ||
698 | pub struct Variant { | ||
699 | pub name: Name, | ||
700 | pub fields: Fields, | ||
701 | } | ||
702 | |||
703 | pub struct IdRange<T> { | ||
704 | range: Range<u32>, | ||
705 | _p: PhantomData<T>, | ||
706 | } | ||
707 | |||
708 | impl<T> IdRange<T> { | ||
709 | fn new(range: Range<Idx<T>>) -> Self { | ||
710 | Self { range: range.start.into_raw().into()..range.end.into_raw().into(), _p: PhantomData } | ||
711 | } | ||
712 | } | ||
713 | |||
714 | impl<T> Iterator for IdRange<T> { | ||
715 | type Item = Idx<T>; | ||
716 | fn next(&mut self) -> Option<Self::Item> { | ||
717 | self.range.next().map(|raw| Idx::from_raw(raw.into())) | ||
718 | } | ||
719 | } | ||
720 | |||
721 | impl<T> fmt::Debug for IdRange<T> { | ||
722 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
723 | f.debug_tuple(&format!("IdRange::<{}>", type_name::<T>())).field(&self.range).finish() | ||
724 | } | ||
725 | } | ||
726 | |||
727 | impl<T> Clone for IdRange<T> { | ||
728 | fn clone(&self) -> Self { | ||
729 | Self { range: self.range.clone(), _p: PhantomData } | ||
730 | } | ||
731 | } | ||
732 | |||
733 | impl<T> PartialEq for IdRange<T> { | ||
734 | fn eq(&self, other: &Self) -> bool { | ||
735 | self.range == other.range | ||
736 | } | ||
737 | } | ||
738 | |||
739 | impl<T> Eq for IdRange<T> {} | ||
740 | |||
741 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
742 | pub enum Fields { | ||
743 | Record(IdRange<Field>), | ||
744 | Tuple(IdRange<Field>), | ||
745 | Unit, | ||
746 | } | ||
747 | |||
748 | /// A single field of an enum variant or struct | ||
749 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
750 | pub struct Field { | ||
751 | pub name: Name, | ||
752 | pub type_ref: TypeRef, | ||
753 | pub visibility: RawVisibilityId, | ||
754 | } | ||
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs deleted file mode 100644 index 450ef8798..000000000 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ /dev/null | |||
@@ -1,705 +0,0 @@ | |||
1 | //! AST -> `ItemTree` lowering code. | ||
2 | |||
3 | use std::{collections::hash_map::Entry, mem, sync::Arc}; | ||
4 | |||
5 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId}; | ||
6 | use ra_arena::map::ArenaMap; | ||
7 | use ra_syntax::{ | ||
8 | ast::{self, ModuleItemOwner}, | ||
9 | SyntaxNode, | ||
10 | }; | ||
11 | use smallvec::SmallVec; | ||
12 | |||
13 | use crate::{ | ||
14 | attr::Attrs, | ||
15 | generics::{GenericParams, TypeParamData, TypeParamProvenance}, | ||
16 | }; | ||
17 | |||
18 | use super::*; | ||
19 | |||
20 | fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> { | ||
21 | FileItemTreeId { index, _p: PhantomData } | ||
22 | } | ||
23 | |||
24 | struct ModItems(SmallVec<[ModItem; 1]>); | ||
25 | |||
26 | impl<T> From<T> for ModItems | ||
27 | where | ||
28 | T: Into<ModItem>, | ||
29 | { | ||
30 | fn from(t: T) -> Self { | ||
31 | ModItems(SmallVec::from_buf([t.into(); 1])) | ||
32 | } | ||
33 | } | ||
34 | |||
35 | pub(super) struct Ctx { | ||
36 | tree: ItemTree, | ||
37 | hygiene: Hygiene, | ||
38 | file: HirFileId, | ||
39 | source_ast_id_map: Arc<AstIdMap>, | ||
40 | body_ctx: crate::body::LowerCtx, | ||
41 | inner_items: Vec<ModItem>, | ||
42 | forced_visibility: Option<RawVisibilityId>, | ||
43 | } | ||
44 | |||
45 | impl Ctx { | ||
46 | pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { | ||
47 | Self { | ||
48 | tree: ItemTree::empty(), | ||
49 | hygiene, | ||
50 | file, | ||
51 | source_ast_id_map: db.ast_id_map(file), | ||
52 | body_ctx: crate::body::LowerCtx::new(db, file), | ||
53 | inner_items: Vec::new(), | ||
54 | forced_visibility: None, | ||
55 | } | ||
56 | } | ||
57 | |||
58 | pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { | ||
59 | self.tree.top_level = item_owner | ||
60 | .items() | ||
61 | .flat_map(|item| self.lower_mod_item(&item, false)) | ||
62 | .flat_map(|items| items.0) | ||
63 | .collect(); | ||
64 | self.tree | ||
65 | } | ||
66 | |||
67 | pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree { | ||
68 | self.collect_inner_items(within); | ||
69 | self.tree | ||
70 | } | ||
71 | |||
72 | fn data(&mut self) -> &mut ItemTreeData { | ||
73 | self.tree.data_mut() | ||
74 | } | ||
75 | |||
76 | fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItems> { | ||
77 | assert!(inner || self.inner_items.is_empty()); | ||
78 | |||
79 | // Collect inner items for 1-to-1-lowered items. | ||
80 | match item { | ||
81 | ast::Item::Struct(_) | ||
82 | | ast::Item::Union(_) | ||
83 | | ast::Item::Enum(_) | ||
84 | | ast::Item::Fn(_) | ||
85 | | ast::Item::TypeAlias(_) | ||
86 | | ast::Item::Const(_) | ||
87 | | ast::Item::Static(_) | ||
88 | | ast::Item::MacroCall(_) => { | ||
89 | // Skip this if we're already collecting inner items. We'll descend into all nodes | ||
90 | // already. | ||
91 | if !inner { | ||
92 | self.collect_inner_items(item.syntax()); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | // These are handled in their respective `lower_X` method (since we can't just blindly | ||
97 | // walk them). | ||
98 | ast::Item::Trait(_) | ast::Item::Impl(_) | ast::Item::ExternBlock(_) => {} | ||
99 | |||
100 | // These don't have inner items. | ||
101 | ast::Item::Module(_) | ast::Item::ExternCrate(_) | ast::Item::Use(_) => {} | ||
102 | }; | ||
103 | |||
104 | let attrs = Attrs::new(item, &self.hygiene); | ||
105 | let items = match item { | ||
106 | ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into), | ||
107 | ast::Item::Union(ast) => self.lower_union(ast).map(Into::into), | ||
108 | ast::Item::Enum(ast) => self.lower_enum(ast).map(Into::into), | ||
109 | ast::Item::Fn(ast) => self.lower_function(ast).map(Into::into), | ||
110 | ast::Item::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into), | ||
111 | ast::Item::Static(ast) => self.lower_static(ast).map(Into::into), | ||
112 | ast::Item::Const(ast) => Some(self.lower_const(ast).into()), | ||
113 | ast::Item::Module(ast) => self.lower_module(ast).map(Into::into), | ||
114 | ast::Item::Trait(ast) => self.lower_trait(ast).map(Into::into), | ||
115 | ast::Item::Impl(ast) => self.lower_impl(ast).map(Into::into), | ||
116 | ast::Item::Use(ast) => Some(ModItems( | ||
117 | self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(), | ||
118 | )), | ||
119 | ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into), | ||
120 | ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), | ||
121 | ast::Item::ExternBlock(ast) => { | ||
122 | Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>())) | ||
123 | } | ||
124 | }; | ||
125 | |||
126 | if !attrs.is_empty() { | ||
127 | for item in items.iter().flat_map(|items| &items.0) { | ||
128 | self.add_attrs((*item).into(), attrs.clone()); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | items | ||
133 | } | ||
134 | |||
135 | fn add_attrs(&mut self, item: AttrOwner, attrs: Attrs) { | ||
136 | match self.tree.attrs.entry(item) { | ||
137 | Entry::Occupied(mut entry) => { | ||
138 | *entry.get_mut() = entry.get().merge(attrs); | ||
139 | } | ||
140 | Entry::Vacant(entry) => { | ||
141 | entry.insert(attrs); | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | |||
146 | fn collect_inner_items(&mut self, container: &SyntaxNode) { | ||
147 | let forced_vis = self.forced_visibility.take(); | ||
148 | let mut inner_items = mem::take(&mut self.tree.inner_items); | ||
149 | inner_items.extend(container.descendants().skip(1).filter_map(ast::Item::cast).filter_map( | ||
150 | |item| { | ||
151 | let ast_id = self.source_ast_id_map.ast_id(&item); | ||
152 | Some((ast_id, self.lower_mod_item(&item, true)?.0)) | ||
153 | }, | ||
154 | )); | ||
155 | self.tree.inner_items = inner_items; | ||
156 | self.forced_visibility = forced_vis; | ||
157 | } | ||
158 | |||
159 | fn lower_assoc_item(&mut self, item: &ast::AssocItem) -> Option<AssocItem> { | ||
160 | match item { | ||
161 | ast::AssocItem::Fn(ast) => self.lower_function(ast).map(Into::into), | ||
162 | ast::AssocItem::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into), | ||
163 | ast::AssocItem::Const(ast) => Some(self.lower_const(ast).into()), | ||
164 | ast::AssocItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), | ||
165 | } | ||
166 | } | ||
167 | |||
168 | fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> { | ||
169 | let visibility = self.lower_visibility(strukt); | ||
170 | let name = strukt.name()?.as_name(); | ||
171 | let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt); | ||
172 | let fields = self.lower_fields(&strukt.kind()); | ||
173 | let ast_id = self.source_ast_id_map.ast_id(strukt); | ||
174 | let kind = match strukt.kind() { | ||
175 | ast::StructKind::Record(_) => StructDefKind::Record, | ||
176 | ast::StructKind::Tuple(_) => StructDefKind::Tuple, | ||
177 | ast::StructKind::Unit => StructDefKind::Unit, | ||
178 | }; | ||
179 | let res = Struct { name, visibility, generic_params, fields, ast_id, kind }; | ||
180 | Some(id(self.data().structs.alloc(res))) | ||
181 | } | ||
182 | |||
183 | fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields { | ||
184 | match strukt_kind { | ||
185 | ast::StructKind::Record(it) => { | ||
186 | let range = self.lower_record_fields(it); | ||
187 | Fields::Record(range) | ||
188 | } | ||
189 | ast::StructKind::Tuple(it) => { | ||
190 | let range = self.lower_tuple_fields(it); | ||
191 | Fields::Tuple(range) | ||
192 | } | ||
193 | ast::StructKind::Unit => Fields::Unit, | ||
194 | } | ||
195 | } | ||
196 | |||
197 | fn lower_record_fields(&mut self, fields: &ast::RecordFieldList) -> IdRange<Field> { | ||
198 | let start = self.next_field_idx(); | ||
199 | for field in fields.fields() { | ||
200 | if let Some(data) = self.lower_record_field(&field) { | ||
201 | let idx = self.data().fields.alloc(data); | ||
202 | self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene)); | ||
203 | } | ||
204 | } | ||
205 | let end = self.next_field_idx(); | ||
206 | IdRange::new(start..end) | ||
207 | } | ||
208 | |||
209 | fn lower_record_field(&mut self, field: &ast::RecordField) -> Option<Field> { | ||
210 | let name = field.name()?.as_name(); | ||
211 | let visibility = self.lower_visibility(field); | ||
212 | let type_ref = self.lower_type_ref_opt(field.ty()); | ||
213 | let res = Field { name, type_ref, visibility }; | ||
214 | Some(res) | ||
215 | } | ||
216 | |||
217 | fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldList) -> IdRange<Field> { | ||
218 | let start = self.next_field_idx(); | ||
219 | for (i, field) in fields.fields().enumerate() { | ||
220 | let data = self.lower_tuple_field(i, &field); | ||
221 | let idx = self.data().fields.alloc(data); | ||
222 | self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene)); | ||
223 | } | ||
224 | let end = self.next_field_idx(); | ||
225 | IdRange::new(start..end) | ||
226 | } | ||
227 | |||
228 | fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field { | ||
229 | let name = Name::new_tuple_field(idx); | ||
230 | let visibility = self.lower_visibility(field); | ||
231 | let type_ref = self.lower_type_ref_opt(field.ty()); | ||
232 | let res = Field { name, type_ref, visibility }; | ||
233 | res | ||
234 | } | ||
235 | |||
236 | fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> { | ||
237 | let visibility = self.lower_visibility(union); | ||
238 | let name = union.name()?.as_name(); | ||
239 | let generic_params = self.lower_generic_params(GenericsOwner::Union, union); | ||
240 | let fields = match union.record_field_list() { | ||
241 | Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)), | ||
242 | None => Fields::Record(IdRange::new(self.next_field_idx()..self.next_field_idx())), | ||
243 | }; | ||
244 | let ast_id = self.source_ast_id_map.ast_id(union); | ||
245 | let res = Union { name, visibility, generic_params, fields, ast_id }; | ||
246 | Some(id(self.data().unions.alloc(res))) | ||
247 | } | ||
248 | |||
249 | fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> { | ||
250 | let visibility = self.lower_visibility(enum_); | ||
251 | let name = enum_.name()?.as_name(); | ||
252 | let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); | ||
253 | let variants = match &enum_.variant_list() { | ||
254 | Some(variant_list) => self.lower_variants(variant_list), | ||
255 | None => IdRange::new(self.next_variant_idx()..self.next_variant_idx()), | ||
256 | }; | ||
257 | let ast_id = self.source_ast_id_map.ast_id(enum_); | ||
258 | let res = Enum { name, visibility, generic_params, variants, ast_id }; | ||
259 | Some(id(self.data().enums.alloc(res))) | ||
260 | } | ||
261 | |||
262 | fn lower_variants(&mut self, variants: &ast::VariantList) -> IdRange<Variant> { | ||
263 | let start = self.next_variant_idx(); | ||
264 | for variant in variants.variants() { | ||
265 | if let Some(data) = self.lower_variant(&variant) { | ||
266 | let idx = self.data().variants.alloc(data); | ||
267 | self.add_attrs(idx.into(), Attrs::new(&variant, &self.hygiene)); | ||
268 | } | ||
269 | } | ||
270 | let end = self.next_variant_idx(); | ||
271 | IdRange::new(start..end) | ||
272 | } | ||
273 | |||
274 | fn lower_variant(&mut self, variant: &ast::Variant) -> Option<Variant> { | ||
275 | let name = variant.name()?.as_name(); | ||
276 | let fields = self.lower_fields(&variant.kind()); | ||
277 | let res = Variant { name, fields }; | ||
278 | Some(res) | ||
279 | } | ||
280 | |||
281 | fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> { | ||
282 | let visibility = self.lower_visibility(func); | ||
283 | let name = func.name()?.as_name(); | ||
284 | |||
285 | let mut params = Vec::new(); | ||
286 | let mut has_self_param = false; | ||
287 | if let Some(param_list) = func.param_list() { | ||
288 | if let Some(self_param) = param_list.self_param() { | ||
289 | let self_type = match self_param.ty() { | ||
290 | Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), | ||
291 | None => { | ||
292 | let self_type = TypeRef::Path(name![Self].into()); | ||
293 | match self_param.kind() { | ||
294 | ast::SelfParamKind::Owned => self_type, | ||
295 | ast::SelfParamKind::Ref => { | ||
296 | TypeRef::Reference(Box::new(self_type), Mutability::Shared) | ||
297 | } | ||
298 | ast::SelfParamKind::MutRef => { | ||
299 | TypeRef::Reference(Box::new(self_type), Mutability::Mut) | ||
300 | } | ||
301 | } | ||
302 | } | ||
303 | }; | ||
304 | params.push(self_type); | ||
305 | has_self_param = true; | ||
306 | } | ||
307 | for param in param_list.params() { | ||
308 | let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty()); | ||
309 | params.push(type_ref); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | let mut is_varargs = false; | ||
314 | if let Some(params) = func.param_list() { | ||
315 | if let Some(last) = params.params().last() { | ||
316 | is_varargs = last.dotdotdot_token().is_some(); | ||
317 | } | ||
318 | } | ||
319 | |||
320 | let ret_type = match func.ret_type().and_then(|rt| rt.ty()) { | ||
321 | Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), | ||
322 | _ => TypeRef::unit(), | ||
323 | }; | ||
324 | |||
325 | let ret_type = if func.async_token().is_some() { | ||
326 | let future_impl = desugar_future_path(ret_type); | ||
327 | let ty_bound = TypeBound::Path(future_impl); | ||
328 | TypeRef::ImplTrait(vec![ty_bound]) | ||
329 | } else { | ||
330 | ret_type | ||
331 | }; | ||
332 | |||
333 | let ast_id = self.source_ast_id_map.ast_id(func); | ||
334 | let mut res = Function { | ||
335 | name, | ||
336 | visibility, | ||
337 | generic_params: GenericParamsId::EMPTY, | ||
338 | has_self_param, | ||
339 | is_unsafe: func.unsafe_token().is_some(), | ||
340 | params: params.into_boxed_slice(), | ||
341 | is_varargs, | ||
342 | ret_type, | ||
343 | ast_id, | ||
344 | }; | ||
345 | res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); | ||
346 | |||
347 | Some(id(self.data().functions.alloc(res))) | ||
348 | } | ||
349 | |||
350 | fn lower_type_alias( | ||
351 | &mut self, | ||
352 | type_alias: &ast::TypeAlias, | ||
353 | ) -> Option<FileItemTreeId<TypeAlias>> { | ||
354 | let name = type_alias.name()?.as_name(); | ||
355 | let type_ref = type_alias.ty().map(|it| self.lower_type_ref(&it)); | ||
356 | let visibility = self.lower_visibility(type_alias); | ||
357 | let bounds = self.lower_type_bounds(type_alias); | ||
358 | let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias); | ||
359 | let ast_id = self.source_ast_id_map.ast_id(type_alias); | ||
360 | let res = TypeAlias { | ||
361 | name, | ||
362 | visibility, | ||
363 | bounds: bounds.into_boxed_slice(), | ||
364 | generic_params, | ||
365 | type_ref, | ||
366 | ast_id, | ||
367 | }; | ||
368 | Some(id(self.data().type_aliases.alloc(res))) | ||
369 | } | ||
370 | |||
371 | fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> { | ||
372 | let name = static_.name()?.as_name(); | ||
373 | let type_ref = self.lower_type_ref_opt(static_.ty()); | ||
374 | let visibility = self.lower_visibility(static_); | ||
375 | let mutable = static_.mut_token().is_some(); | ||
376 | let ast_id = self.source_ast_id_map.ast_id(static_); | ||
377 | let res = Static { name, visibility, mutable, type_ref, ast_id }; | ||
378 | Some(id(self.data().statics.alloc(res))) | ||
379 | } | ||
380 | |||
381 | fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> { | ||
382 | let name = konst.name().map(|it| it.as_name()); | ||
383 | let type_ref = self.lower_type_ref_opt(konst.ty()); | ||
384 | let visibility = self.lower_visibility(konst); | ||
385 | let ast_id = self.source_ast_id_map.ast_id(konst); | ||
386 | let res = Const { name, visibility, type_ref, ast_id }; | ||
387 | id(self.data().consts.alloc(res)) | ||
388 | } | ||
389 | |||
390 | fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> { | ||
391 | let name = module.name()?.as_name(); | ||
392 | let visibility = self.lower_visibility(module); | ||
393 | let kind = if module.semicolon_token().is_some() { | ||
394 | ModKind::Outline {} | ||
395 | } else { | ||
396 | ModKind::Inline { | ||
397 | items: module | ||
398 | .item_list() | ||
399 | .map(|list| { | ||
400 | list.items() | ||
401 | .flat_map(|item| self.lower_mod_item(&item, false)) | ||
402 | .flat_map(|items| items.0) | ||
403 | .collect() | ||
404 | }) | ||
405 | .unwrap_or_else(|| { | ||
406 | mark::hit!(name_res_works_for_broken_modules); | ||
407 | Box::new([]) as Box<[_]> | ||
408 | }), | ||
409 | } | ||
410 | }; | ||
411 | let ast_id = self.source_ast_id_map.ast_id(module); | ||
412 | let res = Mod { name, visibility, kind, ast_id }; | ||
413 | Some(id(self.data().mods.alloc(res))) | ||
414 | } | ||
415 | |||
416 | fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<FileItemTreeId<Trait>> { | ||
417 | let name = trait_def.name()?.as_name(); | ||
418 | let visibility = self.lower_visibility(trait_def); | ||
419 | let generic_params = | ||
420 | self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def); | ||
421 | let auto = trait_def.auto_token().is_some(); | ||
422 | let items = trait_def.assoc_item_list().map(|list| { | ||
423 | self.with_inherited_visibility(visibility, |this| { | ||
424 | list.assoc_items() | ||
425 | .filter_map(|item| { | ||
426 | let attrs = Attrs::new(&item, &this.hygiene); | ||
427 | this.collect_inner_items(item.syntax()); | ||
428 | this.lower_assoc_item(&item).map(|item| { | ||
429 | this.add_attrs(ModItem::from(item).into(), attrs); | ||
430 | item | ||
431 | }) | ||
432 | }) | ||
433 | .collect() | ||
434 | }) | ||
435 | }); | ||
436 | let ast_id = self.source_ast_id_map.ast_id(trait_def); | ||
437 | let res = Trait { | ||
438 | name, | ||
439 | visibility, | ||
440 | generic_params, | ||
441 | auto, | ||
442 | items: items.unwrap_or_default(), | ||
443 | ast_id, | ||
444 | }; | ||
445 | Some(id(self.data().traits.alloc(res))) | ||
446 | } | ||
447 | |||
448 | fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> { | ||
449 | let generic_params = | ||
450 | self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); | ||
451 | let target_trait = impl_def.trait_().map(|tr| self.lower_type_ref(&tr)); | ||
452 | let target_type = self.lower_type_ref(&impl_def.self_ty()?); | ||
453 | let is_negative = impl_def.excl_token().is_some(); | ||
454 | |||
455 | // We cannot use `assoc_items()` here as that does not include macro calls. | ||
456 | let items = impl_def | ||
457 | .assoc_item_list() | ||