@@ -23,12 +23,14 @@ template <typename Options>
2323void OptionsParser<Options>::AddOption(const char * name,
2424 const char * help_text,
2525 bool Options::* field,
26- OptionEnvvarSettings env_setting) {
26+ OptionEnvvarSettings env_setting,
27+ bool default_is_true) {
2728 options_.emplace (name,
2829 OptionInfo{kBoolean ,
2930 std::make_shared<SimpleOptionField<bool >>(field),
3031 env_setting,
31- help_text});
32+ help_text,
33+ default_is_true});
3234}
3335
3436template <typename Options>
@@ -186,7 +188,8 @@ auto OptionsParser<Options>::Convert(
186188 return OptionInfo{original.type ,
187189 Convert (original.field , get_child),
188190 original.env_setting ,
189- original.help_text };
191+ original.help_text ,
192+ original.default_is_true };
190193}
191194
192195template <typename Options>
@@ -225,6 +228,10 @@ inline std::string RequiresArgumentErr(const std::string& arg) {
225228 return arg + " requires an argument" ;
226229}
227230
231+ inline std::string NegationImpliesBooleanError (const std::string& arg) {
232+ return arg + " is an invalid negation because it is not a boolean option" ;
233+ }
234+
228235// We store some of the basic information around a single Parse call inside
229236// this struct, to separate storage of command line arguments and their
230237// handling. In particular, this makes it easier to introduce 'synthetic'
@@ -325,6 +332,13 @@ void OptionsParser<Options>::Parse(
325332 name[i] = ' -' ;
326333 }
327334
335+ // Convert --no-foo to --foo and keep in mind that we're negating.
336+ bool is_negation = false ;
337+ if (name.find (" --no-" ) == 0 ) {
338+ name.erase (2 , 3 ); // remove no-
339+ is_negation = true ;
340+ }
341+
328342 {
329343 auto it = aliases_.end ();
330344 // Expand aliases:
@@ -367,7 +381,12 @@ void OptionsParser<Options>::Parse(
367381 }
368382
369383 {
370- auto implications = implications_.equal_range (name);
384+ std::string implied_name = name;
385+ if (is_negation) {
386+ // Implications for negated options are defined with "--no-".
387+ implied_name.insert (2 , " no-" );
388+ }
389+ auto implications = implications_.equal_range (implied_name);
371390 for (auto it = implications.first ; it != implications.second ; ++it) {
372391 if (it->second .type == kV8Option ) {
373392 v8_args->push_back (it->second .name );
@@ -384,6 +403,13 @@ void OptionsParser<Options>::Parse(
384403 }
385404
386405 const OptionInfo& info = it->second ;
406+
407+ // Some V8 options can be negated and they are validated by V8 later.
408+ if (is_negation && info.type != kBoolean && info.type != kV8Option ) {
409+ errors->push_back (NegationImpliesBooleanError (arg));
410+ break ;
411+ }
412+
387413 std::string value;
388414 if (info.type != kBoolean && info.type != kNoOp && info.type != kV8Option ) {
389415 if (equals_index != std::string::npos) {
@@ -412,7 +438,7 @@ void OptionsParser<Options>::Parse(
412438
413439 switch (info.type ) {
414440 case kBoolean :
415- *Lookup<bool >(info.field , options) = true ;
441+ *Lookup<bool >(info.field , options) = !is_negation ;
416442 break ;
417443 case kInteger :
418444 *Lookup<int64_t >(info.field , options) = std::atoll (value.c_str ());
0 commit comments