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