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

dart-lang / ffigen / 4851318812

01 May 2023 01:06PM UTC coverage: 91.872% (-0.5%) from 92.376%
4851318812

push

github

GitHub
Support for generating Variadic functions (#515)

177 of 177 new or added lines in 9 files covered. (100.0%)

3357 of 3654 relevant lines covered (91.87%)

25.29 hits per line

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

92.75
/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 'package:ffigen/src/code_generator.dart';
6
import 'package:ffigen/src/config_provider/config_types.dart';
7
import 'package:ffigen/src/header_parser/data.dart';
8
import 'package:logging/logging.dart';
9

10
import '../clang_bindings/clang_bindings.dart' as clang_types;
11
import '../includer.dart';
12
import '../utils.dart';
13

14
final _logger = Logger('ffigen.header_parser.functiondecl_parser');
69✔
15

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

26
final _stack = Stack<_ParserFunc>();
75✔
27

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

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

37
    final rt = _getFunctionReturnType(cursor);
23✔
38
    final parameters = _getParameters(cursor, funcName);
23✔
39

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

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

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

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

107
  return _stack.pop().funcs;
75✔
108
}
109

110
Type _getFunctionReturnType(clang_types.CXCursor cursor) {
23✔
111
  return cursor.returnType().toCodeGenType();
46✔
112
}
113

114
List<Parameter> _getParameters(clang_types.CXCursor cursor, String funcName) {
23✔
115
  final parameters = <Parameter>[];
23✔
116

117
  final totalArgs = clang.clang_Cursor_getNumArguments(cursor);
46✔
118
  for (var i = 0; i < totalArgs; i++) {
43✔
119
    final paramCursor = clang.clang_Cursor_getArgument(cursor, i);
40✔
120

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

123
    final pt = _getParameterType(paramCursor);
20✔
124
    if (pt.isIncompleteCompound) {
20✔
125
      _stack.top.incompleteStructParameter = true;
×
126
    } else if (pt.baseType is UnimplementedType) {
40✔
127
      _logger.finer('Unimplemented type: ${pt.baseType}');
12✔
128
      _stack.top.unimplementedParameterType = true;
9✔
129
    }
130

131
    final pn = paramCursor.spelling();
20✔
132

133
    /// If [pn] is null or empty, its set to `arg$i` by code_generator.
134
    parameters.add(
20✔
135
      Parameter(
20✔
136
        originalName: pn,
137
        name: config.functionDecl.renameMemberUsingConfig(funcName, pn),
60✔
138
        type: pt,
139
      ),
140
    );
141
  }
142

143
  return parameters;
144
}
145

146
Type _getParameterType(clang_types.CXCursor cursor) {
20✔
147
  return cursor.toCodeGenType();
20✔
148
}
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