From 37a7044e74fd36d44b1dfd70038009fe1fea818b Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Thu, 26 Jan 2023 17:09:13 +0100 Subject: [PATCH] FIR LT: fix line offsets calculations for text files with crlf #KT-55886 fixed --- .../kotlin/KtSourceFileLinesMapping.kt | 2 +- .../kotlin/lightTree/LightTreeParsingTest.kt | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 compiler/tests/org/jetbrains/kotlin/lightTree/LightTreeParsingTest.kt diff --git a/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceFileLinesMapping.kt b/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceFileLinesMapping.kt index 5630d9c08a5..66ae3b0901b 100644 --- a/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceFileLinesMapping.kt +++ b/compiler/frontend.common/src/org/jetbrains/kotlin/KtSourceFileLinesMapping.kt @@ -91,7 +91,7 @@ fun InputStreamReader.readSourceFileWithMapping(): Pair { - lineOffsets[lineOffsets.size - 1] = charsRead + charsRead-- skipNextLf = false } c == '\n' || c == '\r' -> { diff --git a/compiler/tests/org/jetbrains/kotlin/lightTree/LightTreeParsingTest.kt b/compiler/tests/org/jetbrains/kotlin/lightTree/LightTreeParsingTest.kt new file mode 100644 index 00000000000..b040fffe41d --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/lightTree/LightTreeParsingTest.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.lightTree + +import com.intellij.lang.LighterASTNode +import com.intellij.openapi.util.Ref +import com.intellij.util.diff.FlyweightCapableTreeStructure +import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir +import org.jetbrains.kotlin.readSourceFileWithMapping +import org.junit.Assert +import org.junit.Test +import java.io.ByteArrayInputStream + +class LightTreeParsingTest { + + @Test + fun testLightTreeReadLineEndings() { + fun String.makeCodeMappingAndLines() = run { + val (code, mapping) = ByteArrayInputStream(toByteArray()).reader().readSourceFileWithMapping() + val lines = + LightTree2Fir.buildLightTree(code).getChildrenAsArray().mapNotNull { it?.startOffset }.map { mapping.getLineByOffset(it) } + Triple(code, mapping, lines) + } + + val (codeFromTextWithLf, mappingFromTextWithLf, linesFromTextWithLf) = MULTILINE_SOURCE.makeCodeMappingAndLines() + + val (codeFromTextWithCrLf, mappingFromTextWithCrLf, linesFromTextWithCrLf) = + MULTILINE_SOURCE.replace("\n", "\r\n").makeCodeMappingAndLines() + + // classic Mac OS line endings are probably not to be found in the wild, but checking the support nevertheless + val (codeFromTextWithCr, mappingFromTextWithCr, linesFromTextWithCr) = + MULTILINE_SOURCE.replace("\n", "\r").makeCodeMappingAndLines() + + Assert.assertEquals(codeFromTextWithLf.toString(), codeFromTextWithCrLf.toString()) + Assert.assertEquals(codeFromTextWithLf.toString(), codeFromTextWithCr.toString()) + + Assert.assertEquals(mappingFromTextWithLf.linesCount, mappingFromTextWithCrLf.linesCount) + Assert.assertEquals(mappingFromTextWithLf.linesCount, mappingFromTextWithCr.linesCount) + + Assert.assertEquals(linesFromTextWithLf, linesFromTextWithCrLf) + Assert.assertEquals(linesFromTextWithLf, linesFromTextWithCr) + + Assert.assertEquals(mappingFromTextWithLf.lastOffset, mappingFromTextWithCrLf.lastOffset) + Assert.assertEquals(mappingFromTextWithLf.lastOffset, mappingFromTextWithCr.lastOffset) + } +} + +private fun FlyweightCapableTreeStructure.getChildrenAsArray(): Array { + val kidsRef = Ref>() + getChildren(root, kidsRef) + return kidsRef.get() +} + +private const val MULTILINE_SOURCE = """ +val a = 1 + val b = 2 + val c = 3 + val d = 4 +""" \ No newline at end of file