1 // Internal
2 use crate::{
3     build::{arg::PossibleValue, App, AppSettings as AS, Arg, ArgSettings},
4     output::Usage,
5     parse::{
6         errors::{Error, ErrorKind, Result as ClapResult},
7         ArgMatcher, MatchedArg, ParseState, Parser,
8     },
9     util::Id,
10     INTERNAL_ERROR_MSG, INVALID_UTF8,
11 };
12 
13 pub(crate) struct Validator<'help, 'app, 'parser> {
14     p: &'parser mut Parser<'help, 'app>,
15 }
16 
17 impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> {
new(p: &'parser mut Parser<'help, 'app>) -> Self18     pub(crate) fn new(p: &'parser mut Parser<'help, 'app>) -> Self {
19         Validator { p }
20     }
21 
validate( &mut self, parse_state: ParseState, is_subcmd: bool, matcher: &mut ArgMatcher, trailing_values: bool, ) -> ClapResult<()>22     pub(crate) fn validate(
23         &mut self,
24         parse_state: ParseState,
25         is_subcmd: bool,
26         matcher: &mut ArgMatcher,
27         trailing_values: bool,
28     ) -> ClapResult<()> {
29         debug!("Validator::validate");
30         let mut reqs_validated = false;
31 
32         #[cfg(feature = "env")]
33         self.p.add_env(matcher, trailing_values)?;
34 
35         self.p.add_defaults(matcher, trailing_values);
36 
37         if let ParseState::Opt(a) = parse_state {
38             debug!("Validator::validate: needs_val_of={:?}", a);
39             self.validate_required(matcher)?;
40             self.validate_required_unless(matcher)?;
41 
42             let o = &self.p.app[&a];
43             reqs_validated = true;
44             let should_err = if let Some(v) = matcher.args.get(&o.id) {
45                 v.all_val_groups_empty() && !(o.min_vals.is_some() && o.min_vals.unwrap() == 0)
46             } else {
47                 true
48             };
49             if should_err {
50                 return Err(Error::empty_value(
51                     self.p.app,
52                     o,
53                     Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]),
54                 ));
55             }
56         }
57 
58         if matcher.is_empty()
59             && matcher.subcommand_name().is_none()
60             && self.p.is_set(AS::ArgRequiredElseHelp)
61         {
62             let message = self.p.write_help_err()?;
63             return Err(Error::new(
64                 message,
65                 ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
66                 self.p.is_set(AS::WaitOnError),
67             ));
68         }
69         self.validate_conflicts(matcher)?;
70         if !(self.p.is_set(AS::SubcommandsNegateReqs) && is_subcmd || reqs_validated) {
71             self.validate_required(matcher)?;
72             self.validate_required_unless(matcher)?;
73         }
74         self.validate_matched_args(matcher)?;
75 
76         Ok(())
77     }
78 
validate_arg_values( &self, arg: &Arg, ma: &MatchedArg, matcher: &ArgMatcher, ) -> ClapResult<()>79     fn validate_arg_values(
80         &self,
81         arg: &Arg,
82         ma: &MatchedArg,
83         matcher: &ArgMatcher,
84     ) -> ClapResult<()> {
85         debug!("Validator::validate_arg_values: arg={:?}", arg.name);
86         for val in ma.vals_flatten() {
87             if !arg.is_set(ArgSettings::AllowInvalidUtf8) && val.to_str().is_none() {
88                 debug!(
89                     "Validator::validate_arg_values: invalid UTF-8 found in val {:?}",
90                     val
91                 );
92                 return Err(Error::invalid_utf8(
93                     self.p.app,
94                     Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]),
95                 ));
96             }
97             if !arg.possible_vals.is_empty() {
98                 debug!(
99                     "Validator::validate_arg_values: possible_vals={:?}",
100                     arg.possible_vals
101                 );
102                 let val_str = val.to_string_lossy();
103                 let ok = arg
104                     .possible_vals
105                     .iter()
106                     .any(|pv| pv.matches(&val_str, arg.is_set(ArgSettings::IgnoreCase)));
107                 if !ok {
108                     let used: Vec<Id> = matcher
109                         .arg_names()
110                         .filter(|&n| {
111                             self.p.app.find(n).map_or(true, |a| {
112                                 !(a.is_set(ArgSettings::Hidden) || self.p.required.contains(&a.id))
113                             })
114                         })
115                         .cloned()
116                         .collect();
117                     return Err(Error::invalid_value(
118                         self.p.app,
119                         val_str.into_owned(),
120                         &arg.possible_vals
121                             .iter()
122                             .filter_map(PossibleValue::get_visible_name)
123                             .collect::<Vec<_>>(),
124                         arg,
125                         Usage::new(self.p.app, &self.p.required).create_usage_with_title(&used),
126                     ));
127                 }
128             }
129             if arg.is_set(ArgSettings::ForbidEmptyValues)
130                 && val.is_empty()
131                 && matcher.contains(&arg.id)
132             {
133                 debug!("Validator::validate_arg_values: illegal empty val found");
134                 return Err(Error::empty_value(
135                     self.p.app,
136                     arg,
137                     Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]),
138                 ));
139             }
140 
141             if let Some(ref vtor) = arg.validator {
142                 debug!("Validator::validate_arg_values: checking validator...");
143                 let mut vtor = vtor.lock().unwrap();
144                 if let Err(e) = vtor(&*val.to_string_lossy()) {
145                     debug!("error");
146                     return Err(Error::value_validation(
147                         self.p.app,
148                         arg.to_string(),
149                         val.to_string_lossy().into_owned(),
150                         e,
151                     ));
152                 } else {
153                     debug!("good");
154                 }
155             }
156             if let Some(ref vtor) = arg.validator_os {
157                 debug!("Validator::validate_arg_values: checking validator_os...");
158                 let mut vtor = vtor.lock().unwrap();
159                 if let Err(e) = vtor(val) {
160                     debug!("error");
161                     return Err(Error::value_validation(
162                         self.p.app,
163                         arg.to_string(),
164                         val.to_string_lossy().into(),
165                         e,
166                     ));
167                 } else {
168                     debug!("good");
169                 }
170             }
171         }
172         Ok(())
173     }
174 
validate_conflicts(&self, matcher: &ArgMatcher) -> ClapResult<()>175     fn validate_conflicts(&self, matcher: &ArgMatcher) -> ClapResult<()> {
176         debug!("Validator::validate_conflicts");
177 
178         self.validate_exclusive(matcher)?;
179 
180         let mut conflicts = Conflicts::new();
181         for arg_id in matcher
182             .arg_names()
183             .filter(|arg_id| matcher.contains_explicit(arg_id) && self.p.app.find(arg_id).is_some())
184         {
185             debug!("Validator::validate_conflicts::iter: id={:?}", arg_id);
186             let conflicts = conflicts.gather_conflicts(self.p.app, matcher, arg_id);
187             self.build_conflict_err(arg_id, &conflicts, matcher)?;
188         }
189 
190         Ok(())
191     }
192 
validate_exclusive(&self, matcher: &ArgMatcher) -> ClapResult<()>193     fn validate_exclusive(&self, matcher: &ArgMatcher) -> ClapResult<()> {
194         debug!("Validator::validate_exclusive");
195         let args_count = matcher.arg_names().count();
196         matcher
197             .arg_names()
198             .filter_map(|name| {
199                 debug!("Validator::validate_exclusive:iter:{:?}", name);
200                 self.p
201                     .app
202                     .find(name)
203                     // Find `arg`s which are exclusive but also appear with other args.
204                     .filter(|&arg| arg.is_set(ArgSettings::Exclusive) && args_count > 1)
205             })
206             // Throw an error for the first conflict found.
207             .try_for_each(|arg| {
208                 Err(Error::argument_conflict(
209                     self.p.app,
210                     arg,
211                     Vec::new(),
212                     Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]),
213                 ))
214             })
215     }
216 
build_conflict_err( &self, name: &Id, conflict_ids: &[Id], matcher: &ArgMatcher, ) -> ClapResult<()>217     fn build_conflict_err(
218         &self,
219         name: &Id,
220         conflict_ids: &[Id],
221         matcher: &ArgMatcher,
222     ) -> ClapResult<()> {
223         if conflict_ids.is_empty() {
224             return Ok(());
225         }
226 
227         debug!("Validator::build_conflict_err: name={:?}", name);
228         let mut seen = std::collections::HashSet::new();
229         let conflicts = conflict_ids
230             .iter()
231             .flat_map(|c_id| {
232                 if self.p.app.find_group(c_id).is_some() {
233                     self.p.app.unroll_args_in_group(c_id)
234                 } else {
235                     vec![c_id.clone()]
236                 }
237             })
238             .filter_map(|c_id| {
239                 seen.insert(c_id.clone()).then(|| {
240                     let c_arg = self.p.app.find(&c_id).expect(INTERNAL_ERROR_MSG);
241                     c_arg.to_string()
242                 })
243             })
244             .collect();
245 
246         let former_arg = self.p.app.find(name).expect(INTERNAL_ERROR_MSG);
247         let usg = self.build_conflict_err_usage(matcher, conflict_ids);
248         Err(Error::argument_conflict(
249             self.p.app, former_arg, conflicts, usg,
250         ))
251     }
252 
build_conflict_err_usage(&self, matcher: &ArgMatcher, conflicting_keys: &[Id]) -> String253     fn build_conflict_err_usage(&self, matcher: &ArgMatcher, conflicting_keys: &[Id]) -> String {
254         let used_filtered: Vec<Id> = matcher
255             .arg_names()
256             .filter(|key| !conflicting_keys.contains(key))
257             .cloned()
258             .collect();
259         let required: Vec<Id> = used_filtered
260             .iter()
261             .filter_map(|key| self.p.app.find(key))
262             .flat_map(|arg| arg.requires.iter().map(|item| &item.1))
263             .filter(|key| !used_filtered.contains(key) && !conflicting_keys.contains(key))
264             .chain(used_filtered.iter())
265             .cloned()
266             .collect();
267         Usage::new(self.p.app, &self.p.required).create_usage_with_title(&required)
268     }
269 
gather_requirements(&mut self, matcher: &ArgMatcher)270     fn gather_requirements(&mut self, matcher: &ArgMatcher) {
271         debug!("Validator::gather_requirements");
272         for name in matcher.arg_names() {
273             debug!("Validator::gather_requirements:iter:{:?}", name);
274             if let Some(arg) = self.p.app.find(name) {
275                 for req in self.p.app.unroll_requirements_for_arg(&arg.id, matcher) {
276                     self.p.required.insert(req);
277                 }
278             } else if let Some(g) = self.p.app.find_group(name) {
279                 debug!("Validator::gather_requirements:iter:{:?}:group", name);
280                 for r in &g.requires {
281                     self.p.required.insert(r.clone());
282                 }
283             }
284         }
285     }
286 
validate_matched_args(&self, matcher: &ArgMatcher) -> ClapResult<()>287     fn validate_matched_args(&self, matcher: &ArgMatcher) -> ClapResult<()> {
288         debug!("Validator::validate_matched_args");
289         matcher.iter().try_for_each(|(name, ma)| {
290             debug!(
291                 "Validator::validate_matched_args:iter:{:?}: vals={:#?}",
292                 name,
293                 ma.vals_flatten()
294             );
295             if let Some(arg) = self.p.app.find(name) {
296                 self.validate_arg_num_vals(arg, ma)?;
297                 self.validate_arg_values(arg, ma, matcher)?;
298                 self.validate_arg_num_occurs(arg, ma)?;
299             }
300             Ok(())
301         })
302     }
303 
validate_arg_num_occurs(&self, a: &Arg, ma: &MatchedArg) -> ClapResult<()>304     fn validate_arg_num_occurs(&self, a: &Arg, ma: &MatchedArg) -> ClapResult<()> {
305         debug!(
306             "Validator::validate_arg_num_occurs: {:?}={}",
307             a.name,
308             ma.get_occurrences()
309         );
310         // Occurrence of positional argument equals to number of values rather
311         // than number of grouped values.
312         if ma.get_occurrences() > 1
313             && !a.is_set(ArgSettings::MultipleOccurrences)
314             && !a.is_positional()
315         {
316             // Not the first time, and we don't allow multiples
317             return Err(Error::unexpected_multiple_usage(
318                 self.p.app,
319                 a,
320                 Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]),
321             ));
322         }
323         if let Some(max_occurs) = a.max_occurs {
324             debug!(
325                 "Validator::validate_arg_num_occurs: max_occurs set...{}",
326                 max_occurs
327             );
328             let occurs = ma.get_occurrences() as usize;
329             if occurs > max_occurs {
330                 return Err(Error::too_many_occurrences(
331                     self.p.app,
332                     a,
333                     max_occurs,
334                     occurs,
335                     Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]),
336                 ));
337             }
338         }
339 
340         Ok(())
341     }
342 
validate_arg_num_vals(&self, a: &Arg, ma: &MatchedArg) -> ClapResult<()>343     fn validate_arg_num_vals(&self, a: &Arg, ma: &MatchedArg) -> ClapResult<()> {
344         debug!("Validator::validate_arg_num_vals");
345         if let Some(num) = a.num_vals {
346             let total_num = ma.num_vals();
347             debug!("Validator::validate_arg_num_vals: num_vals set...{}", num);
348             let should_err = if a.is_set(ArgSettings::MultipleOccurrences) {
349                 total_num % num != 0
350             } else {
351                 num != total_num
352             };
353             if should_err {
354                 debug!("Validator::validate_arg_num_vals: Sending error WrongNumberOfValues");
355                 return Err(Error::wrong_number_of_values(
356                     self.p.app,
357                     a,
358                     num,
359                     if a.is_set(ArgSettings::MultipleOccurrences) {
360                         total_num % num
361                     } else {
362                         total_num
363                     },
364                     Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]),
365                 ));
366             }
367         }
368         if let Some(num) = a.max_vals {
369             debug!("Validator::validate_arg_num_vals: max_vals set...{}", num);
370             if ma.num_vals() > num {
371                 debug!("Validator::validate_arg_num_vals: Sending error TooManyValues");
372                 return Err(Error::too_many_values(
373                     self.p.app,
374                     ma.vals_flatten()
375                         .last()
376                         .expect(INTERNAL_ERROR_MSG)
377                         .to_str()
378                         .expect(INVALID_UTF8)
379                         .to_string(),
380                     a.to_string(),
381                     Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]),
382                 ));
383             }
384         }
385         let min_vals_zero = if let Some(num) = a.min_vals {
386             debug!("Validator::validate_arg_num_vals: min_vals set: {}", num);
387             if ma.num_vals() < num && num != 0 {
388                 debug!("Validator::validate_arg_num_vals: Sending error TooFewValues");
389                 return Err(Error::too_few_values(
390                     self.p.app,
391                     a,
392                     num,
393                     ma.num_vals(),
394                     Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]),
395                 ));
396             }
397             num == 0
398         } else {
399             false
400         };
401         // Issue 665 (https://github.com/clap-rs/clap/issues/665)
402         // Issue 1105 (https://github.com/clap-rs/clap/issues/1105)
403         if a.is_set(ArgSettings::TakesValue) && !min_vals_zero && ma.all_val_groups_empty() {
404             return Err(Error::empty_value(
405                 self.p.app,
406                 a,
407                 Usage::new(self.p.app, &self.p.required).create_usage_with_title(&[]),
408             ));
409         }
410         Ok(())
411     }
412 
validate_required(&mut self, matcher: &ArgMatcher) -> ClapResult<()>413     fn validate_required(&mut self, matcher: &ArgMatcher) -> ClapResult<()> {
414         debug!(
415             "Validator::validate_required: required={:?}",
416             self.p.required
417         );
418         self.gather_requirements(matcher);
419 
420         for arg_or_group in self.p.required.iter().filter(|r| !matcher.contains(r)) {
421             debug!("Validator::validate_required:iter:aog={:?}", arg_or_group);
422             if let Some(arg) = self.p.app.find(arg_or_group) {
423                 debug!("Validator::validate_required:iter: This is an arg");
424                 if !self.is_missing_required_ok(arg, matcher) {
425                     return self.missing_required_error(matcher, vec![]);
426                 }
427             } else if let Some(group) = self.p.app.find_group(arg_or_group) {
428                 debug!("Validator::validate_required:iter: This is a group");
429                 if !self
430                     .p
431                     .app
432                     .unroll_args_in_group(&group.id)
433                     .iter()
434                     .any(|a| matcher.contains(a))
435                 {
436                     return self.missing_required_error(matcher, vec![]);
437                 }
438             }
439         }
440 
441         // Validate the conditionally required args
442         for a in self.p.app.args.args() {
443             for (other, val) in &a.r_ifs {
444                 if let Some(ma) = matcher.get(other) {
445                     if ma.contains_val(val) && !matcher.contains(&a.id) {
446                         return self.missing_required_error(matcher, vec![a.id.clone()]);
447                     }
448                 }
449             }
450 
451             let match_all = a
452                 .r_ifs_all
453                 .iter()
454                 .all(|(other, val)| matcher.get(other).map_or(false, |ma| ma.contains_val(val)));
455             if match_all && !a.r_ifs_all.is_empty() && !matcher.contains(&a.id) {
456                 return self.missing_required_error(matcher, vec![a.id.clone()]);
457             }
458         }
459         Ok(())
460     }
461 
is_missing_required_ok(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool462     fn is_missing_required_ok(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool {
463         debug!("Validator::is_missing_required_ok: {}", a.name);
464         self.validate_arg_conflicts(a, matcher) || self.p.overridden.borrow().contains(&a.id)
465     }
466 
validate_arg_conflicts(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool467     fn validate_arg_conflicts(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool {
468         debug!("Validator::validate_arg_conflicts: a={:?}", a.name);
469         a.blacklist.iter().any(|conf| {
470             matcher.contains(conf)
471                 || self
472                     .p
473                     .app
474                     .find_group(conf)
475                     .map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg)))
476         })
477     }
478 
validate_required_unless(&self, matcher: &ArgMatcher) -> ClapResult<()>479     fn validate_required_unless(&self, matcher: &ArgMatcher) -> ClapResult<()> {
480         debug!("Validator::validate_required_unless");
481         let failed_args: Vec<_> = self
482             .p
483             .app
484             .args
485             .args()
486             .filter(|&a| {
487                 (!a.r_unless.is_empty() || !a.r_unless_all.is_empty())
488                     && !matcher.contains(&a.id)
489                     && self.fails_arg_required_unless(a, matcher)
490             })
491             .map(|a| a.id.clone())
492             .collect();
493         if failed_args.is_empty() {
494             Ok(())
495         } else {
496             self.missing_required_error(matcher, failed_args)
497         }
498     }
499 
500     // Failing a required unless means, the arg's "unless" wasn't present, and neither were they
fails_arg_required_unless(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool501     fn fails_arg_required_unless(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool {
502         debug!("Validator::fails_arg_required_unless: a={:?}", a.name);
503         let exists = |id| matcher.contains(id);
504 
505         (a.r_unless_all.is_empty() || !a.r_unless_all.iter().all(exists))
506             && !a.r_unless.iter().any(exists)
507     }
508 
509     // `incl`: an arg to include in the error even if not used
missing_required_error(&self, matcher: &ArgMatcher, incl: Vec<Id>) -> ClapResult<()>510     fn missing_required_error(&self, matcher: &ArgMatcher, incl: Vec<Id>) -> ClapResult<()> {
511         debug!("Validator::missing_required_error; incl={:?}", incl);
512         debug!(
513             "Validator::missing_required_error: reqs={:?}",
514             self.p.required
515         );
516 
517         let usg = Usage::new(self.p.app, &self.p.required);
518 
519         let req_args = usg.get_required_usage_from(&incl, Some(matcher), true);
520 
521         debug!(
522             "Validator::missing_required_error: req_args={:#?}",
523             req_args
524         );
525 
526         let used: Vec<Id> = matcher
527             .arg_names()
528             .filter(|n| {
529                 // Filter out the args we don't want to specify.
530                 self.p.app.find(n).map_or(true, |a| {
531                     !a.is_set(ArgSettings::Hidden)
532                         && a.default_vals.is_empty()
533                         && !self.p.required.contains(&a.id)
534                 })
535             })
536             .cloned()
537             .chain(incl)
538             .collect();
539 
540         Err(Error::missing_required_argument(
541             self.p.app,
542             req_args,
543             usg.create_usage_with_title(&used),
544         ))
545     }
546 }
547 
548 #[derive(Default, Clone, Debug)]
549 struct Conflicts {
550     potential: std::collections::HashMap<Id, Vec<Id>>,
551 }
552 
553 impl Conflicts {
new() -> Self554     fn new() -> Self {
555         Self::default()
556     }
557 
gather_conflicts(&mut self, app: &App, matcher: &ArgMatcher, arg_id: &Id) -> Vec<Id>558     fn gather_conflicts(&mut self, app: &App, matcher: &ArgMatcher, arg_id: &Id) -> Vec<Id> {
559         debug!("Conflicts::gather_conflicts");
560         let mut conflicts = Vec::new();
561         for other_arg_id in matcher
562             .arg_names()
563             .filter(|arg_id| matcher.contains_explicit(arg_id))
564         {
565             if arg_id == other_arg_id {
566                 continue;
567             }
568 
569             if self
570                 .gather_direct_conflicts(app, arg_id)
571                 .contains(other_arg_id)
572             {
573                 conflicts.push(other_arg_id.clone());
574             }
575             if self
576                 .gather_direct_conflicts(app, other_arg_id)
577                 .contains(arg_id)
578             {
579                 conflicts.push(other_arg_id.clone());
580             }
581         }
582         conflicts
583     }
584 
gather_direct_conflicts(&mut self, app: &App, arg_id: &Id) -> &[Id]585     fn gather_direct_conflicts(&mut self, app: &App, arg_id: &Id) -> &[Id] {
586         self.potential.entry(arg_id.clone()).or_insert_with(|| {
587             let conf = if let Some(arg) = app.find(arg_id) {
588                 let mut conf = arg.blacklist.clone();
589                 for group_id in app.groups_for_arg(arg_id) {
590                     let group = app.find_group(&group_id).expect(INTERNAL_ERROR_MSG);
591                     conf.extend(group.conflicts.iter().cloned());
592                     if !group.multiple {
593                         for member_id in &group.args {
594                             if member_id != arg_id {
595                                 conf.push(member_id.clone());
596                             }
597                         }
598                     }
599                 }
600                 conf
601             } else if let Some(group) = app.find_group(arg_id) {
602                 group.conflicts.clone()
603             } else {
604                 debug_assert!(false, "id={:?} is unknown", arg_id);
605                 Vec::new()
606             };
607             debug!(
608                 "Conflicts::gather_direct_conflicts id={:?}, conflicts={:?}",
609                 arg_id, conf
610             );
611             conf
612         })
613     }
614 }
615