From 352c0c4f20ed734a6205ed2ad7a8b1bd4e33e2e1 Mon Sep 17 00:00:00 2001 From: Paul Dingemans Date: Sun, 26 Nov 2023 15:19:07 +0100 Subject: [PATCH] Prevent stack overflow exception when code provided vis stdin can not be parsed as Kotlin, nor Kotlin script (#2380) Closes #2379 --- .../ktlint/cli/internal/KtlintCommandLine.kt | 72 +++++++++++++------ .../com/pinterest/ktlint/cli/SimpleCLITest.kt | 22 ++++++ 2 files changed, 72 insertions(+), 22 deletions(-) diff --git a/ktlint-cli/src/main/kotlin/com/pinterest/ktlint/cli/internal/KtlintCommandLine.kt b/ktlint-cli/src/main/kotlin/com/pinterest/ktlint/cli/internal/KtlintCommandLine.kt index 0364a055c1..0d13311624 100644 --- a/ktlint-cli/src/main/kotlin/com/pinterest/ktlint/cli/internal/KtlintCommandLine.kt +++ b/ktlint-cli/src/main/kotlin/com/pinterest/ktlint/cli/internal/KtlintCommandLine.kt @@ -538,18 +538,32 @@ internal class KtlintCommandLine { } } catch (e: Exception) { if (code.isStdIn && e is KtLintParseException) { - logger.warn { - """ - Can not parse input from as Kotlin, due to error below: - ${e.toKtlintCliError(code).detail} - Now, trying to read the input as Kotlin Script. - """.trimIndent() + if (code.script) { + // When reading from stdin, code is only parsed as Kotlint script, if it could not be parsed as pure Kotlin. Now parsing + // of the code has failed for both, the file has to be ignored. + logger.error { + """ + Can not parse input from as Kotlin, due to error below: + ${e.toKtlintCliError(code).detail} + """.trimIndent() + } + ktlintCliErrors.add(e.toKtlintCliError(code)) + } else { + // When reading from stdin, it is first assumed that the provided code is pure Kotlin instead of Kotlin script. If + // parsing fails, retry parsing at Kotlin script. + logger.warn { + """ + Can not parse input from as Kotlin, due to error below: + ${e.toKtlintCliError(code).detail} + Now, trying to read the input as Kotlin Script. + """.trimIndent() + } + return format( + ktLintRuleEngine = ktLintRuleEngine, + code = Code.fromSnippet(code.content, script = true), + baselineLintErrors = baselineLintErrors, + ) } - return format( - ktLintRuleEngine = ktLintRuleEngine, - code = Code.fromSnippet(code.content, script = true), - baselineLintErrors = baselineLintErrors, - ) } else { ktlintCliErrors.add(e.toKtlintCliError(code)) tripped.set(true) @@ -587,18 +601,32 @@ internal class KtlintCommandLine { } } catch (e: Exception) { if (code.isStdIn && e is KtLintParseException) { - logger.warn { - """ - Can not parse input from as Kotlin, due to error below: - ${e.toKtlintCliError(code).detail} - Now, trying to read the input as Kotlin Script. - """.trimIndent() + if (code.script) { + // When reading from stdin, code is only parsed as Kotlint script, if it could not be parsed as pure Kotlin. Now parsing + // of the code has failed for both, the file has to be ignored. + logger.error { + """ + Can not parse input from as Kotlin, due to error below: + ${e.toKtlintCliError(code).detail} + """.trimIndent() + } + ktlintCliErrors.add(e.toKtlintCliError(code)) + } else { + // When reading from stdin, it is first assumed that the provided code is pure Kotlin instead of Kotlin script. If + // parsing fails, retry parsing at Kotlin script. + logger.warn { + """ + Can not parse input from as Kotlin, due to error below: + ${e.toKtlintCliError(code).detail} + Now, trying to read the input as Kotlin Script. + """.trimIndent() + } + return lint( + ktLintRuleEngine = ktLintRuleEngine, + code = Code.fromSnippet(code.content, script = true), + baselineLintErrors = baselineLintErrors, + ) } - return lint( - ktLintRuleEngine = ktLintRuleEngine, - code = Code.fromSnippet(code.content, script = true), - baselineLintErrors = baselineLintErrors, - ) } else { ktlintCliErrors.add(e.toKtlintCliError(code)) tripped.set(true) diff --git a/ktlint-cli/src/test/kotlin/com/pinterest/ktlint/cli/SimpleCLITest.kt b/ktlint-cli/src/test/kotlin/com/pinterest/ktlint/cli/SimpleCLITest.kt index 9474f49e5b..60f4eab3ac 100644 --- a/ktlint-cli/src/test/kotlin/com/pinterest/ktlint/cli/SimpleCLITest.kt +++ b/ktlint-cli/src/test/kotlin/com/pinterest/ktlint/cli/SimpleCLITest.kt @@ -515,6 +515,28 @@ class SimpleCLITest { } } + @Test + fun `Issue 2379 - Given stdin input resulting in a KtLintParseException when formatted as Kotlin Script code`( + @TempDir + tempDir: Path, + ) { + CommandLineTestRunner(tempDir) + .run( + testProjectName = "too-many-empty-lines", + arguments = listOf("--stdin", "--format"), + stdin = + ByteArrayInputStream( + """ + fun foo() = + """.trimIndent().toByteArray(), + ), + ) { + assertThat(errorOutput) + .containsLineMatching(Regex(".*Not a valid Kotlin file.*")) + .doesNotContainLineMatching(Regex(".*Now, trying to read the input as Kotlin Script.*")) + } + } + @Test fun `Enable android code style via parameter --code-style=android_studio`( @TempDir