diff --git a/CHANGELOG.md b/CHANGELOG.md index e39e64c727..1292cebc29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,12 @@ # Gluecodium project Release Notes +## Unreleased + * Kotlin: explicitly generate 'internal' visibility and synthetic attribute for elements nested in 'internal' type. + ## 14.1.0 Release date 2026-02-21 * Kotlin: use `@JvmSynthetic` annotation for Kotlin internal elements whenever possible to hide them from Java code. + * Kotlin: ensure that visibility of each element nested in another internal element is explicitly set via 'internal' Kotlin keyword. * Kotlin: allow the usage of 'RequiresOptIn' and 'OptIn' annotations for internal API via CLI parameters. This way error is generated when the code, which is not intended to access the internal API uses it. Three new CLI parameters are available: 'androidrequiresoptinannotation', 'androidoptinannotation' and 'androidinternalapiannotationname'. * Kotlin: for external types usage in Kotlin, use 'internal' keyword for the types, which are generated by Gluecodium as their 'internal' representation. * Kotlin: minimize the usage of 'JvmSuppressWildcards' annotation for collection parameters. This annotation was used for all generated collection types. It needs to be used only when collection type holds enumeration or open type e.g.: 'open class', 'interface' or 'fun interface'. diff --git a/functional-tests/functional/CMakeLists.txt b/functional-tests/functional/CMakeLists.txt index 987eabac5c..89cd42b11d 100644 --- a/functional-tests/functional/CMakeLists.txt +++ b/functional-tests/functional/CMakeLists.txt @@ -456,9 +456,11 @@ feature(Visibility android android-kotlin swift dart SOURCES input/lime/VisibilityPlatform.lime input/lime/VisibilityPlatformReverse.lime input/lime/InternalFields.lime + input/lime/NestedInternalElements.lime input/src/cpp/VisibilityAttribute.cpp input/src/cpp/VisibilityInternal.cpp + input/src/cpp/NestedInternalElements.cpp ) feature(SkipAttribute cpp android android-kotlin swift dart SOURCES diff --git a/functional-tests/functional/android-kotlin/src/test/kotlin/com/here/android/test/NestedInternalElementsTest.kt b/functional-tests/functional/android-kotlin/src/test/kotlin/com/here/android/test/NestedInternalElementsTest.kt new file mode 100644 index 0000000000..3b999257fa --- /dev/null +++ b/functional-tests/functional/android-kotlin/src/test/kotlin/com/here/android/test/NestedInternalElementsTest.kt @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2016-2026 HERE Europe B.V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ +@file:OptIn(com.here.android.lorem.ipsum.FunctionalTestsInternalAPI::class) + +package com.here.android.test + +import com.here.android.RobolectricApplication +import org.junit.Assert.assertEquals +import org.junit.Assert.assertThrows +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(application = RobolectricApplication::class) +class NestedInternalElementsTest { + ////////// 1. Tests related to direct members of 'InternalClassWithNestedElements'. + @Test + fun constantOfInternalClassCanBeAccessed() { + assertEquals(2026, InternalClassWithNestedElements.SOME_CONSTANT) + } + + @Test + fun functionOfInternalClassCanBeAccessed() { + val internalClassObj = InternalClassWithNestedElements(20, 26) + assertEquals(46, internalClassObj.someFunction()) + } + + @Test + fun staticFunctionOfInternalClassCanBeAccessed() { + assertEquals("SOME_STATIC_FUNCTION", InternalClassWithNestedElements.someStaticFunction()) + } + + @Test + fun propertyOfInternalClassCanBeAccessed() { + val internalClassObj = InternalClassWithNestedElements(20, 26) + assertEquals(2202, internalClassObj.someProperty) + + internalClassObj.someProperty = 77 + assertEquals(77, internalClassObj.someProperty) + } + + @Test + fun staticPropertyOfInternalClassCanBeAccessed() { + assertEquals(11, InternalClassWithNestedElements.getSomeStaticProperty()) + + InternalClassWithNestedElements.setSomeStaticProperty(37) + assertEquals(37, InternalClassWithNestedElements.getSomeStaticProperty()) + } + + ////////// 2. Tests related to direct members of 'InternalClassWithNestedElements.NestedClassLevelOne'. + @Test + fun functionOfClassNestedInInternalClassCanBeAccessed() { + val obj = InternalClassWithNestedElements.NestedClassLevelOne(2, 3) + assertEquals(6, obj.someNestedFunction()) + } + + @Test + fun staticFunctionOfClassNestedInInternalClassCanBeAccessed() { + assertEquals("LEVEL_1_NESTING", InternalClassWithNestedElements.NestedClassLevelOne.someNestedStaticFunction()) + } + + @Test + fun propertyOfClassNestedInInternalClassCanBeAccessed() { + val obj = InternalClassWithNestedElements.NestedClassLevelOne(2, 3) + assertEquals(333, obj.someNestedProperty) + + obj.someNestedProperty = 11 + assertEquals(11, obj.someNestedProperty) + } + + @Test + fun staticPropertyOfClassNestedInInternalClassCanBeAccessed() { + assertEquals(77, InternalClassWithNestedElements.NestedClassLevelOne.getSomeNestedStaticProperty()) + + InternalClassWithNestedElements.NestedClassLevelOne.setSomeNestedStaticProperty(37) + assertEquals(37, InternalClassWithNestedElements.NestedClassLevelOne.getSomeNestedStaticProperty()) + } + + ////////// 3. Tests related to direct members of 'InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo'. + @Test + fun functionOfClassNestedInClassNestedInInternalClassCanBeAccessed() { + val obj = InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo(2, 33) + assertEquals(66, obj.doubleNestedFunction()) + } + + @Test + fun staticFunctionOfClassNestedInClassNestedInInternalClassCanBeAccessed() { + assertEquals("LEVEL_2_NESTING", InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo.doubleNestedStaticFunction()) + } + + @Test + fun propertyOfClassNestedInClassNestedInInternalClassCanBeAccessed() { + val obj = InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo(2, 33) + assertEquals(17, obj.doubleNestedProperty) + + obj.doubleNestedProperty = 13 + assertEquals(13, obj.doubleNestedProperty) + } + + @Test + fun staticPropertyOfClassNestedInClassNestedInInternalClassCanBeAccessed() { + assertEquals(123, InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo.getDoubleNestedStaticProperty()) + + InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo.setDoubleNestedStaticProperty(9) + assertEquals(9, InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo.getDoubleNestedStaticProperty()) + } + + ////////// 4. Tests related to nested enum, nested exception and nested lambda. + @Test + fun enumeratorsOfEnumNestedInInternalClassCanBeAccessed() { + val someObject = InternalClassWithNestedElements.NestedEnum.OPTION_1 + assertEquals(1, someObject.value) + + assertEquals(InternalClassWithNestedElements.NestedEnum.OPTION_1, someObject) + } + + @Test + fun exceptionNestedInInternalClassCanBeAccessed() { + val exception = assertThrows(InternalClassWithNestedElements.NestedException::class.java) { + InternalClassWithNestedElements.throwNestedException() + } + assertEquals(exception.error, InternalClassWithNestedElements.NestedEnum.OPTION_1) + } + + @Test + fun lambdaNestedInInternalClassCanBeAccessedWhenObtainedFromCpp() { + val someLambda = InternalClassWithNestedElements.produceNestedLambda() + assertEquals("CONTENT_FROM_NESTED_LAMBDA_FROM_CPP: 'Kotlin 2026'", someLambda.apply("Kotlin ", 2026)) + } + + ////////// 5. Tests related to direct members of 'InternalClassWithNestedElements.NestedStruct'. + @Test + fun fieldsOfStructNestedInInternalClassCanBeAccessed() { + val obj = InternalClassWithNestedElements.NestedStruct(10, 2026) + assertEquals(10, obj.firstField) + assertEquals("2026", obj.secondField) + } + + @Test + fun fieldConstructorOfStructNestedInInternalClassCanBeAccessed() { + val obj = InternalClassWithNestedElements.NestedStruct(123, "NESTED_STRUCT") + assertEquals(123, obj.firstField) + assertEquals("NESTED_STRUCT", obj.secondField) + } + + @Test + fun functionOfStructNestedInInternalClassCanBeAccessed() { + val obj = InternalClassWithNestedElements.NestedStruct(10, 2026) + assertEquals(20, obj.nestedStructFunction()) + } + + @Test + fun staticFunctionOfStructNestedInInternalClassCanBeAccessed() { + assertEquals("NESTED_STRUCT_STATIC_FUN", InternalClassWithNestedElements.NestedStruct.nestedStructStaticFunction()) + } + + ////////// 6. Tests related to direct members of 'InternalClassWithNestedElements.NestedInterface'. + @Test + fun staticFunctionOfInterfaceNestedInInternalClassCanBeAccessed() { + assertEquals("NESTED_ITF_STATIC_FUN", InternalClassWithNestedElements.NestedInterface.nestedInterfaceStaticFunction()) + } + + @Test + fun staticPropertyOfInterfaceNestedInInternalClassCanBeAccessed() { + assertEquals(572, InternalClassWithNestedElements.NestedInterface.getNestedInterfaceStaticProperty()) + + InternalClassWithNestedElements.NestedInterface.setNestedInterfaceStaticProperty(37) + assertEquals(37, InternalClassWithNestedElements.NestedInterface.getNestedInterfaceStaticProperty()) + } + + @Test + fun interfaceNestedInInternalClassCanBeAccessedWhenObtainedFromCpp() { + val itfImpl = InternalClassWithNestedElements.produceNestedInterfaceImplementation() + assertEquals(909, itfImpl.nestedInterfaceFunction()) + assertEquals(77, itfImpl.nestedInterfaceProperty) + + itfImpl.nestedInterfaceProperty = 123 + assertEquals(123, itfImpl.nestedInterfaceProperty) + } +} \ No newline at end of file diff --git a/functional-tests/functional/android-kotlin/src/test/kotlin/com/here/android/test/VisibilityAttributeTest.kt b/functional-tests/functional/android-kotlin/src/test/kotlin/com/here/android/test/VisibilityAttributeTest.kt index de8e68a635..ad8ba19efc 100644 --- a/functional-tests/functional/android-kotlin/src/test/kotlin/com/here/android/test/VisibilityAttributeTest.kt +++ b/functional-tests/functional/android-kotlin/src/test/kotlin/com/here/android/test/VisibilityAttributeTest.kt @@ -27,11 +27,22 @@ import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config -class ImplementationOfSomeInternalInterface: SomeInternalInterface { +class ImplementationOfSomeInternalInterface : SomeInternalInterface { override fun foo(): Int = 709 override fun bar(): Long = 121 } +class ImplementationOfInternalAttributeInterfaceParent : InternalAttributeInterfaceParent { + override fun fooBar() {} + override var prop: String + get() = propHolder + set(value) { + propHolder = value + } + + private var propHolder: String = "Hello world!" +} + @RunWith(RobolectricTestRunner::class) @Config(application = RobolectricApplication::class) class VisibilityAttributeTest { diff --git a/functional-tests/functional/android/src/test/java/com/here/android/test/VisibilityAttributeTest.java b/functional-tests/functional/android/src/test/java/com/here/android/test/VisibilityAttributeTest.java index 95557b5fe9..0429efe3c2 100644 --- a/functional-tests/functional/android/src/test/java/com/here/android/test/VisibilityAttributeTest.java +++ b/functional-tests/functional/android/src/test/java/com/here/android/test/VisibilityAttributeTest.java @@ -31,18 +31,6 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -class ImplementationOfSomeInternalInterface implements SomeInternalInterface { - @Override - public int foo() { - return 709; - } - - @Override - public long bar() { - return 121; - } -} - @RunWith(RobolectricTestRunner.class) @Config(sdk = Build.VERSION_CODES.M, application = RobolectricApplication.class) public class VisibilityAttributeTest { @@ -52,40 +40,11 @@ public void internalConstructorOfClassCanBeCalled() { SomeClassWithInternalMembers someObject = new SomeClassWithInternalMembers(); } - @Test - public void functionOfInternalClassCanBeCalled() { - SomeInternalClassWithMembers someObject = SomeInternalClassWithMembers.create(); - assertEquals(987, someObject.someFunction()); - } - - @Test - public void staticFunctionOfInternalClassCanBeCalled() { - assertEquals(765, SomeInternalClassWithMembers.someStaticFunction()); - } - - @Test - public void fieldOfInternalStructCanBeAccessed() { - SomeInternalStructWithMembers someObject = SomeInternalStructWithMembers.create(); - assertEquals(123, someObject.someInteger); - assertEquals(456, someObject.someLong); - } - - @Test - public void functionOfInternalStructCanBeCalled() { - SomeInternalStructWithMembers someObject = SomeInternalStructWithMembers.create(); - assertEquals(32, someObject.someFunction()); - } - - @Test - public void internalFieldOfStructCanBeAccessed() { - SomeStructWithInternalMembers someObject = new SomeStructWithInternalMembers(21); - assertEquals(21, someObject.someInteger); - assertEquals(444, someObject.someLong); - } - @Test public void internalFreeArgsCtorCanBeCalled() { SomeStructWithInternalFreeArgsCtor someObject = new SomeStructWithInternalFreeArgsCtor(33); + + // Note: 'someObject.someString' is a public field of public structure. assertEquals("Special string", someObject.someString); } @@ -97,6 +56,8 @@ public void internalAllArgsCtorCanBeCalled() { @Test public void internalFieldCtorCanBeCalled() { SomeStructWithInternalFieldConstructor someObject = new SomeStructWithInternalFieldConstructor(77); + + // Note: 'someObject.someString' is a public field of public structure. assertEquals("QAZWSX", someObject.someString); } @@ -106,18 +67,10 @@ public void valueOfInternalEnumCanBeAccessed() { assertEquals(SomeInternalEnum.TWO, someObject); } - @Test - public void internaInterfaceFromJavaCanBeUsed() { - ImplementationOfSomeInternalInterface someInterfaceImpl = new ImplementationOfSomeInternalInterface(); - SomeStructWithInternalMembers someObject = new SomeStructWithInternalMembers(21); - } - @Test public void internalExceptionCanBeThrown() { SomethingBadHappenedException exception = assertThrows(SomethingBadHappenedException.class, () -> { throw new SomethingBadHappenedException(SomeInternalEnum.ONE); }); - - assertEquals(exception.error, SomeInternalEnum.ONE); } } diff --git a/functional-tests/functional/input/lime/NestedInternalElements.lime b/functional-tests/functional/input/lime/NestedInternalElements.lime new file mode 100644 index 0000000000..f85fe035ca --- /dev/null +++ b/functional-tests/functional/input/lime/NestedInternalElements.lime @@ -0,0 +1,206 @@ +# Copyright (C) 2016-2026 HERE Europe B.V. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# License-Filename: LICENSE + +package test + +############################################################################################### +# The test cases in this file are used to check the access to elements nested in internal # +# type. They are explicitly treated as internal in Kotlin. Multi-level nesting is tested. # +############################################################################################### + +// This is a class, which contains multiple nested elements. +// It has internal visibility because 'Internal' is used. +// Each element inside should be treated as internal. +@Skip(Dart, Swift) +@Internal +class InternalClassWithNestedElements { + // This is a constant nested in internal class. + // It should be generated as internal and synthetic. + const SOME_CONSTANT: Int = 2026 + + // This is a constructor in internal class. It should be explicitly annotated as internal. + // Unfortunately, it cannot use synthetic, because constructor is not allowed target. + constructor some_constructor(x: Int, y: Int) + + // This is a function in internal class. It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + fun some_function(): Int + + // This is a static function in internal class. It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + static fun some_static_function(): String + + // This is a property in internal class. It should be explicitly annotated as internal. + // And use synthetic for get/set functions to hide them from Java. + property some_property: Long + + // This is a static property in internal class. + // It is represented as static get/set functions pair. + // They should be explicitly annotated as internal and use JvmStatic to hide them from Java. + static property some_static_property: Long + + // This is a static function used solely to throw the nested exception. + // It should be generated as internal and synthetic. + static fun throw_nested_exception() throws Nested + + // This is a static function used solely to created the nested lambda on C++ site. + // It should be generated as internal and synthetic. + static fun produce_nested_lambda(): NestedLambda + + // This is a static function used solely to created the nested interface impl on C++ site. + // It should be generated as internal and synthetic. + static fun produce_nested_interface_implementation(): NestedInterface + + // This is a class nested inside internal class. + // It should be generated with explicit 'internal' keyword. + // Each element nested inside this class should also have explicit internal visibility. + class NestedClassLevelOne { + // This is a constructor of class nested in internal class. + // It should be explicitly annotated as internal. + // Unfortunately, it cannot use synthetic, because constructor is not allowed target. + constructor some_nested_constructor(x: Int, y: Int) + + // This is a function in class nested inside internal class. + // It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + fun some_nested_function(): Int + + // This is a static function in class nested in internal class. + // It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + static fun some_nested_static_function(): String + + // This is a property in class nested in internal class. + // It should be explicitly annotated as internal. + // And use synthetic for get/set functions to hide them from Java. + property some_nested_property: Long + + // This is a static property in class nested in internal class. + // It is represented as static get/set functions pair. + // They should be explicitly annotated as internal and use JvmStatic to hide them from Java. + static property some_nested_static_property: Long + + // This is a class nested inside class, that is nested in internal class. + // It should be generated with explicit 'internal' keyword. + // Each element nested inside this class should also have explicit internal visibility. + class NestedClassLevelTwo { + // This is a constructor of class, that is nested in class, that is nested in internal class. + // It should be explicitly annotated as internal. + // Unfortunately, it cannot use synthetic, because constructor is not allowed target. + constructor double_nested_constructor(x: Int, y: Int) + + // This is a function in class, that is nested in class, that is nested in internal class. + // It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + fun double_nested_function(): Int + + // This is a static function in class, that is nested in class, that is nested in internal class. + // It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + static fun double_nested_static_function(): String + + // This is a property in class, that is nested in class, that is nested in internal class. + // It should be explicitly annotated as internal. + // And use synthetic for get/set functions to hide them from Java. + property double_nested_property: Long + + // This is a static property in class, that is nested in class, that is nested in internal class. + // It is represented as static get/set functions pair. + // They should be explicitly annotated as internal and use JvmStatic to hide them from Java. + static property double_nested_static_property: Long + } + } + + // This is an enumeration nested in internal class. + // It should be annotated as internal. + // Its value field should be synthetic to disallow accessing it from Java. + enum NestedEnum { + OPTION_1 = 1, + OPTION_2 = 2 + } + + // This is an exception nested in internal class. + // It should be annotated as internal. + // Its error field should be internal and synthetic to disallow accessing it from Java. + exception Nested(NestedEnum) + + // This is a lambda nested in internal class. + // It should be annotated as internal. + // Its 'call()' function should be synthetic to disallow accessing it from Java. + @Overloaded + lambda NestedLambda = (String, Long) -> String + + // This is a structure nested in internal class. + // It should be annotated as internal. + // Its fields should be internal and synthetic. + // Its functions should be internal and synthetic. + // Its constructors should be internal (sadly, they cannot be synthetic). + struct NestedStruct { + // This is a field of structure, which is nested in internal class. + // It should use 'internal' and synthetic. + firstField: Int + + // This is a field of structure, which is nested in internal class. + // It should use 'internal' and synthetic. + secondField: String + + // This is a field constructor of structure. The structure is nested in internal class. + // It should be explicitly internal. Sadly, it cannot be synthetic. + field constructor(firstField, secondField) + + // This is a constructor of structure, and the structure is nested in internal class. + // It should be explicitly annotated as internal. + // Unfortunately, it cannot use synthetic, because constructor is not allowed target. + constructor constructor_of_struct(x: Int, y: Int) + + // This is a function in structure nested inside internal class. + // It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + fun nested_struct_function(): Int + + // This is a static function in structure nested in internal class. + // It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + static fun nested_struct_static_function(): String + } + + // This is an interface nested in internal class. + // It should be annotated as internal. + // Its fields should be synthetic --> sadly, Kotlin does not allow 'internal' keyword in interfaces. + // But from Kotlin language POV elements are not accessible, because interface itself is internal. + // The elements should not be accessible in Java because of synthetic attribute. + interface NestedInterface { + // This is a function in interface nested inside internal class. + // It must use synthetic annotation. + // Sadly, it cannot use 'internal' keyword. + fun nested_interface_function(): Int + + // This is a static function in interface nested in internal class. + // Sadly, it cannot use 'internal' keyword. + static fun nested_interface_static_function(): String + + // This is a property in interface nested in internal class. + // It must use synthetic annotation for get/set functions. + // Sadly, it cannot use 'internal' keyword. + property nested_interface_property: Long + + // This is a static property in class nested in internal class. + // It must use synthetic annotation for get/set functions. + // Sadly, it cannot use 'internal' keyword. + static property nested_interface_static_property: Long + } +} diff --git a/functional-tests/functional/input/src/cpp/NestedInternalElements.cpp b/functional-tests/functional/input/src/cpp/NestedInternalElements.cpp new file mode 100644 index 0000000000..4f7718510d --- /dev/null +++ b/functional-tests/functional/input/src/cpp/NestedInternalElements.cpp @@ -0,0 +1,249 @@ +// ------------------------------------------------------------------------------------------------- +// Copyright (C) 2016-2026 HERE Europe B.V. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 +// License-Filename: LICENSE +// +// ------------------------------------------------------------------------------------------------- + +#include "test/InternalClassWithNestedElements.h" + +#include +#include + +namespace test +{ + +////////////// Implementation of type derived from nested interface type --> 'InternalClassWithNestedElements.NestedInterface' +class SomeImplOfNestedInterface : public InternalClassWithNestedElements::NestedInterface { +public: + SomeImplOfNestedInterface() = default; + ~SomeImplOfNestedInterface() override = default; + + int32_t nested_interface_function() override { + return 909; + } + + int64_t get_nested_interface_property() const override { + return m_prop; + } + + void set_nested_interface_property( const int64_t value ) override { + m_prop = value; + } + +private: + int64_t m_prop{77}; +}; + +////////////// Top level internal class: 'InternalClassWithNestedElements' +static int64_t g_some_static_property_of_internal_class = 11; + +class SomeImplOfInternalClassWithNestedElements : public InternalClassWithNestedElements { +public: + SomeImplOfInternalClassWithNestedElements(int32_t x, int32_t y) + : m_x{x}, m_y{y} + {} + + ~SomeImplOfInternalClassWithNestedElements() override = default; + + int32_t some_function() override { + return m_x + m_y; + } + + int64_t get_some_property() const override { + return m_some_property; + } + + void set_some_property(const int64_t value) override { + m_some_property = value; + } + +private: + int32_t m_x; + int32_t m_y; + int64_t m_some_property{2202}; +}; + +std::string +InternalClassWithNestedElements::some_static_function() { + return "SOME_STATIC_FUNCTION"; +} + +::std::error_code +InternalClassWithNestedElements::throw_nested_exception() { + return make_error_code(InternalClassWithNestedElements::NestedEnum::OPTION_1); +} + +InternalClassWithNestedElements::NestedLambda +InternalClassWithNestedElements::produce_nested_lambda() { + return [] (const std::string& p1, const int64_t p2) { + return "CONTENT_FROM_NESTED_LAMBDA_FROM_CPP: '" + p1 + std::to_string(p2) + "'"; + }; +} + +std::shared_ptr +InternalClassWithNestedElements::produce_nested_interface_implementation() { + return std::make_shared(); +} + +int64_t +InternalClassWithNestedElements::get_some_static_property() { + return g_some_static_property_of_internal_class; +} + +void +InternalClassWithNestedElements::set_some_static_property(const int64_t value) { + g_some_static_property_of_internal_class = value; +} + +std::shared_ptr +InternalClassWithNestedElements::some_constructor(int32_t x, int32_t y) { + return std::make_shared(x, y); +} + +////////////// A class nested in internal class: 'InternalClassWithNestedElements.NestedClassLevelOne' +static int64_t g_some_static_property_of_nested_level_1_class = 77; + +class SomeImplOfNestedClassLevelOne : public InternalClassWithNestedElements::NestedClassLevelOne { +public: + SomeImplOfNestedClassLevelOne(int32_t x, int32_t y) + : m_x{x}, m_y{y} + {} + + ~SomeImplOfNestedClassLevelOne() override = default; + + int32_t some_nested_function() override { + return m_x * m_y; + } + + int64_t get_some_nested_property() const override { + return m_some_nested_property; + } + + void set_some_nested_property(const int64_t value) override { + m_some_nested_property = value; + } + +private: + int32_t m_x; + int32_t m_y; + int64_t m_some_nested_property{333}; +}; + +std::string +InternalClassWithNestedElements::NestedClassLevelOne::some_nested_static_function() { + return "LEVEL_1_NESTING"; +} + +int64_t +InternalClassWithNestedElements::NestedClassLevelOne::get_some_nested_static_property() { + return g_some_static_property_of_nested_level_1_class; +} + +void +InternalClassWithNestedElements::NestedClassLevelOne::set_some_nested_static_property(const int64_t value) { + g_some_static_property_of_nested_level_1_class = value; +} + +std::shared_ptr +InternalClassWithNestedElements::NestedClassLevelOne::some_nested_constructor(int32_t x, int32_t y) { + return std::make_shared(x, y); +} + +////////////// A class nested in internal class: 'InternalClassWithNestedElements.NestedClassLevelOne.NestedClassLevelTwo' +static int64_t g_some_static_property_of_nested_level_2_class = 123; + +class SomeImplOfNestedClassLevelTwo : public InternalClassWithNestedElements::NestedClassLevelOne::NestedClassLevelTwo { +public: + SomeImplOfNestedClassLevelTwo(int32_t x, int32_t y) + : m_x{x}, m_y{y} + {} + + ~SomeImplOfNestedClassLevelTwo() override = default; + + int32_t double_nested_function() override { + return m_x * m_y; + } + + int64_t get_double_nested_property() const override { + return m_double_nested_property; + } + + void set_double_nested_property(const int64_t value) override { + m_double_nested_property = value; + } + +private: + int32_t m_x; + int32_t m_y; + int64_t m_double_nested_property{17}; +}; + +std::string +InternalClassWithNestedElements::NestedClassLevelOne::NestedClassLevelTwo::double_nested_static_function() { + return "LEVEL_2_NESTING"; +} + +int64_t +InternalClassWithNestedElements::NestedClassLevelOne::NestedClassLevelTwo::get_double_nested_static_property() { + return g_some_static_property_of_nested_level_2_class; +} + +void +InternalClassWithNestedElements::NestedClassLevelOne::NestedClassLevelTwo::set_double_nested_static_property(const int64_t value) { + g_some_static_property_of_nested_level_2_class = value; +} + +std::shared_ptr +InternalClassWithNestedElements::NestedClassLevelOne::NestedClassLevelTwo::double_nested_constructor(int32_t x, int32_t y) { + return std::make_shared(x, y); +} + +////////////// A struct nested in internal class: 'InternalClassWithNestedElements.NestedStruct' +InternalClassWithNestedElements::NestedStruct +InternalClassWithNestedElements::NestedStruct::constructor_of_struct(int32_t x, int32_t y) { + return InternalClassWithNestedElements::NestedStruct{x, std::to_string(y)}; +} + +int32_t +InternalClassWithNestedElements::NestedStruct::nested_struct_function() const { + return 2 * first_field; +} + +std::string +InternalClassWithNestedElements::NestedStruct::nested_struct_static_function() { + return "NESTED_STRUCT_STATIC_FUN"; +} + +////////////// A struct nested in internal class: 'InternalClassWithNestedElements.NestedInterface' +static int64_t g_nested_interface_static_property = 572; + +std::string +InternalClassWithNestedElements::NestedInterface::nested_interface_static_function() { + return "NESTED_ITF_STATIC_FUN"; +} + +int64_t +InternalClassWithNestedElements::NestedInterface::get_nested_interface_static_property() { + return g_nested_interface_static_property; +} + +void +InternalClassWithNestedElements::NestedInterface::set_nested_interface_static_property(const int64_t value) { + g_nested_interface_static_property = value; +} + +} // namespace test \ No newline at end of file diff --git a/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinGenerator.kt b/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinGenerator.kt index c5ceeccda4..8b6fbfdac7 100644 --- a/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinGenerator.kt +++ b/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinGenerator.kt @@ -129,6 +129,7 @@ internal class KotlinGenerator : Generator { basePackages = basePackages, ) + val syntheticResolver = KotlinSyntheticResolver(limeModel.referenceMap) val visibilityResolver = KotlinVisibilityResolver(limeModel.referenceMap) val internalApiAnnotation = if (requireOptInAnnotation != null) internalApiAnnotationName!! else null @@ -152,6 +153,7 @@ internal class KotlinGenerator : Generator { it, nameResolver, visibilityResolver, + syntheticResolver, importResolver, importCollector, internalApiAnnotation, @@ -238,6 +240,7 @@ internal class KotlinGenerator : Generator { limeElement: LimeNamedElement, nameResolver: KotlinNameResolver, visibilityResolver: KotlinVisibilityResolver, + syntheticResolver: KotlinSyntheticResolver, importResolver: KotlinImportResolver, importCollector: KotlinImportCollector, internalApiAnnotation: String?, @@ -274,7 +277,7 @@ internal class KotlinGenerator : Generator { "internalApiAnnotationClassPath" to internalApiAnnotationClassPath, ) - val nameResolvers = mapOf("" to nameResolver, "visibility" to visibilityResolver) + val nameResolvers = mapOf("" to nameResolver, "visibility" to visibilityResolver, "synthetic" to syntheticResolver) val mainContent = TemplateEngine.render("kotlin/KotlinFile", templateData, nameResolvers, KotlinGeneratorPredicates.predicates) diff --git a/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinGeneratorPredicates.kt b/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinGeneratorPredicates.kt index 37fa6e7d4f..2f8f72e52f 100644 --- a/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinGeneratorPredicates.kt +++ b/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinGeneratorPredicates.kt @@ -29,7 +29,6 @@ import com.here.gluecodium.model.lime.LimeExternalDescriptor import com.here.gluecodium.model.lime.LimeFunction import com.here.gluecodium.model.lime.LimeInterface import com.here.gluecodium.model.lime.LimeLambda -import com.here.gluecodium.model.lime.LimeNamedElement import com.here.gluecodium.model.lime.LimeProperty import com.here.gluecodium.model.lime.LimeStruct @@ -46,7 +45,6 @@ internal object KotlinGeneratorPredicates { "hasStaticProperties" to this::hasStaticProperties, "isExceptionSameForCtorAndHookFun" to this::isExceptionSameForCtorAndHookFun, "isFunctionalInterface" to this::isFunctionalInterface, - "isInternal" to this::isInternal, "propertyGetterRequiresJvmName" to this::propertyGetterRequiresJvmName, "propertySetterRequiresJvmName" to this::propertySetterRequiresJvmName, "needsAllFieldsConstructor" to this::needsAllFieldsConstructor, @@ -156,7 +154,4 @@ internal object KotlinGeneratorPredicates { CommonGeneratorPredicates.isInternal(property, LimeAttributeType.KOTLIN) || (property.setter?.attributes?.have(LimeAttributeType.KOTLIN, LimeAttributeValueType.NAME)) ?: false ) - - private fun isInternal(element: Any) = - element is LimeNamedElement && CommonGeneratorPredicates.isInternal(element, LimeAttributeType.KOTLIN) } diff --git a/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinInternalVisibilityPredicate.kt b/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinInternalVisibilityPredicate.kt new file mode 100644 index 0000000000..99e02f3cd3 --- /dev/null +++ b/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinInternalVisibilityPredicate.kt @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016-2026 HERE Europe B.V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +package com.here.gluecodium.generator.kotlin + +import com.here.gluecodium.cli.GluecodiumExecutionException +import com.here.gluecodium.generator.common.CommonGeneratorPredicates +import com.here.gluecodium.model.lime.LimeAttributeType.KOTLIN +import com.here.gluecodium.model.lime.LimeElement +import com.here.gluecodium.model.lime.LimeField +import com.here.gluecodium.model.lime.LimeNamedElement +import com.here.gluecodium.model.lime.LimeType + +internal class KotlinInternalVisibilityPredicate(private val referenceMap: Map) { + // Returns true when the element is conceptually internal. + // Some elements cannot use internal keyword (e.g. the ones which are children of Kotlin interface). + // In such cases we still want to have information about 'conceptual' internal visibility of such + // elements to annotate them with 'JvmSynthetic' --> to hide them when Kotlin is accessed from Java. + // + // The children of such interface will not be visible in Kotlin, but without JvmSynthetic they would + // be visible in Java. + fun isConceptuallyInternal(element: Any): Boolean { + if (element !is LimeNamedElement) { + throw GluecodiumExecutionException("Unsupported element type ${element.javaClass.name}") + } + + return isInternal(element) || isInInternalTypesHierarchy(element) + } + + private fun isInternal(element: LimeNamedElement): Boolean { + var internal = CommonGeneratorPredicates.isInternal(element, KOTLIN) + if (!internal && element is LimeField) { + internal = CommonGeneratorPredicates.isInternal(element.typeRef.type, KOTLIN) + } + + return internal + } + + private fun isInInternalTypesHierarchy(element: LimeNamedElement): Boolean { + val parentElement = referenceMap[element.path.parent.toString()] as LimeNamedElement? ?: return false + if (isInternal(parentElement)) { + return true + } + + val isEachParentPublic = + generateSequence(parentElement) { + referenceMap[it.path.parent.toString()] as? LimeType + }.none { isInternal(it) } + + return !isEachParentPublic + } +} diff --git a/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinSyntheticResolver.kt b/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinSyntheticResolver.kt new file mode 100644 index 0000000000..c470fb3407 --- /dev/null +++ b/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinSyntheticResolver.kt @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016-2026 HERE Europe B.V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ + +package com.here.gluecodium.generator.kotlin + +import com.here.gluecodium.cli.GluecodiumExecutionException +import com.here.gluecodium.generator.common.NameResolver +import com.here.gluecodium.model.lime.LimeElement +import com.here.gluecodium.model.lime.LimeNamedElement + +internal class KotlinSyntheticResolver( + private val referenceMap: Map, + private val predicate: KotlinInternalVisibilityPredicate = KotlinInternalVisibilityPredicate(referenceMap), +) : NameResolver { + override fun resolveName(element: Any): String { + if (element !is LimeNamedElement) { + throw GluecodiumExecutionException("Unsupported element type ${element.javaClass.name}") + } + + return when { + predicate.isConceptuallyInternal(element) -> "@JvmSynthetic " + else -> "" + } + } +} diff --git a/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinVisibilityResolver.kt b/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinVisibilityResolver.kt index 2032e5c2aa..0bf4b0358b 100644 --- a/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinVisibilityResolver.kt +++ b/gluecodium/src/main/java/com/here/gluecodium/generator/kotlin/KotlinVisibilityResolver.kt @@ -20,40 +20,26 @@ package com.here.gluecodium.generator.kotlin import com.here.gluecodium.cli.GluecodiumExecutionException -import com.here.gluecodium.generator.common.CommonGeneratorPredicates import com.here.gluecodium.generator.common.NameResolver -import com.here.gluecodium.model.lime.LimeAttributeType.KOTLIN import com.here.gluecodium.model.lime.LimeElement -import com.here.gluecodium.model.lime.LimeField import com.here.gluecodium.model.lime.LimeInterface import com.here.gluecodium.model.lime.LimeLambda import com.here.gluecodium.model.lime.LimeNamedElement -import com.here.gluecodium.model.lime.LimeProperty -import com.here.gluecodium.model.lime.LimeType -internal class KotlinVisibilityResolver(private val referenceMap: Map) : NameResolver { +internal class KotlinVisibilityResolver( + private val referenceMap: Map, + private val predicate: KotlinInternalVisibilityPredicate = KotlinInternalVisibilityPredicate(referenceMap), +) : NameResolver { override fun resolveName(element: Any): String { - val namedElement = element as? LimeNamedElement - if (namedElement != null) { - return if (!isInternal(element)) { - "" - } else if (!isDirectKotlinInterfaceChild(element)) { - "internal " - } else { - "" - } - } else { + if (element !is LimeNamedElement) { throw GluecodiumExecutionException("Unsupported element type ${element.javaClass.name}") } - } - private fun isInternal(element: LimeNamedElement): Boolean { - var internal = CommonGeneratorPredicates.isInternal(element, KOTLIN) - if (!internal && element is LimeField) { - internal = CommonGeneratorPredicates.isInternal(element.typeRef.type, KOTLIN) + return when { + isDirectKotlinInterfaceChild(element) -> "" + predicate.isConceptuallyInternal(element) -> "internal " + else -> "" } - - return internal } // Elements which are direct children of 'interface' or 'fun interface' cannot use 'internal' keyword in Kotlin. @@ -62,33 +48,4 @@ internal class KotlinVisibilityResolver(private val referenceMap: Mapkotlin/KotlinDocComment}}{{>kotlin/KotlinAttributes}} -{{#resolveName "visibility"}}{{#unless this.isEmpty}}@JvmSynthetic {{this}}{{/unless}}{{/resolveName}}{{!! +{{resolveName "synthetic"}}{{resolveName "visibility"}}{{!! }}@JvmField final val {{resolveName}}: {{resolveName typeRef}} = {{resolveName value}} \ No newline at end of file diff --git a/gluecodium/src/main/resources/templates/kotlin/KotlinEnumeration.mustache b/gluecodium/src/main/resources/templates/kotlin/KotlinEnumeration.mustache index ede99aa88f..0ce76235ea 100644 --- a/gluecodium/src/main/resources/templates/kotlin/KotlinEnumeration.mustache +++ b/gluecodium/src/main/resources/templates/kotlin/KotlinEnumeration.mustache @@ -24,11 +24,7 @@ {{/unless}}{{/internalApiAnnotation}}internal {{!! }}{{/if}}{{!! }}{{#unless external.kotlin.converter}}{{>kotlin/KotlinTypeVisibility}}{{/unless}}{{!! -}}enum class {{resolveName}}(@JvmField {{!! -}}{{#resolveName "visibility"}}{{!! -}}{{#unless this.isEmpty}}@JvmSynthetic {{/unless}}{{!! -}}{{this}}{{!! -}}{{/resolveName}}val value: Int) { +}}enum class {{resolveName}}(@JvmField {{resolveName "synthetic"}}{{resolveName "visibility"}}val value: Int) { {{joinPartial uniqueEnumerators "kotlin/KotlinEnumerator" ", "}}{{#if uniqueEnumerators}};{{/if}}{{#if aliasEnumerators}} diff --git a/gluecodium/src/main/resources/templates/kotlin/KotlinEnumerator.mustache b/gluecodium/src/main/resources/templates/kotlin/KotlinEnumerator.mustache index 5f18233a53..de1564ca44 100644 --- a/gluecodium/src/main/resources/templates/kotlin/KotlinEnumerator.mustache +++ b/gluecodium/src/main/resources/templates/kotlin/KotlinEnumerator.mustache @@ -21,10 +21,6 @@ {{#if comment}} {{prefixPartial "kotlin/KotlinDocComment" " "}}{{/if}}{{!! }}{{prefixPartial "kotlin/KotlinAttributes" " "}}{{!! -}}{{#if isAlias}} @JvmField {{!! -}}{{#resolveName "visibility"}}{{!! -}}{{#unless this.isEmpty}}@JvmSynthetic {{/unless}}{{!! -}}{{this}}{{!! -}}{{/resolveName}}val {{resolveName}}{{!! +}}{{#if isAlias}} @JvmField {{resolveName "synthetic"}}{{resolveName "visibility"}}val {{resolveName}}{{!! }} = {{resolveName value}}{{/if}}{{!! }}{{#unless isAlias}} {{resolveName}}({{resolveName value}}){{/unless}} \ No newline at end of file diff --git a/gluecodium/src/main/resources/templates/kotlin/KotlinException.mustache b/gluecodium/src/main/resources/templates/kotlin/KotlinException.mustache index 0d1f97387b..631e7e26a5 100644 --- a/gluecodium/src/main/resources/templates/kotlin/KotlinException.mustache +++ b/gluecodium/src/main/resources/templates/kotlin/KotlinException.mustache @@ -20,5 +20,5 @@ !}} {{>kotlin/KotlinDocComment}}{{>kotlin/KotlinAttributes}} {{>kotlin/KotlinTypeVisibility}}{{!! -}}class {{resolveName}}(@JvmField val error: {{resolveName errorType}}) : Exception(error.toString()) +}}class {{resolveName}}({{resolveName "synthetic"}}@JvmField val error: {{resolveName errorType}}) : Exception(error.toString()) diff --git a/gluecodium/src/main/resources/templates/kotlin/KotlinFunction.mustache b/gluecodium/src/main/resources/templates/kotlin/KotlinFunction.mustache index 54d18e45fc..496404acf8 100644 --- a/gluecodium/src/main/resources/templates/kotlin/KotlinFunction.mustache +++ b/gluecodium/src/main/resources/templates/kotlin/KotlinFunction.mustache @@ -21,8 +21,21 @@ {{#unless this.isConstructor}}{{>kotlin/KotlinMethodComment}}{{>kotlin/KotlinAttributes}}{{/unless}} {{#thrownType}}@Throws({{resolveName typeRef}}::class){{/thrownType}} {{#if isStatic}}@JvmStatic {{/if}}{{!! -}}{{#resolveName "visibility"}}{{#unless this.isEmpty}}@JvmSynthetic {{/unless}}{{/resolveName}}{{!! -}}{{#unless override}}{{#unless isInterface}}{{#ifPredicate "isInternal"}}@JvmName("{{resolveName}}") {{/ifPredicate}}{{/unless}}{{/unless}}{{!! + + 1. If function has internal visibility then hide it from java. +}}{{resolveName "synthetic"}}{{!! + +}}{{#unless override}}{{#unless isInterface}}{{!! + + 2. If function can use internal keyword, then set JvmName() to properly resolve JNI symbol. +}}{{#set thisFunction=this}}{{#thisFunction}}{{!! + }}{{#resolveName "visibility"}}{{#unless this.isEmpty}}{{!! + }}@JvmName("{{resolveName thisFunction}}") {{!! + }}{{/unless}}{{/resolveName}}{{!! +}}{{/thisFunction}}{{/set}}{{!! + +}}{{/unless}}{{/unless}}{{!! + }}{{#if override}}override {{/if}}{{!! }}{{#unless isInterface}}{{!! }}{{#unless this.isConstructor}}{{resolveName "visibility"}}{{/unless}}{{!! diff --git a/gluecodium/src/main/resources/templates/kotlin/KotlinProperty.mustache b/gluecodium/src/main/resources/templates/kotlin/KotlinProperty.mustache index ae36c16655..3b47913cb1 100644 --- a/gluecodium/src/main/resources/templates/kotlin/KotlinProperty.mustache +++ b/gluecodium/src/main/resources/templates/kotlin/KotlinProperty.mustache @@ -26,19 +26,29 @@ }}{{#unless setter}}val{{/unless}}{{!! }} {{resolveName}}: {{resolveName typeRef}} {{#unless isCached}}{{#set thisProperty=this}}{{#thisProperty}} - {{#unless isInterface}}{{!! + {{resolveName thisProperty "synthetic"}}{{#unless isInterface}}{{!! }}{{#unless override}}{{!! -}}{{#resolveName thisProperty "visibility" ""}}{{#unless this.isEmpty}}@JvmSynthetic {{/unless}}{{/resolveName}}{{!! -}}{{#ifPredicate thisProperty "propertyGetterRequiresJvmName"}}@JvmName("{{resolveName thisProperty "" "getter"}}") {{/ifPredicate}}{{/unless}}{{!! + +}}{{#resolveName thisProperty "visibility" ""}}{{!! + }}{{#unless this.isEmpty}}@JvmName("{{resolveName thisProperty "" "getter"}}") {{/unless}}{{!! + }}{{#if this.isEmpty}}{{#ifPredicate thisProperty "propertyGetterRequiresJvmName"}}@JvmName("{{resolveName thisProperty "" "getter"}}") {{/ifPredicate}}{{/if}}{{!! +}}{{/resolveName}}{{!! + +}}{{/unless}}{{!! }}external {{/unless}}get{{#setter}} - {{#unless isInterface}}{{!! + {{resolveName thisProperty "synthetic"}}{{#unless isInterface}}{{!! }}{{#unless override}}{{!! -}}{{#resolveName thisProperty "visibility" ""}}{{#unless this.isEmpty}}@JvmSynthetic {{/unless}}{{/resolveName}}{{!! -}}{{#ifPredicate thisProperty "propertySetterRequiresJvmName"}}@JvmName("{{resolveName thisProperty "" "setter"}}") {{/ifPredicate}}{{/unless}}{{!! + +}}{{#resolveName thisProperty "visibility" ""}}{{!! + }}{{#unless this.isEmpty}}@JvmName("{{resolveName thisProperty "" "setter"}}") {{/unless}}{{!! + }}{{#if this.isEmpty}}{{#ifPredicate thisProperty "propertySetterRequiresJvmName"}}@JvmName("{{resolveName thisProperty "" "setter"}}") {{/ifPredicate}}{{/if}}{{!! +}}{{/resolveName}}{{!! + +}}{{/unless}}{{!! }}external {{/unless}}set{{/setter}} {{/thisProperty}}{{/set}}{{/unless}} {{#if isCached}}{{#set thisProperty=this}}{{#thisProperty}} - {{#resolveName thisProperty "visibility" ""}}{{#unless this.isEmpty}}@JvmSynthetic {{/unless}}{{/resolveName}}{{!! + {{resolveName thisProperty "synthetic" ""}}{{!! }}get() { if (!is_cached_{{resolveName}}) { cache_{{resolveName}} = {{resolveName this "" "getter"}}_private() diff --git a/gluecodium/src/main/resources/templates/kotlin/KotlinStruct.mustache b/gluecodium/src/main/resources/templates/kotlin/KotlinStruct.mustache index 16bd4ff7a0..6289213aaf 100644 --- a/gluecodium/src/main/resources/templates/kotlin/KotlinStruct.mustache +++ b/gluecodium/src/main/resources/templates/kotlin/KotlinStruct.mustache @@ -32,7 +32,7 @@ {{#fields}} {{prefixPartial "kotlin/KotlinDocComment" " "}}{{prefixPartial "kotlin/KotlinAttributes" " "}}{{!! }} @JvmField {{!! -}}{{#resolveName "visibility"}}{{#unless this.isEmpty}}@JvmSynthetic {{this}}{{/unless}}{{/resolveName}}{{!! +}}{{resolveName "synthetic"}}{{resolveName "visibility"}}{{!! }}{{#unless isImmutable}}var {{/unless}}{{!! }}{{#if isImmutable}}val {{/if}}{{!! }}{{resolveName}}: {{resolveName typeRef}}{{!! diff --git a/gluecodium/src/test/resources/smoke/annotations/input/Annotations.lime b/gluecodium/src/test/resources/smoke/annotations/input/Annotations.lime index 0c5d7ca0aa..0ea6549845 100644 --- a/gluecodium/src/test/resources/smoke/annotations/input/Annotations.lime +++ b/gluecodium/src/test/resources/smoke/annotations/input/Annotations.lime @@ -32,6 +32,8 @@ class OuterPublicClazz { @Internal interface OuterInternalInterface { fun someFunction(): Int + property someProperty: Int + static property someStaticProperty: Int } @Internal diff --git a/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/Annotations.kt b/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/Annotations.kt index 31353f7fd7..a5b3707af0 100644 --- a/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/Annotations.kt +++ b/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/Annotations.kt @@ -29,7 +29,7 @@ internal class Annotations : NativeBase { - external fun testOptional(self: Annotations) : Boolean? + @JvmSynthetic @JvmName("testOptional") internal external fun testOptional(self: Annotations) : Boolean? @@ -39,4 +39,3 @@ internal class Annotations : NativeBase { } } - diff --git a/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalException.kt b/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalException.kt index e9fc711d3d..0f9266f23c 100644 --- a/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalException.kt +++ b/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalException.kt @@ -11,6 +11,6 @@ package com.example.smoke import com.example.MySmokeTestsInternalApi @MySmokeTestsInternalApi -internal class OuterInternalException(@JvmField val error: OuterInternalEnum) : Exception(error.toString()) +internal class OuterInternalException(@JvmSynthetic @JvmField val error: OuterInternalEnum) : Exception(error.toString()) diff --git a/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalInterface.kt b/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalInterface.kt index 48313e65b6..f1a32b6fa1 100644 --- a/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalInterface.kt +++ b/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalInterface.kt @@ -12,13 +12,31 @@ import com.example.MySmokeTestsInternalApi import com.example.NativeBase @MySmokeTestsInternalApi -internal fun interface OuterInternalInterface { +internal interface OuterInternalInterface { - fun someFunction() : Int + @JvmSynthetic fun someFunction() : Int + var someProperty: Int + @JvmSynthetic get + @JvmSynthetic set + + companion object { + + + @JvmStatic @JvmSynthetic fun getSomeStaticProperty() : Int { + return OuterInternalInterfaceImpl.getSomeStaticProperty() + } + + + + @JvmStatic @JvmSynthetic fun setSomeStaticProperty(value: Int) : Unit { + OuterInternalInterfaceImpl.setSomeStaticProperty(value) + } + + } } /** @@ -33,11 +51,20 @@ private class OuterInternalInterfaceImpl : NativeBase, OuterInternalInterface { - override external fun someFunction() : Int + @JvmSynthetic override external fun someFunction() : Int + + override var someProperty: Int + @JvmSynthetic external get + @JvmSynthetic external set companion object { @JvmStatic private external fun disposeNativeHandle(nativeHandle: Long) + + + @JvmStatic @JvmSynthetic @JvmName("getSomeStaticProperty") internal external fun getSomeStaticProperty() : Int + + @JvmStatic @JvmSynthetic @JvmName("setSomeStaticProperty") internal external fun setSomeStaticProperty(value: Int) : Unit } } diff --git a/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalLambda.kt b/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalLambda.kt index 2fee46637a..1c452aba53 100644 --- a/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalLambda.kt +++ b/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalLambda.kt @@ -15,7 +15,7 @@ import com.example.NativeBase internal fun interface OuterInternalLambda { - fun apply(p0: String) : Int + @JvmSynthetic fun apply(p0: String) : Int } /** @@ -30,7 +30,7 @@ private class OuterInternalLambdaImpl : NativeBase, OuterInternalLambda { - override external fun apply(p0: String) : Int + @JvmSynthetic override external fun apply(p0: String) : Int diff --git a/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalStruct.kt b/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalStruct.kt index a147be61c6..2a6785b2ec 100644 --- a/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalStruct.kt +++ b/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterInternalStruct.kt @@ -12,7 +12,7 @@ import com.example.MySmokeTestsInternalApi @MySmokeTestsInternalApi internal class OuterInternalStruct { - @JvmField var someField: Int + @JvmField @JvmSynthetic internal var someField: Int diff --git a/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterPublicClazz.kt b/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterPublicClazz.kt index f23bc21f77..7ebfbf988f 100644 --- a/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterPublicClazz.kt +++ b/gluecodium/src/test/resources/smoke/annotations/output/android-kotlin/com/example/smoke/OuterPublicClazz.kt @@ -31,7 +31,7 @@ class OuterPublicClazz : NativeBase { - external fun someFunction() : Boolean + @JvmSynthetic @JvmName("someFunction") internal external fun someFunction() : Boolean @@ -43,7 +43,6 @@ class OuterPublicClazz : NativeBase { - /** * For internal use only. * @suppress @@ -64,4 +63,3 @@ class OuterPublicClazz : NativeBase { } } - diff --git a/gluecodium/src/test/resources/smoke/comments/output/android-kotlin/com/example/smoke/InternalClassWithComments.kt b/gluecodium/src/test/resources/smoke/comments/output/android-kotlin/com/example/smoke/InternalClassWithComments.kt index 55a3415767..949cdb87db 100644 --- a/gluecodium/src/test/resources/smoke/comments/output/android-kotlin/com/example/smoke/InternalClassWithComments.kt +++ b/gluecodium/src/test/resources/smoke/comments/output/android-kotlin/com/example/smoke/InternalClassWithComments.kt @@ -5,6 +5,7 @@ @file:JvmName("InternalClassWithCommentsExtensions") + package com.example.smoke import com.example.NativeBase @@ -31,7 +32,7 @@ internal class InternalClassWithComments : NativeBase { * This is definitely internal */ - external fun doNothing() : Unit + @JvmSynthetic @JvmName("doNothing") internal external fun doNothing() : Unit diff --git a/gluecodium/src/test/resources/smoke/errors/output/android-kotlin/com/example/smoke/SomethingBadHappenedException.kt b/gluecodium/src/test/resources/smoke/errors/output/android-kotlin/com/example/smoke/SomethingBadHappenedException.kt index 7b02006df3..f6d0beb181 100644 --- a/gluecodium/src/test/resources/smoke/errors/output/android-kotlin/com/example/smoke/SomethingBadHappenedException.kt +++ b/gluecodium/src/test/resources/smoke/errors/output/android-kotlin/com/example/smoke/SomethingBadHappenedException.kt @@ -5,9 +5,10 @@ @file:JvmName("SomethingBadHappenedExtensions") + package com.example.smoke -internal class SomethingBadHappenedException(@JvmField val error: SomeInternalEnum) : Exception(error.toString()) +internal class SomethingBadHappenedException(@JvmSynthetic @JvmField val error: SomeInternalEnum) : Exception(error.toString()) diff --git a/gluecodium/src/test/resources/smoke/visibility_attribute/input/KotlinNestedInternalElements.lime b/gluecodium/src/test/resources/smoke/visibility_attribute/input/KotlinNestedInternalElements.lime new file mode 100644 index 0000000000..888966d6c4 --- /dev/null +++ b/gluecodium/src/test/resources/smoke/visibility_attribute/input/KotlinNestedInternalElements.lime @@ -0,0 +1,193 @@ +# Copyright (C) 2016-2026 HERE Europe B.V. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# License-Filename: LICENSE + +package smoke + +############################################################################################# +# The test cases in this file are used to check if elements nested in any internal type are # +# explicitly annotated as internal in Kotlin. # +############################################################################################# + +// This is a class, which contains multiple nested elements. +// It has internal visibility because 'Internal' is used. +// Each element inside should be treated as internal. +@Skip(Dart, Java, Swift) +@Internal +class InternalClassWithNestedElements { + // This is a constant nested in internal class. + // It should be generated as internal and synthetic. + const SOME_CONSTANT: Int = 2026 + + // This is a constructor in internal class. It should be explicitly annotated as internal. + // Unfortunately, it cannot use synthetic, because constructor is not allowed target. + constructor some_constructor(x: Int, y: Int) + + // This is a function in internal class. It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + fun some_function(): Double + + // This is a static function in internal class. It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + static fun some_static_function(): String + + // This is a property in internal class. It should be explicitly annotated as internal. + // And use synthetic for get/set functions to hide them from Java. + property some_property: Long + + // This is a static property in internal class. + // It is represented as static get/set functions pair. + // They should be explicitly annotated as internal and use JvmStatic to hide them from Java. + static property some_static_property: Long + + // This is a class nested inside internal class. + // It should be generated with explicit 'internal' keyword. + // Each element nested inside this class should also have explicit internal visibility. + class NestedClassLevelOne { + // This is a constructor of class nested in internal class. + // It should be explicitly annotated as internal. + // Unfortunately, it cannot use synthetic, because constructor is not allowed target. + constructor some_nested_constructor(x: Int, y: Int) + + // This is a function in class nested inside internal class. + // It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + fun some_nested_function(): Double + + // This is a static function in class nested in internal class. + // It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + static fun some_nested_static_function(): String + + // This is a property in class nested in internal class. + // It should be explicitly annotated as internal. + // And use synthetic for get/set functions to hide them from Java. + property some_nested_property: Long + + // This is a static property in class nested in internal class. + // It is represented as static get/set functions pair. + // They should be explicitly annotated as internal and use JvmStatic to hide them from Java. + static property some_nested_static_property: Long + + // This is a class nested inside class, that is nested in internal class. + // It should be generated with explicit 'internal' keyword. + // Each element nested inside this class should also have explicit internal visibility. + class NestedClassLevelTwo { + // This is a constructor of class, that is nested in class, that is nested in internal class. + // It should be explicitly annotated as internal. + // Unfortunately, it cannot use synthetic, because constructor is not allowed target. + constructor double_nested_constructor(x: Int, y: Int) + + // This is a function in class, that is nested in class, that is nested in internal class. + // It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + fun double_nested_function(): Double + + // This is a static function in class, that is nested in class, that is nested in internal class. + // It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + static fun double_nested_static_function(): String + + // This is a property in class, that is nested in class, that is nested in internal class. + // It should be explicitly annotated as internal. + // And use synthetic for get/set functions to hide them from Java. + property double_nested_property: Long + + // This is a static property in class, that is nested in class, that is nested in internal class. + // It is represented as static get/set functions pair. + // They should be explicitly annotated as internal and use JvmStatic to hide them from Java. + static property double_nested_static_property: Long + } + } + + // This is an enumeration nested in internal class. + // It should be annotated as internal. + // Its value field should be synthetic to disallow accessing it from Java. + enum NestedEnum { + OPTION_1, + OPTION_2 + } + + // This is an exception nested in internal class. + // It should be annotated as internal. + // Its error field should be internal and synthetic to disallow accessing it from Java. + exception NestedException(NestedEnum) + + // This is a lambda nested in internal class. + // It should be annotated as internal. + // Its 'call()' function should be synthetic to disallow accessing it from Java. + lambda NestedLambda = () -> Void + + // This is a structure nested in internal class. + // It should be annotated as internal. + // Its fields should be internal and synthetic. + // Its functions should be internal and synthetic. + // Its constructors should be internal (sadly, they cannot be synthetic). + struct NestedStruct { + // This is a field of structure, which is nested in internal class. + // It should use 'internal' and synthetic. + firstField: Int + + // This is a field of structure, which is nested in internal class. + // It should use 'internal' and synthetic. + secondField: String + + // This is a field constructor of structure. The structure is nested in internal class. + // It should be explicitly internal. Sadly, it cannot be synthetic. + field constructor(firstField, secondField) + + // This is a constructor of structure, and the structure is nested in internal class. + // It should be explicitly annotated as internal. + // Unfortunately, it cannot use synthetic, because constructor is not allowed target. + constructor constructor_of_struct(x: Int, y: Int) + + // This is a function in structure nested inside internal class. + // It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + fun nested_struct_function(): Double + + // This is a static function in structure nested in internal class. + // It should be explicitly annotated as internal. + // And use synthetic annotation to hide it from Java. + static fun nested_struct_static_function(): String + } + + // This is an interface nested in internal class. + // It should be annotated as internal. + // Its fields should be synthetic --> sadly, Kotlin does not allow 'internal' keyword in interfaces. + // But from Kotlin language POV elements are not accessible, because interface itself is internal. + // The elements should not be accessible in Java because of synthetic attribute. + interface NestedInterface { + // This is a function in interface nested inside internal class. + // It must use synthetic annotation. + // Sadly, it cannot use 'internal' keyword. + fun nested_interface_function(): Double + + // This is a static function in interface nested in internal class. + // Sadly, it cannot use 'internal' keyword. + static fun nested_interface_static_function(): String + + // This is a property in interface nested in internal class. + // It must use synthetic annotation for get/set functions. + // Sadly, it cannot use 'internal' keyword. + property nested_interface_property: Long + + // This is a static property in class nested in internal class. + // It must use synthetic annotation for get/set functions. + // Sadly, it cannot use 'internal' keyword. + static property nested_interface_static_property: Long + } +} diff --git a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClass.kt b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClass.kt index d63db72d91..b721a65240 100644 --- a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClass.kt +++ b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClass.kt @@ -5,6 +5,7 @@ @file:JvmName("InternalClassExtensions") + package com.example.smoke import com.example.NativeBase @@ -26,7 +27,7 @@ internal class InternalClass : NativeBase { - external fun fooBar() : Unit + @JvmSynthetic @JvmName("fooBar") internal external fun fooBar() : Unit diff --git a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClassInherits.kt b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClassInherits.kt index 01dffd47a4..57d574b415 100644 --- a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClassInherits.kt +++ b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClassInherits.kt @@ -5,6 +5,7 @@ @file:JvmName("InternalClassInheritsExtensions") + package com.example.smoke import com.example.NativeBase @@ -28,10 +29,10 @@ internal class InternalClassInherits : NativeBase, InternalInterfaceParent { - override external fun fooBar() : Unit + @JvmSynthetic override external fun fooBar() : Unit override var prop: String - external get - external set + @JvmSynthetic external get + @JvmSynthetic external set diff --git a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClassWithFunctions.kt b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClassWithFunctions.kt index d36ae91fe9..5d54f76899 100644 --- a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClassWithFunctions.kt +++ b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClassWithFunctions.kt @@ -15,12 +15,12 @@ internal class InternalClassWithFunctions : NativeBase { - constructor() : this(make(), null as Any?) { + internal constructor() : this(make(), null as Any?) { cacheThisInstance(); } - constructor(foo: String) : this(make(foo), null as Any?) { + internal constructor(foo: String) : this(make(foo), null as Any?) { cacheThisInstance(); } @@ -38,7 +38,7 @@ internal class InternalClassWithFunctions : NativeBase { - external fun fooBar() : Unit + @JvmSynthetic @JvmName("fooBar") internal external fun fooBar() : Unit @@ -46,10 +46,9 @@ internal class InternalClassWithFunctions : NativeBase { companion object { @JvmStatic private external fun disposeNativeHandle(nativeHandle: Long) - @JvmStatic private external fun make() : Long + @JvmStatic @JvmSynthetic @JvmName("make") private external fun make() : Long - @JvmStatic private external fun make(foo: String) : Long + @JvmStatic @JvmSynthetic @JvmName("make") private external fun make(foo: String) : Long } } - diff --git a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClassWithNestedElements.kt b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClassWithNestedElements.kt new file mode 100644 index 0000000000..7b5dd64718 --- /dev/null +++ b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalClassWithNestedElements.kt @@ -0,0 +1,513 @@ +/* + + * + */ + +@file:JvmName("InternalClassWithNestedElementsExtensions") + + +package com.example.smoke + +import com.example.NativeBase + +/** + * This is a class, which contains multiple nested elements. + * It has internal visibility because 'Internal' is used. + * Each element inside should be treated as internal. + */ +internal class InternalClassWithNestedElements : NativeBase { + + /** + * This is an enumeration nested in internal class. + * It should be annotated as internal. + * Its value field should be synthetic to disallow accessing it from Java. + */ + internal enum class NestedEnum(@JvmField @JvmSynthetic internal val value: Int) { + OPTION_1(0), + OPTION_2(1); + } + /** + * This is an exception nested in internal class. + * It should be annotated as internal. + * Its error field should be internal and synthetic to disallow accessing it from Java. + */ + internal class NestedExceptionException(@JvmSynthetic @JvmField val error: InternalClassWithNestedElements.NestedEnum) : Exception(error.toString()) + + + /** + * This is a structure nested in internal class. + * It should be annotated as internal. + * Its fields should be internal and synthetic. + * Its functions should be internal and synthetic. + * Its constructors should be internal (sadly, they cannot be synthetic). + */ + internal class NestedStruct { + /** + * This is a field of structure, which is nested in internal class. + * It should use 'internal' and synthetic. + */ + @JvmField @JvmSynthetic internal var firstField: Int + /** + * This is a field of structure, which is nested in internal class. + * It should use 'internal' and synthetic. + */ + @JvmField @JvmSynthetic internal var secondField: String + + + /** + * This is a constructor of structure, and the structure is nested in internal class. + * It should be explicitly annotated as internal. + * Unfortunately, it cannot use synthetic, because constructor is not allowed target. + * @param x + * @param y + */ + + + internal constructor(x: Int, y: Int) { + val _other = constructorOfStruct(x, y) + this.firstField = _other.firstField + this.secondField = _other.secondField + } + + /** + * This is a field constructor of structure. The structure is nested in internal class. + * It should be explicitly internal. Sadly, it cannot be synthetic. + * @param firstField This is a field of structure, which is nested in internal class. + * It should use 'internal' and synthetic. + * @param secondField This is a field of structure, which is nested in internal class. + * It should use 'internal' and synthetic. + */ + + internal constructor(firstField: Int, secondField: String) { + this.firstField = firstField + this.secondField = secondField + } + + + + /** + * This is a function in structure nested inside internal class. + * It should be explicitly annotated as internal. + * And use synthetic annotation to hide it from Java. + * @return + */ + + @JvmSynthetic @JvmName("nestedStructFunction") internal external fun nestedStructFunction() : Double + + + companion object { + + @JvmStatic @JvmSynthetic @JvmName("constructorOfStruct") private external fun constructorOfStruct(x: Int, y: Int) : NestedStruct + /** + * This is a static function in structure nested in internal class. + * It should be explicitly annotated as internal. + * And use synthetic annotation to hide it from Java. + * @return + */ + + @JvmStatic @JvmSynthetic @JvmName("nestedStructStaticFunction") internal external fun nestedStructStaticFunction() : String + } + } + + /** + * This is a class nested inside internal class. + * It should be generated with explicit 'internal' keyword. + * Each element nested inside this class should also have explicit internal visibility. + */ + internal class NestedClassLevelOne : NativeBase { + + /** + * This is a class nested inside class, that is nested in internal class. + * It should be generated with explicit 'internal' keyword. + * Each element nested inside this class should also have explicit internal visibility. + */ + internal class NestedClassLevelTwo : NativeBase { + + + /** + * This is a constructor of class, that is nested in class, that is nested in internal class. + * It should be explicitly annotated as internal. + * Unfortunately, it cannot use synthetic, because constructor is not allowed target. + * @param x + * @param y + */ + + internal constructor(x: Int, y: Int) : this(doubleNestedConstructor(x, y), null as Any?) { + cacheThisInstance(); + } + + /** + * For internal use only. + * @suppress + * @param nativeHandle The handle to resources on C++ side. + * @param tag Tag used by callers to avoid overload resolution problems. + */ + protected constructor(nativeHandle: Long, @Suppress("UNUSED_PARAMETER") tag: Any?) + : super(nativeHandle, { disposeNativeHandle(it) }) {} + + private external fun cacheThisInstance() + + + /** + * This is a function in class, that is nested in class, that is nested in internal class. + * It should be explicitly annotated as internal. + * And use synthetic annotation to hide it from Java. + * @return + */ + + @JvmSynthetic @JvmName("doubleNestedFunction") internal external fun doubleNestedFunction() : Double + + /** + * This is a property in class, that is nested in class, that is nested in internal class. + * It should be explicitly annotated as internal. + * And use synthetic for get/set functions to hide them from Java. + */ + internal var doubleNestedProperty: Long + @JvmSynthetic @JvmName("getDoubleNestedProperty") external get + @JvmSynthetic @JvmName("setDoubleNestedProperty") external set + + + + + companion object { + @JvmStatic private external fun disposeNativeHandle(nativeHandle: Long) + + @JvmStatic @JvmSynthetic @JvmName("doubleNestedConstructor") private external fun doubleNestedConstructor(x: Int, y: Int) : Long + /** + * This is a static function in class, that is nested in class, that is nested in internal class. + * It should be explicitly annotated as internal. + * And use synthetic annotation to hide it from Java. + * @return + */ + + @JvmStatic @JvmSynthetic @JvmName("doubleNestedStaticFunction") internal external fun doubleNestedStaticFunction() : String + /** + * + * @return This is a static property in class, that is nested in class, that is nested in internal class. + * It is represented as static get/set functions pair. + * They should be explicitly annotated as internal and use JvmStatic to hide them from Java. + */ + + @JvmStatic @JvmSynthetic @JvmName("getDoubleNestedStaticProperty") internal external fun getDoubleNestedStaticProperty() : Long/** + * + * @param value This is a static property in class, that is nested in class, that is nested in internal class. + * It is represented as static get/set functions pair. + * They should be explicitly annotated as internal and use JvmStatic to hide them from Java. + */ + + @JvmStatic @JvmSynthetic @JvmName("setDoubleNestedStaticProperty") internal external fun setDoubleNestedStaticProperty(value: Long) : Unit + } + } + + + /** + * This is a constructor of class nested in internal class. + * It should be explicitly annotated as internal. + * Unfortunately, it cannot use synthetic, because constructor is not allowed target. + * @param x + * @param y + */ + + internal constructor(x: Int, y: Int) : this(someNestedConstructor(x, y), null as Any?) { + cacheThisInstance(); + } + + /** + * For internal use only. + * @suppress + * @param nativeHandle The handle to resources on C++ side. + * @param tag Tag used by callers to avoid overload resolution problems. + */ + protected constructor(nativeHandle: Long, @Suppress("UNUSED_PARAMETER") tag: Any?) + : super(nativeHandle, { disposeNativeHandle(it) }) {} + + private external fun cacheThisInstance() + + + /** + * This is a function in class nested inside internal class. + * It should be explicitly annotated as internal. + * And use synthetic annotation to hide it from Java. + * @return + */ + + @JvmSynthetic @JvmName("someNestedFunction") internal external fun someNestedFunction() : Double + + /** + * This is a property in class nested in internal class. + * It should be explicitly annotated as internal. + * And use synthetic for get/set functions to hide them from Java. + */ + internal var someNestedProperty: Long + @JvmSynthetic @JvmName("getSomeNestedProperty") external get + @JvmSynthetic @JvmName("setSomeNestedProperty") external set + + + + + companion object { + @JvmStatic private external fun disposeNativeHandle(nativeHandle: Long) + + @JvmStatic @JvmSynthetic @JvmName("someNestedConstructor") private external fun someNestedConstructor(x: Int, y: Int) : Long + /** + * This is a static function in class nested in internal class. + * It should be explicitly annotated as internal. + * And use synthetic annotation to hide it from Java. + * @return + */ + + @JvmStatic @JvmSynthetic @JvmName("someNestedStaticFunction") internal external fun someNestedStaticFunction() : String + /** + * + * @return This is a static property in class nested in internal class. + * It is represented as static get/set functions pair. + * They should be explicitly annotated as internal and use JvmStatic to hide them from Java. + */ + + @JvmStatic @JvmSynthetic @JvmName("getSomeNestedStaticProperty") internal external fun getSomeNestedStaticProperty() : Long/** + * + * @param value This is a static property in class nested in internal class. + * It is represented as static get/set functions pair. + * They should be explicitly annotated as internal and use JvmStatic to hide them from Java. + */ + + @JvmStatic @JvmSynthetic @JvmName("setSomeNestedStaticProperty") internal external fun setSomeNestedStaticProperty(value: Long) : Unit + } + } + + /** + * This is an interface nested in internal class. + * It should be annotated as internal. + * Its fields should be synthetic --> sadly, Kotlin does not allow 'internal' keyword in interfaces. + * But from Kotlin language POV elements are not accessible, because interface itself is internal. + * The elements should not be accessible in Java because of synthetic attribute. + */ + internal interface NestedInterface { + + /** + * This is a function in interface nested inside internal class. + * It must use synthetic annotation. + * Sadly, it cannot use 'internal' keyword. + * @return + */ + + @JvmSynthetic fun nestedInterfaceFunction() : Double + + /** + * This is a property in interface nested in internal class. + * It must use synthetic annotation for get/set functions. + * Sadly, it cannot use 'internal' keyword. + */ + var nestedInterfaceProperty: Long + @JvmSynthetic get + @JvmSynthetic set + + + companion object { + /** + * This is a static function in interface nested in internal class. + * Sadly, it cannot use 'internal' keyword. + * @return + */ + + @JvmStatic @JvmSynthetic fun nestedInterfaceStaticFunction() : String { + return NestedInterfaceImpl.nestedInterfaceStaticFunction() + } + + /** + * + * @return This is a static property in class nested in internal class. + * It must use synthetic annotation for get/set functions. + * Sadly, it cannot use 'internal' keyword. + */ + + @JvmStatic @JvmSynthetic fun getNestedInterfaceStaticProperty() : Long { + return NestedInterfaceImpl.getNestedInterfaceStaticProperty() + } + + /** + * + * @param value This is a static property in class nested in internal class. + * It must use synthetic annotation for get/set functions. + * Sadly, it cannot use 'internal' keyword. + */ + + @JvmStatic @JvmSynthetic fun setNestedInterfaceStaticProperty(value: Long) : Unit { + NestedInterfaceImpl.setNestedInterfaceStaticProperty(value) + } + + } + } + + /** + * @suppress + * + * This class is used to represent C++ implementations of the interface or lambda in Kotlin. + * It is instantiated by JNI and should not be used by the end users. + */ + private class NestedInterfaceImpl : NativeBase, NestedInterface { + protected constructor(nativeHandle: Long, @Suppress("UNUSED_PARAMETER") tag: Any?) + : super(nativeHandle, { disposeNativeHandle(it) }) {} + + /** + * This is a function in interface nested inside internal class. + * It must use synthetic annotation. + * Sadly, it cannot use 'internal' keyword. + * @return + */ + + @JvmSynthetic override external fun nestedInterfaceFunction() : Double + + /** + * This is a property in interface nested in internal class. + * It must use synthetic annotation for get/set functions. + * Sadly, it cannot use 'internal' keyword. + */ + override var nestedInterfaceProperty: Long + @JvmSynthetic external get + @JvmSynthetic external set + + + + companion object { + @JvmStatic private external fun disposeNativeHandle(nativeHandle: Long) + /** + * This is a static function in interface nested in internal class. + * Sadly, it cannot use 'internal' keyword. + * @return + */ + + @JvmStatic @JvmSynthetic external fun nestedInterfaceStaticFunction() : String + /** + * + * @return This is a static property in class nested in internal class. + * It must use synthetic annotation for get/set functions. + * Sadly, it cannot use 'internal' keyword. + */ + + @JvmStatic @JvmSynthetic @JvmName("getNestedInterfaceStaticProperty") internal external fun getNestedInterfaceStaticProperty() : Long/** + * + * @param value This is a static property in class nested in internal class. + * It must use synthetic annotation for get/set functions. + * Sadly, it cannot use 'internal' keyword. + */ + + @JvmStatic @JvmSynthetic @JvmName("setNestedInterfaceStaticProperty") internal external fun setNestedInterfaceStaticProperty(value: Long) : Unit + } + } + /** + * This is a lambda nested in internal class. + * It should be annotated as internal. + * Its 'call()' function should be synthetic to disallow accessing it from Java. + */ + internal fun interface NestedLambda { + /** + * This is a lambda nested in internal class. + * It should be annotated as internal. + * Its 'call()' function should be synthetic to disallow accessing it from Java. + */ + + @JvmSynthetic fun apply() : Unit + } + + /** + * @suppress + * + * This class is used to represent C++ implementations of the interface or lambda in Kotlin. + * It is instantiated by JNI and should not be used by the end users. + */ + private class NestedLambdaImpl : NativeBase, NestedLambda { + protected constructor(nativeHandle: Long, @Suppress("UNUSED_PARAMETER") tag: Any?) + : super(nativeHandle, { disposeNativeHandle(it) }) {} + + /** + * This is a lambda nested in internal class. + * It should be annotated as internal. + * Its 'call()' function should be synthetic to disallow accessing it from Java. + */ + + @JvmSynthetic override external fun apply() : Unit + + + + companion object { + @JvmStatic private external fun disposeNativeHandle(nativeHandle: Long) + } + } + + /** + * This is a constructor in internal class. It should be explicitly annotated as internal. + * Unfortunately, it cannot use synthetic, because constructor is not allowed target. + * @param x + * @param y + */ + + internal constructor(x: Int, y: Int) : this(someConstructor(x, y), null as Any?) { + cacheThisInstance(); + } + + /** + * For internal use only. + * @suppress + * @param nativeHandle The handle to resources on C++ side. + * @param tag Tag used by callers to avoid overload resolution problems. + */ + protected constructor(nativeHandle: Long, @Suppress("UNUSED_PARAMETER") tag: Any?) + : super(nativeHandle, { disposeNativeHandle(it) }) {} + + private external fun cacheThisInstance() + + + /** + * This is a function in internal class. It should be explicitly annotated as internal. + * And use synthetic annotation to hide it from Java. + * @return + */ + + @JvmSynthetic @JvmName("someFunction") internal external fun someFunction() : Double + + /** + * This is a property in internal class. It should be explicitly annotated as internal. + * And use synthetic for get/set functions to hide them from Java. + */ + internal var someProperty: Long + @JvmSynthetic @JvmName("getSomeProperty") external get + @JvmSynthetic @JvmName("setSomeProperty") external set + + + + + companion object { + /** + * This is a constant nested in internal class. + * It should be generated as internal and synthetic. + */ + @JvmSynthetic internal @JvmField final val SOME_CONSTANT: Int = 2026 + @JvmStatic private external fun disposeNativeHandle(nativeHandle: Long) + + @JvmStatic @JvmSynthetic @JvmName("someConstructor") private external fun someConstructor(x: Int, y: Int) : Long + /** + * This is a static function in internal class. It should be explicitly annotated as internal. + * And use synthetic annotation to hide it from Java. + * @return + */ + + @JvmStatic @JvmSynthetic @JvmName("someStaticFunction") internal external fun someStaticFunction() : String + /** + * + * @return This is a static property in internal class. + * It is represented as static get/set functions pair. + * They should be explicitly annotated as internal and use JvmStatic to hide them from Java. + */ + + @JvmStatic @JvmSynthetic @JvmName("getSomeStaticProperty") internal external fun getSomeStaticProperty() : Long/** + * + * @param value This is a static property in internal class. + * It is represented as static get/set functions pair. + * They should be explicitly annotated as internal and use JvmStatic to hide them from Java. + */ + + @JvmStatic @JvmSynthetic @JvmName("setSomeStaticProperty") internal external fun setSomeStaticProperty(value: Long) : Unit + } +} + diff --git a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalInterface.kt b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalInterface.kt index 0dfb799d10..ad0b6eeae9 100644 --- a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalInterface.kt +++ b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalInterface.kt @@ -14,19 +14,19 @@ internal fun interface InternalInterface { - fun fooBar() : Unit + @JvmSynthetic fun fooBar() : Unit companion object { - @JvmStatic fun getSomePropertyOfInternalInterface() : String { + @JvmStatic @JvmSynthetic fun getSomePropertyOfInternalInterface() : String { return InternalInterfaceImpl.getSomePropertyOfInternalInterface() } - @JvmStatic fun setSomePropertyOfInternalInterface(value: String) : Unit { + @JvmStatic @JvmSynthetic fun setSomePropertyOfInternalInterface(value: String) : Unit { InternalInterfaceImpl.setSomePropertyOfInternalInterface(value) } @@ -45,7 +45,7 @@ private class InternalInterfaceImpl : NativeBase, InternalInterface { - override external fun fooBar() : Unit + @JvmSynthetic override external fun fooBar() : Unit @@ -53,8 +53,8 @@ private class InternalInterfaceImpl : NativeBase, InternalInterface { @JvmStatic private external fun disposeNativeHandle(nativeHandle: Long) - @JvmStatic external fun getSomePropertyOfInternalInterface() : String + @JvmStatic @JvmSynthetic @JvmName("getSomePropertyOfInternalInterface") internal external fun getSomePropertyOfInternalInterface() : String - @JvmStatic external fun setSomePropertyOfInternalInterface(value: String) : Unit + @JvmStatic @JvmSynthetic @JvmName("setSomePropertyOfInternalInterface") internal external fun setSomePropertyOfInternalInterface(value: String) : Unit } } diff --git a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalInterfaceParent.kt b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalInterfaceParent.kt index 14a95b677f..02fb61bf84 100644 --- a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalInterfaceParent.kt +++ b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalInterfaceParent.kt @@ -14,11 +14,11 @@ internal interface InternalInterfaceParent { - fun fooBar() : Unit + @JvmSynthetic fun fooBar() : Unit var prop: String - get - set + @JvmSynthetic get + @JvmSynthetic set } @@ -35,11 +35,11 @@ private class InternalInterfaceParentImpl : NativeBase, InternalInterfaceParent - override external fun fooBar() : Unit + @JvmSynthetic override external fun fooBar() : Unit override var prop: String - external get - external set + @JvmSynthetic external get + @JvmSynthetic external set diff --git a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalLambda.kt b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalLambda.kt index 44c274d169..b641296ab8 100644 --- a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalLambda.kt +++ b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/InternalLambda.kt @@ -13,7 +13,7 @@ import com.example.NativeBase internal fun interface InternalLambda { - fun apply() : Unit + @JvmSynthetic fun apply() : Unit } /** @@ -28,7 +28,7 @@ private class InternalLambdaImpl : NativeBase, InternalLambda { - override external fun apply() : Unit + @JvmSynthetic override external fun apply() : Unit diff --git a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/PublicClass.kt b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/PublicClass.kt index ee77a3ec7f..a91d294a6e 100644 --- a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/PublicClass.kt +++ b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/PublicClass.kt @@ -17,7 +17,7 @@ class PublicClass : NativeBase { BAR(1); } internal class InternalStruct { - @JvmField var stringField: String + @JvmField @JvmSynthetic internal var stringField: String @@ -92,4 +92,3 @@ class PublicClass : NativeBase { } } - diff --git a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/PublicTypeCollection.kt b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/PublicTypeCollection.kt index ee589c4acb..12a155c20e 100644 --- a/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/PublicTypeCollection.kt +++ b/gluecodium/src/test/resources/smoke/visibility_attribute/output/android-kotlin/com/example/smoke/PublicTypeCollection.kt @@ -5,6 +5,7 @@ @file:JvmName("PublicTypeCollectionExtensions") + package com.example.smoke @@ -23,7 +24,7 @@ class PublicTypeCollection { - external fun fooBar() : Unit + @JvmSynthetic @JvmName("fooBar") internal external fun fooBar() : Unit }