Skip to content

Commit

Permalink
Rewrite MaxLineLength & TrailingWhitespace to avoid problematic offse…
Browse files Browse the repository at this point in the history
…t calcs (#7270)

* Ensure positive integers passed when finding elements in provided range

Negative values are invalid as the text range must start and end within the
range 0 to file.text.length

* Rewrite MaxLineLength to avoid problematic offset calcs

* Tidy up

* Improve readability

* Rewrite TrailingWhitespace to avoid problematic offset calcs
  • Loading branch information
3flex committed May 8, 2024
1 parent bf3fc6f commit 236635a
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 33 deletions.
Expand Up @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
* the given [line] from a given offset in a [KtFile].
*/
internal fun findKtElementInParents(file: KtFile, offset: Int, line: String): Sequence<PsiElement> {
return file.elementsInRange(TextRange.create(offset - line.length, offset))
return file.elementsInRange(TextRange.create(offset, offset + line.length))
.asSequence()
.plus(file.findElementAt(offset))
.mapNotNull { it?.getNonStrictParentOfType() }
Expand Down
@@ -1,5 +1,6 @@
package io.gitlab.arturbosch.detekt.rules.style

import io.github.detekt.psi.absolutePath
import io.gitlab.arturbosch.detekt.api.ActiveByDefault
import io.gitlab.arturbosch.detekt.api.CodeSmell
import io.gitlab.arturbosch.detekt.api.Config
Expand All @@ -13,10 +14,13 @@ import io.gitlab.arturbosch.detekt.api.config
import io.gitlab.arturbosch.detekt.rules.lastArgumentMatchesKotlinReferenceUrlSyntax
import io.gitlab.arturbosch.detekt.rules.lastArgumentMatchesMarkdownUrlSyntax
import io.gitlab.arturbosch.detekt.rules.lastArgumentMatchesUrl
import org.jetbrains.kotlin.KtPsiSourceFileLinesMapping
import org.jetbrains.kotlin.com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils.getLineAndColumnRangeInPsiFile
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType

/**
* This rule reports lines of code which exceed a defined maximum line length.
Expand Down Expand Up @@ -48,26 +52,25 @@ class MaxLineLength(config: Config) : Rule(

override fun visitKtFile(file: KtFile) {
super.visitKtFile(file)
var offset = 0
val lines = file.text.lines()

for (line in lines) {
offset += line.length
if (!isValidLine(file, offset, line)) {
val sourceFileLinesMapping = KtPsiSourceFileLinesMapping(file)

file.text.lines().withIndex()
.filterNot { (index, line) -> isValidLine(file, sourceFileLinesMapping.getLineStartOffset(index), line) }
.forEach { (index, line) ->
val offset = sourceFileLinesMapping.getLineStartOffset(index)
val ktElement = findFirstMeaningfulKtElementInParents(file, offset, line) ?: file
val location = Location.from(file, offset - line.length).let { location ->
val textRange = TextRange(offset, offset + line.length)
val lineAndColumnRange = getLineAndColumnRangeInPsiFile(file, textRange)
val location =
Location(
source = location.source,
endSource = SourceLocation(location.source.line, line.length + 1),
text = TextLocation(offset - line.length, offset),
path = location.path,
source = SourceLocation(lineAndColumnRange.start.line, lineAndColumnRange.start.column),
endSource = SourceLocation(lineAndColumnRange.end.line, lineAndColumnRange.end.column),
text = TextLocation(offset, offset + line.length),
path = file.absolutePath(),
)
}
report(CodeSmell(Entity.from(ktElement, location), description))
}

offset += 1 // '\n'
}
}

private fun isValidLine(file: KtFile, offset: Int, line: String): Boolean {
Expand Down Expand Up @@ -123,5 +126,5 @@ class MaxLineLength(config: Config) : Rule(
}

private fun PsiElement.isInsideRawString(): Boolean {
return this is KtStringTemplateExpression || getParentOfType<KtStringTemplateExpression>(false) != null
return this is KtStringTemplateExpression || getNonStrictParentOfType<KtStringTemplateExpression>() != null
}
@@ -1,13 +1,18 @@
package io.gitlab.arturbosch.detekt.rules.style

import io.github.detekt.psi.absolutePath
import io.gitlab.arturbosch.detekt.api.CodeSmell
import io.gitlab.arturbosch.detekt.api.Config
import io.gitlab.arturbosch.detekt.api.Entity
import io.gitlab.arturbosch.detekt.api.Location
import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.SourceLocation
import io.gitlab.arturbosch.detekt.api.TextLocation
import io.gitlab.arturbosch.detekt.rules.isPartOfString
import org.jetbrains.kotlin.KtPsiSourceFileLinesMapping
import org.jetbrains.kotlin.com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils.getLineAndColumnRangeInPsiFile
import org.jetbrains.kotlin.psi.KtFile

/**
Expand All @@ -26,29 +31,29 @@ class TrailingWhitespace(config: Config) : Rule(

override fun visitKtFile(file: KtFile) {
super.visitKtFile(file)
var offset = 0

val sourceFileLinesMapping = KtPsiSourceFileLinesMapping(file)

file.text.lineSequence().forEachIndexed { index, line ->
offset += line.length
val trailingWhitespaces = countTrailingWhitespace(line)
if (trailingWhitespaces > 0) {
val ktElement = findFirstKtElementInParentsOrNull(file, offset, line)
val lineEndOffset = sourceFileLinesMapping.getLineStartOffset(index) + line.length
val ktElement = findFirstKtElementInParentsOrNull(file, lineEndOffset, line)
if (ktElement == null || !ktElement.isPartOfString()) {
val entity = Entity.from(file, offset - trailingWhitespaces).let { entity ->
Entity(
entity.name,
entity.signature,
location = Location(
entity.location.source,
entity.location.endSource,
TextLocation(entity.location.text.start, offset),
entity.location.path
)
val startOffset = lineEndOffset - trailingWhitespaces
val textRange = TextRange(startOffset, lineEndOffset)
val lineAndColumnRange = getLineAndColumnRangeInPsiFile(file, textRange)
val location =
Location(
source = SourceLocation(lineAndColumnRange.start.line, lineAndColumnRange.start.column),
endSource = SourceLocation(lineAndColumnRange.end.line, lineAndColumnRange.end.column),
text = TextLocation(startOffset, lineEndOffset),
path = file.absolutePath(),
)
}
report(CodeSmell(entity, createMessage(index)))

report(CodeSmell(Entity.from(file, location), createMessage(index)))
}
}
offset += 1 // '\n'
}
}

Expand Down

0 comments on commit 236635a

Please sign in to comment.