Repository: rust-lang/rustfmt (rust)

Issue:
Left behind trailing whitespace on complicated generics
The following code yields "error[internal]: left behind trailing whitespace" error on rustfmt:

```
fn foo(
    a: <u16 as intercom::type_system::ExternType<
        intercom::type_system::AutomationTypeSystem,
    >>::ForeignType,
) {}
```

[(Playground)](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f080efcbdeb52da55894a2066d946f10)

As far as I know, this has worked in the past, but has regressed somewhere within this year (unfortunately can't pinpoint the timeframe more accurately than that). Also I believe rustfmt does manage to format that properly, but adds an extra newline _before_ the parameter.

From what I can tell, the output from rustfmt is:

```
fn foo(
    
    a: <u16 as intercom::type_system::ExternType<
        intercom::type_system::AutomationTypeSystem,
    >>::ForeignType,
) {}
```

(The second line has indent, but no other content.)

Unfortunately the lines are output from a proc macro and end up as top-level functions in the module. I'm using full mod paths to avoid polluting the caller scope by introducing elements with `use` statements. Although in my case I'm using rustfmt just to get nicer test output for macro expansion tests so it's not like this is breaking crate usage, just tests.

#### Meta

- rustfmt version: rustfmt 1.4.38-nightly (532d2b14 2021-12-03) and whatever playground has.
- Running with: `cargo fmt` or playground

Pull request description:
Prevent adding trailing whitespace when rewriting ast::Param
Fixes #5125

Previously, a newline was always added, even if the parameter name was
not preceded by any param attrs.

Now a newline is only added if there were param attrs.

Patch:
diff --git a/Configurations.md b/Configurations.md
index a89fbe86..4476f2a4 100644
--- a/Configurations.md
+++ b/Configurations.md
@@ -929,9 +929,9 @@ fn add_one(x: i32) -> i32 {
 ## `format_generated_files`
 
 Format generated files. A file is considered generated
-if any of the first five lines contains `@generated` marker.
+if any of the first five lines contain a `@generated` comment marker.
 
-- **Default value**: `false`
+- **Default value**: `true`
 - **Possible values**: `true`, `false`
 - **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080))
 
diff --git a/rust-toolchain b/rust-toolchain
index d4cdcec2..d8bf02ae 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-12-29"
+channel = "nightly-2022-01-23"
 components = ["rustc-dev"]
diff --git a/src/cargo-fmt/main.rs b/src/cargo-fmt/main.rs
index 759b2121..8cb7b458 100644
--- a/src/cargo-fmt/main.rs
+++ b/src/cargo-fmt/main.rs
@@ -387,8 +387,7 @@ fn get_targets_root_only(
                         .unwrap_or_default()
                         == current_dir_manifest
             })
-            .map(|p| p.targets)
-            .flatten()
+            .flat_map(|p| p.targets)
             .collect(),
     };
 
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 5dbe532a..cd90e090 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -138,7 +138,7 @@ create_config! {
     inline_attribute_width: usize, 0, false,
         "Write an item and its attribute on the same line \
         if their combined width is below a threshold";
-    format_generated_files: bool, false, false, "Format generated files";
+    format_generated_files: bool, true, false, "Format generated files";
 
     // Options that can change the source code beyond whitespace/blocks (somewhat linty things)
     merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one";
@@ -606,7 +606,7 @@ blank_lines_lower_bound = 0
 edition = "2015"
 version = "One"
 inline_attribute_width = 0
-format_generated_files = false
+format_generated_files = true
 merge_derives = true
 use_try_shorthand = false
 use_field_init_shorthand = false
diff --git a/src/expr.rs b/src/expr.rs
index c9c8852c..e1865c8a 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -334,9 +334,7 @@ pub(crate) fn format_expr(
         // satisfy our width restrictions.
         // Style Guide RFC for InlineAsm variant pending
         // https://github.com/rust-dev-tools/fmt-rfcs/issues/152
-        ast::ExprKind::LlvmInlineAsm(..) | ast::ExprKind::InlineAsm(..) => {
-            Some(context.snippet(expr.span).to_owned())
-        }
+        ast::ExprKind::InlineAsm(..) => Some(context.snippet(expr.span).to_owned()),
         ast::ExprKind::TryBlock(ref block) => {
             if let rw @ Some(_) =
                 rewrite_single_line_block(context, "try ", block, Some(&expr.attrs), None, shape)
diff --git a/src/format_report_formatter.rs b/src/format_report_formatter.rs
index c8202592..90406cdb 100644
--- a/src/format_report_formatter.rs
+++ b/src/format_report_formatter.rs
@@ -20,6 +20,7 @@ impl<'a> FormatReportFormatterBuilder<'a> {
     }
 
     /// Enables colors and formatting in the output.
+    #[must_use]
     pub fn enable_colors(self, enable_colors: bool) -> Self {
         Self {
             enable_colors,
diff --git a/src/formatting.rs b/src/formatting.rs
index 67cf1232..ca93955a 100644
--- a/src/formatting.rs
+++ b/src/formatting.rs
@@ -80,7 +80,9 @@ fn should_skip_module<T: FormatHandler>(
         return true;
     }
 
-    if !config.format_generated_files() {
+    // FIXME(calebcartwright) - we need to determine how we'll handle the
+    // `format_generated_files` option with stdin based input.
+    if !input_is_stdin && !config.format_generated_files() {
         let source_file = context.parse_session.span_to_file_contents(module.span);
         let src = source_file.src.as_ref().expect("SourceFile without src");
 
diff --git a/src/items.rs b/src/items.rs
index babc56f8..007609ab 100644
--- a/src/items.rs
+++ b/src/items.rs
@@ -1374,17 +1374,21 @@ fn format_empty_struct_or_tuple(
         result.push_str(&offset.to_string_with_newline(context.config))
     }
     result.push_str(opener);
-    match rewrite_missing_comment(span, Shape::indented(offset, context.config), context) {
+
+    // indented shape for proper indenting of multi-line comments
+    let shape = Shape::indented(offset.block_indent(context.config), context.config);
+    match rewrite_missing_comment(span, shape, context) {
         Some(ref s) if s.is_empty() => (),
         Some(ref s) => {
-            if !is_single_line(s) || first_line_contains_single_line_comment(s) {
+            let is_multi_line = !is_single_line(s);
+            if is_multi_line || first_line_contains_single_line_comment(s) {
                 let nested_indent_str = offset
                     .block_indent(context.config)
                     .to_string_with_newline(context.config);
                 result.push_str(&nested_indent_str);
             }
             result.push_str(s);
-            if last_line_contains_single_line_comment(s) {
+            if is_multi_line || last_line_contains_single_line_comment(s) {
                 result.push_str(&offset.to_string_with_newline(context.config));
             }
         }
@@ -2014,9 +2018,15 @@ impl Rewrite for ast::Param {
                 {
                     result.push_str(&ty_str);
                 } else {
+                    let prev_str = if param_attrs_result.is_empty() {
+                        param_attrs_result
+                    } else {
+                        param_attrs_result + &shape.to_string_with_newline(context.config)
+                    };
+
                     result = combine_strs_with_missing_comments(
                         context,
-                        &(param_attrs_result + &shape.to_string_with_newline(context.config)),
+                        &prev_str,
                         param_name,
                         span,
                         shape,
diff --git a/src/lib.rs b/src/lib.rs
index ad23b16e..fae8080c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,6 +3,7 @@
 #![warn(unreachable_pub)]
 #![recursion_limit = "256"]
 #![allow(clippy::match_like_matches_macro)]
+#![allow(unreachable_pub)]
 
 #[macro_use]
 extern crate derive_new;
diff --git a/src/macros.rs b/src/macros.rs
index f29552ca..fdbe3374 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -152,7 +152,7 @@ pub(crate) fn rewrite_macro(
 ) -> Option<String> {
     let should_skip = context
         .skip_context
-        .skip_macro(&context.snippet(mac.path.span).to_owned());
+        .skip_macro(context.snippet(mac.path.span));
     if should_skip {
         None
     } else {
diff --git a/src/types.rs b/src/types.rs
index 88f5dc43..5de30129 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -1,7 +1,7 @@
 use std::iter::ExactSizeIterator;
 use std::ops::Deref;
 
-use rustc_ast::ast::{self, FnRetTy, Mutability};
+use rustc_ast::ast::{self, FnRetTy, Mutability, Term};
 use rustc_ast::ptr;
 use rustc_span::{symbol::kw, BytePos, Pos, Span};
 
@@ -141,7 +141,7 @@ pub(crate) enum SegmentParam<'a> {
     Const(&'a ast::AnonConst),
     LifeTime(&'a ast::Lifetime),
     Type(&'a ast::Ty),
-    Binding(&'a ast::AssocTyConstraint),
+    Binding(&'a ast::AssocConstraint),
 }
 
 impl<'a> SegmentParam<'a> {
@@ -176,9 +176,9 @@ impl<'a> Rewrite for SegmentParam<'a> {
     }
 }
 
-impl Rewrite for ast::AssocTyConstraint {
+impl Rewrite for ast::AssocConstraint {
     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
-        use ast::AssocTyConstraintKind::{Bound, Equality};
+        use ast::AssocConstraintKind::{Bound, Equality};
 
         let mut result = String::with_capacity(128);
         result.push_str(rewrite_ident(context, self.ident));
@@ -206,11 +206,14 @@ impl Rewrite for ast::AssocTyConstraint {
     }
 }
 
-impl Rewrite for ast::AssocTyConstraintKind {
+impl Rewrite for ast::AssocConstraintKind {
     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
         match self {
-            ast::AssocTyConstraintKind::Equality { ty } => ty.rewrite(context, shape),
-            ast::AssocTyConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
+            ast::AssocConstraintKind::Equality { term } => match term {
+                Term::Ty(ty) => ty.rewrite(context, shape),
+                Term::Const(c) => c.rewrite(context, shape),
+            },
+            ast::AssocConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
         }
     }
 }
diff --git a/src/utils.rs b/src/utils.rs
index 0c0b789a..2428d8cb 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -507,7 +507,6 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
         | ast::ExprKind::Err
         | ast::ExprKind::Field(..)
         | ast::ExprKind::InlineAsm(..)
-        | ast::ExprKind::LlvmInlineAsm(..)
         | ast::ExprKind::Let(..)
         | ast::ExprKind::Path(..)
         | ast::ExprKind::Range(..)


Test patch:
diff --git a/src/test/mod.rs b/src/test/mod.rs
index 2d5a8f22..ab966d4a 100644
--- a/src/test/mod.rs
+++ b/src/test/mod.rs
@@ -557,6 +557,27 @@ fn stdin_disable_all_formatting_test() {
     assert_eq!(input, String::from_utf8(output.stdout).unwrap());
 }
 
+#[test]
+fn stdin_generated_files_issue_5172() {
+    init_log();
+    let input = Input::Text("//@generated\nfn   main() {}".to_owned());
+    let mut config = Config::default();
+    config.set().emit_mode(EmitMode::Stdout);
+    config.set().format_generated_files(false);
+    config.set().newline_style(NewlineStyle::Unix);
+    let mut buf: Vec<u8> = vec![];
+    {
+        let mut session = Session::new(config, Some(&mut buf));
+        session.format(input).unwrap();
+        assert!(session.has_no_errors());
+    }
+    // N.B. this should be changed once `format_generated_files` is supported with stdin
+    assert_eq!(
+        String::from_utf8(buf).unwrap(),
+        "<stdin>:\n\n//@generated\nfn main() {}\n",
+    );
+}
+
 #[test]
 fn format_lines_errors_are_reported() {
     init_log();
diff --git a/tests/source/issue_4854.rs b/tests/source/issue_4854.rs
new file mode 100644
index 00000000..35d6e21a
--- /dev/null
+++ b/tests/source/issue_4854.rs
@@ -0,0 +1,113 @@
+struct Struct {
+    // Multiline comment
+    // should be formatted
+    // properly.
+}
+
+struct Struct2 {
+    // This formatting
+// Should be changed
+}
+
+struct Struct3(
+    // This
+    // is
+    // correct
+);
+
+struct Struct4(
+    // This
+// is
+// not
+// correct
+);
+
+struct Struct5 {
+    /*
+    Comment block
+    with many lines.
+    */
+}
+
+struct Struct6(
+    /*
+    Comment block
+    with many lines.
+    */
+);
+
+struct Struct7 {
+    /*
+Invalid
+format
+*/
+}
+
+struct Struct8(
+    /*
+Invalid
+format
+*/
+);
+
+struct Struct9 { /* bar */ }
+
+struct Struct10 { /* bar
+baz
+*/ }
+
+mod module {
+    struct Struct {
+        // Multiline comment
+        // should be formatted
+        // properly.
+    }
+
+    struct Struct2 {
+        // This formatting
+// Should be changed
+    }
+
+    struct Struct3(
+        // This
+        // is
+        // correct
+    );
+
+    struct Struct4(
+        // This
+    // is
+    // not
+// correct
+    );
+
+    struct Struct5 {
+        /*
+        Comment block
+        with many lines.
+         */
+    }
+
+    struct Struct6(
+        /*
+        Comment block
+        with many lines.
+        */
+    );
+
+    struct Struct7 {
+        /*
+Invalid
+format
+*/
+    }
+
+    struct Struct8(
+        /*
+Invalid
+format
+*/
+    );
+
+    struct Struct9 { /* bar */ }
+}
diff --git a/tests/target/comments-in-lists/format-doc-comments.rs b/tests/target/comments-in-lists/format-doc-comments.rs
index be31bf0a..be4b7a8c 100644
--- a/tests/target/comments-in-lists/format-doc-comments.rs
+++ b/tests/target/comments-in-lists/format-doc-comments.rs
@@ -25,9 +25,8 @@ pub enum E {
 }
 
 pub enum E2 {
-    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
-// Expand as needed, numbers should be ascending according to the stage
-// through the inclusion pipeline, or according to the descriptions
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
 }
 
 pub struct S {
@@ -42,9 +41,8 @@ pub struct S {
 }
 
 pub struct S2 {
-    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
-// Expand as needed, numbers should be ascending according to the stage
-// through the inclusion pipeline, or according to the descriptions
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
 }
 
 fn foo(
diff --git a/tests/target/comments-in-lists/wrap-comments-false.rs b/tests/target/comments-in-lists/wrap-comments-false.rs
index 80aea59d..db4da622 100644
--- a/tests/target/comments-in-lists/wrap-comments-false.rs
+++ b/tests/target/comments-in-lists/wrap-comments-false.rs
@@ -13,9 +13,8 @@ pub enum E {
 }
 
 pub enum E2 {
-    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
-// Expand as needed, numbers should be ascending according to the stage
-// through the inclusion pipeline, or according to the descriptions
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
 }
 
 pub struct S {
@@ -30,9 +29,8 @@ pub struct S {
 }
 
 pub struct S2 {
-    // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
-// Expand as needed, numbers should be ascending according to the stage
-// through the inclusion pipeline, or according to the descriptions
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
 }
 
 fn foo(
diff --git a/tests/target/comments-in-lists/wrap-comments-not-normalized.rs b/tests/target/comments-in-lists/wrap-comments-not-normalized.rs
index 52315f47..9b9147eb 100644
--- a/tests/target/comments-in-lists/wrap-comments-not-normalized.rs
+++ b/tests/target/comments-in-lists/wrap-comments-not-normalized.rs
@@ -14,8 +14,8 @@ pub enum E {
 
 pub enum E2 {
     // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
-// Expand as needed, numbers should be ascending according to the stage
-// through the inclusion pipeline, or according to the descriptions
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
 }
 
 pub enum E3 {
@@ -42,8 +42,8 @@ pub struct S {
 
 pub struct S2 {
     // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
-// Expand as needed, numbers should be ascending according to the stage
-// through the inclusion pipeline, or according to the descriptions
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
 }
 
 pub struct S3 {
diff --git a/tests/target/comments-in-lists/wrap-comments-true.rs b/tests/target/comments-in-lists/wrap-comments-true.rs
index e0bfcf0b..c1531d22 100644
--- a/tests/target/comments-in-lists/wrap-comments-true.rs
+++ b/tests/target/comments-in-lists/wrap-comments-true.rs
@@ -15,8 +15,8 @@ pub enum E {
 
 pub enum E2 {
     // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
-// Expand as needed, numbers should be ascending according to the stage
-// through the inclusion pipeline, or according to the descriptions
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
 }
 
 pub enum E3 {
@@ -43,8 +43,8 @@ pub struct S {
 
 pub struct S2 {
     // This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
-// Expand as needed, numbers should be ascending according to the stage
-// through the inclusion pipeline, or according to the descriptions
+    // Expand as needed, numbers should be ascending according to the stage
+    // through the inclusion pipeline, or according to the descriptions
 }
 
 pub struct S3 {
diff --git a/tests/target/issue-5125/attributes_in_formal_fuction_parameter.rs b/tests/target/issue-5125/attributes_in_formal_fuction_parameter.rs
new file mode 100644
index 00000000..5d167932
--- /dev/null
+++ b/tests/target/issue-5125/attributes_in_formal_fuction_parameter.rs
@@ -0,0 +1,6 @@
+fn foo(
+    #[unused] a: <u16 as intercom::type_system::ExternType<
+        intercom::type_system::AutomationTypeSystem,
+    >>::ForeignType,
+) {
+}
diff --git a/tests/target/issue-5125/long_parameter_in_different_positions.rs b/tests/target/issue-5125/long_parameter_in_different_positions.rs
new file mode 100644
index 00000000..cab20381
--- /dev/null
+++ b/tests/target/issue-5125/long_parameter_in_different_positions.rs
@@ -0,0 +1,24 @@
+fn middle(
+    a: usize,
+    b: <u16 as intercom::type_system::ExternType<
+        intercom::type_system::AutomationTypeSystem,
+    >>::ForeignType,
+    c: bool,
+) {
+}
+
+fn last(
+    a: usize,
+    b: <u16 as intercom::type_system::ExternType<
+        intercom::type_system::AutomationTypeSystem,
+    >>::ForeignType,
+) {
+}
+
+fn first(
+    a: <u16 as intercom::type_system::ExternType<
+        intercom::type_system::AutomationTypeSystem,
+    >>::ForeignType,
+    b: usize,
+) {
+}
diff --git a/tests/target/issue-5125/minimum_example.rs b/tests/target/issue-5125/minimum_example.rs
new file mode 100644
index 00000000..8003e669
--- /dev/null
+++ b/tests/target/issue-5125/minimum_example.rs
@@ -0,0 +1,6 @@
+fn foo(
+    a: <u16 as intercom::type_system::ExternType<
+        intercom::type_system::AutomationTypeSystem,
+    >>::ForeignType,
+) {
+}
diff --git a/tests/target/issue-5125/with_leading_and_inline_comments.rs b/tests/target/issue-5125/with_leading_and_inline_comments.rs
new file mode 100644
index 00000000..2340b2f3
--- /dev/null
+++ b/tests/target/issue-5125/with_leading_and_inline_comments.rs
@@ -0,0 +1,7 @@
+fn foo(
+    // Pre Comment
+    a: <u16 as intercom::type_system::ExternType<
+        intercom::type_system::AutomationTypeSystem,
+    >>::ForeignType, // Inline comment
+) {
+}
diff --git a/tests/target/issue_4854.rs b/tests/target/issue_4854.rs
new file mode 100644
index 00000000..a81c5a51
--- /dev/null
+++ b/tests/target/issue_4854.rs
@@ -0,0 +1,115 @@
+struct Struct {
+    // Multiline comment
+    // should be formatted
+    // properly.
+}
+
+struct Struct2 {
+    // This formatting
+    // Should be changed
+}
+
+struct Struct3(
+    // This
+    // is
+    // correct
+);
+
+struct Struct4(
+    // This
+    // is
+    // not
+    // correct
+);
+
+struct Struct5 {
+    /*
+    Comment block
+    with many lines.
+    */
+}
+
+struct Struct6(
+    /*
+    Comment block
+    with many lines.
+    */
+);
+
+struct Struct7 {
+    /*
+    Invalid
+    format
+    */
+}
+
+struct Struct8(
+    /*
+    Invalid
+    format
+    */
+);
+
+struct Struct9 {/* bar */}
+
+struct Struct10 {
+    /* bar
+    baz
+    */
+}
+
+mod module {
+    struct Struct {
+        // Multiline comment
+        // should be formatted
+        // properly.
+    }
+
+    struct Struct2 {
+        // This formatting
+        // Should be changed
+    }
+
+    struct Struct3(
+        // This
+        // is
+        // correct
+    );
+
+    struct Struct4(
+        // This
+        // is
+        // not
+        // correct
+    );
+
+    struct Struct5 {
+        /*
+        Comment block
+        with many lines.
+         */
+    }
+
+    struct Struct6(
+        /*
+        Comment block
+        with many lines.
+        */
+    );
+
+    struct Struct7 {
+        /*
+        Invalid
+        format
+        */
+    }
+
+    struct Struct8(
+        /*
+        Invalid
+        format
+        */
+    );
+
+    struct Struct9 {/* bar */}
+}