diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 7a336a8f694..460d54739a2 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -1315,6 +1315,54 @@ pub fn get_associated_type( tcx.try_normalize_erasing_regions(self.param_env, proj).ok() }) } + + /// If the given expression is a local binding, find the initializer expression. + /// If that initializer expression is another local or **outside** (`const`/`static`) + /// binding, find its initializer again. + /// + /// This process repeats as long as possible (but usually no more than once). + /// Type-check adjustments are not taken in account in this function. + /// + /// Examples: + /// ``` + /// const ABC: i32 = 1; + /// // ^ output + /// let def = ABC; + /// dbg!(def); + /// // ^^^ input + /// + /// // or... + /// let abc = 1; + /// let def = abc + 2; + /// // ^^^^^^^ output + /// dbg!(def); + /// // ^^^ input + /// ``` + pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> { + expr = expr.peel_blocks(); + + while let hir::ExprKind::Path(ref qpath) = expr.kind + && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) { + Res::Local(hir_id) => self.tcx.hir().find_parent(hir_id), + Res::Def(_, def_id) => self.tcx.hir().get_if_local(def_id), + _ => None, + } + && let Some(init) = match parent_node { + hir::Node::Expr(expr) => Some(expr), + hir::Node::Local(hir::Local { init, .. }) => *init, + hir::Node::Item(item) => match item.kind { + hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => { + Some(self.tcx.hir().body(body_id).value) + } + _ => None + } + _ => None + } + { + expr = init.peel_blocks(); + } + expr + } } impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {