2 use rustc::hir::map::Node::{NodeItem, NodeImplItem};
5 use utils::{is_expn_of, match_def_path, resolve_node, span_lint, match_path_old};
6 use format::get_argument_fmtstr_parts;
8 /// **What it does:** This lint warns when you using `print!()` with a format string that
11 /// **Why is this bad?** You should use `println!()` instead, which appends the newline.
13 /// **Known problems:** None.
17 /// print!("Hello {}!\n", name);
20 pub PRINT_WITH_NEWLINE,
22 "using `print!()` with a format string that ends in a newline"
25 /// **What it does:** Checks for printing on *stdout*. The purpose of this lint
26 /// is to catch debugging remnants.
28 /// **Why is this bad?** People often print on *stdout* while debugging an
29 /// application and might forget to remove those prints afterward.
31 /// **Known problems:** Only catches `print!` and `println!` calls.
35 /// println!("Hello world!");
43 /// **What it does:** Checks for use of `Debug` formatting. The purpose of this
44 /// lint is to catch debugging remnants.
46 /// **Why is this bad?** The purpose of the `Debug` trait is to facilitate
47 /// debugging Rust code. It should not be used in in user-facing output.
51 /// println!("{:?}", foo);
56 "use of `Debug`-based formatting"
59 #[derive(Copy, Clone, Debug)]
62 impl LintPass for Pass {
63 fn get_lints(&self) -> LintArray {
64 lint_array!(PRINT_WITH_NEWLINE, PRINT_STDOUT, USE_DEBUG)
68 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
69 fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
71 let ExprCall(ref fun, ref args) = expr.node,
72 let ExprPath(ref qpath) = fun.node,
74 let fun = resolve_node(cx, qpath, fun.id);
75 let fun_id = fun.def_id();
77 // Search for `std::io::_print(..)` which is unique in a
78 // `print!` expansion.
79 if match_def_path(cx.tcx, fun_id, &paths::IO_PRINT) {
80 if let Some(span) = is_expn_of(cx, expr.span, "print") {
81 // `println!` uses `print!`.
82 let (span, name) = match is_expn_of(cx, span, "println") {
83 Some(span) => (span, "println"),
84 None => (span, "print"),
87 span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name));
89 // Check print! with format string ending in "\n".
93 // ensure we're calling Arguments::new_v1
95 let ExprCall(ref args_fun, ref args_args) = args[0].node,
96 let ExprPath(ref qpath) = args_fun.node,
97 match_def_path(cx.tcx,
98 resolve_node(cx, qpath, args_fun.id).def_id(),
99 &paths::FMT_ARGUMENTS_NEWV1),
100 args_args.len() == 2,
101 let ExprAddrOf(_, ref match_expr) = args_args[1].node,
102 let ExprMatch(ref args, _, _) = match_expr.node,
103 let ExprTup(ref args) = args.node,
105 // collect the format string parts and check the last one
106 let Some(fmtstrs) = get_argument_fmtstr_parts(cx, &args_args[0]),
107 let Some(last_str) = fmtstrs.last(),
108 let Some('\n') = last_str.chars().last(),
110 // "foo{}bar" is made into two strings + one argument,
111 // if the format string starts with `{}` (eg. "{}foo"),
112 // the string array is prepended an empty string "".
113 // We only want to check the last string after any `{}`:
114 args.len() < fmtstrs.len(),
116 span_lint(cx, PRINT_WITH_NEWLINE, span,
117 "using `print!()` with a format string that ends in a \
118 newline, consider using `println!()` instead");
122 // Search for something like
123 // `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)`
124 else if args.len() == 2 && match_def_path(cx.tcx, fun_id, &paths::FMT_ARGUMENTV1_NEW) {
125 if let ExprPath(ref qpath) = args[1].node {
126 let def_id = cx.tables.qpath_def(qpath, args[1].id).def_id();
127 if match_def_path(cx.tcx, def_id, &paths::DEBUG_FMT_METHOD) && !is_in_debug_impl(cx, expr) &&
128 is_expn_of(cx, expr.span, "panic").is_none() {
129 span_lint(cx, USE_DEBUG, args[0].span, "use of `Debug`-based formatting");
137 fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool {
138 let map = &cx.tcx.hir;
141 if let Some(NodeImplItem(item)) = map.find(map.get_parent(expr.id)) {
143 if let Some(NodeItem(item)) = map.find(map.get_parent(item.id)) {
144 if let ItemImpl(_, _, _, Some(ref tr), _, _) = item.node {
145 return match_path_old(&tr.path, &["Debug"]);