From d3efa92dc1ea823af80a84e2b5faa9ccc96d401d Mon Sep 17 00:00:00 2001 From: Anna Antonova Date: Wed, 22 Oct 2025 15:43:47 +0200 Subject: [PATCH] [kotlin] KTIJ-32668 Merge KtWhenExpressionPostfixTemplate and KotlinWhenPostfixTemplate GitOrigin-RevId: 53e718c72f1b5f702871dbeb6cf59338c621bfc0 --- .../postfix/KotlinWhenPostfixTemplate.kt | 164 +----------------- .../testData/expansion/oldTestData/when.kt | 1 - .../expansion/oldTestData/when.kt.after | 1 - .../expansion/oldTestData/whenExpression.kt | 1 - .../oldTestData/whenExpression.kt.after | 1 - .../expansion/oldTestData/whenOnThis.kt | 1 - .../expansion/oldTestData/whenOnThis.kt.after | 1 - .../oldTestData/whenOnThisInExtension.kt | 1 - .../whenOnThisInExtension.kt.after | 1 - .../expansion/when/nonSealed.after.kt | 5 +- 10 files changed, 12 insertions(+), 165 deletions(-) diff --git a/plugins/kotlin/code-insight/postfix-templates/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KotlinWhenPostfixTemplate.kt b/plugins/kotlin/code-insight/postfix-templates/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KotlinWhenPostfixTemplate.kt index 5ce62bc37093..94ec99d8c1a7 100644 --- a/plugins/kotlin/code-insight/postfix-templates/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KotlinWhenPostfixTemplate.kt +++ b/plugins/kotlin/code-insight/postfix-templates/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KotlinWhenPostfixTemplate.kt @@ -1,161 +1,13 @@ // 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.codeInsight.postfix -import com.intellij.codeInsight.template.postfix.templates.StringBasedPostfixTemplate -import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.analysis.api.KaContextParameterApi -import org.jetbrains.kotlin.analysis.api.KaSession -import org.jetbrains.kotlin.analysis.api.analyze -import org.jetbrains.kotlin.analysis.api.components.sealedClassInheritors -import org.jetbrains.kotlin.analysis.api.components.staticDeclaredMemberScope -import org.jetbrains.kotlin.analysis.api.permissions.KaAllowAnalysisFromWriteAction -import org.jetbrains.kotlin.analysis.api.permissions.KaAllowAnalysisOnEdt -import org.jetbrains.kotlin.analysis.api.permissions.allowAnalysisFromWriteAction -import org.jetbrains.kotlin.analysis.api.permissions.allowAnalysisOnEdt -import org.jetbrains.kotlin.analysis.api.symbols.KaClassKind -import org.jetbrains.kotlin.analysis.api.symbols.KaEnumEntrySymbol -import org.jetbrains.kotlin.analysis.api.symbols.KaNamedClassSymbol -import org.jetbrains.kotlin.analysis.api.symbols.KaSymbolModality -import org.jetbrains.kotlin.analysis.api.types.KaClassType -import org.jetbrains.kotlin.analysis.api.types.KaType -import org.jetbrains.kotlin.name.CallableId -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.psi.KtExpression +import com.intellij.codeInsight.template.postfix.templates.PostfixTemplateProvider +import com.intellij.codeInsight.template.postfix.templates.SurroundPostfixTemplateBase +import org.jetbrains.kotlin.idea.codeInsight.surroundWith.expression.KotlinWhenSurrounder -internal class KotlinWhenPostfixTemplate : StringBasedPostfixTemplate { - @Suppress("ConvertSecondaryConstructorToPrimary") - constructor(provider: KotlinPostfixTemplateProvider) : super( - /* name = */ "when", - /* example = */ "when (expr) {}", - /* selector = */ allExpressions(ValuedFilter, ExpressionTypeFilter { isSealedType(it) }), - /* provider = */ provider - ) - - override fun getTemplateString(element: PsiElement): String { - return buildString { - val branches = collectPossibleBranches(element) - - append("when (\$expr\$) {") - - if (branches.isNotEmpty()) { - for ((index, branch) in branches.withIndex()) { - when (branch) { - is CaseBranch.Callable -> { - append("\n") - append(branch.callableId.asSingleFqName().asString()) - } - is CaseBranch.Object -> { - append("\n") - append(branch.classId.asFqNameString()) - } - is CaseBranch.Instance -> { - append("\nis ") - append(branch.classId.asFqNameString()) - } - } - append(" -> ") - if (index == 0) { - append("\$END\$") - } - append("TODO()") - } - } else { - append("\nelse -> \$END\$TODO()") - } - - append("\n}") - } - } - - @OptIn(KaAllowAnalysisOnEdt::class) - private fun collectPossibleBranches(element: PsiElement): List { - if (element !is KtExpression) { - return emptyList() - } - - allowAnalysisOnEdt { - @OptIn(KaAllowAnalysisFromWriteAction::class) - allowAnalysisFromWriteAction { - analyze(element) { - val type = element.expressionType - if (type is KaClassType) { - val klass = type.symbol - if (klass is KaNamedClassSymbol) { - return when (klass.classKind) { - KaClassKind.ENUM_CLASS -> collectEnumBranches(klass) - else -> collectSealedClassInheritors(klass) - } - } - } - } - } - } - - return emptyList() - } - - @OptIn(KaContextParameterApi::class) - context(_: KaSession) - private fun collectEnumBranches(klass: KaNamedClassSymbol): List { - val enumEntries = klass.staticDeclaredMemberScope - .callables - .filterIsInstance() - - return buildList { - for (enumEntry in enumEntries) { - val callableId = enumEntry.callableId ?: return emptyList() - add(CaseBranch.Callable(callableId)) - } - } - } - - context(_: KaSession) - private fun collectSealedClassInheritors(klass: KaNamedClassSymbol): List { - return mutableListOf().also { processSealedClassInheritor(klass, it) } - } - - @OptIn(KaContextParameterApi::class) - context(_: KaSession) - private fun processSealedClassInheritor(klass: KaNamedClassSymbol, consumer: MutableList): Boolean { - val classId = klass.classId ?: return false - - if (klass.classKind == KaClassKind.OBJECT) { - consumer.add(CaseBranch.Object(classId)) - return true - } - - if (klass.modality == KaSymbolModality.SEALED) { - val inheritors = klass.sealedClassInheritors - if (inheritors.isNotEmpty()) { - for (inheritor in inheritors) { - if (!processSealedClassInheritor(inheritor, consumer)) { - return false - } - } - return true - } - } - - consumer.add(CaseBranch.Instance(classId)) - return true - } - - override fun getElementToRemove(expr: PsiElement): PsiElement = expr -} - -private sealed class CaseBranch { - class Callable(val callableId: CallableId) : CaseBranch() - class Object(val classId: ClassId) : CaseBranch() - class Instance(val classId: ClassId) : CaseBranch() -} - -private fun isSealedType(type: KaType): Boolean { - if (type is KaClassType) { - val symbol = type.symbol - if (symbol is KaNamedClassSymbol) { - return symbol.classKind == KaClassKind.ENUM_CLASS || symbol.modality == KaSymbolModality.SEALED - } - } - - return false +internal class KotlinWhenPostfixTemplate(provider: PostfixTemplateProvider) : SurroundPostfixTemplateBase( + "when", "when (expr)", + KtPostfixTemplatePsiInfo, createPostfixExpressionSelector(), provider +) { + override fun getSurrounder(): KotlinWhenSurrounder = KotlinWhenSurrounder() } \ No newline at end of file diff --git a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/when.kt b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/when.kt index cbc902625960..d7ac08c5037a 100644 --- a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/when.kt +++ b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/when.kt @@ -1,4 +1,3 @@ -// IGNORE_K2 fun foo(x: String) { x.when } diff --git a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/when.kt.after b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/when.kt.after index dc2ff17da6c6..6bb39974bb12 100644 --- a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/when.kt.after +++ b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/when.kt.after @@ -1,4 +1,3 @@ -// IGNORE_K2 fun foo(x: String) { when (x) { -> {} diff --git a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenExpression.kt b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenExpression.kt index d51bbce03456..42156014ed38 100644 --- a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenExpression.kt +++ b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenExpression.kt @@ -1,4 +1,3 @@ -// IGNORE_K2 fun foo(x: String) { val y = x.when } diff --git a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenExpression.kt.after b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenExpression.kt.after index c2e46cc24b15..3d28a08fbfc3 100644 --- a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenExpression.kt.after +++ b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenExpression.kt.after @@ -1,4 +1,3 @@ -// IGNORE_K2 fun foo(x: String) { val y = when (x) { -> {} diff --git a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThis.kt b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThis.kt index d4c3cb4c25ed..978888082800 100644 --- a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThis.kt +++ b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThis.kt @@ -1,4 +1,3 @@ -// IGNORE_K2 class C { fun foo() { this.when diff --git a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThis.kt.after b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThis.kt.after index 171fbb74f6ed..6b30d5aeca01 100644 --- a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThis.kt.after +++ b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThis.kt.after @@ -1,4 +1,3 @@ -// IGNORE_K2 class C { fun foo() { when (this) { diff --git a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThisInExtension.kt b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThisInExtension.kt index 5fbd9929d113..26054f8e260a 100644 --- a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThisInExtension.kt +++ b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThisInExtension.kt @@ -1,4 +1,3 @@ -// IGNORE_K2 fun String.foo() { this.when } \ No newline at end of file diff --git a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThisInExtension.kt.after b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThisInExtension.kt.after index d006f99dbc78..0c6a968ad85d 100644 --- a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThisInExtension.kt.after +++ b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/oldTestData/whenOnThisInExtension.kt.after @@ -1,4 +1,3 @@ -// IGNORE_K2 fun String.foo() { when (this) { -> {} diff --git a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/when/nonSealed.after.kt b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/when/nonSealed.after.kt index 7e3a94712fb2..f0c6e219c6d4 100644 --- a/plugins/kotlin/code-insight/postfix-templates/testData/expansion/when/nonSealed.after.kt +++ b/plugins/kotlin/code-insight/postfix-templates/testData/expansion/when/nonSealed.after.kt @@ -1,5 +1,8 @@ fun test(f: Foo) { - f.when + when (f) { + -> {} + else -> {} + } } class Foo {