Skip to main content

harper_core/linting/
call_them.rs

1use std::{ops::Range, sync::Arc};
2
3use crate::expr::{Expr, ExprMap, SequenceExpr};
4use crate::patterns::DerivedFrom;
5use crate::{Token, TokenStringExt};
6
7use super::{ExprLinter, Lint, LintKind, Suggestion};
8use crate::linting::expr_linter::Chunk;
9
10pub struct CallThem {
11    expr: ExprMap<Range<usize>>,
12}
13
14impl Default for CallThem {
15    fn default() -> Self {
16        let mut map = ExprMap::default();
17
18        let post_exception = Arc::new(SequenceExpr::default().t_ws().then_word_set(&["if", "it"]));
19
20        map.insert(
21            SequenceExpr::with(DerivedFrom::new_from_str("call"))
22                .t_ws()
23                .then_pronoun()
24                .t_ws()
25                .t_aco("as")
26                .then_unless(post_exception.clone()),
27            3..5,
28        );
29
30        map.insert(
31            SequenceExpr::with(DerivedFrom::new_from_str("call"))
32                .t_ws()
33                .t_aco("as")
34                .t_ws()
35                .then_pronoun()
36                .then_unless(post_exception.clone()),
37            1..3,
38        );
39
40        Self { expr: map }
41    }
42}
43
44impl ExprLinter for CallThem {
45    type Unit = Chunk;
46
47    fn expr(&self) -> &dyn Expr {
48        &self.expr
49    }
50
51    fn match_to_lint(&self, matched_tokens: &[Token], source: &[char]) -> Option<Lint> {
52        let removal_range = self.expr.lookup(0, matched_tokens, source)?.clone();
53        let offending_tokens = matched_tokens.get(removal_range)?;
54
55        Some(Lint {
56            span: offending_tokens.span()?,
57            lint_kind: LintKind::Redundancy,
58            suggestions: vec![Suggestion::Remove],
59            message: "`as` is redundant in this context.".to_owned(),
60            ..Default::default()
61        })
62    }
63
64    fn description(&self) -> &'static str {
65        "Addresses the non-idiomatic phrases `call them as`."
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    #[allow(unused_imports)]
72    use crate::Document;
73    use crate::linting::tests::{assert_no_lints, assert_suggestion_result};
74
75    use super::CallThem;
76
77    #[test]
78    fn prefer_plug_and_receptacle() {
79        assert_suggestion_result(
80            r#"I prefer to call them as Plug (male) and Receptacle (female). Receptacles are seen in laptops, mobile phones etc.."#,
81            CallThem::default(),
82            r#"I prefer to call them Plug (male) and Receptacle (female). Receptacles are seen in laptops, mobile phones etc.."#,
83        );
84    }
85
86    #[test]
87    fn builtins_id() {
88        assert_suggestion_result(
89            r#"I’d categorically ignore *id* as a builtin, and when you do need it in a module, make it super explicit and `import builtins` and call it as `builtins.id`."#,
90            CallThem::default(),
91            r#"I’d categorically ignore *id* as a builtin, and when you do need it in a module, make it super explicit and `import builtins` and call it `builtins.id`."#,
92        );
93    }
94
95    #[test]
96    fn non_modal_dialogue() {
97        assert_suggestion_result(
98            r#"We usually call it as non-modal dialogue e.g. when hit Gmail compose button, a nonmodal dialogue opens."#,
99            CallThem::default(),
100            r#"We usually call it non-modal dialogue e.g. when hit Gmail compose button, a nonmodal dialogue opens."#,
101        );
102    }
103
104    #[test]
105    fn prefer_to_call_them() {
106        assert_suggestion_result(
107            r#"So, how do you typically prefer to call them as?"#,
108            CallThem::default(),
109            r#"So, how do you typically prefer to call them?"#,
110        );
111    }
112
113    #[test]
114    fn called_them_allies() {
115        assert_suggestion_result(
116            r#"Yes as tribes or nomads you called them as allies but you didn’t get their levies as your own."#,
117            CallThem::default(),
118            r#"Yes as tribes or nomads you called them allies but you didn’t get their levies as your own."#,
119        );
120    }
121
122    #[test]
123    fn character_development() {
124        assert_suggestion_result(
125            r#"I call this as character development."#,
126            CallThem::default(),
127            r#"I call this character development."#,
128        );
129    }
130
131    #[test]
132    fn fate_or_time() {
133        assert_suggestion_result(
134            r#"Should I Call It As Fate Or Time"#,
135            CallThem::default(),
136            r#"Should I Call It Fate Or Time"#,
137        );
138    }
139
140    #[test]
141    fn abstract_latte_art() {
142        assert_suggestion_result(
143            r#"Can we just call it as abstract latte art."#,
144            CallThem::default(),
145            r#"Can we just call it abstract latte art."#,
146        );
147    }
148
149    #[test]
150    fn sounding_boards() {
151        assert_suggestion_result(
152            r#"I call them as my ‘sounding boards’"#,
153            CallThem::default(),
154            r#"I call them my ‘sounding boards’"#,
155        );
156    }
157
158    #[test]
159    fn calling_them_disaster() {
160        assert_suggestion_result(
161            r#"I totally disagree with your point listed and calling them as disaster."#,
162            CallThem::default(),
163            r#"I totally disagree with your point listed and calling them disaster."#,
164        );
165    }
166
167    #[test]
168    fn battle_of_boxes() {
169        assert_suggestion_result(
170            r#"Windows Sandbox and VirtualBox or I would like to call this as “Battle of Boxes.”"#,
171            CallThem::default(),
172            r#"Windows Sandbox and VirtualBox or I would like to call this “Battle of Boxes.”"#,
173        );
174    }
175
176    #[test]
177    fn called_her_shinnasan() {
178        assert_suggestion_result(
179            r#"Nice meeting a follower from reddit I called her as Shinna-san, welcome again to Toram!!"#,
180            CallThem::default(),
181            r#"Nice meeting a follower from reddit I called her Shinna-san, welcome again to Toram!!"#,
182        );
183    }
184
185    #[test]
186    fn calling_it_otp() {
187        assert_suggestion_result(
188            r#"Calling it as OTP in this case misleading"#,
189            CallThem::default(),
190            r#"Calling it OTP in this case misleading"#,
191        );
192    }
193
194    #[test]
195    fn call_it_procrastination() {
196        assert_suggestion_result(
197            r#"To summarise it in just one word I would call it as procrastination."#,
198            CallThem::default(),
199            r#"To summarise it in just one word I would call it procrastination."#,
200        );
201    }
202
203    #[test]
204    fn call_her_important() {
205        assert_suggestion_result(
206            r#"Liked the article overall but to call her as important to rap as Jay or Dre is a bold overstatement."#,
207            CallThem::default(),
208            r#"Liked the article overall but to call her important to rap as Jay or Dre is a bold overstatement."#,
209        );
210    }
211
212    #[test]
213    fn call_him_kindles() {
214        assert_suggestion_result(
215            r#"The days when I had my first best friend, I would rather call him as human version of kindle audiobook, who keeps on talking about everything under the umbrella."#,
216            CallThem::default(),
217            r#"The days when I had my first best friend, I would rather call him human version of kindle audiobook, who keeps on talking about everything under the umbrella."#,
218        );
219    }
220
221    #[test]
222    fn call_them_defenders() {
223        assert_suggestion_result(
224            r#"Declaring war challenging land of a vassal should call them as defenders!"#,
225            CallThem::default(),
226            r#"Declaring war challenging land of a vassal should call them defenders!"#,
227        );
228    }
229
230    #[test]
231    fn call_it_magical() {
232        assert_suggestion_result(
233            r#"I would like to call it as magical."#,
234            CallThem::default(),
235            r#"I would like to call it magical."#,
236        );
237    }
238
239    #[test]
240    fn forward_lateral() {
241        assert_suggestion_result(
242            r#"Surprised the refs didn’t call this as a forward lateral."#,
243            CallThem::default(),
244            r#"Surprised the refs didn’t call this a forward lateral."#,
245        );
246    }
247
248    #[test]
249    fn calling_best_friend() {
250        assert_suggestion_result(
251            r#"Meet my buddy! I love calling him as my best friend, because he never failed to bring some cheer in me!"#,
252            CallThem::default(),
253            r#"Meet my buddy! I love calling him my best friend, because he never failed to bring some cheer in me!"#,
254        );
255    }
256
257    #[test]
258    fn calling_everyone_titles() {
259        assert_suggestion_result(
260            r#"Currently, I’m teaching in Asia and the students have the local custom of calling everyone as Mr. Givenname or Miss Givenname"#,
261            CallThem::default(),
262            r#"Currently, I’m teaching in Asia and the students have the local custom of calling everyone Mr. Givenname or Miss Givenname"#,
263        );
264    }
265
266    #[test]
267    fn called_as_he() {
268        assert_suggestion_result(
269            r#"I prefer to be called as he when referred in 3rd person and I’m sure that everyone would be ok to call me as he."#,
270            CallThem::default(),
271            r#"I prefer to be called he when referred in 3rd person and I’m sure that everyone would be ok to call me he."#,
272        );
273    }
274
275    #[test]
276    fn calls_him_bob() {
277        assert_suggestion_result(
278            r#"In Twelve Monkeys, Cole hears someone who calls him as “Bob”"#,
279            CallThem::default(),
280            r#"In Twelve Monkeys, Cole hears someone who calls him “Bob”"#,
281        );
282    }
283
284    #[test]
285    fn pliny_called_it() {
286        assert_suggestion_result(
287            r#"Pliny the Elder called it as lake of Gennesaret or Taricheae in his encyclopedia, Natural History."#,
288            CallThem::default(),
289            r#"Pliny the Elder called it lake of Gennesaret or Taricheae in his encyclopedia, Natural History."#,
290        );
291    }
292
293    #[test]
294    fn students_call_you() {
295        assert_suggestion_result(
296            r#"In the same way your students will call you as ~先生 even after they graduated/move to higher education."#,
297            CallThem::default(),
298            r#"In the same way your students will call you ~先生 even after they graduated/move to higher education."#,
299        );
300    }
301
302    #[test]
303    fn paradoxical_reaction() {
304        assert_suggestion_result(
305            r#"We can call it as Paradoxical Reaction which means a medicine which is used to reduce pain increases the pain when it is"#,
306            CallThem::default(),
307            r#"We can call it Paradoxical Reaction which means a medicine which is used to reduce pain increases the pain when it is"#,
308        );
309    }
310
311    #[test]
312    fn rust_module() {
313        assert_no_lints(
314            "I want to call them as if they were just another Rust module",
315            CallThem::default(),
316        );
317    }
318
319    #[test]
320    fn want_to_do() {
321        assert_no_lints(
322            "however its a design choice to not call it as it does things I don't want to do.",
323            CallThem::default(),
324        );
325    }
326}