aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/attr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/attr.rs')
-rw-r--r--crates/hir_def/src/attr.rs289
1 files changed, 194 insertions, 95 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index e4c84afbf..52a2bce9b 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -21,7 +21,7 @@ use crate::{
21 item_tree::{ItemTreeId, ItemTreeNode}, 21 item_tree::{ItemTreeId, ItemTreeNode},
22 nameres::ModuleSource, 22 nameres::ModuleSource,
23 path::{ModPath, PathKind}, 23 path::{ModPath, PathKind},
24 src::HasChildSource, 24 src::{HasChildSource, HasSource},
25 AdtId, AttrDefId, EnumId, GenericParamId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, 25 AdtId, AttrDefId, EnumId, GenericParamId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup,
26 VariantId, 26 VariantId,
27}; 27};
@@ -51,6 +51,12 @@ pub(crate) struct RawAttrs {
51#[derive(Default, Debug, Clone, PartialEq, Eq)] 51#[derive(Default, Debug, Clone, PartialEq, Eq)]
52pub struct Attrs(RawAttrs); 52pub struct Attrs(RawAttrs);
53 53
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct AttrsWithOwner {
56 attrs: Attrs,
57 owner: AttrDefId,
58}
59
54impl ops::Deref for RawAttrs { 60impl ops::Deref for RawAttrs {
55 type Target = [Attr]; 61 type Target = [Attr];
56 62
@@ -73,6 +79,14 @@ impl ops::Deref for Attrs {
73 } 79 }
74} 80}
75 81
82impl ops::Deref for AttrsWithOwner {
83 type Target = Attrs;
84
85 fn deref(&self) -> &Attrs {
86 &self.attrs
87 }
88}
89
76impl RawAttrs { 90impl RawAttrs {
77 pub(crate) const EMPTY: Self = Self { entries: None }; 91 pub(crate) const EMPTY: Self = Self { entries: None };
78 92
@@ -169,77 +183,6 @@ impl RawAttrs {
169impl Attrs { 183impl Attrs {
170 pub const EMPTY: Self = Self(RawAttrs::EMPTY); 184 pub const EMPTY: Self = Self(RawAttrs::EMPTY);
171 185
172 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
173 let raw_attrs = match def {
174 AttrDefId::ModuleId(module) => {
175 let def_map = module.def_map(db);
176 let mod_data = &def_map[module.local_id];
177 match mod_data.declaration_source(db) {
178 Some(it) => {
179 let raw_attrs = RawAttrs::from_attrs_owner(
180 db,
181 it.as_ref().map(|it| it as &dyn ast::AttrsOwner),
182 );
183 match mod_data.definition_source(db) {
184 InFile { file_id, value: ModuleSource::SourceFile(file) } => raw_attrs
185 .merge(RawAttrs::from_attrs_owner(db, InFile::new(file_id, &file))),
186 _ => raw_attrs,
187 }
188 }
189 None => RawAttrs::from_attrs_owner(
190 db,
191 mod_data.definition_source(db).as_ref().map(|src| match src {
192 ModuleSource::SourceFile(file) => file as &dyn ast::AttrsOwner,
193 ModuleSource::Module(module) => module as &dyn ast::AttrsOwner,
194 ModuleSource::BlockExpr(block) => block as &dyn ast::AttrsOwner,
195 }),
196 ),
197 }
198 }
199 AttrDefId::FieldId(it) => {
200 return db.fields_attrs(it.parent)[it.local_id].clone();
201 }
202 AttrDefId::EnumVariantId(it) => {
203 return db.variants_attrs(it.parent)[it.local_id].clone();
204 }
205 AttrDefId::AdtId(it) => match it {
206 AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
207 AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
208 AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
209 },
210 AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
211 AttrDefId::MacroDefId(it) => {
212 it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
213 }
214 AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
215 AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
216 AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
217 AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
218 AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
219 AttrDefId::GenericParamId(it) => match it {
220 GenericParamId::TypeParamId(it) => {
221 let src = it.parent.child_source(db);
222 RawAttrs::from_attrs_owner(
223 db,
224 src.with_value(
225 src.value[it.local_id].as_ref().either(|it| it as _, |it| it as _),
226 ),
227 )
228 }
229 GenericParamId::LifetimeParamId(it) => {
230 let src = it.parent.child_source(db);
231 RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
232 }
233 GenericParamId::ConstParamId(it) => {
234 let src = it.parent.child_source(db);
235 RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
236 }
237 },
238 };
239
240 raw_attrs.filter(db, def.krate(db))
241 }
242
243 pub(crate) fn variants_attrs_query( 186 pub(crate) fn variants_attrs_query(
244 db: &dyn DefDatabase, 187 db: &dyn DefDatabase,
245 e: EnumId, 188 e: EnumId,
@@ -280,13 +223,6 @@ impl Attrs {
280 Arc::new(res) 223 Arc::new(res)
281 } 224 }
282 225
283 /// Constructs a map that maps the lowered `Attr`s in this `Attrs` back to its original syntax nodes.
284 ///
285 /// `owner` must be the original owner of the attributes.
286 pub fn source_map(&self, owner: &dyn ast::AttrsOwner) -> AttrSourceMap {
287 AttrSourceMap { attrs: collect_attrs(owner).collect() }
288 }
289
290 pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { 226 pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
291 AttrQuery { attrs: self, key } 227 AttrQuery { attrs: self, key }
292 } 228 }
@@ -343,6 +279,180 @@ impl Attrs {
343 } 279 }
344} 280}
345 281
282impl AttrsWithOwner {
283 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Self {
284 // FIXME: this should use `Trace` to avoid duplication in `source_map` below
285 let raw_attrs = match def {
286 AttrDefId::ModuleId(module) => {
287 let def_map = module.def_map(db);
288 let mod_data = &def_map[module.local_id];
289 match mod_data.declaration_source(db) {
290 Some(it) => {
291 let raw_attrs = RawAttrs::from_attrs_owner(
292 db,
293 it.as_ref().map(|it| it as &dyn ast::AttrsOwner),
294 );
295 match mod_data.definition_source(db) {
296 InFile { file_id, value: ModuleSource::SourceFile(file) } => raw_attrs
297 .merge(RawAttrs::from_attrs_owner(db, InFile::new(file_id, &file))),
298 _ => raw_attrs,
299 }
300 }
301 None => RawAttrs::from_attrs_owner(
302 db,
303 mod_data.definition_source(db).as_ref().map(|src| match src {
304 ModuleSource::SourceFile(file) => file as &dyn ast::AttrsOwner,
305 ModuleSource::Module(module) => module as &dyn ast::AttrsOwner,
306 ModuleSource::BlockExpr(block) => block as &dyn ast::AttrsOwner,
307 }),
308 ),
309 }
310 }
311 AttrDefId::FieldId(it) => {
312 return Self { attrs: db.fields_attrs(it.parent)[it.local_id].clone(), owner: def };
313 }
314 AttrDefId::EnumVariantId(it) => {
315 return Self {
316 attrs: db.variants_attrs(it.parent)[it.local_id].clone(),
317 owner: def,
318 };
319 }
320 AttrDefId::AdtId(it) => match it {
321 AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
322 AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
323 AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
324 },
325 AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
326 AttrDefId::MacroDefId(it) => it
327 .ast_id()
328 .left()
329 .map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)),
330 AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
331 AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
332 AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
333 AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
334 AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
335 AttrDefId::GenericParamId(it) => match it {
336 GenericParamId::TypeParamId(it) => {
337 let src = it.parent.child_source(db);
338 RawAttrs::from_attrs_owner(
339 db,
340 src.with_value(
341 src.value[it.local_id].as_ref().either(|it| it as _, |it| it as _),
342 ),
343 )
344 }
345 GenericParamId::LifetimeParamId(it) => {
346 let src = it.parent.child_source(db);
347 RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
348 }
349 GenericParamId::ConstParamId(it) => {
350 let src = it.parent.child_source(db);
351 RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
352 }
353 },
354 };
355
356 let attrs = raw_attrs.filter(db, def.krate(db));
357 Self { attrs, owner: def }
358 }
359
360 pub fn source_map(&self, db: &dyn DefDatabase) -> AttrSourceMap {
361 let owner = match self.owner {
362 AttrDefId::ModuleId(module) => {
363 // Modules can have 2 attribute owners (the `mod x;` item, and the module file itself).
364
365 let def_map = module.def_map(db);
366 let mod_data = &def_map[module.local_id];
367 let attrs = match mod_data.declaration_source(db) {
368 Some(it) => {
369 let mut attrs: Vec<_> = collect_attrs(&it.value as &dyn ast::AttrsOwner)
370 .map(|attr| InFile::new(it.file_id, attr))
371 .collect();
372 if let InFile { file_id, value: ModuleSource::SourceFile(file) } =
373 mod_data.definition_source(db)
374 {
375 attrs.extend(
376 collect_attrs(&file as &dyn ast::AttrsOwner)
377 .map(|attr| InFile::new(file_id, attr)),
378 )
379 }
380 attrs
381 }
382 None => {
383 let InFile { file_id, value } = mod_data.definition_source(db);
384 match &value {
385 ModuleSource::SourceFile(file) => {
386 collect_attrs(file as &dyn ast::AttrsOwner)
387 }
388 ModuleSource::Module(module) => {
389 collect_attrs(module as &dyn ast::AttrsOwner)
390 }
391 ModuleSource::BlockExpr(block) => {
392 collect_attrs(block as &dyn ast::AttrsOwner)
393 }
394 }
395 .map(|attr| InFile::new(file_id, attr))
396 .collect()
397 }
398 };
399 return AttrSourceMap { attrs };
400 }
401 AttrDefId::FieldId(id) => {
402 id.parent.child_source(db).map(|source| match &source[id.local_id] {
403 Either::Left(field) => ast::AttrsOwnerNode::new(field.clone()),
404 Either::Right(field) => ast::AttrsOwnerNode::new(field.clone()),
405 })
406 }
407 AttrDefId::AdtId(adt) => match adt {
408 AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
409 AdtId::UnionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
410 AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
411 },
412 AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
413 AttrDefId::EnumVariantId(id) => id
414 .parent
415 .child_source(db)
416 .map(|source| ast::AttrsOwnerNode::new(source[id.local_id].clone())),
417 AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
418 AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
419 AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
420 AttrDefId::TypeAliasId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
421 AttrDefId::MacroDefId(id) => match id.ast_id() {
422 Either::Left(it) => {
423 it.with_value(ast::AttrsOwnerNode::new(it.to_node(db.upcast())))
424 }
425 Either::Right(it) => {
426 it.with_value(ast::AttrsOwnerNode::new(it.to_node(db.upcast())))
427 }
428 },
429 AttrDefId::ImplId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
430 AttrDefId::GenericParamId(id) => match id {
431 GenericParamId::TypeParamId(id) => {
432 id.parent.child_source(db).map(|source| match &source[id.local_id] {
433 Either::Left(id) => ast::AttrsOwnerNode::new(id.clone()),
434 Either::Right(id) => ast::AttrsOwnerNode::new(id.clone()),
435 })
436 }
437 GenericParamId::LifetimeParamId(id) => id
438 .parent
439 .child_source(db)
440 .map(|source| ast::AttrsOwnerNode::new(source[id.local_id].clone())),
441 GenericParamId::ConstParamId(id) => id
442 .parent
443 .child_source(db)
444 .map(|source| ast::AttrsOwnerNode::new(source[id.local_id].clone())),
445 },
446 };
447
448 AttrSourceMap {
449 attrs: collect_attrs(&owner.value)
450 .map(|attr| InFile::new(owner.file_id, attr))
451 .collect(),
452 }
453 }
454}
455
346fn inner_attributes( 456fn inner_attributes(
347 syntax: &SyntaxNode, 457 syntax: &SyntaxNode,
348) -> Option<(impl Iterator<Item = ast::Attr>, impl Iterator<Item = ast::Comment>)> { 458) -> Option<(impl Iterator<Item = ast::Attr>, impl Iterator<Item = ast::Comment>)> {
@@ -379,7 +489,7 @@ fn inner_attributes(
379} 489}
380 490
381pub struct AttrSourceMap { 491pub struct AttrSourceMap {
382 attrs: Vec<Either<ast::Attr, ast::Comment>>, 492 attrs: Vec<InFile<Either<ast::Attr, ast::Comment>>>,
383} 493}
384 494
385impl AttrSourceMap { 495impl AttrSourceMap {
@@ -389,10 +499,11 @@ impl AttrSourceMap {
389 /// 499 ///
390 /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of 500 /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of
391 /// the attribute represented by `Attr`. 501 /// the attribute represented by `Attr`.
392 pub fn source_of(&self, attr: &Attr) -> &Either<ast::Attr, ast::Comment> { 502 pub fn source_of(&self, attr: &Attr) -> InFile<&Either<ast::Attr, ast::Comment>> {
393 self.attrs 503 self.attrs
394 .get(attr.index as usize) 504 .get(attr.index as usize)
395 .unwrap_or_else(|| panic!("cannot find `Attr` at index {}", attr.index)) 505 .unwrap_or_else(|| panic!("cannot find `Attr` at index {}", attr.index))
506 .as_ref()
396 } 507 }
397} 508}
398 509
@@ -414,7 +525,7 @@ pub enum AttrInput {
414impl Attr { 525impl Attr {
415 fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> { 526 fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> {
416 let path = ModPath::from_src(ast.path()?, hygiene)?; 527 let path = ModPath::from_src(ast.path()?, hygiene)?;
417 let input = if let Some(lit) = ast.literal() { 528 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
418 let value = match lit.kind() { 529 let value = match lit.kind() {
419 ast::LiteralKind::String(string) => string.value()?.into(), 530 ast::LiteralKind::String(string) => string.value()?.into(),
420 _ => lit.syntax().first_token()?.text().trim_matches('"').into(), 531 _ => lit.syntax().first_token()?.text().trim_matches('"').into(),
@@ -428,18 +539,6 @@ impl Attr {
428 Some(Attr { index, path, input }) 539 Some(Attr { index, path, input })
429 } 540 }
430 541
431 /// Maps this lowered `Attr` back to its original syntax node.
432 ///
433 /// `owner` must be the original owner of the attribute.
434 ///
435 /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of
436 /// the attribute represented by `Attr`.
437 pub fn to_src(&self, owner: &dyn ast::AttrsOwner) -> Either<ast::Attr, ast::Comment> {
438 collect_attrs(owner).nth(self.index as usize).unwrap_or_else(|| {
439 panic!("cannot find `Attr` at index {} in {}", self.index, owner.syntax())
440 })
441 }
442
443 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths 542 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths
444 /// to derive macros. 543 /// to derive macros.
445 /// 544 ///
@@ -539,7 +638,7 @@ fn collect_attrs(
539 owner: &dyn ast::AttrsOwner, 638 owner: &dyn ast::AttrsOwner,
540) -> impl Iterator<Item = Either<ast::Attr, ast::Comment>> { 639) -> impl Iterator<Item = Either<ast::Attr, ast::Comment>> {
541 let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) 640 let (inner_attrs, inner_docs) = inner_attributes(owner.syntax())
542 .map_or((None, None), |(attrs, docs)| ((Some(attrs), Some(docs)))); 641 .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs)));
543 642
544 let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none()); 643 let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none());
545 let attrs = outer_attrs 644 let attrs = outer_attrs