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 ast::PathSegment::Missing(missing_segment) => missing_segment.ident(db),
130 }
131 }
132 fn generic_args(&self, db: &'a dyn Database) -> Option<Vec<ast::GenericArg<'a>>> {
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<'a> GetIdentifier<'a> for ast::PathSegment<'a> {
142 fn identifier(&self, db: &'a dyn Database) -> SmolStrId<'a> {
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<'a> GetIdentifier<'a> for ast::PathSegmentSimple<'a> {
152 fn identifier(&self, db: &'a dyn Database) -> SmolStrId<'a> {
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<'a> GetIdentifier<'a> for ast::PathSegmentWithGenericArgs<'a> {
161 fn identifier(&self, db: &'a dyn Database) -> SmolStrId<'a> {
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<'a> GetIdentifier<'a> for ast::PathSegmentMissing<'a> {
171 fn identifier(&self, db: &'a dyn Database) -> SmolStrId<'a> {
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<'a> GetIdentifier<'a> for ast::Modifier<'a> {
181 fn identifier(&self, db: &'a dyn Database) -> SmolStrId<'a> {
182 match self {
183 Modifier::Ref(r) => r.text(db),
184 Modifier::Mut(m) => m.text(db),
185 }
186 }
187}
188
189pub trait NameGreen<'a> {
191 fn name_green(self, db: &'a dyn Database) -> TerminalIdentifierGreen<'a>;
193}
194
195impl<'a> NameGreen<'a> for FunctionDeclarationGreen<'a> {
196 fn name_green(self, db: &'a dyn Database) -> TerminalIdentifierGreen<'a> {
197 TerminalIdentifierGreen(self.0.long(db).children()[FunctionDeclaration::INDEX_NAME])
198 }
199}
200
201impl<'a> NameGreen<'a> for FunctionWithBodyPtr<'a> {
202 fn name_green(self, db: &'a dyn Database) -> TerminalIdentifierGreen<'a> {
203 self.declaration_green(db).name_green(db)
204 }
205}
206
207impl<'a> NameGreen<'a> for ItemExternFunctionPtr<'a> {
208 fn name_green(self, db: &'a dyn Database) -> TerminalIdentifierGreen<'a> {
209 self.declaration_green(db).name_green(db)
210 }
211}
212
213impl<'a> NameGreen<'a> for TraitItemFunctionPtr<'a> {
214 fn name_green(self, db: &'a dyn Database) -> TerminalIdentifierGreen<'a> {
215 self.declaration_green(db).name_green(db)
216 }
217}
218
219pub trait HasName<'a> {
221 fn name(&self, db: &'a dyn Database) -> ast::TerminalIdentifier<'a>;
223}
224
225impl<'a> HasName<'a> for FunctionWithBody<'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 ItemExternFunction<'a> {
232 fn name(&self, db: &'a dyn Database) -> TerminalIdentifier<'a> {
233 self.declaration(db).name(db)
234 }
235}
236
237impl<'a> HasName<'a> for TraitItemFunction<'a> {
238 fn name(&self, db: &'a dyn Database) -> TerminalIdentifier<'a> {
239 self.declaration(db).name(db)
240 }
241}
242
243impl<'a> HasName<'a> for UsePathLeaf<'a> {
244 fn name(&self, db: &'a dyn Database) -> TerminalIdentifier<'a> {
245 match self.alias_clause(db) {
246 ast::OptionAliasClause::Empty(_) => self.ident(db).identifier_ast(db),
247 ast::OptionAliasClause::AliasClause(alias) => alias.alias(db),
248 }
249 }
250}
251
252pub trait GenericParamEx<'a> {
253 fn name(&self, db: &'a dyn Database) -> Option<ast::TerminalIdentifier<'a>>;
255}
256impl<'a> GenericParamEx<'a> for ast::GenericParam<'a> {
257 fn name(&self, db: &'a dyn Database) -> Option<ast::TerminalIdentifier<'a>> {
258 match self {
259 ast::GenericParam::Type(t) => Some(t.name(db)),
260 ast::GenericParam::Const(c) => Some(c.name(db)),
261 ast::GenericParam::ImplNamed(i) => Some(i.name(db)),
262 ast::GenericParam::ImplAnonymous(_) => None,
263 ast::GenericParam::NegativeImpl(_) => None,
264 }
265 }
266}
267
268pub fn is_single_arg_attr(db: &dyn Database, attr: &Attribute<'_>, arg_name: &str) -> bool {
270 match attr.arguments(db) {
271 OptionArgListParenthesized::ArgListParenthesized(args) => {
272 matches!(args.arguments(db).elements(db).exactly_one(),
273 Ok(arg) if arg.as_syntax_node().get_text_without_trivia(db).long(db) == arg_name)
274 }
275 OptionArgListParenthesized::Empty(_) => false,
276 }
277}
278
279pub trait QueryAttrs<'a> {
281 #[doc(hidden)]
286 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>>;
287
288 fn attributes_elements(&self, db: &'a dyn Database) -> impl Iterator<Item = Attribute<'a>> {
290 self.try_attributes(db).into_iter().flat_map(move |attrs| attrs.elements(db))
291 }
292
293 fn query_attr(
295 &self,
296 db: &'a dyn Database,
297 attr: &'a str,
298 ) -> impl Iterator<Item = Attribute<'a>> {
299 self.attributes_elements(db).filter(move |a| {
300 a.attr(db).as_syntax_node().get_text_without_trivia(db).long(db) == attr
301 })
302 }
303
304 fn find_attr(&self, db: &'a dyn Database, attr: &'a str) -> Option<Attribute<'a>> {
306 self.query_attr(db, attr).next()
307 }
308
309 fn has_attr(&self, db: &'a dyn Database, attr: &'a str) -> bool {
311 self.find_attr(db, attr).is_some()
312 }
313
314 fn has_attr_with_arg(&self, db: &'a dyn Database, attr_name: &'a str, arg_name: &str) -> bool {
316 self.query_attr(db, attr_name).any(|attr| is_single_arg_attr(db, &attr, arg_name))
317 }
318}
319
320impl<'a> QueryAttrs<'a> for ItemConstant<'a> {
321 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
322 Some(self.attributes(db))
323 }
324}
325impl<'a> QueryAttrs<'a> for ItemModule<'a> {
326 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
327 Some(self.attributes(db))
328 }
329}
330impl<'a> QueryAttrs<'a> for FunctionWithBody<'a> {
331 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
332 Some(self.attributes(db))
333 }
334}
335impl<'a> QueryAttrs<'a> for ItemUse<'a> {
336 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
337 Some(self.attributes(db))
338 }
339}
340impl<'a> QueryAttrs<'a> for ItemExternFunction<'a> {
341 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
342 Some(self.attributes(db))
343 }
344}
345impl<'a> QueryAttrs<'a> for ItemExternType<'a> {
346 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
347 Some(self.attributes(db))
348 }
349}
350impl<'a> QueryAttrs<'a> for ItemTrait<'a> {
351 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
352 Some(self.attributes(db))
353 }
354}
355impl<'a> QueryAttrs<'a> for ItemImpl<'a> {
356 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
357 Some(self.attributes(db))
358 }
359}
360impl<'a> QueryAttrs<'a> for ItemImplAlias<'a> {
361 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
362 Some(self.attributes(db))
363 }
364}
365impl<'a> QueryAttrs<'a> for ItemStruct<'a> {
366 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
367 Some(self.attributes(db))
368 }
369}
370impl<'a> QueryAttrs<'a> for ItemEnum<'a> {
371 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
372 Some(self.attributes(db))
373 }
374}
375impl<'a> QueryAttrs<'a> for ItemTypeAlias<'a> {
376 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
377 Some(self.attributes(db))
378 }
379}
380impl<'a> QueryAttrs<'a> for ItemMacroDeclaration<'a> {
381 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
382 Some(self.attributes(db))
383 }
384}
385impl<'a> QueryAttrs<'a> for TraitItemFunction<'a> {
386 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
387 Some(self.attributes(db))
388 }
389}
390impl<'a> QueryAttrs<'a> for TraitItemType<'a> {
391 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
392 Some(self.attributes(db))
393 }
394}
395impl<'a> QueryAttrs<'a> for TraitItemConstant<'a> {
396 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
397 Some(self.attributes(db))
398 }
399}
400impl<'a> QueryAttrs<'a> for TraitItemImpl<'a> {
401 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
402 Some(self.attributes(db))
403 }
404}
405impl<'a> QueryAttrs<'a> for TraitItem<'a> {
406 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
407 match self {
408 TraitItem::Function(item) => Some(item.attributes(db)),
409 TraitItem::Type(item) => Some(item.attributes(db)),
410 TraitItem::Constant(item) => Some(item.attributes(db)),
411 TraitItem::Impl(item) => Some(item.attributes(db)),
412 TraitItem::Missing(_) => None,
413 }
414 }
415}
416
417impl<'a> QueryAttrs<'a> for ItemInlineMacro<'a> {
418 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
419 Some(self.attributes(db))
420 }
421}
422
423impl<'a> QueryAttrs<'a> for ModuleItem<'a> {
424 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
425 match self {
426 ModuleItem::Constant(item) => Some(item.attributes(db)),
427 ModuleItem::Module(item) => Some(item.attributes(db)),
428 ModuleItem::FreeFunction(item) => Some(item.attributes(db)),
429 ModuleItem::Use(item) => Some(item.attributes(db)),
430 ModuleItem::ExternFunction(item) => Some(item.attributes(db)),
431 ModuleItem::ExternType(item) => Some(item.attributes(db)),
432 ModuleItem::Trait(item) => Some(item.attributes(db)),
433 ModuleItem::Impl(item) => Some(item.attributes(db)),
434 ModuleItem::ImplAlias(item) => Some(item.attributes(db)),
435 ModuleItem::Struct(item) => Some(item.attributes(db)),
436 ModuleItem::Enum(item) => Some(item.attributes(db)),
437 ModuleItem::TypeAlias(item) => Some(item.attributes(db)),
438 ModuleItem::InlineMacro(item) => Some(item.attributes(db)),
439 ModuleItem::MacroDeclaration(macro_declaration) => {
440 Some(macro_declaration.attributes(db))
441 }
442 ModuleItem::Missing(_) => None,
443 ModuleItem::HeaderDoc(_) => None,
444 }
445 }
446}
447
448impl<'a> QueryAttrs<'a> for ImplItem<'a> {
449 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
450 match self {
451 ImplItem::Function(item) => Some(item.attributes(db)),
452 ImplItem::Type(item) => Some(item.attributes(db)),
453 ImplItem::Constant(item) => Some(item.attributes(db)),
454 ImplItem::Impl(item) => Some(item.attributes(db)),
455 ImplItem::Module(item) => Some(item.attributes(db)),
456 ImplItem::Use(item) => Some(item.attributes(db)),
457 ImplItem::ExternFunction(item) => Some(item.attributes(db)),
458 ImplItem::ExternType(item) => Some(item.attributes(db)),
459 ImplItem::Trait(item) => Some(item.attributes(db)),
460 ImplItem::Struct(item) => Some(item.attributes(db)),
461 ImplItem::Enum(item) => Some(item.attributes(db)),
462 ImplItem::Missing(_) => None,
463 }
464 }
465}
466
467impl<'a> QueryAttrs<'a> for AttributeList<'a> {
468 fn try_attributes(&self, _db: &'a dyn Database) -> Option<AttributeList<'a>> {
469 Some(self.clone())
470 }
471}
472impl<'a> QueryAttrs<'a> for Member<'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 Variant<'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 StatementBreak<'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 StatementContinue<'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 StatementReturn<'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 StatementLet<'a> {
503 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
504 Some(self.attributes(db))
505 }
506}
507
508impl<'a> QueryAttrs<'a> for StatementExpr<'a> {
509 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
510 Some(self.attributes(db))
511 }
512}
513
514impl<'a> QueryAttrs<'a> for SyntaxNode<'a> {
517 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
518 match self.kind(db) {
519 SyntaxKind::ItemConstant => {
520 Some(ast::ItemConstant::from_syntax_node(db, *self).attributes(db))
521 }
522 SyntaxKind::ItemModule => {
523 Some(ast::ItemModule::from_syntax_node(db, *self).attributes(db))
524 }
525 SyntaxKind::FunctionWithBody => {
526 Some(ast::FunctionWithBody::from_syntax_node(db, *self).attributes(db))
527 }
528 SyntaxKind::ItemUse => Some(ast::ItemUse::from_syntax_node(db, *self).attributes(db)),
529 SyntaxKind::ItemExternFunction => {
530 Some(ast::ItemExternFunction::from_syntax_node(db, *self).attributes(db))
531 }
532 SyntaxKind::ItemExternType => {
533 Some(ast::ItemExternType::from_syntax_node(db, *self).attributes(db))
534 }
535 SyntaxKind::ItemTrait => {
536 Some(ast::ItemTrait::from_syntax_node(db, *self).attributes(db))
537 }
538 SyntaxKind::ItemImpl => Some(ast::ItemImpl::from_syntax_node(db, *self).attributes(db)),
539 SyntaxKind::ItemImplAlias => {
540 Some(ast::ItemImplAlias::from_syntax_node(db, *self).attributes(db))
541 }
542 SyntaxKind::ItemStruct => {
543 Some(ast::ItemStruct::from_syntax_node(db, *self).attributes(db))
544 }
545 SyntaxKind::ItemEnum => Some(ast::ItemEnum::from_syntax_node(db, *self).attributes(db)),
546 SyntaxKind::ItemTypeAlias => {
547 Some(ast::ItemTypeAlias::from_syntax_node(db, *self).attributes(db))
548 }
549 SyntaxKind::TraitItemFunction => {
550 Some(ast::TraitItemFunction::from_syntax_node(db, *self).attributes(db))
551 }
552 SyntaxKind::ItemInlineMacro => {
553 Some(ast::ItemInlineMacro::from_syntax_node(db, *self).attributes(db))
554 }
555 SyntaxKind::AttributeList => Some(ast::AttributeList::from_syntax_node(db, *self)),
556 SyntaxKind::Member => Some(ast::Member::from_syntax_node(db, *self).attributes(db)),
557 SyntaxKind::Variant => Some(ast::Variant::from_syntax_node(db, *self).attributes(db)),
558 SyntaxKind::StatementBreak => {
559 Some(ast::StatementBreak::from_syntax_node(db, *self).attributes(db))
560 }
561 SyntaxKind::StatementContinue => {
562 Some(ast::StatementContinue::from_syntax_node(db, *self).attributes(db))
563 }
564 SyntaxKind::StatementReturn => {
565 Some(ast::StatementReturn::from_syntax_node(db, *self).attributes(db))
566 }
567 SyntaxKind::StatementLet => {
568 Some(ast::StatementLet::from_syntax_node(db, *self).attributes(db))
569 }
570 SyntaxKind::StatementExpr => {
571 Some(ast::StatementExpr::from_syntax_node(db, *self).attributes(db))
572 }
573 _ => None,
574 }
575 }
576}
577
578impl<'a> QueryAttrs<'a> for Statement<'a> {
579 fn try_attributes(&self, db: &'a dyn Database) -> Option<AttributeList<'a>> {
580 match self {
581 Statement::Break(statement) => Some(statement.attributes(db)),
582 Statement::Continue(statement) => Some(statement.attributes(db)),
583 Statement::Return(statement) => Some(statement.attributes(db)),
584 Statement::Let(statement) => Some(statement.attributes(db)),
585 Statement::Expr(statement) => Some(statement.attributes(db)),
586 Statement::Item(statement) => statement.item(db).try_attributes(db),
587 Statement::Missing(_) => None,
588 }
589 }
590}
591pub trait WrappedArgListHelper<'a> {
592 fn arg_list(&self, db: &'a dyn Database) -> Option<ast::ArgList<'a>>;
594 fn right_bracket_syntax_node(&self, db: &'a dyn Database) -> SyntaxNode<'a>;
596 fn left_bracket_syntax_node(&self, db: &'a dyn Database) -> SyntaxNode<'a>;
598 fn left_bracket_stable_ptr(&self, db: &'a dyn Database) -> SyntaxStablePtrId<'a>;
600}
601impl<'a> WrappedArgListHelper<'a> for WrappedArgList<'a> {
602 fn arg_list(&self, db: &'a dyn Database) -> Option<ast::ArgList<'a>> {
603 match self {
604 WrappedArgList::ParenthesizedArgList(args) => Some(args.arguments(db)),
605 WrappedArgList::BracketedArgList(args) => Some(args.arguments(db)),
606 WrappedArgList::BracedArgList(args) => Some(args.arguments(db)),
607 WrappedArgList::Missing(_) => None,
608 }
609 }
610
611 fn right_bracket_syntax_node(&self, db: &'a dyn Database) -> SyntaxNode<'a> {
612 match self {
613 WrappedArgList::ParenthesizedArgList(args) => args.rparen(db).as_syntax_node(),
614 WrappedArgList::BracketedArgList(args) => args.rbrack(db).as_syntax_node(),
615 WrappedArgList::BracedArgList(args) => args.rbrace(db).as_syntax_node(),
616 WrappedArgList::Missing(_) => self.as_syntax_node(),
617 }
618 }
619
620 fn left_bracket_syntax_node(&self, db: &'a dyn Database) -> SyntaxNode<'a> {
621 match self {
622 WrappedArgList::ParenthesizedArgList(args) => args.lparen(db).as_syntax_node(),
623 WrappedArgList::BracketedArgList(args) => args.lbrack(db).as_syntax_node(),
624 WrappedArgList::BracedArgList(args) => args.lbrace(db).as_syntax_node(),
625 WrappedArgList::Missing(_) => self.as_syntax_node(),
626 }
627 }
628
629 fn left_bracket_stable_ptr(&self, db: &'a dyn Database) -> SyntaxStablePtrId<'a> {
630 match self {
631 WrappedArgList::ParenthesizedArgList(args) => args.lparen(db).stable_ptr(db).untyped(),
632 WrappedArgList::BracketedArgList(args) => args.lbrack(db).stable_ptr(db).untyped(),
633 WrappedArgList::BracedArgList(args) => args.lbrace(db).stable_ptr(db).untyped(),
634 WrappedArgList::Missing(_) => self.stable_ptr(db).untyped(),
635 }
636 }
637}
638
639pub trait WrappedGenericParamListHelper<'a> {
640 fn is_empty(&'a self, db: &'a dyn Database) -> bool;
642}
643impl<'a> WrappedGenericParamListHelper<'a> for ast::WrappedGenericParamList<'a> {
644 fn is_empty(&'a self, db: &'a dyn Database) -> bool {
645 self.generic_params(db).elements(db).len() == 0
646 }
647}
648
649pub trait OptionWrappedGenericParamListHelper<'a> {
650 fn is_empty(&'a self, db: &'a dyn Database) -> bool;
653}
654impl<'a> OptionWrappedGenericParamListHelper<'a> for ast::OptionWrappedGenericParamList<'a> {
655 fn is_empty(&'a self, db: &'a dyn Database) -> bool {
656 match self {
657 ast::OptionWrappedGenericParamList::Empty(_) => true,
658 ast::OptionWrappedGenericParamList::WrappedGenericParamList(
659 wrapped_generic_param_list,
660 ) => wrapped_generic_param_list.is_empty(db),
661 }
662 }
663}
664
665pub trait BodyItems<'a> {
667 type Item: 'a;
669 fn iter_items(&self, db: &'a dyn Database) -> impl Iterator<Item = Self::Item> + 'a;
677}
678
679impl<'a> BodyItems<'a> for ast::ModuleBody<'a> {
680 type Item = ModuleItem<'a>;
681 fn iter_items(&self, db: &'a dyn Database) -> impl Iterator<Item = Self::Item> + 'a {
682 self.items(db).elements(db)
683 }
684}
685
686impl<'a> BodyItems<'a> for ast::TraitBody<'a> {
687 type Item = TraitItem<'a>;
688 fn iter_items(&self, db: &'a dyn Database) -> impl Iterator<Item = Self::Item> + 'a {
689 self.items(db).elements(db)
690 }
691}
692
693impl<'a> BodyItems<'a> for ast::ImplBody<'a> {
694 type Item = ImplItem<'a>;
695 fn iter_items(&self, db: &'a dyn Database) -> impl Iterator<Item = Self::Item> + 'a {
696 self.items(db).elements(db)
697 }
698}
699
700pub trait UsePathEx<'a> {
702 fn get_item(&self, db: &'a dyn Database) -> ast::ItemUse<'a>;
704}
705impl<'a> UsePathEx<'a> for ast::UsePath<'a> {
706 fn get_item(&self, db: &'a dyn Database) -> ast::ItemUse<'a> {
707 let mut node = self.as_syntax_node();
708 loop {
709 let Some(parent) = node.parent(db) else {
710 unreachable!("UsePath is not under an ItemUse.");
711 };
712 match parent.kind(db) {
713 SyntaxKind::ItemUse => {
714 break ast::ItemUse::from_syntax_node(db, parent);
715 }
716 _ => node = parent,
717 }
718 }
719 }
720}
721
722impl<'a> UsePathLeaf<'a> {
723 pub fn name_stable_ptr(&self, db: &'a dyn Database) -> SyntaxStablePtrId<'a> {
725 self.name(db).stable_ptr(db).untyped()
726 }
727}
728
729pub trait IsDependentType<'db> {
731 fn is_dependent_type(&self, db: &'db dyn Database, identifiers: &[SmolStrId<'db>]) -> bool;
736}
737
738impl<'a> IsDependentType<'a> for ast::ExprPath<'a> {
739 fn is_dependent_type(&self, db: &'a dyn Database, identifiers: &[SmolStrId<'a>]) -> bool {
740 let mut segments = self.segments(db).elements(db);
741 match segments.next() {
742 None => false,
743 Some(ast::PathSegment::Simple(simple)) if segments.len() == 0 => {
744 identifiers.contains(&simple.identifier(db))
745 }
746 Some(first) => chain!([first], segments).any(|segment| {
747 let ast::PathSegment::WithGenericArgs(with_generics) = segment else {
748 return false;
749 };
750 with_generics.generic_args(db).generic_args(db).elements(db).any(|arg| {
751 match arg {
752 ast::GenericArg::Named(named) => named.value(db),
753 ast::GenericArg::Unnamed(unnamed) => unnamed.value(db),
754 }
755 .is_dependent_type(db, identifiers)
756 })
757 }),
758 }
759 }
760}
761
762impl<'a> IsDependentType<'a> for ast::Expr<'a> {
763 fn is_dependent_type(&self, db: &dyn Database, identifiers: &[SmolStrId<'a>]) -> bool {
764 match self {
765 ast::Expr::Path(type_path) => type_path.is_dependent_type(db, identifiers),
766 ast::Expr::Unary(unary) => unary.expr(db).is_dependent_type(db, identifiers),
767 ast::Expr::Binary(binary) => {
768 binary.lhs(db).is_dependent_type(db, identifiers)
769 || binary.rhs(db).is_dependent_type(db, identifiers)
770 }
771 ast::Expr::Tuple(tuple) => tuple
772 .expressions(db)
773 .elements(db)
774 .any(|expr| expr.is_dependent_type(db, identifiers)),
775 ast::Expr::FixedSizeArray(arr) => {
776 arr.exprs(db).elements(db).any(|expr| expr.is_dependent_type(db, identifiers))
777 || match arr.size(db) {
778 ast::OptionFixedSizeArraySize::Empty(_) => false,
779 ast::OptionFixedSizeArraySize::FixedSizeArraySize(size) => {
780 size.size(db).is_dependent_type(db, identifiers)
781 }
782 }
783 }
784 ast::Expr::Literal(_)
785 | ast::Expr::ShortString(_)
786 | ast::Expr::String(_)
787 | ast::Expr::False(_)
788 | ast::Expr::True(_)
789 | ast::Expr::Parenthesized(_)
790 | ast::Expr::FunctionCall(_)
791 | ast::Expr::StructCtorCall(_)
792 | ast::Expr::Block(_)
793 | ast::Expr::Match(_)
794 | ast::Expr::If(_)
795 | ast::Expr::Loop(_)
796 | ast::Expr::While(_)
797 | ast::Expr::For(_)
798 | ast::Expr::Closure(_)
799 | ast::Expr::ErrorPropagate(_)
800 | ast::Expr::FieldInitShorthand(_)
801 | ast::Expr::Indexed(_)
802 | ast::Expr::InlineMacro(_)
803 | ast::Expr::Missing(_)
804 | ast::Expr::Underscore(_) => false,
805 }
806 }
807}