Skip to content

Commit

Permalink
Fix compilation for "overloading over inheritance" (#1405)
Browse files Browse the repository at this point in the history
Fixed varios compilation issues when "overloading over inheritance". For
C++, adding a `using` directive for the parent functions in the child
class. For JNI and CBridge, adding a signature suffix to the C
functions.

For Dart FFI no changes, since it has this logic in place already, due
to overloading being absent from the Dart language as a concept
entirely.

Resolves: #1401
Signed-off-by: Daniel Kamkha <[email protected]>
  • Loading branch information
DanielKamkha authored Jun 29, 2022
1 parent d961133 commit c46acb7
Show file tree
Hide file tree
Showing 17 changed files with 394 additions and 6 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
### Features:
* Added support for declaring `typealias` and `lambda` elements inside a `struct`.
* Restored support for `internal const`.
### Breaking changes:
### Bug fixes:
* Fixed compilation issues in C++, JNI, and CBridge when "overloading over inheritance", i.e. both the child and the
parent types have functions with the same name (but of different signature).
### Removed:
* Support for `@Swift(Extension)` attribute was removed.

## 12.0.0
Expand Down
1 change: 1 addition & 0 deletions functional-tests/functional/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ feature(MethodOverloading cpp android swift dart SOURCES
input/src/cpp/MethodOverloads.cpp

input/lime/MethodOverloads.lime
input/lime/InheritanceOverloads.lime
)

feature(Blob cpp android swift dart SOURCES
Expand Down
55 changes: 55 additions & 0 deletions functional-tests/functional/input/lime/InheritanceOverloads.lime
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Copyright (C) 2016-2022 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

interface ParentInterfaceOverloads {
fun foo()
@Dart("fooInt")
fun foo(input: Int)
fun bar()
fun baz()
}

open class ParentClassOverloads {
fun foo()
@Dart("fooInt")
fun foo(input: Int)
fun bar()
fun baz()
}

interface ChildInterfaceOverloads: ParentInterfaceOverloads {
@Dart("fooString")
fun foo(input: String)
@Dart("barString")
fun bar(input: String)
}

class ChildClassFromInterfaceOverloads: ParentInterfaceOverloads {
@Dart("fooString")
fun foo(input: String)
@Dart("barString")
fun bar(input: String)
}

class ChildClassFromClassOverloads: ParentClassOverloads {
@Dart("fooString")
fun foo(input: String)
@Dart("barString")
fun bar(input: String)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package com.here.gluecodium.generator.cbridge

import com.here.gluecodium.cli.GluecodiumExecutionException
import com.here.gluecodium.generator.common.NameResolver
import com.here.gluecodium.generator.common.PlatformSignatureResolver
import com.here.gluecodium.generator.common.ReferenceMapBasedResolver
import com.here.gluecodium.generator.swift.SwiftNameRules
import com.here.gluecodium.model.lime.LimeAttributeType
Expand All @@ -38,7 +39,6 @@ import com.here.gluecodium.model.lime.LimeNamedElement
import com.here.gluecodium.model.lime.LimeProperty
import com.here.gluecodium.model.lime.LimeReturnType
import com.here.gluecodium.model.lime.LimeSet
import com.here.gluecodium.model.lime.LimeSignatureResolver
import com.here.gluecodium.model.lime.LimeType
import com.here.gluecodium.model.lime.LimeTypeAlias
import com.here.gluecodium.model.lime.LimeTypeRef
Expand All @@ -47,7 +47,7 @@ internal class CBridgeNameResolver(
limeReferenceMap: Map<String, LimeElement>,
private val swiftNameRules: SwiftNameRules,
private val internalPrefix: String,
private val signatureResolver: LimeSignatureResolver
private val signatureResolver: PlatformSignatureResolver
) : ReferenceMapBasedResolver(limeReferenceMap), NameResolver {

override fun resolveName(element: Any): String =
Expand Down Expand Up @@ -85,7 +85,7 @@ internal class CBridgeNameResolver(

private fun getOverloadSuffix(limeFunction: LimeFunction) =
when {
!signatureResolver.isOverloaded(limeFunction) -> emptyList()
!signatureResolver.isOverloadedInBindings(limeFunction) -> emptyList()
limeFunction.parameters.isEmpty() -> listOf("")
else -> signatureResolver.getSignature(limeFunction).map { mangleSignature(it) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ package com.here.gluecodium.generator.common
import com.here.gluecodium.common.LimeModelSkipPredicates
import com.here.gluecodium.model.lime.LimeAttributeType
import com.here.gluecodium.model.lime.LimeAttributeValueType
import com.here.gluecodium.model.lime.LimeClass
import com.here.gluecodium.model.lime.LimeContainer
import com.here.gluecodium.model.lime.LimeContainerWithInheritance
import com.here.gluecodium.model.lime.LimeElement
import com.here.gluecodium.model.lime.LimeFunction
import com.here.gluecodium.model.lime.LimeSignatureResolver
Expand All @@ -41,4 +43,16 @@ internal open class PlatformSignatureResolver(
override fun getFunctionName(limeFunction: LimeFunction) =
limeFunction.attributes.get(platformAttributeType, LimeAttributeValueType.NAME, String::class.java)
?: nameRules.getName(limeFunction)

fun isOverloadedInBindings(limeFunction: LimeFunction): Boolean {
if (isOverloaded(limeFunction)) return true

val container = getContainer(limeFunction) as? LimeContainerWithInheritance ?: return false
val inheritedFunctions =
if (container is LimeClass) container.interfaceInheritedFunctions else container.inheritedFunctions
if (inheritedFunctions.isEmpty()) return false

val functionName = getFunctionName(limeFunction)
return inheritedFunctions.any { getFunctionName(it) == functionName }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ internal class CppGenerator : Generator {

val generatedFiles = filteredModel.topElements.flatMap {
val fileName = nameRules.getOutputFilePath(it)
generateCode(it, fileName, includeResolver, nameResolver, fullNameResolver, allErrorEnums)
generateCode(it, fileName, includeResolver, nameResolver, fullNameResolver, signatureResolver, allErrorEnums)
} + COMMON_HEADERS.map { generateHelperFile(it, "include", ".h") } +
COMMON_IMPLS.map { generateHelperFile(it, "src", ".cpp") } +
generateExportHelperFile(exportCommonName, "Common", GeneratedFile.SourceSet.COMMON) +
Expand All @@ -146,6 +146,7 @@ internal class CppGenerator : Generator {
includeResolver: CppIncludeResolver,
nameResolver: CppNameResolver,
fullNameResolver: CppFullNameResolver,
signatureResolver: CppSignatureResolver,
allErrorEnums: Set<String>
): List<GeneratedFile> {

Expand Down Expand Up @@ -184,6 +185,7 @@ internal class CppGenerator : Generator {
if (needsHeader) {
val headerIncludesCollector = CppHeaderIncludesCollector(includeResolver, allErrorEnums)
val headerIncludes = headerIncludesCollector.collectImports(rootElement) + exportInclude
templateData["functionUsings"] = collectFunctionUsings(rootElement, signatureResolver)
result += generateHeader(rootElement, nameResolvers, fileName, templateData, headerIncludes)
}
if (needsImplementation) {
Expand All @@ -196,6 +198,15 @@ internal class CppGenerator : Generator {
return result
}

private fun collectFunctionUsings(rootElement: LimeNamedElement, signatureResolver: CppSignatureResolver) =
LimeTypeHelper.getAllTypes(rootElement)
.filterIsInstance<LimeContainerWithInheritance>()
.filter { it.parents.isNotEmpty() }
.associateBy({ it.fullName }, { getFunctionUsing(it, signatureResolver) })

private fun getFunctionUsing(limeContainer: LimeContainerWithInheritance, signatureResolver: CppSignatureResolver) =
limeContainer.functions.mapNotNull { signatureResolver.getInheritedOverloads(it).firstOrNull() }

private fun generateImplementation(
rootElement: LimeNamedElement,
nameResolvers: Map<String, NameResolver>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import com.here.gluecodium.generator.common.PlatformSignatureResolver
import com.here.gluecodium.model.lime.LimeAttributeType
import com.here.gluecodium.model.lime.LimeContainerWithInheritance
import com.here.gluecodium.model.lime.LimeElement
import com.here.gluecodium.model.lime.LimeFunction
import com.here.gluecodium.model.lime.LimeTypeRef

internal class CppSignatureResolver(
Expand All @@ -36,4 +37,10 @@ internal class CppSignatureResolver(
limeTypeRef.type.actualType is LimeContainerWithInheritance -> ""
else -> "?"
}

fun getInheritedOverloads(limeFunction: LimeFunction): List<LimeFunction> {
val container = getContainer(limeFunction) as? LimeContainerWithInheritance ?: return emptyList()
val functionName = getFunctionName(limeFunction)
return container.inheritedFunctions.filter { !it.isStatic }.filter { getFunctionName(it) == functionName }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ internal class JniGeneratorPredicates(
return typeId.isNumericType || typeId == VOID || typeId == BOOLEAN
},
"isOverloaded" to { limeFunction: Any ->
limeFunction is LimeFunction && javaSignatureResolver.isOverloaded(limeFunction)
limeFunction is LimeFunction && javaSignatureResolver.isOverloadedInBindings(limeFunction)
},
"needsOrdinalConversion" to fun(limeEnumeration: Any): Boolean {
if (limeEnumeration !is LimeEnumeration) return false
Expand Down
6 changes: 6 additions & 0 deletions gluecodium/src/main/resources/templates/cpp/CppClass.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,13 @@ public:
{{#properties}}
{{prefixPartial "cpp/CppProperty" " "}}
{{/properties}}
{{#eval "functionUsings" fullName}}{{#if this}}

{{#this}}
using {{resolveName "FQN"}};
{{/this}}
{{/if}}
{{/eval}}
{{/if}}
{{#if attributes.equatable}}
public:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Copyright (C) 2016-2022 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

interface ParentInterface {
fun foo()
fun foo(input: Int)
fun bar()
fun baz()
}

open class ParentClass {
fun foo()
fun foo(input: Int)
fun bar()
fun baz()
}

interface ChildInterfaceOverloads: ParentInterface {
fun foo(input: String)
fun bar(input: String)
}

class ChildClassFromInterfaceOverloads: ParentInterface {
fun foo(input: String)
fun bar(input: String)
}

class ChildClassFromClassOverloads: ParentClass {
fun foo(input: String)
fun bar(input: String)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
*
*/
#pragma once
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL
Java_com_example_smoke_ChildClassFromInterfaceOverloads_foo__Ljava_lang_String_2(JNIEnv* _jenv, jobject _jinstance, jstring jinput);
JNIEXPORT void JNICALL
Java_com_example_smoke_ChildClassFromInterfaceOverloads_bar__Ljava_lang_String_2(JNIEnv* _jenv, jobject _jinstance, jstring jinput);
JNIEXPORT void JNICALL
Java_com_example_smoke_ChildClassFromInterfaceOverloads_foo__(JNIEnv* _jenv, jobject _jinstance);
JNIEXPORT void JNICALL
Java_com_example_smoke_ChildClassFromInterfaceOverloads_foo__I(JNIEnv* _jenv, jobject _jinstance, jint jinput);
JNIEXPORT void JNICALL
Java_com_example_smoke_ChildClassFromInterfaceOverloads_bar(JNIEnv* _jenv, jobject _jinstance);
JNIEXPORT void JNICALL
Java_com_example_smoke_ChildClassFromInterfaceOverloads_baz(JNIEnv* _jenv, jobject _jinstance);
#ifdef __cplusplus
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
*
*/
#pragma once
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL
Java_com_example_smoke_ChildInterfaceOverloadsImpl_foo__Ljava_lang_String_2(JNIEnv* _jenv, jobject _jinstance, jstring jinput);
JNIEXPORT void JNICALL
Java_com_example_smoke_ChildInterfaceOverloadsImpl_bar__Ljava_lang_String_2(JNIEnv* _jenv, jobject _jinstance, jstring jinput);
JNIEXPORT void JNICALL
Java_com_example_smoke_ChildInterfaceOverloadsImpl_foo__(JNIEnv* _jenv, jobject _jinstance);
JNIEXPORT void JNICALL
Java_com_example_smoke_ChildInterfaceOverloadsImpl_foo__I(JNIEnv* _jenv, jobject _jinstance, jint jinput);
JNIEXPORT void JNICALL
Java_com_example_smoke_ChildInterfaceOverloadsImpl_bar(JNIEnv* _jenv, jobject _jinstance);
JNIEXPORT void JNICALL
Java_com_example_smoke_ChildInterfaceOverloadsImpl_baz(JNIEnv* _jenv, jobject _jinstance);
#ifdef __cplusplus
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
//
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "cbridge/include/BaseHandle.h"
#include "cbridge/include/Export.h"
#include <stdint.h>
_GLUECODIUM_C_EXPORT void smoke_ChildClassFromInterfaceOverloads_release_handle(_baseRef handle);
_GLUECODIUM_C_EXPORT _baseRef smoke_ChildClassFromInterfaceOverloads_copy_handle(_baseRef handle);
_GLUECODIUM_C_EXPORT const void* smoke_ChildClassFromInterfaceOverloads_get_swift_object_from_wrapper_cache(_baseRef handle);
_GLUECODIUM_C_EXPORT void smoke_ChildClassFromInterfaceOverloads_cache_swift_object_wrapper(_baseRef handle, const void* swift_pointer);
_GLUECODIUM_C_EXPORT void smoke_ChildClassFromInterfaceOverloads_remove_swift_object_from_wrapper_cache(_baseRef handle);
_GLUECODIUM_C_EXPORT void* smoke_ChildClassFromInterfaceOverloads_get_typed(_baseRef handle);
_GLUECODIUM_C_EXPORT void smoke_ChildClassFromInterfaceOverloads_foo_String(_baseRef _instance, _baseRef input);
_GLUECODIUM_C_EXPORT void smoke_ChildClassFromInterfaceOverloads_bar_String(_baseRef _instance, _baseRef input);
_GLUECODIUM_C_EXPORT void smoke_ChildClassFromInterfaceOverloads_foo_(_baseRef _instance);
_GLUECODIUM_C_EXPORT void smoke_ChildClassFromInterfaceOverloads_foo_Int(_baseRef _instance, int32_t input);
_GLUECODIUM_C_EXPORT void smoke_ChildClassFromInterfaceOverloads_bar(_baseRef _instance);
_GLUECODIUM_C_EXPORT void smoke_ChildClassFromInterfaceOverloads_baz(_baseRef _instance);
#ifdef __cplusplus
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
//
// -------------------------------------------------------------------------------------------------
#pragma once
#include "gluecodium/ExportGluecodiumCpp.h"
#include "smoke/ParentClass.h"
#include <string>
namespace smoke {
class _GLUECODIUM_CPP_EXPORT ChildClassFromClassOverloads: public ::smoke::ParentClass {
public:
ChildClassFromClassOverloads();
virtual ~ChildClassFromClassOverloads() = 0;
public:
virtual void foo( const ::std::string& input ) = 0;
virtual void bar( const ::std::string& input ) = 0;
using ::smoke::ParentClass::foo;
using ::smoke::ParentClass::bar;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
//
// -------------------------------------------------------------------------------------------------
#pragma once
#include "gluecodium/ExportGluecodiumCpp.h"
#include "smoke/ParentInterface.h"
#include <string>
namespace smoke {
class _GLUECODIUM_CPP_EXPORT ChildClassFromInterfaceOverloads: public ::smoke::ParentInterface {
public:
ChildClassFromInterfaceOverloads();
virtual ~ChildClassFromInterfaceOverloads() = 0;
public:
virtual void foo( const ::std::string& input ) = 0;
virtual void bar( const ::std::string& input ) = 0;
using ::smoke::ParentInterface::foo;
using ::smoke::ParentInterface::bar;
};
}
Loading

0 comments on commit c46acb7

Please sign in to comment.