[kotlin] k2: fix test data for renderer

- don't copy actual from super when container has no attribute

KT-66052

GitOrigin-RevId: 6a1274794e0372b745a02053e4c64c190a02f6eb
This commit is contained in:
Anna Kozlova
2024-03-26 14:46:34 +01:00
committed by intellij-monorepo-bot
parent ffef0db30a
commit 7cd267ea10
5 changed files with 93 additions and 28 deletions
@@ -1,8 +1,15 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.k2.codeinsight.fixes
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.quickfix.AbstractQuickFixMultiModuleTest
import org.jetbrains.kotlin.psi.KtFile
abstract class AbstractHighLevelQuickFixMultiModuleTest : AbstractQuickFixMultiModuleTest() {
override fun isFirPlugin(): Boolean = true
override fun findAfterFile(editedFile: KtFile): PsiFile? {
val firAfter = editedFile.containingDirectory?.findFile(editedFile.name + ".fir.after")
if (firAfter != null) return firAfter
return editedFile.containingDirectory?.findFile(editedFile.name + ".after")
}
}
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.rendere
import org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers.KtRendererOtherModifiersProvider
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossibleMultiplatformSymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.idea.base.util.names.FqNames
import org.jetbrains.kotlin.idea.core.TemplateKind
@@ -132,11 +133,63 @@ fun generateMember(
modalityProvider = modalityProvider.onlyIf { s -> s != symbol }
otherModifiersProvider = otherModifiersProvider and object : KtRendererOtherModifiersProvider {
val containingSymbol = targetClass?.getSymbol() as? KtClassOrObjectSymbol
otherModifiersProvider = object : KtRendererOtherModifiersProvider {
//copy from KtRendererOtherModifiersProvider.ALL with `actual` and `override` specifics
context(KtAnalysisSession)
override fun getOtherModifiers(symbol: KtDeclarationSymbol): List<KtModifierKeywordToken> =
listOf(KtTokens.OVERRIDE_KEYWORD)
}.onlyIf { s -> mode == MemberGenerateMode.OVERRIDE && s == symbol }
override fun getOtherModifiers(s: KtDeclarationSymbol): List<KtModifierKeywordToken> = buildList {
if (mode == MemberGenerateMode.OVERRIDE && s is KtPossibleMultiplatformSymbol && containingSymbol?.isActual == true) {
//include actual modifier explicitly when containing class has modifier
if (s.isActual) add(KtTokens.ACTUAL_KEYWORD)
}
if (s is KtFunctionSymbol) {
if (s.isExternal) add(KtTokens.EXTERNAL_KEYWORD)
if (s.isOverride) add(KtTokens.OVERRIDE_KEYWORD)
if (s.isInline) add(KtTokens.INLINE_KEYWORD)
if (s.isInfix) add(KtTokens.INFIX_KEYWORD)
if (s.isOperator) add(KtTokens.OPERATOR_KEYWORD)
if (s.isSuspend) add(KtTokens.SUSPEND_KEYWORD)
}
if (s is KtPropertySymbol) {
if (s.isOverride) add(KtTokens.OVERRIDE_KEYWORD)
}
if (s is KtValueParameterSymbol) {
if (s.isVararg) add(KtTokens.VARARG_KEYWORD)
if (s.isCrossinline) add(KtTokens.CROSSINLINE_KEYWORD)
if (s.isNoinline) add(KtTokens.NOINLINE_KEYWORD)
}
if (s is KtKotlinPropertySymbol) {
if (s.isConst) add(KtTokens.CONST_KEYWORD)
if (s.isLateInit) add(KtTokens.LATEINIT_KEYWORD)
}
if (s is KtNamedClassOrObjectSymbol) {
if (s.isExternal) add(KtTokens.EXTERNAL_KEYWORD)
if (s.isInline) add(KtTokens.INLINE_KEYWORD)
if (s.isData) add(KtTokens.DATA_KEYWORD)
if (s.isFun) add(KtTokens.FUN_KEYWORD)
if (s.isInner) add(KtTokens.INNER_KEYWORD)
}
if (s is KtTypeParameterSymbol) {
if (s.isReified) add(KtTokens.REIFIED_KEYWORD)
when (s.variance) {
Variance.INVARIANT -> {}
Variance.IN_VARIANCE -> add(KtTokens.IN_KEYWORD)
Variance.OUT_VARIANCE -> add(KtTokens.OUT_KEYWORD)
}
}
if (s == symbol && mode == MemberGenerateMode.OVERRIDE) {
//include additional override modifier
add(KtTokens.OVERRIDE_KEYWORD)
}
}
}
}
}
@@ -158,15 +211,13 @@ fun generateMember(
}
MemberGenerateMode.OVERRIDE -> {
// TODO: add `actual` keyword to the generated member if the target class has `actual` and the generated member corresponds to
// an `expect` member.
}
}
if (copyDoc) {
val kDoc = when (val originalOverriddenPsi = symbol.unwrapFakeOverrides.psi) {
is KtDeclaration ->
findDocComment(originalOverriddenPsi)
is KtDeclaration -> findDocComment(originalOverriddenPsi)
is PsiDocCommentOwner -> {
val kDocText = originalOverriddenPsi.docComment?.let { IdeaDocCommentConverter.convertDocComment(it) }
@@ -243,25 +294,21 @@ private fun generateProperty(
val returnType = symbol.returnType
val returnsNotUnit = !returnType.isUnit
val body =
if (bodyType != BodyType.NoBody) {
buildString {
append("\nget()")
append(" = ")
append(generateUnsupportedOrSuperCall(project, symbol, bodyType, !returnsNotUnit))
if (!symbol.isVal) {
append("\nset(value) {}")
}
val body = if (bodyType != BodyType.NoBody) {
buildString {
append("\nget()")
append(" = ")
append(generateUnsupportedOrSuperCall(project, symbol, bodyType, !returnsNotUnit))
if (!symbol.isVal) {
append("\nset(value) {}")
}
} else ""
}
} else ""
return KtPsiFactory(project).createProperty(symbol.render(renderer) + body)
}
private fun <T> KtAnalysisSession.generateUnsupportedOrSuperCall(
project: Project,
symbol: T,
bodyType: BodyType,
canBeEmpty: Boolean = true
project: Project, symbol: T, bodyType: BodyType, canBeEmpty: Boolean = true
): String where T : KtNamedSymbol, T : KtCallableSymbol {
when (bodyType.effectiveBodyType(canBeEmpty)) {
BodyType.EmptyOrTemplate -> return ""
@@ -272,11 +319,7 @@ private fun <T> KtAnalysisSession.generateUnsupportedOrSuperCall(
else -> throw IllegalArgumentException("$symbol must be either a function or a property")
}
return getFunctionBodyTextFromTemplate(
project,
templateKind,
symbol.name.asString(),
symbol.returnType.render(position = Variance.OUT_VARIANCE),
null
project, templateKind, symbol.name.asString(), symbol.returnType.render(position = Variance.OUT_VARIANCE), null
)
}
@@ -9,6 +9,7 @@ import com.intellij.openapi.ui.Messages
import com.intellij.openapi.ui.TestDialog
import com.intellij.openapi.ui.TestDialogManager
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import com.intellij.rt.execution.junit.FileComparisonData
import com.intellij.testFramework.IdeaTestUtil
import com.intellij.testFramework.UsefulTestCase
@@ -154,7 +155,7 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest(), Quic
val afterFiles = projectDirectory.walkTopDown().filter { it.path.endsWith(".after") }.toList()
for (editedFile in project.allKotlinFiles()) {
val afterFileInTmpProject = editedFile.containingDirectory?.findFile(editedFile.name + ".after") ?: continue
val afterFileInTmpProject = findAfterFile(editedFile) ?: continue
val afterFileInTestData = afterFiles.filter { it.name == afterFileInTmpProject.name }.single {
it.readText() == File(afterFileInTmpProject.virtualFile.path).readText()
}
@@ -169,6 +170,8 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest(), Quic
}
}
protected open fun findAfterFile(editedFile: KtFile): PsiFile? = editedFile.containingDirectory?.findFile(editedFile.name + ".after")
private val availableActions: List<IntentionAction>
get() {
doHighlighting()
@@ -8,5 +8,5 @@ expect class Foo
*/
actual class F<caret>oo
//K2_INFO: <div class='definition'><pre><span style="color:#000080;font-weight:bold;">public</span> <span style="color:#000080;font-weight:bold;">final</span> <span style="color:#000080;font-weight:bold;">class</span> <span style="color:#000000;">Foo</span></pre></div><div class='content'><p style='margin-top:0;padding-top:0;'>Doc for actual class Foo</p></div><table class='sections'></table><div class='bottom'><icon src="/org/jetbrains/kotlin/idea/icons/kotlin_file.svg"/>&nbsp;OnActualDeclaration.kt<br/></div>
//K2_INFO: <div class='definition'><pre><span style="color:#000080;font-weight:bold;">public</span> <span style="color:#000080;font-weight:bold;">actual</span> <span style="color:#000080;font-weight:bold;">final</span> <span style="color:#000080;font-weight:bold;">class</span> <span style="color:#000000;">Foo</span></pre></div><div class='content'><p style='margin-top:0;padding-top:0;'>Doc for actual class Foo</p></div><table class='sections'></table><div class='bottom'><icon src="/org/jetbrains/kotlin/idea/icons/kotlin_file.svg"/>&nbsp;OnActualDeclaration.kt<br/></div>
//INFO: <div class='definition'><pre><span style="color:#000080;font-weight:bold;">public</span> <span style="color:#000080;font-weight:bold;">final</span> <span style="color:#000080;font-weight:bold;">actual</span> <span style="color:#000080;font-weight:bold;">class</span> <span style="color:#000000;">Foo</span></pre></div><div class='content'><p style='margin-top:0;padding-top:0;'>Doc for actual class Foo</p></div><table class='sections'></table><div class='bottom'><icon src="/org/jetbrains/kotlin/idea/icons/kotlin_file.svg"/>&nbsp;OnActualDeclaration.kt<br/></div>
@@ -0,0 +1,12 @@
// "Implement members" "true"
// DISABLE-ERRORS
actual interface ExpInterface {
actual fun first()
}
actual class ExpImpl : ExpInterface {
actual override fun first() {
TODO("Not yet implemented")
}
}