Skip to content

Commit

Permalink
Generate type aliases in Dart
Browse files Browse the repository at this point in the history
Added dedicated DartTypeAlias template, as type aliases (typedefs) are now
supported in Dart language (since Dart version 2.13). Updated other Dart
tempates and resolvers to treat type aliases as a normal type, instead of
skipping it through to the target type.

Added/updated related smoke and functional tests.

Unrelated smoke tests are updated in a separate commit.

Resolves: #907
Signed-off-by: Daniel Kamkha <[email protected]>
  • Loading branch information
DanielKamkha committed Jul 5, 2022
1 parent 861ba70 commit bd7f7e1
Show file tree
Hide file tree
Showing 16 changed files with 139 additions and 40 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/functional-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ jobs:
- name: Install Dart SDK
run: |
DART_RELEASE_CHANNEL=stable
DART_VERSION=2.12.0
DART_VERSION=2.13.3
wget -nv https://storage.googleapis.com/dart-archive/channels/${DART_RELEASE_CHANNEL}/release/${DART_VERSION}/linux_packages/dart_${DART_VERSION}-1_amd64.deb
sudo apt -y install ./dart_${DART_VERSION}-1_amd64.deb
- name: Build and run functional tests
Expand Down Expand Up @@ -363,7 +363,7 @@ jobs:
- name: Install Dart SDK
run: |
DART_RELEASE_CHANNEL=stable
DART_VERSION=2.12.0
DART_VERSION=2.13.3
wget -nv https://storage.googleapis.com/dart-archive/channels/${DART_RELEASE_CHANNEL}/release/${DART_VERSION}/linux_packages/dart_${DART_VERSION}-1_amd64.deb
sudo apt -y install ./dart_${DART_VERSION}-1_amd64.deb
- name: Build and run functional tests
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Gluecodium project Release Notes

## Unreleased
### Features:
* Added support for type aliases (typedefs) in Dart
### Breaking changes:
* Generated Dart code now requires minimum Dart version 2.13.0.

## Unreleased
### Removed:
* Support for `types` declaration was removed.
Expand Down
4 changes: 3 additions & 1 deletion functional-tests/functional/dart/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ import "test/StaticIntMethods_test.dart" as StaticIntMethodsTests;
import "test/StaticStringMethods_test.dart" as StaticStringMethodsTests;
import "test/StructsWithConstants_test.dart" as StructsWithConstantsTests;
import "test/StructsWithMethods_test.dart" as StructsWithMethodsTests;
import "test/TypeAliases_test.dart" as TypeAliasesTests;

final _allTests = [
AsyncTests.main,
Expand Down Expand Up @@ -117,7 +118,8 @@ final _allTests = [
StaticIntMethodsTests.main,
StaticStringMethodsTests.main,
StructsWithConstantsTests.main,
StructsWithMethodsTests.main
StructsWithMethodsTests.main,
TypeAliasesTests.main
];

String _getLibraryPath(String nativeLibraryName) {
Expand Down
2 changes: 1 addition & 1 deletion functional-tests/functional/dart/pubspec.yaml.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: FunctionalDartTests
environment:
sdk: '>=2.12.0 <3.0.0'
sdk: '>=2.13.0 <3.0.0'
dependencies:
test:
functional:
Expand Down
55 changes: 55 additions & 0 deletions functional-tests/functional/dart/test/TypeAliases_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// -------------------------------------------------------------------------------------------------
// Copyright (C) 2016-2021 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
//
// -------------------------------------------------------------------------------------------------

import "package:test/test.dart";
import "package:functional/test.dart";
import "../test_suite.dart";

final _testSuite = TestSuite("Type Aliases");

void main() {
_testSuite.test("Type alias to struct", () {
final result = StaticTypedefExampleStructTypedef("nonsense");

expect(result is StaticTypedefExampleStruct, isTrue);
expect(result.exampleString, "nonsense");
});
_testSuite.test("Type alias used by a function", () {
final result = StaticTypedef.returnIntTypedef(2);

expect(result is int, isTrue);
expect(result, 3);
});
_testSuite.test("Type alias points to a type alias", () {
final result = StaticTypedef.returnNestedIntTypedef(4);

expect(result is int, isTrue);
expect(result, 5);
});
_testSuite.test("Type alias from type collection", () {
final result = StaticTypedef.returnTypedefPointFromTypeCollection(
TypeCollectionPointTypedef(1.0, 3.0)
);

expect(result is TypeCollectionPoint, isTrue);
expect(result.x, 1.0);
expect(result.y, 3.0);
});
}
1 change: 1 addition & 0 deletions functional-tests/functional/input/lime/StaticTypedef.lime
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class StaticTypedef {
// Example struct
struct ExampleStruct {
exampleString: String = ""
field constructor(exampleString)
}
typealias IntTypedef = Int
typealias NestedIntTypedef = IntTypedef
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ internal class DartGenerator : Generator {
injectAsyncHelpers(ffiReferenceMap, asyncHelpers)

val generatedFiles = dartFilteredModel.topElements.flatMap {
listOfNotNull(
listOf(
generateDart(
it, dartResolvers, dartNameResolver, listOf(importsCollector, declarationImportsCollector),
exportsCollector, typeRepositoriesCollector, predicatesMap, descendantInterfaces,
Expand Down Expand Up @@ -214,15 +214,15 @@ internal class DartGenerator : Generator {
predicates: Map<String, (Any) -> Boolean>,
descendantInterfaces: Map<String, List<LimeInterface>>,
asyncHelpers: DartAsyncHelpers.AsyncHelpersGroup?
): GeneratedFile? {
val contentTemplateName = selectTemplate(rootElement) ?: return null
): GeneratedFile {
val contentTemplateName = selectTemplate(rootElement)

val packagePath = rootElement.path.head.joinToString(separator = "/")
val fileName = dartNameResolver.resolveFileName(rootElement)
val filePath = "$packagePath/$fileName"
val relativePath = "$SRC_DIR_SUFFIX/$filePath.dart"

val allTypes = LimeTypeHelper.getAllTypes(rootElement).filterNot { it is LimeTypeAlias }
val allTypes = LimeTypeHelper.getAllTypes(rootElement)
val nonExternalTypes = allTypes.filter { it.external?.dart == null }
val allSymbols = nonExternalTypes.filter { it.visibility.isPublic }
if (allSymbols.isNotEmpty()) {
Expand Down Expand Up @@ -527,7 +527,7 @@ internal class DartGenerator : Generator {
is LimeEnumeration -> "dart/DartEnumeration"
is LimeException -> "dart/DartException"
is LimeLambda -> "dart/DartLambda"
is LimeTypeAlias -> null
is LimeTypeAlias -> "dart/DartTypeAlias"
else -> throw GluecodiumExecutionException(
"Unsupported top-level element: " +
limeElement::class.java.name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,16 @@ internal class DartImportResolver(
}

private fun resolveTypeImports(limeType: LimeType, skipHelpers: Boolean = false): List<DartImport> {
val actualType = limeType.actualType
when (actualType) {
is LimeBasicType -> return resolveBasicTypeImports(actualType)
is LimeGenericType -> return resolveGenericTypeImports(actualType)
when (limeType) {
is LimeBasicType -> return resolveBasicTypeImports(limeType)
is LimeGenericType -> return resolveGenericTypeImports(limeType)
}

val externalImport = resolveExternalImport(actualType, IMPORT_PATH_NAME, useAlias = true)
val externalImport = resolveExternalImport(limeType, IMPORT_PATH_NAME, useAlias = true)
return when {
externalImport == null -> listOf(createImport(actualType))
externalImport == null -> listOf(createImport(limeType))
skipHelpers -> listOf(externalImport)
else -> listOf(createImport(actualType), externalImport)
else -> listOf(createImport(limeType), externalImport)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ internal class DartImportsCollector(importsResolver: ImportsResolver<DartImport>
importsResolver,
collectTypeRefImports = true,
collectValueImports = true,
parentTypeFilter = { true }
parentTypeFilter = { true },
collectTypeAliasImports = true
) {

override fun collectParentTypeRefs(limeContainer: LimeContainerWithInheritance) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ import com.here.gluecodium.model.lime.LimeReturnType
import com.here.gluecodium.model.lime.LimeSet
import com.here.gluecodium.model.lime.LimeStruct
import com.here.gluecodium.model.lime.LimeType
import com.here.gluecodium.model.lime.LimeTypeAlias
import com.here.gluecodium.model.lime.LimeTypeHelper
import com.here.gluecodium.model.lime.LimeTypeRef
import com.here.gluecodium.model.lime.LimeValue
Expand Down Expand Up @@ -85,7 +84,6 @@ internal class DartNameResolver(
is LimeValue -> resolveValue(element)
is LimeGenericType -> resolveGenericType(element)
is LimeTypeRef -> resolveTypeRefName(element)
is LimeTypeAlias -> resolveName(element.typeRef)
is LimeType -> resolveTypeName(element)
is LimeNamedElement -> getPlatformName(element)
else ->
Expand Down Expand Up @@ -269,11 +267,11 @@ internal class DartNameResolver(

private fun resolveTypeRefName(limeTypeRef: LimeTypeRef, ignoreDuplicates: Boolean = false): String {
val typeName = resolveName(limeTypeRef.type)
val importPath = limeTypeRef.type.actualType.external?.dart?.get(IMPORT_PATH_NAME)
val importPath = limeTypeRef.type.external?.dart?.get(IMPORT_PATH_NAME)
val alias = when {
importPath != null -> computeAlias(importPath)
ignoreDuplicates -> null
duplicateNames.contains(typeName) -> limeTypeRef.type.actualType.path.head.joinToString("_")
duplicateNames.contains(typeName) -> limeTypeRef.type.path.head.joinToString("_")
else -> null
}
val suffix = if (limeTypeRef.isNullable) "?" else ""
Expand Down Expand Up @@ -311,7 +309,7 @@ internal class DartNameResolver(
private fun buildDuplicateNames() =
limeReferenceMap.values
.filterIsInstance<LimeType>()
.filterNot { it is LimeTypeAlias || it is LimeGenericType || it is LimeBasicType }
.filterNot { it is LimeGenericType || it is LimeBasicType }
.filter { it.external?.dart == null }
.groupBy { resolveTypeName(it) }
.filterValues { it.size > 1 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ abstract class {{resolveName}}{{!!
{{/ifPredicate}}
}

{{#typeAliases}}
{{>dart/DartTypeAlias}}
{{/typeAliases}}
{{#enumerations}}
{{>dart/DartEnumeration}}
{{/enumerations}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ abstract class {{resolveName}}{{!!
{{/ifPredicate}}
}

{{#typeAliases}}
{{>dart/DartTypeAlias}}
{{/typeAliases}}
{{#enumerations}}
{{>dart/DartEnumeration}}
{{/enumerations}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
!}}
name: {{libraryName}}
environment:
sdk: '>=2.12.0 <3.0.0'
sdk: '>=2.13.0 <3.0.0'
dependencies:
ffi:
intl:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ class {{resolveName}}{{#if external.dart.converter}}Internal{{/if}} {
}
{{/unlessPredicate}}

{{#typeAliases}}
{{>dart/DartTypeAlias}}
{{/typeAliases}}
{{#enumerations}}
{{>dart/DartEnumeration}}
{{/enumerations}}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{{!!
!
! Copyright (C) 2016-2021 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
!
!}}
{{>dart/DartDocumentation}}{{>dart/DartAttributes}}
typedef {{resolveName visibility}}{{resolveName}} = {{resolveName typeRef}};
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,26 @@ import 'package:library/src/generic_types__conversion.dart';
import 'package:library/src/smoke/type_collection.dart';
import 'package:meta/meta.dart';
abstract class TypeDefs {
static double methodWithPrimitiveTypeDef(double input) => $prototype.methodWithPrimitiveTypeDef(input);
static List<TypeDefs_TestStruct> methodWithComplexTypeDef(List<TypeDefs_TestStruct> input) => $prototype.methodWithComplexTypeDef(input);
static double returnNestedIntTypeDef(double input) => $prototype.returnNestedIntTypeDef(input);
static TypeDefs_TestStruct returnTestStructTypeDef(TypeDefs_TestStruct input) => $prototype.returnTestStructTypeDef(input);
static TypeDefs_TestStruct returnNestedStructTypeDef(TypeDefs_TestStruct input) => $prototype.returnNestedStructTypeDef(input);
static TypeCollection_Point returnTypeDefPointFromTypeCollection(TypeCollection_Point input) => $prototype.returnTypeDefPointFromTypeCollection(input);
List<double> get primitiveTypeProperty;
set primitiveTypeProperty(List<double> value);
static TypeDefs_PrimitiveTypeDef methodWithPrimitiveTypeDef(TypeDefs_PrimitiveTypeDef input) => $prototype.methodWithPrimitiveTypeDef(input);
static TypeDefs_ComplexTypeDef methodWithComplexTypeDef(TypeDefs_ComplexTypeDef input) => $prototype.methodWithComplexTypeDef(input);
static TypeDefs_NestedIntTypeDef returnNestedIntTypeDef(TypeDefs_NestedIntTypeDef input) => $prototype.returnNestedIntTypeDef(input);
static TypeDefs_TestStructTypeDef returnTestStructTypeDef(TypeDefs_TestStructTypeDef input) => $prototype.returnTestStructTypeDef(input);
static TypeDefs_NestedStructTypeDef returnNestedStructTypeDef(TypeDefs_NestedStructTypeDef input) => $prototype.returnNestedStructTypeDef(input);
static PointTypeDef returnTypeDefPointFromTypeCollection(PointTypeDef input) => $prototype.returnTypeDefPointFromTypeCollection(input);
List<TypeDefs_PrimitiveTypeDef> get primitiveTypeProperty;
set primitiveTypeProperty(List<TypeDefs_PrimitiveTypeDef> value);
/// @nodoc
@visibleForTesting
static dynamic $prototype = TypeDefs$Impl(Pointer<Void>.fromAddress(0));
}
typedef TypeDefs_NestedIntTypeDef = TypeDefs_PrimitiveTypeDef;
typedef TypeDefs_PrimitiveTypeDef = double;
typedef TypeDefs_StructArray = List<TypeDefs_TestStruct>;
typedef TypeDefs_ComplexTypeDef = TypeDefs_StructArray;
typedef TypeDefs_TestStructTypeDef = TypeDefs_TestStruct;
typedef TypeDefs_NestedStructTypeDef = TypeDefs_TestStructTypeDef;
class TypeDefs_StructHavingAliasFieldDefinedBelow {
double field;
TypeDefs_PrimitiveTypeDef field;
TypeDefs_StructHavingAliasFieldDefinedBelow(this.field);
}
// TypeDefs_StructHavingAliasFieldDefinedBelow "private" section, not exported.
Expand Down Expand Up @@ -162,7 +168,7 @@ final _smokeTypedefsReleaseHandle = __lib.catchArgumentError(() => __lib.nativeL
@visibleForTesting
class TypeDefs$Impl extends __lib.NativeBase implements TypeDefs {
TypeDefs$Impl(Pointer<Void> handle) : super(handle);
double methodWithPrimitiveTypeDef(double input) {
TypeDefs_PrimitiveTypeDef methodWithPrimitiveTypeDef(TypeDefs_PrimitiveTypeDef input) {
final _methodWithPrimitiveTypeDefFfi = __lib.catchArgumentError(() => __lib.nativeLibrary.lookupFunction<Double Function(Int32, Double), double Function(int, double)>('library_smoke_TypeDefs_methodWithPrimitiveTypeDef__Double'));
final _inputHandle = (input);
final __resultHandle = _methodWithPrimitiveTypeDefFfi(__lib.LibraryContext.isolateId, _inputHandle);
Expand All @@ -171,7 +177,7 @@ class TypeDefs$Impl extends __lib.NativeBase implements TypeDefs {
} finally {
}
}
List<TypeDefs_TestStruct> methodWithComplexTypeDef(List<TypeDefs_TestStruct> input) {
TypeDefs_ComplexTypeDef methodWithComplexTypeDef(TypeDefs_ComplexTypeDef input) {
final _methodWithComplexTypeDefFfi = __lib.catchArgumentError(() => __lib.nativeLibrary.lookupFunction<Pointer<Void> Function(Int32, Pointer<Void>), Pointer<Void> Function(int, Pointer<Void>)>('library_smoke_TypeDefs_methodWithComplexTypeDef__ListOf_smoke_TypeDefs_TestStruct'));
final _inputHandle = foobarListofSmokeTypedefsTeststructToFfi(input);
final __resultHandle = _methodWithComplexTypeDefFfi(__lib.LibraryContext.isolateId, _inputHandle);
Expand All @@ -182,7 +188,7 @@ class TypeDefs$Impl extends __lib.NativeBase implements TypeDefs {
foobarListofSmokeTypedefsTeststructReleaseFfiHandle(__resultHandle);
}
}
double returnNestedIntTypeDef(double input) {
TypeDefs_NestedIntTypeDef returnNestedIntTypeDef(TypeDefs_NestedIntTypeDef input) {
final _returnNestedIntTypeDefFfi = __lib.catchArgumentError(() => __lib.nativeLibrary.lookupFunction<Double Function(Int32, Double), double Function(int, double)>('library_smoke_TypeDefs_returnNestedIntTypeDef__Double'));
final _inputHandle = (input);
final __resultHandle = _returnNestedIntTypeDefFfi(__lib.LibraryContext.isolateId, _inputHandle);
Expand All @@ -191,7 +197,7 @@ class TypeDefs$Impl extends __lib.NativeBase implements TypeDefs {
} finally {
}
}
TypeDefs_TestStruct returnTestStructTypeDef(TypeDefs_TestStruct input) {
TypeDefs_TestStructTypeDef returnTestStructTypeDef(TypeDefs_TestStructTypeDef input) {
final _returnTestStructTypeDefFfi = __lib.catchArgumentError(() => __lib.nativeLibrary.lookupFunction<Pointer<Void> Function(Int32, Pointer<Void>), Pointer<Void> Function(int, Pointer<Void>)>('library_smoke_TypeDefs_returnTestStructTypeDef__TestStruct'));
final _inputHandle = smokeTypedefsTeststructToFfi(input);
final __resultHandle = _returnTestStructTypeDefFfi(__lib.LibraryContext.isolateId, _inputHandle);
Expand All @@ -202,7 +208,7 @@ class TypeDefs$Impl extends __lib.NativeBase implements TypeDefs {
smokeTypedefsTeststructReleaseFfiHandle(__resultHandle);
}
}
TypeDefs_TestStruct returnNestedStructTypeDef(TypeDefs_TestStruct input) {
TypeDefs_NestedStructTypeDef returnNestedStructTypeDef(TypeDefs_NestedStructTypeDef input) {
final _returnNestedStructTypeDefFfi = __lib.catchArgumentError(() => __lib.nativeLibrary.lookupFunction<Pointer<Void> Function(Int32, Pointer<Void>), Pointer<Void> Function(int, Pointer<Void>)>('library_smoke_TypeDefs_returnNestedStructTypeDef__TestStruct'));
final _inputHandle = smokeTypedefsTeststructToFfi(input);
final __resultHandle = _returnNestedStructTypeDefFfi(__lib.LibraryContext.isolateId, _inputHandle);
Expand All @@ -213,7 +219,7 @@ class TypeDefs$Impl extends __lib.NativeBase implements TypeDefs {
smokeTypedefsTeststructReleaseFfiHandle(__resultHandle);
}
}
TypeCollection_Point returnTypeDefPointFromTypeCollection(TypeCollection_Point input) {
PointTypeDef returnTypeDefPointFromTypeCollection(PointTypeDef input) {
final _returnTypeDefPointFromTypeCollectionFfi = __lib.catchArgumentError(() => __lib.nativeLibrary.lookupFunction<Pointer<Void> Function(Int32, Pointer<Void>), Pointer<Void> Function(int, Pointer<Void>)>('library_smoke_TypeDefs_returnTypeDefPointFromTypeCollection__Point'));
final _inputHandle = smokeTypecollectionPointToFfi(input);
final __resultHandle = _returnTypeDefPointFromTypeCollectionFfi(__lib.LibraryContext.isolateId, _inputHandle);
Expand All @@ -225,7 +231,7 @@ class TypeDefs$Impl extends __lib.NativeBase implements TypeDefs {
}
}
@override
List<double> get primitiveTypeProperty {
List<TypeDefs_PrimitiveTypeDef> get primitiveTypeProperty {
final _getFfi = __lib.catchArgumentError(() => __lib.nativeLibrary.lookupFunction<Pointer<Void> Function(Pointer<Void>, Int32), Pointer<Void> Function(Pointer<Void>, int)>('library_smoke_TypeDefs_primitiveTypeProperty_get'));
final _handle = this.handle;
final __resultHandle = _getFfi(_handle, __lib.LibraryContext.isolateId);
Expand All @@ -236,7 +242,7 @@ class TypeDefs$Impl extends __lib.NativeBase implements TypeDefs {
}
}
@override
set primitiveTypeProperty(List<double> value) {
set primitiveTypeProperty(List<TypeDefs_PrimitiveTypeDef> value) {
final _setFfi = __lib.catchArgumentError(() => __lib.nativeLibrary.lookupFunction<Void Function(Pointer<Void>, Int32, Pointer<Void>), void Function(Pointer<Void>, int, Pointer<Void>)>('library_smoke_TypeDefs_primitiveTypeProperty_set__ListOf_Double'));
final _valueHandle = foobarListofDoubleToFfi(value);
final _handle = this.handle;
Expand Down

0 comments on commit bd7f7e1

Please sign in to comment.