diff --git a/.changelog/fix-generated-trailing-whitespace.md b/.changelog/fix-generated-trailing-whitespace.md new file mode 100644 index 0000000000..07d6281f8b --- /dev/null +++ b/.changelog/fix-generated-trailing-whitespace.md @@ -0,0 +1,13 @@ +--- +applies_to: +- server +authors: +- jlizen +references: +- smithy-rs#4634 +breaking: false +new_feature: false +bug_fix: true +--- + +Strip trailing whitespace from generated Rust code. Smithy's `AbstractCodeWriter` adds indentation to blank lines, producing whitespace-only lines that cause `cargo fmt` to fail with `error[internal]: left behind trailing whitespace`. diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt index 80ae291537..9d6e505bee 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt @@ -598,6 +598,8 @@ class RustWriter private constructor( ) : SymbolWriter(UseDeclarations(namespace)) { companion object { + private val TRAILING_WHITESPACE_RE = Regex("[ \\t]+\\n") + fun root() = forModule(null) fun forModule(module: String?): RustWriter = @@ -925,6 +927,7 @@ class RustWriter private constructor( null } return listOfNotNull(preheader, header, useDecls, contents).joinToString(separator = "\n", postfix = "\n") + .replace(TRAILING_WHITESPACE_RE, "\n") } fun format(r: Any) = formatter.apply(r, "") diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt index 7b4ca78fbe..5fab010c87 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt @@ -228,4 +228,37 @@ class RustWriterTest { val sut = RustWriter.forModule("src/module_name") sut.module().shouldBe("module_name") } + + // Regression test for https://github.com/smithy-lang/smithy-rs/issues/4634 + @Test + fun `output does not contain trailing whitespace`() { + val sut = RustWriter.root() + // Reproduce the two patterns from the issue: + sut.rustBlock("fn example()") { + // join("\n") separator creates a blank line that gets indented + val writables = + listOf( + writable { rust("let a = 1;") }, + writable { rust("let b = 2;") }, + ) + writables.join("\n")(this) + + // Empty string interpolation leaves a blank line that gets indented + val empty = "" + rust( + """ + something + .method() + $empty + .chain() + """, + ) + } + val output = sut.toString() + val trailingWhitespaceLines = + output.lines().filter { line -> + line != line.trimEnd() + } + trailingWhitespaceLines shouldBe emptyList() + } }