]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/utils/author.rs
Update upstream source from tag 'upstream/1.52.1+dfsg1'
[rustc.git] / src / tools / clippy / clippy_lints / src / utils / author.rs
CommitLineData
f20569fa
XL
1//! A group of attributes that can be attached to Rust code in order
2//! to generate a clippy lint detecting said code automatically.
3
4use crate::utils::get_attr;
5use rustc_ast::ast::{LitFloatType, LitKind};
6use rustc_ast::walk_list;
7use rustc_data_structures::fx::FxHashMap;
8use rustc_hir as hir;
9use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
10use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, Pat, PatKind, QPath, Stmt, StmtKind, TyKind};
11use rustc_lint::{LateContext, LateLintPass, LintContext};
12use rustc_middle::hir::map::Map;
13use rustc_session::{declare_lint_pass, declare_tool_lint};
14
15declare_clippy_lint! {
16 /// **What it does:** Generates clippy code that detects the offending pattern
17 ///
18 /// **Example:**
19 /// ```rust,ignore
20 /// // ./tests/ui/my_lint.rs
21 /// fn foo() {
22 /// // detect the following pattern
23 /// #[clippy::author]
24 /// if x == 42 {
25 /// // but ignore everything from here on
26 /// #![clippy::author = "ignore"]
27 /// }
28 /// ()
29 /// }
30 /// ```
31 ///
32 /// Running `TESTNAME=ui/my_lint cargo uitest` will produce
33 /// a `./tests/ui/new_lint.stdout` file with the generated code:
34 ///
35 /// ```rust,ignore
36 /// // ./tests/ui/new_lint.stdout
37 /// if_chain! {
38 /// if let ExprKind::If(ref cond, ref then, None) = item.kind,
39 /// if let ExprKind::Binary(BinOp::Eq, ref left, ref right) = cond.kind,
40 /// if let ExprKind::Path(ref path) = left.kind,
41 /// if let ExprKind::Lit(ref lit) = right.kind,
42 /// if let LitKind::Int(42, _) = lit.node,
43 /// then {
44 /// // report your lint here
45 /// }
46 /// }
47 /// ```
48 pub LINT_AUTHOR,
49 internal_warn,
50 "helper for writing lints"
51}
52
53declare_lint_pass!(Author => [LINT_AUTHOR]);
54
55fn prelude() {
56 println!("if_chain! {{");
57}
58
59fn done() {
60 println!(" then {{");
61 println!(" // report your lint here");
62 println!(" }}");
63 println!("}}");
64}
65
66impl<'tcx> LateLintPass<'tcx> for Author {
67 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
68 if !has_attr(cx, item.hir_id()) {
69 return;
70 }
71 prelude();
72 PrintVisitor::new("item").visit_item(item);
73 done();
74 }
75
76 fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
77 if !has_attr(cx, item.hir_id()) {
78 return;
79 }
80 prelude();
81 PrintVisitor::new("item").visit_impl_item(item);
82 done();
83 }
84
85 fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
86 if !has_attr(cx, item.hir_id()) {
87 return;
88 }
89 prelude();
90 PrintVisitor::new("item").visit_trait_item(item);
91 done();
92 }
93
94 fn check_variant(&mut self, cx: &LateContext<'tcx>, var: &'tcx hir::Variant<'_>) {
95 if !has_attr(cx, var.id) {
96 return;
97 }
98 prelude();
99 let parent_hir_id = cx.tcx.hir().get_parent_node(var.id);
100 PrintVisitor::new("var").visit_variant(var, &hir::Generics::empty(), parent_hir_id);
101 done();
102 }
103
104 fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'_>) {
105 if !has_attr(cx, field.hir_id) {
106 return;
107 }
108 prelude();
109 PrintVisitor::new("field").visit_field_def(field);
110 done();
111 }
112
113 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
114 if !has_attr(cx, expr.hir_id) {
115 return;
116 }
117 prelude();
118 PrintVisitor::new("expr").visit_expr(expr);
119 done();
120 }
121
122 fn check_arm(&mut self, cx: &LateContext<'tcx>, arm: &'tcx hir::Arm<'_>) {
123 if !has_attr(cx, arm.hir_id) {
124 return;
125 }
126 prelude();
127 PrintVisitor::new("arm").visit_arm(arm);
128 done();
129 }
130
131 fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) {
132 if !has_attr(cx, stmt.hir_id) {
133 return;
134 }
135 prelude();
136 PrintVisitor::new("stmt").visit_stmt(stmt);
137 done();
138 }
139
140 fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ForeignItem<'_>) {
141 if !has_attr(cx, item.hir_id()) {
142 return;
143 }
144 prelude();
145 PrintVisitor::new("item").visit_foreign_item(item);
146 done();
147 }
148}
149
150impl PrintVisitor {
151 #[must_use]
152 fn new(s: &'static str) -> Self {
153 Self {
154 ids: FxHashMap::default(),
155 current: s.to_owned(),
156 }
157 }
158
159 fn next(&mut self, s: &'static str) -> String {
160 use std::collections::hash_map::Entry::{Occupied, Vacant};
161 match self.ids.entry(s) {
162 // already there: start numbering from `1`
163 Occupied(mut occ) => {
164 let val = occ.get_mut();
165 *val += 1;
166 format!("{}{}", s, *val)
167 },
168 // not there: insert and return name as given
169 Vacant(vac) => {
170 vac.insert(0);
171 s.to_owned()
172 },
173 }
174 }
175
176 fn print_qpath(&mut self, path: &QPath<'_>) {
177 if let QPath::LangItem(lang_item, _) = *path {
178 println!(
179 " if matches!({}, QPath::LangItem(LangItem::{:?}, _));",
180 self.current, lang_item,
181 );
182 } else {
183 print!(" if match_qpath({}, &[", self.current);
184 print_path(path, &mut true);
185 println!("]);");
186 }
187 }
188}
189
190struct PrintVisitor {
191 /// Fields are the current index that needs to be appended to pattern
192 /// binding names
193 ids: FxHashMap<&'static str, usize>,
194 /// the name that needs to be destructured
195 current: String,
196}
197
198impl<'tcx> Visitor<'tcx> for PrintVisitor {
199 type Map = Map<'tcx>;
200
201 #[allow(clippy::too_many_lines)]
202 fn visit_expr(&mut self, expr: &Expr<'_>) {
203 print!(" if let ExprKind::");
204 let current = format!("{}.kind", self.current);
205 match expr.kind {
206 ExprKind::Box(ref inner) => {
207 let inner_pat = self.next("inner");
208 println!("Box(ref {}) = {};", inner_pat, current);
209 self.current = inner_pat;
210 self.visit_expr(inner);
211 },
212 ExprKind::Array(ref elements) => {
213 let elements_pat = self.next("elements");
214 println!("Array(ref {}) = {};", elements_pat, current);
215 println!(" if {}.len() == {};", elements_pat, elements.len());
216 for (i, element) in elements.iter().enumerate() {
217 self.current = format!("{}[{}]", elements_pat, i);
218 self.visit_expr(element);
219 }
220 },
221 ExprKind::Call(ref func, ref args) => {
222 let func_pat = self.next("func");
223 let args_pat = self.next("args");
224 println!("Call(ref {}, ref {}) = {};", func_pat, args_pat, current);
225 self.current = func_pat;
226 self.visit_expr(func);
227 println!(" if {}.len() == {};", args_pat, args.len());
228 for (i, arg) in args.iter().enumerate() {
229 self.current = format!("{}[{}]", args_pat, i);
230 self.visit_expr(arg);
231 }
232 },
233 ExprKind::MethodCall(ref _method_name, ref _generics, ref _args, ref _fn_span) => {
234 println!(
235 "MethodCall(ref method_name, ref generics, ref args, ref fn_span) = {};",
236 current
237 );
238 println!(" // unimplemented: `ExprKind::MethodCall` is not further destructured at the moment");
239 },
240 ExprKind::Tup(ref elements) => {
241 let elements_pat = self.next("elements");
242 println!("Tup(ref {}) = {};", elements_pat, current);
243 println!(" if {}.len() == {};", elements_pat, elements.len());
244 for (i, element) in elements.iter().enumerate() {
245 self.current = format!("{}[{}]", elements_pat, i);
246 self.visit_expr(element);
247 }
248 },
249 ExprKind::Binary(ref op, ref left, ref right) => {
250 let op_pat = self.next("op");
251 let left_pat = self.next("left");
252 let right_pat = self.next("right");
253 println!(
254 "Binary(ref {}, ref {}, ref {}) = {};",
255 op_pat, left_pat, right_pat, current
256 );
257 println!(" if BinOpKind::{:?} == {}.node;", op.node, op_pat);
258 self.current = left_pat;
259 self.visit_expr(left);
260 self.current = right_pat;
261 self.visit_expr(right);
262 },
263 ExprKind::Unary(ref op, ref inner) => {
264 let inner_pat = self.next("inner");
265 println!("Unary(UnOp::{:?}, ref {}) = {};", op, inner_pat, current);
266 self.current = inner_pat;
267 self.visit_expr(inner);
268 },
269 ExprKind::Lit(ref lit) => {
270 let lit_pat = self.next("lit");
271 println!("Lit(ref {}) = {};", lit_pat, current);
272 match lit.node {
273 LitKind::Bool(val) => println!(" if let LitKind::Bool({:?}) = {}.node;", val, lit_pat),
274 LitKind::Char(c) => println!(" if let LitKind::Char({:?}) = {}.node;", c, lit_pat),
275 LitKind::Err(val) => println!(" if let LitKind::Err({}) = {}.node;", val, lit_pat),
276 LitKind::Byte(b) => println!(" if let LitKind::Byte({}) = {}.node;", b, lit_pat),
277 // FIXME: also check int type
278 LitKind::Int(i, _) => println!(" if let LitKind::Int({}, _) = {}.node;", i, lit_pat),
279 LitKind::Float(_, LitFloatType::Suffixed(_)) => println!(
280 " if let LitKind::Float(_, LitFloatType::Suffixed(_)) = {}.node;",
281 lit_pat
282 ),
283 LitKind::Float(_, LitFloatType::Unsuffixed) => println!(
284 " if let LitKind::Float(_, LitFloatType::Unsuffixed) = {}.node;",
285 lit_pat
286 ),
287 LitKind::ByteStr(ref vec) => {
288 let vec_pat = self.next("vec");
289 println!(" if let LitKind::ByteStr(ref {}) = {}.node;", vec_pat, lit_pat);
290 println!(" if let [{:?}] = **{};", vec, vec_pat);
291 },
292 LitKind::Str(ref text, _) => {
293 let str_pat = self.next("s");
294 println!(" if let LitKind::Str(ref {}, _) = {}.node;", str_pat, lit_pat);
295 println!(" if {}.as_str() == {:?}", str_pat, &*text.as_str())
296 },
297 }
298 },
299 ExprKind::Cast(ref expr, ref ty) => {
300 let cast_pat = self.next("expr");
301 let cast_ty = self.next("cast_ty");
302 let qp_label = self.next("qp");
303
304 println!("Cast(ref {}, ref {}) = {};", cast_pat, cast_ty, current);
305 if let TyKind::Path(ref qp) = ty.kind {
306 println!(" if let TyKind::Path(ref {}) = {}.kind;", qp_label, cast_ty);
307 self.current = qp_label;
308 self.print_qpath(qp);
309 }
310 self.current = cast_pat;
311 self.visit_expr(expr);
312 },
313 ExprKind::Type(ref expr, ref _ty) => {
314 let cast_pat = self.next("expr");
315 println!("Type(ref {}, _) = {};", cast_pat, current);
316 self.current = cast_pat;
317 self.visit_expr(expr);
318 },
319 ExprKind::Loop(ref body, _, desugaring, _) => {
320 let body_pat = self.next("body");
321 let des = loop_desugaring_name(desugaring);
322 let label_pat = self.next("label");
323 println!("Loop(ref {}, ref {}, {}) = {};", body_pat, label_pat, des, current);
324 self.current = body_pat;
325 self.visit_block(body);
326 },
327 ExprKind::If(ref cond, ref then, ref opt_else) => {
328 let cond_pat = self.next("cond");
329 let then_pat = self.next("then");
330 if let Some(ref else_) = *opt_else {
331 let else_pat = self.next("else_");
332 println!(
333 "If(ref {}, ref {}, Some(ref {})) = {};",
334 cond_pat, then_pat, else_pat, current
335 );
336 self.current = else_pat;
337 self.visit_expr(else_);
338 } else {
339 println!("If(ref {}, ref {}, None) = {};", cond_pat, then_pat, current);
340 }
341 self.current = cond_pat;
342 self.visit_expr(cond);
343 self.current = then_pat;
344 self.visit_expr(then);
345 },
346 ExprKind::Match(ref expr, ref arms, desugaring) => {
347 let des = desugaring_name(desugaring);
348 let expr_pat = self.next("expr");
349 let arms_pat = self.next("arms");
350 println!("Match(ref {}, ref {}, {}) = {};", expr_pat, arms_pat, des, current);
351 self.current = expr_pat;
352 self.visit_expr(expr);
353 println!(" if {}.len() == {};", arms_pat, arms.len());
354 for (i, arm) in arms.iter().enumerate() {
355 self.current = format!("{}[{}].body", arms_pat, i);
356 self.visit_expr(&arm.body);
357 if let Some(ref guard) = arm.guard {
358 let guard_pat = self.next("guard");
359 println!(" if let Some(ref {}) = {}[{}].guard;", guard_pat, arms_pat, i);
360 match guard {
361 hir::Guard::If(ref if_expr) => {
362 let if_expr_pat = self.next("expr");
363 println!(" if let Guard::If(ref {}) = {};", if_expr_pat, guard_pat);
364 self.current = if_expr_pat;
365 self.visit_expr(if_expr);
366 },
367 hir::Guard::IfLet(ref if_let_pat, ref if_let_expr) => {
368 let if_let_pat_pat = self.next("pat");
369 let if_let_expr_pat = self.next("expr");
370 println!(
371 " if let Guard::IfLet(ref {}, ref {}) = {};",
372 if_let_pat_pat, if_let_expr_pat, guard_pat
373 );
374 self.current = if_let_expr_pat;
375 self.visit_expr(if_let_expr);
376 self.current = if_let_pat_pat;
377 self.visit_pat(if_let_pat);
378 },
379 }
380 }
381 self.current = format!("{}[{}].pat", arms_pat, i);
382 self.visit_pat(&arm.pat);
383 }
384 },
385 ExprKind::Closure(ref _capture_clause, ref _func, _, _, _) => {
386 println!("Closure(ref capture_clause, ref func, _, _, _) = {};", current);
387 println!(" // unimplemented: `ExprKind::Closure` is not further destructured at the moment");
388 },
389 ExprKind::Yield(ref sub, _) => {
390 let sub_pat = self.next("sub");
391 println!("Yield(ref sub) = {};", current);
392 self.current = sub_pat;
393 self.visit_expr(sub);
394 },
395 ExprKind::Block(ref block, _) => {
396 let block_pat = self.next("block");
397 println!("Block(ref {}) = {};", block_pat, current);
398 self.current = block_pat;
399 self.visit_block(block);
400 },
401 ExprKind::Assign(ref target, ref value, _) => {
402 let target_pat = self.next("target");
403 let value_pat = self.next("value");
404 println!(
405 "Assign(ref {}, ref {}, ref _span) = {};",
406 target_pat, value_pat, current
407 );
408 self.current = target_pat;
409 self.visit_expr(target);
410 self.current = value_pat;
411 self.visit_expr(value);
412 },
413 ExprKind::AssignOp(ref op, ref target, ref value) => {
414 let op_pat = self.next("op");
415 let target_pat = self.next("target");
416 let value_pat = self.next("value");
417 println!(
418 "AssignOp(ref {}, ref {}, ref {}) = {};",
419 op_pat, target_pat, value_pat, current
420 );
421 println!(" if BinOpKind::{:?} == {}.node;", op.node, op_pat);
422 self.current = target_pat;
423 self.visit_expr(target);
424 self.current = value_pat;
425 self.visit_expr(value);
426 },
427 ExprKind::Field(ref object, ref field_ident) => {
428 let obj_pat = self.next("object");
429 let field_name_pat = self.next("field_name");
430 println!("Field(ref {}, ref {}) = {};", obj_pat, field_name_pat, current);
431 println!(" if {}.as_str() == {:?}", field_name_pat, field_ident.as_str());
432 self.current = obj_pat;
433 self.visit_expr(object);
434 },
435 ExprKind::Index(ref object, ref index) => {
436 let object_pat = self.next("object");
437 let index_pat = self.next("index");
438 println!("Index(ref {}, ref {}) = {};", object_pat, index_pat, current);
439 self.current = object_pat;
440 self.visit_expr(object);
441 self.current = index_pat;
442 self.visit_expr(index);
443 },
444 ExprKind::Path(ref path) => {
445 let path_pat = self.next("path");
446 println!("Path(ref {}) = {};", path_pat, current);
447 self.current = path_pat;
448 self.print_qpath(path);
449 },
450 ExprKind::AddrOf(kind, mutability, ref inner) => {
451 let inner_pat = self.next("inner");
452 println!(
453 "AddrOf(BorrowKind::{:?}, Mutability::{:?}, ref {}) = {};",
454 kind, mutability, inner_pat, current
455 );
456 self.current = inner_pat;
457 self.visit_expr(inner);
458 },
459 ExprKind::Break(ref _destination, ref opt_value) => {
460 let destination_pat = self.next("destination");
461 if let Some(ref value) = *opt_value {
462 let value_pat = self.next("value");
463 println!("Break(ref {}, Some(ref {})) = {};", destination_pat, value_pat, current);
464 self.current = value_pat;
465 self.visit_expr(value);
466 } else {
467 println!("Break(ref {}, None) = {};", destination_pat, current);
468 }
469 // FIXME: implement label printing
470 },
471 ExprKind::Continue(ref _destination) => {
472 let destination_pat = self.next("destination");
473 println!("Again(ref {}) = {};", destination_pat, current);
474 // FIXME: implement label printing
475 },
476 ExprKind::Ret(ref opt_value) => {
477 if let Some(ref value) = *opt_value {
478 let value_pat = self.next("value");
479 println!("Ret(Some(ref {})) = {};", value_pat, current);
480 self.current = value_pat;
481 self.visit_expr(value);
482 } else {
483 println!("Ret(None) = {};", current);
484 }
485 },
486 ExprKind::InlineAsm(_) => {
487 println!("InlineAsm(_) = {};", current);
488 println!(" // unimplemented: `ExprKind::InlineAsm` is not further destructured at the moment");
489 },
490 ExprKind::LlvmInlineAsm(_) => {
491 println!("LlvmInlineAsm(_) = {};", current);
492 println!(" // unimplemented: `ExprKind::LlvmInlineAsm` is not further destructured at the moment");
493 },
494 ExprKind::Struct(ref path, ref fields, ref opt_base) => {
495 let path_pat = self.next("path");
496 let fields_pat = self.next("fields");
497 if let Some(ref base) = *opt_base {
498 let base_pat = self.next("base");
499 println!(
500 "Struct(ref {}, ref {}, Some(ref {})) = {};",
501 path_pat, fields_pat, base_pat, current
502 );
503 self.current = base_pat;
504 self.visit_expr(base);
505 } else {
506 println!("Struct(ref {}, ref {}, None) = {};", path_pat, fields_pat, current);
507 }
508 self.current = path_pat;
509 self.print_qpath(path);
510 println!(" if {}.len() == {};", fields_pat, fields.len());
511 println!(" // unimplemented: field checks");
512 },
513 ExprKind::ConstBlock(_) => {
514 let value_pat = self.next("value");
515 println!("Const({})", value_pat);
516 self.current = value_pat;
517 },
518 // FIXME: compute length (needs type info)
519 ExprKind::Repeat(ref value, _) => {
520 let value_pat = self.next("value");
521 println!("Repeat(ref {}, _) = {};", value_pat, current);
522 println!("// unimplemented: repeat count check");
523 self.current = value_pat;
524 self.visit_expr(value);
525 },
526 ExprKind::Err => {
527 println!("Err = {}", current);
528 },
529 ExprKind::DropTemps(ref expr) => {
530 let expr_pat = self.next("expr");
531 println!("DropTemps(ref {}) = {};", expr_pat, current);
532 self.current = expr_pat;
533 self.visit_expr(expr);
534 },
535 }
536 }
537
538 fn visit_block(&mut self, block: &Block<'_>) {
539 let trailing_pat = self.next("trailing_expr");
540 println!(" if let Some({}) = &{}.expr;", trailing_pat, self.current);
541 println!(" if {}.stmts.len() == {};", self.current, block.stmts.len());
542 let current = self.current.clone();
543 for (i, stmt) in block.stmts.iter().enumerate() {
544 self.current = format!("{}.stmts[{}]", current, i);
545 self.visit_stmt(stmt);
546 }
547 }
548
549 #[allow(clippy::too_many_lines)]
550 fn visit_pat(&mut self, pat: &Pat<'_>) {
551 print!(" if let PatKind::");
552 let current = format!("{}.kind", self.current);
553 match pat.kind {
554 PatKind::Wild => println!("Wild = {};", current),
555 PatKind::Binding(anno, .., ident, ref sub) => {
556 let anno_pat = match anno {
557 BindingAnnotation::Unannotated => "BindingAnnotation::Unannotated",
558 BindingAnnotation::Mutable => "BindingAnnotation::Mutable",
559 BindingAnnotation::Ref => "BindingAnnotation::Ref",
560 BindingAnnotation::RefMut => "BindingAnnotation::RefMut",
561 };
562 let name_pat = self.next("name");
563 if let Some(ref sub) = *sub {
564 let sub_pat = self.next("sub");
565 println!(
566 "Binding({}, _, {}, Some(ref {})) = {};",
567 anno_pat, name_pat, sub_pat, current
568 );
569 self.current = sub_pat;
570 self.visit_pat(sub);
571 } else {
572 println!("Binding({}, _, {}, None) = {};", anno_pat, name_pat, current);
573 }
574 println!(" if {}.as_str() == \"{}\";", name_pat, ident.as_str());
575 },
576 PatKind::Struct(ref path, ref fields, ignore) => {
577 let path_pat = self.next("path");
578 let fields_pat = self.next("fields");
579 println!(
580 "Struct(ref {}, ref {}, {}) = {};",
581 path_pat, fields_pat, ignore, current
582 );
583 self.current = path_pat;
584 self.print_qpath(path);
585 println!(" if {}.len() == {};", fields_pat, fields.len());
586 println!(" // unimplemented: field checks");
587 },
588 PatKind::Or(ref fields) => {
589 let fields_pat = self.next("fields");
590 println!("Or(ref {}) = {};", fields_pat, current);
591 println!(" if {}.len() == {};", fields_pat, fields.len());
592 println!(" // unimplemented: field checks");
593 },
594 PatKind::TupleStruct(ref path, ref fields, skip_pos) => {
595 let path_pat = self.next("path");
596 let fields_pat = self.next("fields");
597 println!(
598 "TupleStruct(ref {}, ref {}, {:?}) = {};",
599 path_pat, fields_pat, skip_pos, current
600 );
601 self.current = path_pat;
602 self.print_qpath(path);
603 println!(" if {}.len() == {};", fields_pat, fields.len());
604 println!(" // unimplemented: field checks");
605 },
606 PatKind::Path(ref path) => {
607 let path_pat = self.next("path");
608 println!("Path(ref {}) = {};", path_pat, current);
609 self.current = path_pat;
610 self.print_qpath(path);
611 },
612 PatKind::Tuple(ref fields, skip_pos) => {
613 let fields_pat = self.next("fields");
614 println!("Tuple(ref {}, {:?}) = {};", fields_pat, skip_pos, current);
615 println!(" if {}.len() == {};", fields_pat, fields.len());
616 println!(" // unimplemented: field checks");
617 },
618 PatKind::Box(ref pat) => {
619 let pat_pat = self.next("pat");
620 println!("Box(ref {}) = {};", pat_pat, current);
621 self.current = pat_pat;
622 self.visit_pat(pat);
623 },
624 PatKind::Ref(ref pat, muta) => {
625 let pat_pat = self.next("pat");
626 println!("Ref(ref {}, Mutability::{:?}) = {};", pat_pat, muta, current);
627 self.current = pat_pat;
628 self.visit_pat(pat);
629 },
630 PatKind::Lit(ref lit_expr) => {
631 let lit_expr_pat = self.next("lit_expr");
632 println!("Lit(ref {}) = {}", lit_expr_pat, current);
633 self.current = lit_expr_pat;
634 self.visit_expr(lit_expr);
635 },
636 PatKind::Range(ref start, ref end, end_kind) => {
637 let start_pat = self.next("start");
638 let end_pat = self.next("end");
639 println!(
640 "Range(ref {}, ref {}, RangeEnd::{:?}) = {};",
641 start_pat, end_pat, end_kind, current
642 );
643 self.current = start_pat;
644 walk_list!(self, visit_expr, start);
645 self.current = end_pat;
646 walk_list!(self, visit_expr, end);
647 },
648 PatKind::Slice(ref start, ref middle, ref end) => {
649 let start_pat = self.next("start");
650 let end_pat = self.next("end");
651 if let Some(ref middle) = middle {
652 let middle_pat = self.next("middle");
653 println!(
654 "Slice(ref {}, Some(ref {}), ref {}) = {};",
655 start_pat, middle_pat, end_pat, current
656 );
657 self.current = middle_pat;
658 self.visit_pat(middle);
659 } else {
660 println!("Slice(ref {}, None, ref {}) = {};", start_pat, end_pat, current);
661 }
662 println!(" if {}.len() == {};", start_pat, start.len());
663 for (i, pat) in start.iter().enumerate() {
664 self.current = format!("{}[{}]", start_pat, i);
665 self.visit_pat(pat);
666 }
667 println!(" if {}.len() == {};", end_pat, end.len());
668 for (i, pat) in end.iter().enumerate() {
669 self.current = format!("{}[{}]", end_pat, i);
670 self.visit_pat(pat);
671 }
672 },
673 }
674 }
675
676 fn visit_stmt(&mut self, s: &Stmt<'_>) {
677 print!(" if let StmtKind::");
678 let current = format!("{}.kind", self.current);
679 match s.kind {
680 // A local (let) binding:
681 StmtKind::Local(ref local) => {
682 let local_pat = self.next("local");
683 println!("Local(ref {}) = {};", local_pat, current);
684 if let Some(ref init) = local.init {
685 let init_pat = self.next("init");
686 println!(" if let Some(ref {}) = {}.init;", init_pat, local_pat);
687 self.current = init_pat;
688 self.visit_expr(init);
689 }
690 self.current = format!("{}.pat", local_pat);
691 self.visit_pat(&local.pat);
692 },
693 // An item binding:
694 StmtKind::Item(_) => {
695 println!("Item(item_id) = {};", current);
696 },
697
698 // Expr without trailing semi-colon (must have unit type):
699 StmtKind::Expr(ref e) => {
700 let e_pat = self.next("e");
701 println!("Expr(ref {}, _) = {}", e_pat, current);
702 self.current = e_pat;
703 self.visit_expr(e);
704 },
705
706 // Expr with trailing semi-colon (may have any type):
707 StmtKind::Semi(ref e) => {
708 let e_pat = self.next("e");
709 println!("Semi(ref {}, _) = {}", e_pat, current);
710 self.current = e_pat;
711 self.visit_expr(e);
712 },
713 }
714 }
715
716 fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
717 NestedVisitorMap::None
718 }
719}
720
721fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
722 let attrs = cx.tcx.hir().attrs(hir_id);
723 get_attr(cx.sess(), attrs, "author").count() > 0
724}
725
726#[must_use]
727fn desugaring_name(des: hir::MatchSource) -> String {
728 match des {
729 hir::MatchSource::ForLoopDesugar => "MatchSource::ForLoopDesugar".to_string(),
730 hir::MatchSource::TryDesugar => "MatchSource::TryDesugar".to_string(),
731 hir::MatchSource::WhileDesugar => "MatchSource::WhileDesugar".to_string(),
732 hir::MatchSource::WhileLetDesugar => "MatchSource::WhileLetDesugar".to_string(),
733 hir::MatchSource::Normal => "MatchSource::Normal".to_string(),
734 hir::MatchSource::IfLetDesugar { contains_else_clause } => format!(
735 "MatchSource::IfLetDesugar {{ contains_else_clause: {} }}",
736 contains_else_clause
737 ),
738 hir::MatchSource::IfLetGuardDesugar => "MatchSource::IfLetGuardDesugar".to_string(),
739 hir::MatchSource::AwaitDesugar => "MatchSource::AwaitDesugar".to_string(),
740 }
741}
742
743#[must_use]
744fn loop_desugaring_name(des: hir::LoopSource) -> &'static str {
745 match des {
746 hir::LoopSource::ForLoop => "LoopSource::ForLoop",
747 hir::LoopSource::Loop => "LoopSource::Loop",
748 hir::LoopSource::While => "LoopSource::While",
749 hir::LoopSource::WhileLet => "LoopSource::WhileLet",
750 }
751}
752
753fn print_path(path: &QPath<'_>, first: &mut bool) {
754 match *path {
755 QPath::Resolved(_, ref path) => {
756 for segment in path.segments {
757 if *first {
758 *first = false;
759 } else {
760 print!(", ");
761 }
762 print!("{:?}", segment.ident.as_str());
763 }
764 },
765 QPath::TypeRelative(ref ty, ref segment) => match ty.kind {
766 hir::TyKind::Path(ref inner_path) => {
767 print_path(inner_path, first);
768 if *first {
769 *first = false;
770 } else {
771 print!(", ");
772 }
773 print!("{:?}", segment.ident.as_str());
774 },
775 ref other => print!("/* unimplemented: {:?}*/", other),
776 },
777 QPath::LangItem(..) => panic!("print_path: called for lang item qpath"),
778 }
779}