]> git.lizzy.rs Git - rust.git/blob - crates/syntax/src/ast/node_ext.rs
Don't compare ast::Visibility by stringifying
[rust.git] / crates / syntax / src / ast / node_ext.rs
1 //! Various extension methods to ast Nodes, which are hard to code-generate.
2 //! Extensions for various expressions live in a sibling `expr_extensions` module.
3
4 use std::{borrow::Cow, fmt, iter::successors};
5
6 use itertools::Itertools;
7 use parser::SyntaxKind;
8 use rowan::{GreenNodeData, GreenTokenData};
9
10 use crate::{
11     ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode},
12     NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T,
13 };
14
15 impl ast::Lifetime {
16     pub fn text(&self) -> TokenText<'_> {
17         text_of_first_token(self.syntax())
18     }
19 }
20
21 impl ast::Name {
22     pub fn text(&self) -> TokenText<'_> {
23         text_of_first_token(self.syntax())
24     }
25 }
26
27 impl ast::NameRef {
28     pub fn text(&self) -> TokenText<'_> {
29         text_of_first_token(self.syntax())
30     }
31
32     pub fn as_tuple_field(&self) -> Option<usize> {
33         self.text().parse().ok()
34     }
35 }
36
37 fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> {
38     fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData {
39         green_ref.children().next().and_then(NodeOrToken::into_token).unwrap()
40     }
41
42     match node.green() {
43         Cow::Borrowed(green_ref) => TokenText::borrowed(first_token(green_ref).text()),
44         Cow::Owned(green) => TokenText::owned(first_token(&green).to_owned()),
45     }
46 }
47
48 #[derive(Debug, PartialEq, Eq, Clone)]
49 pub enum Macro {
50     MacroRules(ast::MacroRules),
51     MacroDef(ast::MacroDef),
52 }
53
54 impl From<ast::MacroRules> for Macro {
55     fn from(it: ast::MacroRules) -> Self {
56         Macro::MacroRules(it)
57     }
58 }
59
60 impl From<ast::MacroDef> for Macro {
61     fn from(it: ast::MacroDef) -> Self {
62         Macro::MacroDef(it)
63     }
64 }
65
66 impl AstNode for Macro {
67     fn can_cast(kind: SyntaxKind) -> bool {
68         matches!(kind, SyntaxKind::MACRO_RULES | SyntaxKind::MACRO_DEF)
69     }
70     fn cast(syntax: SyntaxNode) -> Option<Self> {
71         let res = match syntax.kind() {
72             SyntaxKind::MACRO_RULES => Macro::MacroRules(ast::MacroRules { syntax }),
73             SyntaxKind::MACRO_DEF => Macro::MacroDef(ast::MacroDef { syntax }),
74             _ => return None,
75         };
76         Some(res)
77     }
78     fn syntax(&self) -> &SyntaxNode {
79         match self {
80             Macro::MacroRules(it) => it.syntax(),
81             Macro::MacroDef(it) => it.syntax(),
82         }
83     }
84 }
85
86 impl NameOwner for Macro {
87     fn name(&self) -> Option<ast::Name> {
88         match self {
89             Macro::MacroRules(mac) => mac.name(),
90             Macro::MacroDef(mac) => mac.name(),
91         }
92     }
93 }
94
95 impl AttrsOwner for Macro {}
96
97 /// Basically an owned `dyn AttrsOwner` without extra boxing.
98 pub struct AttrsOwnerNode {
99     node: SyntaxNode,
100 }
101
102 impl AttrsOwnerNode {
103     pub fn new<N: AttrsOwner>(node: N) -> Self {
104         AttrsOwnerNode { node: node.syntax().clone() }
105     }
106 }
107
108 impl AttrsOwner for AttrsOwnerNode {}
109 impl AstNode for AttrsOwnerNode {
110     fn can_cast(_: SyntaxKind) -> bool
111     where
112         Self: Sized,
113     {
114         false
115     }
116     fn cast(_: SyntaxNode) -> Option<Self>
117     where
118         Self: Sized,
119     {
120         None
121     }
122     fn syntax(&self) -> &SyntaxNode {
123         &self.node
124     }
125 }
126
127 #[derive(Debug, Clone, PartialEq, Eq)]
128 pub enum AttrKind {
129     Inner,
130     Outer,
131 }
132
133 impl AttrKind {
134     /// Returns `true` if the attr_kind is [`Inner`].
135     pub fn is_inner(&self) -> bool {
136         matches!(self, Self::Inner)
137     }
138
139     /// Returns `true` if the attr_kind is [`Outer`].
140     pub fn is_outer(&self) -> bool {
141         matches!(self, Self::Outer)
142     }
143 }
144
145 impl ast::Attr {
146     pub fn as_simple_atom(&self) -> Option<SmolStr> {
147         if self.eq_token().is_some() || self.token_tree().is_some() {
148             return None;
149         }
150         self.simple_name()
151     }
152
153     pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> {
154         let tt = self.token_tree()?;
155         Some((self.simple_name()?, tt))
156     }
157
158     pub fn simple_name(&self) -> Option<SmolStr> {
159         let path = self.path()?;
160         match (path.segment(), path.qualifier()) {
161             (Some(segment), None) => Some(segment.syntax().first_token()?.text().into()),
162             _ => None,
163         }
164     }
165
166     pub fn kind(&self) -> AttrKind {
167         let first_token = self.syntax().first_token();
168         let first_token_kind = first_token.as_ref().map(SyntaxToken::kind);
169         let second_token_kind =
170             first_token.and_then(|token| token.next_token()).as_ref().map(SyntaxToken::kind);
171
172         match (first_token_kind, second_token_kind) {
173             (Some(T![#]), Some(T![!])) => AttrKind::Inner,
174             _ => AttrKind::Outer,
175         }
176     }
177 }
178
179 #[derive(Debug, Clone, PartialEq, Eq)]
180 pub enum PathSegmentKind {
181     Name(ast::NameRef),
182     Type { type_ref: Option<ast::Type>, trait_ref: Option<ast::PathType> },
183     SelfKw,
184     SuperKw,
185     CrateKw,
186 }
187
188 impl ast::PathSegment {
189     pub fn parent_path(&self) -> ast::Path {
190         self.syntax()
191             .parent()
192             .and_then(ast::Path::cast)
193             .expect("segments are always nested in paths")
194     }
195
196     pub fn crate_token(&self) -> Option<SyntaxToken> {
197         self.name_ref().and_then(|it| it.crate_token())
198     }
199
200     pub fn self_token(&self) -> Option<SyntaxToken> {
201         self.name_ref().and_then(|it| it.self_token())
202     }
203
204     pub fn super_token(&self) -> Option<SyntaxToken> {
205         self.name_ref().and_then(|it| it.super_token())
206     }
207
208     pub fn kind(&self) -> Option<PathSegmentKind> {
209         let res = if let Some(name_ref) = self.name_ref() {
210             match name_ref.syntax().first_token().map(|it| it.kind()) {
211                 Some(T![self]) => PathSegmentKind::SelfKw,
212                 Some(T![super]) => PathSegmentKind::SuperKw,
213                 Some(T![crate]) => PathSegmentKind::CrateKw,
214                 _ => PathSegmentKind::Name(name_ref),
215             }
216         } else {
217             match self.syntax().first_child_or_token()?.kind() {
218                 T![<] => {
219                     // <T> or <T as Trait>
220                     // T is any TypeRef, Trait has to be a PathType
221                     let mut type_refs =
222                         self.syntax().children().filter(|node| ast::Type::can_cast(node.kind()));
223                     let type_ref = type_refs.next().and_then(ast::Type::cast);
224                     let trait_ref = type_refs.next().and_then(ast::PathType::cast);
225                     PathSegmentKind::Type { type_ref, trait_ref }
226                 }
227                 _ => return None,
228             }
229         };
230         Some(res)
231     }
232 }
233
234 impl ast::Path {
235     pub fn parent_path(&self) -> Option<ast::Path> {
236         self.syntax().parent().and_then(ast::Path::cast)
237     }
238
239     pub fn as_single_segment(&self) -> Option<ast::PathSegment> {
240         match self.qualifier() {
241             Some(_) => None,
242             None => self.segment(),
243         }
244     }
245
246     pub fn first_qualifier_or_self(&self) -> ast::Path {
247         successors(Some(self.clone()), ast::Path::qualifier).last().unwrap()
248     }
249
250     pub fn first_segment(&self) -> Option<ast::PathSegment> {
251         self.first_qualifier_or_self().segment()
252     }
253
254     pub fn segments(&self) -> impl Iterator<Item = ast::PathSegment> + Clone {
255         // cant make use of SyntaxNode::siblings, because the returned Iterator is not clone
256         successors(self.first_segment(), |p| {
257             p.parent_path().parent_path().and_then(|p| p.segment())
258         })
259     }
260 }
261 impl ast::UseTree {
262     pub fn is_simple_path(&self) -> bool {
263         self.use_tree_list().is_none() && self.star_token().is_none()
264     }
265 }
266
267 impl ast::UseTreeList {
268     pub fn parent_use_tree(&self) -> ast::UseTree {
269         self.syntax()
270             .parent()
271             .and_then(ast::UseTree::cast)
272             .expect("UseTreeLists are always nested in UseTrees")
273     }
274
275     pub fn has_inner_comment(&self) -> bool {
276         self.syntax()
277             .children_with_tokens()
278             .filter_map(|it| it.into_token())
279             .find_map(ast::Comment::cast)
280             .is_some()
281     }
282 }
283
284 impl ast::Impl {
285     pub fn self_ty(&self) -> Option<ast::Type> {
286         match self.target() {
287             (Some(t), None) | (_, Some(t)) => Some(t),
288             _ => None,
289         }
290     }
291
292     pub fn trait_(&self) -> Option<ast::Type> {
293         match self.target() {
294             (Some(t), Some(_)) => Some(t),
295             _ => None,
296         }
297     }
298
299     fn target(&self) -> (Option<ast::Type>, Option<ast::Type>) {
300         let mut types = support::children(self.syntax());
301         let first = types.next();
302         let second = types.next();
303         (first, second)
304     }
305 }
306
307 #[derive(Debug, Clone, PartialEq, Eq)]
308 pub enum StructKind {
309     Record(ast::RecordFieldList),
310     Tuple(ast::TupleFieldList),
311     Unit,
312 }
313
314 impl StructKind {
315     fn from_node<N: AstNode>(node: &N) -> StructKind {
316         if let Some(nfdl) = support::child::<ast::RecordFieldList>(node.syntax()) {
317             StructKind::Record(nfdl)
318         } else if let Some(pfl) = support::child::<ast::TupleFieldList>(node.syntax()) {
319             StructKind::Tuple(pfl)
320         } else {
321             StructKind::Unit
322         }
323     }
324 }
325
326 impl ast::Struct {
327     pub fn kind(&self) -> StructKind {
328         StructKind::from_node(self)
329     }
330 }
331
332 impl ast::RecordExprField {
333     pub fn for_field_name(field_name: &ast::NameRef) -> Option<ast::RecordExprField> {
334         let candidate = Self::for_name_ref(field_name)?;
335         if candidate.field_name().as_ref() == Some(field_name) {
336             Some(candidate)
337         } else {
338             None
339         }
340     }
341
342     pub fn for_name_ref(name_ref: &ast::NameRef) -> Option<ast::RecordExprField> {
343         let syn = name_ref.syntax();
344         syn.parent()
345             .and_then(ast::RecordExprField::cast)
346             .or_else(|| syn.ancestors().nth(4).and_then(ast::RecordExprField::cast))
347     }
348
349     /// Deals with field init shorthand
350     pub fn field_name(&self) -> Option<ast::NameRef> {
351         if let Some(name_ref) = self.name_ref() {
352             return Some(name_ref);
353         }
354         self.expr()?.name_ref()
355     }
356 }
357
358 #[derive(Debug, Clone)]
359 pub enum NameLike {
360     NameRef(ast::NameRef),
361     Name(ast::Name),
362     Lifetime(ast::Lifetime),
363 }
364
365 impl NameLike {
366     pub fn as_name_ref(&self) -> Option<&ast::NameRef> {
367         match self {
368             NameLike::NameRef(name_ref) => Some(name_ref),
369             _ => None,
370         }
371     }
372 }
373
374 impl ast::AstNode for NameLike {
375     fn can_cast(kind: SyntaxKind) -> bool {
376         matches!(kind, SyntaxKind::NAME | SyntaxKind::NAME_REF | SyntaxKind::LIFETIME)
377     }
378     fn cast(syntax: SyntaxNode) -> Option<Self> {
379         let res = match syntax.kind() {
380             SyntaxKind::NAME => NameLike::Name(ast::Name { syntax }),
381             SyntaxKind::NAME_REF => NameLike::NameRef(ast::NameRef { syntax }),
382             SyntaxKind::LIFETIME => NameLike::Lifetime(ast::Lifetime { syntax }),
383             _ => return None,
384         };
385         Some(res)
386     }
387     fn syntax(&self) -> &SyntaxNode {
388         match self {
389             NameLike::NameRef(it) => it.syntax(),
390             NameLike::Name(it) => it.syntax(),
391             NameLike::Lifetime(it) => it.syntax(),
392         }
393     }
394 }
395
396 mod __ {
397     use super::{
398         ast::{Lifetime, Name, NameRef},
399         NameLike,
400     };
401     stdx::impl_from!(NameRef, Name, Lifetime for NameLike);
402 }
403
404 #[derive(Debug, Clone, PartialEq)]
405 pub enum NameOrNameRef {
406     Name(ast::Name),
407     NameRef(ast::NameRef),
408 }
409
410 impl fmt::Display for NameOrNameRef {
411     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
412         match self {
413             NameOrNameRef::Name(it) => fmt::Display::fmt(it, f),
414             NameOrNameRef::NameRef(it) => fmt::Display::fmt(it, f),
415         }
416     }
417 }
418
419 impl NameOrNameRef {
420     pub fn text(&self) -> TokenText<'_> {
421         match self {
422             NameOrNameRef::Name(name) => name.text(),
423             NameOrNameRef::NameRef(name_ref) => name_ref.text(),
424         }
425     }
426 }
427
428 impl ast::RecordPatField {
429     pub fn for_field_name_ref(field_name: &ast::NameRef) -> Option<ast::RecordPatField> {
430         let candidate = field_name.syntax().parent().and_then(ast::RecordPatField::cast)?;
431         match candidate.field_name()? {
432             NameOrNameRef::NameRef(name_ref) if name_ref == *field_name => Some(candidate),
433             _ => None,
434         }
435     }
436
437     pub fn for_field_name(field_name: &ast::Name) -> Option<ast::RecordPatField> {
438         let candidate =
439             field_name.syntax().ancestors().nth(2).and_then(ast::RecordPatField::cast)?;
440         match candidate.field_name()? {
441             NameOrNameRef::Name(name) if name == *field_name => Some(candidate),
442             _ => None,
443         }
444     }
445
446     /// Deals with field init shorthand
447     pub fn field_name(&self) -> Option<NameOrNameRef> {
448         if let Some(name_ref) = self.name_ref() {
449             return Some(NameOrNameRef::NameRef(name_ref));
450         }
451         match self.pat() {
452             Some(ast::Pat::IdentPat(pat)) => {
453                 let name = pat.name()?;
454                 Some(NameOrNameRef::Name(name))
455             }
456             Some(ast::Pat::BoxPat(pat)) => match pat.pat() {
457                 Some(ast::Pat::IdentPat(pat)) => {
458                     let name = pat.name()?;
459                     Some(NameOrNameRef::Name(name))
460                 }
461                 _ => None,
462             },
463             _ => None,
464         }
465     }
466 }
467
468 impl ast::Variant {
469     pub fn parent_enum(&self) -> ast::Enum {
470         self.syntax()
471             .parent()
472             .and_then(|it| it.parent())
473             .and_then(ast::Enum::cast)
474             .expect("EnumVariants are always nested in Enums")
475     }
476     pub fn kind(&self) -> StructKind {
477         StructKind::from_node(self)
478     }
479 }
480
481 #[derive(Debug, Clone, PartialEq, Eq)]
482 pub enum FieldKind {
483     Name(ast::NameRef),
484     Index(SyntaxToken),
485 }
486
487 impl ast::FieldExpr {
488     pub fn index_token(&self) -> Option<SyntaxToken> {
489         self.syntax
490             .children_with_tokens()
491             // FIXME: Accepting floats here to reject them in validation later
492             .find(|c| c.kind() == SyntaxKind::INT_NUMBER || c.kind() == SyntaxKind::FLOAT_NUMBER)
493             .as_ref()
494             .and_then(SyntaxElement::as_token)
495             .cloned()
496     }
497
498     pub fn field_access(&self) -> Option<FieldKind> {
499         if let Some(nr) = self.name_ref() {
500             Some(FieldKind::Name(nr))
501         } else {
502             self.index_token().map(FieldKind::Index)
503         }
504     }
505 }
506
507 pub struct SlicePatComponents {
508     pub prefix: Vec<ast::Pat>,
509     pub slice: Option<ast::Pat>,
510     pub suffix: Vec<ast::Pat>,
511 }
512
513 impl ast::SlicePat {
514     pub fn components(&self) -> SlicePatComponents {
515         let mut args = self.pats().peekable();
516         let prefix = args
517             .peeking_take_while(|p| match p {
518                 ast::Pat::RestPat(_) => false,
519                 ast::Pat::IdentPat(bp) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
520                 ast::Pat::RefPat(rp) => match rp.pat() {
521                     Some(ast::Pat::RestPat(_)) => false,
522                     Some(ast::Pat::IdentPat(bp)) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
523                     _ => true,
524                 },
525                 _ => true,
526             })
527             .collect();
528         let slice = args.next();
529         let suffix = args.collect();
530
531         SlicePatComponents { prefix, slice, suffix }
532     }
533 }
534
535 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
536 pub enum SelfParamKind {
537     /// self
538     Owned,
539     /// &self
540     Ref,
541     /// &mut self
542     MutRef,
543 }
544
545 impl ast::SelfParam {
546     pub fn kind(&self) -> SelfParamKind {
547         if self.amp_token().is_some() {
548             if self.mut_token().is_some() {
549                 SelfParamKind::MutRef
550             } else {
551                 SelfParamKind::Ref
552             }
553         } else {
554             SelfParamKind::Owned
555         }
556     }
557 }
558
559 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
560 pub enum TypeBoundKind {
561     /// Trait
562     PathType(ast::PathType),
563     /// for<'a> ...
564     ForType(ast::ForType),
565     /// 'a
566     Lifetime(ast::Lifetime),
567 }
568
569 impl ast::TypeBound {
570     pub fn kind(&self) -> TypeBoundKind {
571         if let Some(path_type) = support::children(self.syntax()).next() {
572             TypeBoundKind::PathType(path_type)
573         } else if let Some(for_type) = support::children(self.syntax()).next() {
574             TypeBoundKind::ForType(for_type)
575         } else if let Some(lifetime) = self.lifetime() {
576             TypeBoundKind::Lifetime(lifetime)
577         } else {
578             unreachable!()
579         }
580     }
581 }
582
583 pub enum VisibilityKind {
584     In(ast::Path),
585     PubCrate,
586     PubSuper,
587     PubSelf,
588     Pub,
589 }
590
591 impl ast::Visibility {
592     pub fn kind(&self) -> VisibilityKind {
593         match self.path() {
594             Some(path) => {
595                 if let Some(segment) =
596                     path.as_single_segment().filter(|it| it.coloncolon_token().is_none())
597                 {
598                     if segment.crate_token().is_some() {
599                         return VisibilityKind::PubCrate;
600                     } else if segment.super_token().is_some() {
601                         return VisibilityKind::PubSuper;
602                     } else if segment.self_token().is_some() {
603                         return VisibilityKind::PubSelf;
604                     }
605                 }
606                 VisibilityKind::In(path)
607             }
608             None => VisibilityKind::Pub,
609         }
610     }
611
612     pub fn is_eq_to(&self, other: &Self) -> bool {
613         match (self.kind(), other.kind()) {
614             (VisibilityKind::In(this), VisibilityKind::In(other)) => {
615                 stdx::iter_eq_by(this.segments(), other.segments(), |lhs, rhs| {
616                     lhs.kind().zip(rhs.kind()).map_or(false, |it| match it {
617                         (PathSegmentKind::CrateKw, PathSegmentKind::CrateKw)
618                         | (PathSegmentKind::SelfKw, PathSegmentKind::SelfKw)
619                         | (PathSegmentKind::SuperKw, PathSegmentKind::SuperKw) => true,
620                         (PathSegmentKind::Name(lhs), PathSegmentKind::Name(rhs)) => {
621                             lhs.text() == rhs.text()
622                         }
623                         _ => false,
624                     })
625                 })
626             }
627             (VisibilityKind::PubSelf, VisibilityKind::PubSelf)
628             | (VisibilityKind::PubSuper, VisibilityKind::PubSuper)
629             | (VisibilityKind::PubCrate, VisibilityKind::PubCrate)
630             | (VisibilityKind::Pub, VisibilityKind::Pub) => true,
631             _ => false,
632         }
633     }
634 }
635
636 impl ast::LifetimeParam {
637     pub fn lifetime_bounds(&self) -> impl Iterator<Item = SyntaxToken> {
638         self.syntax()
639             .children_with_tokens()
640             .filter_map(|it| it.into_token())
641             .skip_while(|x| x.kind() != T![:])
642             .filter(|it| it.kind() == T![lifetime_ident])
643     }
644 }
645
646 impl ast::RangePat {
647     pub fn start(&self) -> Option<ast::Pat> {
648         self.syntax()
649             .children_with_tokens()
650             .take_while(|it| !(it.kind() == T![..] || it.kind() == T![..=]))
651             .filter_map(|it| it.into_node())
652             .find_map(ast::Pat::cast)
653     }
654
655     pub fn end(&self) -> Option<ast::Pat> {
656         self.syntax()
657             .children_with_tokens()
658             .skip_while(|it| !(it.kind() == T![..] || it.kind() == T![..=]))
659             .filter_map(|it| it.into_node())
660             .find_map(ast::Pat::cast)
661     }
662 }
663
664 impl ast::TokenTree {
665     pub fn left_delimiter_token(&self) -> Option<SyntaxToken> {
666         self.syntax()
667             .first_child_or_token()?
668             .into_token()
669             .filter(|it| matches!(it.kind(), T!['{'] | T!['('] | T!['[']))
670     }
671
672     pub fn right_delimiter_token(&self) -> Option<SyntaxToken> {
673         self.syntax()
674             .last_child_or_token()?
675             .into_token()
676             .filter(|it| matches!(it.kind(), T!['}'] | T![')'] | T![']']))
677     }
678 }
679
680 impl ast::GenericParamList {
681     pub fn lifetime_params(&self) -> impl Iterator<Item = ast::LifetimeParam> {
682         self.generic_params().filter_map(|param| match param {
683             ast::GenericParam::LifetimeParam(it) => Some(it),
684             ast::GenericParam::TypeParam(_) | ast::GenericParam::ConstParam(_) => None,
685         })
686     }
687     pub fn type_params(&self) -> impl Iterator<Item = ast::TypeParam> {
688         self.generic_params().filter_map(|param| match param {
689             ast::GenericParam::TypeParam(it) => Some(it),
690             ast::GenericParam::LifetimeParam(_) | ast::GenericParam::ConstParam(_) => None,
691         })
692     }
693     pub fn const_params(&self) -> impl Iterator<Item = ast::ConstParam> {
694         self.generic_params().filter_map(|param| match param {
695             ast::GenericParam::ConstParam(it) => Some(it),
696             ast::GenericParam::TypeParam(_) | ast::GenericParam::LifetimeParam(_) => None,
697         })
698     }
699 }
700
701 impl ast::DocCommentsOwner for ast::SourceFile {}
702 impl ast::DocCommentsOwner for ast::Fn {}
703 impl ast::DocCommentsOwner for ast::Struct {}
704 impl ast::DocCommentsOwner for ast::Union {}
705 impl ast::DocCommentsOwner for ast::RecordField {}
706 impl ast::DocCommentsOwner for ast::TupleField {}
707 impl ast::DocCommentsOwner for ast::Enum {}
708 impl ast::DocCommentsOwner for ast::Variant {}
709 impl ast::DocCommentsOwner for ast::Trait {}
710 impl ast::DocCommentsOwner for ast::Module {}
711 impl ast::DocCommentsOwner for ast::Static {}
712 impl ast::DocCommentsOwner for ast::Const {}
713 impl ast::DocCommentsOwner for ast::TypeAlias {}
714 impl ast::DocCommentsOwner for ast::Impl {}
715 impl ast::DocCommentsOwner for ast::MacroRules {}
716 impl ast::DocCommentsOwner for ast::MacroDef {}
717 impl ast::DocCommentsOwner for ast::Macro {}
718 impl ast::DocCommentsOwner for ast::Use {}