diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt index f10c7c25822..68e970389da 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt @@ -38,4 +38,5 @@ object KonanFqNames { val eagerInitialization = FqName("kotlin.native.EagerInitialization") val noReorderFields = FqName("kotlin.native.internal.NoReorderFields") val objCName = FqName("kotlin.native.ObjCName") + val reflectionPackageName = FqName("kotlin.native.internal.ReflectionPackageName") } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt index a8125617945..97bef846fb7 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt @@ -12,10 +12,7 @@ import org.jetbrains.kotlin.backend.konan.ir.getSuperClassNotAny import org.jetbrains.kotlin.backend.konan.ir.isAny import org.jetbrains.kotlin.backend.konan.lower.FunctionReferenceLowering.Companion.isLoweredFunctionReference import org.jetbrains.kotlin.builtins.PrimitiveType -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrField -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrProperty +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.FqName @@ -564,7 +561,15 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { } private fun getReflectionInfo(irClass: IrClass): ReflectionInfo { - val packageName: String = irClass.getPackageFragment().fqName.asString() // Compute and store package name in TypeInfo anyways. + val packageFragment = irClass.getPackageFragment() + val reflectionPackageName = if (packageFragment is IrFile) { + // This annotation is used by test infrastructure. + packageFragment.annotations.findAnnotation(KonanFqNames.reflectionPackageName)?.getAnnotationStringValue() + } else { + null + } + + val packageName: String = reflectionPackageName ?: packageFragment.fqName.asString() // Compute and store package name in TypeInfo anyways. val relativeName: String? val flags: Int diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/Annotations.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/Annotations.kt index 1a6aaacd938..153e461386d 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/Annotations.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/Annotations.kt @@ -178,3 +178,14 @@ internal annotation class HasFreezeHook @Retention(value = AnnotationRetention.BINARY) @InternalForKotlinNative annotation class GCUnsafeCall(val callee: String) + +/** + * Marks a declaration that is internal for Kotlin/Native tests and shouldn't be used externally. + */ +@RequiresOptIn(level = RequiresOptIn.Level.ERROR) +@Retention(value = AnnotationRetention.BINARY) +internal annotation class InternalForKotlinNativeTests + +@InternalForKotlinNativeTests +@Target(AnnotationTarget.FILE) +public annotation class ReflectionPackageName(val name: String) diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/ExtTestCaseGroupProvider.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/ExtTestCaseGroupProvider.kt index b0693322d55..3ab0f7ee51e 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/ExtTestCaseGroupProvider.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/group/ExtTestCaseGroupProvider.kt @@ -152,6 +152,7 @@ private class ExtTestDataFile( val args = mutableListOf() testDataFileSettings.languageSettings.sorted().mapTo(args) { "-XXLanguage:$it" } testDataFileSettings.optInsForCompiler.sorted().mapTo(args) { "-opt-in=$it" } + args += "-opt-in=kotlin.native.internal.InternalForKotlinNativeTests" // for ReflectionPackageName if (testDataFileSettings.expectActualLinker) args += "-Xexpect-actual-linker" return TestCompilerArgs(args) } @@ -281,6 +282,12 @@ private class ExtTestDataFile( file.addAfter(newPackageDirective, file.fileAnnotationList).ensureSurroundedByWhiteSpace() } + // Add @ReflectionPackageName annotation to make the compiler use original package name in the reflective information. + val annotationText = + "kotlin.native.internal.ReflectionPackageName(${oldPackageName.asString().quoteAsKotlinStringLiteral()})" + val fileAnnotationList = handler.psiFactory.createFileAnnotationListWithAnnotation(annotationText) + file.addAnnotations(fileAnnotationList) + visitKtElement(file, file.collectAccessibleDeclarationNames()) } @@ -468,23 +475,13 @@ private class ExtTestDataFile( filesToTransform.forEach { handler -> handler.accept(object : KtTreeVisitorVoid() { override fun visitKtFile(file: KtFile) { - val oldFileAnnotationList = file.fileAnnotationList - val newFileAnnotationList = handler.psiFactory.createFile(buildString { testDataFileSettings.optInsForSourceCode.forEach { appendLine(getAnnotationText(it)) } }).fileAnnotationList!! - if (oldFileAnnotationList != null) { - // Add new annotations to the old ones. - newFileAnnotationList.annotationEntries.forEach { - oldFileAnnotationList.add(it).ensureSurroundedByWhiteSpace() - } - } else { - // Insert the annotations list immediately before package directive. - file.addBefore(newFileAnnotationList, file.packageDirective).ensureSurroundedByWhiteSpace() - } + file.addAnnotations(newFileAnnotationList) } }) } @@ -493,6 +490,19 @@ private class ExtTestDataFile( return allFileLevelAnnotationsSorted } + private fun KtFile.addAnnotations(fileAnnotationList: KtFileAnnotationList) { + val oldFileAnnotationList = this.fileAnnotationList + if (oldFileAnnotationList != null) { + // Add new annotations to the old ones. + fileAnnotationList.annotationEntries.forEach { + oldFileAnnotationList.add(it).ensureSurroundedByWhiteSpace() + } + } else { + // Insert the annotations list immediately before package directive. + this.addBefore(fileAnnotationList, packageDirective).ensureSurroundedByWhiteSpace() + } + } + /** Finds the fully-qualified name of the entry point function (aka `fun box(): String`). */ private fun findEntryPoint(): String = with(structure) { val result = mutableListOf() diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/util/Names.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/util/Names.kt index f11ce9ccd05..c6a09e78b74 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/util/Names.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/util/Names.kt @@ -31,3 +31,28 @@ internal const val LAUNCHER_MODULE_NAME = "__launcher__" // Used only in KLIB te internal const val STATIC_CACHE_DIR_NAME = "__static_cache__" internal fun prettyHash(hash: Int): String = hash.toUInt().toString(16).padStart(8, '0') + +/** + * Returns the expression to be parsed by Kotlin as string literal with given contents, + * i.e. transforms `foo$bar` to `"foo\$bar"`. + */ +internal fun String.quoteAsKotlinStringLiteral(): String = buildString { + append('"') + + this@quoteAsKotlinStringLiteral.forEach { c -> + when (c) { + in charactersAllowedInKotlinStringLiterals -> append(c) + '$' -> append("\\$") + else -> append("\\u" + "%04X".format(c.code)) + } + } + + append('"') +} + +private val charactersAllowedInKotlinStringLiterals: Set = mutableSetOf().apply { + addAll('a' .. 'z') + addAll('A' .. 'Z') + addAll('0' .. '9') + addAll(listOf('_', '@', ':', ';', '.', ',', '{', '}', '=', '[', ']', '^', '#', '*', ' ', '(', ')')) +}