diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index 16ab44881a55..ab8b7d8b2b8f 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -1,8 +1,10 @@ //! This module contains functions for retrieve the original AST from lowered `hir`. use rustc::hir; +use rustc::lint::LateContext; use syntax::ast; -use utils::{match_path, paths}; +use syntax::ptr::P; +use utils::{is_expn_of, match_path, paths}; /// Convert a hir binary operator to the corresponding `ast` type. pub fn binop(op: hir::BinOp_) -> ast::BinOpKind { @@ -148,3 +150,41 @@ pub fn for_loop(expr: &hir::Expr) -> Option<(&hir::Pat, &hir::Expr, &hir::Expr)> }} None } + +/// Represent the pre-expansion arguments of a `vec!` invocation. +pub enum VecArgs<'a> { + /// `vec![elem; len]` + Repeat(&'a P, &'a P), + /// `vec![a, b, c]` + Vec(&'a [P]), +} + +/// Returns the arguments of the `vec!` macro if this expression was expanded from `vec!`. +pub fn vec_macro<'e>(cx: &LateContext, expr: &'e hir::Expr) -> Option> { + if_let_chain!{[ + let hir::ExprCall(ref fun, ref args) = expr.node, + let hir::ExprPath(_, ref path) = fun.node, + is_expn_of(cx, fun.span, "vec").is_some() + ], { + return if match_path(path, &paths::VEC_FROM_ELEM) && args.len() == 2 { + // `vec![elem; size]` case + Some(VecArgs::Repeat(&args[0], &args[1])) + } + else if match_path(path, &["into_vec"]) && args.len() == 1 { + // `vec![a, b, c]` case + if_let_chain!{[ + let hir::ExprBox(ref boxed) = args[0].node, + let hir::ExprVec(ref args) = boxed.node + ], { + return Some(VecArgs::Vec(&*args)); + }} + + None + } + else { + None + }; + }} + + None +} diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 97a45da4536f..8e09f9341c2d 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -2,8 +2,7 @@ use rustc::lint::*; use rustc::ty::TypeVariants; use rustc::hir::*; use syntax::codemap::Span; -use syntax::ptr::P; -use utils::{higher, is_expn_of, match_path, paths, snippet, span_lint_and_then}; +use utils::{higher, snippet, span_lint_and_then}; /// **What it does:** This lint warns about using `&vec![..]` when using `&[..]` would be possible. /// @@ -51,12 +50,12 @@ impl LateLintPass for Pass { } fn check_vec_macro(cx: &LateContext, vec: &Expr, span: Span) { - if let Some(vec_args) = unexpand(cx, vec) { + if let Some(vec_args) = higher::vec_macro(cx, vec) { let snippet = match vec_args { - Args::Repeat(elem, len) => { + higher::VecArgs::Repeat(elem, len) => { format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into() } - Args::Vec(args) => { + higher::VecArgs::Vec(args) => { if let Some(last) = args.iter().last() { let span = Span { lo: args[0].span.lo, @@ -77,40 +76,3 @@ fn check_vec_macro(cx: &LateContext, vec: &Expr, span: Span) { } } -/// Represent the pre-expansion arguments of a `vec!` invocation. -pub enum Args<'a> { - /// `vec![elem; len]` - Repeat(&'a P, &'a P), - /// `vec![a, b, c]` - Vec(&'a [P]), -} - -/// Returns the arguments of the `vec!` macro if this expression was expanded from `vec!`. -pub fn unexpand<'e>(cx: &LateContext, expr: &'e Expr) -> Option> { - if_let_chain!{[ - let ExprCall(ref fun, ref args) = expr.node, - let ExprPath(_, ref path) = fun.node, - is_expn_of(cx, fun.span, "vec").is_some() - ], { - return if match_path(path, &paths::VEC_FROM_ELEM) && args.len() == 2 { - // `vec![elem; size]` case - Some(Args::Repeat(&args[0], &args[1])) - } - else if match_path(path, &["into_vec"]) && args.len() == 1 { - // `vec![a, b, c]` case - if_let_chain!{[ - let ExprBox(ref boxed) = args[0].node, - let ExprVec(ref args) = boxed.node - ], { - return Some(Args::Vec(&*args)); - }} - - None - } - else { - None - }; - }} - - None -}