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 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 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 fn identifier(&self, db: &dyn SyntaxGroup) -> SmolStr {
100 self.elements(db).last().cloned().unwrap().identifier(db)
101 }
102}
103
104pub 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 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 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
142pub trait NameGreen {
144 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
174pub trait HasName {
176 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 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
223pub 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
234pub trait QueryAttrs {
236 #[doc(hidden)]
240 fn attributes_elements(&self, db: &dyn SyntaxGroup) -> Vec<Attribute>;
241
242 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 fn find_attr(&self, db: &dyn SyntaxGroup, attr: &str) -> Option<Attribute> {
252 self.query_attr(db, attr).into_iter().next()
253 }
254
255 fn has_attr(&self, db: &dyn SyntaxGroup, attr: &str) -> bool {
257 self.find_attr(db, attr).is_some()
258 }
259
260 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
452impl 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 fn arg_list(&self, db: &dyn SyntaxGroup) -> Option<ast::ArgList>;
542 fn right_bracket_syntax_node(&self, db: &dyn SyntaxGroup) -> SyntaxNode;
544 fn left_bracket_syntax_node(&self, db: &dyn SyntaxGroup) -> SyntaxNode;
546 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 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 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
613pub trait BodyItems {
615 type Item;
617 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
648pub trait UsePathEx {
650 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 pub fn name_stable_ptr(&self, db: &dyn SyntaxGroup) -> SyntaxStablePtrId {
673 self.name(db).stable_ptr(db).untyped()
674 }
675}
676
677pub trait IsDependentType {
679 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}