[ObjCExport] Implement isObjCBaseCallable util

KT-64226
This commit is contained in:
Sebastian Sellmair
2023-12-14 13:52:20 +01:00
committed by Space Team
parent b5bcfaa2e3
commit e0383282b5
2 changed files with 102 additions and 0 deletions
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.objcexport.analysisApiUtils
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
/**
* Check that given [descriptor] is a so-called "base method", i.e. method
* that doesn't override anything in a generated Objective-C interface.
* Note that it does not mean that it has no "override" keyword.
* Consider example:
* ```kotlin
* private interface I {
* fun f()
* }
*
* class C : I {
* override fun f() {}
* }
* ```
* Interface `I` is not exposed to the generated header, so C#f is considered to be a base method even though it has an "override" keyword.
*/
context(KtAnalysisSession)
fun KtCallableSymbol.isObjCBaseCallable(): Boolean {
return getAllOverriddenSymbols().none { overriddenSymbol ->
overriddenSymbol.isVisibleInObjC()
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.objcexport.tests
import org.jetbrains.kotlin.analysis.api.analyze
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isObjCBaseCallable
import org.jetbrains.kotlin.objcexport.testUtils.InlineSourceCodeAnalysis
import org.jetbrains.kotlin.objcexport.testUtils.getClassOrFail
import org.jetbrains.kotlin.objcexport.testUtils.getFunctionOrFail
import org.junit.jupiter.api.Test
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class IsObjCBaseCallableTest(
private val inlineSourceCodeAnalysis: InlineSourceCodeAnalysis,
) {
@Test
fun `test - top level function`() {
val file = inlineSourceCodeAnalysis.createKtFile("fun foo() = Unit")
analyze(file) {
val fooSymbol = file.getFunctionOrFail("foo")
assertTrue(fooSymbol.isObjCBaseCallable())
}
}
@Test
fun `test - function overriding abstract function`() {
val file = inlineSourceCodeAnalysis.createKtFile(
"""
abstract class Bar {
abstract fun x()
}
class Foo : Bar() {
override fun x() = Unit
}
""".trimIndent()
)
analyze(file) {
val fooSymbol = file.getClassOrFail("Foo")
val xSymbol = fooSymbol.getMemberScope().getFunctionOrFail("x")
assertFalse(xSymbol.isObjCBaseCallable())
}
}
@Test
fun `test - function overriding private interface function`() {
val file = inlineSourceCodeAnalysis.createKtFile(
"""
private interface I {
fun x()
}
class Foo: I {
override fun x() = Unit
}
""".trimIndent()
)
analyze(file) {
val fooSymbol = file.getClassOrFail("Foo")
val xSymbol = fooSymbol.getMemberScope().getFunctionOrFail("x")
assertTrue(xSymbol.isObjCBaseCallable())
}
}
}