diff --git a/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt b/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt index 8be63f76bce..ead9eb78a04 100644 --- a/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt +++ b/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt @@ -318,18 +318,13 @@ public open class NativeIndexImpl(val library: NativeLibrary, val verbose: Boole if (clang_isCursorDefinition(definitionCursor) != 0) { return getEnumDefAt(definitionCursor) } else { - TODO("support enum forward declarations: " + - clang_getTypeSpelling(clang_getCursorType(cursor)).convertAndDispose()) + // FIXME("enum declaration without constants might be not a typedef, but a forward declaration instead") + return enumRegistry.getOrPut(cursor) { createEnumDefImpl(cursor) } } } return enumRegistry.getOrPut(cursor) { - val cursorType = clang_getCursorType(cursor) - val typeSpelling = clang_getTypeSpelling(cursorType).convertAndDispose() - - val baseType = convertType(clang_getEnumDeclIntegerType(cursor)) - - val enumDef = EnumDefImpl(typeSpelling, baseType, getLocation(cursor)) + val enumDef = createEnumDefImpl(cursor) visitChildren(cursor) { childCursor, _ -> if (clang_getCursorKind(childCursor) == CXCursorKind.CXCursor_EnumConstantDecl) { @@ -347,6 +342,13 @@ public open class NativeIndexImpl(val library: NativeLibrary, val verbose: Boole } } + private fun createEnumDefImpl(cursor: CValue): EnumDefImpl { + val cursorType = clang_getCursorType(cursor) + val typeSpelling = clang_getTypeSpelling(cursorType).convertAndDispose() + val baseType = convertType(clang_getEnumDeclIntegerType(cursor)) + return EnumDefImpl(typeSpelling, baseType, getLocation(cursor)) + } + private fun getObjCCategoryClassCursor(cursor: CValue): CValue { assert(cursor.kind == CXCursorKind.CXCursor_ObjCCategoryDecl) var classRef: CValue? = null diff --git a/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleSupport.kt b/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleSupport.kt index 31ea46d517b..44ae1fb5cc6 100644 --- a/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleSupport.kt +++ b/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleSupport.kt @@ -4,7 +4,7 @@ import clang.* import kotlinx.cinterop.* import java.nio.file.Files -data class ModulesInfo(val topLevelHeaders: List, val ownHeaders: Set, val modules: List) +data class ModulesInfo(val topLevelHeaders: List, val ownHeaders: Set, val modules: List) fun getModulesInfo(compilation: Compilation, modules: List): ModulesInfo { if (modules.isEmpty()) return ModulesInfo(emptyList(), emptySet(), emptyList()) @@ -17,9 +17,11 @@ fun getModulesInfo(compilation: Compilation, modules: List): ModulesInfo } } +data class IncludeInfo(val headerPath: String, val moduleName: String?) + private fun buildModulesInfo(index: CXIndex, modules: List, modulesASTFiles: List): ModulesInfo { val ownHeaders = mutableSetOf() - val topLevelHeaders = linkedSetOf() + val topLevelHeaders = linkedSetOf() modulesASTFiles.forEach { val moduleTranslationUnit = clang_createTranslationUnit(index, it)!! try { @@ -89,7 +91,7 @@ private fun getModulesHeaders( index: CXIndex, translationUnit: CXTranslationUnit, modules: Set, - topLevelHeaders: LinkedHashSet + topLevelHeaders: LinkedHashSet ): Set { val nonModularIncludes = mutableMapOf>() val result = mutableSetOf() @@ -99,13 +101,13 @@ private fun getModulesHeaders( val file = info.file!! val includer = clang_indexLoc_getCXSourceLocation(info.hashLoc.readValue()).getContainingFile() + val module = clang_getModuleForFile(translationUnit, file) + if (includer == null) { // i.e. the header is included by the module itself. - topLevelHeaders += file.path + topLevelHeaders += IncludeInfo(file.path, clang_Module_getFullName(module).convertAndDispose()) } - val module = clang_getModuleForFile(translationUnit, file) - if (module != null) { val moduleWithParents = generateSequence(module, { clang_Module_getParent(it) }).map { clang_Module_getFullName(it).convertAndDispose() diff --git a/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt b/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt index a7fa80ee463..cff67b954ed 100644 --- a/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt +++ b/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt @@ -52,7 +52,7 @@ sealed class NativeLibraryHeaderFilter { } interface Compilation { - val includes: List + val includes: List val additionalPreambleLines: List val compilerArgs: List val language: Language @@ -93,7 +93,7 @@ data class CompilationWithPCH( constructor(compilerArgs: List, precompiledHeader: String, language: Language) : this(compilerArgs + listOf("-include-pch", precompiledHeader), language) - override val includes: List + override val includes: List get() = emptyList() override val additionalPreambleLines: List @@ -102,7 +102,7 @@ data class CompilationWithPCH( // TODO: Compilation hierarchy seems to require some refactoring. -data class NativeLibrary(override val includes: List, +data class NativeLibrary(override val includes: List, override val additionalPreambleLines: List, override val compilerArgs: List, val headerToIdMapper: HeaderToIdMapper, diff --git a/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Utils.kt b/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Utils.kt index 7e8385547be..ab2484556a5 100644 --- a/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Utils.kt +++ b/kotlin-native/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Utils.kt @@ -354,7 +354,13 @@ internal fun List.toNativeStringArray(scope: AutofreeScope): CArrayPoint } val Compilation.preambleLines: List - get() = this.includes.map { "#include <$it>" } + this.additionalPreambleLines + get() = this.includes.map { + if (it.moduleName != null && it.moduleName != "" && "-fmodules" in this.compilerArgs) { + "@import ${it.moduleName};" + } else { + "#include <${it.headerPath}>" + } + } + this.additionalPreambleLines internal fun Appendable.appendPreamble(compilation: Compilation) = this.apply { compilation.preambleLines.forEach { @@ -377,7 +383,7 @@ internal fun Compilation.createTempSource(): File { } fun Compilation.copy( - includes: List = this.includes, + includes: List = this.includes, additionalPreambleLines: List = this.additionalPreambleLines, compilerArgs: List = this.compilerArgs, language: Language = this.language @@ -394,7 +400,7 @@ fun Compilation.copyWithArgsForPCH(): Compilation = copy(compilerArgs = compilerArgs.filterNot { it.startsWith("-fmodule-map-file") }) data class CompilationImpl( - override val includes: List, + override val includes: List, override val additionalPreambleLines: List, override val compilerArgs: List, override val language: Language diff --git a/kotlin-native/Interop/Indexer/src/test/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleTests.kt b/kotlin-native/Interop/Indexer/src/test/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleTests.kt index 03b4009284d..b0a85a7976d 100644 --- a/kotlin-native/Interop/Indexer/src/test/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleTests.kt +++ b/kotlin-native/Interop/Indexer/src/test/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleTests.kt @@ -153,7 +153,7 @@ class ModuleTests : IndexerTests() { assertContains(error.message.orEmpty(), "testModuleWithBadCode/Foo.h:1:1: error: unknown type name 'bad'") } - private fun List.canonicalize(): List = this.map { File(it).canonicalPath } + private fun List.canonicalize(): List = this.map { File(it.headerPath).canonicalPath } private fun compilationIncluding(includeDirectory: File) = compilation("-I$includeDirectory") diff --git a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrDriver.kt b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrDriver.kt index b4586ec6d7f..7e83f3e7d1f 100644 --- a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrDriver.kt +++ b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrDriver.kt @@ -24,14 +24,14 @@ class StubIrContext( val plugin: Plugin ) { val libraryForCStubs = configuration.library.copy( - includes = mutableListOf().apply { - add("stdint.h") - add("string.h") + includes = mutableListOf().apply { + add(IncludeInfo("stdint.h", null)) + add(IncludeInfo("string.h", null)) if (platform == KotlinPlatform.JVM) { - add("jni.h") + add(IncludeInfo("jni.h", null)) } if (configuration.library.language == Language.CPP) { - add("new") + add(IncludeInfo("new", null)) } addAll(configuration.library.includes) }, diff --git a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt index f830d603dc0..ba15f4e9532 100644 --- a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt +++ b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt @@ -532,14 +532,14 @@ internal fun buildNativeLibrary( } val compilation = CompilationImpl( - includes = headerFiles, + includes = headerFiles.map { IncludeInfo(it, null) }, additionalPreambleLines = def.defHeaderLines + predefinedMacrosRedefinitions, compilerArgs = defaultCompilerArgs(language) + compilerOpts + tool.platformCompilerOpts, language = language ) val headerFilter: NativeLibraryHeaderFilter - val includes: List + val includes: List val modules = def.config.modules @@ -552,7 +552,7 @@ internal fun buildNativeLibrary( val headerInclusionPolicy = HeaderInclusionPolicyImpl(headerFilterGlobs, excludeFilterGlobs) headerFilter = NativeLibraryHeaderFilter.NameBased(headerInclusionPolicy, excludeDependentModules) - includes = headerFiles + includes = headerFiles.map { IncludeInfo(it, null) } } else { require(language == Language.OBJECTIVE_C) { "cinterop supports 'modules' only when 'language = Objective-C'" } require(headerFiles.isEmpty()) { "cinterop doesn't support having headers and modules specified at the same time" } diff --git a/kotlin-native/platformLibs/src/platform/osx/Hypervisor.def b/kotlin-native/platformLibs/src/platform/osx/Hypervisor.def index 870890d8bfe..37b63db108c 100644 --- a/kotlin-native/platformLibs/src/platform/osx/Hypervisor.def +++ b/kotlin-native/platformLibs/src/platform/osx/Hypervisor.def @@ -1,10 +1,7 @@ depends = Kernel darwin osx posix language = Objective-C package = platform.Hypervisor - -# Using headers instead of modules to workaround incorrect module definition in Xcode 12.2: -headers = Hypervisor/Hypervisor.h -headerFilter = Hypervisor/** +modules = Hypervisor compilerOpts = -framework Hypervisor linkerOpts = -framework Hypervisor diff --git a/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/expected.compilation.failure.txt b/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/expected.compilation.failure.txt new file mode 100644 index 00000000000..c9a02b00dae --- /dev/null +++ b/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/expected.compilation.failure.txt @@ -0,0 +1 @@ +error: comparison of incompatible enums 'pod1.ForwardEnumPOD' and 'pod2.ForwardEnumPOD' is always unsuccessful \ No newline at end of file diff --git a/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/main.kt b/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/main.kt new file mode 100644 index 00000000000..573fb3b0d1a --- /dev/null +++ b/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/main.kt @@ -0,0 +1,9 @@ +import pod1.* +import pod2.* + +fun box(): String { + if (pod1.varPOD != pod2.ForwardEnumPOD.Value2POD) + return "OK" + else + return "FAIL" +} diff --git a/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/pod1.contents.gold.txt b/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/pod1.contents.gold.txt new file mode 100644 index 00000000000..517bd8b42d9 --- /dev/null +++ b/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/pod1.contents.gold.txt @@ -0,0 +1,6 @@ + enum class ForwardEnumPOD private constructor(value: Int) : Enum, CEnum { + var value: ForwardEnumPOD + @Deprecated(level = DeprecationLevel.WARNING, message = "Will be removed.", replaceWith = ReplaceWith(imports = {})) fun byValue(value: Int): ForwardEnumPOD + var varPOD: ForwardEnumPOD + @CCall(id = "knifunptr_pod10_varPOD_getter") get + @CCall(id = "knifunptr_pod11_varPOD_setter") set \ No newline at end of file diff --git a/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/pod1.def b/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/pod1.def new file mode 100644 index 00000000000..9223cbb3451 --- /dev/null +++ b/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/pod1.def @@ -0,0 +1,2 @@ +language = Objective-C +modules = forwardEnum1 diff --git a/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/pod2.contents.gold.txt b/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/pod2.contents.gold.txt new file mode 100644 index 00000000000..6df5b2d28bb --- /dev/null +++ b/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/pod2.contents.gold.txt @@ -0,0 +1,5 @@ + enum class ForwardEnumPOD private constructor(value: Int) : Enum, CEnum { + @ConstantValue.Int(value = 0) enum entry Value1POD + @ConstantValue.Int(value = 1) enum entry Value2POD + var value: ForwardEnumPOD + @Deprecated(level = DeprecationLevel.WARNING, message = "Will be removed.", replaceWith = ReplaceWith(imports = {})) fun byValue(value: Int): ForwardEnumPOD \ No newline at end of file diff --git a/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/pod2.def b/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/pod2.def new file mode 100644 index 00000000000..cfc6f6a30a4 --- /dev/null +++ b/native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/pod2.def @@ -0,0 +1,2 @@ +language = Objective-C +modules = forwardEnum2 diff --git a/native/native.tests/testData/CInterop/KT-39120/forwardEnum1.framework/Headers/forwardEnum1.h b/native/native.tests/testData/CInterop/KT-39120/forwardEnum1.framework/Headers/forwardEnum1.h new file mode 100644 index 00000000000..ef1b525a1eb --- /dev/null +++ b/native/native.tests/testData/CInterop/KT-39120/forwardEnum1.framework/Headers/forwardEnum1.h @@ -0,0 +1,5 @@ +#include + +typedef NS_ENUM (int, ForwardEnumPOD); // Actual definition of the enum follows in another module `forwardEnum2` + +ForwardEnumPOD varPOD; diff --git a/native/native.tests/testData/CInterop/KT-39120/forwardEnum1.framework/Modules/module.modulemap b/native/native.tests/testData/CInterop/KT-39120/forwardEnum1.framework/Modules/module.modulemap new file mode 100644 index 00000000000..0730f3ffde4 --- /dev/null +++ b/native/native.tests/testData/CInterop/KT-39120/forwardEnum1.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module forwardEnum1 { + umbrella header "forwardEnum1.h" + + export * + module * { export * } +} diff --git a/native/native.tests/testData/CInterop/KT-39120/forwardEnum2.framework/Headers/forwardEnum2.h b/native/native.tests/testData/CInterop/KT-39120/forwardEnum2.framework/Headers/forwardEnum2.h new file mode 100644 index 00000000000..0983a08d4a8 --- /dev/null +++ b/native/native.tests/testData/CInterop/KT-39120/forwardEnum2.framework/Headers/forwardEnum2.h @@ -0,0 +1,6 @@ +#include + +typedef NS_ENUM (int, ForwardEnumPOD) { // There was forward definition of this enum in another module `forwardEnum1` + Value1POD, + Value2POD +}; diff --git a/native/native.tests/testData/CInterop/KT-39120/forwardEnum2.framework/Modules/module.modulemap b/native/native.tests/testData/CInterop/KT-39120/forwardEnum2.framework/Modules/module.modulemap new file mode 100644 index 00000000000..285cf14641e --- /dev/null +++ b/native/native.tests/testData/CInterop/KT-39120/forwardEnum2.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module forwardEnum2 { + umbrella header "forwardEnum2.h" + + export * + module * { export * } +} diff --git a/native/native.tests/testData/CInterop/framework/explicitpod1.framework/Headers/explicitSubmodule.h b/native/native.tests/testData/CInterop/framework/explicitpod1.framework/Headers/explicitSubmodule.h new file mode 100644 index 00000000000..56696a60e60 --- /dev/null +++ b/native/native.tests/testData/CInterop/framework/explicitpod1.framework/Headers/explicitSubmodule.h @@ -0,0 +1,15 @@ +#ifndef _IOKIT_IOHIDLIB_H +#define _IOKIT_IOHIDLIB_H + +typedef struct IOGPoint { + int x; +} IOGPoint; + +typedef enum { + NX_OneButton, +} NXMouseButton; + +extern int IOHIDPostEvent( IOGPoint location ); +extern int IOHIDGetButtonEventNum( NXMouseButton button ); + +#endif /* ! _IOKIT_IOHIDLIB_H */ diff --git a/native/native.tests/testData/CInterop/framework/explicitpod1.framework/Modules/module.modulemap b/native/native.tests/testData/CInterop/framework/explicitpod1.framework/Modules/module.modulemap new file mode 100644 index 00000000000..9c2c5cb144e --- /dev/null +++ b/native/native.tests/testData/CInterop/framework/explicitpod1.framework/Modules/module.modulemap @@ -0,0 +1,8 @@ +framework module explicitpod1 { + export * + + explicit module explicitSubmodule { + header "explicitSubmodule.h" + export * + } +} diff --git a/native/native.tests/testData/CInterop/framework/forwardEnum.framework/Headers/forwardEnum-umbrella.h b/native/native.tests/testData/CInterop/framework/forwardEnum.framework/Headers/forwardEnum-umbrella.h new file mode 100644 index 00000000000..c4938c8339b --- /dev/null +++ b/native/native.tests/testData/CInterop/framework/forwardEnum.framework/Headers/forwardEnum-umbrella.h @@ -0,0 +1,8 @@ +#import + +typedef NS_ENUM (long long, ForwardEnum) { + A, + B +}; + +ForwardEnum forwardEnumVar; diff --git a/native/native.tests/testData/CInterop/framework/forwardEnum.framework/Headers/forwardEnum.h b/native/native.tests/testData/CInterop/framework/forwardEnum.framework/Headers/forwardEnum.h new file mode 100644 index 00000000000..ba6cd062cf3 --- /dev/null +++ b/native/native.tests/testData/CInterop/framework/forwardEnum.framework/Headers/forwardEnum.h @@ -0,0 +1,5 @@ +#include + +typedef NS_ENUM (long long, ForwardEnum); +typedef NS_ENUM (long long, EnumWithoutConstant); +EnumWithoutConstant enumWithoutConstantVar; diff --git a/native/native.tests/testData/CInterop/framework/forwardEnum.framework/Modules/module.modulemap b/native/native.tests/testData/CInterop/framework/forwardEnum.framework/Modules/module.modulemap new file mode 100644 index 00000000000..450b7fd1355 --- /dev/null +++ b/native/native.tests/testData/CInterop/framework/forwardEnum.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module forwardEnum { + umbrella header "forwardEnum-umbrella.h" + + export * + module * { export * } +} diff --git a/native/native.tests/testData/CInterop/framework/frameworkDefs/explicitSubmodule/contents.gold.txt b/native/native.tests/testData/CInterop/framework/frameworkDefs/explicitSubmodule/contents.gold.txt new file mode 100644 index 00000000000..c758587b06d --- /dev/null +++ b/native/native.tests/testData/CInterop/framework/frameworkDefs/explicitSubmodule/contents.gold.txt @@ -0,0 +1,32 @@ + +package pod1 { + + @CStruct(spelling = "struct { int x; }") class IOGPoint constructor(rawPtr: NativePtr /* = NativePtr */) : CStructVar { + var x: Int + @CStruct.MemberAt(offset = 0.toLong()) get + @CStruct.MemberAt(offset = 0.toLong()) set + @CStruct.VarType(align = 4, size = 4.toLong()) @Deprecated(level = DeprecationLevel.WARNING, message = "Use sizeOf() or alignOf() instead.", replaceWith = ReplaceWith(imports = {})) companion object : CStructVar.Type + } + + enum class NXMouseButton private constructor(value: UInt) : Enum, CEnum { + @ConstantValue.UInt(value = 0.toUInt()) enum entry NX_OneButton + override val value: UInt + + class Var constructor(rawPtr: NativePtr /* = NativePtr */) : CEnumVar { + var value: NXMouseButton + @CEnumVarTypeSize(size = 4) @Deprecated(level = DeprecationLevel.WARNING, message = "Use sizeOf() or alignOf() instead.", replaceWith = ReplaceWith(imports = {})) companion object : CPrimitiveVar.Type + } + + companion object { + @Deprecated(level = DeprecationLevel.WARNING, message = "Will be removed.", replaceWith = ReplaceWith(imports = {})) fun byValue(value: UInt): NXMouseButton + } + + } + +} + +package pod1 { + @CCall(id = "knifunptr_pod11_IOHIDGetButtonEventNum") external fun IOHIDGetButtonEventNum(button: NXMouseButton): Int + @CCall(id = "knifunptr_pod10_IOHIDPostEvent") external fun IOHIDPostEvent(location: CValue): Int +} + diff --git a/native/native.tests/testData/CInterop/framework/frameworkDefs/explicitSubmodule/pod1.def b/native/native.tests/testData/CInterop/framework/frameworkDefs/explicitSubmodule/pod1.def new file mode 100644 index 00000000000..af0753f6184 --- /dev/null +++ b/native/native.tests/testData/CInterop/framework/frameworkDefs/explicitSubmodule/pod1.def @@ -0,0 +1,2 @@ +language = Objective-C +modules = explicitpod1 diff --git a/native/native.tests/testData/CInterop/framework/frameworkDefs/forwardEnum/contents.gold.txt b/native/native.tests/testData/CInterop/framework/frameworkDefs/forwardEnum/contents.gold.txt new file mode 100644 index 00000000000..8a0b399916e --- /dev/null +++ b/native/native.tests/testData/CInterop/framework/frameworkDefs/forwardEnum/contents.gold.txt @@ -0,0 +1,44 @@ + +package pod1 { + + enum class EnumWithoutConstant private constructor(value: Long) : Enum, CEnum { + override val value: Long + + class Var constructor(rawPtr: NativePtr /* = NativePtr */) : CEnumVar { + var value: EnumWithoutConstant + @CEnumVarTypeSize(size = 8) @Deprecated(level = DeprecationLevel.WARNING, message = "Use sizeOf() or alignOf() instead.", replaceWith = ReplaceWith(imports = {})) companion object : CPrimitiveVar.Type + } + + companion object { + @Deprecated(level = DeprecationLevel.WARNING, message = "Will be removed.", replaceWith = ReplaceWith(imports = {})) fun byValue(value: Long): EnumWithoutConstant + } + + } + + enum class ForwardEnum private constructor(value: Long) : Enum, CEnum { + @ConstantValue.Long(value = 0.toLong()) enum entry A + @ConstantValue.Long(value = 1.toLong()) enum entry B + override val value: Long + + class Var constructor(rawPtr: NativePtr /* = NativePtr */) : CEnumVar { + var value: ForwardEnum + @CEnumVarTypeSize(size = 8) @Deprecated(level = DeprecationLevel.WARNING, message = "Use sizeOf() or alignOf() instead.", replaceWith = ReplaceWith(imports = {})) companion object : CPrimitiveVar.Type + } + + companion object { + @Deprecated(level = DeprecationLevel.WARNING, message = "Will be removed.", replaceWith = ReplaceWith(imports = {})) fun byValue(value: Long): ForwardEnum + } + + } + +} + +package pod1 { + var enumWithoutConstantVar: EnumWithoutConstant + @CCall(id = "knifunptr_pod10_enumWithoutConstantVar_getter") get + @CCall(id = "knifunptr_pod11_enumWithoutConstantVar_setter") set + var forwardEnumVar: ForwardEnum + @CCall(id = "knifunptr_pod12_forwardEnumVar_getter") get + @CCall(id = "knifunptr_pod13_forwardEnumVar_setter") set +} + diff --git a/native/native.tests/testData/CInterop/framework/frameworkDefs/forwardEnum/pod1.def b/native/native.tests/testData/CInterop/framework/frameworkDefs/forwardEnum/pod1.def new file mode 100644 index 00000000000..02fa978357e --- /dev/null +++ b/native/native.tests/testData/CInterop/framework/frameworkDefs/forwardEnum/pod1.def @@ -0,0 +1,2 @@ +language = Objective-C +modules = forwardEnum diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/CInteropFModulesTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/CInteropFModulesTestGenerated.java index 744e8b36c3b..69e926b19a9 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/CInteropFModulesTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/CInteropFModulesTestGenerated.java @@ -120,6 +120,12 @@ public class CInteropFModulesTestGenerated extends AbstractNativeCInteropFModule runTest("native/native.tests/testData/CInterop/framework/frameworkDefs/excludePod1Umbrella/"); } + @Test + @TestMetadata("explicitSubmodule") + public void testExplicitSubmodule() throws Exception { + runTest("native/native.tests/testData/CInterop/framework/frameworkDefs/explicitSubmodule/"); + } + @Test @TestMetadata("filterPod1") public void testFilterPod1() throws Exception { @@ -144,6 +150,12 @@ public class CInteropFModulesTestGenerated extends AbstractNativeCInteropFModule runTest("native/native.tests/testData/CInterop/framework/frameworkDefs/filterPod1UmbrellaPod1A/"); } + @Test + @TestMetadata("forwardEnum") + public void testForwardEnum() throws Exception { + runTest("native/native.tests/testData/CInterop/framework/frameworkDefs/forwardEnum/"); + } + @Test @TestMetadata("full") public void testFull() throws Exception { diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/CInteropKT39120TestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/CInteropKT39120TestGenerated.java index 0f45f720fe9..035e07374e7 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/CInteropKT39120TestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/CInteropKT39120TestGenerated.java @@ -24,6 +24,12 @@ public class CInteropKT39120TestGenerated extends AbstractNativeCInteropKT39120T KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/CInterop/KT-39120/defs"), Pattern.compile("^([^_](.+))$"), null, false); } + @Test + @TestMetadata("ForwardEnum") + public void testForwardEnum() throws Exception { + runTest("native/native.tests/testData/CInterop/KT-39120/defs/ForwardEnum/"); + } + @Test @TestMetadata("interModuleImport") public void testInterModuleImport() throws Exception { diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/CInteropNoFModulesTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/CInteropNoFModulesTestGenerated.java index 25638901041..45621907369 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/CInteropNoFModulesTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/CInteropNoFModulesTestGenerated.java @@ -120,6 +120,12 @@ public class CInteropNoFModulesTestGenerated extends AbstractNativeCInteropNoFMo runTest("native/native.tests/testData/CInterop/framework/frameworkDefs/excludePod1Umbrella/"); } + @Test + @TestMetadata("explicitSubmodule") + public void testExplicitSubmodule() throws Exception { + runTest("native/native.tests/testData/CInterop/framework/frameworkDefs/explicitSubmodule/"); + } + @Test @TestMetadata("filterPod1") public void testFilterPod1() throws Exception { @@ -144,6 +150,12 @@ public class CInteropNoFModulesTestGenerated extends AbstractNativeCInteropNoFMo runTest("native/native.tests/testData/CInterop/framework/frameworkDefs/filterPod1UmbrellaPod1A/"); } + @Test + @TestMetadata("forwardEnum") + public void testForwardEnum() throws Exception { + runTest("native/native.tests/testData/CInterop/framework/frameworkDefs/forwardEnum/"); + } + @Test @TestMetadata("full") public void testFull() throws Exception { diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropBaseTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropBaseTest.kt index ed7bef9a697..ae09cf8bcae 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropBaseTest.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropBaseTest.kt @@ -13,7 +13,6 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.settings.* import java.io.File abstract class AbstractNativeCInteropBaseTest : AbstractNativeSimpleTest() { - private val buildDir: File get() = testRunSettings.get().testBuildDir internal val targets: KotlinNativeTargets get() = testRunSettings.get() internal val kotlinNativeClassLoader: KotlinNativeClassLoader get() = testRunSettings.get() diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropKT39120Test.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropKT39120Test.kt index e4c6a264cba..d757e1a0b50 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropKT39120Test.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/AbstractNativeCInteropKT39120Test.kt @@ -17,6 +17,7 @@ import org.junit.jupiter.api.Tag import org.jetbrains.kotlin.konan.blackboxtest.support.runner.* import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertEquals import org.junit.jupiter.api.Assumptions +import kotlin.test.assertIs @Tag("cinterop") abstract class AbstractNativeCInteropKT39120Test : AbstractNativeCInteropBaseTest() { @@ -51,10 +52,47 @@ abstract class AbstractNativeCInteropKT39120Test : AbstractNativeCInteropBaseTes val expectedFiltered2Output = golden2File.readText() val actualFiltered2Output = filterContentsOutput(contents2, " pod.Version|POD|class Pod") assertEquals(StringUtilRt.convertLineSeparators(expectedFiltered2Output), StringUtilRt.convertLineSeparators(actualFiltered2Output)) + + val ktFile = testPathFull.resolve(DEFAULT_FILE_NAME) + if (ktFile.exists()) { + // Just compile "main.kt" with klib1 and klib2, without running resulting executable + val module = TestModule.Exclusive(DEFAULT_MODULE_NAME, emptySet(), emptySet()).apply { + files += TestFile.createCommitted(ktFile, this) + } + val compilationResult = compileToExecutable( + createTestCaseNoTestRun(module, TestCompilerArgs(listOf())), + klib1.asLibraryDependency(), + klib2.asLibraryDependency() + ) + + val expectedFailureTxtFile = testPathFull.resolve("expected.compilation.failure.txt") + if (expectedFailureTxtFile.exists()) { + assertIs(compilationResult) + val expectedFailureSubstring = expectedFailureTxtFile.readText() + val actualFailure = compilationResult.loggedData.toString() + assert(actualFailure.contains(expectedFailureSubstring)) { + "Expected failure substring:\n$expectedFailureSubstring\nActual failure logged data:\n$actualFailure" + } + } else { + compilationResult.assertSuccess() + } + } } private fun filterContentsOutput(contents: String, pattern: String) = contents.split("\n").filter { it.contains(Regex(pattern)) }.joinToString(separator = "\n") + + private fun createTestCaseNoTestRun(module: TestModule.Exclusive, compilerArgs: TestCompilerArgs) = TestCase( + id = TestCaseId.Named(module.name), + kind = TestKind.STANDALONE_NO_TR, + modules = setOf(module), + freeCompilerArgs = compilerArgs, + nominalPackageName = PackageName.EMPTY, + checks = TestRunChecks.Default(testRunSettings.get().executionTimeout), + extras = TestCase.NoTestRunnerExtras(".${module.name}") + ).apply { + initialize(null, null) + } } diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/CachesAutoBuildTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/CachesAutoBuildTest.kt index c751bf6db44..de46d67ac60 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/CachesAutoBuildTest.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/CachesAutoBuildTest.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.konan.blackboxtest.CachesAutoBuildTest.Companion.TES import org.jetbrains.kotlin.konan.blackboxtest.support.EnforcedHostTarget import org.jetbrains.kotlin.konan.blackboxtest.support.TestCompilerArgs import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.KLIB +import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult.Companion.assertSuccess import org.jetbrains.kotlin.konan.blackboxtest.support.settings.CacheMode import org.jetbrains.kotlin.konan.blackboxtest.support.settings.KotlinNativeTargets import org.jetbrains.kotlin.konan.blackboxtest.support.settings.OptimizationMode @@ -59,7 +60,7 @@ class CachesAutoBuildTest : AbstractNativeSimpleTest() { ) ), *dependencies - ) + ).assertSuccess().resultingArtifact private val autoCacheDir: File get() = buildDir.resolve("__auto_cache__") private val cacheFlavor: String diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/InfrastructureDumpedTestListingTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/InfrastructureDumpedTestListingTest.kt index d1ab04d958f..d27c5763203 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/InfrastructureDumpedTestListingTest.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/InfrastructureDumpedTestListingTest.kt @@ -13,6 +13,8 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.EnforcedHostTarget import org.jetbrains.kotlin.konan.blackboxtest.support.TestCase import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.Executable import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.KLIB +import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult +import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult.Companion.assertSuccess import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult.Success import org.jetbrains.kotlin.konan.blackboxtest.support.runner.TestExecutable import org.jetbrains.kotlin.konan.blackboxtest.support.runner.TestRunners @@ -49,25 +51,23 @@ class InfrastructureDumpedTestListingTest : AbstractNativeSimpleTest() { val barTestCase: TestCase = generateTestCaseWithSingleModule(rootDir.resolve("bar")) - val executableTestCase: TestCase - val executableCompilationResult: Success + val (executableTestCase: TestCase, executableCompilationResult: TestCompilationResult) = + if (fromSources) { + barTestCase to compileToExecutable(barTestCase, fooLibrary.asLibraryDependency()) + } else { + val barCompilationResult: Success = compileToLibrary(barTestCase, fooLibrary.asLibraryDependency()) + val barLibrary: KLIB = barCompilationResult.resultingArtifact - if (fromSources) { - executableTestCase = barTestCase - executableCompilationResult = compileToExecutable(barTestCase, fooLibrary.asLibraryDependency()) - } else { - val barCompilationResult: Success = compileToLibrary(barTestCase, fooLibrary.asLibraryDependency()) - val barLibrary: KLIB = barCompilationResult.resultingArtifact + val executableTestCase = generateTestCaseWithSingleModule(moduleDir = null) // No sources. + executableTestCase to compileToExecutable( + executableTestCase, + fooLibrary.asLibraryDependency(), + barLibrary.asIncludedLibraryDependency() + ) + } - executableTestCase = generateTestCaseWithSingleModule(moduleDir = null) // No sources. - executableCompilationResult = compileToExecutable( - executableTestCase, - fooLibrary.asLibraryDependency(), - barLibrary.asIncludedLibraryDependency() - ) - } - - val executable: Executable = executableCompilationResult.resultingArtifact + val executableCompilationSuccess = executableCompilationResult.assertSuccess() + val executable: Executable = executableCompilationSuccess.resultingArtifact // check that the test listing dumped during the compilation matches our expectations: val testDumpFile = executable.testDumpFile @@ -78,7 +78,7 @@ class InfrastructureDumpedTestListingTest : AbstractNativeSimpleTest() { assertTrue(dumpedTestListing.isNotEmpty()) // parse test listing obtained from executable file with the help of --ktest_list_tests flag: - val testExecutable = TestExecutable.fromCompilationResult(executableTestCase, executableCompilationResult) + val testExecutable = TestExecutable.fromCompilationResult(executableTestCase, executableCompilationSuccess) val extractedTestListing = TestRunners.extractTestNames(testExecutable, testRunSettings).toSet() assertEquals(extractedTestListing, dumpedTestListing) diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/NativeSimpleTestUtils.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/NativeSimpleTestUtils.kt index 47b101668b5..ddc6de472cc 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/NativeSimpleTestUtils.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/NativeSimpleTestUtils.kt @@ -58,10 +58,9 @@ internal fun AbstractNativeSimpleTest.compileToExecutable( sourcesDir: File, freeCompilerArgs: TestCompilerArgs, vararg dependencies: TestCompilationArtifact.KLIB -): TestCompilationArtifact.Executable { +): TestCompilationResult { val testCase: TestCase = generateTestCaseWithSingleModule(sourcesDir, freeCompilerArgs) - val compilationResult = compileToExecutable(testCase, dependencies.map { it.asLibraryDependency() }) - return compilationResult.resultingArtifact + return compileToExecutable(testCase, dependencies.map { it.asLibraryDependency() }) } internal fun AbstractNativeSimpleTest.compileToExecutable(testCase: TestCase, vararg dependencies: TestCompilationDependency<*>) = @@ -109,7 +108,7 @@ private fun AbstractNativeSimpleTest.compileToLibrary( private fun AbstractNativeSimpleTest.compileToExecutable( testCase: TestCase, dependencies: List> -): TestCompilationResult.Success { +): TestCompilationResult { val compilation = ExecutableCompilation( settings = testRunSettings, freeCompilerArgs = testCase.freeCompilerArgs, @@ -118,7 +117,7 @@ private fun AbstractNativeSimpleTest.compileToExecutable( dependencies = dependencies, expectedArtifact = getExecutableArtifact() ) - return compilation.result.assertSuccess() + return compilation.result } private fun getLibraryArtifact(testCase: TestCase, dir: File) =