]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/mem_discriminant.rs
New upstream version 1.54.0+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / mem_discriminant.rs
CommitLineData
cdc7bbd5
XL
1use clippy_utils::diagnostics::span_lint_and_then;
2use clippy_utils::source::snippet;
3use clippy_utils::ty::walk_ptrs_ty_depth;
4use clippy_utils::{match_def_path, paths};
f20569fa
XL
5use if_chain::if_chain;
6use rustc_errors::Applicability;
7use rustc_hir::{BorrowKind, Expr, ExprKind};
8use rustc_lint::{LateContext, LateLintPass};
9use rustc_session::{declare_lint_pass, declare_tool_lint};
f20569fa
XL
10
11declare_clippy_lint! {
12 /// **What it does:** Checks for calls of `mem::discriminant()` on a non-enum type.
13 ///
14 /// **Why is this bad?** The value of `mem::discriminant()` on non-enum types
15 /// is unspecified.
16 ///
17 /// **Known problems:** None.
18 ///
19 /// **Example:**
20 /// ```rust
21 /// use std::mem;
22 ///
23 /// mem::discriminant(&"hello");
24 /// mem::discriminant(&&Some(2));
25 /// ```
26 pub MEM_DISCRIMINANT_NON_ENUM,
27 correctness,
28 "calling `mem::descriminant` on non-enum type"
29}
30
31declare_lint_pass!(MemDiscriminant => [MEM_DISCRIMINANT_NON_ENUM]);
32
33impl<'tcx> LateLintPass<'tcx> for MemDiscriminant {
34 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
35 if_chain! {
cdc7bbd5 36 if let ExprKind::Call(func, func_args) = expr.kind;
f20569fa
XL
37 // is `mem::discriminant`
38 if let ExprKind::Path(ref func_qpath) = func.kind;
39 if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
40 if match_def_path(cx, def_id, &paths::MEM_DISCRIMINANT);
41 // type is non-enum
42 let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0);
43 if !ty_param.is_enum();
44
45 then {
46 span_lint_and_then(
47 cx,
48 MEM_DISCRIMINANT_NON_ENUM,
49 expr.span,
50 &format!("calling `mem::discriminant` on non-enum type `{}`", ty_param),
51 |diag| {
52 // if this is a reference to an enum, suggest dereferencing
53 let (base_ty, ptr_depth) = walk_ptrs_ty_depth(ty_param);
54 if ptr_depth >= 1 && base_ty.is_enum() {
55 let param = &func_args[0];
56
57 // cancel out '&'s first
58 let mut derefs_needed = ptr_depth;
59 let mut cur_expr = param;
60 while derefs_needed > 0 {
cdc7bbd5 61 if let ExprKind::AddrOf(BorrowKind::Ref, _, inner_expr) = cur_expr.kind {
f20569fa
XL
62 derefs_needed -= 1;
63 cur_expr = inner_expr;
64 } else {
65 break;
66 }
67 }
68
17df50a5 69 let derefs = "*".repeat(derefs_needed);
f20569fa
XL
70 diag.span_suggestion(
71 param.span,
72 "try dereferencing",
73 format!("{}{}", derefs, snippet(cx, cur_expr.span, "<param>")),
74 Applicability::MachineApplicable,
75 );
76 }
77 },
78 )
79 }
80 }
81 }
82}