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

dart-lang / ffigen / 6757945116

02 Nov 2023 02:02AM UTC coverage: 91.853% (-0.3%) from 92.193%
6757945116

push

github

web-flow
ObjC static functions (#633)

* WIP static functions

* Revert old code gen changes

* Refactor function code gen

* Arg and return conversions

* fix bugs

* Fix analysis, add more tests

* fmt

* Fix autorelease pool test

* Handle NS_RETURNS_RETAINED

* Daco's comments

36 of 54 new or added lines in 9 files covered. (66.67%)

1 existing line in 1 file now uncovered.

3732 of 4063 relevant lines covered (91.85%)

28.84 hits per line

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

89.61
/lib/src/header_parser/sub_parsers/functiondecl_parser.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 'dart:ffi';
6

7
import 'package:ffigen/src/code_generator.dart';
8
import 'package:ffigen/src/config_provider/config_types.dart';
9
import 'package:ffigen/src/header_parser/data.dart';
10
import 'package:logging/logging.dart';
11

12
import '../clang_bindings/clang_bindings.dart' as clang_types;
13
import '../includer.dart';
14
import '../utils.dart';
15

16
final _logger = Logger('ffigen.header_parser.functiondecl_parser');
69✔
17

18
/// Holds temporary information regarding [Func] while parsing.
19
class _ParserFunc {
20
  /// Multiple values are since there may be more than one instance of the
21
  /// same base C function with different variadic arguments.
22
  List<Func> funcs = [];
23
  bool incompleteStructParameter = false;
24
  bool unimplementedParameterType = false;
25
  bool objCReturnsRetained = false;
26
  _ParserFunc();
25✔
27
}
28

29
final _stack = Stack<_ParserFunc>();
75✔
30

31
/// Parses a function declaration.
32
List<Func>? parseFunctionDeclaration(clang_types.CXCursor cursor) {
25✔
33
  _stack.push(_ParserFunc());
75✔
34

35
  final funcUsr = cursor.usr();
25✔
36
  final funcName = cursor.spelling();
25✔
37
  if (shouldIncludeFunc(funcUsr, funcName)) {
25✔
38
    _logger.fine('++++ Adding Function: ${cursor.completeStringRepr()}');
92✔
39

40
    final rt = _getFunctionReturnType(cursor);
23✔
41
    final parameters = _getParameters(cursor, funcName);
23✔
42
    if (clang.clang_Cursor_isFunctionInlined(cursor) != 0 &&
69✔
43
        clang.clang_Cursor_getStorageClass(cursor) !=
3✔
44
            clang_types.CX_StorageClass.CX_SC_Extern) {
45
      _logger.fine('---- Removed Function, reason: inline function: '
3✔
46
          '${cursor.completeStringRepr()}');
1✔
47
      _logger.warning(
2✔
48
          "Skipped Function '$funcName', inline functions are not supported.");
1✔
49
      // Returning empty so that [addToBindings] function excludes this.
50
      return _stack.pop().funcs;
3✔
51
    }
52

53
    if (rt.isIncompleteCompound || _stack.top.incompleteStructParameter) {
92✔
54
      _logger.fine(
×
55
          '---- Removed Function, reason: Incomplete struct pass/return by '
56
          'value: ${cursor.completeStringRepr()}');
×
57
      _logger.warning(
×
58
          "Skipped Function '$funcName', Incomplete struct pass/return by "
59
          'value not supported.');
60
      // Returning null so that [addToBindings] function excludes this.
61
      return _stack.pop().funcs;
×
62
    }
63

64
    if (rt.baseType is UnimplementedType ||
46✔
65
        _stack.top.unimplementedParameterType) {
69✔
66
      _logger.fine('---- Removed Function, reason: unsupported return type or '
9✔
67
          'parameter type: ${cursor.completeStringRepr()}');
3✔
68
      _logger.warning(
9✔
69
          "Skipped Function '$funcName', function has unsupported return type "
70
          'or parameter type.');
71
      // Returning null so that [addToBindings] function excludes this.
72
      return _stack.pop().funcs;
9✔
73
    }
74

75
    // Look for any annotations on the function.
76
    clang.clang_visitChildren(
46✔
77
        cursor,
78
        _parseAnnotationVisitorPtr ??= Pointer.fromFunction(
79
            _parseAnnotationVisitor, exceptional_visitor_return),
80
        nullptr);
23✔
81

82
    // Initialized with a single value with no prefix and empty var args.
83
    var varArgFunctions = [VarArgFunction('', [])];
69✔
84
    if (config.varArgFunctions.containsKey(funcName)) {
69✔
85
      if (clang.clang_isFunctionTypeVariadic(cursor.type()) == 1) {
4✔
86
        varArgFunctions = config.varArgFunctions[funcName]!;
3✔
87
      } else {
88
        _logger.warning(
×
89
            "Skipping variadic-argument config for function $funcName since its not variadic.");
×
90
      }
91
    }
92
    for (final vaFunc in varArgFunctions) {
46✔
93
      _stack.top.funcs.add(Func(
115✔
94
        dartDoc: getCursorDocComment(
23✔
95
          cursor,
96
          nesting.length + commentPrefix.length,
69✔
97
        ),
98
        usr: funcUsr + vaFunc.postfix,
46✔
99
        name: config.functionDecl.renameUsingConfig(funcName) + vaFunc.postfix,
115✔
100
        originalName: funcName,
101
        returnType: rt,
102
        parameters: parameters,
103
        varArgParameters:
104
            vaFunc.types.map((ta) => Parameter(type: ta, name: 'va')).toList(),
71✔
105
        exposeSymbolAddress:
106
            config.functionDecl.shouldIncludeSymbolAddress(funcName),
69✔
107
        exposeFunctionTypedefs:
108
            config.exposeFunctionTypedefs.shouldInclude(funcName),
69✔
109
        isLeaf: config.leafFunctions.shouldInclude(funcName),
69✔
110
        objCReturnsRetained: _stack.top.objCReturnsRetained,
69✔
111
        ffiNativeConfig: config.ffiNativeConfig,
46✔
112
      ));
113
    }
114
    bindingsIndex.addFuncToSeen(funcUsr, _stack.top.funcs.last);
138✔
115
  } else if (bindingsIndex.isSeenFunc(funcUsr)) {
14✔
116
    _stack.top.funcs.add(bindingsIndex.getSeenFunc(funcUsr)!);
6✔
117
  }
118

119
  return _stack.pop().funcs;
75✔
120
}
121

122
Type _getFunctionReturnType(clang_types.CXCursor cursor) {
23✔
123
  return cursor.returnType().toCodeGenType();
46✔
124
}
125

126
List<Parameter> _getParameters(clang_types.CXCursor cursor, String funcName) {
23✔
127
  final parameters = <Parameter>[];
23✔
128

129
  final totalArgs = clang.clang_Cursor_getNumArguments(cursor);
46✔
130
  for (var i = 0; i < totalArgs; i++) {
43✔
131
    final paramCursor = clang.clang_Cursor_getArgument(cursor, i);
40✔
132

133
    _logger.finer('===== parameter: ${paramCursor.completeStringRepr()}');
80✔
134

135
    final pt = _getParameterType(paramCursor);
20✔
136
    if (pt.isIncompleteCompound) {
20✔
137
      _stack.top.incompleteStructParameter = true;
×
138
    } else if (pt.baseType is UnimplementedType) {
40✔
139
      _logger.finer('Unimplemented type: ${pt.baseType}');
12✔
140
      _stack.top.unimplementedParameterType = true;
9✔
141
    }
142

143
    final pn = paramCursor.spelling();
20✔
144

145
    /// If [pn] is null or empty, its set to `arg$i` by code_generator.
146
    parameters.add(
20✔
147
      Parameter(
20✔
148
        originalName: pn,
149
        name: config.functionDecl.renameMemberUsingConfig(funcName, pn),
60✔
150
        type: pt,
151
      ),
152
    );
153
  }
154

155
  return parameters;
156
}
157

158
Type _getParameterType(clang_types.CXCursor cursor) {
20✔
159
  return cursor.toCodeGenType();
20✔
160
}
161

162
Pointer<
163
        NativeFunction<
164
            Int32 Function(
165
                clang_types.CXCursor, clang_types.CXCursor, Pointer<Void>)>>?
166
    _parseAnnotationVisitorPtr;
167
int _parseAnnotationVisitor(clang_types.CXCursor cursor,
20✔
168
    clang_types.CXCursor parent, Pointer<Void> clientData) {
169
  switch (cursor.kind) {
20✔
170
    case clang_types.CXCursorKind.CXCursor_NSReturnsRetained:
20✔
NEW
171
      _stack.top.objCReturnsRetained = true;
×
172
      break;
173
    default:
174
  }
175
  return clang_types.CXChildVisitResult.CXChildVisit_Continue;
176
}
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