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

dart-lang / ffigen / 5305585135

18 Jun 2023 08:33PM CUT coverage: 85.041% (-6.8%) from 91.879%
5305585135

Pull #586

github

web-flow
Merge 27e2ea8df into 9030eb512
Pull Request #586: Add ffigen schema and refer them in example config yaml using modeline

603 of 603 new or added lines in 3 files covered. (100.0%)

3462 of 4071 relevant lines covered (85.04%)

25.74 hits per line

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

88.57
/lib/src/code_generator/library.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:io';
6

7
import 'package:cli_util/cli_util.dart';
8
import 'package:ffigen/src/code_generator.dart';
9
import 'package:ffigen/src/config_provider/config_types.dart';
10
import 'package:logging/logging.dart';
11
import 'package:path/path.dart' as p;
12
import 'package:yaml_edit/yaml_edit.dart';
13

14
import '../strings.dart' as strings;
15
import 'utils.dart';
16
import 'writer.dart';
17

18
final _logger = Logger('ffigen.code_generator.library');
21✔
19

20
/// Container for all Bindings.
21
class Library {
22
  /// List of bindings in this library.
23
  late List<Binding> bindings;
24

25
  late Writer _writer;
26
  Writer get writer => _writer;
98✔
27

28
  Library({
52✔
29
    required String name,
30
    String? description,
31
    required List<Binding> bindings,
32
    String? header,
33
    bool sort = false,
34
    StructPackingOverride? packingOverride,
35
    Set<LibraryImport>? libraryImports,
36
  }) {
37
    /// Get all dependencies (includes itself).
38
    final dependencies = <Binding>{};
39
    for (final b in bindings) {
89✔
40
      b.addDependencies(dependencies);
37✔
41
    }
42

43
    /// Save bindings.
44
    this.bindings = dependencies.toList();
104✔
45

46
    if (sort) {
47
      _sort();
1✔
48
    }
49

50
    /// Handle any declaration-declaration name conflicts and emit warnings.
51
    final declConflictHandler = UniqueNamer({});
52✔
52
    for (final b in this.bindings) {
89✔
53
      _warnIfPrivateDeclaration(b);
37✔
54
      _resolveIfNameConflicts(declConflictHandler, b);
37✔
55
      _warnIfExposeSymbolAddressAndFfiNative(b);
37✔
56
    }
57

58
    // Override pack values according to config. We do this after declaration
59
    // conflicts have been handled so that users can target the generated names.
60
    if (packingOverride != null) {
61
      for (final b in this.bindings) {
81✔
62
        if (b is Struct && packingOverride.isOverriden(b.name)) {
83✔
63
          b.pack = packingOverride.getOverridenPackValue(b.name);
3✔
64
        }
65
      }
66
    }
67

68
    // Seperate bindings which require lookup.
69
    final lookUpBindings = this.bindings.whereType<LookUpBinding>().where((e) {
186✔
70
      if (e is Func) {
30✔
71
        return !e.ffiNativeConfig.enabled;
58✔
72
      }
73
      return true;
74
    }).toList();
52✔
75
    final ffiNativeBindings = this
76
        .bindings
52✔
77
        .whereType<Func>()
52✔
78
        .where((e) => e.ffiNativeConfig.enabled)
139✔
79
        .toList();
52✔
80
    final noLookUpBindings =
81
        this.bindings.whereType<NoLookUpBinding>().toList();
156✔
82

83
    _writer = Writer(
104✔
84
      lookUpBindings: lookUpBindings,
85
      ffiNativeBindings: ffiNativeBindings,
86
      noLookUpBindings: noLookUpBindings,
87
      className: name,
88
      classDocComment: description,
89
      header: header,
90
      additionalImports: libraryImports,
91
    );
92
  }
93

94
  /// Logs a warning if generated declaration will be private.
95
  void _warnIfPrivateDeclaration(Binding b) {
37✔
96
    if (b.name.startsWith('_') && !b.isInternal) {
79✔
97
      _logger.warning(
10✔
98
          "Generated declaration '${b.name}' start's with '_' and therefore will be private.");
10✔
99
    }
100
  }
101

102
  /// Resolves name conflict(if any) and logs a warning.
103
  void _resolveIfNameConflicts(UniqueNamer namer, Binding b) {
37✔
104
    // Print warning if name was conflicting and has been changed.
105
    if (namer.isUsed(b.name)) {
74✔
106
      final oldName = b.name;
5✔
107
      b.name = namer.makeUnique(b.name);
15✔
108

109
      _logger.warning(
10✔
110
          "Resolved name conflict: Declaration '$oldName' and has been renamed to '${b.name}'.");
10✔
111
    } else {
112
      namer.markUsed(b.name);
74✔
113
    }
114
  }
115

116
  /// Logs a warning if generated declaration will be private.
117
  void _warnIfExposeSymbolAddressAndFfiNative(Binding b) {
37✔
118
    if (b is Func) {
37✔
119
      if (b.exposeSymbolAddress && b.ffiNativeConfig.enabled) {
35✔
120
        _logger.warning(
×
121
            "Ignoring ${strings.symbolAddress} for '${b.name}' because it is generated as FfiNative.");
×
122
      }
123
    }
124
  }
125

126
  /// Sort all bindings in alphabetical order.
127
  void _sort() {
1✔
128
    bindings.sort((b1, b2) => b1.name.compareTo(b2.name));
6✔
129
  }
130

131
  /// Generates [file] by generating C bindings.
132
  ///
133
  /// If format is true(default), the formatter will be called to format the generated file.
134
  void generateFile(File file, {bool format = true}) {
38✔
135
    if (!file.existsSync()) file.createSync(recursive: true);
76✔
136
    file.writeAsStringSync(generate());
76✔
137
    if (format) {
138
      _dartFormat(file.path);
76✔
139
    }
140
  }
141

142
  /// Generates [file] with symbol output yaml.
143
  void generateSymbolOutputFile(File file, String importPath) {
1✔
144
    if (!file.existsSync()) file.createSync(recursive: true);
2✔
145
    final symbolFileYamlMap = writer.generateSymbolOutputYamlMap(importPath);
2✔
146
    final yamlEditor = YamlEditor("");
1✔
147
    yamlEditor.update([], wrapAsYamlNode(symbolFileYamlMap));
3✔
148
    var yamlString = yamlEditor.toString();
1✔
149
    if (!yamlString.endsWith('\n')) {
1✔
150
      yamlString += "\n";
1✔
151
    }
152
    file.writeAsStringSync(yamlString);
1✔
153
  }
154

155
  /// Formats a file using the Dart formatter.
156
  void _dartFormat(String path) {
38✔
157
    final sdkPath = getSdkPath();
38✔
158
    final result = Process.runSync(
38✔
159
        p.join(sdkPath, 'bin', 'dart'), ['format', path],
76✔
160
        runInShell: Platform.isWindows);
38✔
161
    if (result.stderr.toString().isNotEmpty) {
114✔
162
      _logger.severe(result.stderr);
×
163
      throw FormatException('Unable to format generated file: $path.');
×
164
    }
165
  }
166

167
  /// Generates the bindings.
168
  String generate() {
43✔
169
    return writer.generate();
86✔
170
  }
171

172
  @override
×
173
  bool operator ==(other) => other is Library && other.generate() == generate();
×
174

175
  @override
×
176
  int get hashCode => bindings.hashCode;
×
177
}
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