Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite MaxLineLength & TrailingWhitespace to avoid problematic offset calcs #7270

Merged
merged 5 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
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))
3flex marked this conversation as resolved.
Show resolved Hide resolved
.asSequence()
.plus(file.findElementAt(offset))
.mapNotNull { it?.getNonStrictParentOfType() }
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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