New highlighting/line markers/diagnostics test infrastructure

The current test framework has a number of shortcomings, such as
different markups for different kinds, those formats can not be
mixed in one test file, lacks composability, re-use of it is complicated
This commit contains the first version of the new test runner
to which tests will be migrated in the future.
This commit is contained in:
Alexander Dudinsky
2020-09-14 12:21:24 +03:00
parent 994cb6f28e
commit ac98bc9853
5 changed files with 581 additions and 1 deletions
@@ -62,7 +62,7 @@ object CheckerTestUtil {
private const val IGNORE_DIAGNOSTIC_PARAMETER = "IGNORE"
private const val INDIVIDUAL_DIAGNOSTIC = """(\w+;)?(\w+:)?(\w+)(?:\(((?:".*?")(?:,\s*".*?")*)\))?"""
internal val rangeStartOrEndPattern = Pattern.compile("(<!$INDIVIDUAL_DIAGNOSTIC(,\\s*$INDIVIDUAL_DIAGNOSTIC)*!>)|(<!>)")
val rangeStartOrEndPattern = Pattern.compile("(<!$INDIVIDUAL_DIAGNOSTIC(,\\s*$INDIVIDUAL_DIAGNOSTIC)*!>)|(<!>)")
val individualDiagnosticPattern: Pattern = Pattern.compile(INDIVIDUAL_DIAGNOSTIC)
fun getDiagnosticsIncludingSyntaxErrors(
@@ -0,0 +1,252 @@
/*
* 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.codeInsight.daemon.DaemonAnalyzerTestCase
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
import com.intellij.lang.annotation.HighlightSeverity
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.PsiManagerImpl
import com.intellij.psi.impl.cache.CacheManager
import com.intellij.psi.impl.source.tree.PsiErrorElementImpl
import com.intellij.psi.impl.source.tree.TreeElement
import com.intellij.psi.impl.source.tree.TreeUtil
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.UsageSearchContext
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
import com.intellij.testFramework.runInEdtAndWait
import com.intellij.util.io.exists
import gnu.trove.TIntArrayList
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.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.diagnostics.AbstractDiagnostic
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.renderConfigurations.AbstractCodeMetaInfoRenderConfiguration
import org.jetbrains.kotlin.idea.codeMetaInfo.renderConfigurations.DiagnosticCodeMetaInfoRenderConfiguration
import org.jetbrains.kotlin.idea.codeMetaInfo.renderConfigurations.HighlightingRenderConfiguration
import org.jetbrains.kotlin.idea.codeMetaInfo.renderConfigurations.LineMarkerRenderConfiguration
import org.jetbrains.kotlin.idea.multiplatform.setupMppProjectFromTextFile
import org.jetbrains.kotlin.idea.resolve.getDataFlowValueFactory
import org.jetbrains.kotlin.idea.resolve.getLanguageVersionSettings
import org.jetbrains.kotlin.idea.stubs.AbstractMultiModuleTest
import org.jetbrains.kotlin.idea.util.sourceRoots
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
import java.nio.file.Paths
class CodeMetaInfoTestCase(val codeMetaInfoTypes: Collection<AbstractCodeMetaInfoRenderConfiguration>) : DaemonAnalyzerTestCase() {
fun getDiagnosticCodeMetaInfos(
configuration: DiagnosticCodeMetaInfoRenderConfiguration?,
parseDirective: Boolean = true
): Collection<ICodeMetaInfo> {
val tempSourceKtFile = PsiManager.getInstance(project).findFile(file.virtualFile) as KtFile
val resolutionFacade = tempSourceKtFile.getResolutionFacade()
val (bindingContext, moduleDescriptor) = resolutionFacade.analyzeWithAllCompilerChecks(listOf(tempSourceKtFile))
val directives = KotlinTestUtils.parseDirectives(file.text)
val diagnosticsFilter = BaseDiagnosticsTest.parseDiagnosticFilterDirective(directives, allowUnderscoreUsage = false)
val diagnostics = CheckerTestUtil.getDiagnosticsIncludingSyntaxErrors(
bindingContext,
file,
markDynamicCalls = false,
dynamicCallDescriptors = mutableListOf(),
configuration = DiagnosticsRenderingConfiguration(
platform = null, // we don't need to attach platform-description string to diagnostic here
withNewInference = false,
languageVersionSettings = resolutionFacade.getLanguageVersionSettings(),
),
dataFlowValueFactory = resolutionFacade.getDataFlowValueFactory(),
moduleDescriptor = moduleDescriptor as ModuleDescriptorImpl
).map { it.diagnostic }.filter { !parseDirective || diagnosticsFilter.value(it) }
configuration?.renderParams = directives.contains(BaseDiagnosticsTest.RENDER_DIAGNOSTICS_MESSAGES)
return CodeMetaInfoFactory.getCodeMetaInfo(diagnostics, configuration)
}
fun getLineMarkerCodeMetaInfos(configuration: LineMarkerRenderConfiguration): Collection<ICodeMetaInfo> {
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)
}
fun getHighlightingCodeMetaInfos(configuration: HighlightingRenderConfiguration?): Collection<ICodeMetaInfo> {
val infos = CodeInsightTestFixtureImpl.instantiateAndRun(file, editor, TIntArrayList().toNativeArray(), false)
return CodeMetaInfoFactory.getCodeMetaInfo(infos, configuration)
}
fun checkFile(expectedFile: File, project: Project, editor: Editor) {
myProject = project
myPsiManager = PsiManager.getInstance(myProject) as PsiManagerImpl
runInEdtAndWait {
setActiveEditor(editor)
check(expectedFile)
}
}
fun checkFile(file: VirtualFile, expectedFile: File, project: Project) {
myProject = project
myPsiManager = PsiManager.getInstance(myProject) as PsiManagerImpl
configureByExistingFile(file)
check(expectedFile)
}
fun check(expectedFile: File) {
val codeMetaInfoForCheck = mutableListOf<ICodeMetaInfo>()
PsiDocumentManager.getInstance(myProject).commitAllDocuments()
//to load text
ApplicationManager.getApplication().runWriteAction { TreeUtil.clearCaches(myFile.node as TreeElement) }
//to initialize caches
if (!DumbService.isDumb(myProject)) {
CacheManager.SERVICE.getInstance(myProject)
.getFilesWithWord("XXX", UsageSearchContext.IN_COMMENTS, GlobalSearchScope.allScope(myProject), true)
}
for (configuration in codeMetaInfoTypes) {
when (configuration) {
is DiagnosticCodeMetaInfoRenderConfiguration -> {
codeMetaInfoForCheck.addAll(getDiagnosticCodeMetaInfos(configuration))
}
is HighlightingRenderConfiguration -> {
codeMetaInfoForCheck.addAll(getHighlightingCodeMetaInfos(configuration))
}
is LineMarkerRenderConfiguration -> {
codeMetaInfoForCheck.addAll(getLineMarkerCodeMetaInfos(configuration))
}
else -> throw IllegalArgumentException("Unexpected code meta info configuration: $configuration")
}
}
if (codeMetaInfoTypes.any { it is DiagnosticCodeMetaInfoRenderConfiguration } &&
!codeMetaInfoTypes.any { it is HighlightingRenderConfiguration }
) {
checkHighlightErrorItemsInDiagnostics(
getDiagnosticCodeMetaInfos(null, false).filterIsInstance<DiagnosticCodeMetaInfo>()
)
}
val textWithCodeMetaInfo = CodeMetaInfoRenderer.renderTagsToText(codeMetaInfoForCheck, myEditor.document.text)
KotlinTestUtils.assertEqualsToFile(
expectedFile,
textWithCodeMetaInfo.toString()
)
}
private fun checkHighlightErrorItemsInDiagnostics(
diagnostics: Collection<DiagnosticCodeMetaInfo>
) {
val highlightItems: List<ICodeMetaInfo> =
getHighlightingCodeMetaInfos(null).filter { (it as HighlightingCodeMetaInfo).highlightingInfo.severity == HighlightSeverity.ERROR }
highlightItems.forEach { highlightingCodeMetaInfo ->
assert(
diagnostics.any { diagnosticCodeMetaInfo ->
diagnosticCodeMetaInfo.start == highlightingCodeMetaInfo.start &&
when (diagnosticCodeMetaInfo.diagnostic) {
is SyntaxErrorDiagnostic -> {
val diagnostic: SyntaxErrorDiagnostic = diagnosticCodeMetaInfo.diagnostic
(highlightingCodeMetaInfo as HighlightingCodeMetaInfo).highlightingInfo.description in (diagnostic.psiElement as PsiErrorElementImpl).errorDescription
}
is AbstractDiagnostic<*> -> {
val diagnostic: AbstractDiagnostic<*> = diagnosticCodeMetaInfo.diagnostic
diagnostic.factory.toString() in (highlightingCodeMetaInfo as HighlightingCodeMetaInfo).highlightingInfo.description
}
else -> throw java.lang.IllegalArgumentException("Unknown diagnostic type: ${diagnosticCodeMetaInfo.diagnostic}")
}
},
) { "Could not find DIAGNOSTIC for ${(highlightingCodeMetaInfo as HighlightingCodeMetaInfo).highlightingInfo}" }
}
}
}
abstract class AbstractDiagnosticCodeMetaInfoTest : AbstractCodeMetaInfoTest() {
override fun getConfigurations() = listOf(
DiagnosticCodeMetaInfoRenderConfiguration()
)
}
abstract class AbstractLineMarkerCodeMetaInfoTest : AbstractCodeMetaInfoTest() {
override fun getConfigurations() = listOf(
LineMarkerRenderConfiguration()
)
}
abstract class AbstractHighlightingCodeMetaInfoTest : AbstractCodeMetaInfoTest() {
override fun getConfigurations() = listOf(
HighlightingRenderConfiguration()
)
}
abstract class AbstractCodeMetaInfoTest : AbstractMultiModuleTest() {
open fun getConfigurations() = listOf(
DiagnosticCodeMetaInfoRenderConfiguration(),
LineMarkerRenderConfiguration(),
HighlightingRenderConfiguration()
)
protected open fun setupProject(testDataPath: String) {
val dependenciesTxt = File(testDataPath, "dependencies.txt")
require(dependenciesTxt.exists()) {
"${dependenciesTxt.absolutePath} does not exist. dependencies.txt is required"
}
setupMppProjectFromTextFile(File(testDataPath))
}
fun doTest(testDataPath: String) {
val testRoot = File(testDataPath)
val checker = CodeMetaInfoTestCase(getConfigurations())
setupProject(testDataPath)
for (module in ModuleManager.getInstance(project).modules) {
for (sourceRoot in module.sourceRoots) {
VfsUtilCore.processFilesRecursively(sourceRoot) { file ->
if (file.isDirectory) return@processFilesRecursively true
checker.checkFile(file, file.findCorrespondingFileInTestDir(sourceRoot, testRoot), project)
true
}
}
}
}
private fun VirtualFile.findCorrespondingFileInTestDir(containingRoot: VirtualFile, testDir: File): File {
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()
}
}
@@ -0,0 +1,91 @@
/*
* 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.checkers.utils.CheckerTestUtil
import org.jetbrains.kotlin.idea.codeMetaInfo.models.ICodeMetaInfo
import java.io.File
object CodeMetaInfoRenderer {
fun renderTagsToText(
codeMetaInfos: List<ICodeMetaInfo>,
originalText: String
): StringBuffer {
val result = StringBuffer()
if (codeMetaInfos.isEmpty()) {
result.append(originalText)
return result
}
val sortedMetaInfos = getSortedCodeMetaInfos(codeMetaInfos)
val opened = Stack<ICodeMetaInfo>()
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 }) {
openStartTag(result)
val matchedCodeMetaInfos = sortedMetaInfos.filter { it.start == i }.toMutableList()
val iterator = matchedCodeMetaInfos.listIterator()
var current: ICodeMetaInfo? = iterator.next()
while (current != null) {
val next: ICodeMetaInfo? = if (iterator.hasNext()) iterator.next() else null
opened.push(current)
result.append(current.asString())
when {
next == null ->
closeStartTag(result)
next.end == current.end ->
result.append(", ")
else ->
closeStartAndOpenNewTag(result)
}
current = next
}
}
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()
}
return result
}
private fun getSortedCodeMetaInfos(
metaInfos: Collection<ICodeMetaInfo>,
): MutableList<ICodeMetaInfo> {
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 closeString(result: StringBuffer) = result.append("<!>")
private fun openStartTag(result: StringBuffer) = result.append("<!")
private fun closeStartTag(result: StringBuffer) = result.append("!>")
private fun closeStartAndOpenNewTag(result: StringBuffer) = result.append("!><!")
}
fun clearFileFromDiagnosticMarkup(file: File) {
val text = file.readText()
val cleanText = clearTextFromDiagnosticMarkup(text)
file.writeText(cleanText)
}
fun clearTextFromDiagnosticMarkup(text: String): String = CheckerTestUtil.rangeStartOrEndPattern.matcher(text).replaceAll("")
@@ -0,0 +1,106 @@
/*
* 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.models
import com.intellij.codeInsight.daemon.LineMarkerInfo
import com.intellij.codeInsight.daemon.impl.HighlightInfo
import org.jetbrains.kotlin.checkers.diagnostics.ActualDiagnostic
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.codeMetaInfo.renderConfigurations.AbstractCodeMetaInfoRenderConfiguration
import org.jetbrains.kotlin.idea.codeMetaInfo.renderConfigurations.DiagnosticCodeMetaInfoRenderConfiguration
import org.jetbrains.kotlin.idea.codeMetaInfo.renderConfigurations.HighlightingRenderConfiguration
import org.jetbrains.kotlin.idea.codeMetaInfo.renderConfigurations.LineMarkerRenderConfiguration
import org.jetbrains.kotlin.idea.editor.fixers.end
import org.jetbrains.kotlin.idea.editor.fixers.start
interface ICodeMetaInfo {
val start: Int
val end: Int
val renderConfiguration: AbstractCodeMetaInfoRenderConfiguration?
fun asString(): String
}
class DiagnosticCodeMetaInfo(
override val start: Int,
override val end: Int,
override val renderConfiguration: AbstractCodeMetaInfoRenderConfiguration?,
val diagnostic: Diagnostic
) :
ICodeMetaInfo {
override fun asString(): String {
return renderConfiguration!!.asString(this)
}
}
class LineMarkerCodeMetaInfo(
override val renderConfiguration: AbstractCodeMetaInfoRenderConfiguration?,
val lineMarker: LineMarkerInfo<*>
) : ICodeMetaInfo {
override val start: Int
get() = lineMarker.startOffset
override val end: Int
get() = lineMarker.endOffset
val withDescription = true
override fun asString(): String {
return renderConfiguration!!.asString(this)
}
}
class HighlightingCodeMetaInfo(
override val renderConfiguration: AbstractCodeMetaInfoRenderConfiguration?,
val highlightingInfo: HighlightInfo
) : ICodeMetaInfo {
override val start: Int
get() = highlightingInfo.startOffset
override val end: Int
get() = highlightingInfo.endOffset
override fun asString(): String {
return renderConfiguration!!.asString(this)
}
}
object CodeMetaInfoFactory {
private fun createCodeMetaInfo(obj: Any, renderConfiguration: AbstractCodeMetaInfoRenderConfiguration?): Collection<ICodeMetaInfo> {
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<Any>,
renderConfiguration: AbstractCodeMetaInfoRenderConfiguration?
): Collection<ICodeMetaInfo> {
return objects.flatMap { createCodeMetaInfo(it, renderConfiguration) }
}
}
@@ -0,0 +1,131 @@
/*
* 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.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
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.LineMarkerCodeMetaInfo
abstract class AbstractCodeMetaInfoRenderConfiguration(var renderParams: Boolean = true) {
abstract fun asString(codeMetaInfo: ICodeMetaInfo): String
open fun getAdditionalTags(codeMetaInfo: ICodeMetaInfo) = ""
protected fun sanitizeLineMarkerTooltip(originalText: String?): String {
if (originalText == null) return "null"
val noHtmlTags = StringUtil.removeHtmlTags(originalText)
return sanitizeLineBreaks(noHtmlTags)
}
protected fun sanitizeLineBreaks(originalText: String): String {
return StringUtil.replace(originalText, "\n", " ")
}
}
open class DiagnosticCodeMetaInfoRenderConfiguration(
val withNewInference: Boolean = true,
val renderSeverity: Boolean = false
) : AbstractCodeMetaInfoRenderConfiguration() {
override fun asString(codeMetaInfo: ICodeMetaInfo): String {
if (codeMetaInfo !is DiagnosticCodeMetaInfo) return ""
return (getTag(codeMetaInfo) + if (renderParams) "(\"${getParamsString(codeMetaInfo)}\")" else "")
.replace(Regex("""\r?\n"""), "")
}
private fun getParamsString(codeMetaInfo: DiagnosticCodeMetaInfo): String {
val params = mutableListOf<String>()
val renderer = when (codeMetaInfo.diagnostic.factory) {
is DebugInfoDiagnosticFactory1 -> DiagnosticWithParameters1Renderer(
"{0}",
Renderers.TO_STRING
) as DiagnosticRenderer<Diagnostic>
else -> DefaultErrorMessages.getRendererForDiagnostic(codeMetaInfo.diagnostic)
}
if (renderer is AbstractDiagnosticWithParametersRenderer) {
val renderParameters = renderer.renderParameters(codeMetaInfo.diagnostic)
params.addAll(ContainerUtil.map(renderParameters) { it.toString() })
}
if (renderSeverity)
params.add("severity='${codeMetaInfo.diagnostic.severity}'")
params.add(getAdditionalTags(codeMetaInfo))
return params.filter { it.isNotEmpty() }.joinToString("; ")
}
private fun getTag(codeMetaInfo: DiagnosticCodeMetaInfo): String {
return codeMetaInfo.diagnostic.factory.name
}
}
open class LineMarkerRenderConfiguration(val renderDescription: Boolean = true) : AbstractCodeMetaInfoRenderConfiguration() {
override fun asString(codeMetaInfo: ICodeMetaInfo): String {
if (codeMetaInfo !is LineMarkerCodeMetaInfo) return ""
return getTag() + if (renderParams) "(\"${getParamsString(codeMetaInfo)}\")" else ""
}
private fun getTag(): String {
return "LINE_MARKER"
}
private fun getParamsString(lineMarkerCodeMetaInfo: LineMarkerCodeMetaInfo): String {
val params = mutableListOf<String>()
if (renderDescription)
params.add("descr='${sanitizeLineMarkerTooltip(lineMarkerCodeMetaInfo.lineMarker.lineMarkerTooltip)}'")
params.add(getAdditionalTags(lineMarkerCodeMetaInfo))
return params.filter { it.isNotEmpty() }.joinToString("; ")
}
}
open class HighlightingRenderConfiguration(
val renderDescription: Boolean = true,
val renderTextAttributesKey: Boolean = true,
val renderSeverity: Boolean = true
) : AbstractCodeMetaInfoRenderConfiguration() {
override fun asString(codeMetaInfo: ICodeMetaInfo): String {
if (codeMetaInfo !is HighlightingCodeMetaInfo) return ""
return getTag() + if (renderParams) "(${getParamsString(codeMetaInfo)})" else ""
}
private fun getTag(): String {
return "HIGHLIGHTING"
}
private fun getParamsString(highlightingCodeMetaInfo: HighlightingCodeMetaInfo): String {
val params = mutableListOf<String>()
if (renderSeverity)
params.add("severity='${getSeverity(highlightingCodeMetaInfo.highlightingInfo)}'")
if (renderDescription)
params.add("descr='${sanitizeLineBreaks(highlightingCodeMetaInfo.highlightingInfo.description)}'")
if (renderTextAttributesKey)
params.add("textAttributesKey='${highlightingCodeMetaInfo.highlightingInfo.forcedTextAttributesKey}'")
params.add(getAdditionalTags(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()
}
}