Coverage Report

Created: 2026-01-09 06:22

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
95
    // Files.
96
97
    // Case style for filenames. e.g. `foo_bar_generated.rs`
98
    Case filenames;
99
    // Case style for directories, e.g. `output_files/foo_bar/baz/`
100
    Case directories;
101
    // The directory within which we will generate files.
102
    std::string output_path;
103
    // Suffix for generated file names, e.g. "_generated".
104
    std::string filename_suffix;
105
    // Extension for generated files, e.g. ".cpp" or ".rs".
106
    std::string filename_extension;
107
  };
108
  Namer(Config config, std::set<std::string> keywords)
109
0
      : config_(config), keywords_(std::move(keywords)) {}
110
111
0
  virtual ~Namer() {}
112
113
  template <typename T>
114
0
  std::string Method(const T& s) const {
115
0
    return Method(s.name);
116
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
117
118
  virtual std::string Method(const std::string& pre, const std::string& mid,
119
0
                             const std::string& suf) const {
120
0
    return Format(pre + "_" + mid + "_" + suf, config_.methods);
121
0
  }
122
  virtual std::string Method(const std::string& pre,
123
0
                             const std::string& suf) const {
124
0
    return Format(pre + "_" + suf, config_.methods);
125
0
  }
126
0
  virtual std::string Method(const std::string& s) const {
127
0
    return Format(s, config_.methods);
128
0
  }
129
130
0
  virtual std::string Constant(const std::string& s) const {
131
0
    return Format(s, config_.constants);
132
0
  }
133
134
0
  virtual std::string Function(const std::string& s) const {
135
0
    return Format(s, config_.functions);
136
0
  }
137
138
0
  virtual std::string Variable(const std::string& s) const {
139
0
    return Format(s, config_.variables);
140
0
  }
141
142
  template <typename T>
143
0
  std::string Variable(const std::string& p, const T& s) const {
144
0
    return Format(p + "_" + s.name, config_.variables);
145
0
  }
146
  virtual std::string Variable(const std::string& p,
147
0
                               const std::string& s) const {
148
0
    return Format(p + "_" + s, config_.variables);
149
0
  }
150
151
0
  virtual std::string Namespace(const std::string& s) const {
152
0
    return Format(s, config_.namespaces);
153
0
  }
154
155
0
  virtual std::string Namespace(const std::vector<std::string>& ns) const {
156
0
    std::string result;
157
0
    for (auto it = ns.begin(); it != ns.end(); it++) {
158
0
      if (it != ns.begin()) result += config_.namespace_seperator;
159
0
      result += Namespace(*it);
160
0
    }
161
0
    return result;
162
0
  }
163
164
  virtual std::string NamespacedType(const std::vector<std::string>& ns,
165
0
                                     const std::string& s) const {
166
0
    return (ns.empty() ? "" : (Namespace(ns) + config_.namespace_seperator)) +
167
0
           Type(s);
168
0
  }
169
170
  // Returns `filename` with the right casing, suffix, and extension.
171
  virtual std::string File(const std::string& filename,
172
0
                           SkipFile skips = SkipFile::None) const {
173
0
    const bool skip_suffix = (skips & SkipFile::Suffix) != SkipFile::None;
174
0
    const bool skip_ext = (skips & SkipFile::Extension) != SkipFile::None;
175
0
    return ConvertCase(filename, config_.filenames, Case::kUpperCamel) +
176
0
           (skip_suffix ? "" : config_.filename_suffix) +
177
0
           (skip_ext ? "" : config_.filename_extension);
178
0
  }
179
  template <typename T>
180
0
  std::string File(const T& f, SkipFile skips = SkipFile::None) const {
181
0
    return File(f.name, skips);
182
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
183
184
  // Formats `directories` prefixed with the output_path and joined with the
185
  // right seperator. Output path prefixing and the trailing separator may be
186
  // skiped using `skips`.
187
  // Callers may want to use `EnsureDirExists` with the result.
188
  // input_case is used to tell how to modify namespace. e.g. kUpperCamel will
189
  // add a underscode between case changes, so MyGame turns into My_Game
190
  // (depending also on the output_case).
191
  virtual std::string Directories(const std::vector<std::string>& directories,
192
                                  SkipDir skips = SkipDir::None,
193
0
                                  Case input_case = Case::kUpperCamel) const {
194
0
    const bool skip_output_path =
195
0
        (skips & SkipDir::OutputPath) != SkipDir::None;
196
0
    const bool skip_trailing_seperator =
197
0
        (skips & SkipDir::TrailingPathSeperator) != SkipDir::None;
198
0
    std::string result = skip_output_path ? "" : config_.output_path;
199
0
    for (auto d = directories.begin(); d != directories.end(); d++) {
200
0
      result += ConvertCase(*d, config_.directories, input_case);
201
0
      result.push_back(kPathSeparator);
202
0
    }
203
0
    if (skip_trailing_seperator && !result.empty()) result.pop_back();
204
0
    return result;
205
0
  }
206
207
0
  virtual std::string EscapeKeyword(const std::string& name) const {
208
0
    if (keywords_.find(name) == keywords_.end()) {
209
0
      return name;
210
0
    } else {
211
0
      return config_.keyword_prefix + name + config_.keyword_suffix;
212
0
    }
213
0
  }
214
215
0
  virtual std::string Type(const std::string& s) const {
216
0
    return Format(s, config_.types);
217
0
  }
218
0
  virtual std::string Type(const std::string& t, const std::string& s) const {
219
0
    return Format(t + "_" + s, config_.types);
220
0
  }
221
222
0
  virtual std::string ObjectType(const std::string& s) const {
223
0
    return config_.object_prefix + Type(s) + config_.object_suffix;
224
0
  }
225
226
0
  virtual std::string Field(const std::string& s) const {
227
0
    return Format(s, config_.fields);
228
0
  }
229
230
0
  virtual std::string Variant(const std::string& s) const {
231
0
    return Format(s, config_.variants);
232
0
  }
233
234
0
  virtual std::string Format(const std::string& s, Case casing) const {
235
0
    if (config_.escape_keywords == Config::Escape::BeforeConvertingCase) {
236
0
      return ConvertCase(EscapeKeyword(s), casing, Case::kLowerCamel);
237
0
    } else {
238
0
      return EscapeKeyword(ConvertCase(s, casing, Case::kLowerCamel));
239
0
    }
240
0
  }
241
242
  // Denamespaces a string (e.g. The.Quick.Brown.Fox) by returning the last part
243
  // after the `delimiter` (Fox) and placing the rest in `namespace_prefix`
244
  // (The.Quick.Brown).
245
  virtual std::string Denamespace(const std::string& s,
246
                                  std::string& namespace_prefix,
247
0
                                  const char delimiter = '.') const {
248
0
    const size_t pos = s.find_last_of(delimiter);
249
0
    if (pos == std::string::npos) {
250
0
      namespace_prefix = "";
251
0
      return s;
252
0
    }
253
0
    namespace_prefix = s.substr(0, pos);
254
0
    return s.substr(pos + 1);
255
0
  }
256
257
  // Same as above, but disregards the prefix.
258
  virtual std::string Denamespace(const std::string& s,
259
0
                                  const char delimiter = '.') const {
260
0
    std::string prefix;
261
0
    return Denamespace(s, prefix, delimiter);
262
0
  }
263
264
  const Config config_;
265
  const std::set<std::string> keywords_;
266
};
267
268
}  // namespace flatbuffers
269
270
#endif  // FLATBUFFERS_INCLUDE_CODEGEN_NAMER_H_