diff --git a/dart/test/bool_structs_generated.dart b/dart/test/bool_structs_generated.dart index b123ba12f26..5348aebab84 100644 --- a/dart/test/bool_structs_generated.dart +++ b/dart/test/bool_structs_generated.dart @@ -5,6 +5,7 @@ import 'dart:typed_data' show Uint8List; import 'package:flat_buffers/flat_buffers.dart' as fb; + class Foo { Foo._(this._bc, this._bcOffset); factory Foo(List bytes) { diff --git a/dart/test/enums_generated.dart b/dart/test/enums_generated.dart index e2b8c50df7d..fd7fc20699e 100644 --- a/dart/test/enums_generated.dart +++ b/dart/test/enums_generated.dart @@ -5,6 +5,7 @@ import 'dart:typed_data' show Uint8List; import 'package:flat_buffers/flat_buffers.dart' as fb; + enum OptionsEnum { A(1), B(2), diff --git a/dart/test/include_test2_my_game.other_name_space_generated.dart b/dart/test/include_test2_my_game.other_name_space_generated.dart index 365ed3ceb5d..12ce70434c5 100644 --- a/dart/test/include_test2_my_game.other_name_space_generated.dart +++ b/dart/test/include_test2_my_game.other_name_space_generated.dart @@ -7,6 +7,7 @@ import 'dart:typed_data' show Uint8List; import 'package:flat_buffers/flat_buffers.dart' as fb; +export './include_test1_generated.dart'; import './include_test1_generated.dart'; enum FromInclude { diff --git a/dart/test/includes_a.fbs b/dart/test/includes_a.fbs new file mode 100644 index 00000000000..d0339a11970 --- /dev/null +++ b/dart/test/includes_a.fbs @@ -0,0 +1,5 @@ +namespace a; + +table a { + options: uint8; +} diff --git a/dart/test/includes_a_a_generated.dart b/dart/test/includes_a_a_generated.dart new file mode 100644 index 00000000000..f8460ed60c7 --- /dev/null +++ b/dart/test/includes_a_a_generated.dart @@ -0,0 +1,108 @@ +// automatically generated by the FlatBuffers compiler, do not modify +// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable, constant_identifier_names + +library a; + +import 'dart:typed_data' show Uint8List; +import 'package:flat_buffers/flat_buffers.dart' as fb; + + + +class A { + A._(this._bc, this._bcOffset); + factory A(List bytes) { + final rootRef = fb.BufferContext.fromBytes(bytes); + return reader.read(rootRef, 0); + } + + static const fb.Reader reader = _AReader(); + + final fb.BufferContext _bc; + final int _bcOffset; + + int get options => const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 4, 0); + + @override + String toString() { + return 'A{options: ${options}}'; + } + + AT unpack() => AT( + options: options); + + static int pack(fb.Builder fbBuilder, AT? object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class AT implements fb.Packable { + int options; + + AT({ + this.options = 0}); + + @override + int pack(fb.Builder fbBuilder) { + fbBuilder.startTable(1); + fbBuilder.addUint8(0, options); + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'AT{options: ${options}}'; + } +} + +class _AReader extends fb.TableReader { + const _AReader(); + + @override + A createObject(fb.BufferContext bc, int offset) => + A._(bc, offset); +} + +class ABuilder { + ABuilder(this.fbBuilder); + + final fb.Builder fbBuilder; + + void begin() { + fbBuilder.startTable(1); + } + + int addOptions(int? options) { + fbBuilder.addUint8(0, options); + return fbBuilder.offset; + } + + int finish() { + return fbBuilder.endTable(); + } +} + +class AObjectBuilder extends fb.ObjectBuilder { + final int? _options; + + AObjectBuilder({ + int? options, + }) + : _options = options; + + /// Finish building, and store into the [fbBuilder]. + @override + int finish(fb.Builder fbBuilder) { + fbBuilder.startTable(1); + fbBuilder.addUint8(0, _options); + return fbBuilder.endTable(); + } + + /// Convenience method to serialize to byte list. + @override + Uint8List toBytes([String? fileIdentifier]) { + final fbBuilder = fb.Builder(deduplicateTables: false); + fbBuilder.finish(finish(fbBuilder), fileIdentifier); + return fbBuilder.buffer; + } +} diff --git a/dart/test/includes_b.fbs b/dart/test/includes_b.fbs new file mode 100644 index 00000000000..c356b09d309 --- /dev/null +++ b/dart/test/includes_b.fbs @@ -0,0 +1,7 @@ +include 'includes_a.fbs'; + +namespace a; + +table b { + my_a: a; +} diff --git a/dart/test/includes_b_a_generated.dart b/dart/test/includes_b_a_generated.dart new file mode 100644 index 00000000000..dceecbf1276 --- /dev/null +++ b/dart/test/includes_b_a_generated.dart @@ -0,0 +1,112 @@ +// automatically generated by the FlatBuffers compiler, do not modify +// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable, constant_identifier_names + +library a; + +import 'dart:typed_data' show Uint8List; +import 'package:flat_buffers/flat_buffers.dart' as fb; + + +export './includes_a_a_generated.dart'; +import './includes_a_a_generated.dart'; + +class B { + B._(this._bc, this._bcOffset); + factory B(List bytes) { + final rootRef = fb.BufferContext.fromBytes(bytes); + return reader.read(rootRef, 0); + } + + static const fb.Reader reader = _BReader(); + + final fb.BufferContext _bc; + final int _bcOffset; + + A? get myA => A.reader.vTableGetNullable(_bc, _bcOffset, 4); + + @override + String toString() { + return 'B{myA: ${myA}}'; + } + + BT unpack() => BT( + myA: myA?.unpack()); + + static int pack(fb.Builder fbBuilder, BT? object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class BT implements fb.Packable { + AT? myA; + + BT({ + this.myA}); + + @override + int pack(fb.Builder fbBuilder) { + final int? myAOffset = myA?.pack(fbBuilder); + fbBuilder.startTable(1); + fbBuilder.addOffset(0, myAOffset); + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'BT{myA: ${myA}}'; + } +} + +class _BReader extends fb.TableReader { + const _BReader(); + + @override + B createObject(fb.BufferContext bc, int offset) => + B._(bc, offset); +} + +class BBuilder { + BBuilder(this.fbBuilder); + + final fb.Builder fbBuilder; + + void begin() { + fbBuilder.startTable(1); + } + + int addMyAOffset(int? offset) { + fbBuilder.addOffset(0, offset); + return fbBuilder.offset; + } + + int finish() { + return fbBuilder.endTable(); + } +} + +class BObjectBuilder extends fb.ObjectBuilder { + final AObjectBuilder? _myA; + + BObjectBuilder({ + AObjectBuilder? myA, + }) + : _myA = myA; + + /// Finish building, and store into the [fbBuilder]. + @override + int finish(fb.Builder fbBuilder) { + final int? myAOffset = _myA?.getOrCreateOffset(fbBuilder); + fbBuilder.startTable(1); + fbBuilder.addOffset(0, myAOffset); + return fbBuilder.endTable(); + } + + /// Convenience method to serialize to byte list. + @override + Uint8List toBytes([String? fileIdentifier]) { + final fbBuilder = fb.Builder(deduplicateTables: false); + fbBuilder.finish(finish(fbBuilder), fileIdentifier); + return fbBuilder.buffer; + } +} diff --git a/dart/test/includes_c.fbs b/dart/test/includes_c.fbs new file mode 100644 index 00000000000..da9bb2742c7 --- /dev/null +++ b/dart/test/includes_c.fbs @@ -0,0 +1,8 @@ +include 'includes_b.fbs'; + +namespace a; + +table c { + my_a: a; + my_b: b; +} diff --git a/dart/test/includes_c_a_generated.dart b/dart/test/includes_c_a_generated.dart new file mode 100644 index 00000000000..720ce2bd4f0 --- /dev/null +++ b/dart/test/includes_c_a_generated.dart @@ -0,0 +1,127 @@ +// automatically generated by the FlatBuffers compiler, do not modify +// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable, constant_identifier_names + +library a; + +import 'dart:typed_data' show Uint8List; +import 'package:flat_buffers/flat_buffers.dart' as fb; + + +export './includes_b_a_generated.dart'; +import './includes_b_a_generated.dart'; + +class C { + C._(this._bc, this._bcOffset); + factory C(List bytes) { + final rootRef = fb.BufferContext.fromBytes(bytes); + return reader.read(rootRef, 0); + } + + static const fb.Reader reader = _CReader(); + + final fb.BufferContext _bc; + final int _bcOffset; + + A? get myA => A.reader.vTableGetNullable(_bc, _bcOffset, 4); + B? get myB => B.reader.vTableGetNullable(_bc, _bcOffset, 6); + + @override + String toString() { + return 'C{myA: ${myA}, myB: ${myB}}'; + } + + CT unpack() => CT( + myA: myA?.unpack(), + myB: myB?.unpack()); + + static int pack(fb.Builder fbBuilder, CT? object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class CT implements fb.Packable { + AT? myA; + BT? myB; + + CT({ + this.myA, + this.myB}); + + @override + int pack(fb.Builder fbBuilder) { + final int? myAOffset = myA?.pack(fbBuilder); + final int? myBOffset = myB?.pack(fbBuilder); + fbBuilder.startTable(2); + fbBuilder.addOffset(0, myAOffset); + fbBuilder.addOffset(1, myBOffset); + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'CT{myA: ${myA}, myB: ${myB}}'; + } +} + +class _CReader extends fb.TableReader { + const _CReader(); + + @override + C createObject(fb.BufferContext bc, int offset) => + C._(bc, offset); +} + +class CBuilder { + CBuilder(this.fbBuilder); + + final fb.Builder fbBuilder; + + void begin() { + fbBuilder.startTable(2); + } + + int addMyAOffset(int? offset) { + fbBuilder.addOffset(0, offset); + return fbBuilder.offset; + } + int addMyBOffset(int? offset) { + fbBuilder.addOffset(1, offset); + return fbBuilder.offset; + } + + int finish() { + return fbBuilder.endTable(); + } +} + +class CObjectBuilder extends fb.ObjectBuilder { + final AObjectBuilder? _myA; + final BObjectBuilder? _myB; + + CObjectBuilder({ + AObjectBuilder? myA, + BObjectBuilder? myB, + }) + : _myA = myA, + _myB = myB; + + /// Finish building, and store into the [fbBuilder]. + @override + int finish(fb.Builder fbBuilder) { + final int? myAOffset = _myA?.getOrCreateOffset(fbBuilder); + final int? myBOffset = _myB?.getOrCreateOffset(fbBuilder); + fbBuilder.startTable(2); + fbBuilder.addOffset(0, myAOffset); + fbBuilder.addOffset(1, myBOffset); + return fbBuilder.endTable(); + } + + /// Convenience method to serialize to byte list. + @override + Uint8List toBytes([String? fileIdentifier]) { + final fbBuilder = fb.Builder(deduplicateTables: false); + fbBuilder.finish(finish(fbBuilder), fileIdentifier); + return fbBuilder.buffer; + } +} diff --git a/dart/test/includes_test.dart b/dart/test/includes_test.dart new file mode 100644 index 00000000000..8e97ed14868 --- /dev/null +++ b/dart/test/includes_test.dart @@ -0,0 +1,11 @@ +import 'package:test/test.dart'; + +import './includes_c_a_generated.dart'; + +void main() { + group("Recursive import test", () { + test("Test importing a fbs file that imports another fbs file", () { + CT(); + }); + }); +} diff --git a/dart/test/monster_test_my_game.example2_generated.dart b/dart/test/monster_test_my_game.example2_generated.dart index c266f9ce72b..5ddd9ac951e 100644 --- a/dart/test/monster_test_my_game.example2_generated.dart +++ b/dart/test/monster_test_my_game.example2_generated.dart @@ -9,6 +9,7 @@ import 'package:flat_buffers/flat_buffers.dart' as fb; import './monster_test_my_game_generated.dart' as my_game; import './monster_test_my_game.example_generated.dart' as my_game_example; +export './include_test1_generated.dart'; import './include_test1_generated.dart'; class Monster { diff --git a/dart/test/monster_test_my_game.example_generated.dart b/dart/test/monster_test_my_game.example_generated.dart index 5554c4c4b1d..566fcc4d46b 100644 --- a/dart/test/monster_test_my_game.example_generated.dart +++ b/dart/test/monster_test_my_game.example_generated.dart @@ -9,6 +9,7 @@ import 'package:flat_buffers/flat_buffers.dart' as fb; import './monster_test_my_game_generated.dart' as my_game; import './monster_test_my_game.example2_generated.dart' as my_game_example2; +export './include_test1_generated.dart'; import './include_test1_generated.dart'; /// Composite components of Monster color. diff --git a/dart/test/monster_test_my_game_generated.dart b/dart/test/monster_test_my_game_generated.dart index 461d06dfa85..8e3921b7d32 100644 --- a/dart/test/monster_test_my_game_generated.dart +++ b/dart/test/monster_test_my_game_generated.dart @@ -9,6 +9,7 @@ import 'package:flat_buffers/flat_buffers.dart' as fb; import './monster_test_my_game.example_generated.dart' as my_game_example; import './monster_test_my_game.example2_generated.dart' as my_game_example2; +export './include_test1_generated.dart'; import './include_test1_generated.dart'; class InParentNamespace { diff --git a/src/idl_gen_dart.cpp b/src/idl_gen_dart.cpp index f0df15da0f8..4a1e46248af 100644 --- a/src/idl_gen_dart.cpp +++ b/src/idl_gen_dart.cpp @@ -89,7 +89,8 @@ class DartGenerator : public BaseGenerator { DartKeywords()) {} template - void import_generator(const std::vector &definitions, + void import_generator(const std::string ¤t_namespace, + const std::vector &definitions, const std::string &included, std::set &imports) { for (const auto &item : definitions) { @@ -100,10 +101,15 @@ class DartGenerator : public BaseGenerator { std::string filename = namer_.File(filebase + (component.empty() ? "" : "_" + component)); + std::string rename_namespace = component == current_namespace ? "" : component; imports.emplace("import './" + filename + "'" + - (component.empty() + (rename_namespace.empty() ? ";\n" - : " as " + ImportAliasName(component) + ";\n")); + : " as " + ImportAliasName(rename_namespace) + ";\n")); + + if (rename_namespace.empty()) { + imports.emplace("export './" + filename + "';\n"); + } } } } @@ -116,20 +122,6 @@ class DartGenerator : public BaseGenerator { GenerateEnums(namespace_code); GenerateStructs(namespace_code); - std::set imports; - - for (const auto &included_file : parser_.GetIncludedFiles()) { - if (included_file.filename == parser_.file_being_parsed_) continue; - - import_generator(parser_.structs_.vec, included_file.filename, imports); - import_generator(parser_.enums_.vec, included_file.filename, imports); - } - - std::string import_code = ""; - for (const auto &file : imports) { import_code += file; } - - import_code += import_code.empty() ? "" : "\n"; - for (auto kv = namespace_code.begin(); kv != namespace_code.end(); ++kv) { code.clear(); code = code + "// " + FlatBuffersGeneratedWarning() + "\n"; @@ -152,8 +144,19 @@ class DartGenerator : public BaseGenerator { } code += "\n"; - code += import_code; + std::set imports; + for (const auto &included_file : parser_.GetIncludedFiles()) { + if (included_file.filename == parser_.file_being_parsed_) continue; + + import_generator(kv->first, parser_.structs_.vec, + included_file.filename, imports); + import_generator(kv->first, parser_.enums_.vec, included_file.filename, + imports); + } + for (const auto &import_code : imports) { code += import_code; } + + code += "\n"; code += kv->second; if (!SaveFile(Filename(kv->first).c_str(), code, false)) { return false; } @@ -366,7 +369,14 @@ class DartGenerator : public BaseGenerator { } else if (type.enum_def->is_union) { return "dynamic"; } else if (type.base_type != BASE_TYPE_VECTOR) { - return namer_.Type(*type.enum_def); + const std::string cur_namespace = namer_.Namespace(*current_namespace); + std::string enum_namespace = + namer_.Namespace(*type.enum_def->defined_namespace); + std::string typeName = namer_.Type(*type.enum_def); + if (enum_namespace != "" && enum_namespace != cur_namespace) { + typeName = enum_namespace + "." + typeName; + } + return typeName; } } diff --git a/tests/DartTest.sh b/tests/DartTest.sh index 6907da823c2..9583ad43adc 100755 --- a/tests/DartTest.sh +++ b/tests/DartTest.sh @@ -34,6 +34,7 @@ cd ../dart ../flatc --dart --gen-object-api -o ./test ./test/enums.fbs ../flatc --dart --gen-object-api -o ./test ./test/bool_structs.fbs +../flatc --dart --gen-object-api -o ./test ./test/includes_*.fbs # update packages dart pub get