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