GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
#ifndef SRC_NODE_OPTIONS_INL_H_ |
||
2 |
#define SRC_NODE_OPTIONS_INL_H_ |
||
3 |
|||
4 |
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
||
5 |
|||
6 |
#include "node_options.h" |
||
7 |
#include "util.h" |
||
8 |
#include <cstdlib> |
||
9 |
|||
10 |
namespace node { |
||
11 |
|||
12 |
343405 |
PerIsolateOptions* PerProcessOptions::get_per_isolate_options() { |
|
13 |
343405 |
return per_isolate.get(); |
|
14 |
} |
||
15 |
|||
16 |
35856 |
DebugOptions* EnvironmentOptions::get_debug_options() { |
|
17 |
35856 |
return &debug_options_; |
|
18 |
} |
||
19 |
|||
20 |
20384 |
const DebugOptions& EnvironmentOptions::debug_options() const { |
|
21 |
20384 |
return debug_options_; |
|
22 |
} |
||
23 |
|||
24 |
302675 |
EnvironmentOptions* PerIsolateOptions::get_per_env_options() { |
|
25 |
302675 |
return per_env.get(); |
|
26 |
} |
||
27 |
|||
28 |
namespace options_parser { |
||
29 |
|||
30 |
template <typename Options> |
||
31 |
271920 |
void OptionsParser<Options>::AddOption(const char* name, |
|
32 |
const char* help_text, |
||
33 |
bool Options::* field, |
||
34 |
OptionEnvvarSettings env_setting) { |
||
35 |
271920 |
options_.emplace(name, |
|
36 |
OptionInfo{kBoolean, |
||
37 |
std::make_shared<SimpleOptionField<bool>>(field), |
||
38 |
env_setting, |
||
39 |
help_text}); |
||
40 |
271920 |
} |
|
41 |
|||
42 |
template <typename Options> |
||
43 |
14832 |
void OptionsParser<Options>::AddOption(const char* name, |
|
44 |
const char* help_text, |
||
45 |
uint64_t Options::* field, |
||
46 |
OptionEnvvarSettings env_setting) { |
||
47 |
14832 |
options_.emplace( |
|
48 |
name, |
||
49 |
OptionInfo{kUInteger, |
||
50 |
std::make_shared<SimpleOptionField<uint64_t>>(field), |
||
51 |
env_setting, |
||
52 |
help_text}); |
||
53 |
14832 |
} |
|
54 |
|||
55 |
template <typename Options> |
||
56 |
4944 |
void OptionsParser<Options>::AddOption(const char* name, |
|
57 |
const char* help_text, |
||
58 |
int64_t Options::* field, |
||
59 |
OptionEnvvarSettings env_setting) { |
||
60 |
4944 |
options_.emplace( |
|
61 |
name, |
||
62 |
OptionInfo{kInteger, |
||
63 |
std::make_shared<SimpleOptionField<int64_t>>(field), |
||
64 |
env_setting, |
||
65 |
help_text}); |
||
66 |
4944 |
} |
|
67 |
|||
68 |
template <typename Options> |
||
69 |
113712 |
void OptionsParser<Options>::AddOption(const char* name, |
|
70 |
const char* help_text, |
||
71 |
std::string Options::* field, |
||
72 |
OptionEnvvarSettings env_setting) { |
||
73 |
113712 |
options_.emplace( |
|
74 |
name, |
||
75 |
OptionInfo{kString, |
||
76 |
std::make_shared<SimpleOptionField<std::string>>(field), |
||
77 |
env_setting, |
||
78 |
help_text}); |
||
79 |
113712 |
} |
|
80 |
|||
81 |
template <typename Options> |
||
82 |
9888 |
void OptionsParser<Options>::AddOption( |
|
83 |
const char* name, |
||
84 |
const char* help_text, |
||
85 |
std::vector<std::string> Options::* field, |
||
86 |
OptionEnvvarSettings env_setting) { |
||
87 |
9888 |
options_.emplace(name, OptionInfo { |
|
88 |
kStringList, |
||
89 |
std::make_shared<SimpleOptionField<std::vector<std::string>>>(field), |
||
90 |
env_setting, |
||
91 |
help_text |
||
92 |
}); |
||
93 |
9888 |
} |
|
94 |
|||
95 |
template <typename Options> |
||
96 |
4944 |
void OptionsParser<Options>::AddOption(const char* name, |
|
97 |
const char* help_text, |
||
98 |
HostPort Options::* field, |
||
99 |
OptionEnvvarSettings env_setting) { |
||
100 |
4944 |
options_.emplace( |
|
101 |
name, |
||
102 |
OptionInfo{kHostPort, |
||
103 |
std::make_shared<SimpleOptionField<HostPort>>(field), |
||
104 |
env_setting, |
||
105 |
help_text}); |
||
106 |
4944 |
} |
|
107 |
|||
108 |
template <typename Options> |
||
109 |
14832 |
void OptionsParser<Options>::AddOption(const char* name, |
|
110 |
const char* help_text, |
||
111 |
NoOp no_op_tag, |
||
112 |
OptionEnvvarSettings env_setting) { |
||
113 |
14832 |
options_.emplace(name, OptionInfo{kNoOp, nullptr, env_setting, help_text}); |
|
114 |
14832 |
} |
|
115 |
|||
116 |
template <typename Options> |
||
117 |
39552 |
void OptionsParser<Options>::AddOption(const char* name, |
|
118 |
const char* help_text, |
||
119 |
V8Option v8_option_tag, |
||
120 |
OptionEnvvarSettings env_setting) { |
||
121 |
39552 |
options_.emplace(name, |
|
122 |
OptionInfo{kV8Option, nullptr, env_setting, help_text}); |
||
123 |
39552 |
} |
|
124 |
|||
125 |
template <typename Options> |
||
126 |
64272 |
void OptionsParser<Options>::AddAlias(const char* from, |
|
127 |
const char* to) { |
||
128 |
✓✓✓✓ ✓✓ |
64272 |
aliases_[from] = { to }; |
129 |
64272 |
} |
|
130 |
|||
131 |
template <typename Options> |
||
132 |
29664 |
void OptionsParser<Options>::AddAlias(const char* from, |
|
133 |
const std::vector<std::string>& to) { |
||
134 |
29664 |
aliases_[from] = to; |
|
135 |
29664 |
} |
|
136 |
|||
137 |
template <typename Options> |
||
138 |
29664 |
void OptionsParser<Options>::AddAlias( |
|
139 |
const char* from, |
||
140 |
const std::initializer_list<std::string>& to) { |
||
141 |
29664 |
AddAlias(from, std::vector<std::string>(to)); |
|
142 |
29664 |
} |
|
143 |
|||
144 |
template <typename Options> |
||
145 |
34608 |
void OptionsParser<Options>::Implies(const char* from, |
|
146 |
const char* to) { |
||
147 |
34608 |
auto it = options_.find(to); |
|
148 |
✗✓✗✓ ✗✓✗✓ |
34608 |
CHECK_NE(it, options_.end()); |
149 |
✗✓✗✓ ✗✓✗✓ |
34608 |
CHECK_EQ(it->second.type, kBoolean); |
150 |
34608 |
implications_.emplace(from, Implication { |
|
151 |
34608 |
it->second.field, true |
|
152 |
}); |
||
153 |
34608 |
} |
|
154 |
|||
155 |
template <typename Options> |
||
156 |
4944 |
void OptionsParser<Options>::ImpliesNot(const char* from, |
|
157 |
const char* to) { |
||
158 |
4944 |
auto it = options_.find(to); |
|
159 |
✗✓ | 4944 |
CHECK_NE(it, options_.end()); |
160 |
✗✓ | 4944 |
CHECK_EQ(it->second.type, kBoolean); |
161 |
4944 |
implications_.emplace(from, Implication { |
|
162 |
4944 |
it->second.field, false |
|
163 |
}); |
||
164 |
4944 |
} |
|
165 |
|||
166 |
template <typename Options> |
||
167 |
template <typename OriginalField, typename ChildOptions> |
||
168 |
791040 |
auto OptionsParser<Options>::Convert( |
|
169 |
std::shared_ptr<OriginalField> original, |
||
170 |
ChildOptions* (Options::* get_child)()) { |
||
171 |
// If we have a field on ChildOptions, and we want to access it from an |
||
172 |
// Options instance, we call get_child() on the original Options and then |
||
173 |
// access it, i.e. this class implements a kind of function chaining. |
||
174 |
✗✓✗✓ ✗✓ |
1582080 |
struct AdaptedField : BaseOptionField { |
175 |
681920 |
void* LookupImpl(Options* options) const override { |
|
176 |
✓✗✓✗ ✓✗ |
681920 |
return original->LookupImpl((options->*get_child)()); |
177 |
} |
||
178 |
|||
179 |
791040 |
AdaptedField( |
|
180 |
std::shared_ptr<OriginalField> original, |
||
181 |
ChildOptions* (Options::* get_child)()) |
||
182 |
791040 |
: original(original), get_child(get_child) {} |
|
183 |
|||
184 |
std::shared_ptr<OriginalField> original; |
||
185 |
ChildOptions* (Options::* get_child)(); |
||
186 |
}; |
||
187 |
|||
188 |
return std::shared_ptr<BaseOptionField>( |
||
189 |
791040 |
new AdaptedField(original, get_child)); |
|
190 |
} |
||
191 |
template <typename Options> |
||
192 |
template <typename ChildOptions> |
||
193 |
726768 |
auto OptionsParser<Options>::Convert( |
|
194 |
typename OptionsParser<ChildOptions>::OptionInfo original, |
||
195 |
ChildOptions* (Options::* get_child)()) { |
||
196 |
return OptionInfo{original.type, |
||
197 |
Convert(original.field, get_child), |
||
198 |
original.env_setting, |
||
199 |
726768 |
original.help_text}; |
|
200 |
} |
||
201 |
|||
202 |
template <typename Options> |
||
203 |
template <typename ChildOptions> |
||
204 |
64272 |
auto OptionsParser<Options>::Convert( |
|
205 |
typename OptionsParser<ChildOptions>::Implication original, |
||
206 |
ChildOptions* (Options::* get_child)()) { |
||
207 |
return Implication { |
||
208 |
Convert(original.target_field, get_child), |
||
209 |
original.target_value |
||
210 |
64272 |
}; |
|
211 |
} |
||
212 |
|||
213 |
template <typename Options> |
||
214 |
template <typename ChildOptions> |
||
215 |
14832 |
void OptionsParser<Options>::Insert( |
|
216 |
const OptionsParser<ChildOptions>& child_options_parser, |
||
217 |
ChildOptions* (Options::* get_child)()) { |
||
218 |
14832 |
aliases_.insert(std::begin(child_options_parser.aliases_), |
|
219 |
std::end(child_options_parser.aliases_)); |
||
220 |
|||
221 |
✓✓✓✓ ✓✓ |
741600 |
for (const auto& pair : child_options_parser.options_) |
222 |
726768 |
options_.emplace(pair.first, Convert(pair.second, get_child)); |
|
223 |
|||
224 |
✓✓✓✓ ✓✓ |
79104 |
for (const auto& pair : child_options_parser.implications_) |
225 |
64272 |
implications_.emplace(pair.first, Convert(pair.second, get_child)); |
|
226 |
14832 |
} |
|
227 |
|||
228 |
15 |
inline std::string NotAllowedInEnvErr(const std::string& arg) { |
|
229 |
15 |
return arg + " is not allowed in NODE_OPTIONS"; |
|
230 |
} |
||
231 |
|||
232 |
7 |
inline std::string RequiresArgumentErr(const std::string& arg) { |
|
233 |
7 |
return arg + " requires an argument"; |
|
234 |
} |
||
235 |
|||
236 |
// We store some of the basic information around a single Parse call inside |
||
237 |
// this struct, to separate storage of command line arguments and their |
||
238 |
// handling. In particular, this makes it easier to introduce 'synthetic' |
||
239 |
// arguments that get inserted by expanding option aliases. |
||
240 |
9729 |
struct ArgsInfo { |
|
241 |
// Generally, the idea here is that the first entry in `*underlying` stores |
||
242 |
// the "0th" argument (the program name), then `synthetic_args` are inserted, |
||
243 |
// followed by the remainder of `*underlying`. |
||
244 |
std::vector<std::string>* underlying; |
||
245 |
std::vector<std::string> synthetic_args; |
||
246 |
|||
247 |
std::vector<std::string>* exec_args; |
||
248 |
|||
249 |
9729 |
ArgsInfo(std::vector<std::string>* args, |
|
250 |
std::vector<std::string>* exec_args) |
||
251 |
9729 |
: underlying(args), exec_args(exec_args) {} |
|
252 |
|||
253 |
14274 |
size_t remaining() const { |
|
254 |
// -1 to account for the program name. |
||
255 |
14274 |
return underlying->size() - 1 + synthetic_args.size(); |
|
256 |
} |
||
257 |
|||
258 |
14274 |
bool empty() const { return remaining() == 0; } |
|
259 |
9729 |
const std::string& program_name() const { return underlying->at(0); } |
|
260 |
|||
261 |
19777 |
std::string& first() { |
|
262 |
✓✓ | 19777 |
return synthetic_args.empty() ? underlying->at(1) : synthetic_args.front(); |
263 |
} |
||
264 |
|||
265 |
2933 |
std::string pop_first() { |
|
266 |
2933 |
std::string ret = std::move(first()); |
|
267 |
✓✓ | 2933 |
if (synthetic_args.empty()) { |
268 |
// Only push arguments to `exec_args` that were also originally passed |
||
269 |
// on the command line (i.e. not generated through alias expansion). |
||
270 |
// '--' is a special case here since its purpose is to end `exec_argv`, |
||
271 |
// which is why we do not include it. |
||
272 |
✓✓✓✓ ✓✓ |
2440 |
if (exec_args != nullptr && ret != "--") |
273 |
2333 |
exec_args->push_back(ret); |
|
274 |
2440 |
underlying->erase(underlying->begin() + 1); |
|
275 |
} else { |
||
276 |
493 |
synthetic_args.erase(synthetic_args.begin()); |
|
277 |
} |
||
278 |
2933 |
return ret; |
|
279 |
} |
||
280 |
}; |
||
281 |
|||
282 |
template <typename Options> |
||
283 |
9729 |
void OptionsParser<Options>::Parse( |
|
284 |
std::vector<std::string>* const orig_args, |
||
285 |
std::vector<std::string>* const exec_args, |
||
286 |
std::vector<std::string>* const v8_args, |
||
287 |
Options* const options, |
||
288 |
OptionEnvvarSettings required_env_settings, |
||
289 |
std::vector<std::string>* const errors) const { |
||
290 |
9729 |
ArgsInfo args(orig_args, exec_args); |
|
291 |
|||
292 |
// The first entry is the process name. Make sure it ends up in the V8 argv, |
||
293 |
// since V8::SetFlagsFromCommandLine() expects that to hold true for that |
||
294 |
// array as well. |
||
295 |
✓✗✓✗ ✗✗ |
9729 |
if (v8_args->empty()) |
296 |
9729 |
v8_args->push_back(args.program_name()); |
|
297 |
|||
298 |
✓✓✓✗ ✓✓✓✓ ✓✗✓✓ ✗✗✗✗ ✗✗ |
23464 |
while (!args.empty() && errors->empty()) { |
299 |
✓✓✓✓ ✓✓✓✗ ✗✓✗✓ ✗✗✗✗ ✗✗ |
11187 |
if (args.first().size() <= 1 || args.first()[0] != '-') break; |
300 |
|||
301 |
// We know that we're either going to consume this |
||
302 |
// argument or fail completely. |
||
303 |
2362 |
const std::string arg = args.pop_first(); |
|
304 |
|||
305 |
✓✓✓✓ ✗✗ |
2362 |
if (arg == "--") { |
306 |
✓✓✗✓ ✗✗ |
286 |
if (required_env_settings == kAllowedInEnvironment) |
307 |
1 |
errors->push_back(NotAllowedInEnvErr("--")); |
|
308 |
286 |
break; |
|
309 |
} |
||
310 |
|||
311 |
// Only allow --foo=bar notation for options starting with double dashes. |
||
312 |
// (E.g. -e=a is not allowed as shorthand for --eval=a, which would |
||
313 |
// otherwise be the result of alias expansion.) |
||
314 |
const std::string::size_type equals_index = |
||
315 |
✓✗✓✓ ✓✗✓✗ ✗✗✗✗ |
2076 |
arg[0] == '-' && arg[1] == '-' ? arg.find('=') : std::string::npos; |
316 |
std::string name = |
||
317 |
✓✓✓✓ ✓✓✓✓ ✓✓✗✗ ✗✗✗ |
4027 |
equals_index == std::string::npos ? arg : arg.substr(0, equals_index); |
318 |
|||
319 |
// Store the 'original name' of the argument. This name differs from |
||
320 |
// 'name' in that it contains a possible '=' sign and is not affected |
||
321 |
// by alias expansion. |
||
322 |
✓✓✓✓ ✓✓✗✗ ✗ |
4027 |
std::string original_name = name; |
323 |
✓✓✓✓ ✗✗ |
2076 |
if (equals_index != std::string::npos) |
324 |
147 |
original_name += '='; |
|
325 |
|||
326 |
// Normalize by replacing `_` with `-` in options. |
||
327 |
✓✓✓✓ ✗✗ |
24709 |
for (std::string::size_type i = 2; i < name.size(); ++i) { |
328 |
✓✓✗✓ ✗✗ |
22633 |
if (name[i] == '_') |
329 |
58 |
name[i] = '-'; |
|
330 |
} |
||
331 |
|||
332 |
{ |
||
333 |
2076 |
auto it = aliases_.end(); |
|
334 |
// Expand aliases: |
||
335 |
// - If `name` can be found in `aliases_`. |
||
336 |
// - If `name` + '=' can be found in `aliases_`. |
||
337 |
// - If `name` + " <arg>" can be found in `aliases_`, and we have |
||
338 |
// a subsequent argument that does not start with '-' itself. |
||
339 |
✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✗ ✓✓✓✗ ✓✓✓✗ ✓✓✓✗ ✓✓✗✓ ✓✗✗✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗ |
12055 |
while ((it = aliases_.find(name)) != aliases_.end() || |
340 |
(equals_index != std::string::npos && |
||
341 |
✓✓✓✓ ✓✓✓✓ ✗✗✗✗ |
3217 |
(it = aliases_.find(name + '=')) != aliases_.end()) || |
342 |
3718 |
(!args.empty() && |
|
343 |
1804 |
!args.first().empty() && |
|
344 |
1801 |
args.first()[0] != '-' && |
|
345 |
✓✓✓✓ ✓✓✓✓ ✗✗✗✗ |
5395 |
(it = aliases_.find(name + " <arg>")) != aliases_.end())) { |
346 |
997 |
const std::string prev_name = std::move(name); |
|
347 |
997 |
const std::vector<std::string>& expansion = it->second; |
|
348 |
|||
349 |
// Use the first entry in the expansion as the new 'name'. |
||
350 |
997 |
name = expansion.front(); |
|
351 |
|||
352 |
✓✓✗✗ ✗✗ |
997 |
if (expansion.size() > 1) { |
353 |
// The other arguments, if any, are going to be handled later. |
||
354 |
494 |
args.synthetic_args.insert( |
|
355 |
args.synthetic_args.begin(), |
||
356 |
expansion.begin() + 1, |
||
357 |
988 |
expansion.end()); |
|
358 |
} |
||
359 |
|||
360 |
✓✓✓✓ ✗✗✗✗ ✗✗✗✗ |
997 |
if (name == prev_name) break; |
361 |
} |
||
362 |
} |
||
363 |
|||
364 |
2076 |
auto it = options_.find(name); |
|
365 |
|||
366 |
✓✓✓✓ ✓✓✓✗ ✓✓✓✓ ✓✓✗✓ ✓✗✗✓ ✗✗✗✗ ✗✗✗✗ ✗✗ |
4048 |
if ((it == options_.end() || |
367 |
1972 |
it->second.env_setting == kDisallowedInEnvironment) && |
|
368 |
required_env_settings == kAllowedInEnvironment) { |
||
369 |
14 |
errors->push_back(NotAllowedInEnvErr(original_name)); |
|
370 |
14 |
break; |
|
371 |
} |
||
372 |
|||
373 |
✓✓✓✓ ✗✗ |
2062 |
if (it == options_.end()) { |
374 |
104 |
v8_args->push_back(arg); |
|
375 |
104 |
continue; |
|
376 |
} |
||
377 |
|||
378 |
{ |
||
379 |
1958 |
auto implications = implications_.equal_range(name); |
|
380 |
✓✓✓✓ ✗✗ |
2432 |
for (auto it = implications.first; it != implications.second; ++it) { |
381 |
948 |
*it->second.target_field->template Lookup<bool>(options) = |
|
382 |
474 |
it->second.target_value; |
|
383 |
} |
||
384 |
} |
||
385 |
|||
386 |
1958 |
const OptionInfo& info = it->second; |
|
387 |
✓✓✓✓ ✓✓✗✗ ✗ |
3909 |
std::string value; |
388 |
✓✓✓✓ ✓✓✓✓ ✓✗✓✗ ✗✗✗✗ ✗✗ |
1958 |
if (info.type != kBoolean && info.type != kNoOp && info.type != kV8Option) { |
389 |
✓✓✗✓ ✗✗ |
714 |
if (equals_index != std::string::npos) { |
390 |
138 |
value = arg.substr(equals_index + 1); |
|
391 |
✓✓✗✗ ✗✗ |
138 |
if (value.empty()) { |
392 |
missing_argument: |
||
393 |
7 |
errors->push_back(RequiresArgumentErr(original_name)); |
|
394 |
7 |
break; |
|
395 |
} |
||
396 |
} else { |
||
397 |
✓✓✓✓ ✗✗ |
576 |
if (args.empty()) |
398 |
5 |
goto missing_argument; |
|
399 |
|||
400 |
571 |
value = args.pop_first(); |
|
401 |
|||
402 |
✓✓✗✓ ✗✓✓✗ ✗✓✗✓ ✗✗✗✗ ✗✗ |
571 |
if (!value.empty() && value[0] == '-') { |
403 |
goto missing_argument; |
||
404 |
} else { |
||
405 |
✓✓✓✓ ✓✗✓✓ ✓✗✗✓ ✗✗✗✓ ✗✗✗✗ ✗✗✗✗ |
571 |
if (!value.empty() && value[0] == '\\' && value[1] == '-') |
406 |
1 |
value = value.substr(1); // Treat \- as escaping an -. |
|
407 |
} |
||
408 |
} |
||
409 |
} |
||
410 |
|||
411 |
✓✓✓✓ ✓✓✓✓ ✗✓✗✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗ |
1951 |
switch (info.type) { |
412 |
case kBoolean: |
||
413 |
1211 |
*Lookup<bool>(info.field, options) = true; |
|
414 |
1211 |
break; |
|
415 |
case kInteger: |
||
416 |
1 |
*Lookup<int64_t>(info.field, options) = std::atoll(value.c_str()); |
|
417 |
1 |
break; |
|
418 |
case kUInteger: |
||
419 |
16 |
*Lookup<uint64_t>(info.field, options) = std::stoull(value); |
|
420 |
16 |
break; |
|
421 |
case kString: |
||
422 |
553 |
*Lookup<std::string>(info.field, options) = value; |
|
423 |
553 |
break; |
|
424 |
case kStringList: |
||
425 |
39 |
Lookup<std::vector<std::string>>(info.field, options) |
|
426 |
39 |
->emplace_back(std::move(value)); |
|
427 |
39 |
break; |
|
428 |
case kHostPort: |
||
429 |
98 |
Lookup<HostPort>(info.field, options) |
|
430 |
->Update(SplitHostPort(value, errors)); |
||
431 |
98 |
break; |
|
432 |
case kNoOp: |
||
433 |
1 |
break; |
|
434 |
case kV8Option: |
||
435 |
32 |
v8_args->push_back(arg); |
|
436 |
✓✓✓✓ ✗✗ |
32 |
break; |
437 |
default: |
||
438 |
UNREACHABLE(); |
||
439 |
} |
||
440 |
} |
||
441 |
9729 |
options->CheckOptions(errors); |
|
442 |
9729 |
} |
|
443 |
|||
444 |
} // namespace options_parser |
||
445 |
} // namespace node |
||
446 |
|||
447 |
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
||
448 |
|||
449 |
#endif // SRC_NODE_OPTIONS_INL_H_ |
Generated by: GCOVR (Version 3.4) |