From 221caf31e0f15d25b050b051791780eba9dd841d Mon Sep 17 00:00:00 2001 From: kentr0w Date: Tue, 13 Oct 2020 12:37:16 +0300 Subject: [PATCH 1/3] Remove deprecated calculateLineColByOffset methods from Ktlint ### What's done: Copy-paste methods --- .../cqfn/diktat/ruleset/rules/LineLength.kt | 16 ++-- .../cqfn/diktat/ruleset/utils/AstNodeUtils.kt | 4 + .../ruleset/utils/PositionInTextLocator.kt | 77 +++++++++++++++++++ 3 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PositionInTextLocator.kt diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/LineLength.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/LineLength.kt index 92663333d4..dd1729f659 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/LineLength.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/LineLength.kt @@ -1,6 +1,5 @@ package org.cqfn.diktat.ruleset.rules -import com.pinterest.ktlint.core.KtLint.calculateLineColByOffset import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.ast.ElementType.BINARY_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.BLOCK @@ -40,6 +39,7 @@ import org.cqfn.diktat.common.config.rules.getRuleConfig import org.cqfn.diktat.ruleset.constants.Warnings.LONG_LINE import org.cqfn.diktat.ruleset.utils.KotlinParser import org.cqfn.diktat.ruleset.utils.appendNewlineMergingWhiteSpace +import org.cqfn.diktat.ruleset.utils.calculateLineColByOffset import org.cqfn.diktat.ruleset.utils.hasChildOfType import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.CompositeElement @@ -101,7 +101,7 @@ class LineLength(private val configRules: List) : Rule("line-length val newNode = node.psi.findElementAt(offset + configuration.lineLength.toInt())!!.node if ((newNode.elementType != KDOC_TEXT && newNode.elementType != KDOC_MARKDOWN_INLINE_LINK) || !isKDocValid(newNode)) { - positionByOffset = calculateLineColByOffset(node.treeParent.text) + positionByOffset = node.treeParent.calculateLineColByOffset() val fixableType = isFixable(newNode, configuration) LONG_LINE.warnAndFix(configRules, emitWarn, isFixMode, "max line length ${configuration.lineLength}, but was ${it.length}", @@ -394,12 +394,12 @@ class LineLength(private val configRules: List) : Rule("line-length } sealed class LongLineFixableCases { - object None: LongLineFixableCases() - class Comment(val node: ASTNode, val indexLastSpace: Int): LongLineFixableCases() - class Condition(val maximumLineLength: Long, val leftOffset: Int, val binList: MutableList): LongLineFixableCases() - class Fun(val node: ASTNode): LongLineFixableCases() - class Property(val node: ASTNode, val indexLastSpace: Int, val text: String): LongLineFixableCases() + object None : LongLineFixableCases() + class Comment(val node: ASTNode, val indexLastSpace: Int) : LongLineFixableCases() + class Condition(val maximumLineLength: Long, val leftOffset: Int, val binList: MutableList) : LongLineFixableCases() + class Fun(val node: ASTNode) : LongLineFixableCases() + class Property(val node: ASTNode, val indexLastSpace: Int, val text: String) : LongLineFixableCases() class PropertyWithTemplateEntry(val node: ASTNode, val maximumLineLength: Long, - val leftOffset: Int, val binList: MutableList): LongLineFixableCases() + val leftOffset: Int, val binList: MutableList) : LongLineFixableCases() } } diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt index d267aa1dc1..7176cb375d 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtils.kt @@ -499,6 +499,10 @@ fun isLocatedInTest(filePathParts: List, testAnchors: List): Boo fun ASTNode.firstLineOfText(suffix: String = "") = text.lines().run { singleOrNull() ?: (first() + suffix) } +fun ASTNode.calculateLineColByOffset(): (offset: Int) -> Pair { + return buildPositionInTextLocator(text) +} + fun ASTNode.lastLineNumber() = lineNumber()?.plus(text.count { it == '\n' }) fun ASTNode.getFileName(): String = getUserData(KtLint.FILE_PATH_USER_DATA_KEY).let { diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PositionInTextLocator.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PositionInTextLocator.kt new file mode 100644 index 0000000000..5329b7cdab --- /dev/null +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PositionInTextLocator.kt @@ -0,0 +1,77 @@ +package org.cqfn.diktat.ruleset.utils + +internal typealias LineAndColumn = Pair + +/** + * Calculate position in text - line and column based on offset from the text start. + */ +internal fun buildPositionInTextLocator( + text: String +): (offset: Int) -> LineAndColumn { + val textLength = text.length + val arr = ArrayList() + + var endOfLineIndex = -1 + do { + arr.add(endOfLineIndex + 1) + endOfLineIndex = text.indexOf('\n', endOfLineIndex + 1) + } while (endOfLineIndex != -1) + + arr.add(textLength + if (arr.last() == textLength) 1 else 0) + + val segmentTree = SegmentTree(arr.toTypedArray()) + + return { offset -> + val line = segmentTree.indexOf(offset) + if (line != -1) { + val col = offset - segmentTree.get(line).left + line + 1 to col + 1 + } else { + 1 to 1 + } + } +} + +private class SegmentTree( + sortedArray: Array +) { + + init { + require(sortedArray.size > 1) { "At least two data points are required" } + sortedArray.reduce { current, next -> + require(current <= next) { "Data points are not sorted (ASC)" } + next + } + } + + private val segments: List = sortedArray + .dropLast(1) + .mapIndexed { index: Int, element: Int -> + Segment(element, sortedArray[index + 1] - 1) + } + + fun get(i: Int): Segment = segments[i] + fun indexOf(v: Int): Int = binarySearch(v, 0, segments.size - 1) + + private fun binarySearch( + v: Int, + l: Int, + r: Int + ): Int = when { + l > r -> -1 + else -> { + val i = l + (r - l) / 2 + val s = segments[i] + if (v < s.left) { + binarySearch(v, l, i - 1) + } else { + if (s.right < v) binarySearch(v, i + 1, r) else i + } + } + } +} + +private data class Segment( + val left: Int, + val right: Int +) From 9ff408054be566d936d6e7d7ba8b99b2f6437f0a Mon Sep 17 00:00:00 2001 From: kentr0w Date: Tue, 13 Oct 2020 13:03:50 +0300 Subject: [PATCH 2/3] Remove deprecated calculateLineColByOffset methods from Ktlint ### What's done: Renamed variables and fixed bugs --- .../ruleset/utils/PositionInTextLocator.kt | 45 ++++++++----------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PositionInTextLocator.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PositionInTextLocator.kt index 5329b7cdab..a184e282a4 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PositionInTextLocator.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PositionInTextLocator.kt @@ -5,36 +5,32 @@ internal typealias LineAndColumn = Pair /** * Calculate position in text - line and column based on offset from the text start. */ -internal fun buildPositionInTextLocator( - text: String -): (offset: Int) -> LineAndColumn { +internal fun buildPositionInTextLocator(text: String): (offset: Int) -> LineAndColumn { val textLength = text.length - val arr = ArrayList() - + val identifierArray = ArrayList() var endOfLineIndex = -1 + do { - arr.add(endOfLineIndex + 1) + identifierArray.add(endOfLineIndex + 1) endOfLineIndex = text.indexOf('\n', endOfLineIndex + 1) } while (endOfLineIndex != -1) - arr.add(textLength + if (arr.last() == textLength) 1 else 0) + identifierArray.add(textLength + if (identifierArray.last() == textLength) 1 else 0) - val segmentTree = SegmentTree(arr.toTypedArray()) + val segmentTree = SegmentTree(identifierArray.toIntArray()) return { offset -> val line = segmentTree.indexOf(offset) if (line != -1) { - val col = offset - segmentTree.get(line).left - line + 1 to col + 1 + val column = offset - segmentTree.get(line).left + line + 1 to column + 1 } else { 1 to 1 } } } -private class SegmentTree( - sortedArray: Array -) { +private class SegmentTree(sortedArray: IntArray) { init { require(sortedArray.size > 1) { "At least two data points are required" } @@ -50,22 +46,19 @@ private class SegmentTree( Segment(element, sortedArray[index + 1] - 1) } - fun get(i: Int): Segment = segments[i] - fun indexOf(v: Int): Int = binarySearch(v, 0, segments.size - 1) + fun get(index: Int): Segment = segments[index] + + fun indexOf(index: Int): Int = binarySearch(index, 0, segments.size - 1) - private fun binarySearch( - v: Int, - l: Int, - r: Int - ): Int = when { - l > r -> -1 + private fun binarySearch(compareElement: Int, left: Int, right: Int): Int = when { + left > right -> -1 else -> { - val i = l + (r - l) / 2 - val s = segments[i] - if (v < s.left) { - binarySearch(v, l, i - 1) + val index = left + (right - left) / 2 + val midElement = segments[index] + if (compareElement < midElement.left) { + binarySearch(compareElement, left, index - 1) } else { - if (s.right < v) binarySearch(v, i + 1, r) else i + if (midElement.right < compareElement) binarySearch(compareElement, index + 1, right) else index } } } From a1e573e2c6b28a07f13976bccd1d52b1c90937d2 Mon Sep 17 00:00:00 2001 From: kentr0w Date: Wed, 21 Oct 2020 12:58:57 +0300 Subject: [PATCH 3/3] Remove deprecated calculateLineColByOffset methods from Ktlint ### What's done: Added fixme --- .../org/cqfn/diktat/ruleset/utils/PositionInTextLocator.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PositionInTextLocator.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PositionInTextLocator.kt index a184e282a4..0b126174c4 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PositionInTextLocator.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/utils/PositionInTextLocator.kt @@ -1,5 +1,6 @@ package org.cqfn.diktat.ruleset.utils +//fixme this code is copy-pasted from ktlint. Change it internal typealias LineAndColumn = Pair /**