Skip to content

Commit 3557e20

Browse files
committed
Update Clippy
1 parent 5186d18 commit 3557e20

38 files changed

+998
-260
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,7 @@ Released 2018-09-13
10341034
[`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
10351035
[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
10361036
[`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
1037+
[`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
10371038
[`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
10381039
[`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
10391040
[`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
@@ -1176,6 +1177,7 @@ Released 2018-09-13
11761177
[`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
11771178
[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
11781179
[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
1180+
[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
11791181
[`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg
11801182
[`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
11811183
[`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints

README.md

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

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

9-
[There are 311 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
9+
[There are 313 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
1010

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

clippy_lints/src/attrs.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ fn check_clippy_lint_names(cx: &LateContext<'_, '_>, items: &[NestedMetaItem]) {
319319
let name = meta_item.path.segments.last().unwrap().ident.name;
320320
if let CheckLintNameResult::Tool(Err((None, _))) = lint_store.check_lint_name(
321321
&name.as_str(),
322-
Some(tool_name.as_str()),
322+
Some(tool_name.name),
323323
);
324324
then {
325325
span_lint_and_then(
@@ -332,7 +332,7 @@ fn check_clippy_lint_names(cx: &LateContext<'_, '_>, items: &[NestedMetaItem]) {
332332
let name_lower = name.as_str().to_lowercase();
333333
match lint_store.check_lint_name(
334334
&name_lower,
335-
Some(tool_name.as_str())
335+
Some(tool_name.name)
336336
) {
337337
// FIXME: can we suggest similar lint names here?
338338
// https://github.com/rust-lang/rust/pull/56992

clippy_lints/src/copies.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxHashMap;
88
use smallvec::SmallVec;
99
use std::collections::hash_map::Entry;
1010
use std::hash::BuildHasherDefault;
11-
use syntax::symbol::LocalInternedString;
11+
use syntax::symbol::Symbol;
1212

1313
declare_clippy_lint! {
1414
/// **What it does:** Checks for consecutive `if`s with the same condition.
@@ -168,8 +168,8 @@ fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) {
168168
fn lint_match_arms<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &Expr) {
169169
fn same_bindings<'tcx>(
170170
cx: &LateContext<'_, 'tcx>,
171-
lhs: &FxHashMap<LocalInternedString, Ty<'tcx>>,
172-
rhs: &FxHashMap<LocalInternedString, Ty<'tcx>>,
171+
lhs: &FxHashMap<Symbol, Ty<'tcx>>,
172+
rhs: &FxHashMap<Symbol, Ty<'tcx>>,
173173
) -> bool {
174174
lhs.len() == rhs.len()
175175
&& lhs
@@ -275,12 +275,8 @@ fn if_sequence(mut expr: &Expr) -> (SmallVec<[&Expr; 1]>, SmallVec<[&Block; 1]>)
275275
}
276276

277277
/// Returns the list of bindings in a pattern.
278-
fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<LocalInternedString, Ty<'tcx>> {
279-
fn bindings_impl<'a, 'tcx>(
280-
cx: &LateContext<'a, 'tcx>,
281-
pat: &Pat,
282-
map: &mut FxHashMap<LocalInternedString, Ty<'tcx>>,
283-
) {
278+
fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<Symbol, Ty<'tcx>> {
279+
fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut FxHashMap<Symbol, Ty<'tcx>>) {
284280
match pat.node {
285281
PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map),
286282
PatKind::TupleStruct(_, ref pats, _) => {
@@ -289,7 +285,7 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<LocalI
289285
}
290286
},
291287
PatKind::Binding(.., ident, ref as_pat) => {
292-
if let Entry::Vacant(v) = map.entry(ident.as_str()) {
288+
if let Entry::Vacant(v) = map.entry(ident.name) {
293289
v.insert(cx.tables.pat_ty(pat));
294290
}
295291
if let Some(ref as_pat) = *as_pat {

clippy_lints/src/entry.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::utils::SpanlessEq;
2-
use crate::utils::{get_item_name, higher, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty};
2+
use crate::utils::{get_item_name, higher, match_type, paths, snippet, snippet_opt, span_lint_and_then, walk_ptrs_ty};
33
use if_chain::if_chain;
44
use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
55
use rustc::hir::*;
@@ -140,6 +140,7 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for InsertVisitor<'a, 'tcx, 'b> {
140140
if path.ident.name == sym!(insert);
141141
if get_item_name(self.cx, self.map) == get_item_name(self.cx, &params[0]);
142142
if SpanlessEq::new(self.cx).eq_expr(self.key, &params[1]);
143+
if snippet_opt(self.cx, self.map.span) == snippet_opt(self.cx, params[0].span);
143144
then {
144145
span_lint_and_then(self.cx, MAP_ENTRY, self.span,
145146
&format!("usage of `contains_key` followed by `insert` on a `{}`", self.ty), |db| {

clippy_lints/src/enum_variants.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc::lint::{EarlyContext, EarlyLintPass, Lint, LintArray, LintPass};
66
use rustc::{declare_tool_lint, impl_lint_pass};
77
use syntax::ast::*;
88
use syntax::source_map::Span;
9-
use syntax::symbol::{InternedString, LocalInternedString};
9+
use syntax::symbol::Symbol;
1010

1111
declare_clippy_lint! {
1212
/// **What it does:** Detects enumeration variants that are prefixed or suffixed
@@ -102,7 +102,7 @@ declare_clippy_lint! {
102102
}
103103

104104
pub struct EnumVariantNames {
105-
modules: Vec<(InternedString, String)>,
105+
modules: Vec<(Symbol, String)>,
106106
threshold: u64,
107107
}
108108

@@ -122,10 +122,6 @@ impl_lint_pass!(EnumVariantNames => [
122122
MODULE_INCEPTION
123123
]);
124124

125-
fn var2str(var: &Variant) -> LocalInternedString {
126-
var.ident.as_str()
127-
}
128-
129125
/// Returns the number of chars that match from the start
130126
fn partial_match(pre: &str, name: &str) -> usize {
131127
let mut name_iter = name.chars();
@@ -157,7 +153,7 @@ fn check_variant(
157153
return;
158154
}
159155
for var in &def.variants {
160-
let name = var2str(var);
156+
let name = var.ident.name.as_str();
161157
if partial_match(item_name, &name) == item_name_chars
162158
&& name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
163159
&& name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
@@ -168,11 +164,11 @@ fn check_variant(
168164
span_lint(cx, lint, var.span, "Variant name ends with the enum's name");
169165
}
170166
}
171-
let first = var2str(&def.variants[0]);
167+
let first = &def.variants[0].ident.name.as_str();
172168
let mut pre = &first[..camel_case::until(&*first)];
173169
let mut post = &first[camel_case::from(&*first)..];
174170
for var in &def.variants {
175-
let name = var2str(var);
171+
let name = var.ident.name.as_str();
176172

177173
let pre_match = partial_match(pre, &name);
178174
pre = &pre[..pre_match];
@@ -245,14 +241,14 @@ impl EarlyLintPass for EnumVariantNames {
245241

246242
#[allow(clippy::similar_names)]
247243
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
248-
let item_name = item.ident.as_str();
244+
let item_name = item.ident.name.as_str();
249245
let item_name_chars = item_name.chars().count();
250246
let item_camel = to_camel_case(&item_name);
251247
if !item.span.from_expansion() && is_present_in_source(cx, item.span) {
252248
if let Some(&(ref mod_name, ref mod_camel)) = self.modules.last() {
253249
// constants don't have surrounding modules
254250
if !mod_camel.is_empty() {
255-
if mod_name.as_symbol() == item.ident.name {
251+
if mod_name == &item.ident.name {
256252
if let ItemKind::Mod(..) = item.node {
257253
span_lint(
258254
cx,
@@ -299,6 +295,6 @@ impl EarlyLintPass for EnumVariantNames {
299295
};
300296
check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span, lint);
301297
}
302-
self.modules.push((item_name.as_interned_str(), item_camel));
298+
self.modules.push((item.ident.name, item_camel));
303299
}
304300
}

clippy_lints/src/functions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ impl<'a, 'tcx> Functions {
200200
Some(i) => i + 1,
201201
None => 0,
202202
};
203-
let end_brace_idx = match code_snippet.find('}') {
203+
let end_brace_idx = match code_snippet.rfind('}') {
204204
Some(i) => i,
205205
None => code_snippet.len(),
206206
};

clippy_lints/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
793793
methods::ITER_CLONED_COLLECT,
794794
methods::ITER_NTH,
795795
methods::ITER_SKIP_NEXT,
796+
methods::MANUAL_SATURATING_ARITHMETIC,
796797
methods::NEW_RET_NO_SELF,
797798
methods::OK_EXPECT,
798799
methods::OPTION_AND_THEN_SOME,
@@ -804,6 +805,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
804805
methods::STRING_EXTEND_CHARS,
805806
methods::SUSPICIOUS_MAP,
806807
methods::TEMPORARY_CSTRING_AS_PTR,
808+
methods::UNINIT_ASSUMED_INIT,
807809
methods::UNNECESSARY_FILTER_MAP,
808810
methods::UNNECESSARY_FOLD,
809811
methods::USELESS_ASREF,
@@ -957,6 +959,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
957959
methods::INTO_ITER_ON_REF,
958960
methods::ITER_CLONED_COLLECT,
959961
methods::ITER_SKIP_NEXT,
962+
methods::MANUAL_SATURATING_ARITHMETIC,
960963
methods::NEW_RET_NO_SELF,
961964
methods::OK_EXPECT,
962965
methods::OPTION_MAP_OR_NONE,
@@ -1116,6 +1119,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
11161119
methods::CLONE_DOUBLE_REF,
11171120
methods::INTO_ITER_ON_ARRAY,
11181121
methods::TEMPORARY_CSTRING_AS_PTR,
1122+
methods::UNINIT_ASSUMED_INIT,
11191123
minmax::MIN_MAX,
11201124
misc::CMP_NAN,
11211125
misc::FLOAT_CMP,
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
use crate::utils::{match_qpath, snippet_with_applicability, span_lint_and_sugg};
2+
use if_chain::if_chain;
3+
use rustc::hir;
4+
use rustc::lint::LateContext;
5+
use rustc_errors::Applicability;
6+
use rustc_target::abi::LayoutOf;
7+
use syntax::ast;
8+
9+
pub fn lint(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[&[hir::Expr]], arith: &str) {
10+
let unwrap_arg = &args[0][1];
11+
let arith_lhs = &args[1][0];
12+
let arith_rhs = &args[1][1];
13+
14+
let ty = cx.tables.expr_ty(arith_lhs);
15+
if !ty.is_integral() {
16+
return;
17+
}
18+
19+
let mm = if let Some(mm) = is_min_or_max(cx, unwrap_arg) {
20+
mm
21+
} else {
22+
return;
23+
};
24+
25+
if ty.is_signed() {
26+
use self::{MinMax::*, Sign::*};
27+
28+
let sign = if let Some(sign) = lit_sign(arith_rhs) {
29+
sign
30+
} else {
31+
return;
32+
};
33+
34+
match (arith, sign, mm) {
35+
("add", Pos, Max) | ("add", Neg, Min) | ("sub", Neg, Max) | ("sub", Pos, Min) => (),
36+
// "mul" is omitted because lhs can be negative.
37+
_ => return,
38+
}
39+
40+
let mut applicability = Applicability::MachineApplicable;
41+
span_lint_and_sugg(
42+
cx,
43+
super::MANUAL_SATURATING_ARITHMETIC,
44+
expr.span,
45+
"manual saturating arithmetic",
46+
&format!("try using `saturating_{}`", arith),
47+
format!(
48+
"{}.saturating_{}({})",
49+
snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability),
50+
arith,
51+
snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability),
52+
),
53+
applicability,
54+
);
55+
} else {
56+
match (mm, arith) {
57+
(MinMax::Max, "add") | (MinMax::Max, "mul") | (MinMax::Min, "sub") => (),
58+
_ => return,
59+
}
60+
61+
let mut applicability = Applicability::MachineApplicable;
62+
span_lint_and_sugg(
63+
cx,
64+
super::MANUAL_SATURATING_ARITHMETIC,
65+
expr.span,
66+
"manual saturating arithmetic",
67+
&format!("try using `saturating_{}`", arith),
68+
format!(
69+
"{}.saturating_{}({})",
70+
snippet_with_applicability(cx, arith_lhs.span, "..", &mut applicability),
71+
arith,
72+
snippet_with_applicability(cx, arith_rhs.span, "..", &mut applicability),
73+
),
74+
applicability,
75+
);
76+
}
77+
}
78+
79+
#[derive(PartialEq, Eq)]
80+
enum MinMax {
81+
Min,
82+
Max,
83+
}
84+
85+
fn is_min_or_max<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &hir::Expr) -> Option<MinMax> {
86+
// `T::max_value()` `T::min_value()` inherent methods
87+
if_chain! {
88+
if let hir::ExprKind::Call(func, args) = &expr.node;
89+
if args.is_empty();
90+
if let hir::ExprKind::Path(path) = &func.node;
91+
if let hir::QPath::TypeRelative(_, segment) = path;
92+
then {
93+
match &*segment.ident.as_str() {
94+
"max_value" => return Some(MinMax::Max),
95+
"min_value" => return Some(MinMax::Min),
96+
_ => {}
97+
}
98+
}
99+
}
100+
101+
let ty = cx.tables.expr_ty(expr);
102+
let ty_str = ty.to_string();
103+
104+
// `std::T::MAX` `std::T::MIN` constants
105+
if let hir::ExprKind::Path(path) = &expr.node {
106+
if match_qpath(path, &["core", &ty_str, "MAX"][..]) {
107+
return Some(MinMax::Max);
108+
}
109+
110+
if match_qpath(path, &["core", &ty_str, "MIN"][..]) {
111+
return Some(MinMax::Min);
112+
}
113+
}
114+
115+
// Literals
116+
let bits = cx.layout_of(ty).unwrap().size.bits();
117+
let (minval, maxval): (u128, u128) = if ty.is_signed() {
118+
let minval = 1 << (bits - 1);
119+
let mut maxval = !(1 << (bits - 1));
120+
if bits != 128 {
121+
maxval &= (1 << bits) - 1;
122+
}
123+
(minval, maxval)
124+
} else {
125+
(0, if bits == 128 { !0 } else { (1 << bits) - 1 })
126+
};
127+
128+
let check_lit = |expr: &hir::Expr, check_min: bool| {
129+
if let hir::ExprKind::Lit(lit) = &expr.node {
130+
if let ast::LitKind::Int(value, _) = lit.node {
131+
if value == maxval {
132+
return Some(MinMax::Max);
133+
}
134+
135+
if check_min && value == minval {
136+
return Some(MinMax::Min);
137+
}
138+
}
139+
}
140+
141+
None
142+
};
143+
144+
if let r @ Some(_) = check_lit(expr, !ty.is_signed()) {
145+
return r;
146+
}
147+
148+
if ty.is_signed() {
149+
if let hir::ExprKind::Unary(hir::UnNeg, val) = &expr.node {
150+
return check_lit(val, true);
151+
}
152+
}
153+
154+
None
155+
}
156+
157+
#[derive(PartialEq, Eq)]
158+
enum Sign {
159+
Pos,
160+
Neg,
161+
}
162+
163+
fn lit_sign(expr: &hir::Expr) -> Option<Sign> {
164+
if let hir::ExprKind::Unary(hir::UnNeg, inner) = &expr.node {
165+
if let hir::ExprKind::Lit(..) = &inner.node {
166+
return Some(Sign::Neg);
167+
}
168+
} else if let hir::ExprKind::Lit(..) = &expr.node {
169+
return Some(Sign::Pos);
170+
}
171+
172+
None
173+
}

0 commit comments

Comments
 (0)