From f069396d1b8f1afa7976cffa1f1f84acbb718963 Mon Sep 17 00:00:00 2001 From: Huw Rogers Date: Tue, 8 Jun 2021 19:23:05 +0100 Subject: [PATCH] [C++] flatc --cpp-field-case-style option to permit camel-case field names in C++ (#6669) * flatc --cpp-field-case option to permit camel-case field names in C++ * fixed option name; cleaned up tabs * formatting fixed to conform to CI * resolved comments * fixed white space indentation * per PR comments * rename snake case option to unchanged for clarity, per PR comments * cleanup of unchanged case option in C++ codegen, per PR 6669 comments * incorporated PR feedback from vglavnyy * cleaned up to pass Travis CI / clang format * bumped PR to retry transient CI failure * bumped PR to retry transient CI failure * bump PR * assert union type field name length > suffix, per PR 6669 comments --- include/flatbuffers/idl.h | 5 +++++ src/flatc.cpp | 16 ++++++++++++++++ src/idl_gen_cpp.cpp | 24 ++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 7e2a4e293..fa9bfefe4 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -536,6 +536,9 @@ struct ServiceDef : public Definition { // Container of options that may apply to any of the source/text generators. struct IDLOptions { + // field case style options for C++ + enum CaseStyle { CaseStyle_Unchanged = 0, CaseStyle_Upper, CaseStyle_Lower }; + bool gen_jvmstatic; // Use flexbuffers instead for binary and text generation bool use_flexbuffers; @@ -558,6 +561,7 @@ struct IDLOptions { std::string cpp_object_api_pointer_type; std::string cpp_object_api_string_type; bool cpp_object_api_string_flexible_constructor; + CaseStyle cpp_object_api_field_case_style; bool cpp_direct_copy; bool gen_nullable; bool java_checkerframework; @@ -651,6 +655,7 @@ struct IDLOptions { gen_compare(false), cpp_object_api_pointer_type("std::unique_ptr"), cpp_object_api_string_flexible_constructor(false), + cpp_object_api_field_case_style(CaseStyle_Unchanged), cpp_direct_copy(true), gen_nullable(false), java_checkerframework(false), diff --git a/src/flatc.cpp b/src/flatc.cpp index 221b88676..5d755a796 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -121,6 +121,11 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const { " (see the --cpp-str-flex-ctor option to change this behavior).\n" " --cpp-str-flex-ctor Don't construct custom string types by passing std::string\n" " from Flatbuffers, but (char* + length).\n" + " --cpp-field-case-style STYLE Generate C++ fields using selected case style.\n" + " Supported STYLE values:\n" + " * 'unchanged' - leave unchanged (default);\n" + " * 'upper' - schema snake_case emits UpperCamel;\n" + " * 'lower' - schema snake_case emits lowerCamel.\n" " --cpp-std CPP_STD Generate a C++ code using features of selected C++ standard.\n" " Supported CPP_STD values:\n" " * 'c++0x' - generate code compatible with old compilers;\n" @@ -275,6 +280,17 @@ int FlatCompiler::Compile(int argc, const char **argv) { opts.cpp_object_api_string_flexible_constructor = true; } else if (arg == "--no-cpp-direct-copy") { opts.cpp_direct_copy = false; + } else if (arg == "--cpp-field-case-style") { + if (++argi >= argc) Error("missing case style following: " + arg, true); + if (!strcmp(argv[argi], "unchanged")) + opts.cpp_object_api_field_case_style = + IDLOptions::CaseStyle_Unchanged; + else if (!strcmp(argv[argi], "upper")) + opts.cpp_object_api_field_case_style = IDLOptions::CaseStyle_Upper; + else if (!strcmp(argv[argi], "lower")) + opts.cpp_object_api_field_case_style = IDLOptions::CaseStyle_Lower; + else + Error("unknown case style: " + std::string(argv[argi]), true); } else if (arg == "--gen-nullable") { opts.gen_nullable = true; } else if (arg == "--java-checkerframework") { diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index e585d640a..201b32c9f 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -233,6 +233,30 @@ class CppGenerator : public BaseGenerator { return keywords_.find(name) == keywords_.end() ? name : name + "_"; } + std::string Name(const FieldDef &field) const { + // the union type field suffix is immutable. + static size_t union_suffix_len = strlen(UnionTypeFieldSuffix()); + const bool is_union_type = field.value.type.base_type == BASE_TYPE_UTYPE; + // early return if no case transformation required + if (opts_.cpp_object_api_field_case_style == + IDLOptions::CaseStyle_Unchanged) + return EscapeKeyword(field.name); + std::string name = field.name; + // do not change the case style of the union type field suffix + if (is_union_type) { + FLATBUFFERS_ASSERT(name.length() > union_suffix_len); + name.erase(name.length() - union_suffix_len, union_suffix_len); + } + if (opts_.cpp_object_api_field_case_style == IDLOptions::CaseStyle_Upper) + name = MakeCamel(name, true); /* upper */ + else if (opts_.cpp_object_api_field_case_style == + IDLOptions::CaseStyle_Lower) + name = MakeCamel(name, false); /* lower */ + // restore the union field type suffix + if (is_union_type) name.append(UnionTypeFieldSuffix(), union_suffix_len); + return EscapeKeyword(name); + } + std::string Name(const Definition &def) const { return EscapeKeyword(def.name); }