Skip to content

Commit

Permalink
make plugin ready for K2 mode
Browse files Browse the repository at this point in the history
- starting from 242, the plugin works over AnalysisAPI which hides all details about kotlin engine used inside kotlin plugin itself
  • Loading branch information
akozlova committed Oct 1, 2024
1 parent a3b8db7 commit 17f4a8b
Show file tree
Hide file tree
Showing 14 changed files with 343 additions and 120 deletions.
12 changes: 12 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,18 @@ val runWithCustomSandbox by intellijPlatformTesting.runIde.registering {
}
}

//tasks.named<RunIdeTask>("runIde") {
// jvmArgumentProviders += CommandLineArgumentProvider {
// listOf("-Didea.kotlin.plugin.use.k2=true")
// }
//}

//tasks.test {
// jvmArgumentProviders += CommandLineArgumentProvider {
// listOf("-Didea.kotlin.plugin.use.k2=true")
// }
//}

intellijPlatform {
buildSearchableOptions = false
projectName = project.name
Expand Down
36 changes: 36 additions & 0 deletions src/IC-223/kotlin/io/kotest/plugin/intellij/psi/superClasses.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.kotest.plugin.intellij.psi

import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.typeUtil.supertypes

/**
* Recursively returns the list of classes and interfaces extended or implemented by the class.
*/
fun KtClassOrObject.getAllSuperClasses(): List<FqName> {
return superTypeListEntries
.mapNotNull { it.typeReference }
.mapNotNull {
runCatching {
val bindingContext = it.analyze()
bindingContext.get(BindingContext.TYPE, it)
}.getOrNull()
}.flatMap {
runCatching {
it.supertypes() + it
}.getOrElse { emptyList() }
}.mapNotNull {
runCatching {
it.constructor.declarationDescriptor.classId
}.getOrNull()
}.mapNotNull {
runCatching {
val packageName = it.packageFqName
val simpleName = it.relativeClassName
FqName("$packageName.$simpleName")
}.getOrNull()
}.filterNot { it.toString() == "kotlin.Any" }
}
36 changes: 36 additions & 0 deletions src/IC-231/kotlin/io/kotest/plugin/intellij/psi/superClasses.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.kotest.plugin.intellij.psi

import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.typeUtil.supertypes

/**
* Recursively returns the list of classes and interfaces extended or implemented by the class.
*/
fun KtClassOrObject.getAllSuperClasses(): List<FqName> {
return superTypeListEntries
.mapNotNull { it.typeReference }
.mapNotNull {
runCatching {
val bindingContext = it.analyze()
bindingContext.get(BindingContext.TYPE, it)
}.getOrNull()
}.flatMap {
runCatching {
it.supertypes() + it
}.getOrElse { emptyList() }
}.mapNotNull {
runCatching {
it.constructor.declarationDescriptor.classId
}.getOrNull()
}.mapNotNull {
runCatching {
val packageName = it.packageFqName
val simpleName = it.relativeClassName
FqName("$packageName.$simpleName")
}.getOrNull()
}.filterNot { it.toString() == "kotlin.Any" }
}
36 changes: 36 additions & 0 deletions src/IC-232/kotlin/io/kotest/plugin/intellij/psi/superClasses.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.kotest.plugin.intellij.psi

import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.typeUtil.supertypes

/**
* Recursively returns the list of classes and interfaces extended or implemented by the class.
*/
fun KtClassOrObject.getAllSuperClasses(): List<FqName> {
return superTypeListEntries
.mapNotNull { it.typeReference }
.mapNotNull {
runCatching {
val bindingContext = it.analyze()
bindingContext.get(BindingContext.TYPE, it)
}.getOrNull()
}.flatMap {
runCatching {
it.supertypes() + it
}.getOrElse { emptyList() }
}.mapNotNull {
runCatching {
it.constructor.declarationDescriptor.classId
}.getOrNull()
}.mapNotNull {
runCatching {
val packageName = it.packageFqName
val simpleName = it.relativeClassName
FqName("$packageName.$simpleName")
}.getOrNull()
}.filterNot { it.toString() == "kotlin.Any" }
}
36 changes: 36 additions & 0 deletions src/IC-233/kotlin/io/kotest/plugin/intellij/psi/superClasses.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.kotest.plugin.intellij.psi

import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.typeUtil.supertypes

/**
* Recursively returns the list of classes and interfaces extended or implemented by the class.
*/
fun KtClassOrObject.getAllSuperClasses(): List<FqName> {
return superTypeListEntries
.mapNotNull { it.typeReference }
.mapNotNull {
runCatching {
val bindingContext = it.analyze()
bindingContext.get(BindingContext.TYPE, it)
}.getOrNull()
}.flatMap {
runCatching {
it.supertypes() + it
}.getOrElse { emptyList() }
}.mapNotNull {
runCatching {
it.constructor.declarationDescriptor.classId
}.getOrNull()
}.mapNotNull {
runCatching {
val packageName = it.packageFqName
val simpleName = it.relativeClassName
FqName("$packageName.$simpleName")
}.getOrNull()
}.filterNot { it.toString() == "kotlin.Any" }
}
36 changes: 36 additions & 0 deletions src/IC-241/kotlin/io/kotest/plugin/intellij/psi/superClasses.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.kotest.plugin.intellij.psi

import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.typeUtil.supertypes

/**
* Recursively returns the list of classes and interfaces extended or implemented by the class.
*/
fun KtClassOrObject.getAllSuperClasses(): List<FqName> {
return superTypeListEntries
.mapNotNull { it.typeReference }
.mapNotNull {
runCatching {
val bindingContext = it.analyze()
bindingContext.get(BindingContext.TYPE, it)
}.getOrNull()
}.flatMap {
runCatching {
it.supertypes() + it
}.getOrElse { emptyList() }
}.mapNotNull {
runCatching {
it.constructor.declarationDescriptor.classId
}.getOrNull()
}.mapNotNull {
runCatching {
val packageName = it.packageFqName
val simpleName = it.relativeClassName
FqName("$packageName.$simpleName")
}.getOrNull()
}.filterNot { it.toString() == "kotlin.Any" }
}
32 changes: 32 additions & 0 deletions src/IC-242/kotlin/io/kotest/plugin/intellij/psi/superClasses.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.kotest.plugin.intellij.psi

import org.jetbrains.kotlin.analysis.api.analyze
import org.jetbrains.kotlin.analysis.api.permissions.KaAllowAnalysisOnEdt
import org.jetbrains.kotlin.analysis.api.permissions.allowAnalysisOnEdt
import org.jetbrains.kotlin.analysis.api.types.symbol
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.psi.KtClassOrObject

/**
* Recursively returns the list of classes and interfaces extended or implemented by the class.
*/
@OptIn(KaAllowAnalysisOnEdt::class)
fun KtClassOrObject.getAllSuperClasses(): List<FqName> {
return superTypeListEntries.mapNotNull { it.typeReference }
.flatMap { ref ->
// SurroundSelectionWithFunctionIntention.isAvailable is called in EDT before the intention is applied
// unfortunately API to avoid this was introduced in 23.2 only
// this we need to move intentions to the facade or accept EDT here until 23.2- are still supported
allowAnalysisOnEdt {
analyze(this) {
val kaType = ref.type
val superTypes = (kaType.allSupertypes(false) + kaType).toList()
superTypes.mapNotNull {
val classId = it.symbol?.classId?.takeIf { id -> id != StandardClassIds.Any }
classId?.asSingleFqName()
}
}
}
}
}
32 changes: 0 additions & 32 deletions src/main/kotlin/io/kotest/plugin/intellij/psi/classes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isAbstract
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.typeUtil.supertypes

/**
* Returns the [KtClass] from this light class, otherwise null.
Expand Down Expand Up @@ -46,34 +42,6 @@ fun PsiElement.enclosingKtClass(): KtClass? = getStrictParentOfType()
fun PsiElement.enclosingKtClassOrObject(): KtClassOrObject? =
PsiTreeUtil.getParentOfType(this, KtClassOrObject::class.java)

/**
* Recursively returns the list of classes and interfaces extended or implemented by the class.
*/
fun KtClassOrObject.getAllSuperClasses(): List<FqName> {
return superTypeListEntries
.mapNotNull { it.typeReference }
.mapNotNull {
runCatching {
val bindingContext = it.analyze()
bindingContext.get(BindingContext.TYPE, it)
}.getOrNull()
}.flatMap {
runCatching {
it.supertypes() + it
}.getOrElse { emptyList() }
}.mapNotNull {
runCatching {
it.constructor.declarationDescriptor.classId
}.getOrNull()
}.mapNotNull {
runCatching {
val packageName = it.packageFqName
val simpleName = it.relativeClassName
FqName("$packageName.$simpleName")
}.getOrNull()
}.filterNot { it.toString() == "kotlin.Any" }
}

/**
* Returns true if this [KtClassOrObject] points to a runnable spec object.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import io.kotest.plugin.intellij.psi.specs
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jetbrains.kotlin.idea.core.util.toPsiFile
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtProperty
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,8 @@
</intentionAction>
</extensions>

<extensions defaultExtensionNs="org.jetbrains.kotlin">
<supportsKotlinPluginMode supportsK2="true" />
</extensions>

</idea-plugin>
53 changes: 30 additions & 23 deletions src/test/kotlin/io/kotest/plugin/intellij/CallbacksTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.kotest.plugin.intellij

import com.intellij.openapi.application.runReadAction
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase
import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.matchers.shouldBe
Expand All @@ -16,46 +17,52 @@ class CallbacksTest : LightJavaCodeInsightFixtureTestCase() {
return path.toString()
}

override fun runInDispatchThread(): Boolean {
return false
}

fun testCallbacks() {

val psiFile = myFixture.configureByFiles(
"/callbacks.kt",
"/io/kotest/core/spec/style/specs.kt"
)[0]

val ktclass = psiFile.specs()[0]
val callbacks = ktclass.callbacks()
runReadAction {
val ktclass = psiFile.specs()[0]
val callbacks = ktclass.callbacks()

callbacks.shouldHaveSize(10)
callbacks.shouldHaveSize(10)

callbacks[0].psi.startOffset shouldBe 115
callbacks[0].type shouldBe CallbackType.BeforeTest
callbacks[0].psi.startOffset shouldBe 115
callbacks[0].type shouldBe CallbackType.BeforeTest

callbacks[1].psi.startOffset shouldBe 138
callbacks[1].type shouldBe CallbackType.AfterTest
callbacks[1].psi.startOffset shouldBe 138
callbacks[1].type shouldBe CallbackType.AfterTest

callbacks[2].psi.startOffset shouldBe 160
callbacks[2].type shouldBe CallbackType.BeforeSpec
callbacks[2].psi.startOffset shouldBe 160
callbacks[2].type shouldBe CallbackType.BeforeSpec

callbacks[3].psi.startOffset shouldBe 183
callbacks[3].type shouldBe CallbackType.AfterSpec
callbacks[3].psi.startOffset shouldBe 183
callbacks[3].type shouldBe CallbackType.AfterSpec

callbacks[4].psi.startOffset shouldBe 225
callbacks[4].type shouldBe CallbackType.AfterEach
callbacks[4].psi.startOffset shouldBe 225
callbacks[4].type shouldBe CallbackType.AfterEach

callbacks[5].psi.startOffset shouldBe 243
callbacks[5].type shouldBe CallbackType.BeforeEach
callbacks[5].psi.startOffset shouldBe 243
callbacks[5].type shouldBe CallbackType.BeforeEach

callbacks[6].psi.startOffset shouldBe 261
callbacks[6].type shouldBe CallbackType.AfterContainer
callbacks[6].psi.startOffset shouldBe 261
callbacks[6].type shouldBe CallbackType.AfterContainer

callbacks[7].psi.startOffset shouldBe 288
callbacks[7].type shouldBe CallbackType.BeforeContainer
callbacks[7].psi.startOffset shouldBe 288
callbacks[7].type shouldBe CallbackType.BeforeContainer

callbacks[8].psi.startOffset shouldBe 311
callbacks[8].type shouldBe CallbackType.BeforeAny
callbacks[8].psi.startOffset shouldBe 311
callbacks[8].type shouldBe CallbackType.BeforeAny

callbacks[9].psi.startOffset shouldBe 328
callbacks[9].type shouldBe CallbackType.AfterAny
callbacks[9].psi.startOffset shouldBe 328
callbacks[9].type shouldBe CallbackType.AfterAny
}
}
}
Loading

0 comments on commit 17f4a8b

Please sign in to comment.