aboutsummaryrefslogtreecommitdiff
path: root/xtask
diff options
context:
space:
mode:
Diffstat (limited to 'xtask')
-rw-r--r--xtask/src/ast_src.rs1529
-rw-r--r--xtask/src/codegen.rs91
-rw-r--r--xtask/src/codegen/gen_assists_docs.rs209
-rw-r--r--xtask/src/codegen/gen_feature_docs.rs75
-rw-r--r--xtask/src/codegen/gen_syntax.rs26
-rw-r--r--xtask/src/lib.rs6
-rw-r--r--xtask/src/main.rs1
-rw-r--r--xtask/tests/tidy-tests/cli.rs32
-rw-r--r--xtask/tests/tidy.rs (renamed from xtask/tests/tidy-tests/main.rs)71
9 files changed, 1838 insertions, 202 deletions
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index bdd42cb76..f60f0fb16 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -162,6 +162,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
162 "RECORD_LIT", 162 "RECORD_LIT",
163 "RECORD_FIELD_LIST", 163 "RECORD_FIELD_LIST",
164 "RECORD_FIELD", 164 "RECORD_FIELD",
165 "EFFECT_EXPR",
165 "BOX_EXPR", 166 "BOX_EXPR",
166 // postfix 167 // postfix
167 "CALL_EXPR", 168 "CALL_EXPR",
@@ -176,7 +177,6 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
176 "PREFIX_EXPR", 177 "PREFIX_EXPR",
177 "RANGE_EXPR", // just weird 178 "RANGE_EXPR", // just weird
178 "BIN_EXPR", 179 "BIN_EXPR",
179 "BLOCK",
180 "EXTERN_BLOCK", 180 "EXTERN_BLOCK",
181 "EXTERN_ITEM_LIST", 181 "EXTERN_ITEM_LIST",
182 "ENUM_VARIANT", 182 "ENUM_VARIANT",
@@ -230,6 +230,7 @@ pub(crate) struct AstSrc<'a> {
230} 230}
231 231
232pub(crate) struct AstNodeSrc<'a> { 232pub(crate) struct AstNodeSrc<'a> {
233 pub(crate) doc: &'a [&'a str],
233 pub(crate) name: &'a str, 234 pub(crate) name: &'a str,
234 pub(crate) traits: &'a [&'a str], 235 pub(crate) traits: &'a [&'a str],
235 pub(crate) fields: &'a [Field<'a>], 236 pub(crate) fields: &'a [Field<'a>],
@@ -247,6 +248,7 @@ pub(crate) enum FieldSrc<'a> {
247} 248}
248 249
249pub(crate) struct AstEnumSrc<'a> { 250pub(crate) struct AstEnumSrc<'a> {
251 pub(crate) doc: &'a [&'a str],
250 pub(crate) name: &'a str, 252 pub(crate) name: &'a str,
251 pub(crate) traits: &'a [&'a str], 253 pub(crate) traits: &'a [&'a str],
252 pub(crate) variants: &'a [&'a str], 254 pub(crate) variants: &'a [&'a str],
@@ -254,12 +256,14 @@ pub(crate) struct AstEnumSrc<'a> {
254 256
255macro_rules! ast_nodes { 257macro_rules! ast_nodes {
256 ($( 258 ($(
259 $(#[doc = $doc:expr])+
257 struct $name:ident$(: $($trait:ident),*)? { 260 struct $name:ident$(: $($trait:ident),*)? {
258 $($field_name:ident $(![$token:tt])? $(: $ty:tt)?),*$(,)? 261 $($field_name:ident $(![$token:tt])? $(: $ty:tt)?),*$(,)?
259 } 262 }
260 )*) => { 263 )*) => {
261 [$( 264 [$(
262 AstNodeSrc { 265 AstNodeSrc {
266 doc: &[$($doc),*],
263 name: stringify!($name), 267 name: stringify!($name),
264 traits: &[$($(stringify!($trait)),*)?], 268 traits: &[$($(stringify!($trait)),*)?],
265 fields: &[ 269 fields: &[
@@ -288,12 +292,14 @@ macro_rules! field {
288 292
289macro_rules! ast_enums { 293macro_rules! ast_enums {
290 ($( 294 ($(
295 $(#[doc = $doc:expr])+
291 enum $name:ident $(: $($trait:ident),*)? { 296 enum $name:ident $(: $($trait:ident),*)? {
292 $($variant:ident),*$(,)? 297 $($variant:ident),*$(,)?
293 } 298 }
294 )*) => { 299 )*) => {
295 [$( 300 [$(
296 AstEnumSrc { 301 AstEnumSrc {
302 doc: &[$($doc),*],
297 name: stringify!($name), 303 name: stringify!($name),
298 traits: &[$($(stringify!($trait)),*)?], 304 traits: &[$($(stringify!($trait)),*)?],
299 variants: &[$(stringify!($variant)),*], 305 variants: &[$(stringify!($variant)),*],
@@ -305,10 +311,35 @@ macro_rules! ast_enums {
305pub(crate) const AST_SRC: AstSrc = AstSrc { 311pub(crate) const AST_SRC: AstSrc = AstSrc {
306 tokens: &["Whitespace", "Comment", "String", "RawString"], 312 tokens: &["Whitespace", "Comment", "String", "RawString"],
307 nodes: &ast_nodes! { 313 nodes: &ast_nodes! {
308 struct SourceFile: ModuleItemOwner, AttrsOwner { 314 /// The entire Rust source file. Includes all top-level inner attributes and module items.
315 ///
316 /// [Reference](https://doc.rust-lang.org/reference/crates-and-source-files.html)
317 struct SourceFile: ModuleItemOwner, AttrsOwner, DocCommentsOwner {
309 modules: [Module], 318 modules: [Module],
310 } 319 }
311 320
321 /// Function definition either with body or not.
322 /// Includes all of its attributes and doc comments.
323 ///
324 /// ```
325 /// ❰
326 /// /// Docs
327 /// #[attr]
328 /// pub extern "C" fn foo<T>(#[attr] Patern {p}: Pattern) -> u32
329 /// where
330 /// T: Debug
331 /// {
332 /// 42
333 /// }
334 /// ❱
335 ///
336 /// extern "C" {
337 /// ❰ fn fn_decl(also_variadic_ffi: u32, ...) -> u32; ❱
338 /// }
339 /// ```
340 ///
341 /// - [Reference](https://doc.rust-lang.org/reference/items/functions.html)
342 /// - [Nomicon](https://doc.rust-lang.org/nomicon/ffi.html#variadic-functions)
312 struct FnDef: VisibilityOwner, NameOwner, TypeParamsOwner, DocCommentsOwner, AttrsOwner { 343 struct FnDef: VisibilityOwner, NameOwner, TypeParamsOwner, DocCommentsOwner, AttrsOwner {
313 Abi, 344 Abi,
314 T![const], 345 T![const],
@@ -322,42 +353,201 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
322 T![;] 353 T![;]
323 } 354 }
324 355
356 /// Return type annotation.
357 ///
358 /// ```
359 /// fn foo(a: u32) ❰ -> Option<u32> ❱ { Some(a) }
360 /// ```
361 ///
362 /// [Reference](https://doc.rust-lang.org/reference/items/functions.html)
325 struct RetType { T![->], TypeRef } 363 struct RetType { T![->], TypeRef }
326 364
365 /// Struct definition.
366 /// Includes all of its attributes and doc comments.
367 ///
368 /// ```
369 /// ❰
370 /// /// Docs
371 /// #[attr]
372 /// struct Foo<T> where T: Debug {
373 /// /// Docs
374 /// #[attr]
375 /// pub a: u32,
376 /// b: T,
377 /// }
378 /// ❱
379 ///
380 /// ❰ struct Foo; ❱
381 /// ❰ struct Foo<T>(#[attr] T) where T: Debug; ❱
382 /// ```
383 ///
384 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
327 struct StructDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { 385 struct StructDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
328 T![struct], 386 T![struct],
329 FieldDefList, 387 FieldDefList,
330 T![;] 388 T![;]
331 } 389 }
332 390
391 /// Union definition.
392 /// Includes all of its attributes and doc comments.
393 ///
394 /// ```
395 /// ❰
396 /// /// Docs
397 /// #[attr]
398 /// pub union Foo<T> where T: Debug {
399 /// /// Docs
400 /// #[attr]
401 /// a: T,
402 /// b: u32,
403 /// }
404 /// ❱
405 /// ```
406 ///
407 /// [Reference](https://doc.rust-lang.org/reference/items/unions.html)
333 struct UnionDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { 408 struct UnionDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
334 T![union], 409 T![union],
335 RecordFieldDefList, 410 RecordFieldDefList,
336 } 411 }
337 412
413 /// Record field definition list including enclosing curly braces.
414 ///
415 /// ```
416 /// struct Foo // same for union
417 /// ❰
418 /// {
419 /// a: u32,
420 /// b: bool,
421 /// }
422 /// ❱
423 /// ```
424 ///
425 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
338 struct RecordFieldDefList { T!['{'], fields: [RecordFieldDef], T!['}'] } 426 struct RecordFieldDefList { T!['{'], fields: [RecordFieldDef], T!['}'] }
427
428 /// Record field definition including its attributes and doc comments.
429 ///
430 /// ` ``
431 /// same for union
432 /// struct Foo {
433 /// ❰
434 /// /// Docs
435 /// #[attr]
436 /// pub a: u32
437 /// ❱
438 ///
439 /// ❰ b: bool ❱
440 /// }
441 /// ```
442 ///
443 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
339 struct RecordFieldDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { } 444 struct RecordFieldDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { }
340 445
446 /// Tuple field definition list including enclosing parens.
447 ///
448 /// ```
449 /// struct Foo ❰ (u32, String, Vec<u32>) ❱;
450 /// ```
451 ///
452 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
341 struct TupleFieldDefList { T!['('], fields: [TupleFieldDef], T![')'] } 453 struct TupleFieldDefList { T!['('], fields: [TupleFieldDef], T![')'] }
454
455 /// Tuple field definition including its attributes.
456 ///
457 /// ```
458 /// struct Foo(❰ #[attr] u32 ❱);
459 /// ```
460 ///
461 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
342 struct TupleFieldDef: VisibilityOwner, AttrsOwner { 462 struct TupleFieldDef: VisibilityOwner, AttrsOwner {
343 TypeRef, 463 TypeRef,
344 } 464 }
345 465
466 /// Enum definition.
467 /// Includes all of its attributes and doc comments.
468 ///
469 /// ```
470 /// ❰
471 /// /// Docs
472 /// #[attr]
473 /// pub enum Foo<T> where T: Debug {
474 /// /// Docs
475 /// #[attr]
476 /// Bar,
477 /// Baz(#[attr] u32),
478 /// Bruh {
479 /// a: u32,
480 /// /// Docs
481 /// #[attr]
482 /// b: T,
483 /// }
484 /// }
485 /// ❱
486 /// ```
487 ///
488 /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html)
346 struct EnumDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { 489 struct EnumDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
347 T![enum], 490 T![enum],
348 variant_list: EnumVariantList, 491 variant_list: EnumVariantList,
349 } 492 }
493
494 /// Enum variant definition list including enclosing curly braces.
495 ///
496 /// ```
497 /// enum Foo
498 /// ❰
499 /// {
500 /// Bar,
501 /// Baz(u32),
502 /// Bruh {
503 /// a: u32
504 /// }
505 /// }
506 /// ❱
507 /// ```
508 ///
509 /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html)
350 struct EnumVariantList { 510 struct EnumVariantList {
351 T!['{'], 511 T!['{'],
352 variants: [EnumVariant], 512 variants: [EnumVariant],
353 T!['}'] 513 T!['}']
354 } 514 }
515
516 /// Enum variant definition including its attributes and discriminant value definition.
517 ///
518 /// ```
519 /// enum Foo {
520 /// ❰
521 /// /// Docs
522 /// #[attr]
523 /// Bar
524 /// ❱
525 ///
526 /// // same for tuple and record variants
527 /// }
528 /// ```
529 ///
530 /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html)
355 struct EnumVariant: VisibilityOwner, NameOwner, DocCommentsOwner, AttrsOwner { 531 struct EnumVariant: VisibilityOwner, NameOwner, DocCommentsOwner, AttrsOwner {
356 FieldDefList, 532 FieldDefList,
357 T![=], 533 T![=],
358 Expr 534 Expr
359 } 535 }
360 536
537 /// Trait definition.
538 /// Includes all of its attributes and doc comments.
539 ///
540 /// ```
541 /// ❰
542 /// /// Docs
543 /// #[attr]
544 /// pub unsafe trait Foo<T>: Debug where T: Debug {
545 /// // ...
546 /// }
547 /// ❱
548 /// ```
549 ///
550 /// [Reference](https://doc.rust-lang.org/reference/items/traits.html)
361 struct TraitDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeParamsOwner, TypeBoundsOwner { 551 struct TraitDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeParamsOwner, TypeBoundsOwner {
362 T![unsafe], 552 T![unsafe],
363 T![auto], 553 T![auto],
@@ -365,18 +555,73 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
365 ItemList, 555 ItemList,
366 } 556 }
367 557
558 /// Module definition either with body or not.
559 /// Includes all of its inner and outer attributes, module items, doc comments.
560 ///
561 /// ```
562 /// ❰
563 /// /// Docs
564 /// #[attr]
565 /// pub mod foo;
566 /// ❱
567 ///
568 /// ❰
569 /// /// Docs
570 /// #[attr]
571 /// pub mod bar {
572 /// //! Inner docs
573 /// #![inner_attr]
574 /// }
575 /// ❱
576 /// ```
577 ///
578 /// [Reference](https://doc.rust-lang.org/reference/items/modules.html)
368 struct Module: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner { 579 struct Module: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner {
369 T![mod], 580 T![mod],
370 ItemList, 581 ItemList,
371 T![;] 582 T![;]
372 } 583 }
373 584
585 /// Item defintion list.
586 /// This is used for both top-level items and impl block items.
587 ///
588 /// ```
589 /// ❰
590 /// fn foo {}
591 /// struct Bar;
592 /// enum Baz;
593 /// trait Bruh;
594 /// const BRUUH: u32 = 42;
595 /// ❱
596 ///
597 /// impl Foo
598 /// ❰
599 /// {
600 /// fn bar() {}
601 /// const BAZ: u32 = 42;
602 /// }
603 /// ❱
604 /// ```
605 ///
606 /// [Reference](https://doc.rust-lang.org/reference/items.html)
374 struct ItemList: ModuleItemOwner { 607 struct ItemList: ModuleItemOwner {
375 T!['{'], 608 T!['{'],
376 impl_items: [ImplItem], 609 assoc_items: [AssocItem],
377 T!['}'] 610 T!['}']
378 } 611 }
379 612
613 /// Constant variable definition.
614 /// Includes all of its attributes and doc comments.
615 ///
616 /// ```
617 /// ❰
618 /// /// Docs
619 /// #[attr]
620 /// pub const FOO: u32 = 42;
621 /// ❱
622 /// ```
623 ///
624 /// [Reference](https://doc.rust-lang.org/reference/items/constant-items.html)
380 struct ConstDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { 625 struct ConstDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner {
381 T![default], 626 T![default],
382 T![const], 627 T![const],
@@ -385,6 +630,19 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
385 T![;] 630 T![;]
386 } 631 }
387 632
633
634 /// Static variable definition.
635 /// Includes all of its attributes and doc comments.
636 ///
637 /// ```
638 /// ❰
639 /// /// Docs
640 /// #[attr]
641 /// pub static mut FOO: u32 = 42;
642 /// ❱
643 /// ```
644 ///
645 /// [Reference](https://doc.rust-lang.org/reference/items/static-items.html)
388 struct StaticDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { 646 struct StaticDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner {
389 T![static], 647 T![static],
390 T![mut], 648 T![mut],
@@ -393,6 +651,24 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
393 T![;] 651 T![;]
394 } 652 }
395 653
654 /// Type alias definition.
655 /// Includes associated type clauses with type bounds.
656 ///
657 /// ```
658 /// ❰
659 /// /// Docs
660 /// #[attr]
661 /// pub type Foo<T> where T: Debug = T;
662 /// ❱
663 ///
664 /// trait Bar {
665 /// ❰ type Baz: Debug; ❱
666 /// ❰ type Bruh = String; ❱
667 /// ❰ type Bruuh: Debug = u32; ❱
668 /// }
669 /// ```
670 ///
671 /// [Reference](https://doc.rust-lang.org/reference/items/type-aliases.html)
396 struct TypeAliasDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeBoundsOwner { 672 struct TypeAliasDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeBoundsOwner {
397 T![default], 673 T![default],
398 T![type], 674 T![type],
@@ -401,7 +677,21 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
401 T![;] 677 T![;]
402 } 678 }
403 679
404 struct ImplDef: TypeParamsOwner, AttrsOwner { 680 /// Inherent and trait impl definition.
681 /// Includes all of its inner and outer attributes.
682 ///
683 /// ```
684 /// ❰
685 /// #[attr]
686 /// unsafe impl<T> const !Foo for Bar where T: Debug {
687 /// #![inner_attr]
688 /// // ...
689 /// }
690 /// ❱
691 /// ```
692 ///
693 /// [Reference](https://doc.rust-lang.org/reference/items/implementations.html)
694 struct ImplDef: TypeParamsOwner, AttrsOwner, DocCommentsOwner {
405 T![default], 695 T![default],
406 T![const], 696 T![const],
407 T![unsafe], 697 T![unsafe],
@@ -411,73 +701,613 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
411 ItemList, 701 ItemList,
412 } 702 }
413 703
704
705 /// Parenthesized type reference.
706 /// Note: parens are only used for grouping, this is not a tuple type.
707 ///
708 /// ```
709 /// // This is effectively just `u32`.
710 /// // Single-item tuple must be defined with a trailing comma: `(u32,)`
711 /// type Foo = ❰ (u32) ❱;
712 ///
713 /// let bar: &'static ❰ (dyn Debug) ❱ = "bruh";
714 /// ```
414 struct ParenType { T!['('], TypeRef, T![')'] } 715 struct ParenType { T!['('], TypeRef, T![')'] }
716
717 /// Unnamed tuple type.
718 ///
719 /// ```
720 /// let foo: ❰ (u32, bool) ❱ = (42, true);
721 /// ```
722 ///
723 /// [Reference](https://doc.rust-lang.org/reference/types/tuple.html)
415 struct TupleType { T!['('], fields: [TypeRef], T![')'] } 724 struct TupleType { T!['('], fields: [TypeRef], T![')'] }
725
726 /// The never type (i.e. the exclamation point).
727 ///
728 /// ```
729 /// type T = ❰ ! ❱;
730 ///
731 /// fn no_return() -> ❰ ! ❱ {
732 /// loop {}
733 /// }
734 /// ```
735 ///
736 /// [Reference](https://doc.rust-lang.org/reference/types/never.html)
416 struct NeverType { T![!] } 737 struct NeverType { T![!] }
738
739 /// Path to a type.
740 /// Includes single identifier type names and elaborate paths with
741 /// generic parameters.
742 ///
743 /// ```
744 /// type Foo = ❰ String ❱;
745 /// type Bar = ❰ std::vec::Vec<T> ❱;
746 /// type Baz = ❰ ::bruh::<Bruuh as Iterator>::Item ❱;
747 /// ```
748 ///
749 /// [Reference](https://doc.rust-lang.org/reference/paths.html)
417 struct PathType { Path } 750 struct PathType { Path }
751
752 /// Raw pointer type.
753 ///
754 /// ```
755 /// type Foo = ❰ *const u32 ❱;
756 /// type Bar = ❰ *mut u32 ❱;
757 /// ```
758 ///
759 /// [Reference](https://doc.rust-lang.org/reference/types/pointer.html#raw-pointers-const-and-mut)
418 struct PointerType { T![*], T![const], T![mut], TypeRef } 760 struct PointerType { T![*], T![const], T![mut], TypeRef }
761
762 /// Array type.
763 ///
764 /// ```
765 /// type Foo = ❰ [u32; 24 - 3] ❱;
766 /// ```
767 ///
768 /// [Reference](https://doc.rust-lang.org/reference/types/array.html)
419 struct ArrayType { T!['['], TypeRef, T![;], Expr, T![']'] } 769 struct ArrayType { T!['['], TypeRef, T![;], Expr, T![']'] }
770
771 /// Slice type.
772 ///
773 /// ```
774 /// type Foo = ❰ [u8] ❱;
775 /// ```
776 ///
777 /// [Reference](https://doc.rust-lang.org/reference/types/slice.html)
420 struct SliceType { T!['['], TypeRef, T![']'] } 778 struct SliceType { T!['['], TypeRef, T![']'] }
779
780 /// Reference type.
781 ///
782 /// ```
783 /// type Foo = ❰ &'static str ❱;
784 /// ```
785 ///
786 /// [Reference](https://doc.rust-lang.org/reference/types/pointer.html)
421 struct ReferenceType { T![&], T![lifetime], T![mut], TypeRef } 787 struct ReferenceType { T![&], T![lifetime], T![mut], TypeRef }
788
789 /// Placeholder type (i.e. the underscore).
790 ///
791 /// ```
792 /// let foo: ❰ _ ❱ = 42_u32;
793 /// ```
794 ///
795 /// [Reference](https://doc.rust-lang.org/reference/types/inferred.html)
422 struct PlaceholderType { T![_] } 796 struct PlaceholderType { T![_] }
797
798 /// Function pointer type (not to be confused with `Fn*` family of traits).
799 ///
800 /// ```
801 /// type Foo = ❰ async fn(#[attr] u32, named: bool) -> u32 ❱;
802 ///
803 /// type Bar = ❰ extern "C" fn(variadic: u32, #[attr] ...) ❱;
804 /// ```
805 ///
806 /// [Reference](https://doc.rust-lang.org/reference/types/function-pointer.html)
423 struct FnPointerType { Abi, T![unsafe], T![fn], ParamList, RetType } 807 struct FnPointerType { Abi, T![unsafe], T![fn], ParamList, RetType }
808
809 /// Higher order type.
810 ///
811 /// ```
812 /// type Foo = ❰ for<'a> fn(&'a str) ❱;
813 /// ```
814 ///
815 /// [Reference](https://doc.rust-lang.org/nomicon/hrtb.html)
424 struct ForType { T![for], TypeParamList, TypeRef } 816 struct ForType { T![for], TypeParamList, TypeRef }
817
818 /// Opaque `impl Trait` type.
819 ///
820 /// ```
821 /// fn foo(bar: ❰ impl Debug + Eq ❱) {}
822 /// ```
823 ///
824 /// [Reference](https://doc.rust-lang.org/reference/types/impl-trait.html)
425 struct ImplTraitType: TypeBoundsOwner { T![impl] } 825 struct ImplTraitType: TypeBoundsOwner { T![impl] }
826
827 /// Trait object type.
828 ///
829 /// ```
830 /// type Foo = ❰ dyn Debug ❱;
831 /// ```
832 ///
833 /// [Reference](https://doc.rust-lang.org/reference/types/trait-object.html)
426 struct DynTraitType: TypeBoundsOwner { T![dyn] } 834 struct DynTraitType: TypeBoundsOwner { T![dyn] }
427 835
836 /// Tuple literal.
837 ///
838 /// ```
839 /// ❰ (42, true) ❱;
840 /// ```
841 ///
842 /// [Reference](https://doc.rust-lang.org/reference/expressions/tuple-expr.html)
428 struct TupleExpr: AttrsOwner { T!['('], exprs: [Expr], T![')'] } 843 struct TupleExpr: AttrsOwner { T!['('], exprs: [Expr], T![')'] }
844
845 /// Array literal.
846 ///
847 /// ```
848 /// ❰ [#![inner_attr] true, false, true] ❱;
849 ///
850 /// ❰ ["baz"; 24] ❱;
851 /// ```
852 ///
853 /// [Reference](https://doc.rust-lang.org/reference/expressions/array-expr.html)
429 struct ArrayExpr: AttrsOwner { T!['['], exprs: [Expr], T![;], T![']'] } 854 struct ArrayExpr: AttrsOwner { T!['['], exprs: [Expr], T![;], T![']'] }
855
856 /// Parenthesized expression.
857 /// Note: parens are only used for grouping, this is not a tuple literal.
858 ///
859 /// ```
860 /// ❰ (#![inner_attr] 2 + 2) ❱ * 2;
861 /// ```
862 ///
863 /// [Reference](https://doc.rust-lang.org/reference/expressions/grouped-expr.html)
430 struct ParenExpr: AttrsOwner { T!['('], Expr, T![')'] } 864 struct ParenExpr: AttrsOwner { T!['('], Expr, T![')'] }
431 struct PathExpr { Path } 865
866 /// Path to a symbol in expression context.
867 /// Includes single identifier variable names and elaborate paths with
868 /// generic parameters.
869 ///
870 /// ```
871 /// ❰ Some::<i32> ❱;
872 /// ❰ foo ❱ + 42;
873 /// ❰ Vec::<i32>::push ❱;
874 /// ❰ <[i32]>::reverse ❱;
875 /// ❰ <String as std::borrow::Borrow<str>>::borrow ❱;
876 /// ```
877 ///
878 /// [Reference](https://doc.rust-lang.org/reference/expressions/path-expr.html)
879 struct PathExpr { Path }
880
881 /// Anonymous callable object literal a.k.a. closure, lambda or functor.
882 ///
883 /// ```
884 /// ❰ || 42 ❱;
885 /// ❰ |a: u32| val + 1 ❱;
886 /// ❰ async |#[attr] Pattern(_): Pattern| { bar } ❱;
887 /// ❰ move || baz ❱;
888 /// ❰ || -> u32 { closure_with_ret_type_annotation_requires_block_expr } ❱
889 /// ```
890 ///
891 /// [Reference](https://doc.rust-lang.org/reference/expressions/closure-expr.html)
432 struct LambdaExpr: AttrsOwner { 892 struct LambdaExpr: AttrsOwner {
433 T![static], 893 T![static], // Note(@matklad): I belive this is (used to be?) syntax for generators
434 T![async], 894 T![async],
435 T![move], 895 T![move],
436 ParamList, 896 ParamList,
437 RetType, 897 RetType,
438 body: Expr, 898 body: Expr,
439 } 899 }
900
901 /// If expression. Includes both regular `if` and `if let` forms.
902 /// Beware that `else if` is a special case syntax sugar, because in general
903 /// there has to be block expression after `else`.
904 ///
905 /// ```
906 /// ❰ if bool_cond { 42 } ❱
907 /// ❰ if bool_cond { 42 } else { 24 } ❱
908 /// ❰ if bool_cond { 42 } else if bool_cond2 { 42 } ❱
909 ///
910 /// ❰
911 /// if let Pattern(foo) = bar {
912 /// foo
913 /// } else {
914 /// panic!();
915 /// }
916 /// ❱
917 /// ```
918 ///
919 /// [Reference](https://doc.rust-lang.org/reference/expressions/if-expr.html)
440 struct IfExpr: AttrsOwner { T![if], Condition } 920 struct IfExpr: AttrsOwner { T![if], Condition }
921
922 /// Unconditional loop expression.
923 ///
924 /// ```
925 /// ❰
926 /// loop {
927 /// // yeah, it's that simple...
928 /// }
929 /// ❱
930 /// ```
931 ///
932 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html)
441 struct LoopExpr: AttrsOwner, LoopBodyOwner { T![loop] } 933 struct LoopExpr: AttrsOwner, LoopBodyOwner { T![loop] }
934
935 /// Block expression with an optional prefix (label, try ketword,
936 /// unsafe keyword, async keyword...).
937 ///
938 /// ```
939 /// ❰
940 /// 'label: try {
941 /// None?
942 /// }
943 /// ❱
944 /// ```
945 ///
946 /// - [try block](https://doc.rust-lang.org/unstable-book/language-features/try-blocks.html)
947 /// - [unsafe block](https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks)
948 /// - [async block](https://doc.rust-lang.org/reference/expressions/block-expr.html#async-blocks)
949 struct EffectExpr: AttrsOwner { Label, T![try], T![unsafe], T![async], BlockExpr }
950
951
952 /// For loop expression.
953 /// Note: record struct literals are not valid as iterable expression
954 /// due to ambiguity.
955 ///
956 /// ```
957 /// ❰
958 /// for i in (0..4) {
959 /// dbg!(i);
960 /// }
961 /// ❱
962 /// ```
963 ///
964 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#iterator-loops)
442 struct ForExpr: AttrsOwner, LoopBodyOwner { 965 struct ForExpr: AttrsOwner, LoopBodyOwner {
443 T![for], 966 T![for],
444 Pat, 967 Pat,
445 T![in], 968 T![in],
446 iterable: Expr, 969 iterable: Expr,
447 } 970 }
971
972 /// While loop expression. Includes both regular `while` and `while let` forms.
973 ///
974 /// ```
975 /// ❰
976 /// while bool_cond {
977 /// 42;
978 /// }
979 /// ❱
980 /// ❰
981 /// while let Pattern(foo) = bar {
982 /// bar += 1;
983 /// }
984 /// ❱
985 /// ```
986 ///
987 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-loops)
448 struct WhileExpr: AttrsOwner, LoopBodyOwner { T![while], Condition } 988 struct WhileExpr: AttrsOwner, LoopBodyOwner { T![while], Condition }
989
990 /// Continue expression.
991 ///
992 /// ```
993 /// while bool_cond {
994 /// ❰ continue ❱;
995 /// }
996 ///
997 /// 'outer: loop {
998 /// loop {
999 /// ❰ continue 'outer ❱;
1000 /// }
1001 /// }
1002 ///
1003 /// ```
1004 ///
1005 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#continue-expressions)
449 struct ContinueExpr: AttrsOwner { T![continue], T![lifetime] } 1006 struct ContinueExpr: AttrsOwner { T![continue], T![lifetime] }
1007
1008 /// Break expression.
1009 ///
1010 /// ```
1011 /// while bool_cond {
1012 /// ❰ break ❱;
1013 /// }
1014 /// 'outer: loop {
1015 /// for foo in bar {
1016 /// ❰ break 'outer ❱;
1017 /// }
1018 /// }
1019 /// 'outer: loop {
1020 /// loop {
1021 /// ❰ break 'outer 42 ❱;
1022 /// }
1023 /// }
1024 /// ```
1025 ///
1026 /// [Refernce](https://doc.rust-lang.org/reference/expressions/loop-expr.html#break-expressions)
450 struct BreakExpr: AttrsOwner { T![break], T![lifetime], Expr } 1027 struct BreakExpr: AttrsOwner { T![break], T![lifetime], Expr }
1028
1029 /// Label.
1030 ///
1031 /// ```
1032 /// ❰ 'outer: ❱ loop {}
1033 ///
1034 /// let foo = ❰ 'bar: ❱ loop {}
1035 ///
1036 /// ❰ 'baz: ❱ {
1037 /// break 'baz;
1038 /// }
1039 /// ```
1040 ///
1041 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html?highlight=label#loop-labels)
1042 /// [Labels for blocks RFC](https://github.com/rust-lang/rfcs/blob/master/text/2046-label-break-value.md)
451 struct Label { T![lifetime] } 1043 struct Label { T![lifetime] }
452 struct BlockExpr: AttrsOwner { Label, T![unsafe], T![async], Block } 1044
1045 /// Block expression. Includes unsafe blocks and block labels.
1046 ///
1047 /// ```
1048 /// let foo = ❰
1049 /// {
1050 /// #![inner_attr]
1051 /// ❰ { } ❱
1052 ///
1053 /// ❰ 'label: { break 'label } ❱
1054 /// }
1055 /// ❱;
1056 /// ```
1057 ///
1058 /// [Reference](https://doc.rust-lang.org/reference/expressions/block-expr.html)
1059 /// [Labels for blocks RFC](https://github.com/rust-lang/rfcs/blob/master/text/2046-label-break-value.md)
1060 struct BlockExpr: AttrsOwner, ModuleItemOwner {
1061 Label, T!['{'], statements: [Stmt], Expr, T!['}'],
1062 }
1063
1064 /// Return expression.
1065 ///
1066 /// ```
1067 /// || ❰ return 42 ❱;
1068 ///
1069 /// fn bar() {
1070 /// ❰ return ❱;
1071 /// }
1072 /// ```
1073 ///
1074 /// [Reference](https://doc.rust-lang.org/reference/expressions/return-expr.html)
453 struct ReturnExpr: AttrsOwner { Expr } 1075 struct ReturnExpr: AttrsOwner { Expr }
1076
1077 /// Call expression (not to be confused with method call expression, it is
1078 /// a separate ast node).
1079 ///
1080 /// ```
1081 /// ❰ foo() ❱;
1082 /// ❰ &str::len("bar") ❱;
1083 /// ❰ <&str as PartialEq<&str>>::eq(&"", &"") ❱;
1084 /// ```
1085 ///
1086 /// [Reference](https://doc.rust-lang.org/reference/expressions/call-expr.html)
454 struct CallExpr: ArgListOwner { Expr } 1087 struct CallExpr: ArgListOwner { Expr }
1088
1089 /// Method call expression.
1090 ///
1091 /// ```
1092 /// ❰ receiver_expr.method() ❱;
1093 /// ❰ receiver_expr.method::<T>(42, true) ❱;
1094 ///
1095 /// ❰ ❰ ❰ foo.bar() ❱ .baz() ❱ .bruh() ❱;
1096 /// ```
1097 ///
1098 /// [Reference](https://doc.rust-lang.org/reference/expressions/method-call-expr.html)
455 struct MethodCallExpr: AttrsOwner, ArgListOwner { 1099 struct MethodCallExpr: AttrsOwner, ArgListOwner {
456 Expr, T![.], NameRef, TypeArgList, 1100 Expr, T![.], NameRef, TypeArgList,
457 } 1101 }
1102
1103 /// Index expression a.k.a. subscript operator call.
1104 ///
1105 /// ```
1106 /// ❰ foo[42] ❱;
1107 /// ```
1108 ///
1109 /// [Reference](https://doc.rust-lang.org/reference/expressions/array-expr.html)
458 struct IndexExpr: AttrsOwner { T!['['], T![']'] } 1110 struct IndexExpr: AttrsOwner { T!['['], T![']'] }
1111
1112 /// Field access expression.
1113 ///
1114 /// ```
1115 /// ❰ expr.bar ❱;
1116 ///
1117 /// ❰ ❰ ❰ foo.bar ❱ .baz ❱ .bruh ❱;
1118 /// ```
1119 ///
1120 /// [Reference](https://doc.rust-lang.org/reference/expressions/field-expr.html)
459 struct FieldExpr: AttrsOwner { Expr, T![.], NameRef } 1121 struct FieldExpr: AttrsOwner { Expr, T![.], NameRef }
1122
1123 /// Await operator call expression.
1124 ///
1125 /// ```
1126 /// ❰ expr.await ❱;
1127 /// ```
1128 ///
1129 /// [Reference](https://doc.rust-lang.org/reference/expressions/await-expr.html)
460 struct AwaitExpr: AttrsOwner { Expr, T![.], T![await] } 1130 struct AwaitExpr: AttrsOwner { Expr, T![.], T![await] }
461 struct TryExpr: AttrsOwner { T![try], Expr } 1131
1132 /// The question mark operator call.
1133 ///
1134 /// ```
1135 /// ❰ expr? ❱;
1136 /// ```
1137 ///
1138 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator)
1139 struct TryExpr: AttrsOwner { Expr, T![?] }
1140
1141 /// Type cast expression.
1142 ///
1143 /// ```
1144 /// ❰ expr as T ❱;
1145 /// ```
1146 ///
1147 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions)
462 struct CastExpr: AttrsOwner { Expr, T![as], TypeRef } 1148 struct CastExpr: AttrsOwner { Expr, T![as], TypeRef }
463 struct RefExpr: AttrsOwner { T![&], T![raw], T![mut], Expr } 1149
1150
1151 /// Borrow operator call.
1152 ///
1153 /// ```
1154 /// ❰ &foo ❱;
1155 /// ❰ &mut bar ❱;
1156 /// ❰ &raw const bar ❱;
1157 /// ❰ &raw mut bar ❱;
1158 /// ```
1159 ///
1160 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#borrow-operators)
1161 struct RefExpr: AttrsOwner { T![&], T![raw], T![mut], T![const], Expr }
1162
1163 /// Prefix operator call. This is either `!` or `*` or `-`.
1164 ///
1165 /// ```
1166 /// ❰ !foo ❱;
1167 /// ❰ *bar ❱;
1168 /// ❰ -42 ❱;
1169 /// ```
1170 ///
1171 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html)
464 struct PrefixExpr: AttrsOwner { /*PrefixOp,*/ Expr } 1172 struct PrefixExpr: AttrsOwner { /*PrefixOp,*/ Expr }
1173
1174 /// Box operator call.
1175 ///
1176 /// ```
1177 /// ❰ box 42 ❱;
1178 /// ```
1179 ///
1180 /// [RFC](https://github.com/rust-lang/rfcs/blob/0806be4f282144cfcd55b1d20284b43f87cbe1c6/text/0809-box-and-in-for-stdlib.md)
465 struct BoxExpr: AttrsOwner { T![box], Expr } 1181 struct BoxExpr: AttrsOwner { T![box], Expr }
1182
1183 /// Range operator call.
1184 ///
1185 /// ```
1186 /// ❰ 0..42 ❱;
1187 /// ❰ ..42 ❱;
1188 /// ❰ 0.. ❱;
1189 /// ❰ .. ❱;
1190 /// ❰ 0..=42 ❱;
1191 /// ❰ ..=42 ❱;
1192 /// ```
1193 ///
1194 /// [Reference](https://doc.rust-lang.org/reference/expressions/range-expr.html)
466 struct RangeExpr: AttrsOwner { /*RangeOp*/ } 1195 struct RangeExpr: AttrsOwner { /*RangeOp*/ }
1196
1197
1198 /// Binary operator call.
1199 /// Includes all arithmetic, logic, bitwise and assignment operators.
1200 ///
1201 /// ```
1202 /// ❰ 2 + ❰ 2 * 2 ❱ ❱;
1203 /// ❰ ❰ true && false ❱ || true ❱;
1204 /// ```
1205 ///
1206 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators)
467 struct BinExpr: AttrsOwner { /*BinOp*/ } 1207 struct BinExpr: AttrsOwner { /*BinOp*/ }
1208
1209
1210 /// [Raw] string, [raw] byte string, char, byte, integer, float or bool literal.
1211 ///
1212 /// ```
1213 /// ❰ "str" ❱;
1214 /// ❰ br##"raw byte str"## ❱;
1215 /// ❰ 'c' ❱;
1216 /// ❰ b'c' ❱;
1217 /// ❰ 42 ❱;
1218 /// ❰ 1e9 ❱;
1219 /// ❰ true ❱;
1220 /// ```
1221 ///
1222 /// [Reference](https://doc.rust-lang.org/reference/expressions/literal-expr.html)
468 struct Literal { /*LiteralToken*/ } 1223 struct Literal { /*LiteralToken*/ }
469 1224
1225 /// Match expression.
1226 ///
1227 /// ```
1228 /// ❰
1229 /// match expr {
1230 /// Pat1 => {}
1231 /// Pat2(_) => 42,
1232 /// }
1233 /// ❱
1234 /// ```
1235 ///
1236 /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html)
470 struct MatchExpr: AttrsOwner { T![match], Expr, MatchArmList } 1237 struct MatchExpr: AttrsOwner { T![match], Expr, MatchArmList }
1238
1239 /// Match arm list part of match expression. Includes its inner attributes.
1240 ///
1241 /// ```
1242 /// match expr
1243 /// ❰
1244 /// {
1245 /// #![inner_attr]
1246 /// Pat1 => {}
1247 /// Pat2(_) => 42,
1248 /// }
1249 /// ❱
1250 /// ```
1251 ///
1252 /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html)
471 struct MatchArmList: AttrsOwner { T!['{'], arms: [MatchArm], T!['}'] } 1253 struct MatchArmList: AttrsOwner { T!['{'], arms: [MatchArm], T!['}'] }
1254
1255
1256 /// Match arm.
1257 /// Note: record struct literals are not valid as target match expression
1258 /// due to ambiguity.
1259 /// ```
1260 /// match expr {
1261 /// ❰ #[attr] Pattern(it) if bool_cond => it ❱,
1262 /// }
1263 /// ```
1264 ///
1265 /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html)
472 struct MatchArm: AttrsOwner { 1266 struct MatchArm: AttrsOwner {
473 pat: Pat, 1267 pat: Pat,
474 guard: MatchGuard, 1268 guard: MatchGuard,
475 T![=>], 1269 T![=>],
476 Expr, 1270 Expr,
477 } 1271 }
1272
1273 /// Match guard.
1274 ///
1275 /// ```
1276 /// match expr {
1277 /// Pattern(it) ❰ if bool_cond ❱ => it,
1278 /// }
1279 /// ```
1280 ///
1281 /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards)
478 struct MatchGuard { T![if], Expr } 1282 struct MatchGuard { T![if], Expr }
479 1283
1284 /// Record literal expression. The same syntax is used for structs,
1285 /// unions and record enum variants.
1286 ///
1287 /// ```
1288 /// ❰
1289 /// foo::Bar {
1290 /// #![inner_attr]
1291 /// baz: 42,
1292 /// bruh: true,
1293 /// ..spread
1294 /// }
1295 /// ❱
1296 /// ```
1297 ///
1298 /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html)
480 struct RecordLit { Path, RecordFieldList} 1299 struct RecordLit { Path, RecordFieldList}
1300
1301 /// Record field list including enclosing curly braces.
1302 ///
1303 /// foo::Bar ❰
1304 /// {
1305 /// baz: 42,
1306 /// ..spread
1307 /// }
1308 /// ❱
1309 ///
1310 /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html)
481 struct RecordFieldList { 1311 struct RecordFieldList {
482 T!['{'], 1312 T!['{'],
483 fields: [RecordField], 1313 fields: [RecordField],
@@ -485,22 +1315,162 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
485 spread: Expr, 1315 spread: Expr,
486 T!['}'] 1316 T!['}']
487 } 1317 }
1318
1319 /// Record field.
1320 ///
1321 /// ```
1322 /// foo::Bar {
1323 /// ❰ #[attr] baz: 42 ❱
1324 /// }
1325 /// ```
1326 ///
1327 /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html)
488 struct RecordField: AttrsOwner { NameRef, T![:], Expr } 1328 struct RecordField: AttrsOwner { NameRef, T![:], Expr }
489 1329
1330 /// Disjunction of patterns.
1331 ///
1332 /// ```
1333 /// let ❰ Foo(it) | Bar(it) | Baz(it) ❱ = bruh;
1334 /// ```
1335 ///
1336 /// [Reference](https://doc.rust-lang.org/reference/patterns.html)
490 struct OrPat { pats: [Pat] } 1337 struct OrPat { pats: [Pat] }
1338
1339 /// Parenthesized pattern.
1340 /// Note: parens are only used for grouping, this is not a tuple pattern.
1341 ///
1342 /// ```
1343 /// if let ❰ &(0..=42) ❱ = foo {}
1344 /// ```
1345 ///
1346 /// https://doc.rust-lang.org/reference/patterns.html#grouped-patterns
491 struct ParenPat { T!['('], Pat, T![')'] } 1347 struct ParenPat { T!['('], Pat, T![')'] }
1348
1349 /// Reference pattern.
1350 /// Note: this has nothing to do with `ref` keyword, the latter is used in bind patterns.
1351 ///
1352 /// ```
1353 /// let ❰ &mut foo ❱ = bar;
1354 ///
1355 /// let ❰ & ❰ &mut ❰ &_ ❱ ❱ ❱ = baz;
1356 /// ```
1357 ///
1358 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#reference-patterns)
492 struct RefPat { T![&], T![mut], Pat } 1359 struct RefPat { T![&], T![mut], Pat }
1360
1361 /// Box pattern.
1362 ///
1363 /// ```
1364 /// let ❰ box foo ❱ = box 42;
1365 /// ```
1366 ///
1367 /// [Unstable book](https://doc.rust-lang.org/unstable-book/language-features/box-patterns.html)
493 struct BoxPat { T![box], Pat } 1368 struct BoxPat { T![box], Pat }
1369
1370 /// Bind pattern.
1371 ///
1372 /// ```
1373 /// match foo {
1374 /// Some(❰ ref mut bar ❱) => {}
1375 /// ❰ baz @ None ❱ => {}
1376 /// }
1377 /// ```
1378 ///
1379 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#identifier-patterns)
494 struct BindPat: AttrsOwner, NameOwner { T![ref], T![mut], T![@], Pat } 1380 struct BindPat: AttrsOwner, NameOwner { T![ref], T![mut], T![@], Pat }
1381
1382 /// Placeholder pattern a.k.a. the wildcard pattern or the underscore.
1383 ///
1384 /// ```
1385 /// let ❰ _ ❱ = foo;
1386 /// ```
1387 ///
1388 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#wildcard-pattern)
495 struct PlaceholderPat { T![_] } 1389 struct PlaceholderPat { T![_] }
1390
1391 /// Rest-of-the record/tuple pattern.
1392 /// Note: this is not the unbonded range pattern (even more: it doesn't exist).
1393 ///
1394 /// ```
1395 /// let Foo { bar, ❰ .. ❱ } = baz;
1396 /// let (❰ .. ❱, bruh) = (42, 24, 42);
1397 /// let Bruuh(❰ .. ❱) = bruuuh;
1398 /// ```
1399 ///
1400 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
496 struct DotDotPat { T![..] } 1401 struct DotDotPat { T![..] }
1402
1403 /// Path pattern.
1404 /// Doesn't include the underscore pattern (it is a special case, namely `PlaceholderPat`).
1405 ///
1406 /// ```
1407 /// let ❰ foo::bar::Baz ❱ { .. } = bruh;
1408 /// if let ❰ CONST ❱ = 42 {}
1409 /// ```
1410 ///
1411 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#path-patterns)
497 struct PathPat { Path } 1412 struct PathPat { Path }
1413
1414 /// Slice pattern.
1415 ///
1416 /// ```
1417 /// let ❰ [foo, bar, baz] ❱ = [1, 2, 3];
1418 /// ```
1419 ///
1420 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#slice-patterns)
498 struct SlicePat { T!['['], args: [Pat], T![']'] } 1421 struct SlicePat { T!['['], args: [Pat], T![']'] }
499 struct RangePat { /*RangeSeparator*/ } 1422
1423 /// Range pattern.
1424 ///
1425 /// ```
1426 /// match foo {
1427 /// ❰ 0..42 ❱ => {}
1428 /// ❰ 0..=42 ❱ => {}
1429 /// }
1430 /// ```
1431 ///
1432 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#range-patterns)
1433 struct RangePat { } // FIXME(@matklad): here should be T![..], T![..=] I think, if we don't already have an accessor in expresions_ext
1434
1435 /// Literal pattern.
1436 /// Includes only bool, number, char, and string literals.
1437 ///
1438 /// ```
1439 /// match foo {
1440 /// Number(❰ 42 ❱) => {}
1441 /// String(❰ "42" ❱) => {}
1442 /// Bool(❰ true ❱) => {}
1443 /// }
1444 /// ```
1445 ///
1446 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#literal-patterns)
500 struct LiteralPat { Literal } 1447 struct LiteralPat { Literal }
1448
1449 /// Macro invocation in pattern position.
1450 ///
1451 /// ```
1452 /// let ❰ foo!(my custom syntax) ❱ = baz;
1453 ///
1454 /// ```
1455 /// [Reference](https://doc.rust-lang.org/reference/macros.html#macro-invocation)
501 struct MacroPat { MacroCall } 1456 struct MacroPat { MacroCall }
502 1457
1458 /// Record literal pattern.
1459 ///
1460 /// ```
1461 /// let ❰ foo::Bar { baz, .. } ❱ = bruh;
1462 /// ```
1463 ///
1464 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
503 struct RecordPat { RecordFieldPatList, Path } 1465 struct RecordPat { RecordFieldPatList, Path }
1466
1467 /// Record literal's field patterns list including enclosing curly braces.
1468 ///
1469 /// ```
1470 /// let foo::Bar ❰ { baz, bind @ bruh, .. } ❱ = bruuh;
1471 /// ``
1472 ///
1473 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
504 struct RecordFieldPatList { 1474 struct RecordFieldPatList {
505 T!['{'], 1475 T!['{'],
506 pats: [RecordInnerPat], 1476 pats: [RecordInnerPat],
@@ -509,20 +1479,148 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
509 T![..], 1479 T![..],
510 T!['}'] 1480 T!['}']
511 } 1481 }
1482
1483 /// Record literal's field pattern.
1484 /// Note: record literal can also match tuple structs.
1485 ///
1486 /// ```
1487 /// let Foo { ❰ bar: _ ❱ } = baz;
1488 /// let TupleStruct { ❰ 0: _ ❱ } = bruh;
1489 /// ```
1490 ///
1491 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
512 struct RecordFieldPat: AttrsOwner { NameRef, T![:], Pat } 1492 struct RecordFieldPat: AttrsOwner { NameRef, T![:], Pat }
513 1493
1494 /// Tuple struct literal pattern.
1495 ///
1496 /// ```
1497 /// let ❰ foo::Bar(baz, bruh) ❱ = bruuh;
1498 /// ```
1499 ///
1500 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#tuple-struct-patterns)
514 struct TupleStructPat { Path, T!['('], args: [Pat], T![')'] } 1501 struct TupleStructPat { Path, T!['('], args: [Pat], T![')'] }
1502
1503 /// Tuple pattern.
1504 /// Note: this doesn't include tuple structs (see `TupleStructPat`)
1505 ///
1506 /// ```
1507 /// let ❰ (foo, bar, .., baz) ❱ = bruh;
1508 /// ```
1509 ///
1510 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#tuple-patterns)
515 struct TuplePat { T!['('], args: [Pat], T![')'] } 1511 struct TuplePat { T!['('], args: [Pat], T![')'] }
516 1512
1513 /// Visibility.
1514 ///
1515 /// ```
1516 /// ❰ pub mod ❱ foo;
1517 /// ❰ pub(crate) ❱ struct Bar;
1518 /// ❰ pub(self) ❱ enum Baz {}
1519 /// ❰ pub(super) ❱ fn bruh() {}
1520 /// ❰ pub(in bruuh::bruuuh) ❱ type T = u64;
1521 /// ```
1522 ///
1523 /// [Reference](https://doc.rust-lang.org/reference/visibility-and-privacy.html)
517 struct Visibility { T![pub], T![super], T![self], T![crate] } 1524 struct Visibility { T![pub], T![super], T![self], T![crate] }
1525
1526 /// Single identifier.
1527 /// Note(@matklad): `Name` is for things that install a new name into the scope,
1528 /// `NameRef` is a usage of a name. Most of the time, this definition/reference
1529 /// distinction can be determined purely syntactically, ie in
1530 /// ```
1531 /// fn foo() { foo() }
1532 /// ```
1533 /// the first foo is `Name`, the second one is `NameRef`.
1534 /// The notable exception are patterns, where in
1535 /// ``
1536 /// let x = 92
1537 /// ```
1538 /// `x` can be semantically either a name or a name ref, depeding on
1539 /// wether there's an `x` constant in scope.
1540 /// We use `Name` for patterns, and disambiguate semantically (see `NameClass` in ide_db).
1541 ///
1542 /// ```
1543 /// let ❰ foo ❱ = bar;
1544 /// struct ❰ Baz ❱;
1545 /// fn ❰ bruh ❱() {}
1546 /// ```
1547 ///
1548 /// [Reference](https://doc.rust-lang.org/reference/identifiers.html)
518 struct Name { T![ident] } 1549 struct Name { T![ident] }
519 struct NameRef { /*NameRefToken*/ }
520 1550
521 struct MacroCall: NameOwner, AttrsOwner,DocCommentsOwner { 1551 /// Reference to a name.
1552 /// See the explanation on the difference between `Name` and `NameRef`
1553 /// in `Name` ast node docs.
1554 ///
1555 /// ```
1556 /// let foo = ❰ bar ❱(❰ Baz(❰ bruh ❱) ❱;
1557 /// ```
1558 ///
1559 /// [Reference](https://doc.rust-lang.org/reference/identifiers.html)
1560 struct NameRef { }
1561
1562 /// Macro call.
1563 /// Includes all of its attributes and doc comments.
1564 ///
1565 /// ```
1566 /// ❰
1567 /// /// Docs
1568 /// #[attr]
1569 /// macro_rules! foo { // macro rules is also a macro call
1570 /// ($bar: tt) => {}
1571 /// }
1572 /// ❱
1573 ///
1574 /// // semicolon is a part of `MacroCall` when it is used in item positions
1575 /// ❰ foo!(); ❱
1576 ///
1577 /// fn main() {
1578 /// ❰ foo!() ❱; // macro call in expression positions doesn't include the semi
1579 /// }
1580 /// ```
1581 ///
1582 /// [Reference](https://doc.rust-lang.org/reference/macros.html)
1583 struct MacroCall: NameOwner, AttrsOwner, DocCommentsOwner {
522 Path, T![!], TokenTree, T![;] 1584 Path, T![!], TokenTree, T![;]
523 } 1585 }
1586
1587 /// Attribute.
1588 ///
1589 /// ```
1590 /// ❰ #![inner_attr] ❱
1591 ///
1592 /// ❰ #[attr] ❱
1593 /// ❰ #[foo = "bar"] ❱
1594 /// ❰ #[baz(bruh::bruuh = "42")] ❱
1595 /// struct Foo;
1596 /// ```
1597 ///
1598 /// [Reference](https://doc.rust-lang.org/reference/attributes.html)
524 struct Attr { T![#], T![!], T!['['], Path, T![=], input: AttrInput, T![']'] } 1599 struct Attr { T![#], T![!], T!['['], Path, T![=], input: AttrInput, T![']'] }
1600
1601 /// Stores a list of lexer tokens and other `TokenTree`s.
1602 /// It appears in attributes, macro_rules and macro call (foo!)
1603 ///
1604 /// ```
1605 /// macro_call! ❰ { my syntax here } ❱;
1606 /// ```
1607 ///
1608 /// [Reference](https://doc.rust-lang.org/reference/macros.html)
525 struct TokenTree {} 1609 struct TokenTree {}
1610
1611 /// Generic lifetime, type and constants parameters list **declaration**.
1612 ///
1613 /// ```
1614 /// fn foo❰ <'a, 'b, T, U, const BAR: u64> ❱() {}
1615 ///
1616 /// struct Baz❰ <T> ❱(T);
1617 ///
1618 /// impl❰ <T> ❱ Bruh<T> {}
1619 ///
1620 /// type Bruuh = for❰ <'a> ❱ fn(&'a str) -> &'a str;
1621 /// ```
1622 ///
1623 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html)
526 struct TypeParamList { 1624 struct TypeParamList {
527 T![<], 1625 T![<],
528 generic_params: [GenericParam], 1626 generic_params: [GenericParam],
@@ -531,21 +1629,141 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
531 const_params: [ConstParam], 1629 const_params: [ConstParam],
532 T![>] 1630 T![>]
533 } 1631 }
1632
1633 /// Single type parameter **declaration**.
1634 ///
1635 /// ```
1636 /// fn foo<❰ K ❱, ❰ I ❱, ❰ E: Debug ❱, ❰ V = DefaultType ❱>() {}
1637 /// ```
1638 ///
1639 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html)
534 struct TypeParam: NameOwner, AttrsOwner, TypeBoundsOwner { 1640 struct TypeParam: NameOwner, AttrsOwner, TypeBoundsOwner {
535 T![=], 1641 T![=],
536 default_type: TypeRef, 1642 default_type: TypeRef,
537 } 1643 }
1644
1645 /// Const generic parameter **declaration**.
1646 /// ```
1647 /// fn foo<T, U, ❰ const BAR: usize ❱, ❰ const BAZ: bool ❱>() {}
1648 /// ```
1649 ///
1650 /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md#declaring-a-const-parameter)
538 struct ConstParam: NameOwner, AttrsOwner, TypeAscriptionOwner { 1651 struct ConstParam: NameOwner, AttrsOwner, TypeAscriptionOwner {
539 T![=], 1652 T![=],
540 default_val: Expr, 1653 default_val: Expr,
541 } 1654 }
1655
1656 /// Lifetime parameter **declaration**.
1657 ///
1658 /// ```
1659 /// fn foo<❰ 'a ❱, ❰ 'b ❱, V, G, D>(bar: &'a str, baz: &'b mut str) {}
1660 /// ```
1661 ///
1662 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html)
542 struct LifetimeParam: AttrsOwner { T![lifetime] } 1663 struct LifetimeParam: AttrsOwner { T![lifetime] }
543 struct TypeBound { T![lifetime], /* Question, */ T![const], /* Question, */ TypeRef} 1664
1665 /// Type bound declaration clause.
1666 ///
1667 /// ```
1668 /// fn foo<T: ❰ ?Sized ❱ + ❰ Debug ❱>() {}
1669 ///
1670 /// trait Bar<T>
1671 /// where
1672 /// T: ❰ Send ❱ + ❰ Sync ❱
1673 /// {
1674 /// type Baz: ❰ !Sync ❱ + ❰ Debug ❱ + ❰ ?const Add ❱;
1675 /// }
1676 /// ```
1677 ///
1678 /// [Reference](https://doc.rust-lang.org/reference/trait-bounds.html)
1679 struct TypeBound { T![lifetime], /* Question, */ T![const], /* Question, */ TypeRef }
1680
1681 /// Type bounds list.
1682 ///
1683 /// ```
1684 ///
1685 /// fn foo<T: ❰ ?Sized + Debug ❱>() {}
1686 ///
1687 /// trait Bar<T>
1688 /// where
1689 /// T: ❰ Send + Sync ❱
1690 /// {
1691 /// type Baz: ❰ !Sync + Debug ❱;
1692 /// }
1693 /// ```
1694 ///
1695 /// [Reference](https://doc.rust-lang.org/reference/trait-bounds.html)
544 struct TypeBoundList { bounds: [TypeBound] } 1696 struct TypeBoundList { bounds: [TypeBound] }
1697
1698 /// Single where predicate.
1699 ///
1700 /// ```
1701 /// trait Foo<'a, 'b, T>
1702 /// where
1703 /// ❰ 'a: 'b ❱,
1704 /// ❰ T: IntoIterator ❱,
1705 /// ❰ for<'c> <T as IntoIterator>::Item: Bar<'c> ❱
1706 /// {}
1707 /// ```
1708 ///
1709 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html#where-clauses)
545 struct WherePred: TypeBoundsOwner { T![lifetime], TypeRef } 1710 struct WherePred: TypeBoundsOwner { T![lifetime], TypeRef }
1711
1712 /// Where clause.
1713 ///
1714 /// ```
1715 /// trait Foo<'a, T> ❰ where 'a: 'static, T: Debug ❱ {}
1716 ///
1717 /// ```
1718 ///
1719 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html#where-clauses)
546 struct WhereClause { T![where], predicates: [WherePred] } 1720 struct WhereClause { T![where], predicates: [WherePred] }
1721
1722 /// Abi declaration.
1723 /// Note: the abi string is optional.
1724 ///
1725 /// ```
1726 /// ❰ extern "C" ❱ {
1727 /// fn foo() {}
1728 /// }
1729 ///
1730 /// type Bar = ❰ extern ❱ fn() -> u32;
1731 ///
1732 /// type Baz = ❰ extern r#"stdcall"# ❱ fn() -> bool;
1733 /// ```
1734 ///
1735 /// - [Extern blocks reference](https://doc.rust-lang.org/reference/items/external-blocks.html)
1736 /// - [FFI function pointers reference](https://doc.rust-lang.org/reference/items/functions.html#functions)
547 struct Abi { /*String*/ } 1737 struct Abi { /*String*/ }
1738
1739 /// Expression statement.
1740 ///
1741 /// ```
1742 /// ❰ 42; ❱
1743 /// ❰ foo(); ❱
1744 /// ❰ (); ❱
1745 /// ❰ {}; ❱
1746 ///
1747 /// // constructions with trailing curly brace can omit the semicolon
1748 /// // but only when there are satements immediately after them (this is important!)
1749 /// ❰ if bool_cond { } ❱
1750 /// ❰ loop {} ❱
1751 /// ❰ somestatment; ❱
1752 /// ```
1753 ///
1754 /// [Reference](https://doc.rust-lang.org/reference/statements.html)
548 struct ExprStmt: AttrsOwner { Expr, T![;] } 1755 struct ExprStmt: AttrsOwner { Expr, T![;] }
1756
1757 /// Let statement.
1758 ///
1759 /// ```
1760 /// ❰ #[attr] let foo; ❱
1761 /// ❰ let bar: u64; ❱
1762 /// ❰ let baz = 42; ❱
1763 /// ❰ let bruh: bool = true; ❱
1764 /// ```
1765 ///
1766 /// [Reference](https://doc.rust-lang.org/reference/statements.html#let-statements)
549 struct LetStmt: AttrsOwner, TypeAscriptionOwner { 1767 struct LetStmt: AttrsOwner, TypeAscriptionOwner {
550 T![let], 1768 T![let],
551 Pat, 1769 Pat,
@@ -553,48 +1771,192 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
553 initializer: Expr, 1771 initializer: Expr,
554 T![;], 1772 T![;],
555 } 1773 }
1774
1775 /// Condition of `if` or `while` expression.
1776 ///
1777 /// ```
1778 /// if ❰ true ❱ {}
1779 /// if ❰ let Pat(foo) = bar ❱ {}
1780 ///
1781 /// while ❰ true ❱ {}
1782 /// while ❰ let Pat(baz) = bruh ❱ {}
1783 /// ```
1784 ///
1785 /// [If expression reference](https://doc.rust-lang.org/reference/expressions/if-expr.html)
1786 /// [While expression reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-loops)
556 struct Condition { T![let], Pat, T![=], Expr } 1787 struct Condition { T![let], Pat, T![=], Expr }
557 struct Block: AttrsOwner, ModuleItemOwner { 1788
558 T!['{'], 1789 /// Parameter list **declaration**.
559 statements: [Stmt], 1790 ///
560 Expr, 1791 /// ```
561 T!['}'], 1792 /// fn foo❰ (a: u32, b: bool) ❱ -> u32 {}
562 } 1793 /// let bar = ❰ |a, b| ❱ {};
563 struct ParamList { 1794 ///
1795 /// impl Baz {
1796 /// fn bruh❰ (&self, a: u32) ❱ {}
1797 /// }
1798 /// ```
1799 ///
1800 /// [Reference](https://doc.rust-lang.org/reference/items/functions.html)ocs to codegen script
1801 struct ParamList { // FIXME: this node is used by closure expressions too, but hey use pipes instead of parens...
564 T!['('], 1802 T!['('],
565 SelfParam, 1803 SelfParam,
566 params: [Param], 1804 params: [Param],
567 T![')'] 1805 T![')']
568 } 1806 }
1807
1808 /// Self parameter **declaration**.
1809 ///
1810 /// ```
1811 /// impl Bruh {
1812 /// fn foo(❰ self ❱) {}
1813 /// fn bar(❰ &self ❱) {}
1814 /// fn baz(❰ &mut self ❱) {}
1815 /// fn blah<'a>(❰ &'a self ❱) {}
1816 /// fn blin(❰ self: Box<Self> ❱) {}
1817 /// }
1818 /// ```
1819 ///
1820 /// [Reference](https://doc.rust-lang.org/reference/items/functions.html)
569 struct SelfParam: TypeAscriptionOwner, AttrsOwner { T![&], T![mut], T![lifetime], T![self] } 1821 struct SelfParam: TypeAscriptionOwner, AttrsOwner { T![&], T![mut], T![lifetime], T![self] }
1822
1823 /// Parameter **declaration**.
1824 ///
1825 /// ```
1826 /// fn foo(❰ #[attr] Pat(bar): Pat(u32) ❱, ❰ #[attr] _: bool ❱) {}
1827 ///
1828 /// extern "C" {
1829 /// fn bar(❰ baz: u32 ❱, ❰ ... ❱) -> u32;
1830 /// }
1831 /// ```
1832 ///
1833 /// [Reference](https://doc.rust-lang.org/reference/items/functions.html)
570 struct Param: TypeAscriptionOwner, AttrsOwner { 1834 struct Param: TypeAscriptionOwner, AttrsOwner {
571 Pat, 1835 Pat,
572 T![...] 1836 T![...]
573 } 1837 }
1838
1839 /// Use declaration.
1840 ///
1841 /// ```
1842 /// ❰ #[attr] pub use foo; ❱
1843 /// ❰ use bar as baz; ❱
1844 /// ❰ use bruh::{self, bruuh}; ❱
1845 /// ❰ use { blin::blen, blah::* };
1846 /// ```
1847 ///
1848 /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
574 struct UseItem: AttrsOwner, VisibilityOwner { 1849 struct UseItem: AttrsOwner, VisibilityOwner {
575 T![use], 1850 T![use],
576 UseTree, 1851 UseTree,
577 } 1852 }
1853
1854 /// Use tree.
1855 ///
1856 /// ```
1857 /// pub use ❰ foo::❰ * ❱ ❱;
1858 /// use ❰ bar as baz ❱;
1859 /// use ❰ bruh::bruuh::{ ❰ self ❱, ❰ blin ❱ } ❱;
1860 /// use ❰ { ❰ blin::blen ❱ } ❱
1861 /// ```
1862 ///
1863 /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
578 struct UseTree { 1864 struct UseTree {
579 Path, T![*], UseTreeList, Alias 1865 Path, T![*], UseTreeList, Alias
580 } 1866 }
1867
1868 /// Item alias.
1869 /// Note: this is not the type alias.
1870 ///
1871 /// ```
1872 /// use foo ❰ as bar ❱;
1873 /// use baz::{bruh ❰ as _ ❱};
1874 /// extern crate bruuh ❰ as blin ❱;
1875 /// ```
1876 ///
1877 /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
581 struct Alias: NameOwner { T![as] } 1878 struct Alias: NameOwner { T![as] }
1879
1880 /// Sublist of use trees.
1881 ///
1882 /// ```
1883 /// use bruh::bruuh::❰ { ❰ self ❱, ❰ blin ❱ } ❱;
1884 /// use ❰ { blin::blen::❰ {} ❱ } ❱
1885 /// ```
1886 ///
1887 /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
582 struct UseTreeList { T!['{'], use_trees: [UseTree], T!['}'] } 1888 struct UseTreeList { T!['{'], use_trees: [UseTree], T!['}'] }
1889
1890 /// Extern crate item.
1891 ///
1892 /// ```
1893 /// ❰ #[attr] pub extern crate foo; ❱
1894 /// ❰ extern crate self as bar; ❱
1895 /// ```
1896 ///
1897 /// [Reference](https://doc.rust-lang.org/reference/items/extern-crates.html)
583 struct ExternCrateItem: AttrsOwner, VisibilityOwner { 1898 struct ExternCrateItem: AttrsOwner, VisibilityOwner {
584 T![extern], T![crate], NameRef, Alias, 1899 T![extern], T![crate], NameRef, Alias,
585 } 1900 }
1901
1902 /// Call site arguments list.
1903 ///
1904 /// ```
1905 /// foo::<T, U>❰ (42, true) ❱;
1906 /// ```
1907 ///
1908 /// [Reference](https://doc.rust-lang.org/reference/expressions/call-expr.html)
586 struct ArgList { 1909 struct ArgList {
587 T!['('], 1910 T!['('],
588 args: [Expr], 1911 args: [Expr],
589 T![')'] 1912 T![')']
590 } 1913 }
1914
1915 /// Path to a symbol. Includes single identifier names and elaborate paths with
1916 /// generic parameters.
1917 ///
1918 /// ```
1919 /// (0..10).❰ ❰ collect ❱ ::<Vec<_>> ❱();
1920 /// ❰ ❰ ❰ Vec ❱ ::<u8> ❱ ::with_capacity ❱(1024);
1921 /// ❰ ❰ <❰ Foo ❱ as ❰ ❰ bar ❱ ::Bar ❱> ❱ ::baz ❱();
1922 /// ❰ ❰ <❰ bruh ❱> ❱ ::bruuh ❱();
1923 /// ```
1924 ///
1925 /// [Reference](https://doc.rust-lang.org/reference/paths.html)
591 struct Path { 1926 struct Path {
592 segment: PathSegment, 1927 segment: PathSegment,
1928 T![::],
593 qualifier: Path, 1929 qualifier: Path,
594 } 1930 }
1931
1932 /// Segment of the path to a symbol.
1933 /// Only path segment of an absolute path holds the `::` token,
1934 /// all other `::` tokens that connect path segments reside under `Path` itself.`
1935 ///
1936 /// ```
1937 /// (0..10).❰ collect ❱ :: ❰ <Vec<_>> ❱();
1938 /// ❰ Vec ❱ :: ❰ <u8> ❱ :: ❰ with_capacity ❱(1024);
1939 /// ❰ <❰ Foo ❱ as ❰ bar ❱ :: ❰ Bar ❱> ❱ :: ❰ baz ❱();
1940 /// ❰ <❰ bruh ❱> ❱ :: ❰ bruuh ❱();
1941 ///
1942 /// // Note that only in this case `::` token is inlcuded:
1943 /// ❰ ::foo ❱;
1944 /// ```
1945 ///
1946 /// [Reference](https://doc.rust-lang.org/reference/paths.html)
595 struct PathSegment { 1947 struct PathSegment {
596 T![::], T![crate], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>] 1948 T![::], T![crate], T![self], T![super], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>]
597 } 1949 }
1950
1951 /// List of type arguments that are passed at generic instantiation site.
1952 ///
1953 /// ```
1954 /// type _ = Foo ❰ ::<'a, u64, Item = Bar, 42, {true}> ❱::Bar;
1955 ///
1956 /// Vec❰ ::<bool> ❱::();
1957 /// ```
1958 ///
1959 /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions)
598 struct TypeArgList { 1960 struct TypeArgList {
599 T![::], 1961 T![::],
600 T![<], 1962 T![<],
@@ -605,48 +1967,142 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
605 const_args: [ConstArg], 1967 const_args: [ConstArg],
606 T![>] 1968 T![>]
607 } 1969 }
1970
1971 /// Type argument that is passed at generic instantiation site.
1972 ///
1973 /// ```
1974 /// type _ = Foo::<'a, ❰ u64 ❱, ❰ bool ❱, Item = Bar, 42>::Baz;
1975 /// ```
1976 ///
1977 /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions)
608 struct TypeArg { TypeRef } 1978 struct TypeArg { TypeRef }
1979
1980 /// Associated type argument that is passed at generic instantiation site.
1981 /// ```
1982 /// type Foo = Bar::<'a, u64, bool, ❰ Item = Baz ❱, 42>::Bruh;
1983 ///
1984 /// trait Bruh<T>: Iterator<❰ Item: Debug ❱> {}
1985 /// ```
1986 ///
609 struct AssocTypeArg : TypeBoundsOwner { NameRef, T![=], TypeRef } 1987 struct AssocTypeArg : TypeBoundsOwner { NameRef, T![=], TypeRef }
1988
1989 /// Lifetime argument that is passed at generic instantiation site.
1990 ///
1991 /// ```
1992 /// fn foo<'a>(s: &'a str) {
1993 /// bar::<❰ 'a ❱>(s);
1994 /// }
1995 /// ```
1996 ///
1997 /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions)
610 struct LifetimeArg { T![lifetime] } 1998 struct LifetimeArg { T![lifetime] }
611 struct ConstArg { Literal, T![=], BlockExpr }
612 1999
613 struct MacroItems: ModuleItemOwner{ } 2000 /// Constant value argument that is passed at generic instantiation site.
2001 ///
2002 /// ```
2003 /// foo::<u32, ❰ { true } ❱>();
2004 ///
2005 /// bar::<❰ { 2 + 2} ❱>();
2006 /// ```
2007 ///
2008 /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md#declaring-a-const-parameter)
2009 struct ConstArg { Literal, BlockExpr }
2010
2011
2012 /// FIXME: (@edwin0cheng) Remove it to use ItemList instead
2013 /// https://github.com/rust-analyzer/rust-analyzer/pull/4083#discussion_r422666243
2014 ///
2015 /// [Reference](https://doc.rust-lang.org/reference/macros.html)
2016 struct MacroItems: ModuleItemOwner { }
614 2017
2018 /// FIXME: (@edwin0cheng) add some documentation here. As per the writing
2019 /// of this comment this ast node is not used.
2020 ///
2021 /// ```
2022 /// // FIXME: example here
2023 /// ```
2024 ///
2025 /// [Reference](https://doc.rust-lang.org/reference/macros.html)
615 struct MacroStmts { 2026 struct MacroStmts {
616 statements: [Stmt], 2027 statements: [Stmt],
617 Expr, 2028 Expr,
618 } 2029 }
619 2030
2031 /// List of items in an extern block.
2032 ///
2033 /// ```
2034 /// extern "C" ❰
2035 /// {
2036 /// fn foo();
2037 /// static var: u32;
2038 /// }
2039 /// ❱
2040 /// ```
2041 ///
2042 /// [Reference](https://doc.rust-lang.org/reference/items/external-blocks.html)
620 struct ExternItemList: ModuleItemOwner { 2043 struct ExternItemList: ModuleItemOwner {
621 T!['{'], 2044 T!['{'],
622 extern_items: [ExternItem], 2045 extern_items: [ExternItem],
623 T!['}'] 2046 T!['}']
624 } 2047 }
625 2048
2049 /// Extern block.
2050 ///
2051 /// ```
2052 /// ❰
2053 /// extern "C" {
2054 /// fn foo();
2055 /// }
2056 /// ❱
2057 ///
2058 /// ```
2059 ///
2060 /// [Reference](https://doc.rust-lang.org/reference/items/external-blocks.html)
626 struct ExternBlock { 2061 struct ExternBlock {
627 Abi, 2062 Abi,
628 ExternItemList 2063 ExternItemList
629 } 2064 }
630 2065
2066 /// Meta item in an attribute.
2067 ///
2068 /// ```
2069 /// #[❰ bar::baz = "42" ❱]
2070 /// #[❰ bruh(bruuh("true")) ❱]
2071 /// struct Foo;
2072 /// ```
2073 ///
2074 /// [Reference](https://doc.rust-lang.org/reference/attributes.html?highlight=meta,item#meta-item-attribute-syntax)
631 struct MetaItem { 2075 struct MetaItem {
632 Path, T![=], AttrInput, nested_meta_items: [MetaItem] 2076 Path, T![=], AttrInput, nested_meta_items: [MetaItem]
633 } 2077 }
634 2078
2079 /// Macro 2.0 definition.
2080 /// Their syntax is still WIP by rustc team...
2081 /// ```
2082 /// ❰
2083 /// macro foo { }
2084 /// ❱
2085 /// ```
2086 ///
2087 /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/1584-macros.md)
635 struct MacroDef { 2088 struct MacroDef {
636 Name, TokenTree 2089 Name, TokenTree
637 } 2090 }
638 }, 2091 },
639 enums: &ast_enums! { 2092 enums: &ast_enums! {
2093 /// Any kind of nominal type definition.
640 enum NominalDef: NameOwner, TypeParamsOwner, AttrsOwner { 2094 enum NominalDef: NameOwner, TypeParamsOwner, AttrsOwner {
641 StructDef, EnumDef, UnionDef, 2095 StructDef, EnumDef, UnionDef,
642 } 2096 }
643 2097
2098 /// Any kind of **declared** generic parameter
644 enum GenericParam { 2099 enum GenericParam {
645 LifetimeParam, 2100 LifetimeParam,
646 TypeParam, 2101 TypeParam,
647 ConstParam 2102 ConstParam
648 } 2103 }
649 2104
2105 /// Any kind of generic argument passed at instantiation site
650 enum GenericArg { 2106 enum GenericArg {
651 LifetimeArg, 2107 LifetimeArg,
652 TypeArg, 2108 TypeArg,
@@ -654,6 +2110,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
654 AssocTypeArg 2110 AssocTypeArg
655 } 2111 }
656 2112
2113 /// Any kind of construct valid in type context
657 enum TypeRef { 2114 enum TypeRef {
658 ParenType, 2115 ParenType,
659 TupleType, 2116 TupleType,
@@ -670,6 +2127,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
670 DynTraitType, 2127 DynTraitType,
671 } 2128 }
672 2129
2130 /// Any kind of top-level item that may appear in a module
673 enum ModuleItem: NameOwner, AttrsOwner, VisibilityOwner { 2131 enum ModuleItem: NameOwner, AttrsOwner, VisibilityOwner {
674 StructDef, 2132 StructDef,
675 UnionDef, 2133 UnionDef,
@@ -687,16 +2145,23 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
687 ExternBlock 2145 ExternBlock
688 } 2146 }
689 2147
690 /* impl blocks can also contain MacroCall */ 2148
691 enum ImplItem: NameOwner, AttrsOwner { 2149
2150 /// Any kind of item that may appear in an impl block
2151 ///
2152 /// // FIXME: impl blocks can also contain MacroCall
2153 enum AssocItem: NameOwner, AttrsOwner {
692 FnDef, TypeAliasDef, ConstDef 2154 FnDef, TypeAliasDef, ConstDef
693 } 2155 }
694 2156
695 /* extern blocks can also contain MacroCall */ 2157 /// Any kind of item that may appear in an extern block
2158 ///
2159 /// // FIXME: extern blocks can also contain MacroCall
696 enum ExternItem: NameOwner, AttrsOwner, VisibilityOwner { 2160 enum ExternItem: NameOwner, AttrsOwner, VisibilityOwner {
697 FnDef, StaticDef 2161 FnDef, StaticDef
698 } 2162 }
699 2163
2164 /// Any kind of expression
700 enum Expr: AttrsOwner { 2165 enum Expr: AttrsOwner {
701 TupleExpr, 2166 TupleExpr,
702 ArrayExpr, 2167 ArrayExpr,
@@ -720,6 +2185,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
720 FieldExpr, 2185 FieldExpr,
721 AwaitExpr, 2186 AwaitExpr,
722 TryExpr, 2187 TryExpr,
2188 EffectExpr,
723 CastExpr, 2189 CastExpr,
724 RefExpr, 2190 RefExpr,
725 PrefixExpr, 2191 PrefixExpr,
@@ -730,6 +2196,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
730 BoxExpr, 2196 BoxExpr,
731 } 2197 }
732 2198
2199 /// Any kind of pattern
733 enum Pat { 2200 enum Pat {
734 OrPat, 2201 OrPat,
735 ParenPat, 2202 ParenPat,
@@ -748,18 +2215,26 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
748 MacroPat, 2215 MacroPat,
749 } 2216 }
750 2217
2218 /// Any kind of pattern that appears directly inside of the curly
2219 /// braces of a record pattern
751 enum RecordInnerPat { 2220 enum RecordInnerPat {
752 RecordFieldPat, 2221 RecordFieldPat,
753 BindPat 2222 BindPat
754 } 2223 }
755 2224
2225 /// Any kind of input to an attribute
756 enum AttrInput { Literal, TokenTree } 2226 enum AttrInput { Literal, TokenTree }
2227
2228 /// Any kind of statement
2229 /// Note: there are no empty statements, these are just represented as
2230 /// bare semicolons without a dedicated statement ast node.
757 enum Stmt { 2231 enum Stmt {
758 LetStmt, 2232 LetStmt,
759 ExprStmt, 2233 ExprStmt,
760 // macro calls are parsed as expression statements */ 2234 // macro calls are parsed as expression statements
761 } 2235 }
762 2236
2237 /// Any kind of fields list (record or tuple field lists)
763 enum FieldDefList { 2238 enum FieldDefList {
764 RecordFieldDefList, 2239 RecordFieldDefList,
765 TupleFieldDefList, 2240 TupleFieldDefList,
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs
index 0e4dcb95a..5511c01d5 100644
--- a/xtask/src/codegen.rs
+++ b/xtask/src/codegen.rs
@@ -8,14 +8,18 @@
8mod gen_syntax; 8mod gen_syntax;
9mod gen_parser_tests; 9mod gen_parser_tests;
10mod gen_assists_docs; 10mod gen_assists_docs;
11mod gen_feature_docs;
11 12
12use std::{mem, path::Path}; 13use std::{
14 fmt, mem,
15 path::{Path, PathBuf},
16};
13 17
14use crate::{not_bash::fs2, Result}; 18use crate::{not_bash::fs2, project_root, Result};
15 19
16pub use self::{ 20pub use self::{
17 gen_assists_docs::generate_assists_docs, gen_parser_tests::generate_parser_tests, 21 gen_assists_docs::generate_assists_docs, gen_feature_docs::generate_feature_docs,
18 gen_syntax::generate_syntax, 22 gen_parser_tests::generate_parser_tests, gen_syntax::generate_syntax,
19}; 23};
20 24
21const GRAMMAR_DIR: &str = "crates/ra_parser/src/grammar"; 25const GRAMMAR_DIR: &str = "crates/ra_parser/src/grammar";
@@ -27,8 +31,7 @@ const AST_NODES: &str = "crates/ra_syntax/src/ast/generated/nodes.rs";
27const AST_TOKENS: &str = "crates/ra_syntax/src/ast/generated/tokens.rs"; 31const AST_TOKENS: &str = "crates/ra_syntax/src/ast/generated/tokens.rs";
28 32
29const ASSISTS_DIR: &str = "crates/ra_assists/src/handlers"; 33const ASSISTS_DIR: &str = "crates/ra_assists/src/handlers";
30const ASSISTS_TESTS: &str = "crates/ra_assists/src/doc_tests/generated.rs"; 34const ASSISTS_TESTS: &str = "crates/ra_assists/src/tests/generated.rs";
31const ASSISTS_DOCS: &str = "docs/user/assists.md";
32 35
33#[derive(Debug, PartialEq, Eq, Clone, Copy)] 36#[derive(Debug, PartialEq, Eq, Clone, Copy)]
34pub enum Mode { 37pub enum Mode {
@@ -40,7 +43,7 @@ pub enum Mode {
40/// With verify = false, 43/// With verify = false,
41fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { 44fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> {
42 match fs2::read_to_string(path) { 45 match fs2::read_to_string(path) {
43 Ok(ref old_contents) if normalize(old_contents) == normalize(contents) => { 46 Ok(old_contents) if normalize(&old_contents) == normalize(contents) => {
44 return Ok(()); 47 return Ok(());
45 } 48 }
46 _ => (), 49 _ => (),
@@ -58,35 +61,85 @@ fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> {
58} 61}
59 62
60fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> { 63fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> {
61 do_extract_comment_blocks(text, false) 64 do_extract_comment_blocks(text, false).into_iter().map(|(_line, block)| block).collect()
65}
66
67fn extract_comment_blocks_with_empty_lines(tag: &str, text: &str) -> Vec<CommentBlock> {
68 assert!(tag.starts_with(char::is_uppercase));
69 let tag = format!("{}:", tag);
70 let mut res = Vec::new();
71 for (line, mut block) in do_extract_comment_blocks(text, true) {
72 let first = block.remove(0);
73 if first.starts_with(&tag) {
74 let id = first[tag.len()..].trim().to_string();
75 let block = CommentBlock { id, line, contents: block };
76 res.push(block);
77 }
78 }
79 res
62} 80}
63 81
64fn extract_comment_blocks_with_empty_lines(text: &str) -> Vec<Vec<String>> { 82struct CommentBlock {
65 do_extract_comment_blocks(text, true) 83 id: String,
84 line: usize,
85 contents: Vec<String>,
66} 86}
67 87
68fn do_extract_comment_blocks(text: &str, allow_blocks_with_empty_lines: bool) -> Vec<Vec<String>> { 88fn do_extract_comment_blocks(
89 text: &str,
90 allow_blocks_with_empty_lines: bool,
91) -> Vec<(usize, Vec<String>)> {
69 let mut res = Vec::new(); 92 let mut res = Vec::new();
70 93
71 let prefix = "// "; 94 let prefix = "// ";
72 let lines = text.lines().map(str::trim_start); 95 let lines = text.lines().map(str::trim_start);
73 96
74 let mut block = vec![]; 97 let mut block = (0, vec![]);
75 for line in lines { 98 for (line_num, line) in lines.enumerate() {
76 if line == "//" && allow_blocks_with_empty_lines { 99 if line == "//" && allow_blocks_with_empty_lines {
77 block.push(String::new()); 100 block.1.push(String::new());
78 continue; 101 continue;
79 } 102 }
80 103
81 let is_comment = line.starts_with(prefix); 104 let is_comment = line.starts_with(prefix);
82 if is_comment { 105 if is_comment {
83 block.push(line[prefix.len()..].to_string()); 106 block.1.push(line[prefix.len()..].to_string());
84 } else if !block.is_empty() { 107 } else {
85 res.push(mem::replace(&mut block, Vec::new())); 108 if !block.1.is_empty() {
109 res.push(mem::take(&mut block));
110 }
111 block.0 = line_num + 2;
86 } 112 }
87 } 113 }
88 if !block.is_empty() { 114 if !block.1.is_empty() {
89 res.push(mem::replace(&mut block, Vec::new())) 115 res.push(block)
90 } 116 }
91 res 117 res
92} 118}
119
120#[derive(Debug)]
121struct Location {
122 file: PathBuf,
123 line: usize,
124}
125
126impl Location {
127 fn new(file: PathBuf, line: usize) -> Self {
128 Self { file, line }
129 }
130}
131
132impl fmt::Display for Location {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 let path = self.file.strip_prefix(&project_root()).unwrap().display().to_string();
135 let path = path.replace('\\', "/");
136 let name = self.file.file_name().unwrap();
137 write!(
138 f,
139 "https://github.com/rust-analyzer/rust-analyzer/blob/master/{}#L{}[{}]",
140 path,
141 self.line,
142 name.to_str().unwrap()
143 )
144 }
145}
diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs
index 31d606535..6c1be5350 100644
--- a/xtask/src/codegen/gen_assists_docs.rs
+++ b/xtask/src/codegen/gen_assists_docs.rs
@@ -1,114 +1,124 @@
1//! Generates `assists.md` documentation. 1//! Generates `assists.md` documentation.
2 2
3use std::{fs, path::Path}; 3use std::{fmt, fs, path::Path};
4 4
5use crate::{ 5use crate::{
6 codegen::{self, extract_comment_blocks_with_empty_lines, Mode}, 6 codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode},
7 project_root, rust_files, Result, 7 project_root, rust_files, Result,
8}; 8};
9 9
10pub fn generate_assists_docs(mode: Mode) -> Result<()> { 10pub fn generate_assists_docs(mode: Mode) -> Result<()> {
11 let assists = collect_assists()?; 11 let assists = Assist::collect()?;
12 generate_tests(&assists, mode)?; 12 generate_tests(&assists, mode)?;
13 generate_docs(&assists, mode)?; 13
14 let contents = assists.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
15 let contents = contents.trim().to_string() + "\n";
16 let dst = project_root().join("docs/user/generated_assists.adoc");
17 codegen::update(&dst, &contents, mode)?;
18
14 Ok(()) 19 Ok(())
15} 20}
16 21
17#[derive(Debug)] 22#[derive(Debug)]
18struct Assist { 23struct Assist {
19 id: String, 24 id: String,
25 location: Location,
20 doc: String, 26 doc: String,
21 before: String, 27 before: String,
22 after: String, 28 after: String,
23} 29}
24 30
25fn hide_hash_comments(text: &str) -> String { 31impl Assist {
26 text.split('\n') // want final newline 32 fn collect() -> Result<Vec<Assist>> {
27 .filter(|&it| !(it.starts_with("# ") || it == "#")) 33 let mut res = Vec::new();
28 .map(|it| format!("{}\n", it)) 34 for path in rust_files(&project_root().join(codegen::ASSISTS_DIR)) {
29 .collect() 35 collect_file(&mut res, path.as_path())?;
30}
31
32fn reveal_hash_comments(text: &str) -> String {
33 text.split('\n') // want final newline
34 .map(|it| {
35 if it.starts_with("# ") {
36 &it[2..]
37 } else if it == "#" {
38 ""
39 } else {
40 it
41 }
42 })
43 .map(|it| format!("{}\n", it))
44 .collect()
45}
46
47fn collect_assists() -> Result<Vec<Assist>> {
48 let mut res = Vec::new();
49 for path in rust_files(&project_root().join(codegen::ASSISTS_DIR)) {
50 collect_file(&mut res, path.as_path())?;
51 }
52 res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id));
53 return Ok(res);
54
55 fn collect_file(acc: &mut Vec<Assist>, path: &Path) -> Result<()> {
56 let text = fs::read_to_string(path)?;
57 let comment_blocks = extract_comment_blocks_with_empty_lines(&text);
58
59 for block in comment_blocks {
60 // FIXME: doesn't support blank lines yet, need to tweak
61 // `extract_comment_blocks` for that.
62 let mut lines = block.iter();
63 let first_line = lines.next().unwrap();
64 if !first_line.starts_with("Assist: ") {
65 continue;
66 }
67 let id = first_line["Assist: ".len()..].to_string();
68 assert!(
69 id.chars().all(|it| it.is_ascii_lowercase() || it == '_'),
70 "invalid assist id: {:?}",
71 id
72 );
73
74 let doc = take_until(lines.by_ref(), "```").trim().to_string();
75 assert!(
76 doc.chars().next().unwrap().is_ascii_uppercase() && doc.ends_with('.'),
77 "\n\n{}: assist docs should be proper sentences, with capitalization and a full stop at the end.\n\n{}\n\n",
78 id, doc,
79 );
80
81 let before = take_until(lines.by_ref(), "```");
82
83 assert_eq!(lines.next().unwrap().as_str(), "->");
84 assert_eq!(lines.next().unwrap().as_str(), "```");
85 let after = take_until(lines.by_ref(), "```");
86 acc.push(Assist { id, doc, before, after })
87 } 36 }
37 res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id));
38 return Ok(res);
39
40 fn collect_file(acc: &mut Vec<Assist>, path: &Path) -> Result<()> {
41 let text = fs::read_to_string(path)?;
42 let comment_blocks = extract_comment_blocks_with_empty_lines("Assist", &text);
43
44 for block in comment_blocks {
45 // FIXME: doesn't support blank lines yet, need to tweak
46 // `extract_comment_blocks` for that.
47 let id = block.id;
48 assert!(
49 id.chars().all(|it| it.is_ascii_lowercase() || it == '_'),
50 "invalid assist id: {:?}",
51 id
52 );
53 let mut lines = block.contents.iter();
54
55 let doc = take_until(lines.by_ref(), "```").trim().to_string();
56 assert!(
57 doc.chars().next().unwrap().is_ascii_uppercase() && doc.ends_with('.'),
58 "\n\n{}: assist docs should be proper sentences, with capitalization and a full stop at the end.\n\n{}\n\n",
59 id, doc,
60 );
61
62 let before = take_until(lines.by_ref(), "```");
63
64 assert_eq!(lines.next().unwrap().as_str(), "->");
65 assert_eq!(lines.next().unwrap().as_str(), "```");
66 let after = take_until(lines.by_ref(), "```");
67 let location = Location::new(path.to_path_buf(), block.line);
68 acc.push(Assist { id, location, doc, before, after })
69 }
88 70
89 fn take_until<'a>(lines: impl Iterator<Item = &'a String>, marker: &str) -> String { 71 fn take_until<'a>(lines: impl Iterator<Item = &'a String>, marker: &str) -> String {
90 let mut buf = Vec::new(); 72 let mut buf = Vec::new();
91 for line in lines { 73 for line in lines {
92 if line == marker { 74 if line == marker {
93 break; 75 break;
76 }
77 buf.push(line.clone());
94 } 78 }
95 buf.push(line.clone()); 79 buf.join("\n")
96 } 80 }
97 buf.join("\n") 81 Ok(())
98 } 82 }
99 Ok(()) 83 }
84}
85
86impl fmt::Display for Assist {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 let before = self.before.replace("<|>", "┃"); // Unicode pseudo-graphics bar
89 let after = self.after.replace("<|>", "┃");
90 writeln!(
91 f,
92 "[discrete]\n=== `{}`
93**Source:** {}
94
95{}
96
97.Before
98```rust
99{}```
100
101.After
102```rust
103{}```",
104 self.id,
105 self.location,
106 self.doc,
107 hide_hash_comments(&before),
108 hide_hash_comments(&after)
109 )
100 } 110 }
101} 111}
102 112
103fn generate_tests(assists: &[Assist], mode: Mode) -> Result<()> { 113fn generate_tests(assists: &[Assist], mode: Mode) -> Result<()> {
104 let mut buf = String::from("use super::check;\n"); 114 let mut buf = String::from("use super::check_doc_test;\n");
105 115
106 for assist in assists.iter() { 116 for assist in assists.iter() {
107 let test = format!( 117 let test = format!(
108 r######" 118 r######"
109#[test] 119#[test]
110fn doctest_{}() {{ 120fn doctest_{}() {{
111 check( 121 check_doc_test(
112 "{}", 122 "{}",
113r#####" 123r#####"
114{}"#####, r#####" 124{}"#####, r#####"
@@ -127,33 +137,24 @@ r#####"
127 codegen::update(&project_root().join(codegen::ASSISTS_TESTS), &buf, mode) 137 codegen::update(&project_root().join(codegen::ASSISTS_TESTS), &buf, mode)
128} 138}
129 139
130fn generate_docs(assists: &[Assist], mode: Mode) -> Result<()> { 140fn hide_hash_comments(text: &str) -> String {
131 let mut buf = String::from( 141 text.split('\n') // want final newline
132 "# Assists\n\nCursor position or selection is signified by `┃` character.\n\n", 142 .filter(|&it| !(it.starts_with("# ") || it == "#"))
133 ); 143 .map(|it| format!("{}\n", it))
134 144 .collect()
135 for assist in assists { 145}
136 let before = assist.before.replace("<|>", "┃"); // Unicode pseudo-graphics bar
137 let after = assist.after.replace("<|>", "┃");
138 let docs = format!(
139 "
140## `{}`
141
142{}
143
144```rust
145// BEFORE
146{}
147// AFTER
148{}```
149",
150 assist.id,
151 assist.doc,
152 hide_hash_comments(&before),
153 hide_hash_comments(&after)
154 );
155 buf.push_str(&docs);
156 }
157 146
158 codegen::update(&project_root().join(codegen::ASSISTS_DOCS), &buf, mode) 147fn reveal_hash_comments(text: &str) -> String {
148 text.split('\n') // want final newline
149 .map(|it| {
150 if it.starts_with("# ") {
151 &it[2..]
152 } else if it == "#" {
153 ""
154 } else {
155 it
156 }
157 })
158 .map(|it| format!("{}\n", it))
159 .collect()
159} 160}
diff --git a/xtask/src/codegen/gen_feature_docs.rs b/xtask/src/codegen/gen_feature_docs.rs
new file mode 100644
index 000000000..31bc3839d
--- /dev/null
+++ b/xtask/src/codegen/gen_feature_docs.rs
@@ -0,0 +1,75 @@
1//! Generates `assists.md` documentation.
2
3use std::{fmt, fs, path::PathBuf};
4
5use crate::{
6 codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode},
7 project_root, rust_files, Result,
8};
9
10pub fn generate_feature_docs(mode: Mode) -> Result<()> {
11 let features = Feature::collect()?;
12 let contents = features.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
13 let contents = contents.trim().to_string() + "\n";
14 let dst = project_root().join("docs/user/generated_features.adoc");
15 codegen::update(&dst, &contents, mode)?;
16 Ok(())
17}
18
19#[derive(Debug)]
20struct Feature {
21 id: String,
22 location: Location,
23 doc: String,
24}
25
26impl Feature {
27 fn collect() -> Result<Vec<Feature>> {
28 let mut res = Vec::new();
29 for path in rust_files(&project_root()) {
30 collect_file(&mut res, path)?;
31 }
32 res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id));
33 return Ok(res);
34
35 fn collect_file(acc: &mut Vec<Feature>, path: PathBuf) -> Result<()> {
36 let text = fs::read_to_string(&path)?;
37 let comment_blocks = extract_comment_blocks_with_empty_lines("Feature", &text);
38
39 for block in comment_blocks {
40 let id = block.id;
41 assert!(is_valid_feature_name(&id), "invalid feature name: {:?}", id);
42 let doc = block.contents.join("\n");
43 let location = Location::new(path.clone(), block.line);
44 acc.push(Feature { id, location, doc })
45 }
46
47 Ok(())
48 }
49 }
50}
51
52fn is_valid_feature_name(feature: &str) -> bool {
53 'word: for word in feature.split_whitespace() {
54 for &short in ["to", "and"].iter() {
55 if word == short {
56 continue 'word;
57 }
58 }
59 for &short in ["To", "And"].iter() {
60 if word == short {
61 return false;
62 }
63 }
64 if !word.starts_with(char::is_uppercase) {
65 return false;
66 }
67 }
68 true
69}
70
71impl fmt::Display for Feature {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 writeln!(f, "=== {}\n**Source:** {}\n{}", self.id, self.location, self.doc)
74 }
75}
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index e9dc09552..19d5594f5 100644
--- a/xtask/src/codegen/gen_syntax.rs
+++ b/xtask/src/codegen/gen_syntax.rs
@@ -3,7 +3,7 @@
3//! Specifically, it generates the `SyntaxKind` enum and a number of newtype 3//! Specifically, it generates the `SyntaxKind` enum and a number of newtype
4//! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`. 4//! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`.
5 5
6use std::collections::HashSet; 6use std::{collections::HashSet, fmt::Write};
7 7
8use proc_macro2::{Punct, Spacing}; 8use proc_macro2::{Punct, Spacing};
9use quote::{format_ident, quote}; 9use quote::{format_ident, quote};
@@ -102,6 +102,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
102 }); 102 });
103 ( 103 (
104 quote! { 104 quote! {
105 #[pretty_doc_comment_placeholder_workaround]
105 #[derive(Debug, Clone, PartialEq, Eq, Hash)] 106 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
106 pub struct #name { 107 pub struct #name {
107 pub(crate) syntax: SyntaxNode, 108 pub(crate) syntax: SyntaxNode,
@@ -145,6 +146,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
145 146
146 ( 147 (
147 quote! { 148 quote! {
149 #[pretty_doc_comment_placeholder_workaround]
148 #[derive(Debug, Clone, PartialEq, Eq, Hash)] 150 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
149 pub enum #name { 151 pub enum #name {
150 #(#variants(#variants),)* 152 #(#variants(#variants),)*
@@ -230,10 +232,29 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
230 }; 232 };
231 233
232 let ast = ast.to_string().replace("T ! [ ", "T![").replace(" ] )", "])"); 234 let ast = ast.to_string().replace("T ! [ ", "T![").replace(" ] )", "])");
233 let pretty = crate::reformat(ast)?.replace("#[derive", "\n#[derive"); 235
236 let mut res = String::with_capacity(ast.len() * 2);
237
238 let mut docs =
239 grammar.nodes.iter().map(|it| it.doc).chain(grammar.enums.iter().map(|it| it.doc));
240
241 for chunk in ast.split("# [ pretty_doc_comment_placeholder_workaround ]") {
242 res.push_str(chunk);
243 if let Some(doc) = docs.next() {
244 write_doc_comment(doc, &mut res);
245 }
246 }
247
248 let pretty = crate::reformat(res)?;
234 Ok(pretty) 249 Ok(pretty)
235} 250}
236 251
252fn write_doc_comment(contents: &[&str], dest: &mut String) {
253 for line in contents {
254 writeln!(dest, "///{}", line).unwrap();
255 }
256}
257
237fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> { 258fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> {
238 let (single_byte_tokens_values, single_byte_tokens): (Vec<_>, Vec<_>) = grammar 259 let (single_byte_tokens_values, single_byte_tokens): (Vec<_>, Vec<_>) = grammar
239 .punct 260 .punct
@@ -432,6 +453,7 @@ impl Field<'_> {
432 ":" => "colon", 453 ":" => "colon",
433 "::" => "coloncolon", 454 "::" => "coloncolon",
434 "#" => "pound", 455 "#" => "pound",
456 "?" => "question_mark",
435 _ => name, 457 _ => name,
436 }; 458 };
437 format_ident!("{}_token", name) 459 format_ident!("{}_token", name)
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs
index 2b7a461e5..874957885 100644
--- a/xtask/src/lib.rs
+++ b/xtask/src/lib.rs
@@ -191,7 +191,11 @@ Release: release:{}[]
191 let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n)); 191 let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
192 fs2::write(&path, &contents)?; 192 fs2::write(&path, &contents)?;
193 193
194 fs2::copy(project_root().join("./docs/user/readme.adoc"), website_root.join("manual.adoc"))?; 194 for &adoc in ["manual.adoc", "generated_features.adoc", "generated_assists.adoc"].iter() {
195 let src = project_root().join("./docs/user/").join(adoc);
196 let dst = website_root.join(adoc);
197 fs2::copy(src, dst)?;
198 }
195 199
196 let tags = run!("git tag --list"; echo = false)?; 200 let tags = run!("git tag --list"; echo = false)?;
197 let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap(); 201 let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap();
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index dff3ce4a1..9d7cdd114 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -75,6 +75,7 @@ FLAGS:
75 codegen::generate_syntax(Mode::Overwrite)?; 75 codegen::generate_syntax(Mode::Overwrite)?;
76 codegen::generate_parser_tests(Mode::Overwrite)?; 76 codegen::generate_parser_tests(Mode::Overwrite)?;
77 codegen::generate_assists_docs(Mode::Overwrite)?; 77 codegen::generate_assists_docs(Mode::Overwrite)?;
78 codegen::generate_feature_docs(Mode::Overwrite)?;
78 Ok(()) 79 Ok(())
79 } 80 }
80 "format" => { 81 "format" => {
diff --git a/xtask/tests/tidy-tests/cli.rs b/xtask/tests/tidy-tests/cli.rs
deleted file mode 100644
index f5b00a8b8..000000000
--- a/xtask/tests/tidy-tests/cli.rs
+++ /dev/null
@@ -1,32 +0,0 @@
1use xtask::{
2 codegen::{self, Mode},
3 run_rustfmt,
4};
5
6#[test]
7fn generated_grammar_is_fresh() {
8 if let Err(error) = codegen::generate_syntax(Mode::Verify) {
9 panic!("{}. Please update it by running `cargo xtask codegen`", error);
10 }
11}
12
13#[test]
14fn generated_tests_are_fresh() {
15 if let Err(error) = codegen::generate_parser_tests(Mode::Verify) {
16 panic!("{}. Please update tests by running `cargo xtask codegen`", error);
17 }
18}
19
20#[test]
21fn generated_assists_are_fresh() {
22 if let Err(error) = codegen::generate_assists_docs(Mode::Verify) {
23 panic!("{}. Please update assists by running `cargo xtask codegen`", error);
24 }
25}
26
27#[test]
28fn check_code_formatting() {
29 if let Err(error) = run_rustfmt(Mode::Verify) {
30 panic!("{}. Please format the code by running `cargo format`", error);
31 }
32}
diff --git a/xtask/tests/tidy-tests/main.rs b/xtask/tests/tidy.rs
index ead642acc..62626064e 100644
--- a/xtask/tests/tidy-tests/main.rs
+++ b/xtask/tests/tidy.rs
@@ -1,11 +1,48 @@
1mod cli;
2
3use std::{ 1use std::{
4 collections::HashMap, 2 collections::HashMap,
5 path::{Path, PathBuf}, 3 path::{Path, PathBuf},
6}; 4};
7 5
8use xtask::{not_bash::fs2, project_root, rust_files}; 6use xtask::{
7 codegen::{self, Mode},
8 not_bash::fs2,
9 project_root, run_rustfmt, rust_files,
10};
11
12#[test]
13fn generated_grammar_is_fresh() {
14 if let Err(error) = codegen::generate_syntax(Mode::Verify) {
15 panic!("{}. Please update it by running `cargo xtask codegen`", error);
16 }
17}
18
19#[test]
20fn generated_tests_are_fresh() {
21 if let Err(error) = codegen::generate_parser_tests(Mode::Verify) {
22 panic!("{}. Please update tests by running `cargo xtask codegen`", error);
23 }
24}
25
26#[test]
27fn generated_assists_are_fresh() {
28 if let Err(error) = codegen::generate_assists_docs(Mode::Verify) {
29 panic!("{}. Please update assists by running `cargo xtask codegen`", error);
30 }
31}
32
33#[test]
34fn generated_features_are_fresh() {
35 if let Err(error) = codegen::generate_feature_docs(Mode::Verify) {
36 panic!("{}. Please update features by running `cargo xtask codegen`", error);
37 }
38}
39
40#[test]
41fn check_code_formatting() {
42 if let Err(error) = run_rustfmt(Mode::Verify) {
43 panic!("{}. Please format the code by running `cargo format`", error);
44 }
45}
9 46
10#[test] 47#[test]
11fn rust_files_are_tidy() { 48fn rust_files_are_tidy() {
@@ -24,9 +61,10 @@ fn check_todo(path: &Path, text: &str) {
24 // This file itself is whitelisted since this test itself contains matches. 61 // This file itself is whitelisted since this test itself contains matches.
25 "tests/cli.rs", 62 "tests/cli.rs",
26 // Some of our assists generate `todo!()` so those files are whitelisted. 63 // Some of our assists generate `todo!()` so those files are whitelisted.
27 "doc_tests/generated.rs", 64 "tests/generated.rs",
28 "handlers/add_missing_impl_members.rs", 65 "handlers/add_missing_impl_members.rs",
29 "handlers/add_function.rs", 66 "handlers/add_function.rs",
67 "handlers/add_turbo_fish.rs",
30 // To support generating `todo!()` in assists, we have `expr_todo()` in ast::make. 68 // To support generating `todo!()` in assists, we have `expr_todo()` in ast::make.
31 "ast/make.rs", 69 "ast/make.rs",
32 ]; 70 ];
@@ -64,7 +102,7 @@ impl TidyDocs {
64 fn visit(&mut self, path: &Path, text: &str) { 102 fn visit(&mut self, path: &Path, text: &str) {
65 // Test hopefully don't really need comments, and for assists we already 103 // Test hopefully don't really need comments, and for assists we already
66 // have special comments which are source of doc tests and user docs. 104 // have special comments which are source of doc tests and user docs.
67 if is_exclude_dir(path, &["tests", "test_data", "handlers"]) { 105 if is_exclude_dir(path, &["tests", "test_data"]) {
68 return; 106 return;
69 } 107 }
70 108
@@ -79,9 +117,12 @@ impl TidyDocs {
79 117
80 if first_line.starts_with("//!") { 118 if first_line.starts_with("//!") {
81 if first_line.contains("FIXME") { 119 if first_line.contains("FIXME") {
82 self.contains_fixme.push(path.to_path_buf()) 120 self.contains_fixme.push(path.to_path_buf());
83 } 121 }
84 } else { 122 } else {
123 if text.contains("// Feature:") || text.contains("// Assist:") {
124 return;
125 }
85 self.missing_docs.push(path.display().to_string()); 126 self.missing_docs.push(path.display().to_string());
86 } 127 }
87 128
@@ -106,7 +147,6 @@ impl TidyDocs {
106 } 147 }
107 148
108 let whitelist = [ 149 let whitelist = [
109 "ra_db",
110 "ra_hir", 150 "ra_hir",
111 "ra_hir_expand", 151 "ra_hir_expand",
112 "ra_ide", 152 "ra_ide",
@@ -115,7 +155,6 @@ impl TidyDocs {
115 "ra_prof", 155 "ra_prof",
116 "ra_project_model", 156 "ra_project_model",
117 "ra_syntax", 157 "ra_syntax",
118 "ra_text_edit",
119 "ra_tt", 158 "ra_tt",
120 "ra_hir_ty", 159 "ra_hir_ty",
121 ]; 160 ];
@@ -141,13 +180,11 @@ impl TidyDocs {
141} 180}
142 181
143fn is_exclude_dir(p: &Path, dirs_to_exclude: &[&str]) -> bool { 182fn is_exclude_dir(p: &Path, dirs_to_exclude: &[&str]) -> bool {
144 let mut cur_path = p; 183 p.strip_prefix(project_root())
145 while let Some(path) = cur_path.parent() { 184 .unwrap()
146 if dirs_to_exclude.iter().any(|dir| path.ends_with(dir)) { 185 .components()
147 return true; 186 .rev()
148 } 187 .skip(1)
149 cur_path = path; 188 .filter_map(|it| it.as_os_str().to_str())
150 } 189 .any(|it| dirs_to_exclude.contains(&it))
151
152 false
153} 190}