diff --git a/.space/CODEOWNERS b/.space/CODEOWNERS index 7515fc8dd53..13d87486275 100644 --- a/.space/CODEOWNERS +++ b/.space/CODEOWNERS @@ -360,6 +360,7 @@ /license/ "Kotlin Build Infrastructure" /native/ "Kotlin Native" +/native/analysis-api-klib-reader/ "Kotlin Native" "Kotlin in Fleet" /native/commonizer/ "Kotlin Apple Ecosystem" /native/commonizer-api/ "Kotlin Apple Ecosystem" /native/commonizer-embeddable/ "Kotlin Apple Ecosystem" diff --git a/build.gradle.kts b/build.gradle.kts index 2730fdafed6..6e30e682be6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -811,10 +811,11 @@ tasks { // - different GCs // ... register("nativeCompilerTest") { + dependsOn(":kotlin-atomicfu-compiler-plugin:nativeTest") + dependsOn(":native:analysis-api-klib-reader:check") dependsOn(":native:native.tests:test") dependsOn(":native:objcexport-header-generator:check") dependsOn(":native:swift:swift-export-standalone:test") - dependsOn(":kotlin-atomicfu-compiler-plugin:nativeTest") } // These are unit tests of Native compiler diff --git a/native/analysis-api-klib-reader/ReadMe.md b/native/analysis-api-klib-reader/ReadMe.md new file mode 100644 index 00000000000..ee06dafcb86 --- /dev/null +++ b/native/analysis-api-klib-reader/ReadMe.md @@ -0,0 +1,61 @@ +# Native Analysis Api based Klib reader + +## Tasks + +**Run Tests** + +``` +./gradlew :native:analysis-api-klib-reader:check +``` + +## Usage: Reading symbols from a given klib module + +A set of top level `KlibDeclarationAddress` can be read from `KtLibraryModule` by + +```kotlin +fun example(module: KtLibraryModule) { + val addresses = module.readKlibDeclarationAddresses() +} +``` + +Such addresses can be resolved to `KtSymbol`s by + +```kotlin +addresses.flatMap { address -> address.getSymbols() } +``` + +Note: `getSymbols` returns a sequence as multiple symbols can live under the same address. + +## Usage: Getting all library modules in a Standalone Analysis API session. + +Example of creating a session +```kotin + val session = buildStandaloneAnalysisAPISession { + buildKtModuleProvider { + // ... + addModule(buildKtLibraryModule { + addBinaryRoot(pathToKlib) + // .. + }) + } + } +``` + +Example analyzing libraries within the session +```kotlin +session.getAllLibraryModules().forEach { module -> + analyze(module) { + module.readKlibDeclarationAddresses() + .flatMap { address -> address.getSymbols() } + } +} +``` + +## Test Strategy + +### Black Box Test: + +We are building a klib from the `testProject`. +This klib will be used to read the addresses. Those addresses will be rendered and compared to +[!testProject.addresses](testData%2F%21testProject.addresses) + diff --git a/native/analysis-api-klib-reader/build.gradle.kts b/native/analysis-api-klib-reader/build.gradle.kts new file mode 100644 index 00000000000..7619f08c09f --- /dev/null +++ b/native/analysis-api-klib-reader/build.gradle.kts @@ -0,0 +1,67 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages +import org.jetbrains.kotlin.konan.target.HostManager + +plugins { + kotlin("jvm") +} + +sourceSets { + "main" { projectDefault() } + "test" { projectDefault() } +} + +kotlin { + compilerOptions { + explicitApi() + + /* Required to use Analysis Api */ + freeCompilerArgs.add("-Xcontext-receivers") + } +} + +projectTest(jUnitMode = JUnitMode.JUnit5) { + workingDir = rootDir + + useJUnitPlatform() + val testProjectKlib = configurations.create("testProjectKlib") { + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_API)) + attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY)) + attribute(KotlinPlatformType.attribute, KotlinPlatformType.native) + attribute(KotlinNativeTarget.konanTargetAttribute, HostManager.host.name) + } + } + + val testProjectKlibFiles = testProjectKlib.incoming.files + + dependencies { + testProjectKlib(project("testProject")) + } + + inputs.files(testProjectKlibFiles) + .withPathSensitivity(PathSensitivity.RELATIVE) + + doFirst { + systemProperty("testKlibs", testProjectKlibFiles.joinToString(File.pathSeparator)) + } +} + +dependencies { + api(project(":analysis:analysis-api")) + + implementation(project(":core:compiler.common")) + implementation(project(":core:compiler.common.native")) + implementation(project(":kotlin-tooling-core")) + + compileOnly(project(":analysis:analysis-api-standalone")) + compileOnly(project(":core:metadata")) + compileOnly(project(":kotlin-metadata")) + compileOnly(project(":kotlin-util-klib-metadata")) + compileOnly(protobufLite()) + + testImplementation(kotlinTest("junit5")) + testImplementation(project(":compiler:tests-common", "tests-jar")) + testImplementation(project(":analysis:analysis-api-standalone")) +} diff --git a/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/KlibDeclarationAddress.kt b/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/KlibDeclarationAddress.kt new file mode 100644 index 00000000000..1ede34ec823 --- /dev/null +++ b/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/KlibDeclarationAddress.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2024 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.analysis.api.klib.reader + +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name + +public sealed class KlibDeclarationAddress { + public abstract val sourceFileName: String? + public abstract val packageFqName: FqName +} + +public sealed class KlibClassifierAddress : KlibDeclarationAddress() { + public abstract val classId: ClassId +} + +public data class KlibClassAddress( + public override val sourceFileName: String?, + public override val packageFqName: FqName, + public override val classId: ClassId, +) : KlibClassifierAddress() + +public data class KlibTypeAliasAddress( + override val packageFqName: FqName, + override val classId: ClassId, +) : KlibClassifierAddress() { + /** + * TypeAlias do not encode their source file name into klibs. This value is always null. + */ + override val sourceFileName: Nothing? = null +} + +public sealed class KlibCallableAddress : KlibDeclarationAddress() { + public abstract val callableName: Name +} + +public data class KlibPropertyAddress( + override val sourceFileName: String?, + override val packageFqName: FqName, + override val callableName: Name, +) : KlibCallableAddress() + +public data class KlibFunctionAddress( + override val sourceFileName: String?, + override val packageFqName: FqName, + override val callableName: Name, +) : KlibCallableAddress() diff --git a/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/PackageFragmentReadingContext.kt b/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/PackageFragmentReadingContext.kt new file mode 100644 index 00000000000..c05b37994c5 --- /dev/null +++ b/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/PackageFragmentReadingContext.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2010-2024 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.analysis.api.klib.reader + +import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf +import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl +import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull +import org.jetbrains.kotlin.name.FqName + +internal fun PackageFragmentReadingContext(packageFragmentProto: ProtoBuf.PackageFragment): PackageFragmentReadingContext? { + val nameResolver = NameResolverImpl(packageFragmentProto.strings, packageFragmentProto.qualifiedNames) + val packageFqName = packageFragmentProto.`package`.getExtensionOrNull(KlibMetadataProtoBuf.packageFqName) + ?.let { packageFqNameStringIndex -> nameResolver.getPackageFqName(packageFqNameStringIndex) } ?: return null + return PackageFragmentReadingContext(FqName(packageFqName), nameResolver) +} + +internal class PackageFragmentReadingContext( + val packageFqName: FqName, + val nameResolver: NameResolverImpl, +) diff --git a/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/getAllLibraryModules.kt b/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/getAllLibraryModules.kt new file mode 100644 index 00000000000..8ecf82d414c --- /dev/null +++ b/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/getAllLibraryModules.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2024 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.analysis.api.klib.reader + +import org.jetbrains.kotlin.analysis.api.standalone.StandaloneAnalysisAPISession +import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtStaticProjectStructureProvider +import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider +import org.jetbrains.kotlin.analysis.project.structure.allDirectDependencies +import org.jetbrains.kotlin.tooling.core.withClosureSequence + +/** + * Returns all registered [KtLibraryModule] in this [StandaloneAnalysisAPISession]. + * Note: If a library module is not added as a dependency of another module, make sure to add the module directly as in: + * ```kotlin + * buildKtModuleProvider { + * addModule( // <- !! addModule !! + * buildKtLibraryModule { + * addBinaryRoot(myKlibRootPath) + * libraryName = myLibraryName + * // ... + * } + * ) + * } + * ``` + */ +public fun StandaloneAnalysisAPISession.getAllLibraryModules(): Sequence { + val projectStructureProvider = project.getService(ProjectStructureProvider::class.java) + ?: error("${ProjectStructureProvider::class.java} not found") + + if (projectStructureProvider !is KtStaticProjectStructureProvider) { + error("Expected implementation of ${KtStaticProjectStructureProvider::class.java} but found ${projectStructureProvider.javaClass}") + } + + return projectStructureProvider.allKtModules + .withClosureSequence { module -> module.allDirectDependencies().asIterable() } + .filterIsInstance() +} \ No newline at end of file diff --git a/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/getSymbols.kt b/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/getSymbols.kt new file mode 100644 index 00000000000..ade8537df39 --- /dev/null +++ b/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/getSymbols.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2010-2024 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.analysis.api.klib.reader + +import org.jetbrains.kotlin.analysis.api.KtAnalysisSession +import org.jetbrains.kotlin.analysis.api.symbols.* + +/** + * Note: A single [KlibDeclarationAddress] can be shared by multiple symbols. + * e.g. the [KlibDeclarationAddress] for functions with overloads will be shared. + * + * ```kotlin + * fun foo() = 42 + * fun foo(param: Int) = param + * ``` + * + * Both foo functions will live under the same [KlibDeclarationAddress] + * + * @return all symbols under the given [KlibDeclarationAddress]. + * @see [getClassOrObjectSymbol] + * @see [getFunctionSymbols] + * @see [getPropertySymbols] + */ +context(KtAnalysisSession) +public fun KlibDeclarationAddress.getSymbols(): Sequence { + return when (this) { + is KlibClassAddress -> getClassOrObjectSymbol()?.let { symbol -> sequenceOf(symbol) } ?: emptySequence() + is KlibTypeAliasAddress -> getTypeAliasSymbol()?.let { symbol -> sequenceOf(symbol) } ?: emptySequence() + is KlibFunctionAddress -> getFunctionSymbols() + is KlibPropertyAddress -> getPropertySymbols() + } +} + +/** + * @see [getSymbols] + */ +context(KtAnalysisSession) +public fun KlibClassAddress.getClassOrObjectSymbol(): KtClassOrObjectSymbol? { + return getClassOrObjectSymbolByClassId(classId) +} + +context(KtAnalysisSession) +public fun KlibTypeAliasAddress.getTypeAliasSymbol(): KtTypeAliasSymbol? { + return getTypeAliasByClassId(classId) +} + +/** + * @see [getSymbols] + */ +context(KtAnalysisSession) +public fun KlibCallableAddress.getCallableSymbols(): Sequence { + return when (this) { + is KlibFunctionAddress -> getFunctionSymbols() + is KlibPropertyAddress -> getPropertySymbols() + } +} + +/** + * @see [getSymbols] + */ +context(KtAnalysisSession) +public fun KlibFunctionAddress.getFunctionSymbols(): Sequence { + return getTopLevelCallableSymbols(packageFqName, callableName) + .filterIsInstance() +} + +/** + * @see [getSymbols] + */ +context(KtAnalysisSession) +public fun KlibPropertyAddress.getPropertySymbols(): Sequence { + return getTopLevelCallableSymbols(packageFqName, callableName) + .filterIsInstance() +} + diff --git a/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/readKlibDeclarationAddresses.kt b/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/readKlibDeclarationAddresses.kt new file mode 100644 index 00000000000..7f0662f840f --- /dev/null +++ b/native/analysis-api-klib-reader/src/org/jetbrains/kotlin/analysis/api/klib/reader/readKlibDeclarationAddresses.kt @@ -0,0 +1,135 @@ +/* + * Copyright 2010-2024 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.analysis.api.klib.reader + +import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol +import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule +import org.jetbrains.kotlin.konan.file.File +import org.jetbrains.kotlin.library.KotlinLibrary +import org.jetbrains.kotlin.library.ToolingSingleFileKlibResolveStrategy +import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf +import org.jetbrains.kotlin.library.metadata.parseModuleHeader +import org.jetbrains.kotlin.library.metadata.parsePackageFragment +import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.util.DummyLogger +import org.jetbrains.kotlin.util.Logger +import java.nio.file.Path +import kotlin.io.path.extension +import kotlin.io.path.isDirectory + +/** + * Provides a set of [KlibDeclarationAddress] contained within the given [KtLibraryModule] (if the library is based upon a klib file). + * These addresses will contain all top level declarations such as top level classes, interfaces, objects, ... and + * top level callables such as functions and properties. + * + * Example, given the provided source file + * ```kotlin + * package com.example + * fun topLevelFunction() = 42 + * + * class Foo { + * val foo() = 42 + * class Bar { + * fun bar() = 42 + * } + * } + * ``` + * + * The read addresses will include `topLevelFunction` as well as `Foo`, as both declarations are top level. + * These addresses can then be resolved to its given [KtSymbol] by + * + * - [KlibClassAddress.getClassOrObjectSymbol]: Resolves to the class symbol or null + * - [KlibCallableAddress.getCallableSymbols]: Resolves all callable symbols under this given address + * + * @return The returned set has a stable order + */ +public fun KtLibraryModule.readKlibDeclarationAddresses(): Set? { + val binary = getBinaryRoots().singleOrNull() ?: return null + if (!(binary.extension == "klib" || binary.isDirectory())) return null + return readKlibDeclarationAddresses(binary) +} + +internal fun readKlibDeclarationAddresses(path: Path, logger: Logger = DummyLogger): Set? { + val library = ToolingSingleFileKlibResolveStrategy.tryResolve(File(path), logger) ?: return null + return readKlibDeclarationAddresses(library) +} + +internal fun readKlibDeclarationAddresses(library: KotlinLibrary): Set { + val headerProto = parseModuleHeader(library.moduleHeaderData) + + val packageMetadataSequence = headerProto.packageFragmentNameList.asSequence().flatMap { packageFragmentName -> + library.packageMetadataParts(packageFragmentName).asSequence().map { packageMetadataPart -> + library.packageMetadata(packageFragmentName, packageMetadataPart) + } + } + + return packageMetadataSequence.flatMap { packageMetadata -> + val packageFragmentProto = parsePackageFragment(packageMetadata) + + with(PackageFragmentReadingContext(packageFragmentProto) ?: return@flatMap emptySet()) { + packageFragmentProto.readKlibClassAddresses() + + packageFragmentProto.readKlibTypeAliasAddresses() + + packageFragmentProto.readKlibPropertyAddresses() + + packageFragmentProto.readKlibFunctionAddresses() + } + }.toSet() + +} + +context(PackageFragmentReadingContext) +internal fun ProtoBuf.PackageFragment.readKlibClassAddresses(): Set { + return class_List.mapNotNull { classProto -> + val classId = ClassId.fromString(nameResolver.getQualifiedClassName(classProto.fqName)) + if (classId.isNestedClass) return@mapNotNull null + KlibClassAddress( + packageFqName = packageFqName, + sourceFileName = classProto.getExtensionOrNull(KlibMetadataProtoBuf.classFile)?.let { fileNameId -> + nameResolver.strings.getString(fileNameId) + }, + classId = classId + ) + }.toSet() +} + +context(PackageFragmentReadingContext) +internal fun ProtoBuf.PackageFragment.readKlibTypeAliasAddresses(): Set { + return this.`package`.typeAliasList.map { typeAliasProto -> + val name = Name.identifier(nameResolver.getString(typeAliasProto.name)) + KlibTypeAliasAddress( + packageFqName = packageFqName, + classId = ClassId(packageFqName, name) + ) + }.toSet() +} + +context(PackageFragmentReadingContext) +internal fun ProtoBuf.PackageFragment.readKlibPropertyAddresses(): Set { + return `package`.propertyList.map { propertyProto -> + KlibPropertyAddress( + sourceFileName = propertyProto.getExtensionOrNull(KlibMetadataProtoBuf.propertyFile)?.let { fileNameId -> + nameResolver.strings.getString(fileNameId) + }, + packageFqName = packageFqName, + callableName = Name.identifier(nameResolver.getString(propertyProto.name)) + ) + }.toSet() +} + +context(PackageFragmentReadingContext) +internal fun ProtoBuf.PackageFragment.readKlibFunctionAddresses(): Set { + return `package`.functionList.map { functionProto -> + KlibFunctionAddress( + sourceFileName = functionProto.getExtensionOrNull(KlibMetadataProtoBuf.functionFile)?.let { fileNameId -> + nameResolver.getString(fileNameId) + }, + packageFqName = packageFqName, + callableName = Name.identifier(nameResolver.getString(functionProto.name)) + ) + }.toSet() +} diff --git a/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/testUtils/providedTestKlibs.kt b/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/testUtils/providedTestKlibs.kt new file mode 100644 index 00000000000..9e79bcffeec --- /dev/null +++ b/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/testUtils/providedTestKlibs.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2010-2024 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.analysis.api.klib.reader.testUtils + +import java.io.File +import java.nio.file.Path +import kotlin.io.path.Path + +val providedTestKlibs: Set = System.getProperty("testKlibs").let { testKlibs -> + if (testKlibs == null) error("Missing 'testKlibs' System property") + testKlibs.split(File.pathSeparator).map(::Path).toSet() +} + +val providedTestProjectKlib = providedTestKlibs.find { path -> + path.contains(Path("testProject")) +} ?: error("Missing 'testProject' klib") \ No newline at end of file diff --git a/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/testUtils/render.kt b/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/testUtils/render.kt new file mode 100644 index 00000000000..8d6add71a23 --- /dev/null +++ b/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/testUtils/render.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2024 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.analysis.api.klib.reader.testUtils + +import org.jetbrains.kotlin.analysis.api.klib.reader.* + +fun Iterable.render() = joinToString(System.lineSeparator().repeat(2)) { it.render() } + +fun KlibDeclarationAddress.render(): String { + return when (this) { + is KlibFunctionAddress -> render() + is KlibPropertyAddress -> render() + is KlibClassAddress -> render() + is KlibTypeAliasAddress -> render() + } +} + +private fun KlibFunctionAddress.render(): String = """ + Function (${packageFqName.child(callableName).asString()}) + Source File Name : "$sourceFileName" + Package Name : "${packageFqName.asString()}" + Function Name : "${callableName.asString()}" +""".trimIndent() + +private fun KlibPropertyAddress.render(): String = """ + Property (${packageFqName.child(callableName).asString()}) + Source File Name : "$sourceFileName" + Package Name : "${packageFqName.asString()}" + Property Name : "${callableName.asString()}" +""".trimIndent() + +private fun KlibClassAddress.render(): String = """ + Class (${classId.asFqNameString()}) + Source File Name : "$sourceFileName" + Package Name : "${packageFqName.asString()}" + ClassId : "${classId.asString()}" +""".trimIndent() + +private fun KlibTypeAliasAddress.render(): String = """ + TypeAlias (${classId.asFqNameString()}) + Package Name : "${packageFqName.asString()}" + ClassId : "${classId.asString()}" +""".trimIndent() + diff --git a/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/testUtils/testDataDir.kt b/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/testUtils/testDataDir.kt new file mode 100644 index 00000000000..71ba94e25fd --- /dev/null +++ b/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/testUtils/testDataDir.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2010-2024 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.analysis.api.klib.reader.testUtils + +import kotlin.io.path.Path + +val testDataDir = Path("native/analysis-api-klib-reader/testData") \ No newline at end of file diff --git a/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/tests/GetSymbolsTest.kt b/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/tests/GetSymbolsTest.kt new file mode 100644 index 00000000000..4c0fce8f5a9 --- /dev/null +++ b/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/tests/GetSymbolsTest.kt @@ -0,0 +1,158 @@ +/* + * Copyright 2010-2024 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.analysis.api.klib.reader.tests + +import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals +import org.jetbrains.kotlin.analysis.api.KtAnalysisSession +import org.jetbrains.kotlin.analysis.api.analyze +import org.jetbrains.kotlin.analysis.api.klib.reader.* +import org.jetbrains.kotlin.analysis.api.klib.reader.testUtils.providedTestProjectKlib +import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenProvider +import org.jetbrains.kotlin.analysis.api.standalone.KtAlwaysAccessibleLifetimeTokenProvider +import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISession +import org.jetbrains.kotlin.analysis.api.symbols.KtClassKind +import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol +import org.jetbrains.kotlin.analysis.api.symbols.nameOrAnonymous +import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule +import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtLibraryModule +import org.jetbrains.kotlin.konan.target.HostManager +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.platform.konan.NativePlatforms +import kotlin.io.path.nameWithoutExtension +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.fail + +class GetSymbolsTest { + @Test + fun `test - getClassOrObjectSymbol - RootPkgClass`() { + withTestProjectLibraryAnalysisSession { + val addresses = (useSiteModule as KtLibraryModule).readKlibDeclarationAddresses() + ?: error("Failed reading declaration addresses") + + val rootPkgClassAddress = addresses.filterIsInstance() + .first { it.classId == ClassId.fromString("RootPkgClass") } + + + val rootPkgClassSymbol = assertNotNull(rootPkgClassAddress.getClassOrObjectSymbol()) + + assertEquals("RootPkgClass", rootPkgClassSymbol.nameOrAnonymous.asString()) + } + } + + @Test + fun `test - getClassOrObjectSymbol - AObject`() { + withTestProjectLibraryAnalysisSession { + val addresses = (useSiteModule as KtLibraryModule).readKlibDeclarationAddresses() + ?: error("Failed reading declaration addresses") + + val aObjectAddress = addresses.filterIsInstance() + .first { it.classId == ClassId.fromString("org/jetbrains/sample/a/AObject") } + + + val aObjectSymbol = assertNotNull(aObjectAddress.getClassOrObjectSymbol()) + + assertEquals("AObject", aObjectSymbol.nameOrAnonymous.asString()) + assertEquals(KtClassKind.OBJECT, aObjectSymbol.classKind) + } + } + + @Test + fun `test - getSymbols - rootPkgProperty`() { + withTestProjectLibraryAnalysisSession { + val addresses = (useSiteModule as KtLibraryModule).readKlibDeclarationAddresses() + ?: error("Failed reading declaration addresses") + + val rootPkgPropertyAddress = addresses.filterIsInstance() + .first { it.callableName == Name.identifier("rootPkgProperty") } + + val rootPkgPropertySymbols = rootPkgPropertyAddress.getSymbols().toList() + if (rootPkgPropertySymbols.size != 1) fail("Expected only a single 'rootPkgProperty' symbol. Found $rootPkgPropertySymbols") + + /* Check getSymbols and getPropertySymbols behave the same */ + assertEquals( + rootPkgPropertySymbols, + rootPkgPropertyAddress.getPropertySymbols().toList(), + "Expected 'getSymbols' and 'getPropertySymbols' to be equal" + ) + + val symbol = rootPkgPropertySymbols.single() as KtPropertySymbol + assertEquals("rootPkgProperty", symbol.name.asString()) + } + } + + @Test + fun `test - getSymbols - aFunction`() { + withTestProjectLibraryAnalysisSession { + val addresses = (useSiteModule as KtLibraryModule).readKlibDeclarationAddresses() + ?: error("Failed reading declaration addresses") + + val aFunctionAddress = addresses.filterIsInstance() + .first { it.callableName == Name.identifier("aFunction") } + + val aFunctionSymbols = aFunctionAddress.getFunctionSymbols().toList() + if (aFunctionSymbols.size != 2) fail("Expected exactly 2 'aFunction' symbols. Found $aFunctionSymbols") + + /* Check: getFunctionSymbols and getSymbols behave the same */ + assertEquals( + aFunctionSymbols, + aFunctionAddress.getSymbols().toList(), + "Expected 'getSymbols' and 'getFunctionSymbols' to be equal" + ) + + aFunctionSymbols.forEach { symbol -> + assertEquals("aFunction", symbol.name.asString()) + } + + /* Check: One function does not have any value params, the other function has a single param with name 'seed' */ + assertEquals( + setOf(emptyList(), listOf("seed")), aFunctionSymbols.map { it.valueParameters.map { it.name.asString() } }.toSet() + ) + } + } + + @Test + fun `test - getTypeAlias - TypeAliasA`() { + withTestProjectLibraryAnalysisSession { + val addresses = (useSiteModule as KtLibraryModule).readKlibDeclarationAddresses() ?: fail("Failed reading addresses") + val typeAliasAAddress = addresses.filterIsInstance() + .find { it.classId == ClassId.fromString("org/jetbrains/sample/TypeAliasA") } + ?: fail("Could not find TypeAliasA") + + val typeAliasASymbol = assertNotNull(typeAliasAAddress.getTypeAliasSymbol()) + assertEquals(Name.identifier("TypeAliasA"), typeAliasASymbol.name) + assertEquals(Name.identifier("AClass"), typeAliasASymbol.expandedType.expandedClassSymbol?.name) + } + } + + /** + * Runs the given [block] in an analysis session that will have the built library as [KtAnalysisSession.useSiteModule] + */ + private fun withTestProjectLibraryAnalysisSession(block: context(KtAnalysisSession) () -> T): T { + val session = buildStandaloneAnalysisAPISession { + val currentArchitectureTarget = HostManager.host + val nativePlatform = NativePlatforms.nativePlatformByTargets(listOf(currentArchitectureTarget)) + + @OptIn(KtAnalysisApiInternals::class) + registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider()) + + buildKtModuleProvider { + platform = nativePlatform + addModule(buildKtLibraryModule { + addBinaryRoot(providedTestProjectKlib) + platform = nativePlatform + libraryName = providedTestProjectKlib.nameWithoutExtension + }) + } + } + + return analyze(session.getAllLibraryModules().single()) { + block(this) + } + } +} \ No newline at end of file diff --git a/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/tests/ReadKlibDeclarationAddressesBlackBoxTest.kt b/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/tests/ReadKlibDeclarationAddressesBlackBoxTest.kt new file mode 100644 index 00000000000..29fd78b789d --- /dev/null +++ b/native/analysis-api-klib-reader/test/org/jetbrains/kotlin/analysis/api/klib/reader/tests/ReadKlibDeclarationAddressesBlackBoxTest.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2010-2024 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.analysis.api.klib.reader.tests + +import org.jetbrains.kotlin.analysis.api.klib.reader.readKlibDeclarationAddresses +import org.jetbrains.kotlin.analysis.api.klib.reader.testUtils.providedTestProjectKlib +import org.jetbrains.kotlin.analysis.api.klib.reader.testUtils.render +import org.jetbrains.kotlin.analysis.api.klib.reader.testUtils.testDataDir +import org.jetbrains.kotlin.test.KotlinTestUtils +import kotlin.test.Test +import kotlin.test.fail + +class ReadKlibDeclarationAddressesBlackBoxTest { + + @Test + fun `test - testProject`() { + val addresses = readKlibDeclarationAddresses(providedTestProjectKlib) ?: fail("Failed loading klib: $providedTestProjectKlib") + KotlinTestUtils.assertEqualsToFile(testDataDir.resolve("!testProject.addresses"), addresses.render()) + } +} \ No newline at end of file diff --git a/native/analysis-api-klib-reader/testData/!testProject.addresses b/native/analysis-api-klib-reader/testData/!testProject.addresses new file mode 100644 index 00000000000..a5f3bc7fb71 --- /dev/null +++ b/native/analysis-api-klib-reader/testData/!testProject.addresses @@ -0,0 +1,122 @@ +Property (rootPkgProperty) + Source File Name : "RootPkgCallables.kt" + Package Name : "" + Property Name : "rootPkgProperty" + +Function (rootPkgFunction) + Source File Name : "RootPkgCallables.kt" + Package Name : "" + Function Name : "rootPkgFunction" + +Class (RootPkgClass) + Source File Name : "RootPkgClass.kt" + Package Name : "" + ClassId : "RootPkgClass" + +Property (org.jetbrains.sample.constantInt) + Source File Name : "Constants.kt" + Package Name : "org.jetbrains.sample" + Property Name : "constantInt" + +Property (org.jetbrains.sample.constantString) + Source File Name : "Constants.kt" + Package Name : "org.jetbrains.sample" + Property Name : "constantString" + +Property (org.jetbrains.sample.aExtensionProperty) + Source File Name : "Extensions.kt" + Package Name : "org.jetbrains.sample" + Property Name : "aExtensionProperty" + +Function (org.jetbrains.sample.aExtensionFun) + Source File Name : "Extensions.kt" + Package Name : "org.jetbrains.sample" + Function Name : "aExtensionFun" + +Class (org.jetbrains.sample.GenericClass) + Source File Name : "Generics.kt" + Package Name : "org.jetbrains.sample" + ClassId : "org/jetbrains/sample/GenericClass" + +Property (org.jetbrains.sample.genericProperty) + Source File Name : "Generics.kt" + Package Name : "org.jetbrains.sample" + Property Name : "genericProperty" + +Function (org.jetbrains.sample.genericFun) + Source File Name : "Generics.kt" + Package Name : "org.jetbrains.sample" + Function Name : "genericFun" + +Class (org.jetbrains.sample.PrivateClass) + Source File Name : "SymbolsWithDifferentVisibilities.kt" + Package Name : "org.jetbrains.sample" + ClassId : "org/jetbrains/sample/PrivateClass" + +Class (org.jetbrains.sample.InternalClass) + Source File Name : "SymbolsWithDifferentVisibilities.kt" + Package Name : "org.jetbrains.sample" + ClassId : "org/jetbrains/sample/InternalClass" + +Class (org.jetbrains.sample.PublicClass) + Source File Name : "SymbolsWithDifferentVisibilities.kt" + Package Name : "org.jetbrains.sample" + ClassId : "org/jetbrains/sample/PublicClass" + +Function (org.jetbrains.sample.privateFun) + Source File Name : "SymbolsWithDifferentVisibilities.kt" + Package Name : "org.jetbrains.sample" + Function Name : "privateFun" + +Function (org.jetbrains.sample.internalFun) + Source File Name : "SymbolsWithDifferentVisibilities.kt" + Package Name : "org.jetbrains.sample" + Function Name : "internalFun" + +Function (org.jetbrains.sample.publicFun) + Source File Name : "SymbolsWithDifferentVisibilities.kt" + Package Name : "org.jetbrains.sample" + Function Name : "publicFun" + +TypeAlias (org.jetbrains.sample.TypeAliasA) + Package Name : "org.jetbrains.sample" + ClassId : "org/jetbrains/sample/TypeAliasA" + +TypeAlias (org.jetbrains.sample.TypeAliasB) + Package Name : "org.jetbrains.sample" + ClassId : "org/jetbrains/sample/TypeAliasB" + +Property (org.jetbrains.sample.a.aProperty) + Source File Name : "ACallables.kt" + Package Name : "org.jetbrains.sample.a" + Property Name : "aProperty" + +Function (org.jetbrains.sample.a.aFunction) + Source File Name : "ACallables.kt" + Package Name : "org.jetbrains.sample.a" + Function Name : "aFunction" + +Class (org.jetbrains.sample.a.AClass) + Source File Name : "AClass.kt" + Package Name : "org.jetbrains.sample.a" + ClassId : "org/jetbrains/sample/a/AClass" + +Class (org.jetbrains.sample.a.AObject) + Source File Name : "AObject.kt" + Package Name : "org.jetbrains.sample.a" + ClassId : "org/jetbrains/sample/a/AObject" + +Class (org.jetbrains.sample.b.BClass) + Source File Name : "BClass.kt" + Package Name : "org.jetbrains.sample.b" + ClassId : "org/jetbrains/sample/b/BClass" + +Function (org.jetbrains.sample.filePrivateSymbolsClash.foo) + Source File Name : "A.kt" + Package Name : "org.jetbrains.sample.filePrivateSymbolsClash" + Function Name : "foo" + +Function (org.jetbrains.sample.filePrivateSymbolsClash.foo) + Source File Name : "B.kt" + Package Name : "org.jetbrains.sample.filePrivateSymbolsClash" + Function Name : "foo" \ No newline at end of file diff --git a/native/analysis-api-klib-reader/testProject/build.gradle.kts b/native/analysis-api-klib-reader/testProject/build.gradle.kts new file mode 100644 index 00000000000..cd2fc6c03ae --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + kotlin("multiplatform") +} + +kotlin { + macosArm64() + macosX64() + linuxX64() + linuxArm64() + mingwX64() +} diff --git a/native/analysis-api-klib-reader/testProject/gradle.properties b/native/analysis-api-klib-reader/testProject/gradle.properties new file mode 100644 index 00000000000..443e8757632 --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/gradle.properties @@ -0,0 +1,3 @@ +# https://youtrack.jetbrains.com/issue/KT-65985 +kotlin.native.toolchain.enabled=false +kotlin.native.distribution.downloadFromMaven=false \ No newline at end of file diff --git a/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/RootPkgCallables.kt b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/RootPkgCallables.kt new file mode 100644 index 00000000000..7500b22f51c --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/RootPkgCallables.kt @@ -0,0 +1,14 @@ +@file:Suppress("unused") + +import kotlin.random.Random + +/* + * Copyright 2010-2024 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. + */ + +val rootPkgProperty get() = Random.nextInt() + +fun rootPkgFunction() = Random.nextInt() + +fun rootPkgFunction(seed: Int) = Random(seed).nextInt() diff --git a/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/RootPkgClass.kt b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/RootPkgClass.kt new file mode 100644 index 00000000000..ad05496113b --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/RootPkgClass.kt @@ -0,0 +1,10 @@ +@file:Suppress("unused") +/* +* Copyright 2010-2024 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. +*/ + +class RootPkgClass { + fun foo() = Unit + class Nested +} \ No newline at end of file diff --git a/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/Constants.kt b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/Constants.kt new file mode 100644 index 00000000000..82a0c5ef97a --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/Constants.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2010-2024 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. + */ + +@file:Suppress("unused") + +package org.jetbrains.sample + +const val constantInt = 42 + +const val constantString = "Hello There!" \ No newline at end of file diff --git a/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/Extensions.kt b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/Extensions.kt new file mode 100644 index 00000000000..61d73cc7587 --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/Extensions.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2010-2024 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. + */ + +@file:Suppress("unused") + +package org.jetbrains.sample + +import org.jetbrains.sample.a.AClass + +fun AClass.aExtensionFun() = this.toString() + +val AClass.aExtensionProperty get() = this.toString() \ No newline at end of file diff --git a/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/Generics.kt b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/Generics.kt new file mode 100644 index 00000000000..36eacd4a113 --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/Generics.kt @@ -0,0 +1,16 @@ +/* + * Copyright 2010-2024 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. + */ + +@file:Suppress("unused") + +package org.jetbrains.sample + +class GenericClass { + fun foo(value: T) = value +} + +fun genericFun(value: T) = value.toString() + +val T.genericProperty get() = toString() \ No newline at end of file diff --git a/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/SymbolsWithDifferentVisibilities.kt b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/SymbolsWithDifferentVisibilities.kt new file mode 100644 index 00000000000..f3868b79a0c --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/SymbolsWithDifferentVisibilities.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2010-2024 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. + */ + +@file:Suppress("unused") + +package org.jetbrains.sample + +private class PrivateClass + +internal class InternalClass + +class PublicClass + +private fun privateFun() = 42 + +internal fun internalFun() = 42 + +fun publicFun() = 42 \ No newline at end of file diff --git a/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/TypeAlias.kt b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/TypeAlias.kt new file mode 100644 index 00000000000..6164647c5be --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/TypeAlias.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2010-2024 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. + */ + +@file:Suppress("unused") + +package org.jetbrains.sample + +import org.jetbrains.sample.a.AClass +import org.jetbrains.sample.b.BClass + +typealias TypeAliasA = AClass + +internal typealias TypeAliasB = BClass \ No newline at end of file diff --git a/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/a/ACallables.kt b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/a/ACallables.kt new file mode 100644 index 00000000000..3483970487c --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/a/ACallables.kt @@ -0,0 +1,16 @@ +/* + * Copyright 2010-2024 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. + */ + +@file:Suppress("unused") + +package org.jetbrains.sample.a + +import kotlin.random.Random + +val aProperty get() = Random.nextInt() + +fun aFunction() = Random.nextInt() + +fun aFunction(seed: Int) = Random(seed).nextInt() \ No newline at end of file diff --git a/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/a/AClass.kt b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/a/AClass.kt new file mode 100644 index 00000000000..96d66c6f429 --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/a/AClass.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2010-2024 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. + */ + +@file:Suppress("unused") + +package org.jetbrains.sample.a + +class AClass { + class Nested +} \ No newline at end of file diff --git a/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/a/AObject.kt b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/a/AObject.kt new file mode 100644 index 00000000000..50b799545cf --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/a/AObject.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2010-2024 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. + */ + +@file:Suppress("unused") + +package org.jetbrains.sample.a + +object AObject { + class Nested +} \ No newline at end of file diff --git a/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/b/BClass.kt b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/b/BClass.kt new file mode 100644 index 00000000000..bf6bce3f7f6 --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/b/BClass.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2010-2024 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. + */ + +@file:Suppress("unused") + +package org.jetbrains.sample.b + +class BClass \ No newline at end of file diff --git a/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/filePrivateSymbolsClash/A.kt b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/filePrivateSymbolsClash/A.kt new file mode 100644 index 00000000000..cfbf1f27143 --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/filePrivateSymbolsClash/A.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2010-2024 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. + */ + +@file:Suppress("unused") + +package org.jetbrains.sample.filePrivateSymbolsClash + +private fun foo() = 42 \ No newline at end of file diff --git a/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/filePrivateSymbolsClash/B.kt b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/filePrivateSymbolsClash/B.kt new file mode 100644 index 00000000000..cfbf1f27143 --- /dev/null +++ b/native/analysis-api-klib-reader/testProject/src/nativeMain/kotlin/org/jetbrains/sample/filePrivateSymbolsClash/B.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2010-2024 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. + */ + +@file:Suppress("unused") + +package org.jetbrains.sample.filePrivateSymbolsClash + +private fun foo() = 42 \ No newline at end of file diff --git a/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/common-configuration.gradle.kts b/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/common-configuration.gradle.kts index f420608bc74..4d7cabbdd2e 100644 --- a/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/common-configuration.gradle.kts +++ b/repo/gradle-build-conventions/buildsrc-compat/src/main/kotlin/common-configuration.gradle.kts @@ -167,7 +167,10 @@ fun Project.configureKotlinCompilationOptions() { // This is a workaround for KT-50876, but with no clear explanation why doFirst is used. // However, KGP with Native targets is used in the native-xctest project, and this code fails with // The value for property 'freeCompilerArgs' is final and cannot be changed any further. - if (project.path != ":native:kotlin-test-native-xctest" && !project.path.startsWith(":native:objcexport-header-generator")) { + if (project.path != ":native:kotlin-test-native-xctest" && + !project.path.startsWith(":native:objcexport-header-generator") && + !project.path.startsWith(":native:analysis-api-klib-reader") + ) { doFirst { if (!useAbsolutePathsInKlib) { @Suppress("DEPRECATION") diff --git a/settings.gradle b/settings.gradle index 00878cfad5a..6ec8e362625 100644 --- a/settings.gradle +++ b/settings.gradle @@ -118,6 +118,8 @@ include ":benchmarks", ":native:kotlin-klib-commonizer-embeddable", ":native:executors", ":native:base", + ":native:analysis-api-klib-reader", + ":native:analysis-api-klib-reader:testProject", ":native:objcexport-header-generator", ":native:objcexport-header-generator-k1", ":native:objcexport-header-generator-analysis-api",