1
1
//! lint on using `x.get(x.len() - 1)` instead of `x.last()`
2
2
3
- use crate :: utils:: { match_type, paths, span_lint } ;
3
+ use crate :: utils:: { match_type, paths, span_lint_and_sugg , snippet_with_applicability } ;
4
4
use rustc:: lint:: { LateContext , LateLintPass , LintArray , LintPass } ;
5
5
use rustc:: { declare_tool_lint, lint_array} ;
6
6
use rustc:: hir:: { Expr , ExprKind } ;
7
+ use rustc_errors:: Applicability ;
7
8
use syntax:: ast:: { LitKind } ;
8
9
use if_chain:: if_chain;
9
10
10
11
/// **What it does:** Checks for using `x.get(x.len() - 1)` instead of `x.last()`.
11
12
///
12
13
/// **Why is this bad?** Using `x.last()` is easier to read and has the same result.
13
14
///
14
- /// Note that using x[x.len() - 1] is semantically different from x.last(),
15
- /// since indexing into the array will panic on out-of-bounds accesses, while
16
- /// x.get() and x.last() will return None.
15
+ /// Note that using `x[x.len() - 1]` is semantically different from `x.last()`.
16
+ /// Indexing into the array will panic on out-of-bounds accesses, while
17
+ /// `x.get()` and `x.last()` will return `None`.
18
+ ///
19
+ /// There is another lint (get_unwrap) that covers the case of using
20
+ /// `x.get(index).unwrap()` instead of `x[index]`.
17
21
///
18
22
/// **Known problems:** None.
19
23
///
@@ -79,11 +83,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseLast {
79
83
80
84
// LHS of subtraction is "x.len()"
81
85
if let ExprKind :: MethodCall ( ref arg_lhs_path, _, ref lhs_args) = lhs. node;
82
- // let _ = println!("LHS of sub is a method call");
86
+ // let _ = println!("LHS of sub is a method call");
83
87
if arg_lhs_path. ident. name == "len" ;
84
88
// let _ = println!("LHS of sub was method named len");
85
- // if let Some(arg_lhs_struct ) = lhs_args.get(0);
89
+ if let Some ( _arg_lhs_struct ) = lhs_args. get( 0 ) ;
86
90
// let _ = println!("LHS of sub method has an arg");
91
+
87
92
// TODO: Is this a valid way to check if they reference the same vector?
88
93
// if arg_lhs_struct.hir_id == struct_calling_on.hir_id;
89
94
// let _ = println!("The vector in .get and .len were the same");
@@ -96,24 +101,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseLast {
96
101
if rhs_value == 1 ;
97
102
// let _ = println!("RHS of sub was 1");
98
103
99
- // TODO: Figure out how to get name of variable for lint message
100
- // Can't do this (cannot move out of borrowed content (context?))
101
- // if let ExprKind::Struct(ref struct_calling_on_path, _, _) = struct_calling_on.node;
102
- // let _ = println!("It was a struct");
103
- // let vec_name = match struct_calling_on_path.into_inner() {
104
- // rustc::hir::QPath::Resolved(_, path) =>
105
- // path.segments.last().map(|path_seg| path_seg.ident.name.as_str().get()).unwrap_or("x"),
106
- // rustc::hir::QPath::TypeRelative(_, path_seg) => path_seg.ident.name.as_str().get(),
107
- // };
108
- let vec_name = "x" ;
104
+ let mut applicability = Applicability :: MachineApplicable ;
105
+ let vec_name = snippet_with_applicability(
106
+ cx, struct_calling_on. span, "x" , & mut applicability) ;
109
107
// let _ = println!("About to span_lint on \"{}\"", vec_name);
110
108
111
109
then {
112
- span_lint( cx,
113
- USE_LAST ,
114
- expr. span,
115
- & format!( "Use `{}.last()` instead of `{}.get({}.len() - 1)`" ,
116
- vec_name, vec_name, vec_name) ) ;
110
+ span_lint_and_sugg(
111
+ cx,
112
+ USE_LAST ,
113
+ expr. span,
114
+ & format!( "Use `{}.last()` instead of `{}.get({}.len() - 1)`" ,
115
+ vec_name, vec_name, vec_name) ,
116
+ "try" ,
117
+ format!( "{}.last()" , vec_name) ,
118
+ applicability,
119
+ ) ;
117
120
}
118
121
}
119
122
}
0 commit comments