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}