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, TerminalIdentifierGreen,
10    TokenIdentifierGreen, TraitItem, TraitItemConstant, TraitItemFunction, TraitItemFunctionPtr,
11    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        }
102    }
103    fn generic_args(&self, db: &dyn SyntaxGroup) -> Option<Vec<ast::GenericArg>> {
104        match self {
105            ast::PathSegment::Simple(_) => None,
106            ast::PathSegment::WithGenericArgs(segment) => {
107                Some(segment.generic_args(db).generic_args(db).elements(db))
108            }
109        }
110    }
111}
112impl GetIdentifier for ast::PathSegment {
113    /// Retrieves the text of the segment (without the generic args).
114    fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
115        self.identifier_ast(db).text(db)
116    }
117}
118impl GetIdentifier for ast::Modifier {
119    fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
120        match self {
121            Modifier::Ref(r) => r.text(db),
122            Modifier::Mut(m) => m.text(db),
123        }
124    }
125}
126
127/// Trait for ast object with a name terminal.
128pub trait NameGreen {
129    /// Returns the TerminalIdentifierGreen of the `name` node.
130    fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen;
131}
132
133impl NameGreen for FunctionDeclarationGreen {
134    fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen {
135        TerminalIdentifierGreen(
136            self.0.lookup_intern(db).children()[FunctionDeclaration::INDEX_NAME],
137        )
138    }
139}
140
141impl NameGreen for FunctionWithBodyPtr {
142    fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen {
143        self.declaration_green(db).name_green(db)
144    }
145}
146
147impl NameGreen for ItemExternFunctionPtr {
148    fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen {
149        self.declaration_green(db).name_green(db)
150    }
151}
152
153impl NameGreen for TraitItemFunctionPtr {
154    fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen {
155        self.declaration_green(db).name_green(db)
156    }
157}
158
159pub trait GenericParamEx {
160    /// Returns the name of a generic param if one exists.
161    fn name(&self, db: &dyn SyntaxGroup) -> Option<ast::TerminalIdentifier>;
162}
163impl GenericParamEx for ast::GenericParam {
164    fn name(&self, db: &dyn SyntaxGroup) -> Option<ast::TerminalIdentifier> {
165        match self {
166            ast::GenericParam::Type(t) => Some(t.name(db)),
167            ast::GenericParam::Const(c) => Some(c.name(db)),
168            ast::GenericParam::ImplNamed(i) => Some(i.name(db)),
169            ast::GenericParam::ImplAnonymous(_) => None,
170            ast::GenericParam::NegativeImpl(_) => None,
171        }
172    }
173}
174
175/// Checks if the given attribute has a single argument with the given name.
176pub fn is_single_arg_attr(db: &dyn SyntaxGroup, attr: &Attribute, arg_name: &str) -> bool {
177    match attr.arguments(db) {
178        OptionArgListParenthesized::ArgListParenthesized(args) => {
179            matches!(&args.arguments(db).elements(db)[..],
180                    [arg] if arg.as_syntax_node().get_text_without_trivia(db) == arg_name)
181        }
182        OptionArgListParenthesized::Empty(_) => false,
183    }
184}
185
186/// Trait for querying attributes of AST items.
187pub trait QueryAttrs {
188    /// Generic call `self.attributes(db).elements(db)`.
189    ///
190    /// Implementation detail, should not be used by this trait users.
191    #[doc(hidden)]
192    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute>;
193
194    /// Collect all attributes named exactly `attr` attached to this node.
195    fn query_attr(&self, db: &dyn SyntaxGroup, attr: &str) -> Vec<Attribute> {
196        self.attributes_elements(db)
197            .into_iter()
198            .filter(|a| a.attr(db).as_syntax_node().get_text_without_trivia(db) == attr)
199            .collect()
200    }
201
202    /// Find first attribute named exactly `attr` attached do this node.
203    fn find_attr(&self, db: &dyn SyntaxGroup, attr: &str) -> Option<Attribute> {
204        self.query_attr(db, attr).into_iter().next()
205    }
206
207    /// Check if this node has an attribute named exactly `attr`.
208    fn has_attr(&self, db: &dyn SyntaxGroup, attr: &str) -> bool {
209        self.find_attr(db, attr).is_some()
210    }
211
212    /// Checks if the given object has an attribute with the given name and argument.
213    fn has_attr_with_arg(&self, db: &dyn SyntaxGroup, attr_name: &str, arg_name: &str) -> bool {
214        self.query_attr(db, attr_name).iter().any(|attr| is_single_arg_attr(db, attr, arg_name))
215    }
216}
217
218impl QueryAttrs for ItemConstant {
219    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
220        self.attributes(db).elements(db)
221    }
222}
223impl QueryAttrs for ItemModule {
224    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
225        self.attributes(db).elements(db)
226    }
227}
228impl QueryAttrs for FunctionWithBody {
229    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
230        self.attributes(db).elements(db)
231    }
232}
233impl QueryAttrs for ItemUse {
234    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
235        self.attributes(db).elements(db)
236    }
237}
238impl QueryAttrs for ItemExternFunction {
239    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
240        self.attributes(db).elements(db)
241    }
242}
243impl QueryAttrs for ItemExternType {
244    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
245        self.attributes(db).elements(db)
246    }
247}
248impl QueryAttrs for ItemTrait {
249    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
250        self.attributes(db).elements(db)
251    }
252}
253impl QueryAttrs for ItemImpl {
254    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
255        self.attributes(db).elements(db)
256    }
257}
258impl QueryAttrs for ItemImplAlias {
259    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
260        self.attributes(db).elements(db)
261    }
262}
263impl QueryAttrs for ItemStruct {
264    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
265        self.attributes(db).elements(db)
266    }
267}
268impl QueryAttrs for ItemEnum {
269    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
270        self.attributes(db).elements(db)
271    }
272}
273impl QueryAttrs for ItemTypeAlias {
274    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
275        self.attributes(db).elements(db)
276    }
277}
278impl QueryAttrs for TraitItemFunction {
279    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
280        self.attributes(db).elements(db)
281    }
282}
283impl QueryAttrs for TraitItemType {
284    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
285        self.attributes(db).elements(db)
286    }
287}
288impl QueryAttrs for TraitItemConstant {
289    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
290        self.attributes(db).elements(db)
291    }
292}
293impl QueryAttrs for TraitItemImpl {
294    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
295        self.attributes(db).elements(db)
296    }
297}
298impl QueryAttrs for TraitItem {
299    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
300        match self {
301            TraitItem::Function(item) => item.attributes_elements(db),
302            TraitItem::Type(item) => item.attributes_elements(db),
303            TraitItem::Constant(item) => item.attributes_elements(db),
304            TraitItem::Impl(item) => item.attributes_elements(db),
305            TraitItem::Missing(_) => vec![],
306        }
307    }
308}
309
310impl QueryAttrs for ItemInlineMacro {
311    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
312        self.attributes(db).elements(db)
313    }
314}
315
316impl QueryAttrs for ModuleItem {
317    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
318        match self {
319            ModuleItem::Constant(item) => item.attributes_elements(db),
320            ModuleItem::Module(item) => item.attributes_elements(db),
321            ModuleItem::FreeFunction(item) => item.attributes_elements(db),
322            ModuleItem::Use(item) => item.attributes_elements(db),
323            ModuleItem::ExternFunction(item) => item.attributes_elements(db),
324            ModuleItem::ExternType(item) => item.attributes_elements(db),
325            ModuleItem::Trait(item) => item.attributes_elements(db),
326            ModuleItem::Impl(item) => item.attributes_elements(db),
327            ModuleItem::ImplAlias(item) => item.attributes_elements(db),
328            ModuleItem::Struct(item) => item.attributes_elements(db),
329            ModuleItem::Enum(item) => item.attributes_elements(db),
330            ModuleItem::TypeAlias(item) => item.attributes_elements(db),
331            ModuleItem::InlineMacro(item) => item.attributes_elements(db),
332            ModuleItem::Missing(_) => vec![],
333            ModuleItem::HeaderDoc(_) => vec![],
334        }
335    }
336}
337
338impl QueryAttrs for ImplItem {
339    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
340        match self {
341            ImplItem::Function(item) => item.attributes_elements(db),
342            ImplItem::Type(item) => item.attributes_elements(db),
343            ImplItem::Constant(item) => item.attributes_elements(db),
344            ImplItem::Impl(item) => item.attributes_elements(db),
345            ImplItem::Module(item) => item.attributes_elements(db),
346            ImplItem::Use(item) => item.attributes_elements(db),
347            ImplItem::ExternFunction(item) => item.attributes_elements(db),
348            ImplItem::ExternType(item) => item.attributes_elements(db),
349            ImplItem::Trait(item) => item.attributes_elements(db),
350            ImplItem::Struct(item) => item.attributes_elements(db),
351            ImplItem::Enum(item) => item.attributes_elements(db),
352            ImplItem::Missing(_) => vec![],
353        }
354    }
355}
356
357impl QueryAttrs for AttributeList {
358    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
359        self.elements(db)
360    }
361}
362impl QueryAttrs for Member {
363    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
364        self.attributes(db).elements(db)
365    }
366}
367
368impl QueryAttrs for Variant {
369    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
370        self.attributes(db).elements(db)
371    }
372}
373
374impl QueryAttrs for StatementBreak {
375    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
376        self.attributes(db).elements(db)
377    }
378}
379
380impl QueryAttrs for StatementContinue {
381    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
382        self.attributes(db).elements(db)
383    }
384}
385
386impl QueryAttrs for StatementReturn {
387    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
388        self.attributes(db).elements(db)
389    }
390}
391
392impl QueryAttrs for StatementLet {
393    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
394        self.attributes(db).elements(db)
395    }
396}
397
398impl QueryAttrs for StatementExpr {
399    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
400        self.attributes(db).elements(db)
401    }
402}
403
404/// Allows querying attributes of a syntax node, any typed node which QueryAttrs is implemented for
405/// should be added here.
406impl QueryAttrs for SyntaxNode {
407    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
408        match self.kind(db) {
409            SyntaxKind::ItemConstant => {
410                ast::ItemConstant::from_syntax_node(db, self.clone()).attributes_elements(db)
411            }
412            SyntaxKind::ItemModule => {
413                ast::ItemModule::from_syntax_node(db, self.clone()).attributes_elements(db)
414            }
415            SyntaxKind::FunctionWithBody => {
416                ast::FunctionWithBody::from_syntax_node(db, self.clone()).attributes_elements(db)
417            }
418            SyntaxKind::ItemUse => {
419                ast::ItemUse::from_syntax_node(db, self.clone()).attributes_elements(db)
420            }
421            SyntaxKind::ItemExternFunction => {
422                ast::ItemExternFunction::from_syntax_node(db, self.clone()).attributes_elements(db)
423            }
424            SyntaxKind::ItemExternType => {
425                ast::ItemExternType::from_syntax_node(db, self.clone()).attributes_elements(db)
426            }
427            SyntaxKind::ItemTrait => {
428                ast::ItemTrait::from_syntax_node(db, self.clone()).attributes_elements(db)
429            }
430            SyntaxKind::ItemImpl => {
431                ast::ItemImpl::from_syntax_node(db, self.clone()).attributes_elements(db)
432            }
433            SyntaxKind::ItemImplAlias => {
434                ast::ItemImplAlias::from_syntax_node(db, self.clone()).attributes_elements(db)
435            }
436            SyntaxKind::ItemStruct => {
437                ast::ItemStruct::from_syntax_node(db, self.clone()).attributes_elements(db)
438            }
439            SyntaxKind::ItemEnum => {
440                ast::ItemEnum::from_syntax_node(db, self.clone()).attributes_elements(db)
441            }
442            SyntaxKind::ItemTypeAlias => {
443                ast::ItemTypeAlias::from_syntax_node(db, self.clone()).attributes_elements(db)
444            }
445            SyntaxKind::TraitItemFunction => {
446                ast::TraitItemFunction::from_syntax_node(db, self.clone()).attributes_elements(db)
447            }
448            SyntaxKind::ItemInlineMacro => {
449                ast::ItemInlineMacro::from_syntax_node(db, self.clone()).attributes_elements(db)
450            }
451            SyntaxKind::AttributeList => {
452                ast::AttributeList::from_syntax_node(db, self.clone()).attributes_elements(db)
453            }
454            SyntaxKind::Member => {
455                ast::Member::from_syntax_node(db, self.clone()).attributes_elements(db)
456            }
457            SyntaxKind::Variant => {
458                ast::Variant::from_syntax_node(db, self.clone()).attributes_elements(db)
459            }
460            SyntaxKind::StatementBreak => {
461                ast::StatementBreak::from_syntax_node(db, self.clone()).attributes_elements(db)
462            }
463            SyntaxKind::StatementContinue => {
464                ast::StatementContinue::from_syntax_node(db, self.clone()).attributes_elements(db)
465            }
466            SyntaxKind::StatementReturn => {
467                ast::StatementReturn::from_syntax_node(db, self.clone()).attributes_elements(db)
468            }
469            SyntaxKind::StatementLet => {
470                ast::StatementLet::from_syntax_node(db, self.clone()).attributes_elements(db)
471            }
472            SyntaxKind::StatementExpr => {
473                ast::StatementExpr::from_syntax_node(db, self.clone()).attributes_elements(db)
474            }
475            _ => vec![],
476        }
477    }
478}
479
480impl QueryAttrs for Statement {
481    fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
482        match self {
483            Statement::Break(statement) => statement.attributes_elements(db),
484            Statement::Continue(statement) => statement.attributes_elements(db),
485            Statement::Return(statement) => statement.attributes_elements(db),
486            Statement::Let(statement) => statement.attributes_elements(db),
487            Statement::Expr(statement) => statement.attributes_elements(db),
488            Statement::Item(statement) => statement.item(db).attributes_elements(db),
489            Statement::Missing(_) => vec![],
490        }
491    }
492}
493pub trait WrappedArgListHelper {
494    /// Pills the wrapping brackets to get the argument list. Returns None if `self` is `Missing`.
495    fn arg_list(&self, db: &dyn SyntaxGroup) -> Option<ast::ArgList>;
496    /// Gets the syntax node of the right wrapping bracket.
497    fn right_bracket_syntax_node(&self, db: &dyn SyntaxGroup) -> SyntaxNode;
498    /// Gets the syntax node of the left wrapping bracket.
499    fn left_bracket_syntax_node(&self, db: &dyn SyntaxGroup) -> SyntaxNode;
500    /// Gets a stable pointer to the left wrapping bracket.
501    fn left_bracket_stable_ptr(&self, db: &dyn SyntaxGroup) -> SyntaxStablePtrId;
502}
503impl WrappedArgListHelper for WrappedArgList {
504    fn arg_list(&self, db: &dyn SyntaxGroup) -> Option<ast::ArgList> {
505        match self {
506            WrappedArgList::ParenthesizedArgList(args) => Some(args.arguments(db)),
507            WrappedArgList::BracketedArgList(args) => Some(args.arguments(db)),
508            WrappedArgList::BracedArgList(args) => Some(args.arguments(db)),
509            WrappedArgList::Missing(_) => None,
510        }
511    }
512
513    fn right_bracket_syntax_node(&self, db: &dyn SyntaxGroup) -> SyntaxNode {
514        match self {
515            WrappedArgList::ParenthesizedArgList(args) => args.rparen(db).as_syntax_node(),
516            WrappedArgList::BracketedArgList(args) => args.rbrack(db).as_syntax_node(),
517            WrappedArgList::BracedArgList(args) => args.rbrace(db).as_syntax_node(),
518            WrappedArgList::Missing(_) => self.as_syntax_node(),
519        }
520    }
521
522    fn left_bracket_syntax_node(&self, db: &dyn SyntaxGroup) -> SyntaxNode {
523        match self {
524            WrappedArgList::ParenthesizedArgList(args) => args.lparen(db).as_syntax_node(),
525            WrappedArgList::BracketedArgList(args) => args.lbrack(db).as_syntax_node(),
526            WrappedArgList::BracedArgList(args) => args.lbrace(db).as_syntax_node(),
527            WrappedArgList::Missing(_) => self.as_syntax_node(),
528        }
529    }
530
531    fn left_bracket_stable_ptr(&self, db: &dyn SyntaxGroup) -> SyntaxStablePtrId {
532        match self {
533            WrappedArgList::ParenthesizedArgList(args) => (&args.lparen(db)).into(),
534            WrappedArgList::BracketedArgList(args) => (&args.lbrack(db)).into(),
535            WrappedArgList::BracedArgList(args) => (&args.lbrace(db)).into(),
536            WrappedArgList::Missing(_) => self.into(),
537        }
538    }
539}
540
541pub trait WrappedGenericParamListHelper {
542    /// Checks whether there are 0 generic parameters
543    fn is_empty(&self, db: &dyn SyntaxGroup) -> bool;
544}
545impl WrappedGenericParamListHelper for ast::WrappedGenericParamList {
546    fn is_empty(&self, db: &dyn SyntaxGroup) -> bool {
547        self.generic_params(db).elements(db).is_empty()
548    }
549}
550
551pub trait OptionWrappedGenericParamListHelper {
552    /// Checks whether there are 0 generic parameters. True either when the generic params clause
553    /// doesn't exist or when it's empty
554    fn is_empty(&self, db: &dyn SyntaxGroup) -> bool;
555}
556impl OptionWrappedGenericParamListHelper for ast::OptionWrappedGenericParamList {
557    fn is_empty(&self, db: &dyn SyntaxGroup) -> bool {
558        match self {
559            ast::OptionWrappedGenericParamList::Empty(_) => true,
560            ast::OptionWrappedGenericParamList::WrappedGenericParamList(
561                wrapped_generic_param_list,
562            ) => wrapped_generic_param_list.is_empty(db),
563        }
564    }
565}
566
567/// Trait for getting the items of a body-item (an item that contains items), as a vector.
568pub trait BodyItems {
569    /// The type of an Item.
570    type Item;
571    /// Returns the items of the body-item as a vector.
572    /// Use with caution, as this includes items that may be filtered out by plugins.
573    /// Do note that plugins that directly run on this body-item without going/checking up on the
574    /// syntax tree may assume that e.g. out-of-config items were already filtered out.
575    /// Don't use on an item that is not the original plugin's context, unless you are sure that
576    /// while traversing the AST to get to it from the original plugin's context, you did not go
577    /// through another submodule.
578    fn items_vec(&self, db: &dyn SyntaxGroup) -> Vec<Self::Item>;
579}
580
581impl BodyItems for ast::ModuleBody {
582    type Item = ModuleItem;
583    fn items_vec(&self, db: &dyn SyntaxGroup) -> Vec<ModuleItem> {
584        self.items(db).elements(db)
585    }
586}
587
588impl BodyItems for ast::TraitBody {
589    type Item = TraitItem;
590    fn items_vec(&self, db: &dyn SyntaxGroup) -> Vec<TraitItem> {
591        self.items(db).elements(db)
592    }
593}
594
595impl BodyItems for ast::ImplBody {
596    type Item = ImplItem;
597    fn items_vec(&self, db: &dyn SyntaxGroup) -> Vec<ImplItem> {
598        self.items(db).elements(db)
599    }
600}
601
602/// Helper trait for ast::UsePath.
603pub trait UsePathEx {
604    /// Retrieves the item of a use path.
605    fn get_item(&self, db: &dyn SyntaxGroup) -> ast::ItemUse;
606}
607impl UsePathEx for ast::UsePath {
608    fn get_item(&self, db: &dyn SyntaxGroup) -> ast::ItemUse {
609        let mut node = self.as_syntax_node();
610        loop {
611            let Some(parent) = node.parent() else {
612                unreachable!("UsePath is not under an ItemUse.");
613            };
614            match parent.kind(db) {
615                SyntaxKind::ItemUse => {
616                    break ast::ItemUse::from_syntax_node(db, parent);
617                }
618                _ => node = parent,
619            }
620        }
621    }
622}
623
624impl UsePathLeaf {
625    /// Retrieves the stable pointer of the name of the leaf.
626    pub fn name_stable_ptr(&self, db: &dyn SyntaxGroup) -> SyntaxStablePtrId {
627        match self.alias_clause(db) {
628            ast::OptionAliasClause::Empty(_) => self.ident(db).stable_ptr().untyped(),
629            ast::OptionAliasClause::AliasClause(alias) => alias.alias(db).stable_ptr().untyped(),
630        }
631    }
632}