From 6cb94630fb6220240730e2bed8d82f80a107696d Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Thu, 16 Aug 2018 18:20:06 +0200 Subject: [PATCH] WIP of #3016 for hardocded suggestion for writeln on empty string --- clippy_lints/src/write.rs | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index e8c7225041f..9b0b25f3921 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -179,7 +179,7 @@ impl EarlyLintPass for Pass { fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &Mac) { if mac.node.path == "println" { span_lint(cx, PRINT_STDOUT, mac.span, "use of `println!`"); - if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false) { + if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 { if fmtstr == "" { span_lint_and_sugg( cx, @@ -193,7 +193,7 @@ impl EarlyLintPass for Pass { } } else if mac.node.path == "print" { span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`"); - if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false) { + if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 { if fmtstr.ends_with("\\n") && !fmtstr.ends_with("\\n\\n") { span_lint(cx, PRINT_WITH_NEWLINE, mac.span, "using `print!()` with a format string that ends in a \ @@ -201,7 +201,7 @@ impl EarlyLintPass for Pass { } } } else if mac.node.path == "write" { - if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true) { + if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true).0 { if fmtstr.ends_with("\\n") && !fmtstr.ends_with("\\n\\n") { span_lint(cx, WRITE_WITH_NEWLINE, mac.span, "using `write!()` with a format string that ends in a \ @@ -209,15 +209,16 @@ impl EarlyLintPass for Pass { } } } else if mac.node.path == "writeln" { - if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true) { + let check_tts = check_tts(cx, &mac.node.tts, true); + if let Some(fmtstr) = check_tts.0 { if fmtstr == "" { span_lint_and_sugg( cx, WRITELN_EMPTY_STRING, mac.span, - "using `writeln!(v, \"\")`", + format!("using `writeln!({}, \"\")`", check_tts.1).as_str(), "replace it with", - "writeln!(v)".to_string(), + format!("using `writeln!({})`", check_tts.1), ); } } @@ -225,7 +226,7 @@ impl EarlyLintPass for Pass { } } -fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> Option { +fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> (Option, Option) { let tts = TokenStream::from(tts.clone()); let mut parser = parser::Parser::new( &cx.sess.parse_sess, @@ -234,12 +235,14 @@ fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) - false, false, ); - if is_write { - // skip the initial write target - parser.parse_expr().map_err(|mut err| err.cancel()).ok()?; - // might be `writeln!(foo)` - parser.expect(&token::Comma).map_err(|mut err| err.cancel()).ok()?; - } + // skip the initial write target + let expr: Option = match parser.parse_expr().map_err(|mut err| err.cancel()).ok() { + Some(p) => Some(p.into_vec().0), + None => None, + }; + // might be `writeln!(foo)` + parser.expect(&token::Comma).map_err(|mut err| err.cancel()).ok()?; + let fmtstr = parser.parse_str().map_err(|mut err| err.cancel()).ok()?.0.to_string(); use fmt_macros::*; let tmp = fmtstr.clone(); @@ -247,7 +250,7 @@ fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) - let mut fmt_parser = Parser::new(&tmp, None); while let Some(piece) = fmt_parser.next() { if !fmt_parser.errors.is_empty() { - return None; + return (None, expr); } if let Piece::NextArgument(arg) = piece { if arg.format.ty == "?" { @@ -266,7 +269,7 @@ fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) - loop { if !parser.eat(&token::Comma) { assert!(parser.eat(&token::Eof)); - return Some(fmtstr); + return (Some(fmtstr), expr); } let expr = parser.parse_expr().map_err(|mut err| err.cancel()).ok()?; const SIMPLE: FormatSpec<'_> = FormatSpec {