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, ItemMacroDeclaration, ItemModule, ItemStruct,
8 ItemTrait, ItemTypeAlias, ItemUse, Member, Modifier, ModuleItem, OptionArgListParenthesized,
9 Statement, StatementBreak, StatementContinue, StatementExpr, StatementLet, StatementReturn,
10 TerminalIdentifier, TerminalIdentifierGreen, TokenIdentifierGreen, TraitItem,
11 TraitItemConstant, TraitItemFunction, TraitItemFunctionPtr, TraitItemImpl, TraitItemType,
12 UsePathLeaf, Variant, WrappedArgList,
13};
14use super::db::SyntaxGroup;
15use super::ids::SyntaxStablePtrId;
16use super::kind::SyntaxKind;
17use super::{SyntaxNode, Terminal, TypedStablePtr, TypedSyntaxNode};
18use crate::node::ast::{Attribute, AttributeList};
19use crate::node::green::GreenNodeDetails;
20
21#[cfg(test)]
22#[path = "helpers_test.rs"]
23mod test;
24
25pub trait GetIdentifier {
26 fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr;
27}
28impl ast::UsePathLeafPtr {
29 pub fn name_green(&self, _syntax_db: &dyn SyntaxGroup) -> Self {
30 *self
31 }
32}
33impl GetIdentifier for ast::UsePathLeafPtr {
34 fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
35 let alias_clause_green = self.alias_clause_green(db).0;
36 let green_node = alias_clause_green.lookup_intern(db);
37 let children = match &green_node.details {
38 GreenNodeDetails::Node { children, width: _ } => children,
39 _ => panic!("Unexpected token"),
40 };
41 if !children.is_empty() {
42 return ast::TerminalIdentifierGreen(children[ast::AliasClause::INDEX_ALIAS])
43 .identifier(db);
44 }
45 let ident_green = self.ident_green(db);
46 let ident = ident_green.identifier(db);
47 if ident != "self" {
48 return ident;
49 }
50 let mut node = self.0.lookup(db);
51 loop {
52 node = if let Some(parent) = node.parent(db) {
53 parent
54 } else {
55 return ident;
56 };
57 if matches!(node.kind(db), SyntaxKind::UsePathSingle) {
58 return ast::UsePathSingle::from_syntax_node(db, node).ident(db).identifier(db);
59 }
60 }
61 }
62}
63impl GetIdentifier for ast::PathSegmentGreen {
64 fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
66 let green_node = self.0.lookup_intern(db);
67 let children = match &green_node.details {
68 GreenNodeDetails::Node { children, width: _ } => children,
69 _ => panic!("Unexpected token"),
70 };
71 let identifier = ast::TerminalIdentifierGreen(children[0]);
72 identifier.identifier(db)
73 }
74}
75impl GetIdentifier for ast::ExprPathGreen {
76 fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
78 let green_node = self.0.lookup_intern(db);
79 let children = match &green_node.details {
80 GreenNodeDetails::Node { children, width: _ } => children,
81 _ => panic!("Unexpected token"),
82 };
83 let segment_green = ast::ExprPathInnerGreen(*children.last().unwrap());
84 segment_green.identifier(db)
85 }
86}
87
88impl GetIdentifier for ast::ExprPathInnerGreen {
89 fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
91 let green_node = self.0.lookup_intern(db);
92 let children = match &green_node.details {
93 GreenNodeDetails::Node { children, width: _ } => children,
94 _ => panic!("Unexpected token"),
95 };
96 assert_eq!(children.len() & 1, 1, "Expected an odd number of elements in the path.");
97 let segment_green = ast::PathSegmentGreen(*children.last().unwrap());
98 segment_green.identifier(db)
99 }
100}
101impl GetIdentifier for ast::TerminalIdentifierGreen {
102 fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
103 match &self.0.lookup_intern(db).details {
104 GreenNodeDetails::Token(_) => "Unexpected token".into(),
105 GreenNodeDetails::Node { children, width: _ } => {
106 TokenIdentifierGreen(children[1]).text(db)
107 }
108 }
109 }
110}
111impl GetIdentifier for ast::ExprPath {
112 fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
114 self.segments(db).elements(db).next_back().unwrap().identifier(db)
115 }
116}
117
118pub trait PathSegmentEx {
120 fn identifier_ast(&self, db: &dyn SyntaxGroup) -> ast::TerminalIdentifier;
121 fn generic_args(&self, db: &dyn SyntaxGroup) -> Option<Vec<ast::GenericArg>>;
122}
123impl PathSegmentEx for ast::PathSegment {
124 fn identifier_ast(&self, db: &dyn SyntaxGroup) -> ast::TerminalIdentifier {
126 match self {
127 ast::PathSegment::Simple(segment) => segment.ident(db),
128 ast::PathSegment::WithGenericArgs(segment) => segment.ident(db),
129 ast::PathSegment::Missing(missing_segment) => missing_segment.ident(db),
130 }
131 }
132 fn generic_args(&self, db: &dyn SyntaxGroup) -> Option<Vec<ast::GenericArg>> {
133 match self {
134 ast::PathSegment::Simple(_) | ast::PathSegment::Missing(_) => None,
135 ast::PathSegment::WithGenericArgs(segment) => {
136 Some(segment.generic_args(db).generic_args(db).elements_vec(db))
137 }
138 }
139 }
140}
141impl GetIdentifier for ast::PathSegment {
142 fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
144 match self {
145 ast::PathSegment::Simple(segment) => segment.identifier(db),
146 ast::PathSegment::WithGenericArgs(segment) => segment.identifier(db),
147 ast::PathSegment::Missing(missing_segment) => missing_segment.identifier(db),
148 }
149 }
150}
151impl GetIdentifier for ast::PathSegmentSimple {
152 fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
153 let green_node = self.as_syntax_node().green_node(db);
154 let GreenNodeDetails::Node { children, .. } = &green_node.details else {
155 panic!("Unexpected token");
156 };
157 TerminalIdentifierGreen(children[0]).identifier(db)
158 }
159}
160impl GetIdentifier for ast::PathSegmentWithGenericArgs {
161 fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
162 let green_node = self.as_syntax_node().green_node(db);
163 let GreenNodeDetails::Node { children, .. } = &green_node.details else {
164 panic!("Unexpected token");
165 };
166 TerminalIdentifierGreen(children[0]).identifier(db)
167 }
168}
169
170impl GetIdentifier for ast::PathSegmentMissing {
171 fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
172 let green_node = self.as_syntax_node().green_node(db);
173 let GreenNodeDetails::Node { children, .. } = &green_node.details else {
174 panic!("Unexpected token");
175 };
176 TerminalIdentifierGreen(children[0]).identifier(db)
177 }
178}
179
180impl GetIdentifier for ast::Modifier {
181 fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
182 match self {
183 Modifier::Ref(r) => r.text(db),
184 Modifier::Mut(m) => m.text(db),
185 }
186 }
187}
188
189pub trait NameGreen {
191 fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen;
193}
194
195impl NameGreen for FunctionDeclarationGreen {
196 fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen {
197 TerminalIdentifierGreen(
198 self.0.lookup_intern(db).children()[FunctionDeclaration::INDEX_NAME],
199 )
200 }
201}
202
203impl NameGreen for FunctionWithBodyPtr {
204 fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen {
205 self.declaration_green(db).name_green(db)
206 }
207}
208
209impl NameGreen for ItemExternFunctionPtr {
210 fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen {
211 self.declaration_green(db).name_green(db)
212 }
213}
214
215impl NameGreen for TraitItemFunctionPtr {
216 fn name_green(self, db: &dyn SyntaxGroup) -> TerminalIdentifierGreen {
217 self.declaration_green(db).name_green(db)
218 }
219}
220
221pub trait HasName {
223 fn name(&self, db: &dyn SyntaxGroup) -> ast::TerminalIdentifier;
225}
226
227impl HasName for FunctionWithBody {
228 fn name(&self, db: &dyn SyntaxGroup) -> TerminalIdentifier {
229 self.declaration(db).name(db)
230 }
231}
232
233impl HasName for ItemExternFunction {
234 fn name(&self, db: &dyn SyntaxGroup) -> TerminalIdentifier {
235 self.declaration(db).name(db)
236 }
237}
238
239impl HasName for TraitItemFunction {
240 fn name(&self, db: &dyn SyntaxGroup) -> TerminalIdentifier {
241 self.declaration(db).name(db)
242 }
243}
244
245impl HasName for UsePathLeaf {
246 fn name(&self, db: &dyn SyntaxGroup) -> TerminalIdentifier {
247 match self.alias_clause(db) {
248 ast::OptionAliasClause::Empty(_) => self.ident(db).identifier_ast(db),
249 ast::OptionAliasClause::AliasClause(alias) => alias.alias(db),
250 }
251 }
252}
253
254pub trait GenericParamEx {
255 fn name(&self, db: &dyn SyntaxGroup) -> Option<ast::TerminalIdentifier>;
257}
258impl GenericParamEx for ast::GenericParam {
259 fn name(&self, db: &dyn SyntaxGroup) -> Option<ast::TerminalIdentifier> {
260 match self {
261 ast::GenericParam::Type(t) => Some(t.name(db)),
262 ast::GenericParam::Const(c) => Some(c.name(db)),
263 ast::GenericParam::ImplNamed(i) => Some(i.name(db)),
264 ast::GenericParam::ImplAnonymous(_) => None,
265 ast::GenericParam::NegativeImpl(_) => None,
266 }
267 }
268}
269
270pub fn is_single_arg_attr(db: &dyn SyntaxGroup, attr: &Attribute, arg_name: &str) -> bool {
272 match attr.arguments(db) {
273 OptionArgListParenthesized::ArgListParenthesized(args) => {
274 matches!(&args.arguments(db).elements_vec(db)[..],
275 [arg] if arg.as_syntax_node().get_text_without_trivia(db) == arg_name)
276 }
277 OptionArgListParenthesized::Empty(_) => false,
278 }
279}
280
281pub trait QueryAttrs {
283 #[doc(hidden)]
288 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList>;
289
290 fn attributes_elements<'a>(
292 &self,
293 db: &'a dyn SyntaxGroup,
294 ) -> impl Iterator<Item = Attribute> + 'a {
295 self.try_attributes(db).into_iter().flat_map(move |attrs| attrs.elements(db))
296 }
297
298 fn query_attr<'a>(
300 &self,
301 db: &'a dyn SyntaxGroup,
302 attr: &'a str,
303 ) -> impl Iterator<Item = Attribute> + 'a {
304 self.attributes_elements(db)
305 .filter(move |a| a.attr(db).as_syntax_node().get_text_without_trivia(db) == attr)
306 }
307
308 fn find_attr(&self, db: &dyn SyntaxGroup, attr: &str) -> Option<Attribute> {
310 self.query_attr(db, attr).next()
311 }
312
313 fn has_attr(&self, db: &dyn SyntaxGroup, attr: &str) -> bool {
315 self.find_attr(db, attr).is_some()
316 }
317
318 fn has_attr_with_arg(&self, db: &dyn SyntaxGroup, attr_name: &str, arg_name: &str) -> bool {
320 self.query_attr(db, attr_name).any(|attr| is_single_arg_attr(db, &attr, arg_name))
321 }
322}
323
324impl QueryAttrs for ItemConstant {
325 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
326 Some(self.attributes(db))
327 }
328}
329impl QueryAttrs for ItemModule {
330 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
331 Some(self.attributes(db))
332 }
333}
334impl QueryAttrs for FunctionWithBody {
335 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
336 Some(self.attributes(db))
337 }
338}
339impl QueryAttrs for ItemUse {
340 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
341 Some(self.attributes(db))
342 }
343}
344impl QueryAttrs for ItemExternFunction {
345 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
346 Some(self.attributes(db))
347 }
348}
349impl QueryAttrs for ItemExternType {
350 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
351 Some(self.attributes(db))
352 }
353}
354impl QueryAttrs for ItemTrait {
355 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
356 Some(self.attributes(db))
357 }
358}
359impl QueryAttrs for ItemImpl {
360 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
361 Some(self.attributes(db))
362 }
363}
364impl QueryAttrs for ItemImplAlias {
365 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
366 Some(self.attributes(db))
367 }
368}
369impl QueryAttrs for ItemStruct {
370 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
371 Some(self.attributes(db))
372 }
373}
374impl QueryAttrs for ItemEnum {
375 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
376 Some(self.attributes(db))
377 }
378}
379impl QueryAttrs for ItemTypeAlias {
380 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
381 Some(self.attributes(db))
382 }
383}
384impl QueryAttrs for ItemMacroDeclaration {
385 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
386 Some(self.attributes(db))
387 }
388}
389impl QueryAttrs for TraitItemFunction {
390 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
391 Some(self.attributes(db))
392 }
393}
394impl QueryAttrs for TraitItemType {
395 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
396 Some(self.attributes(db))
397 }
398}
399impl QueryAttrs for TraitItemConstant {
400 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
401 Some(self.attributes(db))
402 }
403}
404impl QueryAttrs for TraitItemImpl {
405 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
406 Some(self.attributes(db))
407 }
408}
409impl QueryAttrs for TraitItem {
410 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
411 match self {
412 TraitItem::Function(item) => Some(item.attributes(db)),
413 TraitItem::Type(item) => Some(item.attributes(db)),
414 TraitItem::Constant(item) => Some(item.attributes(db)),
415 TraitItem::Impl(item) => Some(item.attributes(db)),
416 TraitItem::Missing(_) => None,
417 }
418 }
419}
420
421impl QueryAttrs for ItemInlineMacro {
422 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
423 Some(self.attributes(db))
424 }
425}
426
427impl QueryAttrs for ModuleItem {
428 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
429 match self {
430 ModuleItem::Constant(item) => Some(item.attributes(db)),
431 ModuleItem::Module(item) => Some(item.attributes(db)),
432 ModuleItem::FreeFunction(item) => Some(item.attributes(db)),
433 ModuleItem::Use(item) => Some(item.attributes(db)),
434 ModuleItem::ExternFunction(item) => Some(item.attributes(db)),
435 ModuleItem::ExternType(item) => Some(item.attributes(db)),
436 ModuleItem::Trait(item) => Some(item.attributes(db)),
437 ModuleItem::Impl(item) => Some(item.attributes(db)),
438 ModuleItem::ImplAlias(item) => Some(item.attributes(db)),
439 ModuleItem::Struct(item) => Some(item.attributes(db)),
440 ModuleItem::Enum(item) => Some(item.attributes(db)),
441 ModuleItem::TypeAlias(item) => Some(item.attributes(db)),
442 ModuleItem::InlineMacro(item) => Some(item.attributes(db)),
443 ModuleItem::MacroDeclaration(macro_declaration) => {
444 Some(macro_declaration.attributes(db))
445 }
446 ModuleItem::Missing(_) => None,
447 ModuleItem::HeaderDoc(_) => None,
448 }
449 }
450}
451
452impl QueryAttrs for ImplItem {
453 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
454 match self {
455 ImplItem::Function(item) => Some(item.attributes(db)),
456 ImplItem::Type(item) => Some(item.attributes(db)),
457 ImplItem::Constant(item) => Some(item.attributes(db)),
458 ImplItem::Impl(item) => Some(item.attributes(db)),
459 ImplItem::Module(item) => Some(item.attributes(db)),
460 ImplItem::Use(item) => Some(item.attributes(db)),
461 ImplItem::ExternFunction(item) => Some(item.attributes(db)),
462 ImplItem::ExternType(item) => Some(item.attributes(db)),
463 ImplItem::Trait(item) => Some(item.attributes(db)),
464 ImplItem::Struct(item) => Some(item.attributes(db)),
465 ImplItem::Enum(item) => Some(item.attributes(db)),
466 ImplItem::Missing(_) => None,
467 }
468 }
469}
470
471impl QueryAttrs for AttributeList {
472 fn try_attributes(&self, _db: &dyn SyntaxGroup) -> Option<AttributeList> {
473 Some(self.clone())
474 }
475}
476impl QueryAttrs for Member {
477 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
478 Some(self.attributes(db))
479 }
480}
481
482impl QueryAttrs for Variant {
483 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
484 Some(self.attributes(db))
485 }
486}
487
488impl QueryAttrs for StatementBreak {
489 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
490 Some(self.attributes(db))
491 }
492}
493
494impl QueryAttrs for StatementContinue {
495 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
496 Some(self.attributes(db))
497 }
498}
499
500impl QueryAttrs for StatementReturn {
501 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
502 Some(self.attributes(db))
503 }
504}
505
506impl QueryAttrs for StatementLet {
507 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
508 Some(self.attributes(db))
509 }
510}
511
512impl QueryAttrs for StatementExpr {
513 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
514 Some(self.attributes(db))
515 }
516}
517
518impl QueryAttrs for SyntaxNode {
521 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
522 match self.kind(db) {
523 SyntaxKind::ItemConstant => {
524 Some(ast::ItemConstant::from_syntax_node(db, *self).attributes(db))
525 }
526 SyntaxKind::ItemModule => {
527 Some(ast::ItemModule::from_syntax_node(db, *self).attributes(db))
528 }
529 SyntaxKind::FunctionWithBody => {
530 Some(ast::FunctionWithBody::from_syntax_node(db, *self).attributes(db))
531 }
532 SyntaxKind::ItemUse => Some(ast::ItemUse::from_syntax_node(db, *self).attributes(db)),
533 SyntaxKind::ItemExternFunction => {
534 Some(ast::ItemExternFunction::from_syntax_node(db, *self).attributes(db))
535 }
536 SyntaxKind::ItemExternType => {
537 Some(ast::ItemExternType::from_syntax_node(db, *self).attributes(db))
538 }
539 SyntaxKind::ItemTrait => {
540 Some(ast::ItemTrait::from_syntax_node(db, *self).attributes(db))
541 }
542 SyntaxKind::ItemImpl => Some(ast::ItemImpl::from_syntax_node(db, *self).attributes(db)),
543 SyntaxKind::ItemImplAlias => {
544 Some(ast::ItemImplAlias::from_syntax_node(db, *self).attributes(db))
545 }
546 SyntaxKind::ItemStruct => {
547 Some(ast::ItemStruct::from_syntax_node(db, *self).attributes(db))
548 }
549 SyntaxKind::ItemEnum => Some(ast::ItemEnum::from_syntax_node(db, *self).attributes(db)),
550 SyntaxKind::ItemTypeAlias => {
551 Some(ast::ItemTypeAlias::from_syntax_node(db, *self).attributes(db))
552 }
553 SyntaxKind::TraitItemFunction => {
554 Some(ast::TraitItemFunction::from_syntax_node(db, *self).attributes(db))
555 }
556 SyntaxKind::ItemInlineMacro => {
557 Some(ast::ItemInlineMacro::from_syntax_node(db, *self).attributes(db))
558 }
559 SyntaxKind::AttributeList => Some(ast::AttributeList::from_syntax_node(db, *self)),
560 SyntaxKind::Member => Some(ast::Member::from_syntax_node(db, *self).attributes(db)),
561 SyntaxKind::Variant => Some(ast::Variant::from_syntax_node(db, *self).attributes(db)),
562 SyntaxKind::StatementBreak => {
563 Some(ast::StatementBreak::from_syntax_node(db, *self).attributes(db))
564 }
565 SyntaxKind::StatementContinue => {
566 Some(ast::StatementContinue::from_syntax_node(db, *self).attributes(db))
567 }
568 SyntaxKind::StatementReturn => {
569 Some(ast::StatementReturn::from_syntax_node(db, *self).attributes(db))
570 }
571 SyntaxKind::StatementLet => {
572 Some(ast::StatementLet::from_syntax_node(db, *self).attributes(db))
573 }
574 SyntaxKind::StatementExpr => {
575 Some(ast::StatementExpr::from_syntax_node(db, *self).attributes(db))
576 }
577 _ => None,
578 }
579 }
580}
581
582impl QueryAttrs for Statement {
583 fn try_attributes(&self, db: &dyn SyntaxGroup) -> Option<AttributeList> {
584 match self {
585 Statement::Break(statement) => Some(statement.attributes(db)),
586 Statement::Continue(statement) => Some(statement.attributes(db)),
587 Statement::Return(statement) => Some(statement.attributes(db)),
588 Statement::Let(statement) => Some(statement.attributes(db)),
589 Statement::Expr(statement) => Some(statement.attributes(db)),
590 Statement::Item(statement) => statement.item(db).try_attributes(db),
591 Statement::Missing(_) => None,
592 }
593 }
594}
595pub trait WrappedArgListHelper {
596 fn arg_list(&self, db: &dyn SyntaxGroup) -> Option<ast::ArgList>;
598 fn right_bracket_syntax_node(&self, db: &dyn SyntaxGroup) -> SyntaxNode;
600 fn left_bracket_syntax_node(&self, db: &dyn SyntaxGroup) -> SyntaxNode;
602 fn left_bracket_stable_ptr(&self, db: &dyn SyntaxGroup) -> SyntaxStablePtrId;
604}
605impl WrappedArgListHelper for WrappedArgList {
606 fn arg_list(&self, db: &dyn SyntaxGroup) -> Option<ast::ArgList> {
607 match self {
608 WrappedArgList::ParenthesizedArgList(args) => Some(args.arguments(db)),
609 WrappedArgList::BracketedArgList(args) => Some(args.arguments(db)),
610 WrappedArgList::BracedArgList(args) => Some(args.arguments(db)),
611 WrappedArgList::Missing(_) => None,
612 }
613 }
614
615 fn right_bracket_syntax_node(&self, db: &dyn SyntaxGroup) -> SyntaxNode {
616 match self {
617 WrappedArgList::ParenthesizedArgList(args) => args.rparen(db).as_syntax_node(),
618 WrappedArgList::BracketedArgList(args) => args.rbrack(db).as_syntax_node(),
619 WrappedArgList::BracedArgList(args) => args.rbrace(db).as_syntax_node(),
620 WrappedArgList::Missing(_) => self.as_syntax_node(),
621 }
622 }
623
624 fn left_bracket_syntax_node(&self, db: &dyn SyntaxGroup) -> SyntaxNode {
625 match self {
626 WrappedArgList::ParenthesizedArgList(args) => args.lparen(db).as_syntax_node(),
627 WrappedArgList::BracketedArgList(args) => args.lbrack(db).as_syntax_node(),
628 WrappedArgList::BracedArgList(args) => args.lbrace(db).as_syntax_node(),
629 WrappedArgList::Missing(_) => self.as_syntax_node(),
630 }
631 }
632
633 fn left_bracket_stable_ptr(&self, db: &dyn SyntaxGroup) -> SyntaxStablePtrId {
634 match self {
635 WrappedArgList::ParenthesizedArgList(args) => args.lparen(db).stable_ptr(db).untyped(),
636 WrappedArgList::BracketedArgList(args) => args.lbrack(db).stable_ptr(db).untyped(),
637 WrappedArgList::BracedArgList(args) => args.lbrace(db).stable_ptr(db).untyped(),
638 WrappedArgList::Missing(_) => self.stable_ptr(db).untyped(),
639 }
640 }
641}
642
643pub trait WrappedGenericParamListHelper {
644 fn is_empty(&self, db: &dyn SyntaxGroup) -> bool;
646}
647impl WrappedGenericParamListHelper for ast::WrappedGenericParamList {
648 fn is_empty(&self, db: &dyn SyntaxGroup) -> bool {
649 self.generic_params(db).elements(db).len() == 0
650 }
651}
652
653pub trait OptionWrappedGenericParamListHelper {
654 fn is_empty(&self, db: &dyn SyntaxGroup) -> bool;
657}
658impl OptionWrappedGenericParamListHelper for ast::OptionWrappedGenericParamList {
659 fn is_empty(&self, db: &dyn SyntaxGroup) -> bool {
660 match self {
661 ast::OptionWrappedGenericParamList::Empty(_) => true,
662 ast::OptionWrappedGenericParamList::WrappedGenericParamList(
663 wrapped_generic_param_list,
664 ) => wrapped_generic_param_list.is_empty(db),
665 }
666 }
667}
668
669pub trait BodyItems {
671 type Item;
673 fn iter_items<'a>(&self, db: &'a dyn SyntaxGroup) -> impl Iterator<Item = Self::Item> + 'a;
681}
682
683impl BodyItems for ast::ModuleBody {
684 type Item = ModuleItem;
685 fn iter_items<'a>(&self, db: &'a dyn SyntaxGroup) -> impl Iterator<Item = Self::Item> + 'a {
686 self.items(db).elements(db)
687 }
688}
689
690impl BodyItems for ast::TraitBody {
691 type Item = TraitItem;
692 fn iter_items<'a>(&self, db: &'a dyn SyntaxGroup) -> impl Iterator<Item = Self::Item> + 'a {
693 self.items(db).elements(db)
694 }
695}
696
697impl BodyItems for ast::ImplBody {
698 type Item = ImplItem;
699 fn iter_items<'a>(&self, db: &'a dyn SyntaxGroup) -> impl Iterator<Item = Self::Item> + 'a {
700 self.items(db).elements(db)
701 }
702}
703
704pub trait UsePathEx {
706 fn get_item(&self, db: &dyn SyntaxGroup) -> ast::ItemUse;
708}
709impl UsePathEx for ast::UsePath {
710 fn get_item(&self, db: &dyn SyntaxGroup) -> ast::ItemUse {
711 let mut node = self.as_syntax_node();
712 loop {
713 let Some(parent) = node.parent(db) else {
714 unreachable!("UsePath is not under an ItemUse.");
715 };
716 match parent.kind(db) {
717 SyntaxKind::ItemUse => {
718 break ast::ItemUse::from_syntax_node(db, parent);
719 }
720 _ => node = parent,
721 }
722 }
723 }
724}
725
726impl UsePathLeaf {
727 pub fn name_stable_ptr(&self, db: &dyn SyntaxGroup) -> SyntaxStablePtrId {
729 self.name(db).stable_ptr(db).untyped()
730 }
731}
732
733pub trait IsDependentType {
735 fn is_dependent_type(&self, db: &dyn SyntaxGroup, identifiers: &[&str]) -> bool;
740}
741
742impl IsDependentType for ast::ExprPath {
743 fn is_dependent_type(&self, db: &dyn SyntaxGroup, identifiers: &[&str]) -> bool {
744 let segments = self.segments(db).elements_vec(db);
745 if let [ast::PathSegment::Simple(arg_segment)] = &segments[..] {
746 identifiers.contains(&arg_segment.identifier(db).as_str())
747 } else {
748 segments.into_iter().any(|segment| {
749 let ast::PathSegment::WithGenericArgs(with_generics) = segment else {
750 return false;
751 };
752 with_generics.generic_args(db).generic_args(db).elements(db).any(|arg| {
753 let generic_arg_value = match arg {
754 ast::GenericArg::Named(named) => named.value(db),
755 ast::GenericArg::Unnamed(unnamed) => unnamed.value(db),
756 };
757 match generic_arg_value {
758 ast::GenericArgValue::Expr(arg_expr) => {
759 arg_expr.expr(db).is_dependent_type(db, identifiers)
760 }
761 ast::GenericArgValue::Underscore(_) => false,
762 }
763 })
764 })
765 }
766 }
767}
768
769impl IsDependentType for ast::Expr {
770 fn is_dependent_type(&self, db: &dyn SyntaxGroup, identifiers: &[&str]) -> bool {
771 match self {
772 ast::Expr::Path(type_path) => type_path.is_dependent_type(db, identifiers),
773 ast::Expr::Unary(unary) => unary.expr(db).is_dependent_type(db, identifiers),
774 ast::Expr::Binary(binary) => {
775 binary.lhs(db).is_dependent_type(db, identifiers)
776 || binary.rhs(db).is_dependent_type(db, identifiers)
777 }
778 ast::Expr::Tuple(tuple) => tuple
779 .expressions(db)
780 .elements(db)
781 .any(|expr| expr.is_dependent_type(db, identifiers)),
782 ast::Expr::FixedSizeArray(arr) => {
783 arr.exprs(db).elements(db).any(|expr| expr.is_dependent_type(db, identifiers))
784 || match arr.size(db) {
785 ast::OptionFixedSizeArraySize::Empty(_) => false,
786 ast::OptionFixedSizeArraySize::FixedSizeArraySize(size) => {
787 size.size(db).is_dependent_type(db, identifiers)
788 }
789 }
790 }
791 ast::Expr::Literal(_)
792 | ast::Expr::ShortString(_)
793 | ast::Expr::String(_)
794 | ast::Expr::False(_)
795 | ast::Expr::True(_)
796 | ast::Expr::Parenthesized(_)
797 | ast::Expr::FunctionCall(_)
798 | ast::Expr::StructCtorCall(_)
799 | ast::Expr::Block(_)
800 | ast::Expr::Match(_)
801 | ast::Expr::If(_)
802 | ast::Expr::Loop(_)
803 | ast::Expr::While(_)
804 | ast::Expr::For(_)
805 | ast::Expr::Closure(_)
806 | ast::Expr::ErrorPropagate(_)
807 | ast::Expr::FieldInitShorthand(_)
808 | ast::Expr::Indexed(_)
809 | ast::Expr::InlineMacro(_)
810 | ast::Expr::Placeholder(_)
811 | ast::Expr::Missing(_) => false,
812 }
813 }
814}