From 30e7d161049482a8196036e0726fd25227498aa6 Mon Sep 17 00:00:00 2001 From: Yonggang Li Date: Mon, 9 Oct 2017 08:40:17 -0700 Subject: [PATCH] _Nullable cpp interface (#4451) * add _Nullable Support for C++ interface * add _Nullable Support for C++ interface --- include/flatbuffers/idl.h | 2 ++ src/flatc.cpp | 3 +++ src/idl_gen_cpp.cpp | 23 ++++++++++++++++++----- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 4fa401e..201d15b 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -372,6 +372,7 @@ struct IDLOptions { bool generate_object_based_api; std::string cpp_object_api_pointer_type; std::string cpp_object_api_string_type; + bool clang_nullable; std::string object_prefix; std::string object_suffix; bool union_value_namespacing; @@ -426,6 +427,7 @@ struct IDLOptions { generate_name_strings(false), generate_object_based_api(false), cpp_object_api_pointer_type("std::unique_ptr"), + clang_nullable(false), object_suffix("T"), union_value_namespacing(true), allow_non_utf8(false), diff --git a/src/flatc.cpp b/src/flatc.cpp index 701f6fb..ef77b0a 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -89,6 +89,7 @@ std::string FlatCompiler::GetUsageString(const char* program_name) const { " --cpp-ptr-type T Set object API pointer type (default std::unique_ptr)\n" " --cpp-str-type T Set object API string type (default std::string)\n" " T::c_str() and T::length() must be supported\n" + " --clang-nullable Add Clang _Nullable for C++ pointers.\n" " --object-prefix Customise class prefix for C++ object-based API.\n" " --object-suffix Customise class suffix for C++ object-based API.\n" " Default value is \"T\"\n" @@ -205,6 +206,8 @@ int FlatCompiler::Compile(int argc, const char** argv) { } else if (arg == "--cpp-str-type") { if (++argi >= argc) Error("missing type following" + arg, true); opts.cpp_object_api_string_type = argv[argi]; + } else if (arg == "--clang-nullable") { + opts.clang_nullable = true; } else if (arg == "--object-prefix") { if (++argi >= argc) Error("missing prefix following" + arg, true); opts.object_prefix = argv[argi]; diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 58b0170..6df59e2 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -127,6 +127,10 @@ class CppGenerator : public BaseGenerator { code_ += "#define " + include_guard; code_ += ""; + if (parser_.opts.clang_nullable) { + code_ += "#pragma clang system_header\n\n"; + } + code_ += "#include \"flatbuffers/flatbuffers.h\""; if (parser_.uses_flexbuffers_) { code_ += "#include \"flatbuffers/flexbuffers.h\""; @@ -244,10 +248,11 @@ class CppGenerator : public BaseGenerator { code_.SetValue("STRUCT_NAME", name); code_.SetValue("CPP_NAME", cpp_name); + code_.SetValue("NULLABLE_EXT", NullableExtension()); // The root datatype accessor: code_ += "inline \\"; - code_ += "const {{CPP_NAME}} *Get{{STRUCT_NAME}}(const void *buf) {"; + code_ += "const {{CPP_NAME}} *{{NULLABLE_EXT}}Get{{STRUCT_NAME}}(const void *buf) {"; code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);"; code_ += "}"; code_ += ""; @@ -427,6 +432,10 @@ class CppGenerator : public BaseGenerator { } } + std::string NullableExtension() { + return parser_.opts.clang_nullable ? " _Nullable " : ""; + } + static std::string NativeName(const std::string &name, const StructDef *sd, const IDLOptions & opts) { return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix : name; } @@ -1469,10 +1478,12 @@ class CppGenerator : public BaseGenerator { } call += ")"; + std::string afterptr = " *" + NullableExtension(); GenComment(field.doc_comment, " "); code_.SetValue("FIELD_TYPE", - GenTypeGet(field.value.type, " ", "const ", " *", true)); + GenTypeGet(field.value.type, " ", "const ", afterptr.c_str(), true)); code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call)); + code_.SetValue("NULLABLE_EXT", NullableExtension()); code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {"; code_ += " return {{FIELD_VALUE}};"; @@ -1482,7 +1493,7 @@ class CppGenerator : public BaseGenerator { auto u = field.value.type.enum_def; code_ += " template " - "const T *{{FIELD_NAME}}_as() const;"; + "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;"; for (auto u_it = u->vals.vec.begin(); u_it != u->vals.vec.end(); ++u_it) { @@ -1499,9 +1510,10 @@ class CppGenerator : public BaseGenerator { code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *"); code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev)); + code_.SetValue("U_NULLABLE", NullableExtension()); // `const Type *union_name_asType() const` accessor. - code_ += " {{U_FIELD_TYPE}}{{U_FIELD_NAME}}() const {"; + code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {"; code_ += " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? " "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) " ": nullptr;"; @@ -1524,7 +1536,8 @@ class CppGenerator : public BaseGenerator { code_ += " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, {{DEFAULT_VALUE}});"; code_ += " }"; } else { - auto type = GenTypeGet(field.value.type, " ", "", " *", true); + auto postptr = " *" + NullableExtension(); + auto type = GenTypeGet(field.value.type, " ", "", postptr.c_str(), true); auto underlying = accessor + type + ">(" + offset_str + ")"; code_.SetValue("FIELD_TYPE", type); code_.SetValue("FIELD_VALUE", -- 2.7.4