harper_core/linting/
quantifier_needs_of.rs

1use crate::Token;
2use crate::expr::{Expr, SequenceExpr};
3use crate::patterns::WordSet;
4
5use super::{ExprLinter, Lint, LintKind, Suggestion};
6
7/// Flags phrases like `a couple months` → should be `a couple **of** months`.
8pub struct QuantifierNeedsOf {
9    expr: Box<dyn Expr>,
10}
11
12impl Default for QuantifierNeedsOf {
13    fn default() -> Self {
14        let expr = SequenceExpr::default()
15            .then_indefinite_article()
16            .t_ws()
17            .then(WordSet::new(&["couple", "lot"]))
18            .t_ws()
19            .then_plural_nominal();
20
21        Self {
22            expr: Box::new(expr),
23        }
24    }
25}
26
27impl ExprLinter for QuantifierNeedsOf {
28    fn expr(&self) -> &dyn Expr {
29        self.expr.as_ref()
30    }
31
32    fn match_to_lint(&self, matched_tokens: &[Token], _source: &[char]) -> Option<Lint> {
33        Some(Lint {
34            span: matched_tokens.get(2)?.span,
35            lint_kind: LintKind::Miscellaneous,
36            suggestions: vec![Suggestion::InsertAfter(" of".chars().collect())],
37            message: "Add `of` in this quantity phrase.".to_owned(),
38            priority: 32,
39        })
40    }
41
42    fn description(&self) -> &'static str {
43        "Detects missing `of` after the quantifier “a couple” when it precedes a plural noun"
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use crate::linting::tests::assert_suggestion_result;
50
51    use super::QuantifierNeedsOf;
52
53    #[test]
54    fn fixes_a_couple_months() {
55        assert_suggestion_result(
56            "A couple months ago...",
57            QuantifierNeedsOf::default(),
58            "A couple of months ago...",
59        );
60    }
61
62    #[test]
63    fn fixes_a_couple_weeks() {
64        assert_suggestion_result(
65            "A couple weeks ago...",
66            QuantifierNeedsOf::default(),
67            "A couple of weeks ago...",
68        );
69    }
70
71    #[test]
72    fn fixes_a_couple_days() {
73        assert_suggestion_result(
74            "A couple days ago...",
75            QuantifierNeedsOf::default(),
76            "A couple of days ago...",
77        );
78    }
79
80    #[test]
81    fn fixes_a_couple_seconds() {
82        assert_suggestion_result(
83            "A couple seconds ago...",
84            QuantifierNeedsOf::default(),
85            "A couple of seconds ago...",
86        );
87    }
88
89    #[test]
90    fn fixes_a_couple_minutes() {
91        assert_suggestion_result(
92            "A couple minutes ago...",
93            QuantifierNeedsOf::default(),
94            "A couple of minutes ago...",
95        );
96    }
97
98    #[test]
99    fn fixes_a_couple_houses() {
100        assert_suggestion_result(
101            "A couple houses ago...",
102            QuantifierNeedsOf::default(),
103            "A couple of houses ago...",
104        );
105    }
106
107    #[test]
108    fn fixes_a_couple_centuries() {
109        assert_suggestion_result(
110            "A couple centuries ago...",
111            QuantifierNeedsOf::default(),
112            "A couple of centuries ago...",
113        );
114    }
115
116    #[test]
117    fn fixes_a_couple_people() {
118        assert_suggestion_result(
119            "I saw a couple people walk by a few minutes ago.",
120            QuantifierNeedsOf::default(),
121            "I saw a couple of people walk by a few minutes ago.",
122        );
123    }
124}