X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=clippy_lints%2Fsrc%2Futils%2Fmod.rs;h=49d9de35e182160155f06edf5bae6864c7142e2c;hb=52408f5b7d0392b008d647c5414e45dad4c4f5fd;hp=bcb443158397e2b36e7bc9b5f66c0a4e70541b33;hpb=e3c4ffd4aa9a4ec39547c4a5a9715173d4a5f43d;p=rust.git diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index bcb44315839..49d9de35e18 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -47,6 +47,7 @@ use syntax::source_map::{Span, DUMMY_SP}; use syntax::symbol::{kw, Symbol}; +use crate::consts::{constant, Constant}; use crate::reexport::*; /// Returns `true` if the two spans come from differing expansions (i.e., one is @@ -272,6 +273,19 @@ pub fn path_to_res(cx: &LateContext<'_, '_>, path: &[&str]) -> Option<(def::Res) } } +pub fn qpath_res(cx: &LateContext<'_, '_>, qpath: &hir::QPath, id: hir::HirId) -> Res { + match qpath { + hir::QPath::Resolved(_, path) => path.res, + hir::QPath::TypeRelative(..) => { + if cx.tcx.has_typeck_tables(id.owner_def_id()) { + cx.tcx.typeck_tables_of(id.owner_def_id()).qpath_res(qpath, id) + } else { + Res::Err + } + }, + } +} + /// Convenience function to get the `DefId` of a trait by path. /// It could be a trait or trait alias. pub fn get_trait_def_id(cx: &LateContext<'_, '_>, path: &[&str]) -> Option { @@ -669,6 +683,24 @@ fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) { inner(ty, 0) } +/// Checks whether the given expression is a constant integer of the given value. +/// unlike `is_integer_literal`, this version does const folding +pub fn is_integer_const(cx: &LateContext<'_, '_>, e: &Expr, value: u128) -> bool { + if is_integer_literal(e, value) { + return true; + } + let map = cx.tcx.hir(); + let parent_item = map.get_parent_item(e.hir_id); + if let Some((Constant::Int(v), _)) = map + .maybe_body_owned_by(parent_item) + .and_then(|body_id| constant(cx, cx.tcx.body_tables(body_id), e)) + { + value == v + } else { + false + } +} + /// Checks whether the given expression is a constant literal of the given value. pub fn is_integer_literal(expr: &Expr, value: u128) -> bool { // FIXME: use constant folding @@ -1136,3 +1168,47 @@ pub fn match_def_path<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, did: DefId, syms: &[ let path = cx.get_def_path(did); path.len() == syms.len() && path.into_iter().zip(syms.iter()).all(|(a, &b)| a.as_str() == b) } + +/// Returns the list of condition expressions and the list of blocks in a +/// sequence of `if/else`. +/// E.g., this returns `([a, b], [c, d, e])` for the expression +/// `if a { c } else if b { d } else { e }`. +pub fn if_sequence(mut expr: &Expr) -> (SmallVec<[&Expr; 1]>, SmallVec<[&Block; 1]>) { + let mut conds = SmallVec::new(); + let mut blocks: SmallVec<[&Block; 1]> = SmallVec::new(); + + while let Some((ref cond, ref then_expr, ref else_expr)) = higher::if_block(&expr) { + conds.push(&**cond); + if let ExprKind::Block(ref block, _) = then_expr.node { + blocks.push(block); + } else { + panic!("ExprKind::If node is not an ExprKind::Block"); + } + + if let Some(ref else_expr) = *else_expr { + expr = else_expr; + } else { + break; + } + } + + // final `else {..}` + if !blocks.is_empty() { + if let ExprKind::Block(ref block, _) = expr.node { + blocks.push(&**block); + } + } + + (conds, blocks) +} + +pub fn parent_node_is_if_expr<'a, 'b>(expr: &Expr, cx: &LateContext<'a, 'b>) -> bool { + let parent_id = cx.tcx.hir().get_parent_node(expr.hir_id); + let parent_node = cx.tcx.hir().get(parent_id); + + match parent_node { + rustc::hir::Node::Expr(e) => higher::if_block(&e).is_some(), + rustc::hir::Node::Arm(e) => higher::if_block(&e.body).is_some(), + _ => false, + } +}