implemented `let_underscore` lint
actually add files update lints change to pedantic
This commit is contained in:
parent
8b4a3b74e9
commit
a310cb2d0b
|
@ -1064,6 +1064,7 @@ Released 2018-09-13
|
||||||
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
|
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
|
||||||
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
|
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
|
||||||
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
|
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
|
||||||
|
[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
|
||||||
[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
|
[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
|
||||||
[`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist
|
[`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist
|
||||||
[`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
|
[`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
|
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
|
||||||
|
|
||||||
[There are 339 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
|
[There are 340 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
|
||||||
|
|
||||||
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
|
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
attrs::is_proc_macro, iter_input_pats, match_def_path, qpath_res, return_ty, snippet, snippet_opt,
|
attrs::is_proc_macro, is_must_use_ty, iter_input_pats, match_def_path, must_use_attr, qpath_res, return_ty,
|
||||||
span_help_and_lint, span_lint, span_lint_and_then, trait_ref_of_method, type_is_unsafe_function,
|
snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_then, trait_ref_of_method,
|
||||||
must_use_attr, is_must_use_ty,
|
type_is_unsafe_function,
|
||||||
};
|
};
|
||||||
use matches::matches;
|
use matches::matches;
|
||||||
use rustc::hir::{self, def::Res, def_id::DefId, intravisit};
|
use rustc::hir::{self, def::Res, def_id::DefId, intravisit};
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
use if_chain::if_chain;
|
||||||
|
use rustc::declare_lint_pass;
|
||||||
|
use rustc::hir::*;
|
||||||
|
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||||
|
use rustc_session::declare_tool_lint;
|
||||||
|
|
||||||
|
use crate::utils::{is_must_use_func_call, is_must_use_ty, span_help_and_lint};
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// **What it does:** Checks for `let _ = <expr>`
|
||||||
|
/// where expr is #[must_use]
|
||||||
|
///
|
||||||
|
/// **Why is this bad?** It's better to explicitly
|
||||||
|
/// handle the value of a #[must_use] expr
|
||||||
|
///
|
||||||
|
/// **Known problems:** None.
|
||||||
|
///
|
||||||
|
/// **Example:**
|
||||||
|
/// ```rust
|
||||||
|
/// fn f() -> Result<u32, u32> {
|
||||||
|
/// Ok(0)
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let _ = f();
|
||||||
|
/// // is_ok() is marked #[must_use]
|
||||||
|
/// let _ = f().is_ok();
|
||||||
|
/// ```
|
||||||
|
pub LET_UNDERSCORE_MUST_USE,
|
||||||
|
restriction,
|
||||||
|
"non-binding let on a #[must_use] expression"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE]);
|
||||||
|
|
||||||
|
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore {
|
||||||
|
fn check_stmt(&mut self, cx: &LateContext<'_, '_>, stmt: &Stmt) {
|
||||||
|
if_chain! {
|
||||||
|
if let StmtKind::Local(ref local) = stmt.kind;
|
||||||
|
if let PatKind::Wild = local.pat.kind;
|
||||||
|
if let Some(ref init) = local.init;
|
||||||
|
then {
|
||||||
|
if is_must_use_ty(cx, cx.tables.expr_ty(init)) {
|
||||||
|
span_help_and_lint(
|
||||||
|
cx,
|
||||||
|
LET_UNDERSCORE_MUST_USE,
|
||||||
|
stmt.span,
|
||||||
|
"non-binding let on an expression with #[must_use] type",
|
||||||
|
"consider explicitly using expression value"
|
||||||
|
)
|
||||||
|
} else if is_must_use_func_call(cx, init) {
|
||||||
|
span_help_and_lint(
|
||||||
|
cx,
|
||||||
|
LET_UNDERSCORE_MUST_USE,
|
||||||
|
stmt.span,
|
||||||
|
"non-binding let on a result of a #[must_use] function",
|
||||||
|
"consider explicitly using function result"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -220,6 +220,7 @@ pub mod large_enum_variant;
|
||||||
pub mod large_stack_arrays;
|
pub mod large_stack_arrays;
|
||||||
pub mod len_zero;
|
pub mod len_zero;
|
||||||
pub mod let_if_seq;
|
pub mod let_if_seq;
|
||||||
|
pub mod let_underscore;
|
||||||
pub mod lifetimes;
|
pub mod lifetimes;
|
||||||
pub mod literal_representation;
|
pub mod literal_representation;
|
||||||
pub mod loops;
|
pub mod loops;
|
||||||
|
@ -555,6 +556,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
|
||||||
&len_zero::LEN_WITHOUT_IS_EMPTY,
|
&len_zero::LEN_WITHOUT_IS_EMPTY,
|
||||||
&len_zero::LEN_ZERO,
|
&len_zero::LEN_ZERO,
|
||||||
&let_if_seq::USELESS_LET_IF_SEQ,
|
&let_if_seq::USELESS_LET_IF_SEQ,
|
||||||
|
&let_underscore::LET_UNDERSCORE_MUST_USE,
|
||||||
&lifetimes::EXTRA_UNUSED_LIFETIMES,
|
&lifetimes::EXTRA_UNUSED_LIFETIMES,
|
||||||
&lifetimes::NEEDLESS_LIFETIMES,
|
&lifetimes::NEEDLESS_LIFETIMES,
|
||||||
&literal_representation::DECIMAL_LITERAL_REPRESENTATION,
|
&literal_representation::DECIMAL_LITERAL_REPRESENTATION,
|
||||||
|
@ -970,6 +972,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
|
||||||
store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
|
store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
|
||||||
store.register_early_pass(|| box as_conversions::AsConversions);
|
store.register_early_pass(|| box as_conversions::AsConversions);
|
||||||
store.register_early_pass(|| box utils::internal_lints::ProduceIce);
|
store.register_early_pass(|| box utils::internal_lints::ProduceIce);
|
||||||
|
store.register_late_pass(|| box let_underscore::LetUnderscore);
|
||||||
|
|
||||||
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
|
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
|
||||||
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
|
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
|
||||||
|
@ -982,6 +985,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
|
||||||
LintId::of(&indexing_slicing::INDEXING_SLICING),
|
LintId::of(&indexing_slicing::INDEXING_SLICING),
|
||||||
LintId::of(&inherent_impl::MULTIPLE_INHERENT_IMPL),
|
LintId::of(&inherent_impl::MULTIPLE_INHERENT_IMPL),
|
||||||
LintId::of(&integer_division::INTEGER_DIVISION),
|
LintId::of(&integer_division::INTEGER_DIVISION),
|
||||||
|
LintId::of(&let_underscore::LET_UNDERSCORE_MUST_USE),
|
||||||
LintId::of(&literal_representation::DECIMAL_LITERAL_REPRESENTATION),
|
LintId::of(&literal_representation::DECIMAL_LITERAL_REPRESENTATION),
|
||||||
LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM),
|
LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM),
|
||||||
LintId::of(&mem_forget::MEM_FORGET),
|
LintId::of(&mem_forget::MEM_FORGET),
|
||||||
|
|
|
@ -41,7 +41,7 @@ use rustc::ty::{
|
||||||
};
|
};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use syntax::ast::{self, LitKind, Attribute};
|
use syntax::ast::{self, Attribute, LitKind};
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::source_map::{Span, DUMMY_SP};
|
use syntax::source_map::{Span, DUMMY_SP};
|
||||||
use syntax::symbol::{kw, Symbol};
|
use syntax::symbol::{kw, Symbol};
|
||||||
|
@ -1283,3 +1283,25 @@ pub fn is_must_use_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> boo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if expr is calling method or function with #[must_use] attribyte
|
||||||
|
pub fn is_must_use_func_call(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
|
||||||
|
let did = match expr.kind {
|
||||||
|
ExprKind::Call(ref path, _) => if_chain! {
|
||||||
|
if let ExprKind::Path(ref qpath) = path.kind;
|
||||||
|
if let def::Res::Def(_, did) = cx.tables.qpath_res(qpath, path.hir_id);
|
||||||
|
then {
|
||||||
|
Some(did)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ExprKind::MethodCall(_, _, _) => cx.tables.type_dependent_def_id(expr.hir_id),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(did) = did {
|
||||||
|
must_use_attr(&cx.tcx.get_attrs(did)).is_some()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ pub use lint::Lint;
|
||||||
pub use lint::LINT_LEVELS;
|
pub use lint::LINT_LEVELS;
|
||||||
|
|
||||||
// begin lint list, do not remove this comment, it’s used in `update_lints`
|
// begin lint list, do not remove this comment, it’s used in `update_lints`
|
||||||
pub const ALL_LINTS: [Lint; 339] = [
|
pub const ALL_LINTS: [Lint; 340] = [
|
||||||
Lint {
|
Lint {
|
||||||
name: "absurd_extreme_comparisons",
|
name: "absurd_extreme_comparisons",
|
||||||
group: "correctness",
|
group: "correctness",
|
||||||
|
@ -938,6 +938,13 @@ pub const ALL_LINTS: [Lint; 339] = [
|
||||||
deprecation: None,
|
deprecation: None,
|
||||||
module: "returns",
|
module: "returns",
|
||||||
},
|
},
|
||||||
|
Lint {
|
||||||
|
name: "let_underscore_must_use",
|
||||||
|
group: "restriction",
|
||||||
|
desc: "non-binding let on a #[must_use] expression",
|
||||||
|
deprecation: None,
|
||||||
|
module: "let_underscore",
|
||||||
|
},
|
||||||
Lint {
|
Lint {
|
||||||
name: "let_unit_value",
|
name: "let_unit_value",
|
||||||
group: "style",
|
group: "style",
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
#![warn(clippy::let_underscore_must_use)]
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn f() -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn g() -> Result<u32, u32> {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn l<T>(x: T) -> T {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn h() -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S {}
|
||||||
|
|
||||||
|
impl S {
|
||||||
|
#[must_use]
|
||||||
|
pub fn f(&self) -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn g(&self) -> Result<u32, u32> {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn k(&self) -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn h() -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn p() -> Result<u32, u32> {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
#[must_use]
|
||||||
|
fn a() -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for S {
|
||||||
|
fn a() -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = f();
|
||||||
|
let _ = g();
|
||||||
|
let _ = h();
|
||||||
|
let _ = l(0_u32);
|
||||||
|
|
||||||
|
let s = S {};
|
||||||
|
|
||||||
|
let _ = s.f();
|
||||||
|
let _ = s.g();
|
||||||
|
let _ = s.k();
|
||||||
|
|
||||||
|
let _ = S::h();
|
||||||
|
let _ = S::p();
|
||||||
|
|
||||||
|
let _ = S::a();
|
||||||
|
|
||||||
|
let _ = if true { Ok(()) } else { Err(()) };
|
||||||
|
|
||||||
|
let a = Result::<(), ()>::Ok(());
|
||||||
|
|
||||||
|
let _ = a.is_ok();
|
||||||
|
|
||||||
|
let _ = a.map(|_| ());
|
||||||
|
|
||||||
|
let _ = a;
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
error: non-binding let on a result of a #[must_use] function
|
||||||
|
--> $DIR/let_underscore.rs:59:5
|
||||||
|
|
|
||||||
|
LL | let _ = f();
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `-D clippy::let-underscore-must-use` implied by `-D warnings`
|
||||||
|
= help: consider explicitly using function result
|
||||||
|
|
||||||
|
error: non-binding let on an expression with #[must_use] type
|
||||||
|
--> $DIR/let_underscore.rs:60:5
|
||||||
|
|
|
||||||
|
LL | let _ = g();
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider explicitly using expression value
|
||||||
|
|
||||||
|
error: non-binding let on a result of a #[must_use] function
|
||||||
|
--> $DIR/let_underscore.rs:62:5
|
||||||
|
|
|
||||||
|
LL | let _ = l(0_u32);
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider explicitly using function result
|
||||||
|
|
||||||
|
error: non-binding let on a result of a #[must_use] function
|
||||||
|
--> $DIR/let_underscore.rs:66:5
|
||||||
|
|
|
||||||
|
LL | let _ = s.f();
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider explicitly using function result
|
||||||
|
|
||||||
|
error: non-binding let on an expression with #[must_use] type
|
||||||
|
--> $DIR/let_underscore.rs:67:5
|
||||||
|
|
|
||||||
|
LL | let _ = s.g();
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider explicitly using expression value
|
||||||
|
|
||||||
|
error: non-binding let on a result of a #[must_use] function
|
||||||
|
--> $DIR/let_underscore.rs:70:5
|
||||||
|
|
|
||||||
|
LL | let _ = S::h();
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider explicitly using function result
|
||||||
|
|
||||||
|
error: non-binding let on an expression with #[must_use] type
|
||||||
|
--> $DIR/let_underscore.rs:71:5
|
||||||
|
|
|
||||||
|
LL | let _ = S::p();
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider explicitly using expression value
|
||||||
|
|
||||||
|
error: non-binding let on a result of a #[must_use] function
|
||||||
|
--> $DIR/let_underscore.rs:73:5
|
||||||
|
|
|
||||||
|
LL | let _ = S::a();
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider explicitly using function result
|
||||||
|
|
||||||
|
error: non-binding let on an expression with #[must_use] type
|
||||||
|
--> $DIR/let_underscore.rs:75:5
|
||||||
|
|
|
||||||
|
LL | let _ = if true { Ok(()) } else { Err(()) };
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider explicitly using expression value
|
||||||
|
|
||||||
|
error: non-binding let on a result of a #[must_use] function
|
||||||
|
--> $DIR/let_underscore.rs:79:5
|
||||||
|
|
|
||||||
|
LL | let _ = a.is_ok();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider explicitly using function result
|
||||||
|
|
||||||
|
error: non-binding let on an expression with #[must_use] type
|
||||||
|
--> $DIR/let_underscore.rs:81:5
|
||||||
|
|
|
||||||
|
LL | let _ = a.map(|_| ());
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider explicitly using expression value
|
||||||
|
|
||||||
|
error: non-binding let on an expression with #[must_use] type
|
||||||
|
--> $DIR/let_underscore.rs:83:5
|
||||||
|
|
|
||||||
|
LL | let _ = a;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider explicitly using expression value
|
||||||
|
|
||||||
|
error: aborting due to 12 previous errors
|
||||||
|
|
Loading…
Reference in New Issue