diff --git a/compiler/frontend/src/org/jetbrains/kotlin/checkers/utils/CheckerTestUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/checkers/utils/CheckerTestUtil.kt index f26b939d807..8c50415868d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/checkers/utils/CheckerTestUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/checkers/utils/CheckerTestUtil.kt @@ -60,7 +60,7 @@ object CheckerTestUtil { const val OLD_INFERENCE_PREFIX = "OI" private const val IGNORE_DIAGNOSTIC_PARAMETER = "IGNORE" - private const val INDIVIDUAL_DIAGNOSTIC = """(\w+;)?(\w+:)?(\w+)(?:\(((?:".*?")(?:,\s*".*?")*)\))?""" + private const val INDIVIDUAL_DIAGNOSTIC = """(\w+;)?(\w+:)?(\w+)(\{[\w;]+})?(?:\(((?:".*?")(?:,\s*".*?")*)\))?""" val rangeStartOrEndPattern = Pattern.compile("()|()") val individualDiagnosticPattern: Pattern = Pattern.compile(INDIVIDUAL_DIAGNOSTIC) diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/AbstractCodeMetaInfoTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/AbstractCodeMetaInfoTest.kt index 4dd3922b15a..b82e39a2f52 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/AbstractCodeMetaInfoTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/AbstractCodeMetaInfoTest.kt @@ -32,13 +32,12 @@ import org.jetbrains.kotlin.checkers.BaseDiagnosticsTest import org.jetbrains.kotlin.checkers.diagnostics.SyntaxErrorDiagnostic import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil import org.jetbrains.kotlin.checkers.utils.DiagnosticsRenderingConfiguration +import org.jetbrains.kotlin.daemon.common.OSKind import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.diagnostics.AbstractDiagnostic +import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade -import org.jetbrains.kotlin.idea.codeMetaInfo.models.CodeMetaInfoFactory -import org.jetbrains.kotlin.idea.codeMetaInfo.models.DiagnosticCodeMetaInfo -import org.jetbrains.kotlin.idea.codeMetaInfo.models.HighlightingCodeMetaInfo -import org.jetbrains.kotlin.idea.codeMetaInfo.models.ICodeMetaInfo +import org.jetbrains.kotlin.idea.codeMetaInfo.models.* import org.jetbrains.kotlin.idea.codeMetaInfo.renderConfigurations.AbstractCodeMetaInfoRenderConfiguration import org.jetbrains.kotlin.idea.codeMetaInfo.renderConfigurations.DiagnosticCodeMetaInfoRenderConfiguration import org.jetbrains.kotlin.idea.codeMetaInfo.renderConfigurations.HighlightingRenderConfiguration @@ -53,12 +52,15 @@ import org.jetbrains.kotlin.test.KotlinTestUtils import java.io.File import java.nio.file.Paths -class CodeMetaInfoTestCase(val codeMetaInfoTypes: Collection) : DaemonAnalyzerTestCase() { +class CodeMetaInfoTestCase( + val codeMetaInfoTypes: Collection, + val checkNoDiagnosticError: Boolean = false +) : DaemonAnalyzerTestCase() { fun getDiagnosticCodeMetaInfos( - configuration: DiagnosticCodeMetaInfoRenderConfiguration?, + configuration: DiagnosticCodeMetaInfoRenderConfiguration = DiagnosticCodeMetaInfoRenderConfiguration(), parseDirective: Boolean = true - ): Collection { + ): List { val tempSourceKtFile = PsiManager.getInstance(project).findFile(file.virtualFile) as KtFile val resolutionFacade = tempSourceKtFile.getResolutionFacade() val (bindingContext, moduleDescriptor) = resolutionFacade.analyzeWithAllCompilerChecks(listOf(tempSourceKtFile)) @@ -77,23 +79,23 @@ class CodeMetaInfoTestCase(val codeMetaInfoTypes: Collection { + fun getLineMarkerCodeMetaInfos(configuration: LineMarkerRenderConfiguration): Collection { if ("!CHECK_HIGHLIGHTING" in file.text) return emptyList() CodeInsightTestFixtureImpl.instantiateAndRun(file, editor, TIntArrayList().toNativeArray(), false) val lineMarkers = DaemonCodeAnalyzerImpl.getLineMarkers(getDocument(file), project) - return CodeMetaInfoFactory.getCodeMetaInfo(lineMarkers, configuration) + return getCodeMetaInfo(lineMarkers, configuration) } - fun getHighlightingCodeMetaInfos(configuration: HighlightingRenderConfiguration?): Collection { + fun getHighlightingCodeMetaInfos(configuration: HighlightingRenderConfiguration): Collection { val infos = CodeInsightTestFixtureImpl.instantiateAndRun(file, editor, TIntArrayList().toNativeArray(), false) - return CodeMetaInfoFactory.getCodeMetaInfo(infos, configuration) + return getCodeMetaInfo(infos, configuration) } fun checkFile(expectedFile: File, project: Project, editor: Editor) { @@ -113,8 +115,7 @@ class CodeMetaInfoTestCase(val codeMetaInfoTypes: Collection() + val codeMetaInfoForCheck = mutableListOf() PsiDocumentManager.getInstance(myProject).commitAllDocuments() //to load text @@ -144,22 +145,46 @@ class CodeMetaInfoTestCase(val codeMetaInfoTypes: Collection() + getDiagnosticCodeMetaInfos(DiagnosticCodeMetaInfoRenderConfiguration(), false).filterIsInstance() ) } - + val parsedMetaInfo = CodeMetaInfoParser.getCodeMetaInfoFromText(expectedFile.readText()).toMutableList() + codeMetaInfoForCheck.forEach { codeMetaInfo -> + val correspondingParsed = parsedMetaInfo.firstOrNull { it == codeMetaInfo } + if (correspondingParsed != null) { + parsedMetaInfo.remove(correspondingParsed) + codeMetaInfo.platforms.addAll(correspondingParsed.platforms) + if (correspondingParsed.platforms.isNotEmpty() && OSKind.current.toString() !in correspondingParsed.platforms) + codeMetaInfo.platforms.add(OSKind.current.toString()) + } + } + if (parsedMetaInfo.isNotEmpty()) + parsedMetaInfo.forEach { + if (it.platforms.isNotEmpty() && OSKind.current.toString() !in it.platforms) codeMetaInfoForCheck.add( + it + ) + } val textWithCodeMetaInfo = CodeMetaInfoRenderer.renderTagsToText(codeMetaInfoForCheck, myEditor.document.text) KotlinTestUtils.assertEqualsToFile( expectedFile, textWithCodeMetaInfo.toString() ) + + if (checkNoDiagnosticError) { + val diagnosticsErrors = + getDiagnosticCodeMetaInfos().filter { (it as DiagnosticCodeMetaInfo).diagnostic.severity == Severity.ERROR } + assertTrue( + "Diagnostics with severity ERROR were found: ${diagnosticsErrors.joinToString { it.asString() }}", + diagnosticsErrors.isEmpty() + ) + } } private fun checkHighlightErrorItemsInDiagnostics( diagnostics: Collection ) { - val highlightItems: List = - getHighlightingCodeMetaInfos(null).filter { (it as HighlightingCodeMetaInfo).highlightingInfo.severity == HighlightSeverity.ERROR } + val highlightItems: List = + getHighlightingCodeMetaInfos(HighlightingRenderConfiguration()).filter { (it as HighlightingCodeMetaInfo).highlightingInfo.severity == HighlightSeverity.ERROR } highlightItems.forEach { highlightingCodeMetaInfo -> assert( @@ -201,7 +226,7 @@ abstract class AbstractHighlightingCodeMetaInfoTest : AbstractCodeMetaInfoTest() } abstract class AbstractCodeMetaInfoTest : AbstractMultiModuleTest() { - + open val checkNoDiagnosticError get() = false open fun getConfigurations() = listOf( DiagnosticCodeMetaInfoRenderConfiguration(), LineMarkerRenderConfiguration(), @@ -218,7 +243,7 @@ abstract class AbstractCodeMetaInfoTest : AbstractMultiModuleTest() { fun doTest(testDataPath: String) { val testRoot = File(testDataPath) - val checker = CodeMetaInfoTestCase(getConfigurations()) + val checker = CodeMetaInfoTestCase(getConfigurations(), checkNoDiagnosticError) setupProject(testDataPath) for (module in ModuleManager.getInstance(project).modules) { @@ -237,16 +262,13 @@ abstract class AbstractCodeMetaInfoTest : AbstractMultiModuleTest() { val tempRootPath = Paths.get(containingRoot.path) val tempProjectDirPath = tempRootPath.parent val tempSourcePath = Paths.get(path) - val relativeToProjectRootPath = tempProjectDirPath.relativize(tempSourcePath) - val testSourcesProjectDirPath = testDir.toPath() val testSourcePath = testSourcesProjectDirPath.resolve(relativeToProjectRootPath) require(testSourcePath.exists()) { "Can't find file in testdata for copied file $this: checked at path ${testSourcePath.toAbsolutePath()}" } - return testSourcePath.toFile() } } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/CodeMetaInfoParser.kt b/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/CodeMetaInfoParser.kt new file mode 100644 index 00000000000..0888b5b084e --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/CodeMetaInfoParser.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2010-2020 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.idea.codeMetaInfo + +import com.intellij.util.containers.Stack +import org.jetbrains.kotlin.idea.codeMetaInfo.models.ParsedCodeMetaInfo +import org.junit.Assert + +object CodeMetaInfoParser { + private val openingRegex = "(]+?)!>)".toRegex() + private val closingRegex = "()".toRegex() + + private val descriptionRegex = "\\(\".*?\"\\)".toRegex() + private val platformRegex = "\\{(.+)}".toRegex() + + fun getCodeMetaInfoFromText(renderedText: String): List { + var text = renderedText + val openingMatchResults = Stack() + val closingMatchResults = Stack() + val result = mutableListOf() + + while (true) { + var openingStartOffset = Int.MAX_VALUE + var closingStartOffset = Int.MAX_VALUE + val opening = openingRegex.find(text) + val closing = closingRegex.find(text) + if (opening == null && closing == null) break + + if (opening != null) + openingStartOffset = opening.range.first + if (closing != null) + closingStartOffset = closing.range.first + + text = if (openingStartOffset < closingStartOffset) { + openingMatchResults.push(opening) + text.removeRange(openingStartOffset, opening!!.range.last + 1) + } else { + closingMatchResults.push(closing) + text.removeRange(closingStartOffset, closing!!.range.last + 1) + } + } + if (openingMatchResults.size != closingMatchResults.size) { + Assert.fail("Opening and closing tags counts are not equals") + } + while (!openingMatchResults.isEmpty()) { + val openingMatchResult = openingMatchResults.pop() + val closingMatchResult = closingMatchResults.pop() + val metaInfoWithoutParams = openingMatchResult.groups[2]!!.value.replace(descriptionRegex, "") + metaInfoWithoutParams.split(",").forEach { + val tag = platformRegex.replace(it, "").trim() + val platforms = + if (platformRegex.containsMatchIn(it)) platformRegex.find(it)!!.destructured.component1().split(";") else listOf() + result.add( + ParsedCodeMetaInfo( + openingMatchResult.range.first, closingMatchResult.range.first, platforms.toMutableList(), tag, + ) + ) + } + } + return result + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/CodeMetaInfoRenderer.kt b/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/CodeMetaInfoRenderer.kt index 326bfb18b04..a1f6da6e64f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/CodeMetaInfoRenderer.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/CodeMetaInfoRenderer.kt @@ -7,13 +7,12 @@ package org.jetbrains.kotlin.idea.codeMetaInfo import com.intellij.util.containers.Stack import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil -import org.jetbrains.kotlin.idea.codeMetaInfo.models.ICodeMetaInfo +import org.jetbrains.kotlin.idea.codeMetaInfo.models.CodeMetaInfo import java.io.File object CodeMetaInfoRenderer { - fun renderTagsToText( - codeMetaInfos: List, + codeMetaInfos: List, originalText: String ): StringBuffer { val result = StringBuffer() @@ -22,25 +21,18 @@ object CodeMetaInfoRenderer { return result } val sortedMetaInfos = getSortedCodeMetaInfos(codeMetaInfos) - val opened = Stack() + val opened = Stack() - for (i in originalText.indices) { - val c = originalText[i] - var prev: ICodeMetaInfo? = null - - while (!opened.isEmpty() && i == opened.peek().end) { - if (prev == null || prev.start != opened.peek().start) - closeString(result) - prev = opened.pop() - } - if (sortedMetaInfos.any { it.start == i }) { + for ((i, c) in originalText.withIndex()) { + checkOpenedAndCloseStringIfNeeded(opened, i, result) + val matchedCodeMetaInfos = sortedMetaInfos.filter { it.start == i } + if (matchedCodeMetaInfos.isNotEmpty()) { openStartTag(result) - val matchedCodeMetaInfos = sortedMetaInfos.filter { it.start == i }.toMutableList() val iterator = matchedCodeMetaInfos.listIterator() - var current: ICodeMetaInfo? = iterator.next() + var current: CodeMetaInfo? = iterator.next() while (current != null) { - val next: ICodeMetaInfo? = if (iterator.hasNext()) iterator.next() else null + val next: CodeMetaInfo? = if (iterator.hasNext()) iterator.next() else null opened.push(current) result.append(current.asString()) when { @@ -56,30 +48,27 @@ object CodeMetaInfoRenderer { } result.append(c) } - var prev: ICodeMetaInfo? = null - - while (!opened.isEmpty() && originalText.length == opened.peek().end) { - if (prev == null || prev.start != opened.peek().start) - closeString(result) - prev = opened.pop() - } + checkOpenedAndCloseStringIfNeeded(opened, originalText.length, result) return result } - private fun getSortedCodeMetaInfos( - metaInfos: Collection, - ): MutableList { - val result = metaInfos.toMutableList() - result.sortWith(Comparator { d1: ICodeMetaInfo, d2: ICodeMetaInfo -> - if (d1.start != d2.start) d1.start - d2.start else d2.end - d1.end - }) - return result + private fun getSortedCodeMetaInfos(metaInfos: Collection): List { + return metaInfos.sortedWith(compareBy { it.start }.then(compareByDescending { it.end })) } private fun closeString(result: StringBuffer) = result.append("") private fun openStartTag(result: StringBuffer) = result.append("") private fun closeStartAndOpenNewTag(result: StringBuffer) = result.append("!>, end: Int, result: StringBuffer) { + var prev: CodeMetaInfo? = null + while (!opened.isEmpty() && end == opened.peek().end) { + if (prev == null || prev.start != opened.peek().start) + closeString(result) + prev = opened.pop() + } + } } fun clearFileFromDiagnosticMarkup(file: File) { diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/models/CodeMetaInfo.kt b/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/models/CodeMetaInfo.kt index 2e5fea44887..8e483721a5a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/models/CodeMetaInfo.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/models/CodeMetaInfo.kt @@ -16,91 +16,103 @@ import org.jetbrains.kotlin.idea.codeMetaInfo.renderConfigurations.LineMarkerRen import org.jetbrains.kotlin.idea.editor.fixers.end import org.jetbrains.kotlin.idea.editor.fixers.start -interface ICodeMetaInfo { - +interface CodeMetaInfo { val start: Int val end: Int - val renderConfiguration: AbstractCodeMetaInfoRenderConfiguration? + val renderConfiguration: AbstractCodeMetaInfoRenderConfiguration + val platforms: MutableList fun asString(): String + fun getTag(): String } class DiagnosticCodeMetaInfo( override val start: Int, override val end: Int, - override val renderConfiguration: AbstractCodeMetaInfoRenderConfiguration?, + override val renderConfiguration: AbstractCodeMetaInfoRenderConfiguration, val diagnostic: Diagnostic -) : - ICodeMetaInfo { +) : CodeMetaInfo { + override val platforms: MutableList = mutableListOf() - override fun asString(): String { - return renderConfiguration!!.asString(this) - } + override fun asString() = renderConfiguration.asString(this) + + override fun getTag() = (renderConfiguration as DiagnosticCodeMetaInfoRenderConfiguration).getTag(this) } class LineMarkerCodeMetaInfo( - override val renderConfiguration: AbstractCodeMetaInfoRenderConfiguration?, + override val renderConfiguration: AbstractCodeMetaInfoRenderConfiguration, val lineMarker: LineMarkerInfo<*> -) : ICodeMetaInfo { - +) : CodeMetaInfo { override val start: Int get() = lineMarker.startOffset override val end: Int get() = lineMarker.endOffset + override val platforms: MutableList = mutableListOf() - val withDescription = true + override fun asString() = renderConfiguration.asString(this) - override fun asString(): String { - return renderConfiguration!!.asString(this) - } + override fun getTag() = (renderConfiguration as LineMarkerRenderConfiguration).getTag() } class HighlightingCodeMetaInfo( - override val renderConfiguration: AbstractCodeMetaInfoRenderConfiguration?, + override val renderConfiguration: AbstractCodeMetaInfoRenderConfiguration, val highlightingInfo: HighlightInfo -) : ICodeMetaInfo { - +) : CodeMetaInfo { override val start: Int get() = highlightingInfo.startOffset override val end: Int get() = highlightingInfo.endOffset + override val platforms: MutableList = mutableListOf() - override fun asString(): String { - return renderConfiguration!!.asString(this) + override fun asString() = renderConfiguration.asString(this) + + override fun getTag() = (renderConfiguration as HighlightingRenderConfiguration).getTag() +} + +class ParsedCodeMetaInfo( + override val start: Int, + override val end: Int, + override val platforms: MutableList, + private val tag: String +) : CodeMetaInfo { + override val renderConfiguration = object : AbstractCodeMetaInfoRenderConfiguration(false) {} + + override fun asString() = renderConfiguration.asString(this) + + override fun equals(other: Any?): Boolean { + if (other == null || other !is CodeMetaInfo) return false + return this.tag == other.getTag() && this.start == other.start && this.end == other.end + } + + override fun getTag() = tag +} + +fun createCodeMetaInfo(obj: Any, renderConfiguration: AbstractCodeMetaInfoRenderConfiguration): List { + fun errorMessage() = "Unexpected render configuration for object $obj" + return when (obj) { + is Diagnostic -> { + require(renderConfiguration is DiagnosticCodeMetaInfoRenderConfiguration, ::errorMessage) + obj.textRanges.map { DiagnosticCodeMetaInfo(it.start, it.end, renderConfiguration, obj) } + } + is ActualDiagnostic -> { + require(renderConfiguration is DiagnosticCodeMetaInfoRenderConfiguration, ::errorMessage) + obj.diagnostic.textRanges.map { DiagnosticCodeMetaInfo(it.start, it.end, renderConfiguration, obj.diagnostic) } + } + is HighlightInfo -> { + require(renderConfiguration is HighlightingRenderConfiguration, ::errorMessage) + listOf(HighlightingCodeMetaInfo(renderConfiguration, obj)) + } + is LineMarkerInfo<*> -> { + require(renderConfiguration is LineMarkerRenderConfiguration, ::errorMessage) + listOf(LineMarkerCodeMetaInfo(renderConfiguration, obj)) + } + else -> throw IllegalArgumentException("Unknown type for creating CodeMetaInfo object $obj") } } -object CodeMetaInfoFactory { - private fun createCodeMetaInfo(obj: Any, renderConfiguration: AbstractCodeMetaInfoRenderConfiguration?): Collection { - return when (obj) { - is Diagnostic -> { - if (renderConfiguration != null && renderConfiguration !is DiagnosticCodeMetaInfoRenderConfiguration) - throw IllegalArgumentException("Unexpected render configuration for CodeMetaInfo object $obj") - obj.textRanges.map { DiagnosticCodeMetaInfo(it.start, it.end, renderConfiguration, obj) } - } - is ActualDiagnostic -> { - if (renderConfiguration != null && renderConfiguration !is DiagnosticCodeMetaInfoRenderConfiguration) - throw IllegalArgumentException("Unexpected render configuration for CodeMetaInfo object $obj") - obj.diagnostic.textRanges.map { DiagnosticCodeMetaInfo(it.start, it.end, renderConfiguration, obj.diagnostic) } - } - is HighlightInfo -> { - if (renderConfiguration != null && renderConfiguration !is HighlightingRenderConfiguration) - throw IllegalArgumentException("Unexpected render configuration for CodeMetaInfo object $obj") - listOf(HighlightingCodeMetaInfo(renderConfiguration, obj)) - } - is LineMarkerInfo<*> -> { - if (renderConfiguration != null && renderConfiguration !is LineMarkerRenderConfiguration) - throw IllegalArgumentException("Unexpected render configuration for CodeMetaInfo object $obj") - listOf(LineMarkerCodeMetaInfo(renderConfiguration, obj)) - } - else -> throw IllegalArgumentException("Unknown type for creating CodeMetaInfo object $obj") - } - } - - fun getCodeMetaInfo( - objects: Collection, - renderConfiguration: AbstractCodeMetaInfoRenderConfiguration? - ): Collection { - return objects.flatMap { createCodeMetaInfo(it, renderConfiguration) } - } -} \ No newline at end of file +fun getCodeMetaInfo( + objects: List, + renderConfiguration: AbstractCodeMetaInfoRenderConfiguration +): List { + return objects.flatMap { createCodeMetaInfo(it, renderConfiguration) } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/renderConfigurations/AbstractCodeMetaInfoRenderConfiguration.kt b/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/renderConfigurations/AbstractCodeMetaInfoRenderConfiguration.kt index f5a86b4caca..efb82bb2380 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/renderConfigurations/AbstractCodeMetaInfoRenderConfiguration.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeMetaInfo/renderConfigurations/AbstractCodeMetaInfoRenderConfiguration.kt @@ -5,8 +5,6 @@ package org.jetbrains.kotlin.idea.codeMetaInfo.renderConfigurations -import com.intellij.codeInsight.daemon.impl.HighlightInfo -import com.intellij.lang.annotation.HighlightSeverity import com.intellij.openapi.util.text.StringUtil import com.intellij.util.containers.ContainerUtil import org.jetbrains.kotlin.checkers.diagnostics.factories.DebugInfoDiagnosticFactory1 @@ -14,39 +12,48 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.rendering.* import org.jetbrains.kotlin.idea.codeMetaInfo.models.DiagnosticCodeMetaInfo import org.jetbrains.kotlin.idea.codeMetaInfo.models.HighlightingCodeMetaInfo -import org.jetbrains.kotlin.idea.codeMetaInfo.models.ICodeMetaInfo +import org.jetbrains.kotlin.idea.codeMetaInfo.models.CodeMetaInfo import org.jetbrains.kotlin.idea.codeMetaInfo.models.LineMarkerCodeMetaInfo abstract class AbstractCodeMetaInfoRenderConfiguration(var renderParams: Boolean = true) { - abstract fun asString(codeMetaInfo: ICodeMetaInfo): String + open fun asString(codeMetaInfo: CodeMetaInfo) = codeMetaInfo.getTag() + getPlatformsString(codeMetaInfo) - open fun getAdditionalTags(codeMetaInfo: ICodeMetaInfo) = "" + open fun getAdditionalParams(codeMetaInfo: CodeMetaInfo) = "" protected fun sanitizeLineMarkerTooltip(originalText: String?): String { if (originalText == null) return "null" - val noHtmlTags = StringUtil.removeHtmlTags(originalText) + val noHtmlTags = StringUtil.removeHtmlTags(originalText).replace(" ", "") return sanitizeLineBreaks(noHtmlTags) } protected fun sanitizeLineBreaks(originalText: String): String { return StringUtil.replace(originalText, "\n", " ") } + + protected fun getPlatformsString(codeMetaInfo: CodeMetaInfo): String { + if (codeMetaInfo.platforms.isEmpty()) return "" + return "{${codeMetaInfo.platforms.joinToString(";")}}" + } } open class DiagnosticCodeMetaInfoRenderConfiguration( val withNewInference: Boolean = true, val renderSeverity: Boolean = false ) : AbstractCodeMetaInfoRenderConfiguration() { + private val crossPlatformLineBreak = """\r?\n""".toRegex() - override fun asString(codeMetaInfo: ICodeMetaInfo): String { + override fun asString(codeMetaInfo: CodeMetaInfo): String { if (codeMetaInfo !is DiagnosticCodeMetaInfo) return "" - return (getTag(codeMetaInfo) + if (renderParams) "(\"${getParamsString(codeMetaInfo)}\")" else "") - .replace(Regex("""\r?\n"""), "") + return (getTag(codeMetaInfo) + + getPlatformsString(codeMetaInfo) + + getParamsString(codeMetaInfo)) + .replace(crossPlatformLineBreak, "") } private fun getParamsString(codeMetaInfo: DiagnosticCodeMetaInfo): String { + if (!renderParams) return "" val params = mutableListOf() val renderer = when (codeMetaInfo.diagnostic.factory) { is DebugInfoDiagnosticFactory1 -> DiagnosticWithParameters1Renderer( @@ -62,25 +69,23 @@ open class DiagnosticCodeMetaInfoRenderConfiguration( if (renderSeverity) params.add("severity='${codeMetaInfo.diagnostic.severity}'") - params.add(getAdditionalTags(codeMetaInfo)) + params.add(getAdditionalParams(codeMetaInfo)) - return params.filter { it.isNotEmpty() }.joinToString("; ") + return "(\"${params.filter { it.isNotEmpty() }.joinToString("; ")}\")" } - private fun getTag(codeMetaInfo: DiagnosticCodeMetaInfo): String { + fun getTag(codeMetaInfo: DiagnosticCodeMetaInfo): String { return codeMetaInfo.diagnostic.factory.name } } open class LineMarkerRenderConfiguration(val renderDescription: Boolean = true) : AbstractCodeMetaInfoRenderConfiguration() { - override fun asString(codeMetaInfo: ICodeMetaInfo): String { + override fun asString(codeMetaInfo: CodeMetaInfo): String { if (codeMetaInfo !is LineMarkerCodeMetaInfo) return "" return getTag() + if (renderParams) "(\"${getParamsString(codeMetaInfo)}\")" else "" } - private fun getTag(): String { - return "LINE_MARKER" - } + fun getTag() = "LINE_MARKER" private fun getParamsString(lineMarkerCodeMetaInfo: LineMarkerCodeMetaInfo): String { val params = mutableListOf() @@ -88,7 +93,7 @@ open class LineMarkerRenderConfiguration(val renderDescription: Boolean = true) if (renderDescription) params.add("descr='${sanitizeLineMarkerTooltip(lineMarkerCodeMetaInfo.lineMarker.lineMarkerTooltip)}'") - params.add(getAdditionalTags(lineMarkerCodeMetaInfo)) + params.add(getAdditionalParams(lineMarkerCodeMetaInfo)) return params.filter { it.isNotEmpty() }.joinToString("; ") } @@ -100,32 +105,25 @@ open class HighlightingRenderConfiguration( val renderSeverity: Boolean = true ) : AbstractCodeMetaInfoRenderConfiguration() { - override fun asString(codeMetaInfo: ICodeMetaInfo): String { + override fun asString(codeMetaInfo: CodeMetaInfo): String { if (codeMetaInfo !is HighlightingCodeMetaInfo) return "" return getTag() + if (renderParams) "(${getParamsString(codeMetaInfo)})" else "" } - private fun getTag(): String { - return "HIGHLIGHTING" - } + fun getTag() = "HIGHLIGHTING" private fun getParamsString(highlightingCodeMetaInfo: HighlightingCodeMetaInfo): String { val params = mutableListOf() if (renderSeverity) - params.add("severity='${getSeverity(highlightingCodeMetaInfo.highlightingInfo)}'") + params.add("severity='${highlightingCodeMetaInfo.highlightingInfo.severity}'") if (renderDescription) params.add("descr='${sanitizeLineBreaks(highlightingCodeMetaInfo.highlightingInfo.description)}'") if (renderTextAttributesKey) params.add("textAttributesKey='${highlightingCodeMetaInfo.highlightingInfo.forcedTextAttributesKey}'") - params.add(getAdditionalTags(highlightingCodeMetaInfo)) + params.add(getAdditionalParams(highlightingCodeMetaInfo)) return params.filter { it.isNotEmpty() }.joinToString("; ") } - - private fun getSeverity(highlightingInfo: HighlightInfo): String { - return if (highlightingInfo.severity == HighlightSeverity.INFORMATION) "info" else highlightingInfo.severity.toString() - .toLowerCase() - } } \ No newline at end of file