diff --git a/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/Junk.kt b/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/Junk.kt index acbb900d8e0..30530eb4b3f 100644 --- a/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/Junk.kt +++ b/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/Junk.kt @@ -8,12 +8,12 @@ import org.jetbrains.kotlin.psi.psiUtil.elementsInRange import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType /** - * Util function to search for the first [KtElement] in the parents of + * Util function to search for the [KtElement]s in the parents of * the given [line] from a given offset in a [KtFile]. */ -internal fun findFirstKtElementInParents(file: KtFile, offset: Int, line: String): PsiElement? { +internal fun findKtElementInParents(file: KtFile, offset: Int, line: String): Sequence { return file.elementsInRange(TextRange.create(offset - line.length, offset)) + .asSequence() .plus(file.findElementAt(offset)) .mapNotNull { it?.getNonStrictParentOfType() } - .firstOrNull() } diff --git a/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/MaxLineLength.kt b/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/MaxLineLength.kt index be2e6452163..e1c29b65386 100644 --- a/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/MaxLineLength.kt +++ b/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/MaxLineLength.kt @@ -11,6 +11,8 @@ import io.gitlab.arturbosch.detekt.api.config import io.gitlab.arturbosch.detekt.api.internal.ActiveByDefault import io.gitlab.arturbosch.detekt.api.internal.Configuration import io.gitlab.arturbosch.detekt.rules.lastArgumentMatchesUrl +import org.jetbrains.kotlin.com.intellij.psi.PsiElement +import org.jetbrains.kotlin.psi.KtFile /** * This rule reports lines of code which exceed a defined maximum line length. @@ -49,7 +51,7 @@ class MaxLineLength(config: Config = Config.empty) : Rule(config) { for (line in lines) { offset += line.length if (!isValidLine(line)) { - val ktElement = findFirstKtElementInParents(file, offset, line) + val ktElement = findFirstMeaningfulKtElementInParents(file, offset, line) if (ktElement != null) { report(CodeSmell(issue, Entity.from(ktElement), issue.description)) } else { @@ -94,5 +96,11 @@ class MaxLineLength(config: Config = Config.empty) : Rule(config) { companion object { private const val DEFAULT_IDEA_LINE_LENGTH = 120 + private val BLANK_OR_QUOTES = """[\s\"]*""".toRegex() + + private fun findFirstMeaningfulKtElementInParents(file: KtFile, offset: Int, line: String): PsiElement? { + return findKtElementInParents(file, offset, line) + .firstOrNull { !BLANK_OR_QUOTES.matches(it.text) } + } } } diff --git a/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/TrailingWhitespace.kt b/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/TrailingWhitespace.kt index 861bd84d695..dc0b93d7214 100644 --- a/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/TrailingWhitespace.kt +++ b/detekt-rules-style/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/style/TrailingWhitespace.kt @@ -8,6 +8,8 @@ import io.gitlab.arturbosch.detekt.api.Issue import io.gitlab.arturbosch.detekt.api.Rule import io.gitlab.arturbosch.detekt.api.Severity import io.gitlab.arturbosch.detekt.rules.isPartOfString +import org.jetbrains.kotlin.com.intellij.psi.PsiElement +import org.jetbrains.kotlin.psi.KtFile /** * This rule reports lines that end with a whitespace. @@ -28,7 +30,7 @@ class TrailingWhitespace(config: Config = Config.empty) : Rule(config) { val trailingWhitespaces = countTrailingWhitespace(line) if (trailingWhitespaces > 0) { val file = fileContent.file - val ktElement = findFirstKtElementInParents(file, offset, line) + val ktElement = findFirstKtElementInParentsOrNull(file, offset, line) if (ktElement == null || !ktElement.isPartOfString()) { val entity = Entity.from(file, offset - trailingWhitespaces).let { entity -> entity.copy( @@ -49,4 +51,9 @@ class TrailingWhitespace(config: Config = Config.empty) : Rule(config) { } private fun createMessage(line: Int) = "Line ${line + 1} ends with a whitespace." + + private fun findFirstKtElementInParentsOrNull(file: KtFile, offset: Int, line: String): PsiElement? { + return findKtElementInParents(file, offset, line) + .firstOrNull() + } } diff --git a/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/MaxLineLengthSpec.kt b/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/MaxLineLengthSpec.kt index 21a1dafd36b..38aaaeacaed 100644 --- a/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/MaxLineLengthSpec.kt +++ b/detekt-rules-style/src/test/kotlin/io/gitlab/arturbosch/detekt/rules/style/MaxLineLengthSpec.kt @@ -8,6 +8,7 @@ import io.gitlab.arturbosch.detekt.test.TestConfig import io.gitlab.arturbosch.detekt.test.assertThat import org.spekframework.spek2.Spek import org.spekframework.spek2.style.specification.describe +import org.assertj.core.api.Assertions.assertThat as doAssert private const val MAX_LINE_LENGTH = "maxLineLength" private const val EXCLUDE_PACKAGE_STATEMENTS = "excludePackageStatements" @@ -35,7 +36,15 @@ class MaxLineLengthSpec : Spek({ val rule = MaxLineLength() rule.visit(fileContent) - assertThat(rule.findings).hasSize(6) + assertThat(rule.findings).hasSize(7) + } + + it("should report meaningful signature for all violations") { + val rule = MaxLineLength() + + rule.visit(fileContent) + val locations = rule.findings.map { it.signature.substringAfterLast('$') } + doAssert(locations).allSatisfy { doAssert(it).isNotBlank() } } } diff --git a/detekt-rules-style/src/test/resources/MaxLineLength.kt b/detekt-rules-style/src/test/resources/MaxLineLength.kt index eddcbd39ba2..567a100731e 100644 --- a/detekt-rules-style/src/test/resources/MaxLineLength.kt +++ b/detekt-rules-style/src/test/resources/MaxLineLength.kt @@ -6,24 +6,30 @@ class MaxLineLength { val LOREM_IPSUM = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua." val A_VERY_LONG_MULTI_LINE = """ - This is anotehr very very very very very very very very, very long multiline String that will break the MaxLineLength" + This is another very very very very very very very very, very long multiline String that will break the MaxLineLength" """.trimIndent() } val loremIpsumField = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua." val longMultiLineField = """ - This is anotehr very very very very very very very very + This is another very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long multiline String that will break the MaxLineLength """.trimIndent() val longMultiLineFieldWithLineBreaks = """ - This is anotehr very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very + This is another very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long multiline String with Line Break that will break the MaxLineLength """.trimIndent() + val longMultiLineFieldWithLeadingQuote = + """ + "This is yet another very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very" + "very long multiline String with Line Break that will break the MaxLineLength" + """.trimIndent() + fun main() { val thisIsAVeryLongValName = "This is a very, very long String that will break the MaxLineLength"