cairo_lang_semantic/items/
attribute.rs

1use cairo_lang_defs::ids::{
2    EnumId, ExternTypeId, FreeFunctionId, FunctionWithBodyId, ImplAliasId, ImplDefId,
3    ImplFunctionId, ImplTypeDefId, ModuleId, StructId, SubmoduleId, TraitFunctionId, TraitId,
4    TraitTypeId,
5};
6use cairo_lang_diagnostics::Maybe;
7use cairo_lang_filesystem::ids::SmolStrId;
8use cairo_lang_syntax::attribute::structured::Attribute;
9use salsa::Database;
10
11use crate::items::enm::EnumSemantic;
12use crate::items::extern_type::ExternTypeSemantic;
13use crate::items::function_with_body::FunctionWithBodySemantic;
14use crate::items::imp::ImplSemantic;
15use crate::items::impl_alias::ImplAliasSemantic;
16use crate::items::module::ModuleSemantic;
17use crate::items::structure::StructSemantic;
18use crate::items::trt::TraitSemantic;
19use crate::{ConcreteEnumId, ConcreteExternTypeId, ConcreteStructId};
20
21pub trait AttributeTrait<'db> {
22    fn name(&self, db: &'db dyn Database) -> SmolStrId<'db>;
23    fn args(&self, db: &dyn Database) -> String;
24    fn full_text(&self, db: &'db dyn Database) -> String {
25        if self.args(db).is_empty() {
26            self.name(db).to_string(db)
27        } else {
28            format!("{}({})", self.name(db).long(db), self.args(db))
29        }
30    }
31    fn format(&self, db: &'db dyn Database) -> String {
32        format!("#[{}]", self.full_text(db))
33    }
34}
35impl<'db> AttributeTrait<'db> for Attribute<'db> {
36    fn name(&self, _db: &'db dyn Database) -> SmolStrId<'db> {
37        self.id
38    }
39    fn args(&self, db: &dyn Database) -> String {
40        self.args.iter().map(|arg| arg.text(db)).collect::<Vec<_>>().join(", ")
41    }
42}
43
44/// Trait for querying attributes of semantic items.
45pub trait SemanticQueryAttrs<'db> {
46    /// Get the list of attributes attached to this node.
47    ///
48    /// Implementation detail, should not be used by this trait users.
49    #[doc(hidden)]
50    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]>;
51
52    /// All attributes attached to this node whose name (without args) is exactly `attr`.
53    fn query_attr(
54        &self,
55        db: &'db dyn Database,
56        attr: &str,
57    ) -> Maybe<impl Iterator<Item = &'db Attribute<'db>>> {
58        Ok(self.attributes_elements(db)?.iter().filter(move |a| a.id.long(db) == attr))
59    }
60
61    /// Find first attribute attached to this node whose name (without args) is exactly `attr`.
62    fn find_attr(&self, db: &'db dyn Database, attr: &str) -> Maybe<Option<&'db Attribute<'db>>> {
63        Ok(self.query_attr(db, attr)?.next())
64    }
65
66    /// Check if this node has an attribute whose name (without args) is exactly `attr`.
67    fn has_attr(&self, db: &'db dyn Database, attr: &str) -> Maybe<bool> {
68        Ok(self.find_attr(db, attr)?.is_some())
69    }
70
71    /// Checks if the given object has an attribute with the given name and argument.
72    fn has_attr_with_arg(
73        &self,
74        db: &'db dyn Database,
75        attr_name: &str,
76        arg_name: &str,
77    ) -> Maybe<bool> {
78        Ok(self.query_attr(db, attr_name)?.any(|attr| attr.is_single_unnamed_arg(db, arg_name)))
79    }
80}
81
82impl<'db> SemanticQueryAttrs<'db> for ModuleId<'db> {
83    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
84        db.module_attributes(*self)
85    }
86}
87impl<'db> SemanticQueryAttrs<'db> for StructId<'db> {
88    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
89        db.struct_attributes(*self)
90    }
91}
92impl<'db> SemanticQueryAttrs<'db> for ConcreteStructId<'db> {
93    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
94        self.struct_id(db).attributes_elements(db)
95    }
96}
97impl<'db> SemanticQueryAttrs<'db> for TraitId<'db> {
98    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
99        db.trait_attributes(*self)
100    }
101}
102impl<'db> SemanticQueryAttrs<'db> for FunctionWithBodyId<'db> {
103    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
104        db.function_with_body_attributes(*self)
105    }
106}
107impl<'db> SemanticQueryAttrs<'db> for ImplDefId<'db> {
108    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
109        db.impl_def_attributes(*self)
110    }
111}
112impl<'db> SemanticQueryAttrs<'db> for ImplAliasId<'db> {
113    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
114        db.impl_alias_attributes(*self)
115    }
116}
117impl<'db> SemanticQueryAttrs<'db> for EnumId<'db> {
118    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
119        db.enum_attributes(*self)
120    }
121}
122impl<'db> SemanticQueryAttrs<'db> for ConcreteEnumId<'db> {
123    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
124        self.enum_id(db).attributes_elements(db)
125    }
126}
127impl<'db> SemanticQueryAttrs<'db> for ExternTypeId<'db> {
128    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
129        db.extern_type_attributes(*self)
130    }
131}
132impl<'db> SemanticQueryAttrs<'db> for ConcreteExternTypeId<'db> {
133    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
134        self.extern_type_id(db).attributes_elements(db)
135    }
136}
137impl<'db> SemanticQueryAttrs<'db> for SubmoduleId<'db> {
138    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
139        ModuleId::Submodule(*self).attributes_elements(db)
140    }
141}
142impl<'db> SemanticQueryAttrs<'db> for FreeFunctionId<'db> {
143    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
144        FunctionWithBodyId::Free(*self).attributes_elements(db)
145    }
146}
147
148impl<'db> SemanticQueryAttrs<'db> for TraitTypeId<'db> {
149    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
150        db.trait_type_attributes(*self)
151    }
152}
153impl<'db> SemanticQueryAttrs<'db> for TraitFunctionId<'db> {
154    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
155        db.trait_function_attributes(*self)
156    }
157}
158
159impl<'db> SemanticQueryAttrs<'db> for ImplTypeDefId<'db> {
160    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
161        db.impl_type_def_attributes(*self)
162    }
163}
164impl<'db> SemanticQueryAttrs<'db> for ImplFunctionId<'db> {
165    fn attributes_elements(&self, db: &'db dyn Database) -> Maybe<&'db [Attribute<'db>]> {
166        db.impl_function_attributes(*self)
167    }
168}