diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index b38b906b4a6..3b624ff3d6c 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -53,21 +53,6 @@ pub enum Constant { Tuple(Vec), } -impl Constant { - /// Convert to `u64` if possible. - /// - /// # panics - /// - /// If the constant could not be converted to `u64` losslessly. - fn as_u64(&self) -> u64 { - if let Constant::Int(val) = *self { - val.to_u64().expect("negative constant can't be casted to `u64`") - } else { - panic!("Could not convert a `{:?}` to `u64`", self); - } - } -} - impl PartialEq for Constant { fn eq(&self, other: &Constant) -> bool { match (self, other) { @@ -266,11 +251,12 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { ExprLit(ref lit) => Some(lit_to_constant(&lit.node, self.tcx, self.tables.expr_ty(e))), ExprArray(ref vec) => self.multi(vec).map(Constant::Vec), ExprTup(ref tup) => self.multi(tup).map(Constant::Tuple), - ExprRepeat(ref value, number_id) => { - let val = &self.tcx.hir.body(number_id).value; - self.binop_apply(value, - val, - |v, n| Some(Constant::Repeat(Box::new(v), n.as_u64() as usize))) + ExprRepeat(ref value, _) => { + let n = match self.tables.expr_ty(e).sty { + ty::TyArray(_, n) => n, + _ => span_bug!(e.span, "typeck error"), + }; + self.expr(value).map(|v| Constant::Repeat(Box::new(v), n)) }, ExprUnary(op, ref operand) => { self.expr(operand).and_then(|o| match op { @@ -375,15 +361,4 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { _ => None, } } - - - fn binop_apply(&mut self, left: &Expr, right: &Expr, op: F) -> Option - where F: Fn(Constant, Constant) -> Option - { - if let (Some(lc), Some(rc)) = (self.expr(left), self.expr(right)) { - op(lc, rc) - } else { - None - } - } } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 4df2052cdce..8729a39733a 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -10,7 +10,7 @@ use syntax::ast::LitKind; use syntax::codemap::Span; use utils::paths; use utils::{match_type, snippet, span_note_and_lint, span_lint_and_then, in_external_macro, expr_block, walk_ptrs_ty, - is_expn_of}; + is_expn_of, remove_blocks}; use utils::sugg::Sugg; /// **What it does:** Checks for matches with a single arm where an `if let` @@ -179,11 +179,12 @@ fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none() && arms[1].pats.len() == 1 && arms[1].guard.is_none() { - let els = if is_unit_expr(&arms[1].body) { + let els = remove_blocks(&arms[1].body); + let els = if is_unit_expr(els) { None - } else if let ExprBlock(_) = arms[1].body.node { + } else if let ExprBlock(_) = els.node { // matches with blocks that contain statements are prettier as `if let + else` - Some(&*arms[1].body) + Some(els) } else { // allow match arms with just expressions return; @@ -198,29 +199,33 @@ fn check_single_match(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr) { fn check_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) { if arms[1].pats[0].node == PatKind::Wild { - let lint = if els.is_some() { - SINGLE_MATCH_ELSE - } else { - SINGLE_MATCH - }; - let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, ".."))); - span_lint_and_then(cx, - lint, - expr.span, - "you seem to be trying to use match for destructuring a single pattern. \ - Consider using `if let`", - |db| { - db.span_suggestion(expr.span, - "try this", - format!("if let {} = {} {}{}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, ".."), - els_str)); - }); + report_single_match_single_pattern(cx, ex, arms, expr, els); } } +fn report_single_match_single_pattern(cx: &LateContext, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) { + let lint = if els.is_some() { + SINGLE_MATCH_ELSE + } else { + SINGLE_MATCH + }; + let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, ".."))); + span_lint_and_then(cx, + lint, + expr.span, + "you seem to be trying to use match for destructuring a single pattern. \ + Consider using `if let`", + |db| { + db.span_suggestion(expr.span, + "try this", + format!("if let {} = {} {}{}", + snippet(cx, arms[0].pats[0].span, ".."), + snippet(cx, ex.span, ".."), + expr_block(cx, &arms[0].body, None, ".."), + els_str)); + }); +} + fn check_single_match_opt_like( cx: &LateContext, ex: &Expr, @@ -253,26 +258,7 @@ fn check_single_match_opt_like( for &(ty_path, pat_path) in candidates { if &path == pat_path && match_type(cx, ty, ty_path) { - let lint = if els.is_some() { - SINGLE_MATCH_ELSE - } else { - SINGLE_MATCH - }; - let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, ".."))); - span_lint_and_then(cx, - lint, - expr.span, - "you seem to be trying to use match for destructuring a single pattern. Consider \ - using `if let`", - |db| { - db.span_suggestion(expr.span, - "try this", - format!("if let {} = {} {}{}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, ex.span, ".."), - expr_block(cx, &arms[0].body, None, ".."), - els_str)); - }); + report_single_match_single_pattern(cx, ex, arms, expr, els); } } } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 18864d42df2..32e8c90ad99 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -385,7 +385,7 @@ pub fn get_item_name(cx: &LateContext, expr: &Expr) -> Option { /// snippet(cx, expr.span, "..") /// ``` pub fn snippet<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { - cx.sess().codemap().span_to_snippet(span).map(From::from).unwrap_or_else(|_| Cow::Borrowed(default)) + snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from) } /// Convert a span to a code snippet. Returns `None` if not available. diff --git a/tests/run-pass/ice-1588.rs b/tests/run-pass/ice-1588.rs new file mode 100644 index 00000000000..d53d3a1cc75 --- /dev/null +++ b/tests/run-pass/ice-1588.rs @@ -0,0 +1,13 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![allow(clippy)] + +fn main() { + match 1 { + 1 => {} + 2 => { + [0; 1]; + } + _ => {} + } +} diff --git a/tests/run-pass/single-match-else.rs b/tests/run-pass/single-match-else.rs new file mode 100644 index 00000000000..fe3cf1ce71f --- /dev/null +++ b/tests/run-pass/single-match-else.rs @@ -0,0 +1,11 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![warn(single_match_else)] + +fn main() { + let n = match (42, 43) { + (42, n) => n, + _ => panic!("typeck error"), + }; + assert_eq!(n, 43); +}