Coverage Report

Created: 2026-05-30 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/flatbuffers/include/codegen/namer.h
Line
Count
Source
1
#ifndef FLATBUFFERS_INCLUDE_CODEGEN_NAMER_H_
2
#define FLATBUFFERS_INCLUDE_CODEGEN_NAMER_H_
3
4
#include "flatbuffers/util.h"
5
6
namespace flatbuffers {
7
8
// Options for Namer::File.
9
enum class SkipFile {
10
  None = 0,
11
  Suffix = 1,
12
  Extension = 2,
13
  SuffixAndExtension = 3,
14
};
15
0
inline SkipFile operator&(SkipFile a, SkipFile b) {
16
0
  return static_cast<SkipFile>(static_cast<int>(a) & static_cast<int>(b));
17
0
}
18
// Options for Namer::Directories
19
enum class SkipDir {
20
  None = 0,
21
  // Skip prefixing the -o $output_path.
22
  OutputPath = 1,
23
  // Skip trailing path seperator.
24
  TrailingPathSeperator = 2,
25
  OutputPathAndTrailingPathSeparator = 3,
26
};
27
0
inline SkipDir operator&(SkipDir a, SkipDir b) {
28
0
  return static_cast<SkipDir>(static_cast<int>(a) & static_cast<int>(b));
29
0
}
30
31
// `Namer` applies style configuration to symbols in generated code. It manages
32
// casing, escapes keywords, and object API naming.
33
// TODO: Refactor all code generators to use this.
34
class Namer {
35
 public:
36
  struct Config {
37
    // Symbols in code.
38
39
    // Case style for flatbuffers-defined types.
40
    // e.g. `class TableA {}`
41
    Case types;
42
    // Case style for flatbuffers-defined constants.
43
    // e.g. `uint64_t ENUM_A_MAX`;
44
    Case constants;
45
    // Case style for flatbuffers-defined methods.
46
    // e.g. `class TableA { int field_a(); }`
47
    Case methods;
48
    // Case style for flatbuffers-defined functions.
49
    // e.g. `TableA* get_table_a_root()`;
50
    Case functions;
51
    // Case style for flatbuffers-defined fields.
52
    // e.g. `struct Struct { int my_field; }`
53
    Case fields;
54
    // Case style for flatbuffers-defined variables.
55
    // e.g. `int my_variable = 2`
56
    Case variables;
57
    // Case style for flatbuffers-defined variants.
58
    // e.g. `enum class Enum { MyVariant, }`
59
    Case variants;
60
    // Seperator for qualified enum names.
61
    // e.g. `Enum::MyVariant` uses `::`.
62
    std::string enum_variant_seperator;
63
64
    // Configures, when formatting code, whether symbols are checked against
65
    // keywords and escaped before or after case conversion. It does not make
66
    // sense to do so before, but its legacy behavior. :shrug:
67
    // TODO(caspern): Deprecate.
68
    enum class Escape {
69
      BeforeConvertingCase,
70
      AfterConvertingCase,
71
    };
72
    Escape escape_keywords;
73
74
    // Namespaces
75
76
    // e.g. `namespace my_namespace {}`
77
    Case namespaces;
78
    // The seperator between namespaces in a namespace path.
79
    std::string namespace_seperator;
80
81
    // Object API.
82
    // Native versions flatbuffers types have this prefix.
83
    // e.g. "" (it's usually empty string)
84
    std::string object_prefix;
85
    // Native versions flatbuffers types have this suffix.
86
    // e.g. "T"
87
    std::string object_suffix;
88
89
    // Keywords.
90
    // Prefix used to escape keywords. It is usually empty string.
91
    std::string keyword_prefix;
92
    // Suffix used to escape keywords. It is usually "_".
93
    std::string keyword_suffix;
94
    // The casing used for keywords when escaping. For most languages, keywords
95
    // are case sensitive. PHP is an instance where some keywords are case
96
    // insensitive.
97
    enum class KeywordsCasing {
98
      CaseSensitive,
99
      CaseInsensitive,
100
    };
101
    KeywordsCasing keywords_casing;
102
103
    // Files.
104
105
    // Case style for filenames. e.g. `foo_bar_generated.rs`
106
    Case filenames;
107
    // Case style for directories, e.g. `output_files/foo_bar/baz/`
108
    Case directories;
109
    // The directory within which we will generate files.
110
    std::string output_path;
111
    // Suffix for generated file names, e.g. "_generated".
112
    std::string filename_suffix;
113
    // Extension for generated files, e.g. ".cpp" or ".rs".
114
    std::string filename_extension;
115
  };
116
  Namer(Config config, std::set<std::string> keywords)
117
0
      : config_(config), keywords_(std::move(keywords)) {}
118
119
0
  virtual ~Namer() {}
120
121
  template <typename T>
122
0
  std::string Method(const T& s) const {
123
0
    return Method(s.name);
124
0
  }
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::Namer::Method<flatbuffers::FieldDef>(flatbuffers::FieldDef const&) const
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::Namer::Method<flatbuffers::EnumVal>(flatbuffers::EnumVal const&) const
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::Namer::Method<flatbuffers::EnumDef>(flatbuffers::EnumDef const&) const
125
126
  virtual std::string Method(const std::string& pre, const std::string& mid,
127
0
                             const std::string& suf) const {
128
0
    return Format(pre + "_" + mid + "_" + suf, config_.methods);
129
0
  }
130
  virtual std::string Method(const std::string& pre,
131
0
                             const std::string& suf) const {
132
0
    return Format(pre + "_" + suf, config_.methods);
133
0
  }
134
0
  virtual std::string Method(const std::string& s) const {
135
0
    return Format(s, config_.methods);
136
0
  }
137
138
0
  virtual std::string Constant(const std::string& s) const {
139
0
    return Format(s, config_.constants);
140
0
  }
141
142
0
  virtual std::string Function(const std::string& s) const {
143
0
    return Format(s, config_.functions);
144
0
  }
145
146
0
  virtual std::string Variable(const std::string& s) const {
147
0
    return Format(s, config_.variables);
148
0
  }
149
150
  template <typename T>
151
0
  std::string Variable(const std::string& p, const T& s) const {
152
0
    return Format(p + "_" + s.name, config_.variables);
153
0
  }
154
  virtual std::string Variable(const std::string& p,
155
0
                               const std::string& s) const {
156
0
    return Format(p + "_" + s, config_.variables);
157
0
  }
158
159
0
  virtual std::string Namespace(const std::string& s) const {
160
0
    return Format(s, config_.namespaces);
161
0
  }
162
163
0
  virtual std::string Namespace(const std::vector<std::string>& ns) const {
164
0
    std::string result;
165
0
    for (auto it = ns.begin(); it != ns.end(); it++) {
166
0
      if (it != ns.begin()) result += config_.namespace_seperator;
167
0
      result += Namespace(*it);
168
0
    }
169
0
    return result;
170
0
  }
171
172
  virtual std::string NamespacedType(const std::vector<std::string>& ns,
173
0
                                     const std::string& s) const {
174
0
    return (ns.empty() ? "" : (Namespace(ns) + config_.namespace_seperator)) +
175
0
           Type(s);
176
0
  }
177
178
  // Returns `filename` with the right casing, suffix, and extension.
179
  virtual std::string File(const std::string& filename,
180
0
                           SkipFile skips = SkipFile::None) const {
181
0
    const bool skip_suffix = (skips & SkipFile::Suffix) != SkipFile::None;
182
0
    const bool skip_ext = (skips & SkipFile::Extension) != SkipFile::None;
183
0
    return ConvertCase(filename, config_.filenames, Case::kUpperCamel) +
184
0
           (skip_suffix ? "" : config_.filename_suffix) +
185
0
           (skip_ext ? "" : config_.filename_extension);
186
0
  }
187
  template <typename T>
188
0
  std::string File(const T& f, SkipFile skips = SkipFile::None) const {
189
0
    return File(f.name, skips);
190
0
  }
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::Namer::File<flatbuffers::Definition>(flatbuffers::Definition const&, flatbuffers::SkipFile) const
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::Namer::File<flatbuffers::StructDef>(flatbuffers::StructDef const&, flatbuffers::SkipFile) const
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::Namer::File<flatbuffers::EnumDef>(flatbuffers::EnumDef const&, flatbuffers::SkipFile) const
191
192
  // Formats `directories` prefixed with the output_path and joined with the
193
  // right seperator. Output path prefixing and the trailing separator may be
194
  // skiped using `skips`.
195
  // Callers may want to use `EnsureDirExists` with the result.
196
  // input_case is used to tell how to modify namespace. e.g. kUpperCamel will
197
  // add a underscode between case changes, so MyGame turns into My_Game
198
  // (depending also on the output_case).
199
  virtual std::string Directories(const std::vector<std::string>& directories,
200
                                  SkipDir skips = SkipDir::None,
201
0
                                  Case input_case = Case::kUpperCamel) const {
202
0
    const bool skip_output_path =
203
0
        (skips & SkipDir::OutputPath) != SkipDir::None;
204
0
    const bool skip_trailing_seperator =
205
0
        (skips & SkipDir::TrailingPathSeperator) != SkipDir::None;
206
0
    std::string result = skip_output_path ? "" : config_.output_path;
207
0
    for (auto d = directories.begin(); d != directories.end(); d++) {
208
0
      result += ConvertCase(*d, config_.directories, input_case);
209
0
      result.push_back(kPathSeparator);
210
0
    }
211
0
    if (skip_trailing_seperator && !result.empty()) result.pop_back();
212
0
    return result;
213
0
  }
214
215
0
  virtual std::string NormalizeKeywordCase(const std::string& name) const {
216
0
    if (config_.keywords_casing == Config::KeywordsCasing::CaseInsensitive) {
217
0
      return ConvertCase(name, Case::kAllLower);
218
0
    } else {
219
0
      return name;
220
0
    }
221
0
  }
222
223
0
  virtual std::string EscapeKeyword(const std::string& name) const {
224
0
    if (keywords_.find(NormalizeKeywordCase(name)) == keywords_.end()) {
225
0
      return name;
226
0
    } else {
227
0
      return config_.keyword_prefix + name + config_.keyword_suffix;
228
0
    }
229
0
  }
230
231
0
  virtual std::string Type(const std::string& s) const {
232
0
    return Format(s, config_.types);
233
0
  }
234
0
  virtual std::string Type(const std::string& t, const std::string& s) const {
235
0
    return Format(t + "_" + s, config_.types);
236
0
  }
237
238
0
  virtual std::string ObjectType(const std::string& s) const {
239
0
    return config_.object_prefix + Type(s) + config_.object_suffix;
240
0
  }
241
242
0
  virtual std::string Field(const std::string& s) const {
243
0
    return Format(s, config_.fields);
244
0
  }
245
246
0
  virtual std::string Variant(const std::string& s) const {
247
0
    return Format(s, config_.variants);
248
0
  }
249
250
0
  virtual std::string Format(const std::string& s, Case casing) const {
251
0
    if (config_.escape_keywords == Config::Escape::BeforeConvertingCase) {
252
0
      return ConvertCase(EscapeKeyword(s), casing, Case::kLowerCamel);
253
0
    } else {
254
0
      return EscapeKeyword(ConvertCase(s, casing, Case::kLowerCamel));
255
0
    }
256
0
  }
257
258
  // Denamespaces a string (e.g. The.Quick.Brown.Fox) by returning the last part
259
  // after the `delimiter` (Fox) and placing the rest in `namespace_prefix`
260
  // (The.Quick.Brown).
261
  virtual std::string Denamespace(const std::string& s,
262
                                  std::string& namespace_prefix,
263
0
                                  const char delimiter = '.') const {
264
0
    const size_t pos = s.find_last_of(delimiter);
265
0
    if (pos == std::string::npos) {
266
0
      namespace_prefix = "";
267
0
      return s;
268
0
    }
269
0
    namespace_prefix = s.substr(0, pos);
270
0
    return s.substr(pos + 1);
271
0
  }
272
273
  // Same as above, but disregards the prefix.
274
  virtual std::string Denamespace(const std::string& s,
275
0
                                  const char delimiter = '.') const {
276
0
    std::string prefix;
277
0
    return Denamespace(s, prefix, delimiter);
278
0
  }
279
280
  const Config config_;
281
  const std::set<std::string> keywords_;
282
};
283
284
}  // namespace flatbuffers
285
286
#endif  // FLATBUFFERS_INCLUDE_CODEGEN_NAMER_H_