Merge pull request #1143 from birkenfeld/issue-455
Lint print!("...\n") (closes #455)
This commit is contained in:
commit
ac16695757
@ -255,6 +255,7 @@ All notable changes to this project will be documented in this file.
|
|||||||
[`panic_params`]: https://github.com/Manishearth/rust-clippy/wiki#panic_params
|
[`panic_params`]: https://github.com/Manishearth/rust-clippy/wiki#panic_params
|
||||||
[`precedence`]: https://github.com/Manishearth/rust-clippy/wiki#precedence
|
[`precedence`]: https://github.com/Manishearth/rust-clippy/wiki#precedence
|
||||||
[`print_stdout`]: https://github.com/Manishearth/rust-clippy/wiki#print_stdout
|
[`print_stdout`]: https://github.com/Manishearth/rust-clippy/wiki#print_stdout
|
||||||
|
[`print_with_newline`]: https://github.com/Manishearth/rust-clippy/wiki#print_with_newline
|
||||||
[`ptr_arg`]: https://github.com/Manishearth/rust-clippy/wiki#ptr_arg
|
[`ptr_arg`]: https://github.com/Manishearth/rust-clippy/wiki#ptr_arg
|
||||||
[`range_step_by_zero`]: https://github.com/Manishearth/rust-clippy/wiki#range_step_by_zero
|
[`range_step_by_zero`]: https://github.com/Manishearth/rust-clippy/wiki#range_step_by_zero
|
||||||
[`range_zip_with_len`]: https://github.com/Manishearth/rust-clippy/wiki#range_zip_with_len
|
[`range_zip_with_len`]: https://github.com/Manishearth/rust-clippy/wiki#range_zip_with_len
|
||||||
|
@ -17,7 +17,7 @@ Table of contents:
|
|||||||
|
|
||||||
## Lints
|
## Lints
|
||||||
|
|
||||||
There are 164 lints included in this crate:
|
There are 165 lints included in this crate:
|
||||||
|
|
||||||
name | default | triggers on
|
name | default | triggers on
|
||||||
---------------------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------
|
||||||
@ -130,6 +130,7 @@ name
|
|||||||
[panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` calls
|
[panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` calls
|
||||||
[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | operations where precedence may be unclear
|
[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | operations where precedence may be unclear
|
||||||
[print_stdout](https://github.com/Manishearth/rust-clippy/wiki#print_stdout) | allow | printing on stdout
|
[print_stdout](https://github.com/Manishearth/rust-clippy/wiki#print_stdout) | allow | printing on stdout
|
||||||
|
[print_with_newline](https://github.com/Manishearth/rust-clippy/wiki#print_with_newline) | warn | using `print!()` with a format string that ends in a newline
|
||||||
[ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | warn | arguments of the type `&Vec<...>` (instead of `&[...]`) or `&String` (instead of `&str`)
|
[ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | warn | arguments of the type `&Vec<...>` (instead of `&[...]`) or `&String` (instead of `&str`)
|
||||||
[range_step_by_zero](https://github.com/Manishearth/rust-clippy/wiki#range_step_by_zero) | warn | using `Range::step_by(0)`, which produces an infinite iterator
|
[range_step_by_zero](https://github.com/Manishearth/rust-clippy/wiki#range_step_by_zero) | warn | using `Range::step_by(0)`, which produces an infinite iterator
|
||||||
[range_zip_with_len](https://github.com/Manishearth/rust-clippy/wiki#range_zip_with_len) | warn | zipping iterator with a range when `enumerate()` would do
|
[range_zip_with_len](https://github.com/Manishearth/rust-clippy/wiki#range_zip_with_len) | warn | zipping iterator with a range when `enumerate()` would do
|
||||||
|
@ -69,11 +69,10 @@ impl LateLintPass for Pass {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the expressions matches
|
/// Returns the slice of format string parts in an `Arguments::new_v1` call.
|
||||||
/// ```rust
|
/// Public because it's shared with a lint in print.rs.
|
||||||
/// { static __STATIC_FMTSTR: &[""] = _; __STATIC_FMTSTR }
|
pub fn get_argument_fmtstr_parts<'a, 'b>(cx: &LateContext<'a, 'b>, expr: &'a Expr)
|
||||||
/// ```
|
-> Option<Vec<&'a str>> {
|
||||||
fn check_static_str(cx: &LateContext, expr: &Expr) -> bool {
|
|
||||||
if_let_chain! {[
|
if_let_chain! {[
|
||||||
let ExprBlock(ref block) = expr.node,
|
let ExprBlock(ref block) = expr.node,
|
||||||
block.stmts.len() == 1,
|
block.stmts.len() == 1,
|
||||||
@ -83,16 +82,31 @@ fn check_static_str(cx: &LateContext, expr: &Expr) -> bool {
|
|||||||
decl.name.as_str() == "__STATIC_FMTSTR",
|
decl.name.as_str() == "__STATIC_FMTSTR",
|
||||||
let ItemStatic(_, _, ref expr) = decl.node,
|
let ItemStatic(_, _, ref expr) = decl.node,
|
||||||
let ExprAddrOf(_, ref expr) = expr.node, // &[""]
|
let ExprAddrOf(_, ref expr) = expr.node, // &[""]
|
||||||
let ExprVec(ref expr) = expr.node,
|
let ExprVec(ref exprs) = expr.node,
|
||||||
expr.len() == 1,
|
|
||||||
let ExprLit(ref lit) = expr[0].node,
|
|
||||||
let LitKind::Str(ref lit, _) = lit.node,
|
|
||||||
lit.is_empty()
|
|
||||||
], {
|
], {
|
||||||
return true;
|
let mut result = Vec::new();
|
||||||
|
for expr in exprs {
|
||||||
|
if let ExprLit(ref lit) = expr.node {
|
||||||
|
if let LitKind::Str(ref lit, _) = lit.node {
|
||||||
|
result.push(&**lit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some(result);
|
||||||
}}
|
}}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
false
|
/// Checks if the expressions matches
|
||||||
|
/// ```rust
|
||||||
|
/// { static __STATIC_FMTSTR: &[""] = _; __STATIC_FMTSTR }
|
||||||
|
/// ```
|
||||||
|
fn check_static_str(cx: &LateContext, expr: &Expr) -> bool {
|
||||||
|
if let Some(expr) = get_argument_fmtstr_parts(cx, expr) {
|
||||||
|
expr.len() == 1 && expr[0].is_empty()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the expressions matches
|
/// Checks if the expressions matches
|
||||||
|
@ -403,6 +403,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
|
|||||||
overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
|
overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
|
||||||
panic::PANIC_PARAMS,
|
panic::PANIC_PARAMS,
|
||||||
precedence::PRECEDENCE,
|
precedence::PRECEDENCE,
|
||||||
|
print::PRINT_WITH_NEWLINE,
|
||||||
ptr_arg::PTR_ARG,
|
ptr_arg::PTR_ARG,
|
||||||
ranges::RANGE_STEP_BY_ZERO,
|
ranges::RANGE_STEP_BY_ZERO,
|
||||||
ranges::RANGE_ZIP_WITH_LEN,
|
ranges::RANGE_ZIP_WITH_LEN,
|
||||||
|
@ -3,6 +3,24 @@ use rustc::hir::map::Node::{NodeItem, NodeImplItem};
|
|||||||
use rustc::lint::*;
|
use rustc::lint::*;
|
||||||
use utils::paths;
|
use utils::paths;
|
||||||
use utils::{is_expn_of, match_path, span_lint};
|
use utils::{is_expn_of, match_path, span_lint};
|
||||||
|
use format::get_argument_fmtstr_parts;
|
||||||
|
|
||||||
|
/// **What it does:** This lint warns when you using `print!()` with a format string that
|
||||||
|
/// ends in a newline.
|
||||||
|
///
|
||||||
|
/// **Why is this bad?** You should use `println!()` instead, which appends the newline.
|
||||||
|
///
|
||||||
|
/// **Known problems:** None.
|
||||||
|
///
|
||||||
|
/// **Example:**
|
||||||
|
/// ```rust
|
||||||
|
/// print!("Hello {}!\n", name);
|
||||||
|
/// ```
|
||||||
|
declare_lint! {
|
||||||
|
pub PRINT_WITH_NEWLINE,
|
||||||
|
Warn,
|
||||||
|
"using `print!()` with a format string that ends in a newline"
|
||||||
|
}
|
||||||
|
|
||||||
/// **What it does:** Checks for printing on *stdout*. The purpose of this lint
|
/// **What it does:** Checks for printing on *stdout*. The purpose of this lint
|
||||||
/// is to catch debugging remnants.
|
/// is to catch debugging remnants.
|
||||||
@ -43,7 +61,7 @@ pub struct Pass;
|
|||||||
|
|
||||||
impl LintPass for Pass {
|
impl LintPass for Pass {
|
||||||
fn get_lints(&self) -> LintArray {
|
fn get_lints(&self) -> LintArray {
|
||||||
lint_array!(PRINT_STDOUT, USE_DEBUG)
|
lint_array!(PRINT_WITH_NEWLINE, PRINT_STDOUT, USE_DEBUG)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +80,26 @@ impl LateLintPass for Pass {
|
|||||||
};
|
};
|
||||||
|
|
||||||
span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name));
|
span_lint(cx, PRINT_STDOUT, span, &format!("use of `{}!`", name));
|
||||||
|
|
||||||
|
// Check print! with format string ending in "\n".
|
||||||
|
if_let_chain!{[
|
||||||
|
name == "print",
|
||||||
|
// ensure we're calling Arguments::new_v1
|
||||||
|
args.len() == 1,
|
||||||
|
let ExprCall(ref args_fun, ref args_args) = args[0].node,
|
||||||
|
let ExprPath(_, ref args_path) = args_fun.node,
|
||||||
|
match_path(args_path, &paths::FMT_ARGUMENTS_NEWV1),
|
||||||
|
args_args.len() == 2,
|
||||||
|
// collect the format string parts and check the last one
|
||||||
|
let Some(fmtstrs) = get_argument_fmtstr_parts(cx, &args_args[0]),
|
||||||
|
let Some(last_str) = fmtstrs.last(),
|
||||||
|
let Some(last_chr) = last_str.chars().last(),
|
||||||
|
last_chr == '\n'
|
||||||
|
], {
|
||||||
|
span_lint(cx, PRINT_WITH_NEWLINE, span,
|
||||||
|
"using `print!()` with a format string that ends in a \
|
||||||
|
newline, consider using `println!()` instead");
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Search for something like
|
// Search for something like
|
||||||
|
15
tests/compile-fail/print_with_newline.rs
Executable file
15
tests/compile-fail/print_with_newline.rs
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#![feature(plugin)]
|
||||||
|
#![plugin(clippy)]
|
||||||
|
#![deny(print_with_newline)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
print!("Hello");
|
||||||
|
print!("Hello\n"); //~ERROR using `print!()` with a format string
|
||||||
|
print!("Hello {}\n", "world"); //~ERROR using `print!()` with a format string
|
||||||
|
print!("Hello {} {}\n\n", "world", "#2"); //~ERROR using `print!()` with a format string
|
||||||
|
|
||||||
|
// these are all fine
|
||||||
|
println!("Hello");
|
||||||
|
println!("Hello\n");
|
||||||
|
println!("Hello {}\n", "world");
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user