cairo_lang_syntax/node/
helpers.rs

1use cairo_lang_utils::LookupIntern;
2use smol_str::SmolStr;
3
4use super::ast::{
5    self, FunctionDeclaration, FunctionDeclarationGreen, FunctionWithBody, FunctionWithBodyPtr,
6    ImplItem, ItemConstant, ItemEnum, ItemExternFunction, ItemExternFunctionPtr, ItemExternType,
7    ItemImpl, ItemImplAlias, ItemInlineMacro, ItemModule, ItemStruct, ItemTrait, ItemTypeAlias,
8    ItemUse, Member, Modifier, ModuleItem, OptionArgListParenthesized, Statement, StatementBreak,
9    StatementContinue, StatementExpr, StatementLet, StatementReturn, TerminalIdentifier,
10    TerminalIdentifierGreen, TokenIdentifierGreen, TraitItem, TraitItemConstant, TraitItemFunction,
11    TraitItemFunctionPtr, TraitItemImpl, TraitItemType, UsePathLeaf, Variant, WrappedArgList,
12};
13use super::db::SyntaxGroup;
14use super::ids::SyntaxStablePtrId;
15use super::kind::SyntaxKind;
16use super::{SyntaxNode, Terminal, TypedStablePtr, TypedSyntaxNode};
17use crate::node::ast::{Attribute, AttributeList};
18use crate::node::green::GreenNodeDetails;
19
20#[cfg(test)]
21#[path = "helpers_test.rs"]
22mod test;
23
24pub trait GetIdentifier {
25    fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr;
26}
27impl ast::UsePathLeafPtr {
28    pub fn name_green(&self, _syntax_db: &dyn SyntaxGroup) -> Self {
29        *self
30    }
31}
32impl GetIdentifier for ast::UsePathLeafPtr {
33    fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
34        let alias_clause_green = self.alias_clause_green(db).0;
35        let green_node = alias_clause_green.lookup_intern(db);
36        let children = match &green_node.details {
37            GreenNodeDetails::Node { children, width: _ } => children,
38            _ => panic!("Unexpected token"),
39        };
40        if !children.is_empty() {
41            return ast::TerminalIdentifierGreen(children[ast::AliasClause::INDEX_ALIAS])
42                .identifier(db);
43        }
44        let ident_green = self.ident_green(db);
45        ident_green.identifier(db)
46    }
47}
48impl GetIdentifier for ast::PathSegmentGreen {
49    /// Retrieves the text of the last identifier in the path.
50    fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
51        let green_node = self.0.lookup_intern(db);
52        let children = match &green_node.details {
53            GreenNodeDetails::Node { children, width: _ } => children,
54            _ => panic!("Unexpected token"),
55        };
56        let identifier = ast::TerminalIdentifierGreen(children[0]);
57        identifier.identifier(db)
58    }
59}
60impl GetIdentifier for ast::ExprPathGreen {
61    /// Retrieves the text of the last identifier in the path.
62    fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
63        let green_node = self.0.lookup_intern(db);
64        let children = match &green_node.details {
65            GreenNodeDetails::Node { children, width: _ } => children,
66            _ => panic!("Unexpected token"),
67        };
68        assert_eq!(children.len() & 1, 1, "Expected an odd number of elements in the path.");
69        let segment_green = ast::PathSegmentGreen(*children.last().unwrap());
70        segment_green.identifier(db)
71    }
72}
73impl GetIdentifier for ast::TerminalIdentifierGreen {
74    fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
75        match &self.0.lookup_intern(db).details {
76            GreenNodeDetails::Token(_) => "Unexpected token".into(),
77            GreenNodeDetails::Node { children, width: _ } => {
78                TokenIdentifierGreen(children[1]).text(db)
79            }
80        }
81    }
82}
83impl GetIdentifier for ast::ExprPath {
84    /// Retrieves the identifier of the last segment of the path.
85    fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
86        self.elements(db).last().cloned().unwrap().identifier(db)
87    }
88}
89
90/// Helper trait for ast::PathSegment.
91pub trait PathSegmentEx {
92    fn identifier_ast(&self, db: &dyn SyntaxGroup) -> ast::TerminalIdentifier;
93    fn generic_args(&self, db: &dyn SyntaxGroup) -> Option<Vec<ast::GenericArg>>;
94}
95impl PathSegmentEx for ast::PathSegment {
96    /// Retrieves the identifier ast of a path segment.
97    fn identifier_ast(&self, db: &dyn SyntaxGroup) -> ast::TerminalIdentifier {
98        match self {
99            ast::PathSegment::Simple(segment) => segment.ident(db),
100            ast::PathSegment::WithGenericArgs(segment) => segment.ident(db),
101            ast::PathSegment::Missing(missing_segment) => missing_segment.ident(db),
102        }
103    }
104    fn generic_args(&self, db: &dyn SyntaxGroup) -> Option<Vec<ast::GenericArg>> {
105        match self {
106            ast::PathSegment::Simple(_) | ast::PathSegment::Missing(_) => None,
107            ast::PathSegment::WithGenericArgs(segment) => {
108                Some(segment.generic_args(db).generic_args(db).elements(db))
109            }
110        }
111    }
112}
113impl GetIdentifier for ast::PathSegment {
114    /// Retrieves the text of the segment (without the generic args).
115    fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
116        self.identifier_ast(db).text(db)
117    }
118}
119impl GetIdentifier for ast::Modifier {
120    fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
121        match self {
122            Modifier::Ref(r) => r.text(db),
123            Modifier::Mut(m) => m.text(db),
124        }
125    }
126}
127
128/// Trait for ast object with a name terminal.
129pub trait NameGreen {
130    /// Returns the TerminalIdentifierGreen of the `name` node.
131    fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen;
132}
133
134impl NameGreen for FunctionDeclarationGreen {
135    fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen {
136        TerminalIdentifierGreen(
137            self.0.lookup_intern(db).children()[FunctionDeclaration::INDEX_NAME],
138        )
139    }
140}
141
142impl NameGreen for FunctionWithBodyPtr {
143    fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen {
144        self.declaration_green(db).name_green(db)
145    }
146}
147
148impl NameGreen for ItemExternFunctionPtr {
149    fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen {
150        self.declaration_green(db).name_green(db)
151    }
152}
153
154impl NameGreen for TraitItemFunctionPtr {
155    fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen {
156        self.declaration_green(db).name_green(db)
157    }
158}
159
160/// Provides methods to extract a _name_ of AST objects.
161pub trait HasName {
162    /// Gets a [`TerminalIdentifier`] that represents a _name_ of this AST object.
163    fn name(&self, db: &dyn SyntaxGroup) -> ast::TerminalIdentifier;
164}
165
166impl HasName for FunctionWithBody {
167    fn name(&self, db: &dyn SyntaxGroup) -> TerminalIdentifier {
168        self.declaration(db).name(db)
169    }
170}
171
172impl HasName for ItemExternFunction {
173    fn name(&self, db: &dyn SyntaxGroup) -> TerminalIdentifier {
174        self.declaration(db).name(db)
175    }
176}
177
178impl HasName for TraitItemFunction {
179    fn name(&self, db: &dyn SyntaxGroup) -> TerminalIdentifier {
180        self.declaration(db).name(db)
181    }
182}
183
184impl HasName for UsePathLeaf {
185    fn name(&self, db: &dyn SyntaxGroup) -> TerminalIdentifier {
186        match self.alias_clause(db) {
187            ast::OptionAliasClause::Empty(_) => self.ident(db).identifier_ast(db),
188            ast::OptionAliasClause::AliasClause(alias) => alias.alias(db),
189        }
190    }
191}
192
193pub trait GenericParamEx {
194    /// Returns the name of a generic param if one exists.
195    fn name(&self, db: &dyn SyntaxGroup) -> Option<ast::TerminalIdentifier>;
196}
197impl GenericParamEx for ast::GenericParam {
198    fn name(&self, db: &dyn SyntaxGroup) -> Option<ast::TerminalIdentifier> {
199        match self {
200            ast::GenericParam::Type(t) => Some(t.name(db)),
201            ast::GenericParam::Const(c) => Some(c.name(db)),
202            ast::GenericParam::ImplNamed(i) => Some(i.name(db)),
203            ast::GenericParam::ImplAnonymous(_) => None,
204            ast::GenericParam::NegativeImpl(_) => None,
205        }
206    }
207}
208
209/// Checks if the given attribute has a single argument with the given name.
210pub fn is_single_arg_attr(db: &dyn SyntaxGroup, attr: &Attribute, arg_name: &str) -> bool {
211    match attr.arguments(db) {
212        OptionArgListParenthesized::ArgListParenthesized(args) => {
213            matches!(&args.arguments(db).elements(db)[..],
214                    [arg] if arg.as_syntax_node().get_text_without_trivia(db) == arg_name)
215        }
216        OptionArgListParenthesized::Empty(_) => false,
217    }
218}
219
220/// Trait for querying attributes of AST items.
221pub trait QueryAttrs {
222    /// Generic call `self.attributes(db).elements(db)`.
223    ///
224    /// Implementation detail, should not be used by this trait users.
225    #[doc(hidden)]
226    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute>;
227
228    /// Collect all attributes named exactly `attr` attached to this node.
229    fn query_attr(&self, db: &dyn SyntaxGroup, attr: &str) -> Vec<Attribute> {
230        self.attributes_elements(db)
231            .into_iter()
232            .filter(|a| a.attr(db).as_syntax_node().get_text_without_trivia(db) == attr)
233            .collect()
234    }
235
236    /// Find first attribute named exactly `attr` attached do this node.
237    fn find_attr(&self, db: &dyn SyntaxGroup, attr: &str) -> Option<Attribute> {
238        self.query_attr(db, attr).into_iter().next()
239    }
240
241    /// Check if this node has an attribute named exactly `attr`.
242    fn has_attr(&self, db: &dyn SyntaxGroup, attr: &str) -> bool {
243        self.find_attr(db, attr).is_some()
244    }
245
246    /// Checks if the given object has an attribute with the given name and argument.
247    fn has_attr_with_arg(&self, db: &dyn SyntaxGroup, attr_name: &str, arg_name: &str) -> bool {
248        self.query_attr(db, attr_name).iter().any(|attr| is_single_arg_attr(db, attr, arg_name))
249    }
250}
251
252impl QueryAttrs for ItemConstant {
253    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
254        self.attributes(db).elements(db)
255    }
256}
257impl QueryAttrs for ItemModule {
258    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
259        self.attributes(db).elements(db)
260    }
261}
262impl QueryAttrs for FunctionWithBody {
263    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
264        self.attributes(db).elements(db)
265    }
266}
267impl QueryAttrs for ItemUse {
268    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
269        self.attributes(db).elements(db)
270    }
271}
272impl QueryAttrs for ItemExternFunction {
273    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
274        self.attributes(db).elements(db)
275    }
276}
277impl QueryAttrs for ItemExternType {
278    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
279        self.attributes(db).elements(db)
280    }
281}
282impl QueryAttrs for ItemTrait {
283    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
284        self.attributes(db).elements(db)
285    }
286}
287impl QueryAttrs for ItemImpl {
288    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
289        self.attributes(db).elements(db)
290    }
291}
292impl QueryAttrs for ItemImplAlias {
293    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
294        self.attributes(db).elements(db)
295    }
296}
297impl QueryAttrs for ItemStruct {
298    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
299        self.attributes(db).elements(db)
300    }
301}
302impl QueryAttrs for ItemEnum {
303    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
304        self.attributes(db).elements(db)
305    }
306}
307impl QueryAttrs for ItemTypeAlias {
308    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
309        self.attributes(db).elements(db)
310    }
311}
312impl QueryAttrs for TraitItemFunction {
313    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
314        self.attributes(db).elements(db)
315    }
316}
317impl QueryAttrs for TraitItemType {
318    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
319        self.attributes(db).elements(db)
320    }
321}
322impl QueryAttrs for TraitItemConstant {
323    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
324        self.attributes(db).elements(db)
325    }
326}
327impl QueryAttrs for TraitItemImpl {
328    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
329        self.attributes(db).elements(db)
330    }
331}
332impl QueryAttrs for TraitItem {
333    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
334        match self {
335            TraitItem::Function(item) => item.attributes_elements(db),
336            TraitItem::Type(item) => item.attributes_elements(db),
337            TraitItem::Constant(item) => item.attributes_elements(db),
338            TraitItem::Impl(item) => item.attributes_elements(db),
339            TraitItem::Missing(_) => vec![],
340        }
341    }
342}
343
344impl QueryAttrs for ItemInlineMacro {
345    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
346        self.attributes(db).elements(db)
347    }
348}
349
350impl QueryAttrs for ModuleItem {
351    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
352        match self {
353            ModuleItem::Constant(item) => item.attributes_elements(db),
354            ModuleItem::Module(item) => item.attributes_elements(db),
355            ModuleItem::FreeFunction(item) => item.attributes_elements(db),
356            ModuleItem::Use(item) => item.attributes_elements(db),
357            ModuleItem::ExternFunction(item) => item.attributes_elements(db),
358            ModuleItem::ExternType(item) => item.attributes_elements(db),
359            ModuleItem::Trait(item) => item.attributes_elements(db),
360            ModuleItem::Impl(item) => item.attributes_elements(db),
361            ModuleItem::ImplAlias(item) => item.attributes_elements(db),
362            ModuleItem::Struct(item) => item.attributes_elements(db),
363            ModuleItem::Enum(item) => item.attributes_elements(db),
364            ModuleItem::TypeAlias(item) => item.attributes_elements(db),
365            ModuleItem::InlineMacro(item) => item.attributes_elements(db),
366            ModuleItem::Missing(_) => vec![],
367            ModuleItem::HeaderDoc(_) => vec![],
368        }
369    }
370}
371
372impl QueryAttrs for ImplItem {
373    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
374        match self {
375            ImplItem::Function(item) => item.attributes_elements(db),
376            ImplItem::Type(item) => item.attributes_elements(db),
377            ImplItem::Constant(item) => item.attributes_elements(db),
378            ImplItem::Impl(item) => item.attributes_elements(db),
379            ImplItem::Module(item) => item.attributes_elements(db),
380            ImplItem::Use(item) => item.attributes_elements(db),
381            ImplItem::ExternFunction(item) => item.attributes_elements(db),
382            ImplItem::ExternType(item) => item.attributes_elements(db),
383            ImplItem::Trait(item) => item.attributes_elements(db),
384            ImplItem::Struct(item) => item.attributes_elements(db),
385            ImplItem::Enum(item) => item.attributes_elements(db),
386            ImplItem::Missing(_) => vec![],
387        }
388    }
389}
390
391impl QueryAttrs for AttributeList {
392    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
393        self.elements(db)
394    }
395}
396impl QueryAttrs for Member {
397    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
398        self.attributes(db).elements(db)
399    }
400}
401
402impl QueryAttrs for Variant {
403    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
404        self.attributes(db).elements(db)
405    }
406}
407
408impl QueryAttrs for StatementBreak {
409    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
410        self.attributes(db).elements(db)
411    }
412}
413
414impl QueryAttrs for StatementContinue {
415    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
416        self.attributes(db).elements(db)
417    }
418}
419
420impl QueryAttrs for StatementReturn {
421    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
422        self.attributes(db).elements(db)
423    }
424}
425
426impl QueryAttrs for StatementLet {
427    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
428        self.attributes(db).elements(db)
429    }
430}
431
432impl QueryAttrs for StatementExpr {
433    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
434        self.attributes(db).elements(db)
435    }
436}
437
438/// Allows querying attributes of a syntax node, any typed node which QueryAttrs is implemented for
439/// should be added here.
440impl QueryAttrs for SyntaxNode {
441    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
442        match self.kind(db) {
443            SyntaxKind::ItemConstant => {
444                ast::ItemConstant::from_syntax_node(db, self.clone()).attributes_elements(db)
445            }
446            SyntaxKind::ItemModule => {
447                ast::ItemModule::from_syntax_node(db, self.clone()).attributes_elements(db)
448            }
449            SyntaxKind::FunctionWithBody => {
450                ast::FunctionWithBody::from_syntax_node(db, self.clone()).attributes_elements(db)
451            }
452            SyntaxKind::ItemUse => {
453                ast::ItemUse::from_syntax_node(db, self.clone()).attributes_elements(db)
454            }
455            SyntaxKind::ItemExternFunction => {
456                ast::ItemExternFunction::from_syntax_node(db, self.clone()).attributes_elements(db)
457            }
458            SyntaxKind::ItemExternType => {
459                ast::ItemExternType::from_syntax_node(db, self.clone()).attributes_elements(db)
460            }
461            SyntaxKind::ItemTrait => {
462                ast::ItemTrait::from_syntax_node(db, self.clone()).attributes_elements(db)
463            }
464            SyntaxKind::ItemImpl => {
465                ast::ItemImpl::from_syntax_node(db, self.clone()).attributes_elements(db)
466            }
467            SyntaxKind::ItemImplAlias => {
468                ast::ItemImplAlias::from_syntax_node(db, self.clone()).attributes_elements(db)
469            }
470            SyntaxKind::ItemStruct => {
471                ast::ItemStruct::from_syntax_node(db, self.clone()).attributes_elements(db)
472            }
473            SyntaxKind::ItemEnum => {
474                ast::ItemEnum::from_syntax_node(db, self.clone()).attributes_elements(db)
475            }
476            SyntaxKind::ItemTypeAlias => {
477                ast::ItemTypeAlias::from_syntax_node(db, self.clone()).attributes_elements(db)
478            }
479            SyntaxKind::TraitItemFunction => {
480                ast::TraitItemFunction::from_syntax_node(db, self.clone()).attributes_elements(db)
481            }
482            SyntaxKind::ItemInlineMacro => {
483                ast::ItemInlineMacro::from_syntax_node(db, self.clone()).attributes_elements(db)
484            }
485            SyntaxKind::AttributeList => {
486                ast::AttributeList::from_syntax_node(db, self.clone()).attributes_elements(db)
487            }
488            SyntaxKind::Member => {
489                ast::Member::from_syntax_node(db, self.clone()).attributes_elements(db)
490            }
491            SyntaxKind::Variant => {
492                ast::Variant::from_syntax_node(db, self.clone()).attributes_elements(db)
493            }
494            SyntaxKind::StatementBreak => {
495                ast::StatementBreak::from_syntax_node(db, self.clone()).attributes_elements(db)
496            }
497            SyntaxKind::StatementContinue => {
498                ast::StatementContinue::from_syntax_node(db, self.clone()).attributes_elements(db)
499            }
500            SyntaxKind::StatementReturn => {
501                ast::StatementReturn::from_syntax_node(db, self.clone()).attributes_elements(db)
502            }
503            SyntaxKind::StatementLet => {
504                ast::StatementLet::from_syntax_node(db, self.clone()).attributes_elements(db)
505            }
506            SyntaxKind::StatementExpr => {
507                ast::StatementExpr::from_syntax_node(db, self.clone()).attributes_elements(db)
508            }
509            _ => vec![],
510        }
511    }
512}
513
514impl QueryAttrs for Statement {
515    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
516        match self {
517            Statement::Break(statement) => statement.attributes_elements(db),
518            Statement::Continue(statement) => statement.attributes_elements(db),
519            Statement::Return(statement) => statement.attributes_elements(db),
520            Statement::Let(statement) => statement.attributes_elements(db),
521            Statement::Expr(statement) => statement.attributes_elements(db),
522            Statement::Item(statement) => statement.item(db).attributes_elements(db),
523            Statement::Missing(_) => vec![],
524        }
525    }
526}
527pub trait WrappedArgListHelper {
528    /// Pills the wrapping brackets to get the argument list. Returns None if `self` is `Missing`.
529    fn arg_list(&self, db: &dyn SyntaxGroup) -> Option<ast::ArgList>;
530    /// Gets the syntax node of the right wrapping bracket.
531    fn right_bracket_syntax_node(&self, db: &dyn SyntaxGroup) -> SyntaxNode;
532    /// Gets the syntax node of the left wrapping bracket.
533    fn left_bracket_syntax_node(&self, db: &dyn SyntaxGroup) -> SyntaxNode;
534    /// Gets a stable pointer to the left wrapping bracket.
535    fn left_bracket_stable_ptr(&self, db: &dyn SyntaxGroup) -> SyntaxStablePtrId;
536}
537impl WrappedArgListHelper for WrappedArgList {
538    fn arg_list(&self, db: &dyn SyntaxGroup) -> Option<ast::ArgList> {
539        match self {
540            WrappedArgList::ParenthesizedArgList(args) => Some(args.arguments(db)),
541            WrappedArgList::BracketedArgList(args) => Some(args.arguments(db)),
542            WrappedArgList::BracedArgList(args) => Some(args.arguments(db)),
543            WrappedArgList::Missing(_) => None,
544        }
545    }
546
547    fn right_bracket_syntax_node(&self, db: &dyn SyntaxGroup) -> SyntaxNode {
548        match self {
549            WrappedArgList::ParenthesizedArgList(args) => args.rparen(db).as_syntax_node(),
550            WrappedArgList::BracketedArgList(args) => args.rbrack(db).as_syntax_node(),
551            WrappedArgList::BracedArgList(args) => args.rbrace(db).as_syntax_node(),
552            WrappedArgList::Missing(_) => self.as_syntax_node(),
553        }
554    }
555
556    fn left_bracket_syntax_node(&self, db: &dyn SyntaxGroup) -> SyntaxNode {
557        match self {
558            WrappedArgList::ParenthesizedArgList(args) => args.lparen(db).as_syntax_node(),
559            WrappedArgList::BracketedArgList(args) => args.lbrack(db).as_syntax_node(),
560            WrappedArgList::BracedArgList(args) => args.lbrace(db).as_syntax_node(),
561            WrappedArgList::Missing(_) => self.as_syntax_node(),
562        }
563    }
564
565    fn left_bracket_stable_ptr(&self, db: &dyn SyntaxGroup) -> SyntaxStablePtrId {
566        match self {
567            WrappedArgList::ParenthesizedArgList(args) => (&args.lparen(db)).into(),
568            WrappedArgList::BracketedArgList(args) => (&args.lbrack(db)).into(),
569            WrappedArgList::BracedArgList(args) => (&args.lbrace(db)).into(),
570            WrappedArgList::Missing(_) => self.into(),
571        }
572    }
573}
574
575pub trait WrappedGenericParamListHelper {
576    /// Checks whether there are 0 generic parameters
577    fn is_empty(&self, db: &dyn SyntaxGroup) -> bool;
578}
579impl WrappedGenericParamListHelper for ast::WrappedGenericParamList {
580    fn is_empty(&self, db: &dyn SyntaxGroup) -> bool {
581        self.generic_params(db).elements(db).is_empty()
582    }
583}
584
585pub trait OptionWrappedGenericParamListHelper {
586    /// Checks whether there are 0 generic parameters. True either when the generic params clause
587    /// doesn't exist or when it's empty
588    fn is_empty(&self, db: &dyn SyntaxGroup) -> bool;
589}
590impl OptionWrappedGenericParamListHelper for ast::OptionWrappedGenericParamList {
591    fn is_empty(&self, db: &dyn SyntaxGroup) -> bool {
592        match self {
593            ast::OptionWrappedGenericParamList::Empty(_) => true,
594            ast::OptionWrappedGenericParamList::WrappedGenericParamList(
595                wrapped_generic_param_list,
596            ) => wrapped_generic_param_list.is_empty(db),
597        }
598    }
599}
600
601/// Trait for getting the items of a body-item (an item that contains items), as a vector.
602pub trait BodyItems {
603    /// The type of an Item.
604    type Item;
605    /// Returns the items of the body-item as a vector.
606    /// Use with caution, as this includes items that may be filtered out by plugins.
607    /// Do note that plugins that directly run on this body-item without going/checking up on the
608    /// syntax tree may assume that e.g. out-of-config items were already filtered out.
609    /// Don't use on an item that is not the original plugin's context, unless you are sure that
610    /// while traversing the AST to get to it from the original plugin's context, you did not go
611    /// through another submodule.
612    fn items_vec(&self, db: &dyn SyntaxGroup) -> Vec<Self::Item>;
613}
614
615impl BodyItems for ast::ModuleBody {
616    type Item = ModuleItem;
617    fn items_vec(&self, db: &dyn SyntaxGroup) -> Vec<ModuleItem> {
618        self.items(db).elements(db)
619    }
620}
621
622impl BodyItems for ast::TraitBody {
623    type Item = TraitItem;
624    fn items_vec(&self, db: &dyn SyntaxGroup) -> Vec<TraitItem> {
625        self.items(db).elements(db)
626    }
627}
628
629impl BodyItems for ast::ImplBody {
630    type Item = ImplItem;
631    fn items_vec(&self, db: &dyn SyntaxGroup) -> Vec<ImplItem> {
632        self.items(db).elements(db)
633    }
634}
635
636/// Helper trait for ast::UsePath.
637pub trait UsePathEx {
638    /// Retrieves the item of a use path.
639    fn get_item(&self, db: &dyn SyntaxGroup) -> ast::ItemUse;
640}
641impl UsePathEx for ast::UsePath {
642    fn get_item(&self, db: &dyn SyntaxGroup) -> ast::ItemUse {
643        let mut node = self.as_syntax_node();
644        loop {
645            let Some(parent) = node.parent() else {
646                unreachable!("UsePath is not under an ItemUse.");
647            };
648            match parent.kind(db) {
649                SyntaxKind::ItemUse => {
650                    break ast::ItemUse::from_syntax_node(db, parent);
651                }
652                _ => node = parent,
653            }
654        }
655    }
656}
657
658impl UsePathLeaf {
659    /// Retrieves the stable pointer of the name of the leaf.
660    pub fn name_stable_ptr(&self, db: &dyn SyntaxGroup) -> SyntaxStablePtrId {
661        match self.alias_clause(db) {
662            ast::OptionAliasClause::Empty(_) => self.ident(db).stable_ptr().untyped(),
663            ast::OptionAliasClause::AliasClause(alias) => alias.alias(db).stable_ptr().untyped(),
664        }
665    }
666}
667
668/// Helper trait for check syntactically if a type is dependent on a given identifier.
669pub trait IsDependentType {
670    /// Returns true if `self` is dependent on `identifier` in an internal type.
671    /// For example given identifier `T` will return true for:
672    /// `T`, `Array<T>`, `Array<Array<T>>`, `(T, felt252)`.
673    /// Does not resolve paths, type aliases or named generics.
674    fn is_dependent_type(&self, db: &dyn SyntaxGroup, identifiers: &[&str]) -> bool;
675}
676
677impl IsDependentType for ast::ExprPath {
678    fn is_dependent_type(&self, db: &dyn SyntaxGroup, identifiers: &[&str]) -> bool {
679        let segments = self.elements(db);
680        if let [ast::PathSegment::Simple(arg_segment)] = &segments[..] {
681            identifiers.contains(&arg_segment.ident(db).text(db).as_str())
682        } else {
683            segments.into_iter().any(|segment| {
684                let ast::PathSegment::WithGenericArgs(with_generics) = segment else {
685                    return false;
686                };
687                with_generics.generic_args(db).generic_args(db).elements(db).iter().any(|arg| {
688                    let generic_arg_value = match arg {
689                        ast::GenericArg::Named(named) => named.value(db),
690                        ast::GenericArg::Unnamed(unnamed) => unnamed.value(db),
691                    };
692                    match generic_arg_value {
693                        ast::GenericArgValue::Expr(arg_expr) => {
694                            arg_expr.expr(db).is_dependent_type(db, identifiers)
695                        }
696                        ast::GenericArgValue::Underscore(_) => false,
697                    }
698                })
699            })
700        }
701    }
702}
703
704impl IsDependentType for ast::Expr {
705    fn is_dependent_type(&self, db: &dyn SyntaxGroup, identifiers: &[&str]) -> bool {
706        match self {
707            ast::Expr::Path(type_path) => type_path.is_dependent_type(db, identifiers),
708            ast::Expr::Unary(unary) => unary.expr(db).is_dependent_type(db, identifiers),
709            ast::Expr::Binary(binary) => {
710                binary.lhs(db).is_dependent_type(db, identifiers)
711                    || binary.rhs(db).is_dependent_type(db, identifiers)
712            }
713            ast::Expr::Tuple(tuple) => tuple
714                .expressions(db)
715                .elements(db)
716                .iter()
717                .any(|expr| expr.is_dependent_type(db, identifiers)),
718            ast::Expr::FixedSizeArray(arr) => {
719                arr.exprs(db)
720                    .elements(db)
721                    .iter()
722                    .any(|expr| expr.is_dependent_type(db, identifiers))
723                    || match arr.size(db) {
724                        ast::OptionFixedSizeArraySize::Empty(_) => false,
725                        ast::OptionFixedSizeArraySize::FixedSizeArraySize(size) => {
726                            size.size(db).is_dependent_type(db, identifiers)
727                        }
728                    }
729            }
730            ast::Expr::Literal(_)
731            | ast::Expr::ShortString(_)
732            | ast::Expr::String(_)
733            | ast::Expr::False(_)
734            | ast::Expr::True(_)
735            | ast::Expr::Parenthesized(_)
736            | ast::Expr::FunctionCall(_)
737            | ast::Expr::StructCtorCall(_)
738            | ast::Expr::Block(_)
739            | ast::Expr::Match(_)
740            | ast::Expr::If(_)
741            | ast::Expr::Loop(_)
742            | ast::Expr::While(_)
743            | ast::Expr::For(_)
744            | ast::Expr::Closure(_)
745            | ast::Expr::ErrorPropagate(_)
746            | ast::Expr::FieldInitShorthand(_)
747            | ast::Expr::Indexed(_)
748            | ast::Expr::InlineMacro(_)
749            | ast::Expr::Missing(_) => false,
750        }
751    }
752}