Auto merge of #4560 - rust-lang:must-use-pure, r=phansch
new lints around`#[must_use]` changelog: Add `must_use_candidate` lint, add `must-use-unit` lint, add `double_must_use` lint The first one checks if an public function or method has no mutable argument and mutates no non-local data and lints if it has no `#[must_use]` attribute. It will skip inner functions, because those are usually highly local and the attribute doesn't have as much benefit there. The second lints `#[must_use]` attributes on functions and methods that return unit. Those attributes are likely a remnant from a refactoring that removed the return value. The last one lints for `#[must_use]` attributrs without text on functions that return a type which is already marked `#[must_use]`. This has no auto-suggestion, because while it would be easy to do, there may be value in writing a detailed text for the attribute instead. This fixes #4526
This commit is contained in:
commit
8fae2dd3c1
59 changed files with 948 additions and 112 deletions
|
@ -976,6 +976,7 @@ Released 2018-09-13
|
||||||
[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
|
[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
|
||||||
[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
|
[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
|
||||||
[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
|
[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
|
||||||
|
[`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
|
||||||
[`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
|
[`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
|
||||||
[`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
|
[`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
|
||||||
[`drop_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_bounds
|
[`drop_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_bounds
|
||||||
|
@ -1095,6 +1096,8 @@ Released 2018-09-13
|
||||||
[`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one
|
[`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one
|
||||||
[`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
|
[`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
|
||||||
[`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
|
[`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
|
||||||
|
[`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate
|
||||||
|
[`must_use_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_unit
|
||||||
[`mut_from_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref
|
[`mut_from_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref
|
||||||
[`mut_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_mut
|
[`mut_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_mut
|
||||||
[`mut_range_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_range_bound
|
[`mut_range_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_range_bound
|
||||||
|
|
|
@ -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 321 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
|
[There are 324 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:
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ pub struct Lint {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Lint {
|
impl Lint {
|
||||||
|
#[must_use]
|
||||||
pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Self {
|
pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.to_lowercase(),
|
name: name.to_lowercase(),
|
||||||
|
@ -58,6 +59,7 @@ impl Lint {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the lints in a `HashMap`, grouped by the different lint groups
|
/// Returns the lints in a `HashMap`, grouped by the different lint groups
|
||||||
|
#[must_use]
|
||||||
pub fn by_lint_group(lints: &[Self]) -> HashMap<String, Vec<Self>> {
|
pub fn by_lint_group(lints: &[Self]) -> HashMap<String, Vec<Self>> {
|
||||||
lints
|
lints
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -65,12 +67,14 @@ impl Lint {
|
||||||
.into_group_map()
|
.into_group_map()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_internal(&self) -> bool {
|
pub fn is_internal(&self) -> bool {
|
||||||
self.group.starts_with("internal")
|
self.group.starts_with("internal")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates the Vec items for `register_lint_group` calls in `clippy_lints/src/lib.rs`.
|
/// Generates the Vec items for `register_lint_group` calls in `clippy_lints/src/lib.rs`.
|
||||||
|
#[must_use]
|
||||||
pub fn gen_lint_group_list(lints: Vec<Lint>) -> Vec<String> {
|
pub fn gen_lint_group_list(lints: Vec<Lint>) -> Vec<String> {
|
||||||
lints
|
lints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -86,6 +90,7 @@ pub fn gen_lint_group_list(lints: Vec<Lint>) -> Vec<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates the `pub mod module_name` list in `clippy_lints/src/lib.rs`.
|
/// Generates the `pub mod module_name` list in `clippy_lints/src/lib.rs`.
|
||||||
|
#[must_use]
|
||||||
pub fn gen_modules_list(lints: Vec<Lint>) -> Vec<String> {
|
pub fn gen_modules_list(lints: Vec<Lint>) -> Vec<String> {
|
||||||
lints
|
lints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -103,6 +108,7 @@ pub fn gen_modules_list(lints: Vec<Lint>) -> Vec<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates the list of lint links at the bottom of the README
|
/// Generates the list of lint links at the bottom of the README
|
||||||
|
#[must_use]
|
||||||
pub fn gen_changelog_lint_list(lints: Vec<Lint>) -> Vec<String> {
|
pub fn gen_changelog_lint_list(lints: Vec<Lint>) -> Vec<String> {
|
||||||
let mut lint_list_sorted: Vec<Lint> = lints;
|
let mut lint_list_sorted: Vec<Lint> = lints;
|
||||||
lint_list_sorted.sort_by_key(|l| l.name.clone());
|
lint_list_sorted.sort_by_key(|l| l.name.clone());
|
||||||
|
@ -119,6 +125,7 @@ pub fn gen_changelog_lint_list(lints: Vec<Lint>) -> Vec<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates the `register_removed` code in `./clippy_lints/src/lib.rs`.
|
/// Generates the `register_removed` code in `./clippy_lints/src/lib.rs`.
|
||||||
|
#[must_use]
|
||||||
pub fn gen_deprecated(lints: &[Lint]) -> Vec<String> {
|
pub fn gen_deprecated(lints: &[Lint]) -> Vec<String> {
|
||||||
lints
|
lints
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -42,6 +42,7 @@ fn stderr_files() -> impl Iterator<Item = walkdir::DirEntry> {
|
||||||
.filter(|f| f.path().extension() == Some(OsStr::new("stderr")))
|
.filter(|f| f.path().extension() == Some(OsStr::new("stderr")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn count_linenumbers(filepath: &str) -> usize {
|
fn count_linenumbers(filepath: &str) -> usize {
|
||||||
if let Ok(mut file) = File::open(filepath) {
|
if let Ok(mut file) = File::open(filepath) {
|
||||||
let mut content = String::new();
|
let mut content = String::new();
|
||||||
|
|
|
@ -93,6 +93,7 @@ fn check_known_consts(cx: &LateContext<'_, '_>, e: &Expr, s: symbol::Symbol, mod
|
||||||
/// Returns `false` if the number of significant figures in `value` are
|
/// Returns `false` if the number of significant figures in `value` are
|
||||||
/// less than `min_digits`; otherwise, returns true if `value` is equal
|
/// less than `min_digits`; otherwise, returns true if `value` is equal
|
||||||
/// to `constant`, rounded to the number of digits present in `value`.
|
/// to `constant`, rounded to the number of digits present in `value`.
|
||||||
|
#[must_use]
|
||||||
fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool {
|
fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool {
|
||||||
if value.len() <= min_digits {
|
if value.len() <= min_digits {
|
||||||
false
|
false
|
||||||
|
|
|
@ -229,6 +229,7 @@ fn lint_misrefactored_assign_op(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn is_commutative(op: hir::BinOpKind) -> bool {
|
fn is_commutative(op: hir::BinOpKind) -> bool {
|
||||||
use rustc::hir::BinOpKind::*;
|
use rustc::hir::BinOpKind::*;
|
||||||
match op {
|
match op {
|
||||||
|
|
|
@ -100,6 +100,7 @@ pub struct BitMask {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitMask {
|
impl BitMask {
|
||||||
|
#[must_use]
|
||||||
pub fn new(verbose_bit_mask_threshold: u64) -> Self {
|
pub fn new(verbose_bit_mask_threshold: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
verbose_bit_mask_threshold,
|
verbose_bit_mask_threshold,
|
||||||
|
@ -150,6 +151,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn invert_cmp(cmp: BinOpKind) -> BinOpKind {
|
fn invert_cmp(cmp: BinOpKind) -> BinOpKind {
|
||||||
match cmp {
|
match cmp {
|
||||||
BinOpKind::Eq => BinOpKind::Eq,
|
BinOpKind::Eq => BinOpKind::Eq,
|
||||||
|
|
|
@ -160,6 +160,7 @@ impl<'a> Conversion<'a> {
|
||||||
|
|
||||||
impl ConversionType {
|
impl ConversionType {
|
||||||
/// Creates a conversion type if the type is allowed & conversion is valid
|
/// Creates a conversion type if the type is allowed & conversion is valid
|
||||||
|
#[must_use]
|
||||||
fn try_new(from: &str, to: &str) -> Option<Self> {
|
fn try_new(from: &str, to: &str) -> Option<Self> {
|
||||||
if UINTS.contains(&from) {
|
if UINTS.contains(&from) {
|
||||||
Some(Self::FromUnsigned)
|
Some(Self::FromUnsigned)
|
||||||
|
|
|
@ -29,6 +29,7 @@ pub struct CognitiveComplexity {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CognitiveComplexity {
|
impl CognitiveComplexity {
|
||||||
|
#[must_use]
|
||||||
pub fn new(limit: u64) -> Self {
|
pub fn new(limit: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
limit: LimitStack::new(limit),
|
limit: LimitStack::new(limit),
|
||||||
|
|
|
@ -191,6 +191,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DocMarkdown {
|
||||||
/// need to keep track of
|
/// need to keep track of
|
||||||
/// the spans but this function is inspired from the later.
|
/// the spans but this function is inspired from the later.
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
#[must_use]
|
||||||
pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(usize, Span)>) {
|
pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(usize, Span)>) {
|
||||||
// one-line comments lose their prefix
|
// one-line comments lose their prefix
|
||||||
const ONELINERS: &[&str] = &["///!", "///", "//!", "//"];
|
const ONELINERS: &[&str] = &["///!", "///", "//!", "//"];
|
||||||
|
|
|
@ -107,6 +107,7 @@ pub struct EnumVariantNames {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnumVariantNames {
|
impl EnumVariantNames {
|
||||||
|
#[must_use]
|
||||||
pub fn new(threshold: u64) -> Self {
|
pub fn new(threshold: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
modules: Vec::new(),
|
modules: Vec::new(),
|
||||||
|
@ -123,6 +124,7 @@ impl_lint_pass!(EnumVariantNames => [
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/// Returns the number of chars that match from the start
|
/// Returns the number of chars that match from the start
|
||||||
|
#[must_use]
|
||||||
fn partial_match(pre: &str, name: &str) -> usize {
|
fn partial_match(pre: &str, name: &str) -> usize {
|
||||||
let mut name_iter = name.chars();
|
let mut name_iter = name.chars();
|
||||||
let _ = name_iter.next_back(); // make sure the name is never fully matched
|
let _ = name_iter.next_back(); // make sure the name is never fully matched
|
||||||
|
@ -130,6 +132,7 @@ fn partial_match(pre: &str, name: &str) -> usize {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of chars that match from the end
|
/// Returns the number of chars that match from the end
|
||||||
|
#[must_use]
|
||||||
fn partial_rmatch(post: &str, name: &str) -> usize {
|
fn partial_rmatch(post: &str, name: &str) -> usize {
|
||||||
let mut name_iter = name.chars();
|
let mut name_iter = name.chars();
|
||||||
let _ = name_iter.next(); // make sure the name is never fully matched
|
let _ = name_iter.next(); // make sure the name is never fully matched
|
||||||
|
@ -211,6 +214,7 @@ fn check_variant(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn to_camel_case(item_name: &str) -> String {
|
fn to_camel_case(item_name: &str) -> String {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
let mut up = true;
|
let mut up = true;
|
||||||
|
|
|
@ -62,6 +62,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExcessivePrecision {
|
||||||
|
|
||||||
impl ExcessivePrecision {
|
impl ExcessivePrecision {
|
||||||
// None if nothing to lint, Some(suggestion) if lint necessary
|
// None if nothing to lint, Some(suggestion) if lint necessary
|
||||||
|
#[must_use]
|
||||||
fn check(self, sym: Symbol, fty: FloatTy) -> Option<String> {
|
fn check(self, sym: Symbol, fty: FloatTy) -> Option<String> {
|
||||||
let max = max_digits(fty);
|
let max = max_digits(fty);
|
||||||
let sym_str = sym.as_str();
|
let sym_str = sym.as_str();
|
||||||
|
@ -97,6 +98,7 @@ impl ExcessivePrecision {
|
||||||
/// Should we exclude the float because it has a `.0` or `.` suffix
|
/// Should we exclude the float because it has a `.0` or `.` suffix
|
||||||
/// Ex `1_000_000_000.0`
|
/// Ex `1_000_000_000.0`
|
||||||
/// Ex `1_000_000_000.`
|
/// Ex `1_000_000_000.`
|
||||||
|
#[must_use]
|
||||||
fn dot_zero_exclusion(s: &str) -> bool {
|
fn dot_zero_exclusion(s: &str) -> bool {
|
||||||
s.split('.').nth(1).map_or(false, |after_dec| {
|
s.split('.').nth(1).map_or(false, |after_dec| {
|
||||||
let mut decpart = after_dec.chars().take_while(|c| *c != 'e' || *c != 'E');
|
let mut decpart = after_dec.chars().take_while(|c| *c != 'e' || *c != 'E');
|
||||||
|
@ -109,6 +111,7 @@ fn dot_zero_exclusion(s: &str) -> bool {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn max_digits(fty: FloatTy) -> u32 {
|
fn max_digits(fty: FloatTy) -> u32 {
|
||||||
match fty {
|
match fty {
|
||||||
FloatTy::F32 => f32::DIGITS,
|
FloatTy::F32 => f32::DIGITS,
|
||||||
|
@ -117,6 +120,7 @@ fn max_digits(fty: FloatTy) -> u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Counts the digits excluding leading zeros
|
/// Counts the digits excluding leading zeros
|
||||||
|
#[must_use]
|
||||||
fn count_digits(s: &str) -> usize {
|
fn count_digits(s: &str) -> usize {
|
||||||
// Note that s does not contain the f32/64 suffix, and underscores have been stripped
|
// Note that s does not contain the f32/64 suffix, and underscores have been stripped
|
||||||
s.chars()
|
s.chars()
|
||||||
|
@ -138,6 +142,7 @@ enum FloatFormat {
|
||||||
Normal,
|
Normal,
|
||||||
}
|
}
|
||||||
impl FloatFormat {
|
impl FloatFormat {
|
||||||
|
#[must_use]
|
||||||
fn new(s: &str) -> Self {
|
fn new(s: &str) -> Self {
|
||||||
s.chars()
|
s.chars()
|
||||||
.find_map(|x| match x {
|
.find_map(|x| match x {
|
||||||
|
|
|
@ -235,6 +235,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn has_unary_equivalent(bin_op: BinOpKind) -> bool {
|
fn has_unary_equivalent(bin_op: BinOpKind) -> bool {
|
||||||
// &, *, -
|
// &, *, -
|
||||||
bin_op == BinOpKind::And || bin_op == BinOpKind::Mul || bin_op == BinOpKind::Sub
|
bin_op == BinOpKind::And || bin_op == BinOpKind::Mul || bin_op == BinOpKind::Sub
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
use std::convert::TryFrom;
|
use crate::utils::{
|
||||||
|
iter_input_pats, match_def_path, qpath_res, return_ty, snippet, snippet_opt, span_help_and_lint, span_lint,
|
||||||
use crate::utils::{iter_input_pats, qpath_res, snippet, snippet_opt, span_lint, type_is_unsafe_function};
|
span_lint_and_then, type_is_unsafe_function,
|
||||||
|
};
|
||||||
use matches::matches;
|
use matches::matches;
|
||||||
use rustc::hir;
|
use rustc::hir::{self, def::Res, def_id::DefId, intravisit};
|
||||||
use rustc::hir::def::Res;
|
|
||||||
use rustc::hir::intravisit;
|
|
||||||
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
|
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
|
||||||
use rustc::ty;
|
use rustc::ty::{self, Ty};
|
||||||
use rustc::{declare_tool_lint, impl_lint_pass};
|
use rustc::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
use rustc_errors::Applicability;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use syntax::source_map::{BytePos, Span};
|
use syntax::ast::Attribute;
|
||||||
|
use syntax::source_map::Span;
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// **What it does:** Checks for functions with too many parameters.
|
/// **What it does:** Checks for functions with too many parameters.
|
||||||
|
@ -84,6 +85,80 @@ declare_clippy_lint! {
|
||||||
"public functions dereferencing raw pointer arguments but not marked `unsafe`"
|
"public functions dereferencing raw pointer arguments but not marked `unsafe`"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// **What it does:** Checks for a [`#[must_use]`] attribute on
|
||||||
|
/// unit-returning functions and methods.
|
||||||
|
///
|
||||||
|
/// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
|
||||||
|
///
|
||||||
|
/// **Why is this bad?** Unit values are useless. The attribute is likely
|
||||||
|
/// a remnant of a refactoring that removed the return type.
|
||||||
|
///
|
||||||
|
/// **Known problems:** None.
|
||||||
|
///
|
||||||
|
/// **Examples:**
|
||||||
|
/// ```rust
|
||||||
|
/// #[must_use]
|
||||||
|
/// fn useless() { }
|
||||||
|
/// ```
|
||||||
|
pub MUST_USE_UNIT,
|
||||||
|
style,
|
||||||
|
"`#[must_use]` attribute on a unit-returning function / method"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// **What it does:** Checks for a [`#[must_use]`] attribute without
|
||||||
|
/// further information on functions and methods that return a type already
|
||||||
|
/// marked as `#[must_use]`.
|
||||||
|
///
|
||||||
|
/// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
|
||||||
|
///
|
||||||
|
/// **Why is this bad?** The attribute isn't needed. Not using the result
|
||||||
|
/// will already be reported. Alternatively, one can add some text to the
|
||||||
|
/// attribute to improve the lint message.
|
||||||
|
///
|
||||||
|
/// **Known problems:** None.
|
||||||
|
///
|
||||||
|
/// **Examples:**
|
||||||
|
/// ```rust
|
||||||
|
/// #[must_use]
|
||||||
|
/// fn double_must_use() -> Result<(), ()> {
|
||||||
|
/// unimplemented!();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub DOUBLE_MUST_USE,
|
||||||
|
style,
|
||||||
|
"`#[must_use]` attribute on a `#[must_use]`-returning function / method"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// **What it does:** Checks for public functions that have no
|
||||||
|
/// [`#[must_use]`] attribute, but return something not already marked
|
||||||
|
/// must-use, have no mutable arg and mutate no statics.
|
||||||
|
///
|
||||||
|
/// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
|
||||||
|
///
|
||||||
|
/// **Why is this bad?** Not bad at all, this lint just shows places where
|
||||||
|
/// you could add the attribute.
|
||||||
|
///
|
||||||
|
/// **Known problems:** The lint only checks the arguments for mutable
|
||||||
|
/// types without looking if they are actually changed. On the other hand,
|
||||||
|
/// it also ignores a broad range of potentially interesting side effects,
|
||||||
|
/// because we cannot decide whether the programmer intends the function to
|
||||||
|
/// be called for the side effect or the result. Expect many false
|
||||||
|
/// positives. At least we don't lint if the result type is unit or already
|
||||||
|
/// `#[must_use]`.
|
||||||
|
///
|
||||||
|
/// **Examples:**
|
||||||
|
/// ```rust
|
||||||
|
/// // this could be annotated with `#[must_use]`.
|
||||||
|
/// fn id<T>(t: T) -> T { t }
|
||||||
|
/// ```
|
||||||
|
pub MUST_USE_CANDIDATE,
|
||||||
|
pedantic,
|
||||||
|
"function or method that could take a `#[must_use]` attribute"
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Functions {
|
pub struct Functions {
|
||||||
threshold: u64,
|
threshold: u64,
|
||||||
|
@ -96,7 +171,14 @@ impl Functions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_lint_pass!(Functions => [TOO_MANY_ARGUMENTS, TOO_MANY_LINES, NOT_UNSAFE_PTR_ARG_DEREF]);
|
impl_lint_pass!(Functions => [
|
||||||
|
TOO_MANY_ARGUMENTS,
|
||||||
|
TOO_MANY_LINES,
|
||||||
|
NOT_UNSAFE_PTR_ARG_DEREF,
|
||||||
|
MUST_USE_UNIT,
|
||||||
|
DOUBLE_MUST_USE,
|
||||||
|
MUST_USE_CANDIDATE,
|
||||||
|
]);
|
||||||
|
|
||||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions {
|
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions {
|
||||||
fn check_fn(
|
fn check_fn(
|
||||||
|
@ -134,7 +216,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions {
|
||||||
_,
|
_,
|
||||||
)
|
)
|
||||||
| hir::intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => {
|
| hir::intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => {
|
||||||
self.check_arg_number(cx, decl, span)
|
self.check_arg_number(cx, decl, span.with_hi(decl.output.span().hi()))
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
@ -144,42 +226,88 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions {
|
||||||
self.check_line_number(cx, span, body);
|
self.check_line_number(cx, span, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
|
||||||
|
let attr = must_use_attr(&item.attrs);
|
||||||
|
if let hir::ItemKind::Fn(ref decl, ref _header, ref _generics, ref body_id) = item.kind {
|
||||||
|
if let Some(attr) = attr {
|
||||||
|
let fn_header_span = item.span.with_hi(decl.output.span().hi());
|
||||||
|
check_needless_must_use(cx, decl, item.hir_id, item.span, fn_header_span, attr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if cx.access_levels.is_exported(item.hir_id) {
|
||||||
|
check_must_use_candidate(
|
||||||
|
cx,
|
||||||
|
decl,
|
||||||
|
cx.tcx.hir().body(*body_id),
|
||||||
|
item.span,
|
||||||
|
item.hir_id,
|
||||||
|
item.span.with_hi(decl.output.span().hi()),
|
||||||
|
"this function could have a `#[must_use]` attribute",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplItem) {
|
||||||
|
if let hir::ImplItemKind::Method(ref sig, ref body_id) = item.kind {
|
||||||
|
let attr = must_use_attr(&item.attrs);
|
||||||
|
if let Some(attr) = attr {
|
||||||
|
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
|
||||||
|
check_needless_must_use(cx, &sig.decl, item.hir_id, item.span, fn_header_span, attr);
|
||||||
|
} else if cx.access_levels.is_exported(item.hir_id) {
|
||||||
|
check_must_use_candidate(
|
||||||
|
cx,
|
||||||
|
&sig.decl,
|
||||||
|
cx.tcx.hir().body(*body_id),
|
||||||
|
item.span,
|
||||||
|
item.hir_id,
|
||||||
|
item.span.with_hi(sig.decl.output.span().hi()),
|
||||||
|
"this method could have a `#[must_use]` attribute",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) {
|
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) {
|
||||||
if let hir::TraitItemKind::Method(ref sig, ref eid) = item.kind {
|
if let hir::TraitItemKind::Method(ref sig, ref eid) = item.kind {
|
||||||
// don't lint extern functions decls, it's not their fault
|
// don't lint extern functions decls, it's not their fault
|
||||||
if sig.header.abi == Abi::Rust {
|
if sig.header.abi == Abi::Rust {
|
||||||
self.check_arg_number(cx, &sig.decl, item.span);
|
self.check_arg_number(cx, &sig.decl, item.span.with_hi(sig.decl.output.span().hi()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let attr = must_use_attr(&item.attrs);
|
||||||
|
if let Some(attr) = attr {
|
||||||
|
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
|
||||||
|
check_needless_must_use(cx, &sig.decl, item.hir_id, item.span, fn_header_span, attr);
|
||||||
|
}
|
||||||
if let hir::TraitMethod::Provided(eid) = *eid {
|
if let hir::TraitMethod::Provided(eid) = *eid {
|
||||||
let body = cx.tcx.hir().body(eid);
|
let body = cx.tcx.hir().body(eid);
|
||||||
self.check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id);
|
self.check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id);
|
||||||
|
|
||||||
|
if attr.is_none() && cx.access_levels.is_exported(item.hir_id) {
|
||||||
|
check_must_use_candidate(
|
||||||
|
cx,
|
||||||
|
&sig.decl,
|
||||||
|
body,
|
||||||
|
item.span,
|
||||||
|
item.hir_id,
|
||||||
|
item.span.with_hi(sig.decl.output.span().hi()),
|
||||||
|
"this method could have a `#[must_use]` attribute",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Functions {
|
impl<'a, 'tcx> Functions {
|
||||||
fn check_arg_number(self, cx: &LateContext<'_, '_>, decl: &hir::FnDecl, span: Span) {
|
fn check_arg_number(self, cx: &LateContext<'_, '_>, decl: &hir::FnDecl, fn_span: Span) {
|
||||||
// Remove the function body from the span. We can't use `SourceMap::def_span` because the
|
|
||||||
// argument list might span multiple lines.
|
|
||||||
let span = if let Some(snippet) = snippet_opt(cx, span) {
|
|
||||||
let snippet = snippet.split('{').nth(0).unwrap_or("").trim_end();
|
|
||||||
if snippet.is_empty() {
|
|
||||||
span
|
|
||||||
} else {
|
|
||||||
span.with_hi(BytePos(span.lo().0 + u32::try_from(snippet.len()).unwrap()))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
span
|
|
||||||
};
|
|
||||||
|
|
||||||
let args = decl.inputs.len() as u64;
|
let args = decl.inputs.len() as u64;
|
||||||
if args > self.threshold {
|
if args > self.threshold {
|
||||||
span_lint(
|
span_lint(
|
||||||
cx,
|
cx,
|
||||||
TOO_MANY_ARGUMENTS,
|
TOO_MANY_ARGUMENTS,
|
||||||
span,
|
fn_span,
|
||||||
&format!("this function has too many arguments ({}/{})", args, self.threshold),
|
&format!("this function has too many arguments ({}/{})", args, self.threshold),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -268,6 +396,164 @@ impl<'a, 'tcx> Functions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_needless_must_use(
|
||||||
|
cx: &LateContext<'_, '_>,
|
||||||
|
decl: &hir::FnDecl,
|
||||||
|
item_id: hir::HirId,
|
||||||
|
item_span: Span,
|
||||||
|
fn_header_span: Span,
|
||||||
|
attr: &Attribute,
|
||||||
|
) {
|
||||||
|
if in_external_macro(cx.sess(), item_span) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if returns_unit(decl) {
|
||||||
|
span_lint_and_then(
|
||||||
|
cx,
|
||||||
|
MUST_USE_UNIT,
|
||||||
|
fn_header_span,
|
||||||
|
"this unit-returning function has a `#[must_use]` attribute",
|
||||||
|
|db| {
|
||||||
|
db.span_suggestion(
|
||||||
|
attr.span,
|
||||||
|
"remove the attribute",
|
||||||
|
"".into(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else if !attr.is_value_str() && is_must_use_ty(cx, return_ty(cx, item_id)) {
|
||||||
|
span_help_and_lint(
|
||||||
|
cx,
|
||||||
|
DOUBLE_MUST_USE,
|
||||||
|
fn_header_span,
|
||||||
|
"this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`",
|
||||||
|
"either add some descriptive text or remove the attribute",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_must_use_candidate<'a, 'tcx>(
|
||||||
|
cx: &LateContext<'a, 'tcx>,
|
||||||
|
decl: &'tcx hir::FnDecl,
|
||||||
|
body: &'tcx hir::Body,
|
||||||
|
item_span: Span,
|
||||||
|
item_id: hir::HirId,
|
||||||
|
fn_span: Span,
|
||||||
|
msg: &str,
|
||||||
|
) {
|
||||||
|
if has_mutable_arg(cx, body)
|
||||||
|
|| mutates_static(cx, body)
|
||||||
|
|| in_external_macro(cx.sess(), item_span)
|
||||||
|
|| returns_unit(decl)
|
||||||
|
|| is_must_use_ty(cx, return_ty(cx, item_id))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
span_lint_and_then(cx, MUST_USE_CANDIDATE, fn_span, msg, |db| {
|
||||||
|
if let Some(snippet) = snippet_opt(cx, fn_span) {
|
||||||
|
db.span_suggestion(
|
||||||
|
fn_span,
|
||||||
|
"add the attribute",
|
||||||
|
format!("#[must_use] {}", snippet),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
|
||||||
|
attrs
|
||||||
|
.iter()
|
||||||
|
.find(|attr| attr.ident().map_or(false, |ident| "must_use" == &ident.as_str()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn returns_unit(decl: &hir::FnDecl) -> bool {
|
||||||
|
match decl.output {
|
||||||
|
hir::FunctionRetTy::DefaultReturn(_) => true,
|
||||||
|
hir::FunctionRetTy::Return(ref ty) => match ty.kind {
|
||||||
|
hir::TyKind::Tup(ref tys) => tys.is_empty(),
|
||||||
|
hir::TyKind::Never => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_must_use_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
|
use ty::TyKind::*;
|
||||||
|
match ty.kind {
|
||||||
|
Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(),
|
||||||
|
Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(),
|
||||||
|
Slice(ref ty) | Array(ref ty, _) | RawPtr(ty::TypeAndMut { ref ty, .. }) | Ref(_, ref ty, _) => {
|
||||||
|
// for the Array case we don't need to care for the len == 0 case
|
||||||
|
// because we don't want to lint functions returning empty arrays
|
||||||
|
is_must_use_ty(cx, *ty)
|
||||||
|
},
|
||||||
|
Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
|
||||||
|
Opaque(ref def_id, _) => {
|
||||||
|
for (predicate, _) in &cx.tcx.predicates_of(*def_id).predicates {
|
||||||
|
if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate {
|
||||||
|
if must_use_attr(&cx.tcx.get_attrs(poly_trait_predicate.skip_binder().trait_ref.def_id)).is_some() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
},
|
||||||
|
Dynamic(binder, _) => {
|
||||||
|
for predicate in binder.skip_binder().iter() {
|
||||||
|
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate {
|
||||||
|
if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_mutable_arg(cx: &LateContext<'_, '_>, body: &hir::Body) -> bool {
|
||||||
|
let mut tys = FxHashSet::default();
|
||||||
|
body.params.iter().any(|param| is_mutable_pat(cx, ¶m.pat, &mut tys))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_mutable_pat(cx: &LateContext<'_, '_>, pat: &hir::Pat, tys: &mut FxHashSet<DefId>) -> bool {
|
||||||
|
if let hir::PatKind::Wild = pat.kind {
|
||||||
|
return false; // ignore `_` patterns
|
||||||
|
}
|
||||||
|
let def_id = pat.hir_id.owner_def_id();
|
||||||
|
if cx.tcx.has_typeck_tables(def_id) {
|
||||||
|
is_mutable_ty(cx, &cx.tcx.typeck_tables_of(def_id).pat_ty(pat), pat.span, tys)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static KNOWN_WRAPPER_TYS: &[&[&str]] = &[&["alloc", "rc", "Rc"], &["std", "sync", "Arc"]];
|
||||||
|
|
||||||
|
fn is_mutable_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>, span: Span, tys: &mut FxHashSet<DefId>) -> bool {
|
||||||
|
use ty::TyKind::*;
|
||||||
|
match ty.kind {
|
||||||
|
// primitive types are never mutable
|
||||||
|
Bool | Char | Int(_) | Uint(_) | Float(_) | Str => false,
|
||||||
|
Adt(ref adt, ref substs) => {
|
||||||
|
tys.insert(adt.did) && !ty.is_freeze(cx.tcx, cx.param_env, span)
|
||||||
|
|| KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did, path))
|
||||||
|
&& substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys))
|
||||||
|
},
|
||||||
|
Tuple(ref substs) => substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys)),
|
||||||
|
Array(ty, _) | Slice(ty) => is_mutable_ty(cx, ty, span, tys),
|
||||||
|
RawPtr(ty::TypeAndMut { ty, mutbl }) | Ref(_, ty, mutbl) => {
|
||||||
|
mutbl == hir::Mutability::MutMutable || is_mutable_ty(cx, ty, span, tys)
|
||||||
|
},
|
||||||
|
// calling something constitutes a side effect, so return true on all callables
|
||||||
|
// also never calls need not be used, so return true for them, too
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn raw_ptr_arg(arg: &hir::Param, ty: &hir::Ty) -> Option<hir::HirId> {
|
fn raw_ptr_arg(arg: &hir::Param, ty: &hir::Ty) -> Option<hir::HirId> {
|
||||||
if let (&hir::PatKind::Binding(_, id, _, _), &hir::TyKind::Ptr(_)) = (&arg.pat.kind, &ty.kind) {
|
if let (&hir::PatKind::Binding(_, id, _, _), &hir::TyKind::Ptr(_)) = (&arg.pat.kind, &ty.kind) {
|
||||||
Some(id)
|
Some(id)
|
||||||
|
@ -282,7 +568,7 @@ struct DerefVisitor<'a, 'tcx> {
|
||||||
tables: &'a ty::TypeckTables<'tcx>,
|
tables: &'a ty::TypeckTables<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
|
||||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
|
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
hir::ExprKind::Call(ref f, ref args) => {
|
hir::ExprKind::Call(ref f, ref args) => {
|
||||||
|
@ -308,8 +594,9 @@ impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::intravisit::walk_expr(self, expr);
|
intravisit::walk_expr(self, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
|
fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
|
||||||
intravisit::NestedVisitorMap::None
|
intravisit::NestedVisitorMap::None
|
||||||
}
|
}
|
||||||
|
@ -331,3 +618,72 @@ impl<'a, 'tcx> DerefVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct StaticMutVisitor<'a, 'tcx> {
|
||||||
|
cx: &'a LateContext<'a, 'tcx>,
|
||||||
|
mutates_static: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
|
||||||
|
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
|
||||||
|
use hir::ExprKind::*;
|
||||||
|
|
||||||
|
if self.mutates_static {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
match expr.kind {
|
||||||
|
Call(_, ref args) | MethodCall(_, _, ref args) => {
|
||||||
|
let mut tys = FxHashSet::default();
|
||||||
|
for arg in args {
|
||||||
|
let def_id = arg.hir_id.owner_def_id();
|
||||||
|
if self.cx.tcx.has_typeck_tables(def_id)
|
||||||
|
&& is_mutable_ty(
|
||||||
|
self.cx,
|
||||||
|
self.cx.tcx.typeck_tables_of(def_id).expr_ty(arg),
|
||||||
|
arg.span,
|
||||||
|
&mut tys,
|
||||||
|
)
|
||||||
|
&& is_mutated_static(self.cx, arg)
|
||||||
|
{
|
||||||
|
self.mutates_static = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tys.clear();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Assign(ref target, _) | AssignOp(_, ref target, _) | AddrOf(hir::Mutability::MutMutable, ref target) => {
|
||||||
|
self.mutates_static |= is_mutated_static(self.cx, target)
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
|
||||||
|
intravisit::NestedVisitorMap::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_mutated_static(cx: &LateContext<'_, '_>, e: &hir::Expr) -> bool {
|
||||||
|
use hir::ExprKind::*;
|
||||||
|
|
||||||
|
match e.kind {
|
||||||
|
Path(ref qpath) => {
|
||||||
|
if let Res::Local(_) = qpath_res(cx, qpath, e.hir_id) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(cx, inner),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mutates_static<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, body: &'tcx hir::Body) -> bool {
|
||||||
|
let mut v = StaticMutVisitor {
|
||||||
|
cx,
|
||||||
|
mutates_static: false,
|
||||||
|
};
|
||||||
|
intravisit::walk_expr(&mut v, &body.value);
|
||||||
|
v.mutates_static
|
||||||
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ enum Finiteness {
|
||||||
use self::Finiteness::{Finite, Infinite, MaybeInfinite};
|
use self::Finiteness::{Finite, Infinite, MaybeInfinite};
|
||||||
|
|
||||||
impl Finiteness {
|
impl Finiteness {
|
||||||
|
#[must_use]
|
||||||
fn and(self, b: Self) -> Self {
|
fn and(self, b: Self) -> Self {
|
||||||
match (self, b) {
|
match (self, b) {
|
||||||
(Finite, _) | (_, Finite) => Finite,
|
(Finite, _) | (_, Finite) => Finite,
|
||||||
|
@ -75,6 +76,7 @@ impl Finiteness {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn or(self, b: Self) -> Self {
|
fn or(self, b: Self) -> Self {
|
||||||
match (self, b) {
|
match (self, b) {
|
||||||
(Infinite, _) | (_, Infinite) => Infinite,
|
(Infinite, _) | (_, Infinite) => Infinite,
|
||||||
|
@ -85,6 +87,7 @@ impl Finiteness {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<bool> for Finiteness {
|
impl From<bool> for Finiteness {
|
||||||
|
#[must_use]
|
||||||
fn from(b: bool) -> Self {
|
fn from(b: bool) -> Self {
|
||||||
if b {
|
if b {
|
||||||
Infinite
|
Infinite
|
||||||
|
|
|
@ -35,6 +35,7 @@ pub struct LargeEnumVariant {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LargeEnumVariant {
|
impl LargeEnumVariant {
|
||||||
|
#[must_use]
|
||||||
pub fn new(maximum_size_difference_allowed: u64) -> Self {
|
pub fn new(maximum_size_difference_allowed: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
maximum_size_difference_allowed,
|
maximum_size_difference_allowed,
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#![feature(rustc_private)]
|
#![feature(rustc_private)]
|
||||||
#![feature(slice_patterns)]
|
#![feature(slice_patterns)]
|
||||||
#![feature(stmt_expr_attributes)]
|
#![feature(stmt_expr_attributes)]
|
||||||
#![allow(clippy::missing_docs_in_private_items)]
|
#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]
|
||||||
#![recursion_limit = "512"]
|
#![recursion_limit = "512"]
|
||||||
#![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)]
|
#![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)]
|
||||||
#![deny(rustc::internal)]
|
#![deny(rustc::internal)]
|
||||||
|
@ -648,6 +648,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
|
||||||
enum_variants::MODULE_NAME_REPETITIONS,
|
enum_variants::MODULE_NAME_REPETITIONS,
|
||||||
enum_variants::PUB_ENUM_VARIANT_NAMES,
|
enum_variants::PUB_ENUM_VARIANT_NAMES,
|
||||||
eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
|
eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
|
||||||
|
functions::MUST_USE_CANDIDATE,
|
||||||
functions::TOO_MANY_LINES,
|
functions::TOO_MANY_LINES,
|
||||||
if_not_else::IF_NOT_ELSE,
|
if_not_else::IF_NOT_ELSE,
|
||||||
infinite_iter::MAYBE_INFINITE_ITER,
|
infinite_iter::MAYBE_INFINITE_ITER,
|
||||||
|
@ -744,6 +745,8 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
|
||||||
formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
|
formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
|
||||||
formatting::SUSPICIOUS_ELSE_FORMATTING,
|
formatting::SUSPICIOUS_ELSE_FORMATTING,
|
||||||
formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
|
formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
|
||||||
|
functions::DOUBLE_MUST_USE,
|
||||||
|
functions::MUST_USE_UNIT,
|
||||||
functions::NOT_UNSAFE_PTR_ARG_DEREF,
|
functions::NOT_UNSAFE_PTR_ARG_DEREF,
|
||||||
functions::TOO_MANY_ARGUMENTS,
|
functions::TOO_MANY_ARGUMENTS,
|
||||||
get_last_with_len::GET_LAST_WITH_LEN,
|
get_last_with_len::GET_LAST_WITH_LEN,
|
||||||
|
@ -955,6 +958,8 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
|
||||||
formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
|
formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
|
||||||
formatting::SUSPICIOUS_ELSE_FORMATTING,
|
formatting::SUSPICIOUS_ELSE_FORMATTING,
|
||||||
formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
|
formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
|
||||||
|
functions::DOUBLE_MUST_USE,
|
||||||
|
functions::MUST_USE_UNIT,
|
||||||
infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH,
|
infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH,
|
||||||
inherent_to_string::INHERENT_TO_STRING,
|
inherent_to_string::INHERENT_TO_STRING,
|
||||||
len_zero::LEN_WITHOUT_IS_EMPTY,
|
len_zero::LEN_WITHOUT_IS_EMPTY,
|
||||||
|
|
|
@ -270,6 +270,7 @@ fn lts_from_bounds<'a, T: Iterator<Item = &'a Lifetime>>(mut vec: Vec<RefLt>, bo
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of unique lifetimes in the given vector.
|
/// Number of unique lifetimes in the given vector.
|
||||||
|
#[must_use]
|
||||||
fn unique_lifetimes(lts: &[RefLt]) -> usize {
|
fn unique_lifetimes(lts: &[RefLt]) -> usize {
|
||||||
lts.iter().collect::<FxHashSet<_>>().len()
|
lts.iter().collect::<FxHashSet<_>>().len()
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,7 @@ pub(super) enum Radix {
|
||||||
|
|
||||||
impl Radix {
|
impl Radix {
|
||||||
/// Returns a reasonable digit group size for this radix.
|
/// Returns a reasonable digit group size for this radix.
|
||||||
|
#[must_use]
|
||||||
crate fn suggest_grouping(&self) -> usize {
|
crate fn suggest_grouping(&self) -> usize {
|
||||||
match *self {
|
match *self {
|
||||||
Self::Binary | Self::Hexadecimal => 4,
|
Self::Binary | Self::Hexadecimal => 4,
|
||||||
|
@ -136,6 +137,7 @@ pub(super) struct DigitInfo<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DigitInfo<'a> {
|
impl<'a> DigitInfo<'a> {
|
||||||
|
#[must_use]
|
||||||
crate fn new(lit: &'a str, float: bool) -> Self {
|
crate fn new(lit: &'a str, float: bool) -> Self {
|
||||||
// Determine delimiter for radix prefix, if present, and radix.
|
// Determine delimiter for radix prefix, if present, and radix.
|
||||||
let radix = if lit.starts_with("0x") {
|
let radix = if lit.starts_with("0x") {
|
||||||
|
@ -422,6 +424,7 @@ impl LiteralDigitGrouping {
|
||||||
/// Given the sizes of the digit groups of both integral and fractional
|
/// Given the sizes of the digit groups of both integral and fractional
|
||||||
/// parts, and the length
|
/// parts, and the length
|
||||||
/// of both parts, determine if the digits have been grouped consistently.
|
/// of both parts, determine if the digits have been grouped consistently.
|
||||||
|
#[must_use]
|
||||||
fn parts_consistent(int_group_size: usize, frac_group_size: usize, int_size: usize, frac_size: usize) -> bool {
|
fn parts_consistent(int_group_size: usize, frac_group_size: usize, int_size: usize, frac_size: usize) -> bool {
|
||||||
match (int_group_size, frac_group_size) {
|
match (int_group_size, frac_group_size) {
|
||||||
// No groups on either side of decimal point - trivially consistent.
|
// No groups on either side of decimal point - trivially consistent.
|
||||||
|
@ -499,6 +502,7 @@ impl EarlyLintPass for DecimalLiteralRepresentation {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DecimalLiteralRepresentation {
|
impl DecimalLiteralRepresentation {
|
||||||
|
#[must_use]
|
||||||
pub fn new(threshold: u64) -> Self {
|
pub fn new(threshold: u64) -> Self {
|
||||||
Self { threshold }
|
Self { threshold }
|
||||||
}
|
}
|
||||||
|
@ -573,22 +577,27 @@ impl DecimalLiteralRepresentation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn is_mistyped_suffix(suffix: &str) -> bool {
|
fn is_mistyped_suffix(suffix: &str) -> bool {
|
||||||
["_8", "_16", "_32", "_64"].contains(&suffix)
|
["_8", "_16", "_32", "_64"].contains(&suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn is_possible_suffix_index(lit: &str, idx: usize, len: usize) -> bool {
|
fn is_possible_suffix_index(lit: &str, idx: usize, len: usize) -> bool {
|
||||||
((len > 3 && idx == len - 3) || (len > 2 && idx == len - 2)) && is_mistyped_suffix(lit.split_at(idx).1)
|
((len > 3 && idx == len - 3) || (len > 2 && idx == len - 2)) && is_mistyped_suffix(lit.split_at(idx).1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn is_mistyped_float_suffix(suffix: &str) -> bool {
|
fn is_mistyped_float_suffix(suffix: &str) -> bool {
|
||||||
["_32", "_64"].contains(&suffix)
|
["_32", "_64"].contains(&suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn is_possible_float_suffix_index(lit: &str, idx: usize, len: usize) -> bool {
|
fn is_possible_float_suffix_index(lit: &str, idx: usize, len: usize) -> bool {
|
||||||
(len > 3 && idx == len - 3) && is_mistyped_float_suffix(lit.split_at(idx).1)
|
(len > 3 && idx == len - 3) && is_mistyped_float_suffix(lit.split_at(idx).1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn has_possible_float_suffix(lit: &str) -> bool {
|
fn has_possible_float_suffix(lit: &str) -> bool {
|
||||||
lit.ends_with("_32") || lit.ends_with("_64")
|
lit.ends_with("_32") || lit.ends_with("_64")
|
||||||
}
|
}
|
||||||
|
|
|
@ -610,6 +610,7 @@ enum NeverLoopResult {
|
||||||
Otherwise,
|
Otherwise,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult {
|
fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult {
|
||||||
match *arg {
|
match *arg {
|
||||||
NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
|
NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
|
||||||
|
@ -618,6 +619,7 @@ fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combine two results for parts that are called in order.
|
// Combine two results for parts that are called in order.
|
||||||
|
#[must_use]
|
||||||
fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResult {
|
fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResult {
|
||||||
match first {
|
match first {
|
||||||
NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop => first,
|
NeverLoopResult::AlwaysBreak | NeverLoopResult::MayContinueMainLoop => first,
|
||||||
|
@ -626,6 +628,7 @@ fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResu
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combine two results where both parts are called but not necessarily in order.
|
// Combine two results where both parts are called but not necessarily in order.
|
||||||
|
#[must_use]
|
||||||
fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResult {
|
fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResult {
|
||||||
match (left, right) {
|
match (left, right) {
|
||||||
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
|
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
|
||||||
|
@ -637,6 +640,7 @@ fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResul
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combine two results where only one of the part may have been executed.
|
// Combine two results where only one of the part may have been executed.
|
||||||
|
#[must_use]
|
||||||
fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult {
|
fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult {
|
||||||
match (b1, b2) {
|
match (b1, b2) {
|
||||||
(NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
|
(NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
|
||||||
|
|
|
@ -195,6 +195,7 @@ fn let_binding_name(cx: &LateContext<'_, '_>, var_arg: &hir::Expr) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn suggestion_msg(function_type: &str, map_type: &str) -> String {
|
fn suggestion_msg(function_type: &str, map_type: &str) -> String {
|
||||||
format!(
|
format!(
|
||||||
"called `map(f)` on an {0} value where `f` is a unit {1}",
|
"called `map(f)` on an {0} value where `f` is a unit {1}",
|
||||||
|
|
|
@ -2898,6 +2898,7 @@ impl SelfKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn description(self) -> &'static str {
|
fn description(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Value => "self by value",
|
Self::Value => "self by value",
|
||||||
|
@ -2909,6 +2910,7 @@ impl SelfKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Convention {
|
impl Convention {
|
||||||
|
#[must_use]
|
||||||
fn check(&self, other: &str) -> bool {
|
fn check(&self, other: &str) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Self::Eq(this) => this == other,
|
Self::Eq(this) => this == other,
|
||||||
|
|
|
@ -253,6 +253,7 @@ struct ReturnVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReturnVisitor {
|
impl ReturnVisitor {
|
||||||
|
#[must_use]
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self { found_return: false }
|
Self { found_return: false }
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,6 +128,7 @@ fn method_accepts_dropable(cx: &LateContext<'_, '_>, param_tys: &HirVec<hir::Ty>
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't have to lint on something that's already `const`
|
// We don't have to lint on something that's already `const`
|
||||||
|
#[must_use]
|
||||||
fn already_const(header: hir::FnHeader) -> bool {
|
fn already_const(header: hir::FnHeader) -> bool {
|
||||||
header.constness == Constness::Const
|
header.constness == Constness::Const
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,12 +37,14 @@ pub struct MissingDoc {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::default::Default for MissingDoc {
|
impl ::std::default::Default for MissingDoc {
|
||||||
|
#[must_use]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MissingDoc {
|
impl MissingDoc {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
doc_hidden_stack: vec![false],
|
doc_hidden_stack: vec![false],
|
||||||
|
|
|
@ -405,6 +405,7 @@ fn check_and_warn<'a>(ctx: &EarlyContext<'_>, expr: &'a ast::Expr) {
|
||||||
///
|
///
|
||||||
/// NOTE: when there is no closing brace in `s`, `s` is _not_ preserved, i.e.,
|
/// NOTE: when there is no closing brace in `s`, `s` is _not_ preserved, i.e.,
|
||||||
/// an empty string will be returned in that case.
|
/// an empty string will be returned in that case.
|
||||||
|
#[must_use]
|
||||||
pub fn erode_from_back(s: &str) -> String {
|
pub fn erode_from_back(s: &str) -> String {
|
||||||
let mut ret = String::from(s);
|
let mut ret = String::from(s);
|
||||||
while ret.pop().map_or(false, |c| c != '}') {}
|
while ret.pop().map_or(false, |c| c != '}') {}
|
||||||
|
@ -435,6 +436,7 @@ pub fn erode_from_back(s: &str) -> String {
|
||||||
/// inside_a_block();
|
/// inside_a_block();
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
#[must_use]
|
||||||
pub fn erode_from_front(s: &str) -> String {
|
pub fn erode_from_front(s: &str) -> String {
|
||||||
s.chars()
|
s.chars()
|
||||||
.skip_while(|c| c.is_whitespace())
|
.skip_while(|c| c.is_whitespace())
|
||||||
|
@ -447,6 +449,7 @@ pub fn erode_from_front(s: &str) -> String {
|
||||||
/// tries to get the contents of the block. If there is no closing brace
|
/// tries to get the contents of the block. If there is no closing brace
|
||||||
/// present,
|
/// present,
|
||||||
/// an empty string is returned.
|
/// an empty string is returned.
|
||||||
|
#[must_use]
|
||||||
pub fn erode_block(s: &str) -> String {
|
pub fn erode_block(s: &str) -> String {
|
||||||
erode_from_back(&erode_from_front(s))
|
erode_from_back(&erode_from_front(s))
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ enum Source {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Source {
|
impl Source {
|
||||||
|
#[must_use]
|
||||||
fn lint(&self) -> (&'static Lint, &'static str, Span) {
|
fn lint(&self) -> (&'static Lint, &'static str, Span) {
|
||||||
match self {
|
match self {
|
||||||
Self::Item { item } | Self::Assoc { item, .. } => (
|
Self::Item { item } | Self::Assoc { item, .. } => (
|
||||||
|
|
|
@ -148,6 +148,7 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> {
|
fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> {
|
||||||
for &allow in WHITELIST {
|
for &allow in WHITELIST {
|
||||||
if whitelisted(interned_name, allow) {
|
if whitelisted(interned_name, allow) {
|
||||||
|
@ -157,6 +158,7 @@ fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn whitelisted(interned_name: &str, list: &[&str]) -> bool {
|
fn whitelisted(interned_name: &str, list: &[&str]) -> bool {
|
||||||
list.iter()
|
list.iter()
|
||||||
.any(|&name| interned_name.starts_with(name) || interned_name.ends_with(name))
|
.any(|&name| interned_name.starts_with(name) || interned_name.ends_with(name))
|
||||||
|
@ -383,6 +385,7 @@ fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attri
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Precondition: `a_name.chars().count() < b_name.chars().count()`.
|
/// Precondition: `a_name.chars().count() < b_name.chars().count()`.
|
||||||
|
#[must_use]
|
||||||
fn levenstein_not_1(a_name: &str, b_name: &str) -> bool {
|
fn levenstein_not_1(a_name: &str, b_name: &str) -> bool {
|
||||||
debug_assert!(a_name.chars().count() < b_name.chars().count());
|
debug_assert!(a_name.chars().count() < b_name.chars().count());
|
||||||
let mut a_chars = a_name.chars();
|
let mut a_chars = a_name.chars();
|
||||||
|
|
|
@ -121,6 +121,7 @@ fn is_arith_expr(expr: &Expr) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn is_bit_op(op: BinOpKind) -> bool {
|
fn is_bit_op(op: BinOpKind) -> bool {
|
||||||
use syntax::ast::BinOpKind::*;
|
use syntax::ast::BinOpKind::*;
|
||||||
match op {
|
match op {
|
||||||
|
@ -129,6 +130,7 @@ fn is_bit_op(op: BinOpKind) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn is_arith_op(op: BinOpKind) -> bool {
|
fn is_arith_op(op: BinOpKind) -> bool {
|
||||||
use syntax::ast::BinOpKind::*;
|
use syntax::ast::BinOpKind::*;
|
||||||
match op {
|
match op {
|
||||||
|
|
|
@ -131,6 +131,7 @@ enum Method {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Method {
|
impl Method {
|
||||||
|
#[must_use]
|
||||||
fn suggestion(self) -> &'static str {
|
fn suggestion(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Offset => "add",
|
Self::Offset => "add",
|
||||||
|
|
|
@ -129,6 +129,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Regex {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::cast_possible_truncation)] // truncation very unlikely here
|
#[allow(clippy::cast_possible_truncation)] // truncation very unlikely here
|
||||||
|
#[must_use]
|
||||||
fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u16) -> Span {
|
fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u16) -> Span {
|
||||||
let offset = u32::from(offset);
|
let offset = u32::from(offset);
|
||||||
let end = base.lo() + BytePos(u32::try_from(c.end.offset).expect("offset too large") + offset);
|
let end = base.lo() + BytePos(u32::try_from(c.end.offset).expect("offset too large") + offset);
|
||||||
|
|
|
@ -318,6 +318,7 @@ fn attr_is_cfg(attr: &ast::Attribute) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the def site
|
// get the def site
|
||||||
|
#[must_use]
|
||||||
fn get_def(span: Span) -> Option<Span> {
|
fn get_def(span: Span) -> Option<Span> {
|
||||||
if span.from_expansion() {
|
if span.from_expansion() {
|
||||||
Some(span.ctxt().outer_expn_data().def_site)
|
Some(span.ctxt().outer_expn_data().def_site)
|
||||||
|
|
|
@ -1372,6 +1372,7 @@ pub struct TypeComplexity {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeComplexity {
|
impl TypeComplexity {
|
||||||
|
#[must_use]
|
||||||
pub fn new(threshold: u64) -> Self {
|
pub fn new(threshold: u64) -> Self {
|
||||||
Self { threshold }
|
Self { threshold }
|
||||||
}
|
}
|
||||||
|
@ -1780,6 +1781,7 @@ enum FullInt {
|
||||||
|
|
||||||
impl FullInt {
|
impl FullInt {
|
||||||
#[allow(clippy::cast_sign_loss)]
|
#[allow(clippy::cast_sign_loss)]
|
||||||
|
#[must_use]
|
||||||
fn cmp_s_u(s: i128, u: u128) -> Ordering {
|
fn cmp_s_u(s: i128, u: u128) -> Ordering {
|
||||||
if s < 0 {
|
if s < 0 {
|
||||||
Ordering::Less
|
Ordering::Less
|
||||||
|
@ -1792,12 +1794,14 @@ impl FullInt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for FullInt {
|
impl PartialEq for FullInt {
|
||||||
|
#[must_use]
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.partial_cmp(other).expect("partial_cmp only returns Some(_)") == Ordering::Equal
|
self.partial_cmp(other).expect("partial_cmp only returns Some(_)") == Ordering::Equal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for FullInt {
|
impl PartialOrd for FullInt {
|
||||||
|
#[must_use]
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
Some(match (self, other) {
|
Some(match (self, other) {
|
||||||
(&Self::S(s), &Self::S(o)) => s.cmp(&o),
|
(&Self::S(s), &Self::S(o)) => s.cmp(&o),
|
||||||
|
@ -1808,6 +1812,7 @@ impl PartialOrd for FullInt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Ord for FullInt {
|
impl Ord for FullInt {
|
||||||
|
#[must_use]
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
self.partial_cmp(other)
|
self.partial_cmp(other)
|
||||||
.expect("partial_cmp for FullInt can never return None")
|
.expect("partial_cmp for FullInt can never return None")
|
||||||
|
|
|
@ -72,6 +72,7 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn contains_unsafe(name: &LocalInternedString) -> bool {
|
fn contains_unsafe(name: &LocalInternedString) -> bool {
|
||||||
name.contains("Unsafe") || name.contains("unsafe")
|
name.contains("Unsafe") || name.contains("unsafe")
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ impl Drop for LimitStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LimitStack {
|
impl LimitStack {
|
||||||
|
#[must_use]
|
||||||
pub fn new(limit: u64) -> Self {
|
pub fn new(limit: u64) -> Self {
|
||||||
Self { stack: vec![limit] }
|
Self { stack: vec![limit] }
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,6 +146,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Author {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrintVisitor {
|
impl PrintVisitor {
|
||||||
|
#[must_use]
|
||||||
fn new(s: &'static str) -> Self {
|
fn new(s: &'static str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ids: FxHashMap::default(),
|
ids: FxHashMap::default(),
|
||||||
|
@ -683,6 +684,7 @@ fn has_attr(sess: &Session, attrs: &[Attribute]) -> bool {
|
||||||
get_attr(sess, attrs, "author").count() > 0
|
get_attr(sess, attrs, "author").count() > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn desugaring_name(des: hir::MatchSource) -> String {
|
fn desugaring_name(des: hir::MatchSource) -> String {
|
||||||
match des {
|
match des {
|
||||||
hir::MatchSource::ForLoopDesugar => "MatchSource::ForLoopDesugar".to_string(),
|
hir::MatchSource::ForLoopDesugar => "MatchSource::ForLoopDesugar".to_string(),
|
||||||
|
@ -702,6 +704,7 @@ fn desugaring_name(des: hir::MatchSource) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn loop_desugaring_name(des: hir::LoopSource) -> &'static str {
|
fn loop_desugaring_name(des: hir::LoopSource) -> &'static str {
|
||||||
match des {
|
match des {
|
||||||
hir::LoopSource::ForLoop => "LoopSource::ForLoop",
|
hir::LoopSource::ForLoop => "LoopSource::ForLoop",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/// Returns the index of the character after the first camel-case component of `s`.
|
/// Returns the index of the character after the first camel-case component of `s`.
|
||||||
|
#[must_use]
|
||||||
pub fn until(s: &str) -> usize {
|
pub fn until(s: &str) -> usize {
|
||||||
let mut iter = s.char_indices();
|
let mut iter = s.char_indices();
|
||||||
if let Some((_, first)) = iter.next() {
|
if let Some((_, first)) = iter.next() {
|
||||||
|
@ -32,6 +33,7 @@ pub fn until(s: &str) -> usize {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns index of the last camel-case component of `s`.
|
/// Returns index of the last camel-case component of `s`.
|
||||||
|
#[must_use]
|
||||||
pub fn from(s: &str) -> usize {
|
pub fn from(s: &str) -> usize {
|
||||||
let mut iter = s.char_indices().rev();
|
let mut iter = s.char_indices().rev();
|
||||||
if let Some((_, first)) = iter.next() {
|
if let Some((_, first)) = iter.next() {
|
||||||
|
|
|
@ -90,6 +90,7 @@ macro_rules! define_Conf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn $rust_name() -> define_Conf!(TY $($ty)+) {
|
fn $rust_name() -> define_Conf!(TY $($ty)+) {
|
||||||
define_Conf!(DEFAULT $($ty)+, $default)
|
define_Conf!(DEFAULT $($ty)+, $default)
|
||||||
}
|
}
|
||||||
|
@ -153,6 +154,7 @@ define_Conf! {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Conf {
|
impl Default for Conf {
|
||||||
|
#[must_use]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
toml::from_str("").expect("we never error on empty config files")
|
toml::from_str("").expect("we never error on empty config files")
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ use rustc::{hir, ty};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
/// Converts a hir binary operator to the corresponding `ast` type.
|
/// Converts a hir binary operator to the corresponding `ast` type.
|
||||||
|
#[must_use]
|
||||||
pub fn binop(op: hir::BinOpKind) -> ast::BinOpKind {
|
pub fn binop(op: hir::BinOpKind) -> ast::BinOpKind {
|
||||||
match op {
|
match op {
|
||||||
hir::BinOpKind::Eq => ast::BinOpKind::Eq,
|
hir::BinOpKind::Eq => ast::BinOpKind::Eq,
|
||||||
|
|
|
@ -239,6 +239,7 @@ pub struct CompilerLintFunctions {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompilerLintFunctions {
|
impl CompilerLintFunctions {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut map = FxHashMap::default();
|
let mut map = FxHashMap::default();
|
||||||
map.insert("span_lint", "utils::span_lint");
|
map.insert("span_lint", "utils::span_lint");
|
||||||
|
|
|
@ -52,6 +52,7 @@ use crate::reexport::*;
|
||||||
|
|
||||||
/// Returns `true` if the two spans come from differing expansions (i.e., one is
|
/// Returns `true` if the two spans come from differing expansions (i.e., one is
|
||||||
/// from a macro and one isn't).
|
/// from a macro and one isn't).
|
||||||
|
#[must_use]
|
||||||
pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
|
pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
|
||||||
rhs.ctxt() != lhs.ctxt()
|
rhs.ctxt() != lhs.ctxt()
|
||||||
}
|
}
|
||||||
|
@ -98,6 +99,7 @@ pub fn in_constant(cx: &LateContext<'_, '_>, id: HirId) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if this `span` was expanded by any macro.
|
/// Returns `true` if this `span` was expanded by any macro.
|
||||||
|
#[must_use]
|
||||||
pub fn in_macro(span: Span) -> bool {
|
pub fn in_macro(span: Span) -> bool {
|
||||||
if span.from_expansion() {
|
if span.from_expansion() {
|
||||||
if let ExpnKind::Desugaring(..) = span.ctxt().outer_expn_data().kind {
|
if let ExpnKind::Desugaring(..) = span.ctxt().outer_expn_data().kind {
|
||||||
|
@ -721,6 +723,7 @@ pub fn is_adjusted(cx: &LateContext<'_, '_>, e: &Expr) -> bool {
|
||||||
/// Returns the pre-expansion span if is this comes from an expansion of the
|
/// Returns the pre-expansion span if is this comes from an expansion of the
|
||||||
/// macro `name`.
|
/// macro `name`.
|
||||||
/// See also `is_direct_expn_of`.
|
/// See also `is_direct_expn_of`.
|
||||||
|
#[must_use]
|
||||||
pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
|
pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
|
||||||
loop {
|
loop {
|
||||||
if span.from_expansion() {
|
if span.from_expansion() {
|
||||||
|
@ -748,6 +751,7 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
|
||||||
/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
|
/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
|
||||||
/// `bar!` by
|
/// `bar!` by
|
||||||
/// `is_direct_expn_of`.
|
/// `is_direct_expn_of`.
|
||||||
|
#[must_use]
|
||||||
pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
|
pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
|
||||||
if span.from_expansion() {
|
if span.from_expansion() {
|
||||||
let data = span.ctxt().outer_expn_data();
|
let data = span.ctxt().outer_expn_data();
|
||||||
|
|
|
@ -417,6 +417,7 @@ enum Associativity {
|
||||||
/// Chained `as` and explicit `:` type coercion never need inner parenthesis so
|
/// Chained `as` and explicit `:` type coercion never need inner parenthesis so
|
||||||
/// they are considered
|
/// they are considered
|
||||||
/// associative.
|
/// associative.
|
||||||
|
#[must_use]
|
||||||
fn associativity(op: &AssocOp) -> Associativity {
|
fn associativity(op: &AssocOp) -> Associativity {
|
||||||
use syntax::util::parser::AssocOp::*;
|
use syntax::util::parser::AssocOp::*;
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,7 @@ impl std::fmt::Debug for VersionInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_commit_hash() -> Option<String> {
|
pub fn get_commit_hash() -> Option<String> {
|
||||||
std::process::Command::new("git")
|
std::process::Command::new("git")
|
||||||
.args(&["rev-parse", "--short", "HEAD"])
|
.args(&["rev-parse", "--short", "HEAD"])
|
||||||
|
@ -87,6 +88,7 @@ pub fn get_commit_hash() -> Option<String> {
|
||||||
.and_then(|r| String::from_utf8(r.stdout).ok())
|
.and_then(|r| String::from_utf8(r.stdout).ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_commit_date() -> Option<String> {
|
pub fn get_commit_date() -> Option<String> {
|
||||||
std::process::Command::new("git")
|
std::process::Command::new("git")
|
||||||
.args(&["log", "-1", "--date=short", "--pretty=format:%cd"])
|
.args(&["log", "-1", "--date=short", "--pretty=format:%cd"])
|
||||||
|
@ -95,6 +97,7 @@ pub fn get_commit_date() -> Option<String> {
|
||||||
.and_then(|r| String::from_utf8(r.stdout).ok())
|
.and_then(|r| String::from_utf8(r.stdout).ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_channel() -> Option<String> {
|
pub fn get_channel() -> Option<String> {
|
||||||
match env::var("CFG_RELEASE_CHANNEL") {
|
match env::var("CFG_RELEASE_CHANNEL") {
|
||||||
Ok(channel) => Some(channel),
|
Ok(channel) => Some(channel),
|
||||||
|
|
|
@ -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; 321] = [
|
pub const ALL_LINTS: [Lint; 324] = [
|
||||||
Lint {
|
Lint {
|
||||||
name: "absurd_extreme_comparisons",
|
name: "absurd_extreme_comparisons",
|
||||||
group: "correctness",
|
group: "correctness",
|
||||||
|
@ -350,6 +350,13 @@ pub const ALL_LINTS: [Lint; 321] = [
|
||||||
deprecation: None,
|
deprecation: None,
|
||||||
module: "double_comparison",
|
module: "double_comparison",
|
||||||
},
|
},
|
||||||
|
Lint {
|
||||||
|
name: "double_must_use",
|
||||||
|
group: "style",
|
||||||
|
desc: "`#[must_use]` attribute on a `#[must_use]`-returning function / method",
|
||||||
|
deprecation: None,
|
||||||
|
module: "functions",
|
||||||
|
},
|
||||||
Lint {
|
Lint {
|
||||||
name: "double_neg",
|
name: "double_neg",
|
||||||
group: "style",
|
group: "style",
|
||||||
|
@ -1155,6 +1162,20 @@ pub const ALL_LINTS: [Lint; 321] = [
|
||||||
deprecation: None,
|
deprecation: None,
|
||||||
module: "inherent_impl",
|
module: "inherent_impl",
|
||||||
},
|
},
|
||||||
|
Lint {
|
||||||
|
name: "must_use_candidate",
|
||||||
|
group: "pedantic",
|
||||||
|
desc: "function or method that could take a `#[must_use]` attribute",
|
||||||
|
deprecation: None,
|
||||||
|
module: "functions",
|
||||||
|
},
|
||||||
|
Lint {
|
||||||
|
name: "must_use_unit",
|
||||||
|
group: "style",
|
||||||
|
desc: "`#[must_use]` attribute on a unit-returning function / method",
|
||||||
|
deprecation: None,
|
||||||
|
module: "functions",
|
||||||
|
},
|
||||||
Lint {
|
Lint {
|
||||||
name: "mut_from_ref",
|
name: "mut_from_ref",
|
||||||
group: "correctness",
|
group: "correctness",
|
||||||
|
|
|
@ -9,6 +9,7 @@ use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn clippy_driver_path() -> PathBuf {
|
fn clippy_driver_path() -> PathBuf {
|
||||||
if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
|
if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
|
||||||
PathBuf::from(path)
|
PathBuf::from(path)
|
||||||
|
@ -17,6 +18,7 @@ fn clippy_driver_path() -> PathBuf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn host_libs() -> PathBuf {
|
fn host_libs() -> PathBuf {
|
||||||
if let Some(path) = option_env!("HOST_LIBS") {
|
if let Some(path) = option_env!("HOST_LIBS") {
|
||||||
PathBuf::from(path)
|
PathBuf::from(path)
|
||||||
|
@ -25,10 +27,12 @@ fn host_libs() -> PathBuf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn rustc_test_suite() -> Option<PathBuf> {
|
fn rustc_test_suite() -> Option<PathBuf> {
|
||||||
option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
|
option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn rustc_lib_path() -> PathBuf {
|
fn rustc_lib_path() -> PathBuf {
|
||||||
option_env!("RUSTC_LIB_PATH").unwrap().into()
|
option_env!("RUSTC_LIB_PATH").unwrap().into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
/// Used to test that certain lints don't trigger in imported external macros
|
//! Used to test that certain lints don't trigger in imported external macros
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! foofoo {
|
macro_rules! foofoo {
|
||||||
() => {
|
() => {
|
||||||
loop {}
|
loop {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! must_use_unit {
|
||||||
|
() => {
|
||||||
|
#[must_use]
|
||||||
|
fn foo() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
27
tests/ui/double_must_use.rs
Normal file
27
tests/ui/double_must_use.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#![warn(clippy::double_must_use)]
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn must_use_result() -> Result<(), ()> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn must_use_tuple() -> (Result<(), ()>, u8) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn must_use_array() -> [Result<(), ()>; 1] {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use = "With note"]
|
||||||
|
pub fn must_use_with_note() -> Result<(), ()> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
must_use_result();
|
||||||
|
must_use_tuple();
|
||||||
|
must_use_with_note();
|
||||||
|
}
|
27
tests/ui/double_must_use.stderr
Normal file
27
tests/ui/double_must_use.stderr
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`
|
||||||
|
--> $DIR/double_must_use.rs:4:1
|
||||||
|
|
|
||||||
|
LL | pub fn must_use_result() -> Result<(), ()> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `-D clippy::double-must-use` implied by `-D warnings`
|
||||||
|
= help: either add some descriptive text or remove the attribute
|
||||||
|
|
||||||
|
error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`
|
||||||
|
--> $DIR/double_must_use.rs:9:1
|
||||||
|
|
|
||||||
|
LL | pub fn must_use_tuple() -> (Result<(), ()>, u8) {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: either add some descriptive text or remove the attribute
|
||||||
|
|
||||||
|
error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`
|
||||||
|
--> $DIR/double_must_use.rs:14:1
|
||||||
|
|
|
||||||
|
LL | pub fn must_use_array() -> [Result<(), ()>; 1] {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: either add some descriptive text or remove the attribute
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
|
@ -2,7 +2,7 @@ error: this function has too many arguments (8/7)
|
||||||
--> $DIR/functions.rs:8:1
|
--> $DIR/functions.rs:8:1
|
||||||
|
|
|
|
||||||
LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
|
LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::too-many-arguments` implied by `-D warnings`
|
= note: `-D clippy::too-many-arguments` implied by `-D warnings`
|
||||||
|
|
||||||
|
@ -16,19 +16,19 @@ LL | | three: &str,
|
||||||
... |
|
... |
|
||||||
LL | | eight: ()
|
LL | | eight: ()
|
||||||
LL | | ) {
|
LL | | ) {
|
||||||
| |_^
|
| |__^
|
||||||
|
|
||||||
error: this function has too many arguments (8/7)
|
error: this function has too many arguments (8/7)
|
||||||
--> $DIR/functions.rs:45:5
|
--> $DIR/functions.rs:45:5
|
||||||
|
|
|
|
||||||
LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ());
|
LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: this function has too many arguments (8/7)
|
error: this function has too many arguments (8/7)
|
||||||
--> $DIR/functions.rs:54:5
|
--> $DIR/functions.rs:54:5
|
||||||
|
|
|
|
||||||
LL | fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
|
LL | fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: this public function dereferences a raw pointer but is not marked `unsafe`
|
error: this public function dereferences a raw pointer but is not marked `unsafe`
|
||||||
--> $DIR/functions.rs:63:34
|
--> $DIR/functions.rs:63:34
|
||||||
|
|
|
@ -4,16 +4,17 @@
|
||||||
#![warn(clippy::all, clippy::pedantic, clippy::option_unwrap_used)]
|
#![warn(clippy::all, clippy::pedantic, clippy::option_unwrap_used)]
|
||||||
#![allow(
|
#![allow(
|
||||||
clippy::blacklisted_name,
|
clippy::blacklisted_name,
|
||||||
unused,
|
clippy::default_trait_access,
|
||||||
clippy::print_stdout,
|
clippy::missing_docs_in_private_items,
|
||||||
clippy::non_ascii_literal,
|
clippy::non_ascii_literal,
|
||||||
clippy::new_without_default,
|
clippy::new_without_default,
|
||||||
clippy::missing_docs_in_private_items,
|
|
||||||
clippy::needless_pass_by_value,
|
clippy::needless_pass_by_value,
|
||||||
clippy::default_trait_access,
|
clippy::print_stdout,
|
||||||
|
clippy::must_use_candidate,
|
||||||
clippy::use_self,
|
clippy::use_self,
|
||||||
clippy::useless_format,
|
clippy::useless_format,
|
||||||
clippy::wrong_self_convention
|
clippy::wrong_self_convention,
|
||||||
|
unused
|
||||||
)]
|
)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name
|
error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name
|
||||||
--> $DIR/methods.rs:36:5
|
--> $DIR/methods.rs:37:5
|
||||||
|
|
|
|
||||||
LL | / pub fn add(self, other: T) -> T {
|
LL | / pub fn add(self, other: T) -> T {
|
||||||
LL | | self
|
LL | | self
|
||||||
|
@ -9,7 +9,7 @@ LL | | }
|
||||||
= note: `-D clippy::should-implement-trait` implied by `-D warnings`
|
= note: `-D clippy::should-implement-trait` implied by `-D warnings`
|
||||||
|
|
||||||
error: methods called `new` usually return `Self`
|
error: methods called `new` usually return `Self`
|
||||||
--> $DIR/methods.rs:152:5
|
--> $DIR/methods.rs:153:5
|
||||||
|
|
|
|
||||||
LL | / fn new() -> i32 {
|
LL | / fn new() -> i32 {
|
||||||
LL | | 0
|
LL | | 0
|
||||||
|
@ -19,7 +19,7 @@ LL | | }
|
||||||
= note: `-D clippy::new-ret-no-self` implied by `-D warnings`
|
= note: `-D clippy::new-ret-no-self` implied by `-D warnings`
|
||||||
|
|
||||||
error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead
|
error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead
|
||||||
--> $DIR/methods.rs:174:13
|
--> $DIR/methods.rs:175:13
|
||||||
|
|
|
|
||||||
LL | let _ = opt.map(|x| x + 1)
|
LL | let _ = opt.map(|x| x + 1)
|
||||||
| _____________^
|
| _____________^
|
||||||
|
@ -31,7 +31,7 @@ LL | | .unwrap_or(0);
|
||||||
= note: replace `map(|x| x + 1).unwrap_or(0)` with `map_or(0, |x| x + 1)`
|
= note: replace `map(|x| x + 1).unwrap_or(0)` with `map_or(0, |x| x + 1)`
|
||||||
|
|
||||||
error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead
|
error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead
|
||||||
--> $DIR/methods.rs:178:13
|
--> $DIR/methods.rs:179:13
|
||||||
|
|
|
|
||||||
LL | let _ = opt.map(|x| {
|
LL | let _ = opt.map(|x| {
|
||||||
| _____________^
|
| _____________^
|
||||||
|
@ -41,7 +41,7 @@ LL | | ).unwrap_or(0);
|
||||||
| |____________________________^
|
| |____________________________^
|
||||||
|
|
||||||
error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead
|
error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead
|
||||||
--> $DIR/methods.rs:182:13
|
--> $DIR/methods.rs:183:13
|
||||||
|
|
|
|
||||||
LL | let _ = opt.map(|x| x + 1)
|
LL | let _ = opt.map(|x| x + 1)
|
||||||
| _____________^
|
| _____________^
|
||||||
|
@ -51,7 +51,7 @@ LL | | });
|
||||||
| |__________________^
|
| |__________________^
|
||||||
|
|
||||||
error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead
|
error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead
|
||||||
--> $DIR/methods.rs:187:13
|
--> $DIR/methods.rs:188:13
|
||||||
|
|
|
|
||||||
LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None);
|
LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -59,7 +59,7 @@ LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None);
|
||||||
= note: replace `map(|x| Some(x + 1)).unwrap_or(None)` with `and_then(|x| Some(x + 1))`
|
= note: replace `map(|x| Some(x + 1)).unwrap_or(None)` with `and_then(|x| Some(x + 1))`
|
||||||
|
|
||||||
error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead
|
error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead
|
||||||
--> $DIR/methods.rs:189:13
|
--> $DIR/methods.rs:190:13
|
||||||
|
|
|
|
||||||
LL | let _ = opt.map(|x| {
|
LL | let _ = opt.map(|x| {
|
||||||
| _____________^
|
| _____________^
|
||||||
|
@ -69,7 +69,7 @@ LL | | ).unwrap_or(None);
|
||||||
| |_____________________^
|
| |_____________________^
|
||||||
|
|
||||||
error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead
|
error: called `map(f).unwrap_or(None)` on an Option value. This can be done more directly by calling `and_then(f)` instead
|
||||||
--> $DIR/methods.rs:193:13
|
--> $DIR/methods.rs:194:13
|
||||||
|
|
|
|
||||||
LL | let _ = opt
|
LL | let _ = opt
|
||||||
| _____________^
|
| _____________^
|
||||||
|
@ -80,7 +80,7 @@ LL | | .unwrap_or(None);
|
||||||
= note: replace `map(|x| Some(x + 1)).unwrap_or(None)` with `and_then(|x| Some(x + 1))`
|
= note: replace `map(|x| Some(x + 1)).unwrap_or(None)` with `and_then(|x| Some(x + 1))`
|
||||||
|
|
||||||
error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead
|
error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead
|
||||||
--> $DIR/methods.rs:204:13
|
--> $DIR/methods.rs:205:13
|
||||||
|
|
|
|
||||||
LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id);
|
LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -88,7 +88,7 @@ LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id);
|
||||||
= note: replace `map(|p| format!("{}.", p)).unwrap_or(id)` with `map_or(id, |p| format!("{}.", p))`
|
= note: replace `map(|p| format!("{}.", p)).unwrap_or(id)` with `map_or(id, |p| format!("{}.", p))`
|
||||||
|
|
||||||
error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead
|
error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead
|
||||||
--> $DIR/methods.rs:208:13
|
--> $DIR/methods.rs:209:13
|
||||||
|
|
|
|
||||||
LL | let _ = opt.map(|x| x + 1)
|
LL | let _ = opt.map(|x| x + 1)
|
||||||
| _____________^
|
| _____________^
|
||||||
|
@ -100,7 +100,7 @@ LL | | .unwrap_or_else(|| 0);
|
||||||
= note: replace `map(|x| x + 1).unwrap_or_else(|| 0)` with `map_or_else(|| 0, |x| x + 1)`
|
= note: replace `map(|x| x + 1).unwrap_or_else(|| 0)` with `map_or_else(|| 0, |x| x + 1)`
|
||||||
|
|
||||||
error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead
|
error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead
|
||||||
--> $DIR/methods.rs:212:13
|
--> $DIR/methods.rs:213:13
|
||||||
|
|
|
|
||||||
LL | let _ = opt.map(|x| {
|
LL | let _ = opt.map(|x| {
|
||||||
| _____________^
|
| _____________^
|
||||||
|
@ -110,7 +110,7 @@ LL | | ).unwrap_or_else(|| 0);
|
||||||
| |____________________________________^
|
| |____________________________________^
|
||||||
|
|
||||||
error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead
|
error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead
|
||||||
--> $DIR/methods.rs:216:13
|
--> $DIR/methods.rs:217:13
|
||||||
|
|
|
|
||||||
LL | let _ = opt.map(|x| x + 1)
|
LL | let _ = opt.map(|x| x + 1)
|
||||||
| _____________^
|
| _____________^
|
||||||
|
@ -120,7 +120,7 @@ LL | | );
|
||||||
| |_________________^
|
| |_________________^
|
||||||
|
|
||||||
error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
|
error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
|
||||||
--> $DIR/methods.rs:246:13
|
--> $DIR/methods.rs:247:13
|
||||||
|
|
|
|
||||||
LL | let _ = v.iter().filter(|&x| *x < 0).next();
|
LL | let _ = v.iter().filter(|&x| *x < 0).next();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -129,7 +129,7 @@ LL | let _ = v.iter().filter(|&x| *x < 0).next();
|
||||||
= note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)`
|
= note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)`
|
||||||
|
|
||||||
error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
|
error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
|
||||||
--> $DIR/methods.rs:249:13
|
--> $DIR/methods.rs:250:13
|
||||||
|
|
|
|
||||||
LL | let _ = v.iter().filter(|&x| {
|
LL | let _ = v.iter().filter(|&x| {
|
||||||
| _____________^
|
| _____________^
|
||||||
|
@ -139,7 +139,7 @@ LL | | ).next();
|
||||||
| |___________________________^
|
| |___________________________^
|
||||||
|
|
||||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||||
--> $DIR/methods.rs:266:22
|
--> $DIR/methods.rs:267:22
|
||||||
|
|
|
|
||||||
LL | let _ = v.iter().find(|&x| *x < 0).is_some();
|
LL | let _ = v.iter().find(|&x| *x < 0).is_some();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)`
|
||||||
|
@ -147,25 +147,25 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_some();
|
||||||
= note: `-D clippy::search-is-some` implied by `-D warnings`
|
= note: `-D clippy::search-is-some` implied by `-D warnings`
|
||||||
|
|
||||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||||
--> $DIR/methods.rs:267:20
|
--> $DIR/methods.rs:268:20
|
||||||
|
|
|
|
||||||
LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
|
LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)`
|
||||||
|
|
||||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||||
--> $DIR/methods.rs:268:20
|
--> $DIR/methods.rs:269:20
|
||||||
|
|
|
|
||||||
LL | let _ = (0..1).find(|x| *x == 0).is_some();
|
LL | let _ = (0..1).find(|x| *x == 0).is_some();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)`
|
||||||
|
|
||||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||||
--> $DIR/methods.rs:269:22
|
--> $DIR/methods.rs:270:22
|
||||||
|
|
|
|
||||||
LL | let _ = v.iter().find(|x| **x == 0).is_some();
|
LL | let _ = v.iter().find(|x| **x == 0).is_some();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)`
|
||||||
|
|
||||||
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
|
||||||
--> $DIR/methods.rs:272:13
|
--> $DIR/methods.rs:273:13
|
||||||
|
|
|
|
||||||
LL | let _ = v.iter().find(|&x| {
|
LL | let _ = v.iter().find(|&x| {
|
||||||
| _____________^
|
| _____________^
|
||||||
|
@ -175,13 +175,13 @@ LL | | ).is_some();
|
||||||
| |______________________________^
|
| |______________________________^
|
||||||
|
|
||||||
error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
|
error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
|
||||||
--> $DIR/methods.rs:278:22
|
--> $DIR/methods.rs:279:22
|
||||||
|
|
|
|
||||||
LL | let _ = v.iter().position(|&x| x < 0).is_some();
|
LL | let _ = v.iter().position(|&x| x < 0).is_some();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
|
||||||
|
|
||||||
error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
|
error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
|
||||||
--> $DIR/methods.rs:281:13
|
--> $DIR/methods.rs:282:13
|
||||||
|
|
|
|
||||||
LL | let _ = v.iter().position(|&x| {
|
LL | let _ = v.iter().position(|&x| {
|
||||||
| _____________^
|
| _____________^
|
||||||
|
@ -191,13 +191,13 @@ LL | | ).is_some();
|
||||||
| |______________________________^
|
| |______________________________^
|
||||||
|
|
||||||
error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
|
error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
|
||||||
--> $DIR/methods.rs:287:22
|
--> $DIR/methods.rs:288:22
|
||||||
|
|
|
|
||||||
LL | let _ = v.iter().rposition(|&x| x < 0).is_some();
|
LL | let _ = v.iter().rposition(|&x| x < 0).is_some();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
|
||||||
|
|
||||||
error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
|
error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
|
||||||
--> $DIR/methods.rs:290:13
|
--> $DIR/methods.rs:291:13
|
||||||
|
|
|
|
||||||
LL | let _ = v.iter().rposition(|&x| {
|
LL | let _ = v.iter().rposition(|&x| {
|
||||||
| _____________^
|
| _____________^
|
||||||
|
@ -207,7 +207,7 @@ LL | | ).is_some();
|
||||||
| |______________________________^
|
| |______________________________^
|
||||||
|
|
||||||
error: used unwrap() on an Option value. If you don't want to handle the None case gracefully, consider using expect() to provide a better panic message
|
error: used unwrap() on an Option value. If you don't want to handle the None case gracefully, consider using expect() to provide a better panic message
|
||||||
--> $DIR/methods.rs:305:13
|
--> $DIR/methods.rs:306:13
|
||||||
|
|
|
|
||||||
LL | let _ = opt.unwrap();
|
LL | let _ = opt.unwrap();
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
88
tests/ui/must_use_candidates.fixed
Normal file
88
tests/ui/must_use_candidates.fixed
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
// run-rustfix
|
||||||
|
#![feature(never_type)]
|
||||||
|
#![allow(unused_mut)]
|
||||||
|
#![warn(clippy::must_use_candidate)]
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct MyAtomic(AtomicBool);
|
||||||
|
pub struct MyPure;
|
||||||
|
|
||||||
|
#[must_use] pub fn pure(i: u8) -> u8 {
|
||||||
|
i
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyPure {
|
||||||
|
#[must_use] pub fn inherent_pure(&self) -> u8 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MyPureTrait {
|
||||||
|
fn trait_pure(&self, i: u32) -> u32 {
|
||||||
|
self.trait_impl_pure(i) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trait_impl_pure(&self, i: u32) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyPureTrait for MyPure {
|
||||||
|
#[must_use] fn trait_impl_pure(&self, i: u32) -> u32 {
|
||||||
|
i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn without_result() {
|
||||||
|
// OK
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn impure_primitive(i: &mut u8) -> u8 {
|
||||||
|
*i
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_callback<F: Fn(u32) -> bool>(f: &F) -> bool {
|
||||||
|
f(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn quoth_the_raven(_more: !) -> u32 {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn atomics(b: &AtomicBool) -> bool {
|
||||||
|
b.load(Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use] pub fn rcd(_x: Rc<u32>) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rcmut(_x: Rc<&mut u32>) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use] pub fn arcd(_x: Arc<u32>) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inner_types(_m: &MyAtomic) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut COUNTER: usize = 0;
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Don't ever call this from multiple threads
|
||||||
|
pub unsafe fn mutates_static() -> usize {
|
||||||
|
COUNTER += 1;
|
||||||
|
COUNTER
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(1, pure(1));
|
||||||
|
}
|
88
tests/ui/must_use_candidates.rs
Normal file
88
tests/ui/must_use_candidates.rs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
// run-rustfix
|
||||||
|
#![feature(never_type)]
|
||||||
|
#![allow(unused_mut)]
|
||||||
|
#![warn(clippy::must_use_candidate)]
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct MyAtomic(AtomicBool);
|
||||||
|
pub struct MyPure;
|
||||||
|
|
||||||
|
pub fn pure(i: u8) -> u8 {
|
||||||
|
i
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyPure {
|
||||||
|
pub fn inherent_pure(&self) -> u8 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MyPureTrait {
|
||||||
|
fn trait_pure(&self, i: u32) -> u32 {
|
||||||
|
self.trait_impl_pure(i) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trait_impl_pure(&self, i: u32) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyPureTrait for MyPure {
|
||||||
|
fn trait_impl_pure(&self, i: u32) -> u32 {
|
||||||
|
i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn without_result() {
|
||||||
|
// OK
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn impure_primitive(i: &mut u8) -> u8 {
|
||||||
|
*i
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_callback<F: Fn(u32) -> bool>(f: &F) -> bool {
|
||||||
|
f(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn quoth_the_raven(_more: !) -> u32 {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn atomics(b: &AtomicBool) -> bool {
|
||||||
|
b.load(Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rcd(_x: Rc<u32>) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rcmut(_x: Rc<&mut u32>) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn arcd(_x: Arc<u32>) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inner_types(_m: &MyAtomic) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut COUNTER: usize = 0;
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Don't ever call this from multiple threads
|
||||||
|
pub unsafe fn mutates_static() -> usize {
|
||||||
|
COUNTER += 1;
|
||||||
|
COUNTER
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(1, pure(1));
|
||||||
|
}
|
40
tests/ui/must_use_candidates.stderr
Normal file
40
tests/ui/must_use_candidates.stderr
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
error: this function could have a `#[must_use]` attribute
|
||||||
|
--> $DIR/must_use_candidates.rs:12:1
|
||||||
|
|
|
||||||
|
LL | pub fn pure(i: u8) -> u8 {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn pure(i: u8) -> u8`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::must-use-candidate` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: this method could have a `#[must_use]` attribute
|
||||||
|
--> $DIR/must_use_candidates.rs:17:5
|
||||||
|
|
|
||||||
|
LL | pub fn inherent_pure(&self) -> u8 {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn inherent_pure(&self) -> u8`
|
||||||
|
|
||||||
|
error: this method could have a `#[must_use]` attribute
|
||||||
|
--> $DIR/must_use_candidates.rs:31:5
|
||||||
|
|
|
||||||
|
LL | fn trait_impl_pure(&self, i: u32) -> u32 {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] fn trait_impl_pure(&self, i: u32) -> u32`
|
||||||
|
|
||||||
|
error: this function could have a `#[must_use]` attribute
|
||||||
|
--> $DIR/must_use_candidates.rs:48:1
|
||||||
|
|
|
||||||
|
LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool`
|
||||||
|
|
||||||
|
error: this function could have a `#[must_use]` attribute
|
||||||
|
--> $DIR/must_use_candidates.rs:60:1
|
||||||
|
|
|
||||||
|
LL | pub fn rcd(_x: Rc<u32>) -> bool {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn rcd(_x: Rc<u32>) -> bool`
|
||||||
|
|
||||||
|
error: this function could have a `#[must_use]` attribute
|
||||||
|
--> $DIR/must_use_candidates.rs:68:1
|
||||||
|
|
|
||||||
|
LL | pub fn arcd(_x: Arc<u32>) -> bool {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn arcd(_x: Arc<u32>) -> bool`
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
26
tests/ui/must_use_unit.fixed
Normal file
26
tests/ui/must_use_unit.fixed
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
//run-rustfix
|
||||||
|
// aux-build:macro_rules.rs
|
||||||
|
|
||||||
|
#![warn(clippy::must_use_unit)]
|
||||||
|
#![allow(clippy::unused_unit)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate macro_rules;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn must_use_default() {}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn must_use_unit() -> () {}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn must_use_with_note() {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
must_use_default();
|
||||||
|
must_use_unit();
|
||||||
|
must_use_with_note();
|
||||||
|
|
||||||
|
// We should not lint in external macros
|
||||||
|
must_use_unit!();
|
||||||
|
}
|
26
tests/ui/must_use_unit.rs
Normal file
26
tests/ui/must_use_unit.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
//run-rustfix
|
||||||
|
// aux-build:macro_rules.rs
|
||||||
|
|
||||||
|
#![warn(clippy::must_use_unit)]
|
||||||
|
#![allow(clippy::unused_unit)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate macro_rules;
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn must_use_default() {}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn must_use_unit() -> () {}
|
||||||
|
|
||||||
|
#[must_use = "With note"]
|
||||||
|
pub fn must_use_with_note() {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
must_use_default();
|
||||||
|
must_use_unit();
|
||||||
|
must_use_with_note();
|
||||||
|
|
||||||
|
// We should not lint in external macros
|
||||||
|
must_use_unit!();
|
||||||
|
}
|
28
tests/ui/must_use_unit.stderr
Normal file
28
tests/ui/must_use_unit.stderr
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
error: this unit-returning function has a `#[must_use]` attribute
|
||||||
|
--> $DIR/must_use_unit.rs:11:1
|
||||||
|
|
|
||||||
|
LL | #[must_use]
|
||||||
|
| ----------- help: remove the attribute
|
||||||
|
LL | pub fn must_use_default() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `-D clippy::must-use-unit` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: this unit-returning function has a `#[must_use]` attribute
|
||||||
|
--> $DIR/must_use_unit.rs:14:1
|
||||||
|
|
|
||||||
|
LL | #[must_use]
|
||||||
|
| ----------- help: remove the attribute
|
||||||
|
LL | pub fn must_use_unit() -> () {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this unit-returning function has a `#[must_use]` attribute
|
||||||
|
--> $DIR/must_use_unit.rs:17:1
|
||||||
|
|
|
||||||
|
LL | #[must_use = "With note"]
|
||||||
|
| ------------------------- help: remove the attribute
|
||||||
|
LL | pub fn must_use_with_note() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
|
@ -16,6 +16,7 @@ fn id<T>(x: T) -> T {
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn first(x: (isize, isize)) -> isize {
|
fn first(x: (isize, isize)) -> isize {
|
||||||
x.0
|
x.0
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,135 +1,135 @@
|
||||||
error: `x` is shadowed by itself in `&mut x`
|
error: `x` is shadowed by itself in `&mut x`
|
||||||
--> $DIR/shadow.rs:25:5
|
--> $DIR/shadow.rs:26:5
|
||||||
|
|
|
|
||||||
LL | let x = &mut x;
|
LL | let x = &mut x;
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::shadow-same` implied by `-D warnings`
|
= note: `-D clippy::shadow-same` implied by `-D warnings`
|
||||||
note: previous binding is here
|
note: previous binding is here
|
||||||
--> $DIR/shadow.rs:24:13
|
--> $DIR/shadow.rs:25:13
|
||||||
|
|
|
|
||||||
LL | let mut x = 1;
|
LL | let mut x = 1;
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: `x` is shadowed by itself in `{ x }`
|
error: `x` is shadowed by itself in `{ x }`
|
||||||
--> $DIR/shadow.rs:26:5
|
|
||||||
|
|
|
||||||
LL | let x = { x };
|
|
||||||
| ^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
note: previous binding is here
|
|
||||||
--> $DIR/shadow.rs:25:9
|
|
||||||
|
|
|
||||||
LL | let x = &mut x;
|
|
||||||
| ^
|
|
||||||
|
|
||||||
error: `x` is shadowed by itself in `(&*x)`
|
|
||||||
--> $DIR/shadow.rs:27:5
|
--> $DIR/shadow.rs:27:5
|
||||||
|
|
|
|
||||||
LL | let x = (&*x);
|
LL | let x = { x };
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: previous binding is here
|
note: previous binding is here
|
||||||
--> $DIR/shadow.rs:26:9
|
--> $DIR/shadow.rs:26:9
|
||||||
|
|
|
|
||||||
|
LL | let x = &mut x;
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: `x` is shadowed by itself in `(&*x)`
|
||||||
|
--> $DIR/shadow.rs:28:5
|
||||||
|
|
|
||||||
|
LL | let x = (&*x);
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: previous binding is here
|
||||||
|
--> $DIR/shadow.rs:27:9
|
||||||
|
|
|
||||||
LL | let x = { x };
|
LL | let x = { x };
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: `x` is shadowed by `{ *x + 1 }` which reuses the original value
|
error: `x` is shadowed by `{ *x + 1 }` which reuses the original value
|
||||||
--> $DIR/shadow.rs:28:9
|
--> $DIR/shadow.rs:29:9
|
||||||
|
|
|
|
||||||
LL | let x = { *x + 1 };
|
LL | let x = { *x + 1 };
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::shadow-reuse` implied by `-D warnings`
|
= note: `-D clippy::shadow-reuse` implied by `-D warnings`
|
||||||
note: initialization happens here
|
note: initialization happens here
|
||||||
--> $DIR/shadow.rs:28:13
|
--> $DIR/shadow.rs:29:13
|
||||||
|
|
|
|
||||||
LL | let x = { *x + 1 };
|
LL | let x = { *x + 1 };
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
note: previous binding is here
|
note: previous binding is here
|
||||||
--> $DIR/shadow.rs:27:9
|
--> $DIR/shadow.rs:28:9
|
||||||
|
|
|
|
||||||
LL | let x = (&*x);
|
LL | let x = (&*x);
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: `x` is shadowed by `id(x)` which reuses the original value
|
error: `x` is shadowed by `id(x)` which reuses the original value
|
||||||
--> $DIR/shadow.rs:29:9
|
|
||||||
|
|
|
||||||
LL | let x = id(x);
|
|
||||||
| ^
|
|
||||||
|
|
|
||||||
note: initialization happens here
|
|
||||||
--> $DIR/shadow.rs:29:13
|
|
||||||
|
|
|
||||||
LL | let x = id(x);
|
|
||||||
| ^^^^^
|
|
||||||
note: previous binding is here
|
|
||||||
--> $DIR/shadow.rs:28:9
|
|
||||||
|
|
|
||||||
LL | let x = { *x + 1 };
|
|
||||||
| ^
|
|
||||||
|
|
||||||
error: `x` is shadowed by `(1, x)` which reuses the original value
|
|
||||||
--> $DIR/shadow.rs:30:9
|
--> $DIR/shadow.rs:30:9
|
||||||
|
|
|
|
||||||
LL | let x = (1, x);
|
LL | let x = id(x);
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: initialization happens here
|
note: initialization happens here
|
||||||
--> $DIR/shadow.rs:30:13
|
--> $DIR/shadow.rs:30:13
|
||||||
|
|
|
|
||||||
LL | let x = (1, x);
|
LL | let x = id(x);
|
||||||
| ^^^^^^
|
| ^^^^^
|
||||||
note: previous binding is here
|
note: previous binding is here
|
||||||
--> $DIR/shadow.rs:29:9
|
--> $DIR/shadow.rs:29:9
|
||||||
|
|
|
|
||||||
LL | let x = id(x);
|
LL | let x = { *x + 1 };
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: `x` is shadowed by `first(x)` which reuses the original value
|
error: `x` is shadowed by `(1, x)` which reuses the original value
|
||||||
--> $DIR/shadow.rs:31:9
|
--> $DIR/shadow.rs:31:9
|
||||||
|
|
|
|
||||||
LL | let x = first(x);
|
LL | let x = (1, x);
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
note: initialization happens here
|
note: initialization happens here
|
||||||
--> $DIR/shadow.rs:31:13
|
--> $DIR/shadow.rs:31:13
|
||||||
|
|
|
|
||||||
|
LL | let x = (1, x);
|
||||||
|
| ^^^^^^
|
||||||
|
note: previous binding is here
|
||||||
|
--> $DIR/shadow.rs:30:9
|
||||||
|
|
|
||||||
|
LL | let x = id(x);
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: `x` is shadowed by `first(x)` which reuses the original value
|
||||||
|
--> $DIR/shadow.rs:32:9
|
||||||
|
|
|
||||||
|
LL | let x = first(x);
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
note: initialization happens here
|
||||||
|
--> $DIR/shadow.rs:32:13
|
||||||
|
|
|
||||||
LL | let x = first(x);
|
LL | let x = first(x);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
note: previous binding is here
|
note: previous binding is here
|
||||||
--> $DIR/shadow.rs:30:9
|
--> $DIR/shadow.rs:31:9
|
||||||
|
|
|
|
||||||
LL | let x = (1, x);
|
LL | let x = (1, x);
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: `x` is shadowed by `y`
|
error: `x` is shadowed by `y`
|
||||||
--> $DIR/shadow.rs:33:9
|
--> $DIR/shadow.rs:34:9
|
||||||
|
|
|
|
||||||
LL | let x = y;
|
LL | let x = y;
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::shadow-unrelated` implied by `-D warnings`
|
= note: `-D clippy::shadow-unrelated` implied by `-D warnings`
|
||||||
note: initialization happens here
|
note: initialization happens here
|
||||||
--> $DIR/shadow.rs:33:13
|
--> $DIR/shadow.rs:34:13
|
||||||
|
|
|
|
||||||
LL | let x = y;
|
LL | let x = y;
|
||||||
| ^
|
| ^
|
||||||
note: previous binding is here
|
note: previous binding is here
|
||||||
--> $DIR/shadow.rs:31:9
|
--> $DIR/shadow.rs:32:9
|
||||||
|
|
|
|
||||||
LL | let x = first(x);
|
LL | let x = first(x);
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: `x` shadows a previous declaration
|
error: `x` shadows a previous declaration
|
||||||
--> $DIR/shadow.rs:35:5
|
--> $DIR/shadow.rs:36:5
|
||||||
|
|
|
|
||||||
LL | let x;
|
LL | let x;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
|
|
||||||
note: previous binding is here
|
note: previous binding is here
|
||||||
--> $DIR/shadow.rs:33:9
|
--> $DIR/shadow.rs:34:9
|
||||||
|
|
|
|
||||||
LL | let x = y;
|
LL | let x = y;
|
||||||
| ^
|
| ^
|
||||||
|
|
Loading…
Reference in a new issue