[kotlin] KTIJ-7870 prefer subtypes of sealed classes in as and is operation completions

^KTIJ-7870 fixed

GitOrigin-RevId: 4a63559fc0ce79ac6c54a49f896e97ac1928137b
This commit is contained in:
Frederik Haselmeier
2025-04-23 15:58:48 +00:00
committed by intellij-monorepo-bot
parent 3b716e2453
commit 50795e0f46
16 changed files with 506 additions and 8 deletions
@@ -10,14 +10,17 @@ import com.intellij.openapi.diagnostic.debug
import com.intellij.openapi.diagnostic.logger
import com.intellij.psi.SmartPsiElementPointer
import com.intellij.psi.createSmartPointer
import com.intellij.psi.search.searches.DirectClassInheritorsSearch
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.concurrency.annotations.RequiresReadLock
import org.jetbrains.kotlin.analysis.api.KaExperimentalApi
import org.jetbrains.kotlin.analysis.api.KaSession
import org.jetbrains.kotlin.analysis.api.analyze
import org.jetbrains.kotlin.analysis.api.components.KaScopeWithKind
import org.jetbrains.kotlin.analysis.api.components.ShortenCommand
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.types.KaClassType
import org.jetbrains.kotlin.analysis.api.types.symbol
import org.jetbrains.kotlin.idea.base.psi.replaced
import org.jetbrains.kotlin.idea.completion.KotlinFirCompletionParameters
import org.jetbrains.kotlin.idea.completion.contributors.helpers.CompletionSymbolOrigin
@@ -40,6 +43,7 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.renderer.render
import kotlin.reflect.KClass
import kotlin.sequences.emptySequence
internal open class FirClassifierCompletionContributor(
parameters: KotlinFirCompletionParameters,
@@ -134,8 +138,22 @@ internal open class FirClassifierCompletionContributor(
context: WeighingContext,
): Sequence<LookupElementBuilder> {
val availableFromScope = mutableSetOf<KaClassifierSymbol>()
val scopeClassifiers = context.scopeContext!!
.scopes
val scopesToCheck = context.scopeContext!!.scopes.toMutableList()
context.preferredSubtype?.symbol?.let { preferredSubtypeSymbol ->
preferredSubtypeSymbol.staticScope?.let {
if (!scopesToCheck.contains(it)) {
scopesToCheck.add(it)
}
}
preferredSubtypeSymbol.containingSymbol?.staticScope?.let {
if (!scopesToCheck.contains(it)) {
scopesToCheck.add(it)
}
}
}
val scopeClassifiers = scopesToCheck
.asSequence()
.flatMap { it.getAvailableClassifiers(positionContext, scopeNameFilter, visibilityChecker) }
.filter { filterClassifiers(it.symbol) }
@@ -0,0 +1,40 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.completion.impl.k2.weighers
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementWeigher
import com.intellij.openapi.util.Key
import org.jetbrains.kotlin.analysis.api.KaSession
import org.jetbrains.kotlin.analysis.api.symbols.KaClassLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KaSymbol
import org.jetbrains.kotlin.idea.completion.weighers.WeighingContext
import org.jetbrains.kotlin.psi.UserDataProperty
internal object PreferredSubtypeWeigher {
private const val WEIGHER_ID = "kotlin.preferredSubtype"
private enum class Weight {
PREFERRED_SUBTYPE,
PREFERRED_EXACT_TYPE, // In this weigher we prefer subtypes over the exact type
UNRELATED
}
context(KaSession)
fun addWeight(context: WeighingContext, lookupElement: LookupElement, symbol: KaSymbol) {
val actualClassType = (symbol as? KaClassLikeSymbol)?.defaultType ?: return
val preferredSubtype = context.preferredSubtype ?: return
lookupElement.hasPreferredSubtype = if (actualClassType.semanticallyEquals(preferredSubtype)) {
Weight.PREFERRED_EXACT_TYPE
} else if (!actualClassType.isNothingType && actualClassType.isSubtypeOf(preferredSubtype)) {
Weight.PREFERRED_SUBTYPE
} else {
Weight.UNRELATED
}
}
private var LookupElement.hasPreferredSubtype: Weight? by UserDataProperty(Key("KOTLIN_HAS_PREFERRED_SUBTYPE"))
object Weigher : LookupElementWeigher(WEIGHER_ID) {
override fun weigh(element: LookupElement): Comparable<*> = element.hasPreferredSubtype ?: Weight.UNRELATED
}
}
@@ -16,7 +16,9 @@ import org.jetbrains.kotlin.analysis.api.resolution.KaAnnotationCall
import org.jetbrains.kotlin.analysis.api.resolution.successfulCallOrNull
import org.jetbrains.kotlin.analysis.api.symbols.KaCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KaSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KaSymbolModality
import org.jetbrains.kotlin.analysis.api.symbols.markers.KaNamedSymbol
import org.jetbrains.kotlin.analysis.api.types.KaClassType
import org.jetbrains.kotlin.analysis.api.types.KaErrorType
import org.jetbrains.kotlin.analysis.api.types.KaType
import org.jetbrains.kotlin.analysis.api.types.KaTypeNullability
@@ -32,6 +34,7 @@ import org.jetbrains.kotlin.idea.completion.contributors.helpers.CompletionSymbo
import org.jetbrains.kotlin.idea.completion.contributors.helpers.KtSymbolWithOrigin
import org.jetbrains.kotlin.idea.completion.impl.k2.context.getOriginalDeclarationOrSelf
import org.jetbrains.kotlin.idea.completion.impl.k2.weighers.K2SoftDeprecationWeigher
import org.jetbrains.kotlin.idea.completion.impl.k2.weighers.PreferredSubtypeWeigher
import org.jetbrains.kotlin.idea.completion.impl.k2.weighers.TrailingLambdaParameterNameWeigher
import org.jetbrains.kotlin.idea.completion.impl.k2.weighers.TrailingLambdaWeigher
import org.jetbrains.kotlin.idea.completion.implCommon.weighers.PreferKotlinClassesWeigher
@@ -52,6 +55,7 @@ internal class WeighingContext private constructor(
private val myScopeContext: KaScopeContext?,
private val myExpectedType: KaType?,
private val myActualReceiverTypes: List<List<KaType>>,
private val myPreferredSubtype: KaClassType?,
val contextualSymbolsCache: ContextualSymbolsCache,
val importableFqNameClassifier: ImportableFqNameClassifier,
private val mySymbolsToSkip: Set<KaSymbol>,
@@ -62,6 +66,7 @@ internal class WeighingContext private constructor(
*/
class ContextualSymbolsCache(private val symbolsContainingPosition: Map<Name, List<KaCallableSymbol>>) {
private val contextualOverriddenSymbols: MutableMap<Name, Set<KaCallableSymbol>> = mutableMapOf()
context(KaSession)
fun symbolIsPresentInContext(symbol: KaCallableSymbol): Boolean = withValidityAssertion {
if (symbol !is KaNamedSymbol) return false
@@ -88,6 +93,12 @@ internal class WeighingContext private constructor(
myExpectedType
}
val preferredSubtype: KaClassType?
get() = withValidityAssertion {
myPreferredSubtype
}
val actualReceiverTypes: List<List<KaType>>
get() = withValidityAssertion { myActualReceiverTypes }
@@ -110,8 +121,9 @@ internal class WeighingContext private constructor(
elementInCompletionFile: PsiElement,
scopeContext: KaScopeContext? = null,
expectedType: KaType? = null,
preferredSubtype: KaClassType? = null,
actualReceiverTypes: List<List<KaType>> = emptyList(),
symbolsToSkip: Set<KaSymbol> = emptySet(),
symbolsToSkip: Set<KaSymbol> = emptySet()
): WeighingContext {
val completionFile = parameters.completionFile
val defaultImportPaths = completionFile.getDefaultImportPaths(useSiteModule = parameters.useSiteModule).toSet()
@@ -128,11 +140,20 @@ internal class WeighingContext private constructor(
originalFile = parameters.originalFile,
)
),
myPreferredSubtype = preferredSubtype,
importableFqNameClassifier = ImportableFqNameClassifier(completionFile) { defaultImportPaths.hasImport(it) },
mySymbolsToSkip = symbolsToSkip,
)
}
// For `is` and `as` operations we want to prefer sealed inheritors
context(KaSession)
fun KtExpression.getPreferredSealedType(): KaClassType? {
val comparisonType = expressionType as? KaClassType ?: return null
if (comparisonType.symbol.modality != KaSymbolModality.SEALED) return null
return comparisonType
}
context(KaSession)
fun create(
parameters: KotlinFirCompletionParameters,
@@ -152,6 +173,25 @@ internal class WeighingContext private constructor(
else -> null
}
fun KtBinaryExpressionWithTypeRHS.isAsOrSafeAs(): Boolean {
val operationElementType = operationReference.getReferencedNameElementType()
return operationElementType == KtTokens.AS_KEYWORD || operationElementType == KtTokens.AS_SAFE
}
val preferredSubtype = when (positionContext) {
is KotlinTypeNameReferencePositionContext -> {
val typeReferenceOwner = positionContext.typeReference?.parent
val leftHandExpression = when {
typeReferenceOwner is KtIsExpression -> typeReferenceOwner.leftHandSide
typeReferenceOwner is KtBinaryExpressionWithTypeRHS && typeReferenceOwner.isAsOrSafeAs() -> typeReferenceOwner.left
else -> null
}
leftHandExpression?.getPreferredSealedType()
}
else -> null
}
val symbolToSkip = when (positionContext) {
is KotlinWithSubjectEntryPositionContext -> (positionContext.subjectExpression as? KtSimpleNameExpression)
?.mainReference
@@ -174,11 +214,12 @@ internal class WeighingContext private constructor(
elementInCompletionFile = positionContext.position,
scopeContext = scopeContext,
expectedType = expectedType,
preferredSubtype = preferredSubtype,
actualReceiverTypes = CallableMetadataProvider.calculateActualReceiverTypes(
explicitReceiver = positionContext.explicitReceiver,
implicitReceivers = ::implicitReceivers,
),
symbolsToSkip = setOfNotNull(symbolToSkip),
symbolsToSkip = setOfNotNull(symbolToSkip)
)
}
@@ -275,13 +316,14 @@ internal object Weighers {
NotImportedWeigher.addWeight(context, lookupElement, symbol, availableWithoutImport)
ClassifierWeigher.addWeight(lookupElement, symbol, symbolWithOrigin.origin)
VariableOrFunctionWeigher.addWeight(lookupElement, symbol)
PreferredSubtypeWeigher.addWeight(context, lookupElement, symbol)
if (symbol !is KaCallableSymbol) return@also
K2SoftDeprecationWeigher.addWeight(lookupElement, symbol, context.languageVersionSettings)
PreferContextualCallablesWeigher.addWeight(lookupElement, symbol, context.contextualSymbolsCache)
PreferFewerParametersWeigher. addWeight(lookupElement, symbol)
PreferFewerParametersWeigher.addWeight(lookupElement, symbol)
}
fun CompletionSorter.applyWeighers(positionContext: KotlinRawPositionContext): CompletionSorter =
@@ -292,6 +334,7 @@ internal object Weighers {
ExpectedTypeWeigher.Weigher,
DeprecatedWeigher.Weigher,
PriorityWeigher.Weigher,
PreferredSubtypeWeigher.Weigher,
PreferGetSetMethodsToPropertyWeigher.Weigher,
NotImportedWeigher.Weigher,
KindWeigher.Weigher,
@@ -0,0 +1,26 @@
// IGNORE_K1
class A1
class Z1
sealed class Foo
class A2
class Z2
class Bar: Foo()
class Baz: Foo()
class A3
class Z3
fun f(foo: Foo) {
val t = foo as <caret>
}
// WITH_ORDER
// EXIST: Bar
// EXIST: Baz
// EXIST: Foo
// EXIST: A1
// EXIST: A2
// EXIST: A3
// EXIST: Z1
// EXIST: Z2
// EXIST: Z3
@@ -0,0 +1,26 @@
// IGNORE_K1
class A1
class Z1
sealed class Foo
class A2
class Z2
class Bar: Foo()
class Baz: Foo()
class A3
class Z3
fun f(foo: Foo) {
if (foo is <caret>) {}
}
// WITH_ORDER
// EXIST: Bar
// EXIST: Baz
// EXIST: Foo
// EXIST: A1
// EXIST: A2
// EXIST: A3
// EXIST: Z1
// EXIST: Z2
// EXIST: Z3
@@ -0,0 +1,26 @@
// IGNORE_K1
class A1
class Z1
sealed class Foo
class A2
class Z2
class Bar: Foo()
class Baz: Foo()
class A3
class Z3
fun f(foo: Foo) {
val t = foo as? <caret>
}
// WITH_ORDER
// EXIST: Bar
// EXIST: Baz
// EXIST: Foo
// EXIST: A1
// EXIST: A2
// EXIST: A3
// EXIST: Z1
// EXIST: Z2
// EXIST: Z3
@@ -0,0 +1,31 @@
// IGNORE_K1
class A1
class Z1
class A2
sealed interface Foo {
sealed interface Bar : Foo
sealed interface Baz : Foo
}
class BarImpl : Foo.Bar
class BazImpl : Foo.Baz
class Z2
class A3
class Z3
fun f(foo: Foo) {
val t = foo as <caret>
}
// WITH_ORDER
// EXIST: Bar
// EXIST: Baz
// EXIST: BarImpl
// EXIST: BazImpl
// EXIST: Foo
// EXIST: A1
// EXIST: A2
// EXIST: A3
// EXIST: Z1
// EXIST: Z2
// EXIST: Z3
@@ -2523,6 +2523,40 @@ public abstract class K1JSBasicCompletionTestGenerated extends AbstractK1JSBasic
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../testData/basic/common/sealedHierarchy")
public static class SealedHierarchy extends AbstractK1JSBasicCompletionTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K1;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("PreferSealedHierarchyInAs.kt")
public void testPreferSealedHierarchyInAs() throws Exception {
runTest("../testData/basic/common/sealedHierarchy/PreferSealedHierarchyInAs.kt");
}
@TestMetadata("PreferSealedHierarchyInIs.kt")
public void testPreferSealedHierarchyInIs() throws Exception {
runTest("../testData/basic/common/sealedHierarchy/PreferSealedHierarchyInIs.kt");
}
@TestMetadata("PreferSealedHierarchyInSafeAs.kt")
public void testPreferSealedHierarchyInSafeAs() throws Exception {
runTest("../testData/basic/common/sealedHierarchy/PreferSealedHierarchyInSafeAs.kt");
}
@TestMetadata("PreferSealedHierarchyNested.kt")
public void testPreferSealedHierarchyNested() throws Exception {
runTest("../testData/basic/common/sealedHierarchy/PreferSealedHierarchyNested.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../testData/basic/common/shadowing")
public static class Shadowing extends AbstractK1JSBasicCompletionTest {
@@ -2523,6 +2523,40 @@ public abstract class K1JvmBasicCompletionTestGenerated extends AbstractK1JvmBas
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../testData/basic/common/sealedHierarchy")
public static class SealedHierarchy extends AbstractK1JvmBasicCompletionTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K1;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("PreferSealedHierarchyInAs.kt")
public void testPreferSealedHierarchyInAs() throws Exception {
runTest("../testData/basic/common/sealedHierarchy/PreferSealedHierarchyInAs.kt");
}
@TestMetadata("PreferSealedHierarchyInIs.kt")
public void testPreferSealedHierarchyInIs() throws Exception {
runTest("../testData/basic/common/sealedHierarchy/PreferSealedHierarchyInIs.kt");
}
@TestMetadata("PreferSealedHierarchyInSafeAs.kt")
public void testPreferSealedHierarchyInSafeAs() throws Exception {
runTest("../testData/basic/common/sealedHierarchy/PreferSealedHierarchyInSafeAs.kt");
}
@TestMetadata("PreferSealedHierarchyNested.kt")
public void testPreferSealedHierarchyNested() throws Exception {
runTest("../testData/basic/common/sealedHierarchy/PreferSealedHierarchyNested.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../testData/basic/common/shadowing")
public static class Shadowing extends AbstractK1JvmBasicCompletionTest {
@@ -2523,6 +2523,40 @@ public abstract class K1MLPerformanceCompletionTestGenerated extends AbstractK1M
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../testData/basic/common/sealedHierarchy")
public static class SealedHierarchy extends AbstractK1MLPerformanceCompletionTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K1;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("PreferSealedHierarchyInAs.kt")
public void testPreferSealedHierarchyInAs() throws Exception {
runTest("../testData/basic/common/sealedHierarchy/PreferSealedHierarchyInAs.kt");
}
@TestMetadata("PreferSealedHierarchyInIs.kt")
public void testPreferSealedHierarchyInIs() throws Exception {
runTest("../testData/basic/common/sealedHierarchy/PreferSealedHierarchyInIs.kt");
}
@TestMetadata("PreferSealedHierarchyInSafeAs.kt")
public void testPreferSealedHierarchyInSafeAs() throws Exception {
runTest("../testData/basic/common/sealedHierarchy/PreferSealedHierarchyInSafeAs.kt");
}
@TestMetadata("PreferSealedHierarchyNested.kt")
public void testPreferSealedHierarchyNested() throws Exception {
runTest("../testData/basic/common/sealedHierarchy/PreferSealedHierarchyNested.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../testData/basic/common/shadowing")
public static class Shadowing extends AbstractK1MLPerformanceCompletionTest {
@@ -2523,6 +2523,40 @@ public abstract class K2JsBasicCompletionLegacyStdlibTestGenerated extends Abstr
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../completion/testData/basic/common/sealedHierarchy")
public static class SealedHierarchy extends AbstractK2JsBasicCompletionLegacyStdlibTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K2;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("PreferSealedHierarchyInAs.kt")
public void testPreferSealedHierarchyInAs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInAs.kt");
}
@TestMetadata("PreferSealedHierarchyInIs.kt")
public void testPreferSealedHierarchyInIs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInIs.kt");
}
@TestMetadata("PreferSealedHierarchyInSafeAs.kt")
public void testPreferSealedHierarchyInSafeAs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInSafeAs.kt");
}
@TestMetadata("PreferSealedHierarchyNested.kt")
public void testPreferSealedHierarchyNested() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyNested.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../completion/testData/basic/common/shadowing")
public static class Shadowing extends AbstractK2JsBasicCompletionLegacyStdlibTest {
@@ -2523,6 +2523,40 @@ public abstract class K2JvmBasicCompletionTestGenerated extends AbstractK2JvmBas
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../completion/testData/basic/common/sealedHierarchy")
public static class SealedHierarchy extends AbstractK2JvmBasicCompletionTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K2;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("PreferSealedHierarchyInAs.kt")
public void testPreferSealedHierarchyInAs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInAs.kt");
}
@TestMetadata("PreferSealedHierarchyInIs.kt")
public void testPreferSealedHierarchyInIs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInIs.kt");
}
@TestMetadata("PreferSealedHierarchyInSafeAs.kt")
public void testPreferSealedHierarchyInSafeAs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInSafeAs.kt");
}
@TestMetadata("PreferSealedHierarchyNested.kt")
public void testPreferSealedHierarchyNested() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyNested.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../completion/testData/basic/common/shadowing")
public static class Shadowing extends AbstractK2JvmBasicCompletionTest {
@@ -2667,6 +2667,45 @@ public abstract class CommonNativeJvmKotlinKmpCompletionTestGenerated extends Ab
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../completion/testData/basic/common/sealedHierarchy")
public static class SealedHierarchy extends AbstractKotlinKmpCompletionTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K2;
}
@java.lang.Override
public KMPTestPlatform getTestPlatform() {
return KMPTestPlatform.CommonNativeJvm;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("PreferSealedHierarchyInAs.kt")
public void testPreferSealedHierarchyInAs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInAs.kt");
}
@TestMetadata("PreferSealedHierarchyInIs.kt")
public void testPreferSealedHierarchyInIs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInIs.kt");
}
@TestMetadata("PreferSealedHierarchyInSafeAs.kt")
public void testPreferSealedHierarchyInSafeAs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInSafeAs.kt");
}
@TestMetadata("PreferSealedHierarchyNested.kt")
public void testPreferSealedHierarchyNested() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyNested.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../completion/testData/basic/common/shadowing")
public static class Shadowing extends AbstractKotlinKmpCompletionTest {
@@ -2667,6 +2667,45 @@ public abstract class JsKotlinKmpCompletionTestGenerated extends AbstractKotlinK
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../completion/testData/basic/common/sealedHierarchy")
public static class SealedHierarchy extends AbstractKotlinKmpCompletionTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K2;
}
@java.lang.Override
public KMPTestPlatform getTestPlatform() {
return KMPTestPlatform.Js;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("PreferSealedHierarchyInAs.kt")
public void testPreferSealedHierarchyInAs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInAs.kt");
}
@TestMetadata("PreferSealedHierarchyInIs.kt")
public void testPreferSealedHierarchyInIs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInIs.kt");
}
@TestMetadata("PreferSealedHierarchyInSafeAs.kt")
public void testPreferSealedHierarchyInSafeAs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInSafeAs.kt");
}
@TestMetadata("PreferSealedHierarchyNested.kt")
public void testPreferSealedHierarchyNested() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyNested.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../completion/testData/basic/common/shadowing")
public static class Shadowing extends AbstractKotlinKmpCompletionTest {
@@ -2667,6 +2667,45 @@ public abstract class NativeLinuxKotlinKmpCompletionTestGenerated extends Abstra
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../completion/testData/basic/common/sealedHierarchy")
public static class SealedHierarchy extends AbstractKotlinKmpCompletionTest {
@java.lang.Override
@org.jetbrains.annotations.NotNull
public final KotlinPluginMode getPluginMode() {
return KotlinPluginMode.K2;
}
@java.lang.Override
public KMPTestPlatform getTestPlatform() {
return KMPTestPlatform.NativeLinux;
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("PreferSealedHierarchyInAs.kt")
public void testPreferSealedHierarchyInAs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInAs.kt");
}
@TestMetadata("PreferSealedHierarchyInIs.kt")
public void testPreferSealedHierarchyInIs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInIs.kt");
}
@TestMetadata("PreferSealedHierarchyInSafeAs.kt")
public void testPreferSealedHierarchyInSafeAs() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyInSafeAs.kt");
}
@TestMetadata("PreferSealedHierarchyNested.kt")
public void testPreferSealedHierarchyNested() throws Exception {
runTest("../../completion/testData/basic/common/sealedHierarchy/PreferSealedHierarchyNested.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../../completion/testData/basic/common/shadowing")
public static class Shadowing extends AbstractKotlinKmpCompletionTest {
@@ -89,6 +89,7 @@ class KotlinTypeNameReferencePositionContext(
val typeReference: KtTypeReference?,
) : KotlinSimpleNameReferencePositionContext()
class KotlinAnnotationTypeNameReferencePositionContext(
override val position: PsiElement,
override val reference: KtSimpleNameReference,
@@ -159,10 +160,10 @@ class KotlinInfixCallPositionContext(
/**
* Represents an operator call - binary or unary, postfix or prefix.
*
*
* [nameExpression] does not represent any name in this case - it references
* an operator reference, like `+`, `+=` or unary `-`.
*
*
* [explicitReceiver] points to the main expression in the operator call:
* - the LHS in the binary call (except for the `contains` operator, where the receiver is on the RHS)
* - the underlying expression in the unary call
@@ -349,7 +350,7 @@ object KotlinPositionContextDetector {
KotlinOperatorCallPositionContext(position, reference, nameExpression, explicitReceiver)
}
}
parent is KtUnaryExpression && parent.operationReference == nameExpression ->
KotlinOperatorCallPositionContext(position, reference, nameExpression, explicitReceiver)