diff --git a/src/parse/arg_matcher.rs b/src/parse/arg_matcher.rs index 58a94059c46f..7029cdcfaeb1 100644 --- a/src/parse/arg_matcher.rs +++ b/src/parse/arg_matcher.rs @@ -25,6 +25,12 @@ impl ArgMatcher { }, #[cfg(debug_assertions)] valid_subcommands: _app.subcommands.iter().map(|sc| sc.id.clone()).collect(), + // HACK: Allow an external subcommand's ArgMatches be a stand-in for any ArgMatches + // since users can't detect it and avoid the asserts. + // + // See clap-rs/clap#3263 + #[cfg(debug_assertions)] + disable_asserts: _app.is_set(clap::AppSettings::AllowExternalSubcommands), ..Default::default() }) } diff --git a/src/parse/matches/arg_matches.rs b/src/parse/matches/arg_matches.rs index 91a5841cae2c..cc6c87812639 100644 --- a/src/parse/matches/arg_matches.rs +++ b/src/parse/matches/arg_matches.rs @@ -73,6 +73,8 @@ pub struct ArgMatches { pub(crate) valid_args: Vec, #[cfg(debug_assertions)] pub(crate) valid_subcommands: Vec, + #[cfg(debug_assertions)] + pub(crate) disable_asserts: bool, pub(crate) args: IndexMap, pub(crate) subcommand: Option>, } @@ -1005,7 +1007,7 @@ impl ArgMatches { #[cfg(debug_assertions)] { let id = Id::from(_id); - id == Id::empty_hash() || self.valid_args.contains(&id) + self.disable_asserts || id == Id::empty_hash() || self.valid_args.contains(&id) } #[cfg(not(debug_assertions))] { @@ -1024,7 +1026,7 @@ impl ArgMatches { #[cfg(debug_assertions)] { let id = Id::from(_id); - id == Id::empty_hash() || self.valid_subcommands.contains(&id) + self.disable_asserts || id == Id::empty_hash() || self.valid_subcommands.contains(&id) } #[cfg(not(debug_assertions))] { @@ -1040,7 +1042,7 @@ impl ArgMatches { fn get_arg(&self, arg: &Id) -> Option<&MatchedArg> { #[cfg(debug_assertions)] { - if *arg == Id::empty_hash() || self.valid_args.contains(arg) { + if self.disable_asserts || *arg == Id::empty_hash() || self.valid_args.contains(arg) { } else if self.valid_subcommands.contains(arg) { panic!( "Subcommand `{:?}` used where an argument or group name was expected.", @@ -1064,7 +1066,10 @@ impl ArgMatches { fn get_subcommand(&self, id: &Id) -> Option<&SubCommand> { #[cfg(debug_assertions)] { - if *id == Id::empty_hash() || self.valid_subcommands.contains(id) { + if self.disable_asserts + || *id == Id::empty_hash() + || self.valid_subcommands.contains(id) + { } else if self.valid_args.contains(id) { panic!( "Argument or group `{:?}` used where a subcommand name was expected.",