Skip to content

Commit 682fac9

Browse files
authored
Merge pull request #1035 from Y-Nak/parse-attrs
2 parents 9aa00cc + f143227 commit 682fac9

File tree

12 files changed

+591
-455
lines changed

12 files changed

+591
-455
lines changed

crates/hir-analysis/src/name_resolution/import_resolver.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,7 @@ impl<'db> IntermediateUse<'db> {
821821
}
822822
};
823823

824-
if next_res.is_mod() || next_res.is_enum() {
824+
if next_res.is_mod(db) || next_res.is_enum(db) {
825825
Ok(Self {
826826
use_: self.use_,
827827
current_res: next_res.into(),

crates/hir-analysis/src/name_resolution/name_resolver.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use hir::{
1212
AnonEdge, EdgeKind, FieldEdge, GenericParamEdge, IngotEdge, LexEdge, ModEdge, ScopeId,
1313
SelfEdge, SelfTyEdge, SuperEdge, TraitEdge, TypeEdge, ValueEdge, VariantEdge,
1414
},
15-
GenericParam, GenericParamOwner, IdentId, ItemKind, Trait, Use,
15+
Enum, GenericParam, GenericParamOwner, IdentId, ItemKind, Mod, TopLevelMod, Trait, Use,
1616
},
1717
span::DynLazySpan,
1818
};
@@ -306,17 +306,20 @@ impl<'db> NameRes<'db> {
306306
self.trait_().is_some()
307307
}
308308

309-
pub fn is_enum(&self) -> bool {
309+
pub fn is_enum(&self, db: &dyn HirAnalysisDb) -> bool {
310310
match self.kind {
311311
NameResKind::Prim(_) => false,
312-
NameResKind::Scope(scope) => scope.is_enum(),
312+
NameResKind::Scope(scope) => scope.resolve_to::<Enum>(db.as_hir_db()).is_some(),
313313
}
314314
}
315315

316-
pub fn is_mod(&self) -> bool {
316+
pub fn is_mod(&self, db: &dyn HirAnalysisDb) -> bool {
317317
match self.kind {
318318
NameResKind::Prim(_) => false,
319-
NameResKind::Scope(scope) => scope.is_mod(),
319+
NameResKind::Scope(scope) => {
320+
scope.resolve_to::<TopLevelMod>(db.as_hir_db()).is_some()
321+
|| scope.resolve_to::<Mod>(db.as_hir_db()).is_some()
322+
}
320323
}
321324
}
322325

crates/hir/src/hir_def/item.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,24 @@ impl<'db> ItemKind<'db> {
8282
}
8383
}
8484

85+
/// Returns attributes being applied to this item.
86+
pub fn attrs(self, db: &'db dyn HirDb) -> Option<AttrListId<'db>> {
87+
match self {
88+
Self::Mod(mod_) => mod_.attributes(db),
89+
Self::Func(func) => func.attributes(db),
90+
Self::Struct(struct_) => struct_.attributes(db),
91+
Self::Contract(contract) => contract.attributes(db),
92+
Self::Enum(enum_) => enum_.attributes(db),
93+
Self::TypeAlias(alias) => alias.attributes(db),
94+
Self::Impl(impl_) => impl_.attributes(db),
95+
Self::Trait(trait_) => trait_.attributes(db),
96+
Self::ImplTrait(impl_trait) => impl_trait.attributes(db),
97+
Self::Const(const_) => const_.attributes(db),
98+
_ => return None,
99+
}
100+
.into()
101+
}
102+
85103
pub fn kind_name(self) -> &'static str {
86104
use ItemKind::*;
87105
match self {
@@ -941,6 +959,7 @@ pub struct Const<'db> {
941959
id: TrackedItemId<'db>,
942960

943961
pub name: Partial<IdentId<'db>>,
962+
pub attributes: AttrListId<'db>,
944963
pub ty: Partial<TypeId<'db>>,
945964
pub body: Partial<Body<'db>>,
946965
pub vis: Visibility,
@@ -1093,6 +1112,7 @@ impl<'db> FieldDefListId<'db> {
10931112

10941113
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10951114
pub struct FieldDef<'db> {
1115+
pub attributes: AttrListId<'db>,
10961116
pub name: Partial<IdentId<'db>>,
10971117
pub ty: Partial<TypeId<'db>>,
10981118
pub vis: Visibility,
@@ -1106,6 +1126,7 @@ pub struct VariantDefListId<'db> {
11061126

11071127
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11081128
pub struct VariantDef<'db> {
1129+
pub attributes: AttrListId<'db>,
11091130
pub name: Partial<IdentId<'db>>,
11101131
pub kind: VariantKind<'db>,
11111132
}

crates/hir/src/hir_def/scope_graph.rs

Lines changed: 134 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ use common::indexmap::IndexSet;
44
use rustc_hash::{FxHashMap, FxHashSet};
55

66
use super::{
7-
scope_graph_viz::ScopeGraphFormatter, Body, Enum, ExprId, Func, FuncParamName, IdentId,
8-
IngotId, ItemKind, TopLevelMod, Use, VariantKind, Visibility,
7+
scope_graph_viz::ScopeGraphFormatter, AttrListId, Body, Const, Contract, Enum, ExprId,
8+
FieldDef, Func, FuncParam, FuncParamName, GenericParam, IdentId, Impl, ImplTrait, IngotId,
9+
ItemKind, Mod, TopLevelMod, Trait, TypeAlias, Use, VariantDef, VariantKind, Visibility,
910
};
1011
use crate::{
1112
hir_def::{BodyKind, GenericParamOwner},
@@ -130,6 +131,31 @@ impl<'db> ScopeId<'db> {
130131
}
131132
}
132133

134+
/// Resolves the `ScopeId` to `T`.
135+
/// Returns `None` if the resolution is not defined for this scope.
136+
pub fn resolve_to<T>(self, db: &'db dyn HirDb) -> Option<T>
137+
where
138+
T: FromScope<'db>,
139+
{
140+
T::from_scope(self, db)
141+
}
142+
143+
/// Returns attributes being applied to the scope.
144+
pub fn attrs(self, db: &'db dyn HirDb) -> Option<AttrListId<'db>> {
145+
match self {
146+
ScopeId::Item(item) => item.attrs(db),
147+
ScopeId::Field(..) => {
148+
let def: &FieldDef = self.resolve_to(db).unwrap();
149+
Some(def.attributes)
150+
}
151+
ScopeId::Variant(..) => {
152+
let def: &VariantDef = self.resolve_to(db).unwrap();
153+
Some(def.attributes)
154+
}
155+
_ => None,
156+
}
157+
}
158+
133159
/// Returns the scope graph containing this scope.
134160
pub fn scope_graph(self, db: &'db dyn HirDb) -> &'db ScopeGraph<'db> {
135161
self.top_mod(db).scope_graph(db)
@@ -157,7 +183,7 @@ impl<'db> ScopeId<'db> {
157183
}
158184
}
159185

160-
/// Returns true if `self` is a transitive reflexive child of `of`.
186+
/// Returns `true` if `self` is a transitive reflexive child of `of`.
161187
pub fn is_transitive_child_of(self, db: &dyn HirDb, of: ScopeId) -> bool {
162188
let mut current = Some(self);
163189

@@ -238,19 +264,6 @@ impl<'db> ScopeId<'db> {
238264
}
239265
}
240266

241-
pub fn is_enum(self) -> bool {
242-
matches!(self, ScopeId::Item(ItemKind::Enum(_)))
243-
}
244-
245-
pub fn is_mod(self) -> bool {
246-
matches!(self, ScopeId::Item(ItemKind::Mod(_) | ItemKind::TopMod(_)))
247-
}
248-
249-
/// Returns `true` if the scope is a trait definition.
250-
pub fn is_trait(self) -> bool {
251-
matches!(self, ScopeId::Item(ItemKind::Trait(_)))
252-
}
253-
254267
/// Returns the item that contains this scope.
255268
pub fn parent_item(self, db: &'db dyn HirDb) -> Option<ItemKind<'db>> {
256269
let mut parent = self.parent(db)?;
@@ -268,39 +281,22 @@ impl<'db> ScopeId<'db> {
268281
match self.data(db).id {
269282
ScopeId::Item(item) => item.name(db),
270283

271-
ScopeId::Variant(parent, idx) => {
272-
let enum_: Enum = parent.try_into().unwrap();
273-
enum_.variants(db).data(db)[idx].name.to_opt()
274-
}
284+
ScopeId::Variant(..) => self.resolve_to::<&VariantDef>(db).unwrap().name.to_opt(),
275285

276-
ScopeId::Field(FieldParent::Item(parent), idx) => match parent {
277-
ItemKind::Struct(s) => s.fields(db).data(db)[idx].name.to_opt(),
278-
ItemKind::Contract(c) => c.fields(db).data(db)[idx].name.to_opt(),
279-
_ => unreachable!(),
280-
},
281-
ScopeId::Field(FieldParent::Variant(parent, vidx), fidx) => {
282-
let enum_: Enum = parent.try_into().unwrap();
283-
match enum_.variants(db).data(db)[vidx].kind {
284-
VariantKind::Record(fields) => fields.data(db)[fidx].name.to_opt(),
285-
_ => unreachable!(),
286-
}
287-
}
286+
ScopeId::Field(..) => self.resolve_to::<&FieldDef>(db).unwrap().name.to_opt(),
288287

289-
ScopeId::FuncParam(parent, idx) => {
290-
let func: Func = parent.try_into().unwrap();
291-
let param = &func.params(db).to_opt()?.data(db)[idx];
288+
ScopeId::FuncParam(..) => {
289+
let param: &FuncParam = self.resolve_to(db).unwrap();
292290
if let Some(FuncParamName::Ident(ident)) = param.label {
293291
Some(ident)
294292
} else {
295293
param.name()
296294
}
297295
}
298296

299-
ScopeId::GenericParam(parent, idx) => {
300-
let parent = GenericParamOwner::from_item_opt(parent).unwrap();
301-
302-
let params = &parent.params(db).data(db)[idx];
303-
params.name().to_opt()
297+
ScopeId::GenericParam(..) => {
298+
let param: &GenericParam = self.resolve_to(db).unwrap();
299+
param.name().to_opt()
304300
}
305301

306302
ScopeId::Block(..) => None,
@@ -366,6 +362,7 @@ impl<'db> ScopeId<'db> {
366362
ScopeId::Block(_, _) => "block",
367363
}
368364
}
365+
369366
pub fn pretty_path(self, db: &dyn HirDb) -> Option<String> {
370367
let name = match self {
371368
ScopeId::Block(body, expr) => format!("{{block{}}}", body.iter_block(db)[&expr]),
@@ -594,6 +591,103 @@ pub struct SelfEdge();
594591
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
595592
pub struct AnonEdge();
596593

594+
pub trait FromScope<'db>: Sized {
595+
fn from_scope(scope: ScopeId<'db>, db: &'db dyn HirDb) -> Option<Self>;
596+
}
597+
598+
impl<'db> FromScope<'db> for ItemKind<'db> {
599+
fn from_scope(scope: ScopeId<'db>, _db: &'db dyn HirDb) -> Option<Self> {
600+
match scope {
601+
ScopeId::Item(item) => Some(item),
602+
_ => None,
603+
}
604+
}
605+
}
606+
607+
macro_rules! item_from_scope {
608+
($($item_ty: ty,)*) => {
609+
$(
610+
impl<'db> FromScope<'db> for $item_ty {
611+
fn from_scope(scope: ScopeId<'db>, db: &'db dyn HirDb) -> Option<Self> {
612+
scope.resolve_to::<ItemKind>(db).and_then(|item| item.try_into().ok())
613+
}
614+
}
615+
)*
616+
};
617+
}
618+
619+
item_from_scope! {
620+
TopLevelMod<'db>,
621+
Mod<'db>,
622+
Func<'db>,
623+
Contract<'db>,
624+
Enum<'db>,
625+
TypeAlias<'db>,
626+
Impl<'db>,
627+
Trait<'db>,
628+
ImplTrait<'db>,
629+
Const<'db>,
630+
Use<'db>,
631+
Body<'db>,
632+
}
633+
634+
impl<'db> FromScope<'db> for &'db FieldDef<'db> {
635+
fn from_scope(scope: ScopeId<'db>, db: &'db dyn HirDb) -> Option<Self> {
636+
let ScopeId::Field(parent, idx) = scope else {
637+
return None;
638+
};
639+
640+
match parent {
641+
FieldParent::Item(item) => match item {
642+
ItemKind::Struct(s) => Some(&s.fields(db).data(db)[idx]),
643+
ItemKind::Contract(c) => Some(&c.fields(db).data(db)[idx]),
644+
_ => unreachable!(),
645+
},
646+
647+
FieldParent::Variant(parent, vidx) => {
648+
let enum_: Enum = parent.try_into().unwrap();
649+
match enum_.variants(db).data(db)[vidx].kind {
650+
VariantKind::Record(fields) => Some(&fields.data(db)[idx]),
651+
_ => unreachable!(),
652+
}
653+
}
654+
}
655+
}
656+
}
657+
658+
impl<'db> FromScope<'db> for &'db VariantDef<'db> {
659+
fn from_scope(scope: ScopeId<'db>, db: &'db dyn HirDb) -> Option<Self> {
660+
let ScopeId::Variant(parent, idx) = scope else {
661+
return None;
662+
};
663+
let enum_: Enum = parent.try_into().unwrap();
664+
665+
Some(&enum_.variants(db).data(db)[idx])
666+
}
667+
}
668+
669+
impl<'db> FromScope<'db> for &'db FuncParam<'db> {
670+
fn from_scope(scope: ScopeId<'db>, db: &'db dyn HirDb) -> Option<Self> {
671+
let ScopeId::FuncParam(parent, idx) = scope else {
672+
return None;
673+
};
674+
675+
let func: Func = parent.try_into().unwrap();
676+
func.params(db).to_opt().map(|params| &params.data(db)[idx])
677+
}
678+
}
679+
680+
impl<'db> FromScope<'db> for &'db GenericParam<'db> {
681+
fn from_scope(scope: ScopeId<'db>, db: &'db dyn HirDb) -> Option<Self> {
682+
let ScopeId::GenericParam(parent, idx) = scope else {
683+
return None;
684+
};
685+
686+
let parent = GenericParamOwner::from_item_opt(parent).unwrap();
687+
Some(&parent.params(db).data(db)[idx])
688+
}
689+
}
690+
597691
#[cfg(test)]
598692
mod tests {
599693

crates/hir/src/lower/item.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,12 +350,23 @@ impl<'db> Const<'db> {
350350
let id = ctxt.joined_id(TrackedItemVariant::Const(name));
351351
ctxt.enter_item_scope(id, false);
352352

353+
let attributes = AttrListId::lower_ast_opt(ctxt, ast.attr_list());
353354
let ty = TypeId::lower_ast_partial(ctxt, ast.ty());
354355
let body = ast.value().map(|ast| Body::lower_ast(ctxt, ast)).into();
355356
let vis = ItemModifier::lower_ast(ast.modifier()).to_visibility();
356357
let origin = HirOrigin::raw(&ast);
357358

358-
let const_ = Self::new(ctxt.db(), id, name, ty, body, vis, ctxt.top_mod(), origin);
359+
let const_ = Self::new(
360+
ctxt.db(),
361+
id,
362+
name,
363+
attributes,
364+
ty,
365+
body,
366+
vis,
367+
ctxt.top_mod(),
368+
origin,
369+
);
359370
ctxt.leave_item_scope(const_)
360371
}
361372
}
@@ -392,6 +403,7 @@ impl<'db> FieldDefListId<'db> {
392403

393404
impl<'db> FieldDef<'db> {
394405
fn lower_ast(ctxt: &mut FileLowerCtxt<'db>, ast: ast::RecordFieldDef) -> Self {
406+
let attributes = AttrListId::lower_ast_opt(ctxt, ast.attr_list());
395407
let name = IdentId::lower_token_partial(ctxt, ast.name());
396408
let ty = TypeId::lower_ast_partial(ctxt, ast.ty());
397409
let vis = if ast.pub_kw().is_some() {
@@ -400,7 +412,12 @@ impl<'db> FieldDef<'db> {
400412
Visibility::Private
401413
};
402414

403-
Self { name, ty, vis }
415+
Self {
416+
attributes,
417+
name,
418+
ty,
419+
vis,
420+
}
404421
}
405422
}
406423

@@ -421,12 +438,18 @@ impl<'db> VariantDefListId<'db> {
421438

422439
impl<'db> VariantDef<'db> {
423440
fn lower_ast(ctxt: &mut FileLowerCtxt<'db>, ast: ast::VariantDef) -> Self {
441+
let attributes = AttrListId::lower_ast_opt(ctxt, ast.attr_list());
424442
let name = IdentId::lower_token_partial(ctxt, ast.name());
425443
let kind = match ast.kind() {
426444
ast::VariantKind::Unit => VariantKind::Unit,
427445
ast::VariantKind::Tuple(t) => VariantKind::Tuple(TupleTypeId::lower_ast(ctxt, t)),
428446
ast::VariantKind::Record(r) => VariantKind::Record(FieldDefListId::lower_ast(ctxt, r)),
429447
};
430-
Self { name, kind }
448+
449+
Self {
450+
attributes,
451+
name,
452+
kind,
453+
}
431454
}
432455
}

0 commit comments

Comments
 (0)