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
}
}
+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<DefId> {
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
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,
+ }
+}