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