diff --git a/README.md b/README.md index dc8fd37dfc9..2c8b20f83a9 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 85 lints included in this crate: +There are 86 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -59,6 +59,7 @@ name [option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`) [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` [out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bound constant indexing +[panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` [precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught [ptr_arg](https://github.com/Manishearth/rust-clippy/wiki#ptr_arg) | warn | fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively [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 diff --git a/src/attrs.rs b/src/attrs.rs index 10db4a551f9..0882f3af41f 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -6,7 +6,7 @@ use reexport::*; use syntax::codemap::Span; use syntax::attr::*; use syntax::ast::{Attribute, MetaList, MetaWord}; -use utils::{in_macro, match_path, span_lint}; +use utils::{in_macro, match_path, span_lint, BEGIN_UNWIND}; /// **What it does:** This lint warns on items annotated with `#[inline(always)]`, unless the annotated function is empty or simply panics. /// @@ -94,7 +94,7 @@ fn is_relevant_expr(expr: &Expr) -> bool { ExprRet(None) | ExprBreak(_) => false, ExprCall(ref path_expr, _) => { if let ExprPath(_, ref path) = path_expr.node { - !match_path(path, &["std", "rt", "begin_unwind"]) + !match_path(path, &BEGIN_UNWIND) } else { true } } _ => true diff --git a/src/lib.rs b/src/lib.rs index 29b911a0cb2..adc1d402e92 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,7 @@ pub mod cyclomatic_complexity; pub mod escape; pub mod misc_early; pub mod array_indexing; +pub mod panic; mod reexport { pub use syntax::ast::{Name, NodeId}; @@ -123,6 +124,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_early_lint_pass(box misc_early::MiscEarly); reg.register_late_lint_pass(box misc::UsedUnderscoreBinding); reg.register_late_lint_pass(box array_indexing::ArrayIndexing); + reg.register_late_lint_pass(box panic::PanicPass); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -198,6 +200,7 @@ pub fn plugin_registrar(reg: &mut Registry) { needless_update::NEEDLESS_UPDATE, no_effect::NO_EFFECT, open_options::NONSENSICAL_OPEN_OPTIONS, + panic::PANIC_PARAMS, precedence::PRECEDENCE, ptr_arg::PTR_ARG, ranges::RANGE_STEP_BY_ZERO, diff --git a/src/panic.rs b/src/panic.rs new file mode 100644 index 00000000000..6f713804e8c --- /dev/null +++ b/src/panic.rs @@ -0,0 +1,42 @@ +use rustc::lint::*; +use rustc_front::hir::*; +use syntax::ast::Lit_::LitStr; + +use utils::{span_lint, in_external_macro, match_path, BEGIN_UNWIND}; + +/// **What it does:** Warn about missing parameters in `panic!`. +/// +/// **Known problems:** Should you want to use curly brackets in `panic!` without any parameter, +/// this lint will warn. +/// +/// **Example:** +/// ``` +/// panic!("This panic! is probably missing a parameter there: {}"); +/// ``` +declare_lint!(pub PANIC_PARAMS, Warn, "missing parameters in `panic!`"); + +#[allow(missing_copy_implementations)] +pub struct PanicPass; + +impl LintPass for PanicPass { + fn get_lints(&self) -> LintArray { + lint_array!(PANIC_PARAMS) + } +} + +impl LateLintPass for PanicPass { + fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { + if_let_chain! {[ + in_external_macro(cx, expr.span), + let ExprCall(ref fun, ref params) = expr.node, + params.len() == 2, + let ExprPath(None, ref path) = fun.node, + match_path(path, &BEGIN_UNWIND), + let ExprLit(ref lit) = params[0].node, + let LitStr(ref string, _) = lit.node, + string.contains('{') + ], { + span_lint(cx, PANIC_PARAMS, expr.span, "You probably are missing some parameter in your `panic!` call"); + }} + } +} diff --git a/src/utils.rs b/src/utils.rs index 92b1cb1cd3a..1ce97ccea4e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -21,6 +21,7 @@ pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "Linke pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"]; +pub const BEGIN_UNWIND:[&'static str; 3] = ["std", "rt", "begin_unwind"]; /// Produce a nested chain of if-lets and ifs from the patterns: /// diff --git a/tests/compile-fail/panic.rs b/tests/compile-fail/panic.rs new file mode 100644 index 00000000000..36427f4330b --- /dev/null +++ b/tests/compile-fail/panic.rs @@ -0,0 +1,22 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(panic_params)] + +fn missing() { + panic!("{}"); //~ERROR: You probably are missing some parameter +} + +fn ok_sigle() { + panic!("foo bar"); +} + +fn ok_multiple() { + panic!("{}", "This is {ok}"); +} + +fn main() { + missing(); + ok_sigle(); + ok_multiple(); +}