use rustc::lint::*;
use rustc_front::hir::*;
use syntax::ast::LitKind;
-use utils::{span_lint, in_external_macro, match_path, BEGIN_UNWIND};
+use utils::{span_lint, is_direct_expn_of, match_path, BEGIN_UNWIND};
/// **What it does:** This lint checks for missing parameters in `panic!`.
///
impl LateLintPass for PanicPass {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
if_let_chain! {[
- in_external_macro(cx, expr.span),
let ExprBlock(ref block) = expr.node,
let Some(ref ex) = block.expr,
let ExprCall(ref fun, ref params) = ex.node,
let ExprPath(None, ref path) = fun.node,
match_path(path, &BEGIN_UNWIND),
let ExprLit(ref lit) = params[0].node,
+ is_direct_expn_of(cx, params[0].span, "panic").is_some(),
let LitKind::Str(ref string, _) = lit.node,
let Some(par) = string.find('{'),
- string[par..].contains('}'),
- let Some(sp) = cx.sess().codemap()
- .with_expn_info(expr.span.expn_id,
- |info| info.map(|i| i.call_site))
+ string[par..].contains('}')
], {
-
- span_lint(cx, PANIC_PARAMS, sp,
- "You probably are missing some parameter in your `panic!` call");
+ span_lint(cx, PANIC_PARAMS, params[0].span,
+ "you probably are missing some parameter in your format string");
}}
}
}
}
/// Return the pre-expansion span if is this comes from an expansion of the macro `name`.
+/// See also `is_direct_expn_of`.
pub fn is_expn_of(cx: &LateContext, mut span: Span, name: &str) -> Option<Span> {
loop {
let span_name_span = cx.tcx
}
}
+/// Return the pre-expansion span if is this directly comes from an expansion of the macro `name`.
+/// The difference with `is_expn_of` is that in
+/// ```rust,ignore
+/// foo!(bar!(42));
+/// ```
+/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only `bar!` by
+/// `is_direct_expn_of`.
+pub fn is_direct_expn_of(cx: &LateContext, span: Span, name: &str) -> Option<Span> {
+ let span_name_span = cx.tcx
+ .sess
+ .codemap()
+ .with_expn_info(span.expn_id, |expn| expn.map(|ei| (ei.callee.name(), ei.call_site)));
+
+ match span_name_span {
+ Some((mac_name, new_span)) if mac_name.as_str() == name => Some(new_span),
+ _ => None,
+ }
+}
+
/// Returns index of character after first CamelCase component of `s`
pub fn camel_case_until(s: &str) -> usize {
let mut iter = s.char_indices();
#![feature(plugin)]
#![plugin(clippy)]
-#[deny(panic_params)]
+#![deny(panic_params)]
fn missing() {
if true {
- panic!("{}"); //~ERROR: You probably are missing some parameter
+ panic!("{}"); //~ERROR: you probably are missing some parameter
+ } else if false {
+ panic!("{:?}"); //~ERROR: you probably are missing some parameter
} else {
- panic!("{:?}"); //~ERROR: You probably are missing some parameter
+ assert!(true, "here be missing values: {}"); //~ERROR you probably are missing some parameter
}
}
panic!("foo bar");
}
+fn ok_inner() {
+ // Test for #768
+ assert!("foo bar".contains(&format!("foo {}", "bar")));
+}
+
fn ok_multiple() {
panic!("{}", "This is {ok}");
}
fn ok_bracket() {
- // the match is just here because of #759, it serves no other purpose for the lint
match 42 {
1337 => panic!("{so is this"),
666 => panic!("so is this}"),
ok_single();
ok_multiple();
ok_bracket();
+ ok_inner();
}