]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
New upstream version 1.52.1+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / methods / get_unwrap.rs
CommitLineData
f20569fa
XL
1use crate::methods::derefs_to_slice;
2use crate::utils::{
3 get_parent_expr, is_type_diagnostic_item, match_type, paths, snippet_with_applicability, span_lint_and_sugg,
4};
5use if_chain::if_chain;
6use rustc_errors::Applicability;
7use rustc_hir as hir;
8use rustc_lint::LateContext;
9use rustc_span::sym;
10
11use super::GET_UNWRAP;
12
13pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: &'tcx [hir::Expr<'_>], is_mut: bool) {
14 // Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`,
15 // because they do not implement `IndexMut`
16 let mut applicability = Applicability::MachineApplicable;
17 let expr_ty = cx.typeck_results().expr_ty(&get_args[0]);
18 let get_args_str = if get_args.len() > 1 {
19 snippet_with_applicability(cx, get_args[1].span, "..", &mut applicability)
20 } else {
21 return; // not linting on a .get().unwrap() chain or variant
22 };
23 let mut needs_ref;
24 let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() {
25 needs_ref = get_args_str.parse::<usize>().is_ok();
26 "slice"
27 } else if is_type_diagnostic_item(cx, expr_ty, sym::vec_type) {
28 needs_ref = get_args_str.parse::<usize>().is_ok();
29 "Vec"
30 } else if is_type_diagnostic_item(cx, expr_ty, sym::vecdeque_type) {
31 needs_ref = get_args_str.parse::<usize>().is_ok();
32 "VecDeque"
33 } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::hashmap_type) {
34 needs_ref = true;
35 "HashMap"
36 } else if !is_mut && match_type(cx, expr_ty, &paths::BTREEMAP) {
37 needs_ref = true;
38 "BTreeMap"
39 } else {
40 return; // caller is not a type that we want to lint
41 };
42
43 let mut span = expr.span;
44
45 // Handle the case where the result is immediately dereferenced
46 // by not requiring ref and pulling the dereference into the
47 // suggestion.
48 if_chain! {
49 if needs_ref;
50 if let Some(parent) = get_parent_expr(cx, expr);
51 if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind;
52 then {
53 needs_ref = false;
54 span = parent.span;
55 }
56 }
57
58 let mut_str = if is_mut { "_mut" } else { "" };
59 let borrow_str = if !needs_ref {
60 ""
61 } else if is_mut {
62 "&mut "
63 } else {
64 "&"
65 };
66
67 span_lint_and_sugg(
68 cx,
69 GET_UNWRAP,
70 span,
71 &format!(
72 "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise",
73 mut_str, caller_type
74 ),
75 "try this",
76 format!(
77 "{}{}[{}]",
78 borrow_str,
79 snippet_with_applicability(cx, get_args[0].span, "..", &mut applicability),
80 get_args_str
81 ),
82 applicability,
83 );
84}