diff --git a/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/MultilineRawStringIndentation.kt b/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/MultilineRawStringIndentation.kt index b7af32bf85f..e51f41e0739 100644 --- a/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/MultilineRawStringIndentation.kt +++ b/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/MultilineRawStringIndentation.kt @@ -67,7 +67,16 @@ class MultilineRawStringIndentation(config: Config) : Rule(config) { val lineCount = text.lines().count() if (lineCount <= 1) return if (!expression.isTrimmed()) return - if (!text.matches(rawStringRegex)) return + if (!text.matches(rawStringRegex)) { + report( + CodeSmell( + issue, + Entity.from(expression), + "A multiline raw string should start with a break line and should end with another", + ) + ) + return + } val lineAndColumn = getLineAndColumnInPsiFile(expression.containingFile, expression.textRange) ?: return @@ -158,7 +167,7 @@ private fun message(desiredIntent: Int, currentIndent: Int): String { return "The indentation should be $desiredIntent but it is $currentIndent." } -private val rawStringRegex = "\"{3}\n.*\n *\"{3}".toRegex(RegexOption.DOT_MATCHES_ALL) +private val rawStringRegex = "\"{3}\n(.*\n)? *\"{3}".toRegex(RegexOption.DOT_MATCHES_ALL) private fun String.countIndent() = this.takeWhile { it == ' ' }.count() diff --git a/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/MultilineRawStringIndentationSpec.kt b/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/MultilineRawStringIndentationSpec.kt index b799c910e94..dde5e410906 100644 --- a/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/MultilineRawStringIndentationSpec.kt +++ b/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/MultilineRawStringIndentationSpec.kt @@ -301,38 +301,66 @@ class MultilineRawStringIndentationSpec { } @Test - fun `don't raise if it contains content after the opening triple quote`() { + fun `don't raise if it isEmpty`() { val code = """ - val a = ${TQ}Hello world! - How are you? + val a = $TQ $TQ.trimIndent() """.trimIndent() subject.compileAndLint(code) assertThat(subject.findings) .isEmpty() } + } + + @Nested + inner class MissingBreakingLine { @Test - fun `don't raise if it contains content before the closing triple quote`() { + fun `raise missing break line start`() { + val code = """ + val a = ${TQ}Hello world! + Hola mundo! + $TQ.trimIndent() + """.trimIndent() + subject.compileAndLint(code) + assertThat(subject.findings) + .hasSize(1) + } + + @Test + fun `raise missing break line end`() { val code = """ val a = $TQ Hello world! - How are you?$TQ.trimIndent() + Hola mundo!$TQ.trimIndent() """.trimIndent() subject.compileAndLint(code) assertThat(subject.findings) - .isEmpty() + .hasSize(1) } @Test - fun `don't raise if it isEmpty`() { + fun `raise missing break line both`() { + val code = """ + val a = ${TQ}Hello world! + Hola mundo!$TQ.trimIndent() + """.trimIndent() + subject.compileAndLint(code) + assertThat(subject.findings) + .hasSize(1) + } + + @Test + fun `don't raise multiline raw string when correct`() { val code = """ val a = $TQ + Hello world! + Hola mundo! $TQ.trimIndent() """.trimIndent() subject.compileAndLint(code) assertThat(subject.findings) - .isEmpty() + .hasSize(0) } } }