harper_core/linting/
that_which.rs1use itertools::Itertools;
2
3use crate::{
4 Lrc, Token, TokenStringExt,
5 patterns::{Pattern, SequencePattern, WordPatternGroup},
6};
7
8use super::{Lint, LintKind, PatternLinter, Suggestion};
9
10pub struct ThatWhich {
11 pattern: Box<dyn Pattern>,
12}
13
14impl Default for ThatWhich {
15 fn default() -> Self {
16 let mut pattern = WordPatternGroup::default();
17
18 let matching_pattern = Lrc::new(
19 SequencePattern::default()
20 .then_any_capitalization_of("that")
21 .then_whitespace()
22 .then_any_capitalization_of("that"),
23 );
24
25 pattern.add("that", Box::new(matching_pattern.clone()));
26 pattern.add("That", Box::new(matching_pattern));
27
28 Self {
29 pattern: Box::new(pattern),
30 }
31 }
32}
33
34impl PatternLinter for ThatWhich {
35 fn pattern(&self) -> &dyn Pattern {
36 self.pattern.as_ref()
37 }
38
39 fn match_to_lint(&self, matched_tokens: &[Token], source: &[char]) -> Option<Lint> {
40 let suggestion = format!(
41 "{} which",
42 matched_tokens[0]
43 .span
44 .get_content(source)
45 .iter()
46 .collect::<String>()
47 )
48 .chars()
49 .collect_vec();
50
51 Some(Lint {
52 span: matched_tokens.span()?,
53 lint_kind: LintKind::Repetition,
54 suggestions: vec![Suggestion::ReplaceWith(suggestion)],
55 message: "“that that” sometimes means “that which”, which is clearer.".to_string(),
56 priority: 126,
57 })
58 }
59
60 fn description(&self) -> &'static str {
61 "Repeating the word \"that\" is often redundant. The phrase `that which` is easier to read."
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::super::tests::assert_lint_count;
68 use super::ThatWhich;
69
70 #[test]
71 fn catches_lowercase() {
72 assert_lint_count(
73 "To reiterate, that that is cool is not uncool.",
74 ThatWhich::default(),
75 1,
76 );
77 }
78
79 #[test]
80 fn catches_different_cases() {
81 assert_lint_count("That that is cool is not uncool.", ThatWhich::default(), 1);
82 }
83
84 #[test]
85 fn likes_correction() {
86 assert_lint_count(
87 "To reiterate, that which is cool is not uncool.",
88 ThatWhich::default(),
89 0,
90 );
91 }
92}