Skip to content

Commit 4687415

Browse files
committed
Implement intention for creating contextual overloads
1 parent 33347f5 commit 4687415

File tree

6 files changed

+102
-2
lines changed

6 files changed

+102
-2
lines changed

gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pluginVersion = 1.0.999-SNAPSHOT
88

99
# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
1010
# for insight into build numbers and IntelliJ Platform versions.
11-
pluginSinceBuild = 251
11+
pluginSinceBuild = 252
1212

1313
# !!!! DON'T CHANGE THIS VERSION !!!
1414
pluginUntilBuild = 299.*
@@ -18,7 +18,7 @@ pluginUntilBuild = 299.*
1818
pluginVerifierIdeVersions = 2024.2
1919

2020
platformType = IC
21-
platformVersion = 2025.1
21+
platformVersion = 2025.2
2222

2323
# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
2424
# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22

resources/META-INF/plugin.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@
3838
<lang.inspectionSuppressor language="kotlin" implementationClass="org.jetbrains.kotlin.test.helper.inspections.UnusedDeclarationSuppressor"/>
3939

4040
<registryKey defaultValue="false" description="Support on-the-fly-generated tests in Kotlin Compiler DevKit." key="kotlin.compiler.devkit.on.the.fly" />
41+
42+
<intentionAction>
43+
<language>kotlin</language>
44+
<className>org.jetbrains.kotlin.test.helper.intentions.CreateContextualOverloadIntention</className>
45+
<category>Kotlin Compiler DevKit</category>
46+
</intentionAction>
4147
</extensions>
4248

4349
<extensions defaultExtensionNs="org.jetbrains.kotlin">
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
fun ConeClassLikeLookupTag.toSymbol(useSiteSession: FirSession): FirClassLikeSymbol<*>? { }
2+
3+
context(sessionHolder: SessionHolder)
4+
fun ConeClassLikeLookupTag.toSymbol(): FirClassLikeSymbol<*>? {
5+
return toSymbol(useSiteSession = sessionHolder.session)
6+
}
7+
8+
@Deprecated("Use parameterless overload", replaceWith = ReplaceWith("toSymbol()"))
9+
context(sessionHolder: SessionHolder)
10+
fun ConeClassLikeLookupTag.toSymbol(@Suppress("unused") s: FirSession): FirClassLikeSymbol<*>? {
11+
return toSymbol()
12+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fun ConeClassLikeLookupTag.toSymbol(useSiteSession: FirSession): FirClassLikeSymbol<*>? { }
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<html lang="en">
2+
<body>
3+
Creates a contextual overload and another deprecated overload for migration.
4+
</body>
5+
</html>
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package org.jetbrains.kotlin.test.helper.intentions
2+
3+
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction
4+
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
5+
import com.intellij.codeInspection.util.IntentionFamilyName
6+
import com.intellij.codeInspection.util.IntentionName
7+
import com.intellij.openapi.editor.Editor
8+
import com.intellij.openapi.project.Project
9+
import com.intellij.psi.PsiElement
10+
import com.intellij.psi.PsiFile
11+
import com.intellij.psi.util.parents
12+
import org.jetbrains.kotlin.analysis.api.KaIdeApi
13+
import org.jetbrains.kotlin.idea.base.analysis.api.utils.shortenReferences
14+
import org.jetbrains.kotlin.psi.KtElement
15+
import org.jetbrains.kotlin.psi.KtNamedFunction
16+
import org.jetbrains.kotlin.psi.KtPsiFactory
17+
import org.jetbrains.kotlin.psi.addRemoveModifier.setModifierList
18+
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
19+
20+
class CreateContextualOverloadIntention : PsiElementBaseIntentionAction() {
21+
override fun isAvailable(project: Project, editor: Editor?, element: PsiElement): Boolean {
22+
val function = element.findFunctionParent() ?: return false
23+
return function.nameIdentifier == element
24+
&& function.valueParameters.singleOrNull()?.typeReference?.text == "FirSession"
25+
&& function.contextReceiverList == null
26+
&& function.hasBody()
27+
}
28+
29+
@OptIn(KaIdeApi::class)
30+
override fun invoke(project: Project, editor: Editor?, element: PsiElement) {
31+
val factory = KtPsiFactory(project)
32+
val function = element.findFunctionParent() ?: return
33+
val parameter = function.valueParameters.singleOrNull() ?: return
34+
val functionName = function.name
35+
36+
val copy1 = function.parent.addAfter((function.copy() as KtNamedFunction).apply {
37+
equalsToken?.delete()
38+
bodyExpression?.replace(
39+
factory.createBlock(
40+
"return $functionName()"
41+
)
42+
)
43+
valueParameters.first().run {
44+
addAnnotationEntry(factory.createAnnotationEntry("""@Suppress("unused")"""))
45+
setName("s")
46+
}
47+
setModifierList(factory.createModifierList("context(sessionHolder: org.jetbrains.kotlin.fir.SessionHolder)\n"))
48+
addAnnotationEntry(factory.createAnnotationEntry("""@Deprecated("Use parameterless overload", replaceWith = ReplaceWith("$functionName()"))"""))
49+
}, function) as KtElement
50+
51+
val copy2 = function.parent.addAfter((function.copy() as KtNamedFunction).apply {
52+
equalsToken?.delete()
53+
bodyExpression?.replace(
54+
factory.createBlock(
55+
"return $functionName(${parameter.nameAsName} = sessionHolder.session)"
56+
)
57+
)
58+
valueParameters.first().delete()
59+
setModifierList(factory.createModifierList("context(sessionHolder: org.jetbrains.kotlin.fir.SessionHolder)\n"))
60+
}, function) as KtElement
61+
62+
shortenReferences(listOf(copy1, copy2))
63+
}
64+
65+
private fun PsiElement.findFunctionParent(): KtNamedFunction? {
66+
return parents(withSelf = true).firstIsInstanceOrNull<KtNamedFunction>()
67+
}
68+
69+
override fun generatePreview(project: Project, editor: Editor, psiFile: PsiFile): IntentionPreviewInfo {
70+
return IntentionPreviewInfo.EMPTY
71+
}
72+
73+
override fun startInWriteAction(): Boolean = true
74+
override fun getText(): @IntentionName String = familyName
75+
override fun getFamilyName(): @IntentionFamilyName String = "Add contextual overloads"
76+
}

0 commit comments

Comments
 (0)