• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dart-lang / ffigen / 4769078761

21 Apr 2023 09:59PM UTC coverage: 92.323% (-7.0%) from 99.366%
4769078761

Pull #559

github

GitHub
Merge 451544795 into fd3e1a724
Pull Request #559: Handle multi anonymous struct with same USR

1790 of 1790 new or added lines in 41 files covered. (100.0%)

3235 of 3504 relevant lines covered (92.32%)

25.23 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.26
/lib/src/code_generator/func.dart
1
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2
// for details. All rights reserved. Use of this source code is governed by a
3
// BSD-style license that can be found in the LICENSE file.
4

5
import 'package:ffigen/src/code_generator.dart';
6
import 'package:ffigen/src/config_provider/config_types.dart';
7

8
import 'binding_string.dart';
9
import 'utils.dart';
10
import 'writer.dart';
11

12
/// A binding for C function.
13
///
14
/// For example, take the following C function.
15
///
16
/// ```c
17
/// int sum(int a, int b);
18
/// ```
19
///
20
/// The generated Dart code for this function (without `FfiNative`) is as follows.
21
///
22
/// ```dart
23
/// int sum(int a, int b) {
24
///   return _sum(a, b);
25
/// }
26
///
27
/// final _dart_sum _sum = _dylib.lookupFunction<_c_sum, _dart_sum>('sum');
28
///
29
/// typedef _c_sum = ffi.Int32 Function(ffi.Int32 a, ffi.Int32 b);
30
///
31
/// typedef _dart_sum = int Function(int a, int b);
32
/// ```
33
///
34
/// When using `FfiNative`, the code is as follows.
35
///
36
/// ```dart
37
/// @ffi.FfiNative<ffi.Int32 Function(ffi.Int32 a, ffi.Int32 b)>('sum')
38
/// external int sum(int a, int b);
39
/// ```
40
class Func extends LookUpBinding {
41
  final FunctionType functionType;
42
  final bool exposeSymbolAddress;
43
  final bool exposeFunctionTypedefs;
44
  final bool isLeaf;
45
  final FfiNativeConfig ffiNativeConfig;
46
  late final String funcPointerName;
47

48
  /// Contains typealias for function type if [exposeFunctionTypedefs] is true.
49
  Typealias? _exposedCFunctionTypealias;
50
  Typealias? _exposedDartFunctionTypealias;
51

52
  /// [originalName] is looked up in dynamic library, if not
53
  /// provided, takes the value of [name].
54
  Func({
28✔
55
    String? usr,
56
    required String name,
57
    String? originalName,
58
    String? dartDoc,
59
    required Type returnType,
60
    List<Parameter>? parameters,
61
    this.exposeSymbolAddress = false,
62
    this.exposeFunctionTypedefs = false,
63
    this.isLeaf = false,
64
    bool isInternal = false,
65
    this.ffiNativeConfig = const FfiNativeConfig(enabled: false),
66
  })  : functionType = FunctionType(
28✔
67
          returnType: returnType,
68
          parameters: parameters ?? const [],
69
        ),
70
        super(
28✔
71
          usr: usr,
72
          originalName: originalName,
73
          name: name,
74
          dartDoc: dartDoc,
75
          isInternal: isInternal,
76
        ) {
77
    for (var i = 0; i < functionType.parameters.length; i++) {
135✔
78
      if (functionType.parameters[i].name.trim() == '') {
138✔
79
        functionType.parameters[i].name = 'arg$i';
30✔
80
      }
81
    }
82

83
    // Get function name with first letter in upper case.
84
    final upperCaseName = name[0].toUpperCase() + name.substring(1);
112✔
85
    if (exposeFunctionTypedefs) {
28✔
86
      _exposedCFunctionTypealias = Typealias(
4✔
87
        name: 'Native$upperCaseName',
2✔
88
        type: functionType,
2✔
89
        isInternal: true,
90
      );
91
      _exposedDartFunctionTypealias = Typealias(
4✔
92
        name: 'Dart$upperCaseName',
2✔
93
        type: functionType,
2✔
94
        useDartType: true,
95
        isInternal: true,
96
      );
97
    }
98
  }
99

100
  @override
26✔
101
  BindingString toBindingString(Writer w) {
102
    final s = StringBuffer();
26✔
103
    final enclosingFuncName = name;
26✔
104
    final funcVarName = w.wrapperLevelUniqueNamer.makeUnique('_$name');
104✔
105
    funcPointerName = w.wrapperLevelUniqueNamer.makeUnique('_${name}Ptr');
130✔
106

107
    if (dartDoc != null) {
26✔
108
      s.write(makeDartDoc(dartDoc!));
18✔
109
    }
110
    // Resolve name conflicts in function parameter names.
111
    final paramNamer = UniqueNamer({});
26✔
112
    for (final p in functionType.parameters) {
74✔
113
      p.name = paramNamer.makeUnique(p.name);
66✔
114
    }
115

116
    final cType = exposeFunctionTypedefs
26✔
117
        ? _exposedCFunctionTypealias!.name
4✔
118
        : functionType.getCType(w, writeArgumentNames: false);
50✔
119
    final dartType = exposeFunctionTypedefs
26✔
120
        ? _exposedDartFunctionTypealias!.name
4✔
121
        : functionType.getDartType(w, writeArgumentNames: false);
50✔
122

123
    if (ffiNativeConfig.enabled) {
52✔
124
      final assetString = ffiNativeConfig.asset != null
2✔
125
          ? ", asset: '${ffiNativeConfig.asset}'"
×
126
          : '';
×
127
      final isLeafString = isLeaf ? ', isLeaf: true' : '';
1✔
128
      s.write(
1✔
129
          "@${w.ffiLibraryPrefix}.FfiNative<$cType>('$originalName'$assetString$isLeafString)\n");
3✔
130

131
      s.write(
1✔
132
          'external ${functionType.returnType.getDartType(w)} $enclosingFuncName(\n');
4✔
133
      for (final p in functionType.parameters) {
3✔
134
        s.write('  ${p.type.getDartType(w)} ${p.name},\n');
5✔
135
      }
136
      s.write(');\n\n');
1✔
137
    } else {
138
      // Write enclosing function.
139
      s.write(
25✔
140
          '${functionType.returnType.getDartType(w)} $enclosingFuncName(\n');
100✔
141
      for (final p in functionType.parameters) {
71✔
142
        s.write('  ${p.type.getDartType(w)} ${p.name},\n');
105✔
143
      }
144
      s.write(') {\n');
25✔
145
      s.write('return $funcVarName');
50✔
146

147
      s.write('(\n');
25✔
148
      for (final p in functionType.parameters) {
71✔
149
        s.write('    ${p.name},\n');
63✔
150
      }
151
      s.write('  );\n');
25✔
152
      s.write('}\n');
25✔
153

154
      if (exposeSymbolAddress) {
25✔
155
        // Add to SymbolAddress in writer.
156
        w.symbolAddressWriter.addSymbol(
6✔
157
          type:
158
              '${w.ffiLibraryPrefix}.Pointer<${w.ffiLibraryPrefix}.NativeFunction<$cType>>',
9✔
159
          name: name,
3✔
160
          ptrName: funcPointerName,
3✔
161
        );
162
      }
163
      // Write function pointer.
164
      s.write(
25✔
165
          "late final $funcPointerName = ${w.lookupFuncIdentifier}<${w.ffiLibraryPrefix}.NativeFunction<$cType>>('$originalName');\n");
125✔
166
      final isLeafString = isLeaf ? 'isLeaf:true' : '';
25✔
167
      s.write(
25✔
168
          'late final $funcVarName = $funcPointerName.asFunction<$dartType>($isLeafString);\n\n');
50✔
169
    }
170

171
    return BindingString(type: BindingStringType.func, string: s.toString());
52✔
172
  }
173

174
  @override
28✔
175
  void addDependencies(Set<Binding> dependencies) {
176
    if (dependencies.contains(this)) return;
28✔
177

178
    dependencies.add(this);
28✔
179
    functionType.addDependencies(dependencies);
56✔
180
    if (exposeFunctionTypedefs) {
28✔
181
      _exposedCFunctionTypealias!.addDependencies(dependencies);
4✔
182
      _exposedDartFunctionTypealias!.addDependencies(dependencies);
4✔
183
    }
184
  }
185
}
186

187
/// Represents a Parameter, used in [Func] and [Typealias].
188
class Parameter {
189
  final String? originalName;
190
  String name;
191
  final Type type;
192

193
  Parameter({String? originalName, this.name = '', required Type type})
24✔
194
      : originalName = originalName ?? name,
195
        // A [NativeFunc] is wrapped with a pointer because this is a shorthand
196
        // used in C for Pointer to function.
197
        type = type.typealiasType is NativeFunc ? PointerType(type) : type;
49✔
198
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc