Use Opaque to represent empty Structs (#142, #143) (#166)
diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml
index a5cd11a..7de66eb 100644
--- a/.github/workflows/test-package.yml
+++ b/.github/workflows/test-package.yml
@@ -20,7 +20,7 @@
strategy:
fail-fast: false
matrix:
- sdk: [2.12.0-198.0.dev] # TODO(127): Revert to stable.
+ sdk: [2.12.0-237.0.dev] # TODO(127): Revert to stable.
steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1.0
@@ -44,7 +44,7 @@
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1.0
with:
- sdk: 2.12.0-198.0.dev # TODO(127): Revert to stable.
+ sdk: 2.12.0-237.0.dev # TODO(127): Revert to stable.
- name: Install dependencies
run: dart pub get
- name: Install libclang-10-dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1e49bdc..e877eb7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+# 2.0.0-dev.5
+- Use `Opaque` for representing empty `Struct`s.
+
# 2.0.0-dev.4
- Add support for parsing and generating globals.
diff --git a/example/c_json/pubspec.yaml b/example/c_json/pubspec.yaml
index 931aaea..76e4198 100644
--- a/example/c_json/pubspec.yaml
+++ b/example/c_json/pubspec.yaml
@@ -5,7 +5,7 @@
name: c_json_example
environment:
- sdk: '>=2.12.0-198.0.dev <3.0.0'
+ sdk: '>=2.12.0-237.0.dev <3.0.0'
dependencies:
ffi: ^0.2.0-nullsafety.1
diff --git a/example/libclang-example/generated_bindings.dart b/example/libclang-example/generated_bindings.dart
index 0edbcb9..330c63f 100644
--- a/example/libclang-example/generated_bindings.dart
+++ b/example/libclang-example/generated_bindings.dart
@@ -6250,9 +6250,9 @@
external int Count;
}
-class CXTargetInfoImpl extends ffi.Struct {}
+class CXTargetInfoImpl extends ffi.Opaque {}
-class CXTranslationUnitImpl extends ffi.Struct {}
+class CXTranslationUnitImpl extends ffi.Opaque {}
/// Provides the contents of a file that has not yet been saved to disk.
///
@@ -6636,7 +6636,7 @@
external CXString Message;
}
-class CXCursorSetImpl extends ffi.Struct {}
+class CXCursorSetImpl extends ffi.Opaque {}
/// Describes the kind of type
abstract class CXTypeKind {
diff --git a/example/libclang-example/pubspec.yaml b/example/libclang-example/pubspec.yaml
index df66b0b..efce084 100644
--- a/example/libclang-example/pubspec.yaml
+++ b/example/libclang-example/pubspec.yaml
@@ -5,7 +5,7 @@
name: libclang_example
environment:
- sdk: '>=2.12.0-198.0.dev <3.0.0'
+ sdk: '>=2.12.0-237.0.dev <3.0.0'
dev_dependencies:
ffigen:
diff --git a/example/simple/pubspec.yaml b/example/simple/pubspec.yaml
index ce3aa5e..d3562ef 100644
--- a/example/simple/pubspec.yaml
+++ b/example/simple/pubspec.yaml
@@ -5,7 +5,7 @@
name: simple_example
environment:
- sdk: '>=2.12.0-198.0.dev <3.0.0'
+ sdk: '>=2.12.0-237.0.dev <3.0.0'
dev_dependencies:
ffigen:
diff --git a/lib/src/code_generator/global.dart b/lib/src/code_generator/global.dart
index d419e92..42db339 100644
--- a/lib/src/code_generator/global.dart
+++ b/lib/src/code_generator/global.dart
@@ -61,12 +61,18 @@
final pointerName = w.wrapperLevelUniqueNamer.makeUnique('_$globalVarName');
final dartType = type.getDartType(w);
final cType = type.getCType(w);
- final refOrValue = type.broadType == BroadType.Struct ? 'ref' : 'value';
s.write(
- "late final ${w.ffiLibraryPrefix}.Pointer<$dartType> $pointerName = ${w.dylibIdentifier}.lookup<$cType>('$originalName');\n\n");
- s.write('$dartType get $globalVarName => $pointerName.$refOrValue;\n\n');
- if (type.broadType != BroadType.Struct) {
+ "late final ${w.ffiLibraryPrefix}.Pointer<$cType> $pointerName = ${w.dylibIdentifier}.lookup<$cType>('$originalName');\n\n");
+ if (type.broadType == BroadType.Struct) {
+ if (type.struc!.isOpaque) {
+ s.write(
+ '${w.ffiLibraryPrefix}.Pointer<$cType> get $globalVarName => $pointerName;\n\n');
+ } else {
+ s.write('$dartType get $globalVarName => $pointerName.ref;\n\n');
+ }
+ } else {
+ s.write('$dartType get $globalVarName => $pointerName.value;\n\n');
s.write(
'set $globalVarName($dartType value) => $pointerName.value = value;\n\n');
}
diff --git a/lib/src/code_generator/library.dart b/lib/src/code_generator/library.dart
index 4ea8e65..139ef4f 100644
--- a/lib/src/code_generator/library.dart
+++ b/lib/src/code_generator/library.dart
@@ -110,6 +110,7 @@
runInShell: Platform.isWindows);
if (result.stderr.toString().isNotEmpty) {
_logger.severe(result.stderr);
+ throw FormatException('Unable to format generated file: $path.');
}
}
diff --git a/lib/src/code_generator/struc.dart b/lib/src/code_generator/struc.dart
index 8958139..2a0aca5 100644
--- a/lib/src/code_generator/struc.dart
+++ b/lib/src/code_generator/struc.dart
@@ -42,6 +42,8 @@
List<Member> members;
+ bool get isOpaque => members.isEmpty;
+
Struc({
String? usr,
String? originalName,
@@ -102,7 +104,7 @@
// Write class declaration.
s.write(
- 'class $enclosingClassName extends ${w.ffiLibraryPrefix}.Struct{\n');
+ 'class $enclosingClassName extends ${w.ffiLibraryPrefix}.${isOpaque ? 'Opaque' : 'Struct'}{\n');
for (final m in members) {
final memberName = localUniqueNamer.makeUnique(m.name);
if (m.type.broadType == BroadType.ConstantArray) {
diff --git a/lib/src/header_parser/clang_bindings/clang_bindings.dart b/lib/src/header_parser/clang_bindings/clang_bindings.dart
index 7e7ab7c..a68621e 100644
--- a/lib/src/header_parser/clang_bindings/clang_bindings.dart
+++ b/lib/src/header_parser/clang_bindings/clang_bindings.dart
@@ -920,7 +920,7 @@
external int private_flags;
}
-class CXTranslationUnitImpl extends ffi.Struct {}
+class CXTranslationUnitImpl extends ffi.Opaque {}
/// Provides the contents of a file that has not yet been saved to disk.
///
diff --git a/lib/src/header_parser/data.dart b/lib/src/header_parser/data.dart
index c2b371e..ac16572 100644
--- a/lib/src/header_parser/data.dart
+++ b/lib/src/header_parser/data.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:ffi';
-import 'dart:isolate';
import 'package:ffigen/src/code_generator.dart' show Constant;
import 'package:ffigen/src/config_provider.dart' show Config;
diff --git a/pubspec.yaml b/pubspec.yaml
index 87663a2..cb13584 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,12 +3,12 @@
# BSD-style license that can be found in the LICENSE file.
name: ffigen
-version: 2.0.0-dev.4
+version: 2.0.0-dev.5
homepage: https://github.com/dart-lang/ffigen
description: Experimental generator for FFI bindings, using LibClang to parse C header files.
environment:
- sdk: '>=2.12.0-198.0.dev <3.0.0'
+ sdk: '>=2.12.0-237.0.dev <3.0.0'
dependencies:
ffi: ^0.2.0-nullsafety.1
diff --git a/test/code_generator_test.dart b/test/code_generator_test.dart
deleted file mode 100644
index aae8b0f..0000000
--- a/test/code_generator_test.dart
+++ /dev/null
@@ -1,921 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:io';
-
-import 'package:ffigen/src/code_generator.dart';
-import 'package:test/test.dart';
-
-void main() {
- group('code_generator: ', () {
- test('Function Binding (primitives, pointers)', () {
- final library = Library(
- name: 'Bindings',
- bindings: [
- Func(
- name: 'noParam',
- dartDoc: 'Just a test function\nheres another line',
- returnType: Type.nativeType(
- SupportedNativeType.Int32,
- ),
- ),
- Func(
- name: 'withPrimitiveParam',
- parameters: [
- Parameter(
- name: 'a',
- type: Type.nativeType(
- SupportedNativeType.Int32,
- ),
- ),
- Parameter(
- name: 'b',
- type: Type.nativeType(
- SupportedNativeType.Uint8,
- ),
- ),
- ],
- returnType: Type.nativeType(
- SupportedNativeType.Char,
- ),
- ),
- Func(
- name: 'withPointerParam',
- parameters: [
- Parameter(
- name: 'a',
- type: Type.pointer(
- Type.nativeType(
- SupportedNativeType.Int32,
- ),
- ),
- ),
- Parameter(
- name: 'b',
- type: Type.pointer(
- Type.pointer(
- Type.nativeType(
- SupportedNativeType.Uint8,
- ),
- ),
- ),
- ),
- ],
- returnType: Type.pointer(
- Type.nativeType(
- SupportedNativeType.Double,
- ),
- ),
- ),
- ],
- );
-
- final gen = library.generate();
-
- // Writing to file for debug purpose.
- final file = File(
- 'test/debug_generated/Function-Binding-test-output.dart',
- );
- try {
- expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT.
-//
-// Generated by `package:ffigen`.
-import 'dart:ffi' as ffi;
-
-class Bindings{
-/// Holds the Dynamic library.
-final ffi.DynamicLibrary _dylib;
-
-/// The symbols are looked up in [dynamicLibrary].
-Bindings(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary;
-
-/// Just a test function
-/// heres another line
-int noParam(
-) {
-return (_noParam ??= _dylib.lookupFunction<_c_noParam,_dart_noParam>('noParam'))(
- );
-}
-_dart_noParam? _noParam;
-
-int withPrimitiveParam(
- int a,
- int b,
-) {
-return (_withPrimitiveParam ??= _dylib.lookupFunction<_c_withPrimitiveParam,_dart_withPrimitiveParam>('withPrimitiveParam'))(
- a,
- b,
- );
-}
-_dart_withPrimitiveParam? _withPrimitiveParam;
-
-ffi.Pointer<ffi.Double> withPointerParam(
- ffi.Pointer<ffi.Int32> a,
- ffi.Pointer<ffi.Pointer<ffi.Uint8>> b,
-) {
-return (_withPointerParam ??= _dylib.lookupFunction<_c_withPointerParam,_dart_withPointerParam>('withPointerParam'))(
- a,
- b,
- );
-}
-_dart_withPointerParam? _withPointerParam;
-
-}
-
-typedef _c_noParam = ffi.Int32 Function(
-);
-
-typedef _dart_noParam = int Function(
-);
-
-typedef _c_withPrimitiveParam = ffi.Uint8 Function(
- ffi.Int32 a,
- ffi.Uint8 b,
-);
-
-typedef _dart_withPrimitiveParam = int Function(
- int a,
- int b,
-);
-
-typedef _c_withPointerParam = ffi.Pointer<ffi.Double> Function(
- ffi.Pointer<ffi.Int32> a,
- ffi.Pointer<ffi.Pointer<ffi.Uint8>> b,
-);
-
-typedef _dart_withPointerParam = ffi.Pointer<ffi.Double> Function(
- ffi.Pointer<ffi.Int32> a,
- ffi.Pointer<ffi.Pointer<ffi.Uint8>> b,
-);
-
-''');
- if (file.existsSync()) {
- file.delete();
- }
- } catch (e) {
- file.writeAsStringSync(gen);
- print('Failed test, Debug output: ${file.absolute.path}');
- rethrow;
- }
- });
-
- test('Struct Binding (primitives, pointers)', () {
- final library = Library(
- name: 'Bindings',
- bindings: [
- Struc(
- name: 'NoMember',
- dartDoc: 'Just a test struct\nheres another line',
- ),
- Struc(
- name: 'WithPrimitiveMember',
- members: [
- Member(
- name: 'a',
- type: Type.nativeType(
- SupportedNativeType.Int32,
- ),
- ),
- Member(
- name: 'b',
- type: Type.nativeType(
- SupportedNativeType.Double,
- ),
- ),
- Member(
- name: 'c',
- type: Type.nativeType(
- SupportedNativeType.Char,
- ),
- ),
- ],
- ),
- Struc(
- name: 'WithPointerMember',
- members: [
- Member(
- name: 'a',
- type: Type.pointer(
- Type.nativeType(
- SupportedNativeType.Int32,
- ),
- ),
- ),
- Member(
- name: 'b',
- type: Type.pointer(
- Type.pointer(
- Type.nativeType(
- SupportedNativeType.Double,
- ),
- ),
- ),
- ),
- Member(
- name: 'c',
- type: Type.nativeType(
- SupportedNativeType.Char,
- ),
- ),
- ],
- ),
- ],
- );
-
- final gen = library.generate();
-
- // Writing to file for debug purpose.
- final file = File('test/debug_generated/Struct-Binding-test-output.dart');
-
- try {
- expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT.
-//
-// Generated by `package:ffigen`.
-import 'dart:ffi' as ffi;
-
-/// Just a test struct
-/// heres another line
-class NoMember extends ffi.Struct{
-}
-
-class WithPrimitiveMember extends ffi.Struct{
- @ffi.Int32()
- external int a;
-
- @ffi.Double()
- external double b;
-
- @ffi.Uint8()
- external int c;
-
-}
-
-class WithPointerMember extends ffi.Struct{
- external ffi.Pointer<ffi.Int32> a;
-
- external ffi.Pointer<ffi.Pointer<ffi.Double>> b;
-
- @ffi.Uint8()
- external int c;
-
-}
-
-''');
- if (file.existsSync()) {
- file.delete();
- }
- } catch (e) {
- file.writeAsStringSync(gen);
- print('Failed test, Debug output: ${file.absolute.path}');
- rethrow;
- }
- });
-
- test('Function and Struct Binding (pointer to Struct)', () {
- final struct_some = Struc(
- name: 'SomeStruc',
- members: [
- Member(
- name: 'a',
- type: Type.nativeType(
- SupportedNativeType.Int32,
- ),
- ),
- Member(
- name: 'b',
- type: Type.nativeType(
- SupportedNativeType.Double,
- ),
- ),
- Member(
- name: 'c',
- type: Type.nativeType(
- SupportedNativeType.Char,
- ),
- ),
- ],
- );
- final library = Library(
- name: 'Bindings',
- bindings: [
- struct_some,
- Func(
- name: 'someFunc',
- parameters: [
- Parameter(
- name: 'some',
- type: Type.pointer(
- Type.pointer(
- Type.struct(
- struct_some,
- ),
- ),
- ),
- ),
- ],
- returnType: Type.pointer(
- Type.struct(
- struct_some,
- ),
- ),
- ),
- ],
- );
-
- final gen = library.generate();
-
- // Writing to file for debug purpose.
- final file =
- File('test/debug_generated/Func-n-Struct-Binding-test-output.dart');
- try {
- //expect
- expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT.
-//
-// Generated by `package:ffigen`.
-import 'dart:ffi' as ffi;
-
-class Bindings{
-/// Holds the Dynamic library.
-final ffi.DynamicLibrary _dylib;
-
-/// The symbols are looked up in [dynamicLibrary].
-Bindings(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary;
-
-ffi.Pointer<SomeStruc> someFunc(
- ffi.Pointer<ffi.Pointer<SomeStruc>> some,
-) {
-return (_someFunc ??= _dylib.lookupFunction<_c_someFunc,_dart_someFunc>('someFunc'))(
- some,
- );
-}
-_dart_someFunc? _someFunc;
-
-}
-
-class SomeStruc extends ffi.Struct{
- @ffi.Int32()
- external int a;
-
- @ffi.Double()
- external double b;
-
- @ffi.Uint8()
- external int c;
-
-}
-
-typedef _c_someFunc = ffi.Pointer<SomeStruc> Function(
- ffi.Pointer<ffi.Pointer<SomeStruc>> some,
-);
-
-typedef _dart_someFunc = ffi.Pointer<SomeStruc> Function(
- ffi.Pointer<ffi.Pointer<SomeStruc>> some,
-);
-
-''');
- if (file.existsSync()) {
- file.delete();
- }
- } catch (e) {
- file.writeAsStringSync(gen);
- print('Failed test, Debug output: ${file.absolute.path}');
- rethrow;
- }
- });
-
- test('global (primitives, pointers, pointer to struct)', () {
- final struc_some = Struc(
- name: 'Some',
- );
- final library = Library(
- name: 'Bindings',
- bindings: [
- Global(
- name: 'test1',
- type: Type.nativeType(
- SupportedNativeType.Int32,
- ),
- ),
- Global(
- name: 'test2',
- type: Type.pointer(
- Type.nativeType(
- SupportedNativeType.Float,
- ),
- ),
- ),
- struc_some,
- Global(
- name: 'test5',
- type: Type.pointer(
- Type.struct(
- struc_some,
- ),
- ),
- ),
- ],
- );
-
- final gen = library.generate();
-
- // Writing to file for debug purpose.
- final file = File(
- 'test/debug_generated/Global-Binding-test-output.dart',
- );
- try {
- expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT.
-//
-// Generated by `package:ffigen`.
-import 'dart:ffi' as ffi;
-
-class Bindings{
-/// Holds the Dynamic library.
-final ffi.DynamicLibrary _dylib;
-
-/// The symbols are looked up in [dynamicLibrary].
-Bindings(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary;
-
-late final ffi.Pointer<int> _test1 = _dylib.lookup<ffi.Int32>('test1');
-
-int get test1 => _test1.value;
-
-set test1(int value) => _test1.value = value;
-
-late final ffi.Pointer<ffi.Pointer<ffi.Float>> _test2 = _dylib.lookup<ffi.Pointer<ffi.Float>>('test2');
-
-ffi.Pointer<ffi.Float> get test2 => _test2.value;
-
-set test2(ffi.Pointer<ffi.Float> value) => _test2.value = value;
-
-late final ffi.Pointer<ffi.Pointer<Some>> _test5 = _dylib.lookup<ffi.Pointer<Some>>('test5');
-
-ffi.Pointer<Some> get test5 => _test5.value;
-
-set test5(ffi.Pointer<Some> value) => _test5.value = value;
-
-}
-
-class Some extends ffi.Struct{
-}
-
-''');
- if (file.existsSync()) {
- file.delete();
- }
- } catch (e) {
- file.writeAsStringSync(gen);
- print('Failed test, Debug output: ${file.absolute.path}');
- rethrow;
- }
- });
-
- test('constant', () {
- final library = Library(
- name: 'Bindings',
- bindings: [
- Constant(
- name: 'test1',
- rawType: 'int',
- rawValue: '20',
- ),
- Constant(
- name: 'test2',
- rawType: 'double',
- rawValue: '20.0',
- ),
- ],
- );
-
- final gen = library.generate();
-
- // Writing to file for debug purpose.
- final file = File(
- 'test/debug_generated/Constant-test-output.dart',
- );
- try {
- expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT.
-//
-// Generated by `package:ffigen`.
-import 'dart:ffi' as ffi;
-
-const int test1 = 20;
-
-const double test2 = 20.0;
-
-''');
- if (file.existsSync()) {
- file.delete();
- }
- } catch (e) {
- file.writeAsStringSync(gen);
- print('Failed test, Debug output: ${file.absolute.path}');
- rethrow;
- }
- });
-
- test('enum_class', () {
- final library = Library(
- name: 'Bindings',
- bindings: [
- EnumClass(
- name: 'Constants',
- dartDoc: 'test line 1\ntest line 2',
- enumConstants: [
- EnumConstant(
- name: 'a',
- value: 10,
- ),
- EnumConstant(name: 'b', value: -1, dartDoc: 'negative'),
- ],
- ),
- ],
- );
-
- final gen = library.generate();
-
- // Writing to file for debug purpose.
- final file = File(
- 'test/debug_generated/enum-class-test-output.dart',
- );
- try {
- expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT.
-//
-// Generated by `package:ffigen`.
-import 'dart:ffi' as ffi;
-
-/// test line 1
-/// test line 2
-abstract class Constants {
- static const int a = 10;
- /// negative
- static const int b = -1;
-}
-
-''');
- if (file.existsSync()) {
- file.delete();
- }
- } catch (e) {
- file.writeAsStringSync(gen);
- print('Failed test, Debug output: ${file.absolute.path}');
- rethrow;
- }
- });
- test('Internal conflict resolution', () {
- final library = Library(
- name: 'init_dylib',
- bindings: [
- Func(
- name: 'test',
- returnType: Type.nativeType(SupportedNativeType.Void),
- ),
- Func(
- name: '_test',
- returnType: Type.nativeType(SupportedNativeType.Void),
- ),
- Func(
- name: '_c_test',
- returnType: Type.nativeType(SupportedNativeType.Void),
- ),
- Func(
- name: '_dart_test',
- returnType: Type.nativeType(SupportedNativeType.Void),
- ),
- Struc(
- name: '_Test',
- members: [
- Member(
- name: 'array',
- type: Type.constantArray(
- 2,
- Type.nativeType(
- SupportedNativeType.Int8,
- ),
- ),
- ),
- ],
- ),
- Struc(name: 'ArrayHelperPrefixCollisionTest'),
- Func(
- name: 'Test',
- returnType: Type.nativeType(SupportedNativeType.Void),
- ),
- EnumClass(name: '_c_Test'),
- EnumClass(name: 'init_dylib'),
- ],
- );
-
- final gen = library.generate();
-
- // Writing to file for debug purpose.
- final file = File(
- 'test/debug_generated/internal-conflict-resolution.dart',
- );
- try {
- expect(gen, r'''// AUTO GENERATED FILE, DO NOT EDIT.
-//
-// Generated by `package:ffigen`.
-import 'dart:ffi' as ffi;
-
-class init_dylib_1{
-/// Holds the Dynamic library.
-final ffi.DynamicLibrary _dylib;
-
-/// The symbols are looked up in [dynamicLibrary].
-init_dylib_1(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary;
-
-void test(
-) {
-return (_test_1 ??= _dylib.lookupFunction<_c_test1,_dart_test1>('test'))(
- );
-}
-_dart_test1? _test_1;
-
-void _test(
-) {
-return (__test ??= _dylib.lookupFunction<_c__test,_dart__test>('_test'))(
- );
-}
-_dart__test? __test;
-
-void _c_test(
-) {
-return (__c_test ??= _dylib.lookupFunction<_c__c_test,_dart__c_test>('_c_test'))(
- );
-}
-_dart__c_test? __c_test;
-
-void _dart_test(
-) {
-return (__dart_test ??= _dylib.lookupFunction<_c__dart_test,_dart__dart_test>('_dart_test'))(
- );
-}
-_dart__dart_test? __dart_test;
-
-void Test(
-) {
-return (_Test ??= _dylib.lookupFunction<_c_Test1,_dart_Test>('Test'))(
- );
-}
-_dart_Test? _Test;
-
-}
-
-class _Test extends ffi.Struct{
- @ffi.Int8()
- external int _unique_array_item_0;
- @ffi.Int8()
- external int _unique_array_item_1;
-/// Helper for array `array`.
-ArrayHelper1__Test_array_level0 get array => ArrayHelper1__Test_array_level0(this, [2], 0, 0);
-}
-
-/// Helper for array `array` in struct `_Test`.
-class ArrayHelper1__Test_array_level0{
-final _Test _struct;
-final List<int> dimensions;
-final int level;
-final int _absoluteIndex;
-int get length => dimensions[level];
-ArrayHelper1__Test_array_level0(this._struct, this.dimensions, this.level, this._absoluteIndex);
- void _checkBounds(int index) {
- if (index >= length || index < 0) {
- throw RangeError('Dimension $level: index not in range 0..${length} exclusive.');
- }
- }
- int operator[](int index){
-_checkBounds(index);
-switch(_absoluteIndex+index){
-case 0:
- return _struct._unique_array_item_0;
-case 1:
- return _struct._unique_array_item_1;
-default:
- throw Exception('Invalid Array Helper generated.');}
-}
-void operator[]=(int index, int value){
-_checkBounds(index);
-switch(_absoluteIndex+index){
-case 0:
- _struct._unique_array_item_0 = value;
- break;
-case 1:
- _struct._unique_array_item_1 = value;
- break;
-default:
- throw Exception('Invalid Array Helper generated.');
-}
-}
-}
-class ArrayHelperPrefixCollisionTest extends ffi.Struct{
-}
-
-abstract class _c_Test {
-}
-
-abstract class init_dylib {
-}
-
-typedef _c_test1 = ffi.Void Function(
-);
-
-typedef _dart_test1 = void Function(
-);
-
-typedef _c__test = ffi.Void Function(
-);
-
-typedef _dart__test = void Function(
-);
-
-typedef _c__c_test = ffi.Void Function(
-);
-
-typedef _dart__c_test = void Function(
-);
-
-typedef _c__dart_test = ffi.Void Function(
-);
-
-typedef _dart__dart_test = void Function(
-);
-
-typedef _c_Test1 = ffi.Void Function(
-);
-
-typedef _dart_Test = void Function(
-);
-
-''');
- if (file.existsSync()) {
- file.delete();
- }
- } catch (e) {
- file.writeAsStringSync(gen);
- print('Failed test, Debug output: ${file.absolute.path}');
- rethrow;
- }
- });
- });
- test('boolean_dartBool', () {
- final library = Library(
- name: 'Bindings',
- dartBool: true,
- bindings: [
- Func(
- name: 'test1',
- returnType: Type.boolean(),
- parameters: [
- Parameter(name: 'a', type: Type.boolean()),
- Parameter(name: 'b', type: Type.pointer(Type.boolean())),
- ],
- ),
- Struc(
- name: 'test2',
- members: [
- Member(name: 'a', type: Type.boolean()),
- ],
- ),
- ],
- );
-
- final gen = library.generate();
-
- // Writing to file for debug purpose.
- final file = File(
- 'test/debug_generated/boolean-dartbool-output.dart',
- );
- try {
- expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT.
-//
-// Generated by `package:ffigen`.
-import 'dart:ffi' as ffi;
-
-class Bindings{
-/// Holds the Dynamic library.
-final ffi.DynamicLibrary _dylib;
-
-/// The symbols are looked up in [dynamicLibrary].
-Bindings(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary;
-
-bool test1(
- bool a,
- ffi.Pointer<ffi.Uint8> b,
-) {
-return (_test1 ??= _dylib.lookupFunction<_c_test1,_dart_test1>('test1'))(
- a?1:0,
- b,
- )!=0;
-}
-_dart_test1? _test1;
-
-}
-
-class test2 extends ffi.Struct{
- @ffi.Uint8()
- external int a;
-
-}
-
-typedef _c_test1 = ffi.Uint8 Function(
- ffi.Uint8 a,
- ffi.Pointer<ffi.Uint8> b,
-);
-
-typedef _dart_test1 = int Function(
- int a,
- ffi.Pointer<ffi.Uint8> b,
-);
-
-''');
- if (file.existsSync()) {
- file.delete();
- }
- } catch (e) {
- file.writeAsStringSync(gen);
- print('Failed test, Debug output: ${file.absolute.path}');
- rethrow;
- }
- });
- test('boolean_no_dartBool', () {
- final library = Library(
- name: 'Bindings',
- dartBool: false,
- bindings: [
- Func(
- name: 'test1',
- returnType: Type.boolean(),
- parameters: [
- Parameter(name: 'a', type: Type.boolean()),
- Parameter(name: 'b', type: Type.pointer(Type.boolean())),
- ],
- ),
- Struc(
- name: 'test2',
- members: [
- Member(name: 'a', type: Type.boolean()),
- ],
- ),
- ],
- );
-
- final gen = library.generate();
-
- // Writing to file for debug purpose.
- final file = File(
- 'test/debug_generated/boolean-no-dartBool-output.dart',
- );
- try {
- expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT.
-//
-// Generated by `package:ffigen`.
-import 'dart:ffi' as ffi;
-
-class Bindings{
-/// Holds the Dynamic library.
-final ffi.DynamicLibrary _dylib;
-
-/// The symbols are looked up in [dynamicLibrary].
-Bindings(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary;
-
-int test1(
- int a,
- ffi.Pointer<ffi.Uint8> b,
-) {
-return (_test1 ??= _dylib.lookupFunction<_c_test1,_dart_test1>('test1'))(
- a,
- b,
- );
-}
-_dart_test1? _test1;
-
-}
-
-class test2 extends ffi.Struct{
- @ffi.Uint8()
- external int a;
-
-}
-
-typedef _c_test1 = ffi.Uint8 Function(
- ffi.Uint8 a,
- ffi.Pointer<ffi.Uint8> b,
-);
-
-typedef _dart_test1 = int Function(
- int a,
- ffi.Pointer<ffi.Uint8> b,
-);
-
-''');
- if (file.existsSync()) {
- file.delete();
- }
- } catch (e) {
- file.writeAsStringSync(gen);
- print('Failed test, Debug output: ${file.absolute.path}');
- rethrow;
- }
- });
-}
diff --git a/test/code_generator_tests/code_generator_test.dart b/test/code_generator_tests/code_generator_test.dart
new file mode 100644
index 0000000..350b799
--- /dev/null
+++ b/test/code_generator_tests/code_generator_test.dart
@@ -0,0 +1,382 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:ffigen/src/code_generator.dart';
+import 'package:test/test.dart';
+import '../test_utils.dart';
+
+void main() {
+ group('code_generator: ', () {
+ test('Function Binding (primitives, pointers)', () {
+ final library = Library(
+ name: 'Bindings',
+ bindings: [
+ Func(
+ name: 'noParam',
+ dartDoc: 'Just a test function\nheres another line',
+ returnType: Type.nativeType(
+ SupportedNativeType.Int32,
+ ),
+ ),
+ Func(
+ name: 'withPrimitiveParam',
+ parameters: [
+ Parameter(
+ name: 'a',
+ type: Type.nativeType(
+ SupportedNativeType.Int32,
+ ),
+ ),
+ Parameter(
+ name: 'b',
+ type: Type.nativeType(
+ SupportedNativeType.Uint8,
+ ),
+ ),
+ ],
+ returnType: Type.nativeType(
+ SupportedNativeType.Char,
+ ),
+ ),
+ Func(
+ name: 'withPointerParam',
+ parameters: [
+ Parameter(
+ name: 'a',
+ type: Type.pointer(
+ Type.nativeType(
+ SupportedNativeType.Int32,
+ ),
+ ),
+ ),
+ Parameter(
+ name: 'b',
+ type: Type.pointer(
+ Type.pointer(
+ Type.nativeType(
+ SupportedNativeType.Uint8,
+ ),
+ ),
+ ),
+ ),
+ ],
+ returnType: Type.pointer(
+ Type.nativeType(
+ SupportedNativeType.Double,
+ ),
+ ),
+ ),
+ ],
+ );
+
+ _matchLib(library, 'function');
+ });
+
+ test('Struct Binding (primitives, pointers)', () {
+ final library = Library(
+ name: 'Bindings',
+ bindings: [
+ Struc(
+ name: 'NoMember',
+ dartDoc: 'Just a test struct\nheres another line',
+ ),
+ Struc(
+ name: 'WithPrimitiveMember',
+ members: [
+ Member(
+ name: 'a',
+ type: Type.nativeType(
+ SupportedNativeType.Int32,
+ ),
+ ),
+ Member(
+ name: 'b',
+ type: Type.nativeType(
+ SupportedNativeType.Double,
+ ),
+ ),
+ Member(
+ name: 'c',
+ type: Type.nativeType(
+ SupportedNativeType.Char,
+ ),
+ ),
+ ],
+ ),
+ Struc(
+ name: 'WithPointerMember',
+ members: [
+ Member(
+ name: 'a',
+ type: Type.pointer(
+ Type.nativeType(
+ SupportedNativeType.Int32,
+ ),
+ ),
+ ),
+ Member(
+ name: 'b',
+ type: Type.pointer(
+ Type.pointer(
+ Type.nativeType(
+ SupportedNativeType.Double,
+ ),
+ ),
+ ),
+ ),
+ Member(
+ name: 'c',
+ type: Type.nativeType(
+ SupportedNativeType.Char,
+ ),
+ ),
+ ],
+ ),
+ ],
+ );
+
+ _matchLib(library, 'struct');
+ });
+
+ test('Function and Struct Binding (pointer to Struct)', () {
+ final struct_some = Struc(
+ name: 'SomeStruc',
+ members: [
+ Member(
+ name: 'a',
+ type: Type.nativeType(
+ SupportedNativeType.Int32,
+ ),
+ ),
+ Member(
+ name: 'b',
+ type: Type.nativeType(
+ SupportedNativeType.Double,
+ ),
+ ),
+ Member(
+ name: 'c',
+ type: Type.nativeType(
+ SupportedNativeType.Char,
+ ),
+ ),
+ ],
+ );
+ final library = Library(
+ name: 'Bindings',
+ bindings: [
+ struct_some,
+ Func(
+ name: 'someFunc',
+ parameters: [
+ Parameter(
+ name: 'some',
+ type: Type.pointer(
+ Type.pointer(
+ Type.struct(
+ struct_some,
+ ),
+ ),
+ ),
+ ),
+ ],
+ returnType: Type.pointer(
+ Type.struct(
+ struct_some,
+ ),
+ ),
+ ),
+ ],
+ );
+
+ _matchLib(library, 'function_n_struct');
+ });
+
+ test('global (primitives, pointers, pointer to struct)', () {
+ final struc_some = Struc(
+ name: 'Some',
+ );
+ final emptyGlobalStruc = Struc(name: 'EmptyStruct');
+
+ final library = Library(
+ name: 'Bindings',
+ bindings: [
+ Global(
+ name: 'test1',
+ type: Type.nativeType(
+ SupportedNativeType.Int32,
+ ),
+ ),
+ Global(
+ name: 'test2',
+ type: Type.pointer(
+ Type.nativeType(
+ SupportedNativeType.Float,
+ ),
+ ),
+ ),
+ struc_some,
+ Global(
+ name: 'test5',
+ type: Type.pointer(
+ Type.struct(
+ struc_some,
+ ),
+ ),
+ ),
+ emptyGlobalStruc,
+ Global(name: 'globalStruct', type: Type.struct(emptyGlobalStruc)),
+ ],
+ );
+ _matchLib(library, 'global');
+ });
+
+ test('constant', () {
+ final library = Library(
+ name: 'Bindings',
+ header: '// ignore_for_file: unused_import\n',
+ bindings: [
+ Constant(
+ name: 'test1',
+ rawType: 'int',
+ rawValue: '20',
+ ),
+ Constant(
+ name: 'test2',
+ rawType: 'double',
+ rawValue: '20.0',
+ ),
+ ],
+ );
+ _matchLib(library, 'constant');
+ });
+
+ test('enum_class', () {
+ final library = Library(
+ name: 'Bindings',
+ header: '// ignore_for_file: unused_import\n',
+ bindings: [
+ EnumClass(
+ name: 'Constants',
+ dartDoc: 'test line 1\ntest line 2',
+ enumConstants: [
+ EnumConstant(
+ name: 'a',
+ value: 10,
+ ),
+ EnumConstant(name: 'b', value: -1, dartDoc: 'negative'),
+ ],
+ ),
+ ],
+ );
+ _matchLib(library, 'enumclass');
+ });
+ test('Internal conflict resolution', () {
+ final library = Library(
+ name: 'init_dylib',
+ header: '// ignore_for_file: unused_element\n',
+ bindings: [
+ Func(
+ name: 'test',
+ returnType: Type.nativeType(SupportedNativeType.Void),
+ ),
+ Func(
+ name: '_test',
+ returnType: Type.nativeType(SupportedNativeType.Void),
+ ),
+ Func(
+ name: '_c_test',
+ returnType: Type.nativeType(SupportedNativeType.Void),
+ ),
+ Func(
+ name: '_dart_test',
+ returnType: Type.nativeType(SupportedNativeType.Void),
+ ),
+ Struc(
+ name: '_Test',
+ members: [
+ Member(
+ name: 'array',
+ type: Type.constantArray(
+ 2,
+ Type.nativeType(
+ SupportedNativeType.Int8,
+ ),
+ ),
+ ),
+ ],
+ ),
+ Struc(name: 'ArrayHelperPrefixCollisionTest'),
+ Func(
+ name: 'Test',
+ returnType: Type.nativeType(SupportedNativeType.Void),
+ ),
+ EnumClass(name: '_c_Test'),
+ EnumClass(name: 'init_dylib'),
+ ],
+ );
+ _matchLib(library, 'internal_conflict_resolution');
+ });
+ });
+ test('boolean_dartBool', () {
+ final library = Library(
+ name: 'Bindings',
+ dartBool: true,
+ bindings: [
+ Func(
+ name: 'test1',
+ returnType: Type.boolean(),
+ parameters: [
+ Parameter(name: 'a', type: Type.boolean()),
+ Parameter(name: 'b', type: Type.pointer(Type.boolean())),
+ ],
+ ),
+ Struc(
+ name: 'test2',
+ members: [
+ Member(name: 'a', type: Type.boolean()),
+ ],
+ ),
+ ],
+ );
+ _matchLib(library, 'boolean_dartbool');
+ });
+ test('boolean_no_dartBool', () {
+ final library = Library(
+ name: 'Bindings',
+ dartBool: false,
+ bindings: [
+ Func(
+ name: 'test1',
+ returnType: Type.boolean(),
+ parameters: [
+ Parameter(name: 'a', type: Type.boolean()),
+ Parameter(name: 'b', type: Type.pointer(Type.boolean())),
+ ],
+ ),
+ Struc(
+ name: 'test2',
+ members: [
+ Member(name: 'a', type: Type.boolean()),
+ ],
+ ),
+ ],
+ );
+ _matchLib(library, 'boolean_no_dartbool');
+ });
+}
+
+/// Utility to match expected bindings to the generated bindings.
+void _matchLib(Library lib, String testName) {
+ matchLibraryWithExpected(lib, [
+ 'test',
+ 'debug_generated',
+ 'code_generator_test_${testName}_output.dart'
+ ], [
+ 'test',
+ 'code_generator_tests',
+ 'expected_bindings',
+ '_expected_${testName}_bindings.dart'
+ ]);
+}
diff --git a/test/code_generator_tests/expected_bindings/_expected_boolean_dartbool_bindings.dart b/test/code_generator_tests/expected_bindings/_expected_boolean_dartbool_bindings.dart
new file mode 100644
index 0000000..9e9d6ac
--- /dev/null
+++ b/test/code_generator_tests/expected_bindings/_expected_boolean_dartbool_bindings.dart
@@ -0,0 +1,40 @@
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+class Bindings {
+ /// Holds the Dynamic library.
+ final ffi.DynamicLibrary _dylib;
+
+ /// The symbols are looked up in [dynamicLibrary].
+ Bindings(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary;
+
+ bool test1(
+ bool a,
+ ffi.Pointer<ffi.Uint8> b,
+ ) {
+ return (_test1 ??= _dylib.lookupFunction<_c_test1, _dart_test1>('test1'))(
+ a ? 1 : 0,
+ b,
+ ) !=
+ 0;
+ }
+
+ _dart_test1? _test1;
+}
+
+class test2 extends ffi.Struct {
+ @ffi.Uint8()
+ external int a;
+}
+
+typedef _c_test1 = ffi.Uint8 Function(
+ ffi.Uint8 a,
+ ffi.Pointer<ffi.Uint8> b,
+);
+
+typedef _dart_test1 = int Function(
+ int a,
+ ffi.Pointer<ffi.Uint8> b,
+);
diff --git a/test/code_generator_tests/expected_bindings/_expected_boolean_no_dartbool_bindings.dart b/test/code_generator_tests/expected_bindings/_expected_boolean_no_dartbool_bindings.dart
new file mode 100644
index 0000000..99ed563
--- /dev/null
+++ b/test/code_generator_tests/expected_bindings/_expected_boolean_no_dartbool_bindings.dart
@@ -0,0 +1,39 @@
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+class Bindings {
+ /// Holds the Dynamic library.
+ final ffi.DynamicLibrary _dylib;
+
+ /// The symbols are looked up in [dynamicLibrary].
+ Bindings(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary;
+
+ int test1(
+ int a,
+ ffi.Pointer<ffi.Uint8> b,
+ ) {
+ return (_test1 ??= _dylib.lookupFunction<_c_test1, _dart_test1>('test1'))(
+ a,
+ b,
+ );
+ }
+
+ _dart_test1? _test1;
+}
+
+class test2 extends ffi.Struct {
+ @ffi.Uint8()
+ external int a;
+}
+
+typedef _c_test1 = ffi.Uint8 Function(
+ ffi.Uint8 a,
+ ffi.Pointer<ffi.Uint8> b,
+);
+
+typedef _dart_test1 = int Function(
+ int a,
+ ffi.Pointer<ffi.Uint8> b,
+);
diff --git a/test/code_generator_tests/expected_bindings/_expected_constant_bindings.dart b/test/code_generator_tests/expected_bindings/_expected_constant_bindings.dart
new file mode 100644
index 0000000..d01f2b1
--- /dev/null
+++ b/test/code_generator_tests/expected_bindings/_expected_constant_bindings.dart
@@ -0,0 +1,10 @@
+// ignore_for_file: unused_import
+
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+const int test1 = 20;
+
+const double test2 = 20.0;
diff --git a/test/code_generator_tests/expected_bindings/_expected_enumclass_bindings.dart b/test/code_generator_tests/expected_bindings/_expected_enumclass_bindings.dart
new file mode 100644
index 0000000..0aa2dbb
--- /dev/null
+++ b/test/code_generator_tests/expected_bindings/_expected_enumclass_bindings.dart
@@ -0,0 +1,15 @@
+// ignore_for_file: unused_import
+
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+/// test line 1
+/// test line 2
+abstract class Constants {
+ static const int a = 10;
+
+ /// negative
+ static const int b = -1;
+}
diff --git a/test/code_generator_tests/expected_bindings/_expected_function_bindings.dart b/test/code_generator_tests/expected_bindings/_expected_function_bindings.dart
new file mode 100644
index 0000000..82736d2
--- /dev/null
+++ b/test/code_generator_tests/expected_bindings/_expected_function_bindings.dart
@@ -0,0 +1,73 @@
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+class Bindings {
+ /// Holds the Dynamic library.
+ final ffi.DynamicLibrary _dylib;
+
+ /// The symbols are looked up in [dynamicLibrary].
+ Bindings(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary;
+
+ /// Just a test function
+ /// heres another line
+ int noParam() {
+ return (_noParam ??=
+ _dylib.lookupFunction<_c_noParam, _dart_noParam>('noParam'))();
+ }
+
+ _dart_noParam? _noParam;
+
+ int withPrimitiveParam(
+ int a,
+ int b,
+ ) {
+ return (_withPrimitiveParam ??=
+ _dylib.lookupFunction<_c_withPrimitiveParam, _dart_withPrimitiveParam>(
+ 'withPrimitiveParam'))(
+ a,
+ b,
+ );
+ }
+
+ _dart_withPrimitiveParam? _withPrimitiveParam;
+
+ ffi.Pointer<ffi.Double> withPointerParam(
+ ffi.Pointer<ffi.Int32> a,
+ ffi.Pointer<ffi.Pointer<ffi.Uint8>> b,
+ ) {
+ return (_withPointerParam ??=
+ _dylib.lookupFunction<_c_withPointerParam, _dart_withPointerParam>(
+ 'withPointerParam'))(
+ a,
+ b,
+ );
+ }
+
+ _dart_withPointerParam? _withPointerParam;
+}
+
+typedef _c_noParam = ffi.Int32 Function();
+
+typedef _dart_noParam = int Function();
+
+typedef _c_withPrimitiveParam = ffi.Uint8 Function(
+ ffi.Int32 a,
+ ffi.Uint8 b,
+);
+
+typedef _dart_withPrimitiveParam = int Function(
+ int a,
+ int b,
+);
+
+typedef _c_withPointerParam = ffi.Pointer<ffi.Double> Function(
+ ffi.Pointer<ffi.Int32> a,
+ ffi.Pointer<ffi.Pointer<ffi.Uint8>> b,
+);
+
+typedef _dart_withPointerParam = ffi.Pointer<ffi.Double> Function(
+ ffi.Pointer<ffi.Int32> a,
+ ffi.Pointer<ffi.Pointer<ffi.Uint8>> b,
+);
diff --git a/test/code_generator_tests/expected_bindings/_expected_function_n_struct_bindings.dart b/test/code_generator_tests/expected_bindings/_expected_function_n_struct_bindings.dart
new file mode 100644
index 0000000..4f0ea46
--- /dev/null
+++ b/test/code_generator_tests/expected_bindings/_expected_function_n_struct_bindings.dart
@@ -0,0 +1,42 @@
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+class Bindings {
+ /// Holds the Dynamic library.
+ final ffi.DynamicLibrary _dylib;
+
+ /// The symbols are looked up in [dynamicLibrary].
+ Bindings(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary;
+
+ ffi.Pointer<SomeStruc> someFunc(
+ ffi.Pointer<ffi.Pointer<SomeStruc>> some,
+ ) {
+ return (_someFunc ??=
+ _dylib.lookupFunction<_c_someFunc, _dart_someFunc>('someFunc'))(
+ some,
+ );
+ }
+
+ _dart_someFunc? _someFunc;
+}
+
+class SomeStruc extends ffi.Struct {
+ @ffi.Int32()
+ external int a;
+
+ @ffi.Double()
+ external double b;
+
+ @ffi.Uint8()
+ external int c;
+}
+
+typedef _c_someFunc = ffi.Pointer<SomeStruc> Function(
+ ffi.Pointer<ffi.Pointer<SomeStruc>> some,
+);
+
+typedef _dart_someFunc = ffi.Pointer<SomeStruc> Function(
+ ffi.Pointer<ffi.Pointer<SomeStruc>> some,
+);
diff --git a/test/code_generator_tests/expected_bindings/_expected_global_bindings.dart b/test/code_generator_tests/expected_bindings/_expected_global_bindings.dart
new file mode 100644
index 0000000..215858b
--- /dev/null
+++ b/test/code_generator_tests/expected_bindings/_expected_global_bindings.dart
@@ -0,0 +1,41 @@
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+class Bindings {
+ /// Holds the Dynamic library.
+ final ffi.DynamicLibrary _dylib;
+
+ /// The symbols are looked up in [dynamicLibrary].
+ Bindings(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary;
+
+ late final ffi.Pointer<ffi.Int32> _test1 = _dylib.lookup<ffi.Int32>('test1');
+
+ int get test1 => _test1.value;
+
+ set test1(int value) => _test1.value = value;
+
+ late final ffi.Pointer<ffi.Pointer<ffi.Float>> _test2 =
+ _dylib.lookup<ffi.Pointer<ffi.Float>>('test2');
+
+ ffi.Pointer<ffi.Float> get test2 => _test2.value;
+
+ set test2(ffi.Pointer<ffi.Float> value) => _test2.value = value;
+
+ late final ffi.Pointer<ffi.Pointer<Some>> _test5 =
+ _dylib.lookup<ffi.Pointer<Some>>('test5');
+
+ ffi.Pointer<Some> get test5 => _test5.value;
+
+ set test5(ffi.Pointer<Some> value) => _test5.value = value;
+
+ late final ffi.Pointer<EmptyStruct> _globalStruct =
+ _dylib.lookup<EmptyStruct>('globalStruct');
+
+ ffi.Pointer<EmptyStruct> get globalStruct => _globalStruct;
+}
+
+class Some extends ffi.Opaque {}
+
+class EmptyStruct extends ffi.Opaque {}
diff --git a/test/code_generator_tests/expected_bindings/_expected_internal_conflict_resolution_bindings.dart b/test/code_generator_tests/expected_bindings/_expected_internal_conflict_resolution_bindings.dart
new file mode 100644
index 0000000..a6fbe60
--- /dev/null
+++ b/test/code_generator_tests/expected_bindings/_expected_internal_conflict_resolution_bindings.dart
@@ -0,0 +1,126 @@
+// ignore_for_file: unused_element
+
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+class init_dylib_1 {
+ /// Holds the Dynamic library.
+ final ffi.DynamicLibrary _dylib;
+
+ /// The symbols are looked up in [dynamicLibrary].
+ init_dylib_1(ffi.DynamicLibrary dynamicLibrary) : _dylib = dynamicLibrary;
+
+ void test() {
+ return (_test_1 ??= _dylib.lookupFunction<_c_test1, _dart_test1>('test'))();
+ }
+
+ _dart_test1? _test_1;
+
+ void _test() {
+ return (__test ??= _dylib.lookupFunction<_c__test, _dart__test>('_test'))();
+ }
+
+ _dart__test? __test;
+
+ void _c_test() {
+ return (__c_test ??=
+ _dylib.lookupFunction<_c__c_test, _dart__c_test>('_c_test'))();
+ }
+
+ _dart__c_test? __c_test;
+
+ void _dart_test() {
+ return (__dart_test ??=
+ _dylib.lookupFunction<_c__dart_test, _dart__dart_test>('_dart_test'))();
+ }
+
+ _dart__dart_test? __dart_test;
+
+ void Test() {
+ return (_Test ??= _dylib.lookupFunction<_c_Test1, _dart_Test>('Test'))();
+ }
+
+ _dart_Test? _Test;
+}
+
+class _Test extends ffi.Struct {
+ @ffi.Int8()
+ external int _unique_array_item_0;
+ @ffi.Int8()
+ external int _unique_array_item_1;
+
+ /// Helper for array `array`.
+ ArrayHelper1__Test_array_level0 get array =>
+ ArrayHelper1__Test_array_level0(this, [2], 0, 0);
+}
+
+/// Helper for array `array` in struct `_Test`.
+class ArrayHelper1__Test_array_level0 {
+ final _Test _struct;
+ final List<int> dimensions;
+ final int level;
+ final int _absoluteIndex;
+ int get length => dimensions[level];
+ ArrayHelper1__Test_array_level0(
+ this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError(
+ 'Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+
+ int operator [](int index) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ return _struct._unique_array_item_0;
+ case 1:
+ return _struct._unique_array_item_1;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+
+ void operator []=(int index, int value) {
+ _checkBounds(index);
+ switch (_absoluteIndex + index) {
+ case 0:
+ _struct._unique_array_item_0 = value;
+ break;
+ case 1:
+ _struct._unique_array_item_1 = value;
+ break;
+ default:
+ throw Exception('Invalid Array Helper generated.');
+ }
+ }
+}
+
+class ArrayHelperPrefixCollisionTest extends ffi.Opaque {}
+
+abstract class _c_Test {}
+
+abstract class init_dylib {}
+
+typedef _c_test1 = ffi.Void Function();
+
+typedef _dart_test1 = void Function();
+
+typedef _c__test = ffi.Void Function();
+
+typedef _dart__test = void Function();
+
+typedef _c__c_test = ffi.Void Function();
+
+typedef _dart__c_test = void Function();
+
+typedef _c__dart_test = ffi.Void Function();
+
+typedef _dart__dart_test = void Function();
+
+typedef _c_Test1 = ffi.Void Function();
+
+typedef _dart_Test = void Function();
diff --git a/test/code_generator_tests/expected_bindings/_expected_struct_bindings.dart b/test/code_generator_tests/expected_bindings/_expected_struct_bindings.dart
new file mode 100644
index 0000000..f84642b
--- /dev/null
+++ b/test/code_generator_tests/expected_bindings/_expected_struct_bindings.dart
@@ -0,0 +1,28 @@
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+/// Just a test struct
+/// heres another line
+class NoMember extends ffi.Opaque {}
+
+class WithPrimitiveMember extends ffi.Struct {
+ @ffi.Int32()
+ external int a;
+
+ @ffi.Double()
+ external double b;
+
+ @ffi.Uint8()
+ external int c;
+}
+
+class WithPointerMember extends ffi.Struct {
+ external ffi.Pointer<ffi.Int32> a;
+
+ external ffi.Pointer<ffi.Pointer<ffi.Double>> b;
+
+ @ffi.Uint8()
+ external int c;
+}
diff --git a/test/header_parser_tests/globals.h b/test/header_parser_tests/globals.h
index f0f464f..80da2b0 100644
--- a/test/header_parser_tests/globals.h
+++ b/test/header_parser_tests/globals.h
@@ -13,3 +13,9 @@
// This should be ignored
int GlobalIgnore;
+
+struct EmptyStruct
+{
+};
+
+struct EmptyStruct globalStruct;
diff --git a/test/header_parser_tests/globals_test.dart b/test/header_parser_tests/globals_test.dart
index 7184792..832b89d 100644
--- a/test/header_parser_tests/globals_test.dart
+++ b/test/header_parser_tests/globals_test.dart
@@ -62,6 +62,7 @@
}
Library expectedLibrary() {
+ final globalStruc = Struc(name: 'EmptyStruct');
return Library(
name: 'Bindings',
bindings: [
@@ -70,6 +71,8 @@
Global(
type: Type.pointer(Type.nativeType(SupportedNativeType.Int32)),
name: 'aGlobalPointer'),
+ globalStruc,
+ Global(name: 'globalStruct', type: Type.struct(globalStruc)),
],
);
}
diff --git a/test/large_integration_tests/_expected_libclang_bindings.dart b/test/large_integration_tests/_expected_libclang_bindings.dart
index e0abce7..9d4c52d 100644
--- a/test/large_integration_tests/_expected_libclang_bindings.dart
+++ b/test/large_integration_tests/_expected_libclang_bindings.dart
@@ -5045,13 +5045,13 @@
external int Count;
}
-class CXVirtualFileOverlayImpl extends ffi.Struct {}
+class CXVirtualFileOverlayImpl extends ffi.Opaque {}
-class CXModuleMapDescriptorImpl extends ffi.Struct {}
+class CXModuleMapDescriptorImpl extends ffi.Opaque {}
-class CXTargetInfoImpl extends ffi.Struct {}
+class CXTargetInfoImpl extends ffi.Opaque {}
-class CXTranslationUnitImpl extends ffi.Struct {}
+class CXTranslationUnitImpl extends ffi.Opaque {}
/// Provides the contents of a file that has not yet been saved to disk.
class CXUnsavedFile extends ffi.Struct {
@@ -6333,7 +6333,7 @@
static const int CXTLS_Static = 2;
}
-class CXCursorSetImpl extends ffi.Struct {}
+class CXCursorSetImpl extends ffi.Opaque {}
/// Describes the kind of type
abstract class CXTypeKind {
diff --git a/test/large_integration_tests/_expected_sqlite_bindings.dart b/test/large_integration_tests/_expected_sqlite_bindings.dart
index 6abdd48..fa67d48 100644
--- a/test/large_integration_tests/_expected_sqlite_bindings.dart
+++ b/test/large_integration_tests/_expected_sqlite_bindings.dart
@@ -8984,9 +8984,9 @@
_dart_sqlite3_rtree_query_callback? _sqlite3_rtree_query_callback;
}
-class sqlite3 extends ffi.Struct {}
+class sqlite3 extends ffi.Opaque {}
-class sqlite3_file extends ffi.Struct {}
+class sqlite3_file extends ffi.Opaque {}
class sqlite3_io_methods extends ffi.Struct {
@ffi.Int32()
@@ -9031,19 +9031,19 @@
external ffi.Pointer<ffi.NativeFunction<_typedefC_19>> xUnfetch;
}
-class sqlite3_mutex extends ffi.Struct {}
+class sqlite3_mutex extends ffi.Opaque {}
-class sqlite3_api_routines extends ffi.Struct {}
+class sqlite3_api_routines extends ffi.Opaque {}
-class sqlite3_vfs extends ffi.Struct {}
+class sqlite3_vfs extends ffi.Opaque {}
-class sqlite3_mem_methods extends ffi.Struct {}
+class sqlite3_mem_methods extends ffi.Opaque {}
-class sqlite3_stmt extends ffi.Struct {}
+class sqlite3_stmt extends ffi.Opaque {}
-class sqlite3_value extends ffi.Struct {}
+class sqlite3_value extends ffi.Opaque {}
-class sqlite3_context extends ffi.Struct {}
+class sqlite3_context extends ffi.Opaque {}
/// CAPI3REF: Virtual Table Instance Object
/// KEYWORDS: sqlite3_vtab
@@ -9061,7 +9061,7 @@
/// prior to assigning a new string to zErrMsg. ^After the error message
/// is delivered up to the client application, the string will be automatically
/// freed by sqlite3_free() and the zErrMsg field will be zeroed.
-class sqlite3_vtab extends ffi.Struct {}
+class sqlite3_vtab extends ffi.Opaque {}
/// CAPI3REF: Virtual Table Indexing Information
/// KEYWORDS: sqlite3_index_info
@@ -9163,7 +9163,7 @@
/// It may therefore only be used if
/// sqlite3_libversion_number() returns a value greater than or equal to
/// 3009000.
-class sqlite3_index_info extends ffi.Struct {}
+class sqlite3_index_info extends ffi.Opaque {}
/// CAPI3REF: Virtual Table Cursor Object
/// KEYWORDS: sqlite3_vtab_cursor {virtual table cursor}
@@ -9180,7 +9180,7 @@
///
/// This superclass exists in order to define fields of the cursor that
/// are common to all implementations.
-class sqlite3_vtab_cursor extends ffi.Struct {}
+class sqlite3_vtab_cursor extends ffi.Opaque {}
/// CAPI3REF: Virtual Table Object
/// KEYWORDS: sqlite3_module {virtual table module}
@@ -9196,23 +9196,23 @@
/// module or until the [database connection] closes. The content
/// of this structure must not change while it is registered with
/// any database connection.
-class sqlite3_module extends ffi.Struct {}
+class sqlite3_module extends ffi.Opaque {}
-class sqlite3_blob extends ffi.Struct {}
+class sqlite3_blob extends ffi.Opaque {}
-class sqlite3_mutex_methods extends ffi.Struct {}
+class sqlite3_mutex_methods extends ffi.Opaque {}
-class sqlite3_str extends ffi.Struct {}
+class sqlite3_str extends ffi.Opaque {}
-class sqlite3_pcache extends ffi.Struct {}
+class sqlite3_pcache extends ffi.Opaque {}
-class sqlite3_pcache_page extends ffi.Struct {}
+class sqlite3_pcache_page extends ffi.Opaque {}
-class sqlite3_pcache_methods2 extends ffi.Struct {}
+class sqlite3_pcache_methods2 extends ffi.Opaque {}
-class sqlite3_pcache_methods extends ffi.Struct {}
+class sqlite3_pcache_methods extends ffi.Opaque {}
-class sqlite3_backup extends ffi.Struct {}
+class sqlite3_backup extends ffi.Opaque {}
/// CAPI3REF: Database Snapshot
/// KEYWORDS: {snapshot} {sqlite3_snapshot}
@@ -9610,7 +9610,7 @@
/// A pointer to a structure of the following type is passed as the first
/// argument to callbacks registered using rtree_geometry_callback().
-class sqlite3_rtree_geometry extends ffi.Struct {}
+class sqlite3_rtree_geometry extends ffi.Opaque {}
/// A pointer to a structure of the following type is passed as the
/// argument to scored geometry callback registered using
@@ -9619,7 +9619,7 @@
/// Note that the first 5 fields of this structure are identical to
/// sqlite3_rtree_geometry. This structure is a subclass of
/// sqlite3_rtree_geometry.
-class sqlite3_rtree_query_info extends ffi.Struct {}
+class sqlite3_rtree_query_info extends ffi.Opaque {}
/// EXTENSION API FUNCTIONS
///
@@ -9830,17 +9830,17 @@
///
/// xPhraseNextColumn()
/// See xPhraseFirstColumn above.
-class Fts5ExtensionApi extends ffi.Struct {}
+class Fts5ExtensionApi extends ffi.Opaque {}
-class Fts5Context extends ffi.Struct {}
+class Fts5Context extends ffi.Opaque {}
-class Fts5PhraseIter extends ffi.Struct {}
+class Fts5PhraseIter extends ffi.Opaque {}
-class Fts5Tokenizer extends ffi.Struct {}
+class Fts5Tokenizer extends ffi.Opaque {}
-class fts5_tokenizer extends ffi.Struct {}
+class fts5_tokenizer extends ffi.Opaque {}
-class fts5_api extends ffi.Struct {}
+class fts5_api extends ffi.Opaque {}
const String SQLITE_VERSION = '3.32.3';
diff --git a/test/test_coverage.dart b/test/test_coverage.dart
index ede39f3..9f61cde 100644
--- a/test/test_coverage.dart
+++ b/test/test_coverage.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'code_generator_test.dart' as code_generator_test;
+import 'code_generator_tests/code_generator_test.dart' as code_generator_test;
import 'collision_tests/decl_decl_collision_test.dart'
as collision_tests_decl_decl_collision_test;
import 'collision_tests/reserved_keyword_collision_test.dart'
@@ -19,6 +19,8 @@
as header_parser_tests_function_n_struct_test;
import 'header_parser_tests/functions_test.dart'
as header_parser_tests_functions_test;
+import 'header_parser_tests/globals_test.dart'
+ as header_parser_tests_globals_test;
import 'header_parser_tests/macros_test.dart'
as header_parser_tests_macros_test;
import 'header_parser_tests/native_func_typedef_test.dart'
@@ -43,6 +45,7 @@
collision_tests_reserved_keyword_collision_test.main();
header_parser_tests_dart_handle_test.main();
header_parser_tests_functions_test.main();
+ header_parser_tests_globals_test.main();
header_parser_tests_macros_test.main();
header_parser_tests_function_n_struct_test.main();
header_parser_tests_native_func_typedef_test.main();
diff --git a/test/test_utils.dart b/test/test_utils.dart
index c2d95f0..a967f66 100644
--- a/test/test_utils.dart
+++ b/test/test_utils.dart
@@ -9,8 +9,6 @@
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
-/// Extracts a binding's string from a library.
-
extension LibraryTestExt on Library {
/// Get a [Binding]'s generated string with a given name.
String getBindingAsString(String name) {