X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fissues.rs;h=ad7babca118109a3278f94880bf0c98afb64b761;hb=bb7442802abe354a0ed844ec237cd20969789224;hp=34d5b8ab2c440b7aaabd0791dff06f1d9778991d;hpb=b161815fe0aace4baa7007386b783a88547d7548;p=rust.git diff --git a/src/issues.rs b/src/issues.rs index 34d5b8ab2c4..ad7babca118 100644 --- a/src/issues.rs +++ b/src/issues.rs @@ -8,44 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Objects for seeking through a char stream for occurences of TODO and FIXME. +// Objects for seeking through a char stream for occurrences of TODO and FIXME. // Depending on the loaded configuration, may also check that these have an // associated issue number. use std::fmt; -static TO_DO_CHARS: &'static [char] = &['T', 'O', 'D', 'O']; -static FIX_ME_CHARS: &'static [char] = &['F', 'I', 'X', 'M', 'E']; +use config::ReportTactic; -#[derive(Clone, Copy)] -pub enum ReportTactic { - Always, - Unnumbered, - Never, -} +const TO_DO_CHARS: &[char] = &['t', 'o', 'd', 'o']; +const FIX_ME_CHARS: &[char] = &['f', 'i', 'x', 'm', 'e']; -impl ReportTactic { - fn is_enabled(&self) -> bool { - match *self { - ReportTactic::Always => true, - ReportTactic::Unnumbered => true, - ReportTactic::Never => false - } - } +// Enabled implementation detail is here because it is +// irrelevant outside the issues module +fn is_enabled(report_tactic: ReportTactic) -> bool { + report_tactic != ReportTactic::Never } -impl_enum_decodable!(ReportTactic, Always, Unnumbered, Never); - #[derive(Clone, Copy)] enum Seeking { - Issue { - todo_idx: usize, - fixme_idx: usize, - }, - Number { - issue: Issue, - part: NumberPart, - }, + Issue { todo_idx: usize, fixme_idx: usize }, + Number { issue: Issue, part: NumberPart }, } #[derive(Clone, Copy)] @@ -101,19 +84,29 @@ pub struct BadIssueSeeker { impl BadIssueSeeker { pub fn new(report_todo: ReportTactic, report_fixme: ReportTactic) -> BadIssueSeeker { BadIssueSeeker { - state: Seeking::Issue { todo_idx: 0, fixme_idx: 0 }, - report_todo: report_todo, - report_fixme: report_fixme, + state: Seeking::Issue { + todo_idx: 0, + fixme_idx: 0, + }, + report_todo, + report_fixme, } } + pub fn is_disabled(&self) -> bool { + !is_enabled(self.report_todo) && !is_enabled(self.report_fixme) + } + // Check whether or not the current char is conclusive evidence for an // unnumbered TO-DO or FIX-ME. pub fn inspect(&mut self, c: char) -> Option { match self.state { - Seeking::Issue { todo_idx, fixme_idx } => { + Seeking::Issue { + todo_idx, + fixme_idx, + } => { self.state = self.inspect_issue(c, todo_idx, fixme_idx); - }, + } Seeking::Number { issue, part } => { let result = self.inspect_number(c, issue, part); @@ -121,7 +114,10 @@ pub fn inspect(&mut self, c: char) -> Option { return None; } - self.state = Seeking::Issue { todo_idx: 0, fixme_idx: 0 }; + self.state = Seeking::Issue { + todo_idx: 0, + fixme_idx: 0, + }; if let IssueClassification::Bad(issue) = result { return Some(issue); @@ -133,54 +129,59 @@ pub fn inspect(&mut self, c: char) -> Option { } fn inspect_issue(&mut self, c: char, mut todo_idx: usize, mut fixme_idx: usize) -> Seeking { - // FIXME: Should we also check for lower case characters? - if self.report_todo.is_enabled() && c == TO_DO_CHARS[todo_idx] { - todo_idx += 1; - if todo_idx == TO_DO_CHARS.len() { - return Seeking::Number { - issue: Issue { - issue_type: IssueType::Todo, - missing_number: if let ReportTactic::Unnumbered = self.report_todo { - true - } else { - false - } - }, - part: NumberPart::OpenParen - }; - } - fixme_idx = 0; - } else if self.report_fixme.is_enabled() && c == FIX_ME_CHARS[fixme_idx] { - // Exploit the fact that the character sets of todo and fixme - // are disjoint by adding else. - fixme_idx += 1; - if fixme_idx == FIX_ME_CHARS.len() { - return Seeking::Number { - issue: Issue { - issue_type: IssueType::Fixme, - missing_number: if let ReportTactic::Unnumbered = self.report_fixme { - true - } else { - false - } - }, - part: NumberPart::OpenParen - }; + if let Some(lower_case_c) = c.to_lowercase().next() { + if is_enabled(self.report_todo) && lower_case_c == TO_DO_CHARS[todo_idx] { + todo_idx += 1; + if todo_idx == TO_DO_CHARS.len() { + return Seeking::Number { + issue: Issue { + issue_type: IssueType::Todo, + missing_number: if let ReportTactic::Unnumbered = self.report_todo { + true + } else { + false + }, + }, + part: NumberPart::OpenParen, + }; + } + fixme_idx = 0; + } else if is_enabled(self.report_fixme) && lower_case_c == FIX_ME_CHARS[fixme_idx] { + // Exploit the fact that the character sets of todo and fixme + // are disjoint by adding else. + fixme_idx += 1; + if fixme_idx == FIX_ME_CHARS.len() { + return Seeking::Number { + issue: Issue { + issue_type: IssueType::Fixme, + missing_number: if let ReportTactic::Unnumbered = self.report_fixme { + true + } else { + false + }, + }, + part: NumberPart::OpenParen, + }; + } + todo_idx = 0; + } else { + todo_idx = 0; + fixme_idx = 0; } - todo_idx = 0; - } else { - todo_idx = 0; - fixme_idx = 0; } - Seeking::Issue { todo_idx: todo_idx, fixme_idx: fixme_idx } + Seeking::Issue { + todo_idx, + fixme_idx, + } } - fn inspect_number(&mut self, - c: char, - issue: Issue, - mut part: NumberPart) - -> IssueClassification { + fn inspect_number( + &mut self, + c: char, + issue: Issue, + mut part: NumberPart, + ) -> IssueClassification { if !issue.missing_number || c == '\n' { return IssueClassification::Bad(issue); } else if c == ')' { @@ -198,26 +199,23 @@ fn inspect_number(&mut self, } else { part = NumberPart::Pound; } - }, + } NumberPart::Pound => { if c == '#' { part = NumberPart::Number; } - }, + } NumberPart::Number => { if c >= '0' && c <= '9' { part = NumberPart::CloseParen; } else { return IssueClassification::Bad(issue); } - }, + } NumberPart::CloseParen => {} } - self.state = Seeking::Number { - part: part, - issue: issue - }; + self.state = Seeking::Number { part, issue }; IssueClassification::None } @@ -227,12 +225,15 @@ fn inspect_number(&mut self, fn find_unnumbered_issue() { fn check_fail(text: &str, failing_pos: usize) { let mut seeker = BadIssueSeeker::new(ReportTactic::Unnumbered, ReportTactic::Unnumbered); - assert_eq!(Some(failing_pos), text.chars().position(|c| seeker.inspect(c).is_some())); + assert_eq!( + Some(failing_pos), + text.find(|c| seeker.inspect(c).is_some()) + ); } fn check_pass(text: &str) { let mut seeker = BadIssueSeeker::new(ReportTactic::Unnumbered, ReportTactic::Unnumbered); - assert_eq!(None, text.chars().position(|c| seeker.inspect(c).is_some())); + assert_eq!(None, text.find(|c| seeker.inspect(c).is_some())); } check_fail("TODO\n", 4); @@ -255,40 +256,72 @@ fn is_bad_issue(text: &str, report_todo: ReportTactic, report_fixme: ReportTacti text.chars().any(|c| seeker.inspect(c).is_some()) } - assert!(is_bad_issue("TODO(@maintainer, #1222, hello)\n", - ReportTactic::Always, - ReportTactic::Never)); - - assert!(! is_bad_issue("TODO: no number\n", - ReportTactic::Never, - ReportTactic::Always)); - - assert!(is_bad_issue("This is a FIXME(#1)\n", - ReportTactic::Never, - ReportTactic::Always)); - - assert!(! is_bad_issue("bad FIXME\n", - ReportTactic::Always, - ReportTactic::Never)); + assert!(is_bad_issue( + "TODO(@maintainer, #1222, hello)\n", + ReportTactic::Always, + ReportTactic::Never, + )); + + assert!(!is_bad_issue( + "TODO: no number\n", + ReportTactic::Never, + ReportTactic::Always, + )); + + assert!(!is_bad_issue( + "Todo: mixed case\n", + ReportTactic::Never, + ReportTactic::Always, + )); + + assert!(is_bad_issue( + "This is a FIXME(#1)\n", + ReportTactic::Never, + ReportTactic::Always, + )); + + assert!(is_bad_issue( + "This is a FixMe(#1) mixed case\n", + ReportTactic::Never, + ReportTactic::Always, + )); + + assert!(!is_bad_issue( + "bad FIXME\n", + ReportTactic::Always, + ReportTactic::Never, + )); } #[test] fn issue_type() { let mut seeker = BadIssueSeeker::new(ReportTactic::Always, ReportTactic::Never); - let expected = Some(Issue { issue_type: IssueType::Todo, missing_number: false }); - - assert_eq!(expected, - "TODO(#100): more awesomeness".chars() - .map(|c| seeker.inspect(c)) - .find(Option::is_some) - .unwrap()); + let expected = Some(Issue { + issue_type: IssueType::Todo, + missing_number: false, + }); + + assert_eq!( + expected, + "TODO(#100): more awesomeness" + .chars() + .map(|c| seeker.inspect(c)) + .find(Option::is_some) + .unwrap() + ); let mut seeker = BadIssueSeeker::new(ReportTactic::Never, ReportTactic::Unnumbered); - let expected = Some(Issue { issue_type: IssueType::Fixme, missing_number: true }); - - assert_eq!(expected, - "Test. FIXME: bad, bad, not good".chars() - .map(|c| seeker.inspect(c)) - .find(Option::is_some) - .unwrap()); + let expected = Some(Issue { + issue_type: IssueType::Fixme, + missing_number: true, + }); + + assert_eq!( + expected, + "Test. FIXME: bad, bad, not good" + .chars() + .map(|c| seeker.inspect(c)) + .find(Option::is_some) + .unwrap() + ); }