Added support for various platforms for CodeMetaInfo tests. ^KT-41996
The tests need to be able to parse and render CodeMetaInfo for different
platforms. For example, we must draw a run gutter a MAC application on
OSX, but for a Win application, the gutter should not be drawn at the
same time. This commit allows to do such checks. In order to indicate
on which platform it should be rendered, it is necessary to specify the
platform for a specific CodeMetaInfo in the test data in the format
{OSX,Unix,Win}, if the block with platforms is missing, this means
that it should be rendered on each platform.
<!LINE_MARKER{OSX}(...)!> - should only be on OSX
<!LINE_MARKER(...)!> - should be on any platform
This commit is contained in:
@@ -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("(<!$INDIVIDUAL_DIAGNOSTIC(,\\s*$INDIVIDUAL_DIAGNOSTIC)*!>)|(<!>)")
|
||||
val individualDiagnosticPattern: Pattern = Pattern.compile(INDIVIDUAL_DIAGNOSTIC)
|
||||
|
||||
@@ -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<AbstractCodeMetaInfoRenderConfiguration>) : DaemonAnalyzerTestCase() {
|
||||
class CodeMetaInfoTestCase(
|
||||
val codeMetaInfoTypes: Collection<AbstractCodeMetaInfoRenderConfiguration>,
|
||||
val checkNoDiagnosticError: Boolean = false
|
||||
) : DaemonAnalyzerTestCase() {
|
||||
|
||||
fun getDiagnosticCodeMetaInfos(
|
||||
configuration: DiagnosticCodeMetaInfoRenderConfiguration?,
|
||||
configuration: DiagnosticCodeMetaInfoRenderConfiguration = DiagnosticCodeMetaInfoRenderConfiguration(),
|
||||
parseDirective: Boolean = true
|
||||
): Collection<ICodeMetaInfo> {
|
||||
): List<CodeMetaInfo> {
|
||||
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<AbstractCodeMetaInf
|
||||
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)
|
||||
configuration.renderParams = directives.contains(BaseDiagnosticsTest.RENDER_DIAGNOSTICS_MESSAGES)
|
||||
return getCodeMetaInfo(diagnostics, configuration)
|
||||
}
|
||||
|
||||
fun getLineMarkerCodeMetaInfos(configuration: LineMarkerRenderConfiguration): Collection<ICodeMetaInfo> {
|
||||
fun getLineMarkerCodeMetaInfos(configuration: LineMarkerRenderConfiguration): Collection<CodeMetaInfo> {
|
||||
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<ICodeMetaInfo> {
|
||||
fun getHighlightingCodeMetaInfos(configuration: HighlightingRenderConfiguration): Collection<CodeMetaInfo> {
|
||||
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<AbstractCodeMetaInf
|
||||
}
|
||||
|
||||
fun check(expectedFile: File) {
|
||||
|
||||
val codeMetaInfoForCheck = mutableListOf<ICodeMetaInfo>()
|
||||
val codeMetaInfoForCheck = mutableListOf<CodeMetaInfo>()
|
||||
PsiDocumentManager.getInstance(myProject).commitAllDocuments()
|
||||
|
||||
//to load text
|
||||
@@ -144,22 +145,46 @@ class CodeMetaInfoTestCase(val codeMetaInfoTypes: Collection<AbstractCodeMetaInf
|
||||
!codeMetaInfoTypes.any { it is HighlightingRenderConfiguration }
|
||||
) {
|
||||
checkHighlightErrorItemsInDiagnostics(
|
||||
getDiagnosticCodeMetaInfos(null, false).filterIsInstance<DiagnosticCodeMetaInfo>()
|
||||
getDiagnosticCodeMetaInfos(DiagnosticCodeMetaInfoRenderConfiguration(), false).filterIsInstance<DiagnosticCodeMetaInfo>()
|
||||
)
|
||||
}
|
||||
|
||||
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<DiagnosticCodeMetaInfo>
|
||||
) {
|
||||
val highlightItems: List<ICodeMetaInfo> =
|
||||
getHighlightingCodeMetaInfos(null).filter { (it as HighlightingCodeMetaInfo).highlightingInfo.severity == HighlightSeverity.ERROR }
|
||||
val highlightItems: List<CodeMetaInfo> =
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -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<ParsedCodeMetaInfo> {
|
||||
var text = renderedText
|
||||
val openingMatchResults = Stack<MatchResult>()
|
||||
val closingMatchResults = Stack<MatchResult>()
|
||||
val result = mutableListOf<ParsedCodeMetaInfo>()
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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<ICodeMetaInfo>,
|
||||
codeMetaInfos: List<CodeMetaInfo>,
|
||||
originalText: String
|
||||
): StringBuffer {
|
||||
val result = StringBuffer()
|
||||
@@ -22,25 +21,18 @@ object CodeMetaInfoRenderer {
|
||||
return result
|
||||
}
|
||||
val sortedMetaInfos = getSortedCodeMetaInfos(codeMetaInfos)
|
||||
val opened = Stack<ICodeMetaInfo>()
|
||||
val opened = Stack<CodeMetaInfo>()
|
||||
|
||||
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<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 getSortedCodeMetaInfos(metaInfos: Collection<CodeMetaInfo>): List<CodeMetaInfo> {
|
||||
return metaInfos.sortedWith(compareBy<CodeMetaInfo> { it.start }.then(compareByDescending { it.end }))
|
||||
}
|
||||
|
||||
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("!><!")
|
||||
|
||||
private fun checkOpenedAndCloseStringIfNeeded(opened: Stack<CodeMetaInfo>, 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) {
|
||||
|
||||
@@ -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<String>
|
||||
|
||||
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<String> = 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<String> = 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<String> = 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<String>,
|
||||
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<CodeMetaInfo> {
|
||||
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<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) }
|
||||
}
|
||||
}
|
||||
fun getCodeMetaInfo(
|
||||
objects: List<Any>,
|
||||
renderConfiguration: AbstractCodeMetaInfoRenderConfiguration
|
||||
): List<CodeMetaInfo> {
|
||||
return objects.flatMap { createCodeMetaInfo(it, renderConfiguration) }
|
||||
}
|
||||
|
||||
+26
-28
@@ -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<String>()
|
||||
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<String>()
|
||||
@@ -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<String>()
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user