(Optionally) add an additional suffix namespace to generated fbs files. (#5698)
authorMichael Beardsworth <beardsworth@google.com>
Mon, 6 Jan 2020 18:00:59 +0000 (10:00 -0800)
committerWouter van Oortmerssen <aardappel@gmail.com>
Mon, 6 Jan 2020 18:00:59 +0000 (10:00 -0800)
This change allows for the generation of fbs files (from proto) that
don't contain name collisions with the protobuf generated C++ code,
allowing both the proto and fbs message types to be linked into the same binary.

include/flatbuffers/idl.h
src/flatc.cpp
src/idl_gen_fbs.cpp
tests/BUILD
tests/prototest/test_suffix.golden [new file with mode: 0644]
tests/prototest/test_union_suffix.golden [new file with mode: 0644]
tests/test.cpp

index 792103c..1f013a8 100644 (file)
@@ -557,6 +557,7 @@ struct IDLOptions {
   bool java_primitive_has_method;
   std::vector<std::string> cpp_includes;
   std::string cpp_std;
+  std::string proto_namespace_suffix;
 
   // Possible options for the more general generator below.
   enum Language {
index 8df2014..f13b336 100644 (file)
@@ -134,6 +134,8 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const {
     "                         This may crash flatc given a mismatched schema.\n"
     "  --size-prefixed        Input binaries are size prefixed buffers.\n"
     "  --proto                Input is a .proto, translate to .fbs.\n"
+    "  --proto-namespace-suffix Add this namespace to any flatbuffers generated\n"
+    "    SUFFIX                 from protobufs.\n"
     "  --oneof-union          Translate .proto oneofs to flatbuffer unions.\n"
     "  --grpc                 Generate GRPC interfaces for the specified languages.\n"
     "  --schema               Serialize schemas instead of JSON (use with -b).\n"
@@ -299,6 +301,9 @@ int FlatCompiler::Compile(int argc, const char **argv) {
         binary_files_from = filenames.size();
       } else if (arg == "--proto") {
         opts.proto_mode = true;
+      } else if (arg == "--proto-namespace-suffix") {
+        if (++argi >= argc) Error("missing namespace suffix" + arg, true);
+        opts.proto_namespace_suffix = argv[argi];
       } else if (arg == "--oneof-union") {
         opts.proto_oneof_union = true;
       } else if (arg == "--schema") {
index d3bee62..d2e1068 100644 (file)
@@ -63,6 +63,13 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name) {
     for (size_t i = 0; i < ns.from_table; i++) {
       ns.components[ns.components.size() - 1 - i] += "_";
     }
+
+    if (parser.opts.proto_mode && !parser.opts.proto_namespace_suffix.empty()) {
+      // Since we know that all these namespaces come from a .proto, and all are
+      // being converted, we can simply apply this suffix to all of them.
+      ns.components.insert(ns.components.end() - ns.from_table,
+                           parser.opts.proto_namespace_suffix);
+    }
   }
 
   std::string schema;
index 6308613..b61824c 100644 (file)
@@ -45,8 +45,10 @@ cc_test(
         ":prototest/test.golden",
         ":prototest/test.proto",
         ":prototest/test_include.golden",
+        ":prototest/test_suffix.golden",
         ":prototest/test_union.golden",
         ":prototest/test_union_include.golden",
+        ":prototest/test_union_suffix.golden",
         ":unicode_test.json",
         ":union_vector/union_vector.fbs",
         ":union_vector/union_vector.json",
diff --git a/tests/prototest/test_suffix.golden b/tests/prototest/test_suffix.golden
new file mode 100644 (file)
index 0000000..94ffd26
--- /dev/null
@@ -0,0 +1,59 @@
+// Generated from test.proto
+
+namespace proto.test.test_namespace_suffix;
+
+/// Enum doc comment.
+enum ProtoEnum : int {
+  NUL = 0,
+  FOO = 1,
+  /// Enum 2nd value doc comment misaligned.
+  BAR = 5,
+}
+
+table ImportedMessage {
+  a:int;
+}
+
+/// 2nd table doc comment with
+/// many lines.
+table ProtoMessage {
+  c:int = 16;
+  d:long;
+  p:uint;
+  e:ulong;
+  /// doc comment for f.
+  f:int = -1;
+  g:long;
+  h:uint;
+  q:ulong;
+  i:int;
+  j:long;
+  /// doc comment for k.
+  k:bool;
+  /// doc comment for l on 2
+  /// lines
+  l:string (required);
+  m:[ubyte];
+  n:proto.test.test_namespace_suffix.ProtoMessage_.OtherMessage;
+  o:[string];
+  z:proto.test.test_namespace_suffix.ImportedMessage;
+  /// doc comment for r.
+  r:proto.test.test_namespace_suffix.ProtoMessage_.Anonymous0;
+}
+
+namespace proto.test.test_namespace_suffix.ProtoMessage_;
+
+table OtherMessage {
+  a:double;
+  /// doc comment for b.
+  b:float = 3.14149;
+}
+
+table Anonymous0 {
+  /// doc comment for s.
+  s:proto.test.test_namespace_suffix.ImportedMessage;
+  /// doc comment for t on 2
+  /// lines.
+  t:proto.test.test_namespace_suffix.ProtoMessage_.OtherMessage;
+}
+
diff --git a/tests/prototest/test_union_suffix.golden b/tests/prototest/test_union_suffix.golden
new file mode 100644 (file)
index 0000000..0b0f920
--- /dev/null
@@ -0,0 +1,63 @@
+// Generated from test.proto
+
+namespace proto.test.test_namespace_suffix;
+
+/// Enum doc comment.
+enum ProtoEnum : int {
+  NUL = 0,
+  FOO = 1,
+  /// Enum 2nd value doc comment misaligned.
+  BAR = 5,
+}
+
+namespace proto.test.test_namespace_suffix.ProtoMessage_;
+
+union RUnion {
+  /// doc comment for s.
+  proto.test.test_namespace_suffix.ImportedMessage,
+  /// doc comment for t on 2
+  /// lines.
+  proto.test.test_namespace_suffix.ProtoMessage_.OtherMessage,
+}
+
+namespace proto.test.test_namespace_suffix;
+
+table ImportedMessage {
+  a:int;
+}
+
+/// 2nd table doc comment with
+/// many lines.
+table ProtoMessage {
+  c:int = 16;
+  d:long;
+  p:uint;
+  e:ulong;
+  /// doc comment for f.
+  f:int = -1;
+  g:long;
+  h:uint;
+  q:ulong;
+  i:int;
+  j:long;
+  /// doc comment for k.
+  k:bool;
+  /// doc comment for l on 2
+  /// lines
+  l:string (required);
+  m:[ubyte];
+  n:proto.test.test_namespace_suffix.ProtoMessage_.OtherMessage;
+  o:[string];
+  z:proto.test.test_namespace_suffix.ImportedMessage;
+  /// doc comment for r.
+  r:proto.test.test_namespace_suffix.ProtoMessage_.RUnion;
+}
+
+namespace proto.test.test_namespace_suffix.ProtoMessage_;
+
+table OtherMessage {
+  a:double;
+  /// doc comment for b.
+  b:float = 3.14149;
+}
+
index 88a7b8f..c63502b 100644 (file)
@@ -1128,6 +1128,58 @@ void ParseProtoTest() {
 }
 
 // Parse a .proto schema, output as .fbs
+void ParseProtoTestWithSuffix() {
+  // load the .proto and the golden file from disk
+  std::string protofile;
+  std::string goldenfile;
+  std::string goldenunionfile;
+  TEST_EQ(
+      flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
+                            false, &protofile),
+      true);
+  TEST_EQ(
+      flatbuffers::LoadFile((test_data_path + "prototest/test_suffix.golden").c_str(),
+                            false, &goldenfile),
+      true);
+  TEST_EQ(flatbuffers::LoadFile(
+              (test_data_path + "prototest/test_union_suffix.golden").c_str(), false,
+              &goldenunionfile),
+          true);
+
+  flatbuffers::IDLOptions opts;
+  opts.include_dependence_headers = false;
+  opts.proto_mode = true;
+  opts.proto_namespace_suffix = "test_namespace_suffix";
+
+  // Parse proto.
+  flatbuffers::Parser parser(opts);
+  auto protopath = test_data_path + "prototest/";
+  const char *include_directories[] = { protopath.c_str(), nullptr };
+  TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
+
+  // Generate fbs.
+  auto fbs = flatbuffers::GenerateFBS(parser, "test");
+
+  // Ensure generated file is parsable.
+  flatbuffers::Parser parser2;
+  TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
+  TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
+
+  // Parse proto with --oneof-union option.
+  opts.proto_oneof_union = true;
+  flatbuffers::Parser parser3(opts);
+  TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
+
+  // Generate fbs.
+  auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
+
+  // Ensure generated file is parsable.
+  flatbuffers::Parser parser4;
+  TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
+  TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
+}
+
+// Parse a .proto schema, output as .fbs
 void ParseProtoTestWithIncludes() {
   // load the .proto and the golden file from disk
   std::string protofile;
@@ -3261,6 +3313,7 @@ int FlatBufferTests() {
     FixedLengthArrayJsonTest(true);
     ReflectionTest(flatbuf.data(), flatbuf.size());
     ParseProtoTest();
+    ParseProtoTestWithSuffix();
     ParseProtoTestWithIncludes();
     EvolutionTest();
     UnionVectorTest();