Skip to content

Commit 910e092

Browse files
committed
Update clippy submodule
1 parent c224067 commit 910e092

31 files changed

+534
-160
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,7 @@ All notable changes to this project will be documented in this file.
936936
[`for_loop_over_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loop_over_result
937937
[`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
938938
[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
939+
[`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
939940
[`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
940941
[`identity_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion
941942
[`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
99

10-
[There are 303 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
10+
[There are 304 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
1111

1212
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
1313

clippy_lints/src/consts.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::cmp::PartialOrd;
1414
use std::convert::TryInto;
1515
use std::hash::{Hash, Hasher};
1616
use syntax::ast::{FloatTy, LitKind};
17-
use syntax_pos::symbol::{LocalInternedString, Symbol};
17+
use syntax_pos::symbol::Symbol;
1818

1919
/// A `LitKind`-like enum to fold constant `Expr`s into.
2020
#[derive(Debug, Clone)]
@@ -250,14 +250,18 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
250250
if let ExprKind::Path(qpath) = &callee.node;
251251
let res = self.tables.qpath_res(qpath, callee.hir_id);
252252
if let Some(def_id) = res.opt_def_id();
253-
let get_def_path = self.lcx.get_def_path(def_id);
253+
let get_def_path = self.lcx.get_def_path(def_id, );
254254
let def_path = get_def_path
255255
.iter()
256-
.map(LocalInternedString::get)
256+
.copied()
257+
.map(Symbol::as_str)
257258
.collect::<Vec<_>>();
258-
if let &["core", "num", impl_ty, "max_value"] = &def_path[..];
259+
if def_path[0] == "core";
260+
if def_path[1] == "num";
261+
if def_path[3] == "max_value";
262+
if def_path.len() == 4;
259263
then {
260-
let value = match impl_ty {
264+
let value = match &*def_path[2] {
261265
"<impl i8>" => i8::max_value() as u128,
262266
"<impl i16>" => i16::max_value() as u128,
263267
"<impl i32>" => i32::max_value() as u128,
@@ -326,7 +330,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
326330

327331
let res = self.tables.qpath_res(qpath, id);
328332
match res {
329-
Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssociatedConst, def_id) => {
333+
Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
330334
let substs = self.tables.node_substs(id);
331335
let substs = if self.substs.is_empty() {
332336
substs

clippy_lints/src/copies.rs

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) {
152152
let eq: &dyn Fn(&&Expr, &&Expr) -> bool =
153153
&|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) };
154154

155-
if let Some((i, j)) = search_same(conds, hash, eq) {
155+
for (i, j) in search_same(conds, hash, eq) {
156156
span_note_and_lint(
157157
cx,
158158
IFS_SAME_COND,
@@ -185,7 +185,7 @@ fn lint_match_arms(cx: &LateContext<'_, '_>, expr: &Expr) {
185185
};
186186

187187
let indexed_arms: Vec<(usize, &Arm)> = arms.iter().enumerate().collect();
188-
if let Some((&(_, i), &(_, j))) = search_same(&indexed_arms, hash, eq) {
188+
for (&(_, i), &(_, j)) in search_same(&indexed_arms, hash, eq) {
189189
span_lint_and_then(
190190
cx,
191191
MATCH_SAME_ARMS,
@@ -217,7 +217,10 @@ fn lint_match_arms(cx: &LateContext<'_, '_>, expr: &Expr) {
217217
),
218218
);
219219
} else {
220-
db.span_note(i.body.span, &format!("consider refactoring into `{} | {}`", lhs, rhs));
220+
db.span_help(
221+
i.pats[0].span,
222+
&format!("consider refactoring into `{} | {}`", lhs, rhs),
223+
);
221224
}
222225
}
223226
},
@@ -323,21 +326,33 @@ where
323326
None
324327
}
325328

326-
fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Option<(&T, &T)>
329+
fn search_common_cases<'a, T, Eq>(exprs: &'a [T], eq: &Eq) -> Option<(&'a T, &'a T)>
327330
where
328-
Hash: Fn(&T) -> u64,
329331
Eq: Fn(&T, &T) -> bool,
330332
{
331-
// common cases
332333
if exprs.len() < 2 {
333-
return None;
334+
None
334335
} else if exprs.len() == 2 {
335-
return if eq(&exprs[0], &exprs[1]) {
336+
if eq(&exprs[0], &exprs[1]) {
336337
Some((&exprs[0], &exprs[1]))
337338
} else {
338339
None
339-
};
340+
}
341+
} else {
342+
None
340343
}
344+
}
345+
346+
fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
347+
where
348+
Hash: Fn(&T) -> u64,
349+
Eq: Fn(&T, &T) -> bool,
350+
{
351+
if let Some(expr) = search_common_cases(&exprs, &eq) {
352+
return vec![expr];
353+
}
354+
355+
let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
341356

342357
let mut map: FxHashMap<_, Vec<&_>> =
343358
FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
@@ -347,7 +362,7 @@ where
347362
Entry::Occupied(mut o) => {
348363
for o in o.get() {
349364
if eq(o, expr) {
350-
return Some((o, expr));
365+
match_expr_list.push((o, expr));
351366
}
352367
}
353368
o.get_mut().push(expr);
@@ -358,5 +373,5 @@ where
358373
}
359374
}
360375

361-
None
376+
match_expr_list
362377
}

clippy_lints/src/get_last_with_len.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//! lint on using `x.get(x.len() - 1)` instead of `x.last()`
2+
3+
use crate::utils::{match_type, paths, snippet_with_applicability, span_lint_and_sugg, SpanlessEq};
4+
use if_chain::if_chain;
5+
use rustc::hir::{BinOpKind, Expr, ExprKind};
6+
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
7+
use rustc::{declare_lint_pass, declare_tool_lint};
8+
use rustc_errors::Applicability;
9+
use syntax::ast::LitKind;
10+
use syntax::source_map::Spanned;
11+
use syntax::symbol::Symbol;
12+
13+
declare_clippy_lint! {
14+
/// **What it does:** Checks for using `x.get(x.len() - 1)` instead of
15+
/// `x.last()`.
16+
///
17+
/// **Why is this bad?** Using `x.last()` is easier to read and has the same
18+
/// result.
19+
///
20+
/// Note that using `x[x.len() - 1]` is semantically different from
21+
/// `x.last()`. Indexing into the array will panic on out-of-bounds
22+
/// accesses, while `x.get()` and `x.last()` will return `None`.
23+
///
24+
/// There is another lint (get_unwrap) that covers the case of using
25+
/// `x.get(index).unwrap()` instead of `x[index]`.
26+
///
27+
/// **Known problems:** None.
28+
///
29+
/// **Example:**
30+
///
31+
/// ```rust
32+
/// // Bad
33+
/// let x = vec![2, 3, 5];
34+
/// let last_element = x.get(x.len() - 1);
35+
///
36+
/// // Good
37+
/// let x = vec![2, 3, 5];
38+
/// let last_element = x.last();
39+
/// ```
40+
pub GET_LAST_WITH_LEN,
41+
complexity,
42+
"Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler"
43+
}
44+
45+
declare_lint_pass!(GetLastWithLen => [GET_LAST_WITH_LEN]);
46+
47+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for GetLastWithLen {
48+
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
49+
if_chain! {
50+
// Is a method call
51+
if let ExprKind::MethodCall(ref path, _, ref args) = expr.node;
52+
53+
// Method name is "get"
54+
if path.ident.name == Symbol::intern("get");
55+
56+
// Argument 0 (the struct we're calling the method on) is a vector
57+
if let Some(struct_calling_on) = args.get(0);
58+
let struct_ty = cx.tables.expr_ty(struct_calling_on);
59+
if match_type(cx, struct_ty, &paths::VEC);
60+
61+
// Argument to "get" is a subtraction
62+
if let Some(get_index_arg) = args.get(1);
63+
if let ExprKind::Binary(
64+
Spanned {
65+
node: BinOpKind::Sub,
66+
..
67+
},
68+
lhs,
69+
rhs,
70+
) = &get_index_arg.node;
71+
72+
// LHS of subtraction is "x.len()"
73+
if let ExprKind::MethodCall(arg_lhs_path, _, lhs_args) = &lhs.node;
74+
if arg_lhs_path.ident.name == Symbol::intern("len");
75+
if let Some(arg_lhs_struct) = lhs_args.get(0);
76+
77+
// The two vectors referenced (x in x.get(...) and in x.len())
78+
if SpanlessEq::new(cx).eq_expr(struct_calling_on, arg_lhs_struct);
79+
80+
// RHS of subtraction is 1
81+
if let ExprKind::Lit(rhs_lit) = &rhs.node;
82+
if let LitKind::Int(rhs_value, ..) = rhs_lit.node;
83+
if rhs_value == 1;
84+
85+
then {
86+
let mut applicability = Applicability::MachineApplicable;
87+
let vec_name = snippet_with_applicability(
88+
cx,
89+
struct_calling_on.span, "vec",
90+
&mut applicability,
91+
);
92+
93+
span_lint_and_sugg(
94+
cx,
95+
GET_LAST_WITH_LEN,
96+
expr.span,
97+
&format!("accessing last element with `{0}.get({0}.len() - 1)`", vec_name),
98+
"try",
99+
format!("{}.last()", vec_name),
100+
applicability,
101+
);
102+
}
103+
}
104+
}
105+
}

clippy_lints/src/len_zero.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero {
120120
fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items: &[TraitItemRef]) {
121121
fn is_named_self(cx: &LateContext<'_, '_>, item: &TraitItemRef, name: &str) -> bool {
122122
item.ident.name.as_str() == name
123-
&& if let AssociatedItemKind::Method { has_self } = item.kind {
123+
&& if let AssocItemKind::Method { has_self } = item.kind {
124124
has_self && {
125125
let did = cx.tcx.hir().local_def_id_from_hir_id(item.id.hir_id);
126126
cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
@@ -148,7 +148,7 @@ fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items
148148
.iter()
149149
.flat_map(|&i| cx.tcx.associated_items(i))
150150
.any(|i| {
151-
i.kind == ty::AssociatedKind::Method
151+
i.kind == ty::AssocKind::Method
152152
&& i.method_has_self_argument
153153
&& i.ident.name == sym!(is_empty)
154154
&& cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
@@ -171,7 +171,7 @@ fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items
171171
fn check_impl_items(cx: &LateContext<'_, '_>, item: &Item, impl_items: &[ImplItemRef]) {
172172
fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: &str) -> bool {
173173
item.ident.name.as_str() == name
174-
&& if let AssociatedItemKind::Method { has_self } = item.kind {
174+
&& if let AssocItemKind::Method { has_self } = item.kind {
175175
has_self && {
176176
let did = cx.tcx.hir().local_def_id_from_hir_id(item.id.hir_id);
177177
cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
@@ -258,9 +258,9 @@ fn check_len(
258258

259259
/// Checks if this type has an `is_empty` method.
260260
fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
261-
/// Gets an `AssociatedItem` and return true if it matches `is_empty(self)`.
262-
fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssociatedItem) -> bool {
263-
if let ty::AssociatedKind::Method = item.kind {
261+
/// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
262+
fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssocItem) -> bool {
263+
if let ty::AssocKind::Method = item.kind {
264264
if item.ident.name.as_str() == "is_empty" {
265265
let sig = cx.tcx.fn_sig(item.def_id);
266266
let ty = sig.skip_binder();

clippy_lints/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ pub mod fallible_impl_from;
186186
pub mod format;
187187
pub mod formatting;
188188
pub mod functions;
189+
pub mod get_last_with_len;
189190
pub mod identity_conversion;
190191
pub mod identity_op;
191192
pub mod if_not_else;
@@ -492,6 +493,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
492493
reg.register_late_lint_pass(box types::CharLitAsU8);
493494
reg.register_late_lint_pass(box vec::UselessVec);
494495
reg.register_late_lint_pass(box drop_bounds::DropBounds);
496+
reg.register_late_lint_pass(box get_last_with_len::GetLastWithLen);
495497
reg.register_late_lint_pass(box drop_forget_ref::DropForgetRef);
496498
reg.register_late_lint_pass(box empty_enum::EmptyEnum);
497499
reg.register_late_lint_pass(box types::AbsurdExtremeComparisons);
@@ -710,6 +712,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
710712
formatting::SUSPICIOUS_ELSE_FORMATTING,
711713
functions::NOT_UNSAFE_PTR_ARG_DEREF,
712714
functions::TOO_MANY_ARGUMENTS,
715+
get_last_with_len::GET_LAST_WITH_LEN,
713716
identity_conversion::IDENTITY_CONVERSION,
714717
identity_op::IDENTITY_OP,
715718
indexing_slicing::OUT_OF_BOUNDS_INDEXING,
@@ -981,6 +984,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
981984
explicit_write::EXPLICIT_WRITE,
982985
format::USELESS_FORMAT,
983986
functions::TOO_MANY_ARGUMENTS,
987+
get_last_with_len::GET_LAST_WITH_LEN,
984988
identity_conversion::IDENTITY_CONVERSION,
985989
identity_op::IDENTITY_OP,
986990
int_plus_one::INT_PLUS_ONE,

clippy_lints/src/methods/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2157,7 +2157,7 @@ fn lint_binary_expr_with_method_call(cx: &LateContext<'_, '_>, info: &mut Binary
21572157
lint_with_both_lhs_and_rhs!(lint_chars_last_cmp_with_unwrap, cx, info);
21582158
}
21592159

2160-
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_NEXT_CMP` lints.
2160+
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
21612161
fn lint_chars_cmp(
21622162
cx: &LateContext<'_, '_>,
21632163
info: &BinaryExprInfo<'_>,

clippy_lints/src/new_without_default.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
9595
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
9696
if let hir::ItemKind::Impl(_, _, _, _, None, _, ref items) = item.node {
9797
for assoc_item in items {
98-
if let hir::AssociatedItemKind::Method { has_self: false } = assoc_item.kind {
98+
if let hir::AssocItemKind::Method { has_self: false } = assoc_item.kind {
9999
let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
100100
if in_external_macro(cx.sess(), impl_item.span) {
101101
return;

clippy_lints/src/non_copy_const.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCopyConst {
195195

196196
// Make sure it is a const item.
197197
match cx.tables.qpath_res(qpath, expr.hir_id) {
198-
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssociatedConst, _) => {},
198+
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {},
199199
_ => return,
200200
};
201201

clippy_lints/src/returns.rs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use syntax::source_map::Span;
77
use syntax::visit::FnKind;
88
use syntax_pos::BytePos;
99

10-
use crate::utils::{in_macro_or_desugar, match_path_ast, snippet_opt, span_lint_and_then, span_note_and_lint};
10+
use crate::utils::{in_macro_or_desugar, match_path_ast, snippet_opt, span_lint_and_then};
1111

1212
declare_clippy_lint! {
1313
/// **What it does:** Checks for return statements at the end of a block.
@@ -164,13 +164,28 @@ impl Return {
164164
if match_path_ast(path, &[&*ident.name.as_str()]);
165165
if !in_external_macro(cx.sess(), initexpr.span);
166166
then {
167-
span_note_and_lint(cx,
168-
LET_AND_RETURN,
169-
retexpr.span,
170-
"returning the result of a let binding from a block. \
171-
Consider returning the expression directly.",
172-
initexpr.span,
173-
"this expression can be directly returned");
167+
span_lint_and_then(
168+
cx,
169+
LET_AND_RETURN,
170+
retexpr.span,
171+
"returning the result of a let binding from a block",
172+
|err| {
173+
err.span_label(local.span, "unnecessary let binding");
174+
175+
if let Some(snippet) = snippet_opt(cx, initexpr.span) {
176+
err.multipart_suggestion(
177+
"return the expression directly",
178+
vec![
179+
(local.span, String::new()),
180+
(retexpr.span, snippet),
181+
],
182+
Applicability::MachineApplicable,
183+
);
184+
} else {
185+
err.span_help(initexpr.span, "this expression can be directly returned");
186+
}
187+
},
188+
);
174189
}
175190
}
176191
}

0 commit comments

Comments
 (0)