Skip to content

Commit e0b22d4

Browse files
committed
Update Clippy
1 parent d6410ba commit e0b22d4

25 files changed

+649
-428
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,7 @@ Released 2018-09-13
10931093
[`extend_from_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_from_slice
10941094
[`extra_unused_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes
10951095
[`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from
1096+
[`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file
10961097
[`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map
10971098
[`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next
10981099
[`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next

COPYRIGHT

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright 2014-2019 The Rust Project Developers
1+
Copyright 2014-2020 The Rust Project Developers
22

33
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
44
http://www.apache.org/licenses/LICENSE-2.0> or the MIT license

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 346 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
9+
[There are 347 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/doc.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::utils::{match_type, paths, return_ty, span_lint};
1+
use crate::utils::{is_entrypoint_fn, match_type, paths, return_ty, span_lint};
22
use itertools::Itertools;
33
use rustc::lint::in_external_macro;
44
use rustc_data_structures::fx::FxHashSet;
@@ -153,7 +153,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DocMarkdown {
153153
let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
154154
match item.kind {
155155
hir::ItemKind::Fn(ref sig, ..) => {
156-
if !in_external_macro(cx.tcx.sess, item.span) {
156+
if !(is_entrypoint_fn(cx, cx.tcx.hir().local_def_id(item.hir_id))
157+
|| in_external_macro(cx.tcx.sess, item.span))
158+
{
157159
lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers);
158160
}
159161
},

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
614614
&methods::CLONE_ON_COPY,
615615
&methods::CLONE_ON_REF_PTR,
616616
&methods::EXPECT_FUN_CALL,
617+
&methods::FILETYPE_IS_FILE,
617618
&methods::FILTER_MAP,
618619
&methods::FILTER_MAP_NEXT,
619620
&methods::FILTER_NEXT,
@@ -1007,6 +1008,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10071008
LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM),
10081009
LintId::of(&mem_forget::MEM_FORGET),
10091010
LintId::of(&methods::CLONE_ON_REF_PTR),
1011+
LintId::of(&methods::FILETYPE_IS_FILE),
10101012
LintId::of(&methods::GET_UNWRAP),
10111013
LintId::of(&methods::OPTION_EXPECT_USED),
10121014
LintId::of(&methods::OPTION_UNWRAP_USED),

clippy_lints/src/loops.rs

Lines changed: 15 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,35 @@
1+
use crate::consts::{constant, Constant};
12
use crate::reexport::*;
3+
use crate::utils::paths;
4+
use crate::utils::usage::{is_unused, mutated_variables};
5+
use crate::utils::{
6+
get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
7+
is_integer_const, is_refutable, last_path_segment, match_trait_method, match_type, match_var, multispan_sugg,
8+
snippet, snippet_opt, snippet_with_applicability, span_help_and_lint, span_lint, span_lint_and_sugg,
9+
span_lint_and_then, SpanlessEq,
10+
};
11+
use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sext, sugg};
212
use if_chain::if_chain;
313
use itertools::Itertools;
14+
use rustc::hir::map::Map;
415
use rustc::lint::in_external_macro;
516
use rustc::middle::region;
17+
use rustc::ty::{self, Ty};
18+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
19+
use rustc_errors::Applicability;
620
use rustc_hir::def::{DefKind, Res};
721
use rustc_hir::def_id;
822
use rustc_hir::intravisit::{walk_block, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor};
923
use rustc_hir::*;
1024
use rustc_lint::{LateContext, LateLintPass, LintContext};
1125
use rustc_session::{declare_lint_pass, declare_tool_lint};
12-
// use rustc::middle::region::CodeExtent;
13-
use crate::consts::{constant, Constant};
14-
use crate::utils::usage::mutated_variables;
15-
use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sext, sugg};
16-
use rustc::hir::map::Map;
17-
use rustc::ty::{self, Ty};
18-
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
19-
use rustc_errors::Applicability;
2026
use rustc_span::source_map::Span;
2127
use rustc_span::{BytePos, Symbol};
2228
use rustc_typeck::expr_use_visitor::*;
2329
use std::iter::{once, Iterator};
2430
use std::mem;
2531
use syntax::ast;
2632

27-
use crate::utils::paths;
28-
use crate::utils::{
29-
get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
30-
is_integer_const, is_refutable, last_path_segment, match_trait_method, match_type, match_var, multispan_sugg,
31-
snippet, snippet_opt, snippet_with_applicability, span_help_and_lint, span_lint, span_lint_and_sugg,
32-
span_lint_and_then, SpanlessEq,
33-
};
34-
3533
declare_clippy_lint! {
3634
/// **What it does:** Checks for for-loops that manually copy items between
3735
/// slices that could be optimized by having a memcpy.
@@ -1689,39 +1687,11 @@ fn check_for_mutation(
16891687
fn pat_is_wild<'tcx>(pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool {
16901688
match *pat {
16911689
PatKind::Wild => true,
1692-
PatKind::Binding(.., ident, None) if ident.as_str().starts_with('_') => {
1693-
let mut visitor = UsedVisitor {
1694-
var: ident.name,
1695-
used: false,
1696-
};
1697-
walk_expr(&mut visitor, body);
1698-
!visitor.used
1699-
},
1690+
PatKind::Binding(.., ident, None) if ident.as_str().starts_with('_') => is_unused(&ident, body),
17001691
_ => false,
17011692
}
17021693
}
17031694

1704-
struct UsedVisitor {
1705-
var: ast::Name, // var to look for
1706-
used: bool, // has the var been used otherwise?
1707-
}
1708-
1709-
impl<'tcx> Visitor<'tcx> for UsedVisitor {
1710-
type Map = Map<'tcx>;
1711-
1712-
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
1713-
if match_var(expr, self.var) {
1714-
self.used = true;
1715-
} else {
1716-
walk_expr(self, expr);
1717-
}
1718-
}
1719-
1720-
fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
1721-
NestedVisitorMap::None
1722-
}
1723-
}
1724-
17251695
struct LocalUsedVisitor<'a, 'tcx> {
17261696
cx: &'a LateContext<'a, 'tcx>,
17271697
local: HirId,

clippy_lints/src/matches.rs

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use crate::consts::{constant, miri_to_const, Constant};
22
use crate::utils::paths;
33
use crate::utils::sugg::Sugg;
4+
use crate::utils::usage::is_unused;
45
use crate::utils::{
5-
expr_block, is_allowed, is_expn_of, match_qpath, match_type, multispan_sugg, remove_blocks, snippet,
6+
expr_block, is_allowed, is_expn_of, is_wild, match_qpath, match_type, multispan_sugg, remove_blocks, snippet,
67
snippet_with_applicability, span_help_and_lint, span_lint_and_sugg, span_lint_and_then, span_note_and_lint,
78
walk_ptrs_ty,
89
};
@@ -461,33 +462,40 @@ fn check_overlapping_arms<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ex: &'tcx Expr<'
461462
}
462463
}
463464

464-
fn is_wild<'tcx>(pat: &impl std::ops::Deref<Target = Pat<'tcx>>) -> bool {
465-
match pat.kind {
466-
PatKind::Wild => true,
467-
_ => false,
468-
}
469-
}
470-
471465
fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
472466
let ex_ty = walk_ptrs_ty(cx.tables.expr_ty(ex));
473467
if match_type(cx, ex_ty, &paths::RESULT) {
474468
for arm in arms {
475469
if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind {
476470
let path_str = print::to_string(print::NO_ANN, |s| s.print_qpath(path, false));
477-
if_chain! {
478-
if path_str == "Err";
479-
if inner.iter().any(is_wild);
480-
if let ExprKind::Block(ref block, _) = arm.body.kind;
481-
if is_panic_block(block);
482-
then {
483-
// `Err(_)` arm with `panic!` found
484-
span_note_and_lint(cx,
485-
MATCH_WILD_ERR_ARM,
486-
arm.pat.span,
487-
"`Err(_)` will match all errors, maybe not a good idea",
488-
arm.pat.span,
489-
"to remove this warning, match each error separately \
490-
or use `unreachable!` macro");
471+
if path_str == "Err" {
472+
let mut matching_wild = inner.iter().any(is_wild);
473+
let mut ident_bind_name = String::from("_");
474+
if !matching_wild {
475+
// Looking for unused bindings (i.e.: `_e`)
476+
inner.iter().for_each(|pat| {
477+
if let PatKind::Binding(.., ident, None) = &pat.kind {
478+
if ident.as_str().starts_with('_') && is_unused(ident, arm.body) {
479+
ident_bind_name = (&ident.name.as_str()).to_string();
480+
matching_wild = true;
481+
}
482+
}
483+
});
484+
}
485+
if_chain! {
486+
if matching_wild;
487+
if let ExprKind::Block(ref block, _) = arm.body.kind;
488+
if is_panic_block(block);
489+
then {
490+
// `Err(_)` or `Err(_e)` arm with `panic!` found
491+
span_note_and_lint(cx,
492+
MATCH_WILD_ERR_ARM,
493+
arm.pat.span,
494+
&format!("`Err({})` matches all errors", &ident_bind_name),
495+
arm.pat.span,
496+
"match each error separately or use the error output",
497+
);
498+
}
491499
}
492500
}
493501
}

clippy_lints/src/methods/mod.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,40 @@ declare_clippy_lint! {
11311131
"Check for offset calculations on raw pointers to zero-sized types"
11321132
}
11331133

1134+
declare_clippy_lint! {
1135+
/// **What it does:** Checks for `FileType::is_file()`.
1136+
///
1137+
/// **Why is this bad?** When people testing a file type with `FileType::is_file`
1138+
/// they are testing whether a path is something they can get bytes from. But
1139+
/// `is_file` doesn't cover special file types in unix-like systems, and doesn't cover
1140+
/// symlink in windows. Using `!FileType::is_dir()` is a better way to that intention.
1141+
///
1142+
/// **Example:**
1143+
///
1144+
/// ```rust,ignore
1145+
/// let metadata = std::fs::metadata("foo.txt")?;
1146+
/// let filetype = metadata.file_type();
1147+
///
1148+
/// if filetype.is_file() {
1149+
/// // read file
1150+
/// }
1151+
/// ```
1152+
///
1153+
/// should be written as:
1154+
///
1155+
/// ```rust,ignore
1156+
/// let metadata = std::fs::metadata("foo.txt")?;
1157+
/// let filetype = metadata.file_type();
1158+
///
1159+
/// if !filetype.is_dir() {
1160+
/// // read file
1161+
/// }
1162+
/// ```
1163+
pub FILETYPE_IS_FILE,
1164+
restriction,
1165+
"`FileType::is_file` is not recommended to test for readable file type"
1166+
}
1167+
11341168
declare_lint_pass!(Methods => [
11351169
OPTION_UNWRAP_USED,
11361170
RESULT_UNWRAP_USED,
@@ -1178,6 +1212,7 @@ declare_lint_pass!(Methods => [
11781212
UNINIT_ASSUMED_INIT,
11791213
MANUAL_SATURATING_ARITHMETIC,
11801214
ZST_OFFSET,
1215+
FILETYPE_IS_FILE,
11811216
]);
11821217

11831218
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
@@ -1241,6 +1276,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
12411276
["add"] | ["offset"] | ["sub"] | ["wrapping_offset"] | ["wrapping_add"] | ["wrapping_sub"] => {
12421277
check_pointer_offset(cx, expr, arg_lists[0])
12431278
},
1279+
["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]),
12441280
_ => {},
12451281
}
12461282

@@ -3225,3 +3261,35 @@ fn check_pointer_offset(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[
32253261
}
32263262
}
32273263
}
3264+
3265+
fn lint_filetype_is_file(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
3266+
let ty = cx.tables.expr_ty(&args[0]);
3267+
3268+
if !match_type(cx, ty, &paths::FILE_TYPE) {
3269+
return;
3270+
}
3271+
3272+
let span: Span;
3273+
let verb: &str;
3274+
let lint_unary: &str;
3275+
let help_unary: &str;
3276+
if_chain! {
3277+
if let Some(parent) = get_parent_expr(cx, expr);
3278+
if let hir::ExprKind::Unary(op, _) = parent.kind;
3279+
if op == hir::UnOp::UnNot;
3280+
then {
3281+
lint_unary = "!";
3282+
verb = "denies";
3283+
help_unary = "";
3284+
span = parent.span;
3285+
} else {
3286+
lint_unary = "";
3287+
verb = "covers";
3288+
help_unary = "!";
3289+
span = expr.span;
3290+
}
3291+
}
3292+
let lint_msg = format!("`{}FileType::is_file()` only {} regular files", lint_unary, verb);
3293+
let help_msg = format!("use `{}FileType::is_dir()` instead", help_unary);
3294+
span_help_and_lint(cx, FILETYPE_IS_FILE, span, &lint_msg, &help_msg);
3295+
}

clippy_lints/src/utils/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,14 @@ pub fn is_present_in_source<T: LintContext>(cx: &T, span: Span) -> bool {
127127
true
128128
}
129129

130+
/// Checks if given pattern is a wildcard (`_`)
131+
pub fn is_wild<'tcx>(pat: &impl std::ops::Deref<Target = Pat<'tcx>>) -> bool {
132+
match pat.kind {
133+
PatKind::Wild => true,
134+
_ => false,
135+
}
136+
}
137+
130138
/// Checks if type is struct, enum or union type with the given def path.
131139
pub fn match_type(cx: &LateContext<'_, '_>, ty: Ty<'_>, path: &[&str]) -> bool {
132140
match ty.kind {

clippy_lints/src/utils/paths.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub const DROP_TRAIT: [&str; 4] = ["core", "ops", "drop", "Drop"];
2828
pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
2929
pub const EARLY_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "EarlyContext"];
3030
pub const EXIT: [&str; 3] = ["std", "process", "exit"];
31+
pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
3132
pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"];
3233
pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"];
3334
pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];

clippy_lints/src/utils/usage.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1+
use crate::utils::match_var;
2+
use rustc::hir::map::Map;
13
use rustc::ty;
24
use rustc_data_structures::fx::FxHashSet;
35
use rustc_hir::def::Res;
6+
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
47
use rustc_hir::*;
58
use rustc_lint::LateContext;
9+
use rustc_span::symbol::Ident;
610
use rustc_typeck::expr_use_visitor::*;
11+
use syntax::ast;
712

813
/// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
914
pub fn mutated_variables<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &'a LateContext<'a, 'tcx>) -> Option<FxHashSet<HirId>> {
@@ -70,3 +75,33 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
7075
self.update(&cmt)
7176
}
7277
}
78+
79+
pub struct UsedVisitor {
80+
pub var: ast::Name, // var to look for
81+
pub used: bool, // has the var been used otherwise?
82+
}
83+
84+
impl<'tcx> Visitor<'tcx> for UsedVisitor {
85+
type Map = Map<'tcx>;
86+
87+
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
88+
if match_var(expr, self.var) {
89+
self.used = true;
90+
} else {
91+
walk_expr(self, expr);
92+
}
93+
}
94+
95+
fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> {
96+
NestedVisitorMap::None
97+
}
98+
}
99+
100+
pub fn is_unused<'tcx>(ident: &'tcx Ident, body: &'tcx Expr<'_>) -> bool {
101+
let mut visitor = UsedVisitor {
102+
var: ident.name,
103+
used: false,
104+
};
105+
walk_expr(&mut visitor, body);
106+
!visitor.used
107+
}

0 commit comments

Comments
 (0)