Skip to content

Commit 922c8d3

Browse files
committed
Add support for Kotlin top-level functions
1 parent 5bd3235 commit 922c8d3

File tree

4 files changed

+26
-7
lines changed

4 files changed

+26
-7
lines changed

utbot-core/src/main/kotlin/org/utbot/common/KClassUtil.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ fun Method.invokeCatching(obj: Any?, args: List<Any?>) = try {
1414

1515
val KClass<*>.allNestedClasses: List<KClass<*>>
1616
get() = listOf(this) + nestedClasses.flatMap { it.allNestedClasses }
17+
18+
val Class<*>.allNestedClasses: List<Class<*>>
19+
get() = listOf(this) + this.declaredClasses.flatMap { it.declaredClasses.toList() }

utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineMain.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import org.utbot.framework.plugin.api.util.UtContext
2121
import org.utbot.framework.plugin.api.util.executableId
2222
import org.utbot.framework.plugin.api.util.id
2323
import org.utbot.framework.plugin.api.util.jClass
24+
import org.utbot.framework.plugin.api.util.method
2425
import org.utbot.framework.plugin.services.JdkInfo
2526
import org.utbot.framework.process.generated.*
2627
import org.utbot.framework.util.ConflictTriggers
@@ -36,7 +37,7 @@ import org.utbot.summary.summarize
3637
import java.io.File
3738
import java.net.URLClassLoader
3839
import java.nio.file.Paths
39-
import kotlin.reflect.full.functions
40+
import kotlin.reflect.jvm.kotlinFunction
4041
import kotlin.time.Duration.Companion.seconds
4142

4243
private val messageFromMainTimeoutMillis = 120.seconds
@@ -158,8 +159,8 @@ private fun EngineProcessModel.setup(
158159
synchronizer.measureExecutionForTermination(findMethodsInClassMatchingSelected) { params ->
159160
val classId = kryoHelper.readObject<ClassId>(params.classId)
160161
val selectedSignatures = params.signatures.map { Signature(it.name, it.parametersTypes) }
161-
FindMethodsInClassMatchingSelectedResult(kryoHelper.writeObject(classId.jClass.kotlin.allNestedClasses.flatMap { clazz ->
162-
clazz.functions.sortedWith(compareBy { selectedSignatures.indexOf(it.signature()) })
162+
FindMethodsInClassMatchingSelectedResult(kryoHelper.writeObject(classId.jClass.allNestedClasses.flatMap { clazz ->
163+
clazz.id.allMethods.mapNotNull { it.method.kotlinFunction }.sortedWith(compareBy { selectedSignatures.indexOf(it.signature()) })
163164
.filter { it.signature().normalized() in selectedSignatures }
164165
.map { it.executableId }
165166
}))
@@ -168,7 +169,7 @@ private fun EngineProcessModel.setup(
168169
val classId = kryoHelper.readObject<ClassId>(params.classId)
169170
val bySignature = kryoHelper.readObject<Map<Signature, List<String>>>(params.bySignature)
170171
FindMethodParamNamesResult(kryoHelper.writeObject(
171-
classId.jClass.kotlin.allNestedClasses.flatMap { it.functions }
172+
classId.jClass.allNestedClasses.flatMap { clazz -> clazz.id.allMethods.mapNotNull { it.method.kotlinFunction } }
172173
.mapNotNull { method -> bySignature[method.signature()]?.let { params -> method.executableId to params } }
173174
.toMap()
174175
))

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/actions/GenerateTestsAction.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@ import com.intellij.openapi.roots.ModuleRootManager
1616
import com.intellij.openapi.roots.ProjectFileIndex
1717
import com.intellij.openapi.vfs.VirtualFile
1818
import com.intellij.psi.*
19+
import com.intellij.psi.impl.PsiJavaParserFacadeImpl
1920
import com.intellij.psi.util.PsiTreeUtil
2021
import com.intellij.refactoring.util.classMembers.MemberInfo
22+
import org.jetbrains.kotlin.asJava.findFacadeClass
2123
import org.jetbrains.kotlin.idea.core.getPackage
2224
import org.jetbrains.kotlin.idea.core.util.toPsiDirectory
2325
import org.jetbrains.kotlin.idea.core.util.toPsiFile
2426
import org.utbot.intellij.plugin.util.extractFirstLevelMembers
2527
import org.utbot.intellij.plugin.util.isVisible
2628
import java.util.*
2729
import org.jetbrains.kotlin.j2k.getContainingClass
30+
import org.jetbrains.kotlin.psi.KtFile
2831
import org.jetbrains.kotlin.utils.addIfNotNull
2932
import org.utbot.framework.plugin.api.util.LockFile
3033
import org.utbot.intellij.plugin.models.packageName
@@ -58,11 +61,13 @@ class GenerateTestsAction : AnAction(), UpdateInBackground {
5861
if (editor != null) {
5962
//The action is being called from editor
6063
val file = e.getData(CommonDataKeys.PSI_FILE) ?: return null
64+
//file.setName("abcdef")
6165
val element = findPsiElement(file, editor) ?: return null
6266

6367
val psiElementHandler = PsiElementHandler.makePsiElementHandler(file)
6468

65-
if (psiElementHandler.isCreateTestActionAvailable(element)) {
69+
// When in Kotlin file, we should propose top-level functions for testing
70+
if (psiElementHandler.isCreateTestActionAvailable(element) || file is KtFile) {
6671
val srcClass = psiElementHandler.containingClass(element) ?: return null
6772
val srcSourceRoot = srcClass.getSourceRoot() ?: return null
6873
val srcMembers = srcClass.extractFirstLevelMembers(false)
@@ -225,6 +230,7 @@ class GenerateTestsAction : AnAction(), UpdateInBackground {
225230
return emptySet()
226231
}
227232
val allClasses = psiFiles.flatMap { getClassesFromFile(it) }.toMutableSet()
233+
allClasses.addAll(psiFiles.mapNotNull { (it as? KtFile)?.findFacadeClass() })
228234
for (psiDir in psiDirectories) allClasses += getAllClasses(psiDir)
229235

230236
return allClasses

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/utils/KotlinPsiElementHandler.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ package org.utbot.intellij.plugin.ui.utils
22

33
import com.intellij.psi.PsiClass
44
import com.intellij.psi.PsiElement
5+
import com.intellij.psi.util.findParentOfType
6+
import org.jetbrains.kotlin.asJava.findFacadeClass
57
import org.jetbrains.kotlin.idea.testIntegration.KotlinCreateTestIntention
68
import org.jetbrains.kotlin.psi.KtClass
79
import org.jetbrains.kotlin.psi.KtClassOrObject
810
import org.jetbrains.kotlin.psi.KtFile
911
import org.jetbrains.kotlin.psi.KtNamedDeclaration
1012
import org.jetbrains.kotlin.psi.KtNamedFunction
1113
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
14+
import org.jetbrains.kotlin.toKtPsiSourceElement
1215
import org.jetbrains.uast.toUElement
1316

1417
class KotlinPsiElementHandler(
@@ -31,6 +34,12 @@ class KotlinPsiElementHandler(
3134
element?.parentsWithSelf
3235
?.firstOrNull { it is KtClassOrObject || it is KtNamedDeclaration && it.parent is KtFile } as? KtNamedDeclaration
3336

34-
override fun containingClass(element: PsiElement): PsiClass? =
35-
element.parentsWithSelf.firstOrNull { it is KtClassOrObject }?.let { toPsi(it, PsiClass::class.java) }
37+
override fun containingClass(element: PsiElement): PsiClass? {
38+
element.findParentOfType<KtClassOrObject>(strict=false)?.let {
39+
return toPsi(it, PsiClass::class.java)
40+
}
41+
return element.findParentOfType<KtFile>(strict=false)?.findFacadeClass()?.let {
42+
toPsi(it, PsiClass::class.java)
43+
}
44+
}
3645
}

0 commit comments

Comments
 (0)