]> git.lizzy.rs Git - rust.git/blob - src/print.rs
Merge pull request #928 from oli-obk/unnecessary_operation
[rust.git] / src / print.rs
1 use rustc::hir::*;
2 use rustc::hir::map::Node::{NodeItem, NodeImplItem};
3 use rustc::lint::*;
4 use utils::paths;
5 use utils::{is_expn_of, match_path, span_lint};
6
7 /// **What it does:** This lint warns whenever you print on *stdout*. The purpose of this lint is to catch debugging remnants.
8 ///
9 /// **Why is this bad?** People often print on *stdout* while debugging an application and might
10 /// forget to remove those prints afterward.
11 ///
12 /// **Known problems:** Only catches `print!` and `println!` calls.
13 ///
14 /// **Example:** `println!("Hello world!");`
15 declare_lint! {
16     pub PRINT_STDOUT,
17     Allow,
18     "printing on stdout"
19 }
20
21 /// **What it does:** This lint warns whenever you use `Debug` formatting. The purpose of this lint is to catch debugging remnants.
22 ///
23 /// **Why is this bad?** The purpose of the `Debug` trait is to facilitate debugging Rust code. It
24 /// should not be used in in user-facing output.
25 ///
26 /// **Example:** `println!("{:?}", foo);`
27 declare_lint! {
28     pub USE_DEBUG,
29     Allow,
30     "use `Debug`-based formatting"
31 }
32
33 #[derive(Copy, Clone, Debug)]
34 pub struct PrintLint;
35
36 impl LintPass for PrintLint {
37     fn get_lints(&self) -> LintArray {
38         lint_array!(PRINT_STDOUT, USE_DEBUG)
39     }
40 }
41
42 impl LateLintPass for PrintLint {
43     fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
44         if let ExprCall(ref fun, ref args) = expr.node {
45             if let ExprPath(_, ref path) = fun.node {
46                 // Search for `std::io::_print(..)` which is unique in a
47                 // `print!` expansion.
48                 if match_path(path, &paths::IO_PRINT) {
49                     if let Some(span) = is_expn_of(cx, expr.span, "print") {
50                         // `println!` uses `print!`.
51                         let (span, name) = match is_expn_of(cx, span, "println") {
52                             Some(span) => (span, "println"),
53                             None => (span, "print"),
54                         };
55
56                         span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name));
57                     }
58                 }
59                 // Search for something like
60                 // `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)`
61                 else if args.len() == 2 && match_path(path, &paths::FMT_ARGUMENTV1_NEW) {
62                     if let ExprPath(None, ref path) = args[1].node {
63                         if match_path(path, &paths::DEBUG_FMT_METHOD) && !is_in_debug_impl(cx, expr) &&
64                            is_expn_of(cx, expr.span, "panic").is_none() {
65                             span_lint(cx, USE_DEBUG, args[0].span, "use of `Debug`-based formatting");
66                         }
67                     }
68                 }
69             }
70         }
71     }
72 }
73
74 fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool {
75     let map = &cx.tcx.map;
76
77     // `fmt` method
78     if let Some(NodeImplItem(item)) = map.find(map.get_parent(expr.id)) {
79         // `Debug` impl
80         if let Some(NodeItem(item)) = map.find(map.get_parent(item.id)) {
81             if let ItemImpl(_, _, _, Some(ref tr), _, _) = item.node {
82                 return match_path(&tr.path, &["Debug"]);
83             }
84         }
85     }
86
87     false
88 }